diff --git a/ip/ipaddress.c b/ip/ipaddress.c index cf8ef818..4d37c5e0 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -1012,14 +1012,95 @@ static unsigned int get_ifa_flags(struct ifaddrmsg *ifa, ifa->ifa_flags; } +/* Mapping from argument to address flag mask */ +struct { + const char *name; + unsigned long value; +} ifa_flag_names[] = { + { "secondary", IFA_F_SECONDARY }, + { "temporary", IFA_F_SECONDARY }, + { "nodad", IFA_F_NODAD }, + { "optimistic", IFA_F_OPTIMISTIC }, + { "dadfailed", IFA_F_DADFAILED }, + { "home", IFA_F_HOMEADDRESS }, + { "deprecated", IFA_F_DEPRECATED }, + { "tentative", IFA_F_TENTATIVE }, + { "permanent", IFA_F_PERMANENT }, + { "mngtmpaddr", IFA_F_MANAGETEMPADDR }, + { "noprefixroute", IFA_F_NOPREFIXROUTE }, + { "autojoin", IFA_F_MCAUTOJOIN }, + { "stable-privacy", IFA_F_STABLE_PRIVACY }, +}; + +static void print_ifa_flags(FILE *fp, const struct ifaddrmsg *ifa, + unsigned int flags) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ifa_flag_names); i++) { + unsigned long mask = ifa_flag_names[i].value; + + if (mask == IFA_F_PERMANENT) { + if (!(flags & mask)) + fprintf(fp, "dynamic "); + } else if (flags & mask) { + if (mask == IFA_F_SECONDARY && + ifa->ifa_family == AF_INET6) + fprintf(fp, "temporary "); + else + fprintf(fp, "%s ", ifa_flag_names[i].name); + } + + flags &= ~mask; + } + + if (flags) + fprintf(fp, "flags %02x ", flags); + +} + +static int get_filter(const char *arg) +{ + unsigned int i; + + /* Special cases */ + if (strcmp(arg, "dynamic") == 0) { + filter.flags &= ~IFA_F_PERMANENT; + filter.flagmask |= IFA_F_PERMANENT; + } else if (strcmp(arg, "primary") == 0) { + filter.flags &= ~IFA_F_SECONDARY; + filter.flagmask |= IFA_F_SECONDARY; + } else if (*arg == '-') { + for (i = 0; i < ARRAY_SIZE(ifa_flag_names); i++) { + if (strcmp(arg + 1, ifa_flag_names[i].name)) + continue; + + filter.flags &= ifa_flag_names[i].value; + filter.flagmask |= ifa_flag_names[i].value; + return 0; + } + + return -1; + } else { + for (i = 0; i < ARRAY_SIZE(ifa_flag_names); i++) { + if (strcmp(arg, ifa_flag_names[i].name)) + continue; + filter.flags |= ifa_flag_names[i].value; + filter.flagmask |= ifa_flag_names[i].value; + return 0; + } + return -1; + } + + return 0; +} + int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = arg; struct ifaddrmsg *ifa = NLMSG_DATA(n); int len = n->nlmsg_len; - int deprecated = 0; - /* Use local copy of ifa_flags to not interfere with filtering code */ unsigned int ifa_flags; struct rtattr *rta_tb[IFA_MAX+1]; @@ -1144,52 +1225,9 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, rta_tb[IFA_ANYCAST])); } fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); - if (ifa_flags & IFA_F_SECONDARY) { - ifa_flags &= ~IFA_F_SECONDARY; - if (ifa->ifa_family == AF_INET6) - fprintf(fp, "temporary "); - else - fprintf(fp, "secondary "); - } - if (ifa_flags & IFA_F_TENTATIVE) { - ifa_flags &= ~IFA_F_TENTATIVE; - fprintf(fp, "tentative "); - } - if (ifa_flags & IFA_F_DEPRECATED) { - ifa_flags &= ~IFA_F_DEPRECATED; - deprecated = 1; - fprintf(fp, "deprecated "); - } - if (ifa_flags & IFA_F_HOMEADDRESS) { - ifa_flags &= ~IFA_F_HOMEADDRESS; - fprintf(fp, "home "); - } - if (ifa_flags & IFA_F_NODAD) { - ifa_flags &= ~IFA_F_NODAD; - fprintf(fp, "nodad "); - } - if (ifa_flags & IFA_F_MANAGETEMPADDR) { - ifa_flags &= ~IFA_F_MANAGETEMPADDR; - fprintf(fp, "mngtmpaddr "); - } - if (ifa_flags & IFA_F_NOPREFIXROUTE) { - ifa_flags &= ~IFA_F_NOPREFIXROUTE; - fprintf(fp, "noprefixroute "); - } - if (ifa_flags & IFA_F_MCAUTOJOIN) { - ifa_flags &= ~IFA_F_MCAUTOJOIN; - fprintf(fp, "autojoin "); - } - if (!(ifa_flags & IFA_F_PERMANENT)) - fprintf(fp, "dynamic "); - else - ifa_flags &= ~IFA_F_PERMANENT; - if (ifa_flags & IFA_F_DADFAILED) { - ifa_flags &= ~IFA_F_DADFAILED; - fprintf(fp, "dadfailed "); - } - if (ifa_flags) - fprintf(fp, "flags %02x ", ifa_flags); + + print_ifa_flags(fp, ifa, ifa_flags); + if (rta_tb[IFA_LABEL]) fprintf(fp, "%s", rta_getattr_str(rta_tb[IFA_LABEL])); if (rta_tb[IFA_CACHEINFO]) { @@ -1205,7 +1243,7 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, if (ci->ifa_prefered == INFINITY_LIFE_TIME) fprintf(fp, "forever"); else { - if (deprecated) + if (ifa_flags & IFA_F_DEPRECATED) fprintf(fp, "%dsec", ci->ifa_prefered); else fprintf(fp, "%usec", ci->ifa_prefered); @@ -1608,52 +1646,8 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) filter.scope = scope; } else if (strcmp(*argv, "up") == 0) { filter.up = 1; - } else if (strcmp(*argv, "dynamic") == 0) { - filter.flags &= ~IFA_F_PERMANENT; - filter.flagmask |= IFA_F_PERMANENT; - } else if (strcmp(*argv, "permanent") == 0) { - filter.flags |= IFA_F_PERMANENT; - filter.flagmask |= IFA_F_PERMANENT; - } else if (strcmp(*argv, "secondary") == 0 || - strcmp(*argv, "temporary") == 0) { - filter.flags |= IFA_F_SECONDARY; - filter.flagmask |= IFA_F_SECONDARY; - } else if (strcmp(*argv, "primary") == 0) { - filter.flags &= ~IFA_F_SECONDARY; - filter.flagmask |= IFA_F_SECONDARY; - } else if (strcmp(*argv, "tentative") == 0) { - filter.flags |= IFA_F_TENTATIVE; - filter.flagmask |= IFA_F_TENTATIVE; - } else if (strcmp(*argv, "-tentative") == 0) { - filter.flags &= ~IFA_F_TENTATIVE; - filter.flagmask |= IFA_F_TENTATIVE; - } else if (strcmp(*argv, "deprecated") == 0) { - filter.flags |= IFA_F_DEPRECATED; - filter.flagmask |= IFA_F_DEPRECATED; - } else if (strcmp(*argv, "-deprecated") == 0) { - filter.flags &= ~IFA_F_DEPRECATED; - filter.flagmask |= IFA_F_DEPRECATED; - } else if (strcmp(*argv, "home") == 0) { - filter.flags |= IFA_F_HOMEADDRESS; - filter.flagmask |= IFA_F_HOMEADDRESS; - } else if (strcmp(*argv, "nodad") == 0) { - filter.flags |= IFA_F_NODAD; - filter.flagmask |= IFA_F_NODAD; - } else if (strcmp(*argv, "mngtmpaddr") == 0) { - filter.flags |= IFA_F_MANAGETEMPADDR; - filter.flagmask |= IFA_F_MANAGETEMPADDR; - } else if (strcmp(*argv, "noprefixroute") == 0) { - filter.flags |= IFA_F_NOPREFIXROUTE; - filter.flagmask |= IFA_F_NOPREFIXROUTE; - } else if (strcmp(*argv, "autojoin") == 0) { - filter.flags |= IFA_F_MCAUTOJOIN; - filter.flagmask |= IFA_F_MCAUTOJOIN; - } else if (strcmp(*argv, "dadfailed") == 0) { - filter.flags |= IFA_F_DADFAILED; - filter.flagmask |= IFA_F_DADFAILED; - } else if (strcmp(*argv, "-dadfailed") == 0) { - filter.flags &= ~IFA_F_DADFAILED; - filter.flagmask |= IFA_F_DADFAILED; + } else if (get_filter(*argv) == 0) { + } else if (strcmp(*argv, "label") == 0) { NEXT_ARG(); filter.label = *argv; diff --git a/lib/bpf.c b/lib/bpf.c index e7a4d12f..4f52ad4a 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -208,11 +208,11 @@ static int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, if (from_file) { size_t tmp_len, op_len = sizeof("65535 255 255 4294967295,"); - char *tmp_string, *last; + char *tmp_string, *pos, c, c_prev = ' '; FILE *fp; tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len; - tmp_string = calloc(1, tmp_len); + tmp_string = pos = calloc(1, tmp_len); if (tmp_string == NULL) return -ENOMEM; @@ -223,17 +223,33 @@ static int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, return -ENOENT; } - if (!fgets(tmp_string, tmp_len, fp)) { + while ((c = fgetc(fp)) != EOF) { + switch (c) { + case '\n': + if (c_prev != ',') + *(pos++) = ','; + break; + case ' ': + case '\t': + if (c_prev != ' ') + *(pos++) = c; + break; + default: + *(pos++) = c; + } + if (pos - tmp_string == tmp_len) + break; + c_prev = c; + } + + if (!feof(fp)) { free(tmp_string); fclose(fp); - return -EIO; + return -E2BIG; } fclose(fp); - - last = &tmp_string[strlen(tmp_string) - 1]; - if (*last == '\n') - *last = 0; + *pos = 0; *need_release = true; *bpf_string = tmp_string; diff --git a/lib/utils.c b/lib/utils.c index 9aa3219c..9143ed22 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -616,12 +616,19 @@ done: return err; } +static const char *family_name_verbose(int family) +{ + if (family == AF_UNSPEC) + return "any valid"; + return family_name(family); +} + int get_addr(inet_prefix *dst, const char *arg, int family) { if (get_addr_1(dst, arg, family)) { fprintf(stderr, "Error: %s address is expected rather than \"%s\".\n", - family_name(dst->family), arg); + family_name_verbose(family), arg); exit(1); } return 0; @@ -639,7 +646,7 @@ int get_prefix(inet_prefix *dst, char *arg, int family) if (get_prefix_1(dst, arg, family)) { fprintf(stderr, "Error: %s prefix is expected rather than \"%s\".\n", - family_name(dst->family), arg); + family_name_verbose(family), arg); exit(1); } return 0; diff --git a/man/man8/tc-simple.8 b/man/man8/tc-simple.8 index 2206dc3b..7363ab56 100644 --- a/man/man8/tc-simple.8 +++ b/man/man8/tc-simple.8 @@ -6,15 +6,37 @@ simple - basic example action .in +8 .ti -8 .BR tc " ... " "action simple" -.I STRING +[ +.BI sdata " STRING" +] [ +.BI index " INDEX" +] [ +.I CONTROL +] + +.ti -8 +.IR CONTROL " := {" +.BR reclassify " | " pipe " | " drop " | " continue " | " ok " }" + .SH DESCRIPTION This is a pedagogical example rather than an actually useful action. Upon every access, it prints the given .I STRING which may be of arbitrary length. .SH OPTIONS .TP -.I STRING +.BI sdata " STRING" The actual string to print. +.TP +.BI index " INDEX" +Optional action index value. +.TP +.I CONTROL +Indicate how +.B tc +should proceed after executing the action. For a description of the possible +.I CONTROL +values, see +.BR tc-actions (8). .SH EXAMPLES The following example makes the kernel yell "Incoming ICMP!" every time it sees an incoming ICMP on eth0. Steps are: @@ -36,7 +58,7 @@ display stats again and observe increment by 1 .EX hadi@noma1:$ tc qdisc add dev eth0 ingress hadi@noma1:$tc filter add dev eth0 parent ffff: protocol ip prio 5 \\ - u32 match ip protocol 1 0xff flowid 1:1 action simple "Incoming ICMP" + u32 match ip protocol 1 0xff flowid 1:1 action simple sdata "Incoming ICMP" hadi@noma1:$ sudo tc -s filter ls dev eth0 parent ffff: filter protocol ip pref 5 u32 @@ -74,3 +96,4 @@ display stats again and observe increment by 1 .EE .SH SEE ALSO .BR tc (8) +.BR tc-actions (8) diff --git a/tc/m_simple.c b/tc/m_simple.c index a4457c70..f8937bca 100644 --- a/tc/m_simple.c +++ b/tc/m_simple.c @@ -81,10 +81,10 @@ #endif static void explain(void) { - fprintf(stderr, "Usage:... simple [sdata STRING] [CONTROL] [index INDEX]\n"); + fprintf(stderr, "Usage:... simple [sdata STRING] [index INDEX] [CONTROL]\n"); fprintf(stderr, "\tSTRING being an arbitrary string\n" - "\tCONTROL := reclassify|pipe|drop|continue|ok\n" - "\tINDEX := optional index value used\n"); + "\tINDEX := optional index value used\n" + "\tCONTROL := reclassify|pipe|drop|continue|ok\n"); } static void usage(void)