diff --git a/bridge/Makefile b/bridge/Makefile index 7203f70b..634c370a 100644 --- a/bridge/Makefile +++ b/bridge/Makefile @@ -8,7 +8,7 @@ endif all: bridge -bridge: $(BROBJ) $(LIBNETLINK) +bridge: $(BROBJ) $(LIBNETLINK) $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ install: all @@ -16,4 +16,3 @@ install: all clean: rm -f $(BROBJ) bridge - diff --git a/bridge/fdb.c b/bridge/fdb.c index a9152177..a71a78f2 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -29,7 +29,7 @@ #include "rt_names.h" #include "utils.h" -static unsigned int filter_index, filter_vlan; +static unsigned int filter_index, filter_vlan, filter_state; json_writer_t *jw_global; @@ -39,7 +39,7 @@ static void usage(void) " [ self ] [ master ] [ use ] [ router ]\n" " [ local | static | dynamic ] [ dst IPADDR ] [ vlan VID ]\n" " [ port PORT] [ vni VNI ] [ via DEV ]\n"); - fprintf(stderr, " bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] ]\n"); + fprintf(stderr, " bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] [ state STATE ] ]\n"); exit(-1); } @@ -63,6 +63,24 @@ static const char *state_n2a(unsigned int s) return buf; } +static int state_a2n(unsigned int *s, const char *arg) +{ + if (matches(arg, "permanent") == 0) + *s = NUD_PERMANENT; + else if (matches(arg, "static") == 0 || matches(arg, "temp") == 0) + *s = NUD_NOARP; + else if (matches(arg, "stale") == 0) + *s = NUD_STALE; + else if (matches(arg, "reachable") == 0 || matches(arg, "dynamic") == 0) + *s = NUD_REACHABLE; + else if (strcmp(arg, "all") == 0) + *s = ~0; + else if (get_unsigned(s, arg, 0)) + return -1; + + return 0; +} + static void start_json_fdb_flags_array(bool *fdb_flags) { if (*fdb_flags) @@ -100,6 +118,9 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (filter_index && filter_index != r->ndm_ifindex) return 0; + if (filter_state && !(r->ndm_state & filter_state)) + return 0; + parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); @@ -310,6 +331,13 @@ static int fdb_show(int argc, char **argv) if (filter_vlan) duparg("vlan", *argv); filter_vlan = atoi(*argv); + } else if (strcmp(*argv, "state") == 0) { + unsigned int state; + + NEXT_ARG(); + if (state_a2n(&state, *argv)) + invarg("invalid state", *argv); + filter_state |= state; } else { if (matches(*argv, "help") == 0) usage(); diff --git a/etc/iproute2/nl_protos b/etc/iproute2/nl_protos index 43418f36..7c17cf0f 100644 --- a/etc/iproute2/nl_protos +++ b/etc/iproute2/nl_protos @@ -12,7 +12,7 @@ 9 audit 10 fiblookup 11 connector -12 nft +12 nft 13 ip6fw 14 dec-rt 15 uevent @@ -20,4 +20,4 @@ 18 scsi-trans 19 ecryptfs 20 rdma -21 crypto +21 crypto diff --git a/etc/iproute2/rt_protos.d/README b/etc/iproute2/rt_protos.d/README new file mode 100644 index 00000000..f9c599c6 --- /dev/null +++ b/etc/iproute2/rt_protos.d/README @@ -0,0 +1,2 @@ +Each file in this directory is an rt_protos configuration file. iproute2 +commands scan this directory processing all files that end in '.conf'. diff --git a/etc/iproute2/rt_tables.d/README b/etc/iproute2/rt_tables.d/README index 79386f89..0920cb16 100644 --- a/etc/iproute2/rt_tables.d/README +++ b/etc/iproute2/rt_tables.d/README @@ -1,3 +1,2 @@ Each file in this directory is an rt_tables configuration file. iproute2 commands scan this directory processing all files that end in '.conf'. - diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c index b1c0ae62..b4a7def1 100644 --- a/ip/ip6tunnel.c +++ b/ip/ip6tunnel.c @@ -111,16 +111,17 @@ static void print_tunnel(struct ip6_tnl_parm2 *p) if (p->flags & IP6_TNL_F_RCV_DSCP_COPY) printf(" dscp inherit"); - if (p->proto == IPPROTO_GRE) { - if ((p->i_flags & GRE_KEY) && (p->o_flags & GRE_KEY) && p->o_key == p->i_key) - printf(" key %u", ntohl(p->i_key)); - else if ((p->i_flags | p->o_flags) & GRE_KEY) { - if (p->i_flags & GRE_KEY) - printf(" ikey %u", ntohl(p->i_key)); - if (p->o_flags & GRE_KEY) - printf(" okey %u", ntohl(p->o_key)); - } + if ((p->i_flags & GRE_KEY) && (p->o_flags & GRE_KEY) && + p->o_key == p->i_key) + printf(" key %u", ntohl(p->i_key)); + else { + if (p->i_flags & GRE_KEY) + printf(" ikey %u", ntohl(p->i_key)); + if (p->o_flags & GRE_KEY) + printf(" okey %u", ntohl(p->o_key)); + } + if (p->proto == IPPROTO_GRE) { if (p->i_flags & GRE_SEQ) printf("%s Drop packets out of sequence.", _SL_); if (p->i_flags & GRE_CSUM) diff --git a/ip/ipvrf.c b/ip/ipvrf.c index dc8364a4..8bd99d62 100644 --- a/ip/ipvrf.c +++ b/ip/ipvrf.c @@ -181,7 +181,11 @@ static int vrf_configure_cgroup(const char *path, int ifindex) if (prog_fd < 0) { fprintf(stderr, "Failed to load BPF prog: '%s'\n", strerror(errno)); - fprintf(stderr, "Kernel compiled with CGROUP_BPF enabled?\n"); + + if (errno != EPERM) { + fprintf(stderr, + "Kernel compiled with CGROUP_BPF enabled?\n"); + } goto out; } diff --git a/lib/Makefile b/lib/Makefile index 0c57662b..1d24ca24 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -24,4 +24,3 @@ install: clean: rm -f $(NLOBJ) $(UTILOBJ) $(ADDLIB) libnetlink.a libutil.a - diff --git a/lib/fs.c b/lib/fs.c index 39cc96dc..12a4657a 100644 --- a/lib/fs.c +++ b/lib/fs.c @@ -80,13 +80,21 @@ char *find_cgroup2_mount(void) if (mount("none", mnt, CGROUP2_FS_NAME, 0, NULL)) { /* EBUSY means already mounted */ - if (errno != EBUSY) { + if (errno == EBUSY) + goto out; + + if (errno == ENODEV) { fprintf(stderr, "Failed to mount cgroup2. Are CGROUPS enabled in your kernel?\n"); - free(mnt); - return NULL; + } else { + fprintf(stderr, + "Failed to mount cgroup2: %s\n", + strerror(errno)); } + free(mnt); + return NULL; } +out: return mnt; } @@ -121,7 +129,7 @@ int make_path(const char *path, mode_t mode) if (mkdir(dir, mode) != 0) { fprintf(stderr, - "mkdir failed for %s: %s", + "mkdir failed for %s: %s\n", dir, strerror(errno)); goto out; } diff --git a/lib/rt_names.c b/lib/rt_names.c index c66cb1e4..3a16d5cf 100644 --- a/lib/rt_names.c +++ b/lib/rt_names.c @@ -142,9 +142,36 @@ static int rtnl_rtprot_init; static void rtnl_rtprot_initialize(void) { + struct dirent *de; + DIR *d; + rtnl_rtprot_init = 1; rtnl_tab_initialize(CONFDIR "/rt_protos", rtnl_rtprot_tab, 256); + + d = opendir(CONFDIR "/rt_protos.d"); + if (!d) + return; + + while ((de = readdir(d)) != NULL) { + char path[PATH_MAX]; + size_t len; + + if (*de->d_name == '.') + continue; + + /* only consider filenames ending in '.conf' */ + len = strlen(de->d_name); + if (len <= 5) + continue; + if (strcmp(de->d_name + len - 5, ".conf")) + continue; + + snprintf(path, sizeof(path), CONFDIR "/rt_protos.d/%s", + de->d_name); + rtnl_tab_initialize(path, rtnl_rtprot_tab, 256); + } + closedir(d); } const char *rtnl_rtprot_n2a(int id, char *buf, int len) @@ -404,7 +431,7 @@ int rtnl_rttable_a2n(__u32 *id, const char *arg) static unsigned long res; struct rtnl_hash_entry *entry; char *end; - __u32 i; + unsigned long i; if (cache && strcmp(cache, arg) == 0) { *id = res; diff --git a/man/man3/libnetlink.3 b/man/man3/libnetlink.3 index 99be9cc9..8e3dc620 100644 --- a/man/man3/libnetlink.3 +++ b/man/man3/libnetlink.3 @@ -32,12 +32,12 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, .br void *jarg) .sp -int rtnl_listen(struct rtnl_handle *rtnl, +int rtnl_listen(struct rtnl_handle *rtnl, int (*handler)(struct sockaddr_nl *, struct rtnl_ctrl_data *, struct nlmsghdr *n, void *), void *jarg) .sp -int rtnl_from_file(FILE *rtnl, +int rtnl_from_file(FILE *rtnl, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg) .sp @@ -49,35 +49,35 @@ int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) .sp int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) .SH DESCRIPTION -libnetlink provides a higher level interface to -.BR rtnetlink(7). +libnetlink provides a higher level interface to +.BR rtnetlink(7). The read functions return 0 on success and a negative errno on failure. The send functions return the amount of data sent, or -1 on error. -.TP +.TP rtnl_open Open a rtnetlink socket and save the state into the .B rth -handle. This handle is passed to all subsequent calls. +handle. This handle is passed to all subsequent calls. .B subscriptions is a bitmap of the rtnetlink multicast groups the socket will be a member of. .TP rtnl_wilddump_request -Request a full dump of the +Request a full dump of the .B type database for .B family addresses. .B type -is a rtnetlink message type. +is a rtnetlink message type. .\" XXX .TP rtnl_dump_request -Request a full dump of the -.B type -data buffer into +Request a full dump of the +.B type +data buffer into .B buf with maximum length of .B len. @@ -91,12 +91,12 @@ The .B filter callback checks if the received message is wanted. It gets the source address of the message, the message itself and -.B arg1 +.B arg1 as arguments. 0 as return means that the filter passed, a negative value is returned by -.I rtnl_dump_filter -in case of error. NULL for +.I rtnl_dump_filter +in case of error. NULL for .I filter means to not use a filter. .B junk @@ -106,7 +106,7 @@ pending, this function does not block. .TP rtnl_listen -Receive netlink data after a request and pass it to +Receive netlink data after a request and pass it to .I handler. .B handler is a callback that gets the message source address, anscillary data, the message @@ -118,8 +118,8 @@ pending this function does not block. .TP rtnl_from_file -Works like -.I rtnl_listen, +Works like +.I rtnl_listen, but reads a netlink message bundle from the file .B file and passes the messages to @@ -134,7 +134,7 @@ and .BR netlink(3) on how to generate a rtnetlink message. The following utility functions require a continuous buffer that already contains a netlink message header -and a rtnetlink request. +and a rtnetlink request. .TP rtnl_send @@ -168,7 +168,7 @@ length to netlink message .B n, which is part of a buffer of length .B maxlen. -.B data +.B data is copied. .TP diff --git a/man/man8/.gitignore b/man/man8/.gitignore index 4f1a476d..0c3d1504 100644 --- a/man/man8/.gitignore +++ b/man/man8/.gitignore @@ -2,4 +2,3 @@ ip-address.8 ip-link.8 ip-route.8 - diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index 6617e188..9c5f855d 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -70,7 +70,15 @@ bridge \- show / manipulate bridge addresses and devices .ti -8 .BR "bridge fdb" " [ " show " ] [ " .B dev -.IR DEV " ]" +.IR DEV " ] [ " +.B br +.IR BRDEV " ] [ " +.B brport +.IR DEV " ] [ " +.B vlan +.IR VID " ] [ " +.B state +.IR STATE " ]" .ti -8 .BR "bridge mdb" " { " add " | " del " } " diff --git a/man/man8/tc-ife.8 b/man/man8/tc-ife.8 index aaf0f97d..dae8b9be 100644 --- a/man/man8/tc-ife.8 +++ b/man/man8/tc-ife.8 @@ -99,7 +99,7 @@ classification so that it will match ICMP on the next rule, at prio 3: # tc filter add dev eth0 parent ffff: prio 2 protocol 0xdead \\ u32 match u32 0 0 flowid 1:1 \\ action ife decode reclassify -# tc filter add dev eth0 parent ffff: priod 3 protocol ip \\ +# tc filter add dev eth0 parent ffff: prio 3 protocol ip \\ u32 match ip protocol 0xff flowid 1:1 \\ action continue .EE diff --git a/netem/Makefile b/netem/Makefile index e52e125e..a68e2fdb 100644 --- a/netem/Makefile +++ b/netem/Makefile @@ -3,7 +3,7 @@ DISTDATA = normal.dist pareto.dist paretonormal.dist experimental.dist HOSTCC ?= $(CC) CCOPTS = $(CBUILD_CFLAGS) -LDLIBS += -lm +LDLIBS += -lm all: $(DISTGEN) $(DISTDATA) diff --git a/tc/m_xt.c b/tc/m_xt.c index dbb54981..57ed40d7 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -77,6 +77,9 @@ static struct xtables_globals tcipt_globals = { .orig_opts = original_opts, .opts = original_opts, .exit_err = NULL, +#if (XTABLES_VERSION_CODE >= 11) + .compat_rev = xtables_compatible_revision, +#endif }; /*