Merge branch 'master' into net-next
diff --git a/include/libnetlink.h b/include/libnetlink.h
index 0503dea..4813359 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -42,6 +42,8 @@
int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req,
int len)
__attribute__((warn_unused_result));
+int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
+ __attribute__((warn_unused_result));
struct rtnl_ctrl_data {
int nsid;
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 3d6d00b..689be2e 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -272,6 +272,21 @@
BPF_FUNC_skb_get_tunnel_key,
BPF_FUNC_skb_set_tunnel_key,
BPF_FUNC_perf_event_read, /* u64 bpf_perf_event_read(&map, index) */
+ /**
+ * bpf_redirect(ifindex, flags) - redirect to another netdev
+ * @ifindex: ifindex of the net device
+ * @flags: bit 0 - if set, redirect to ingress instead of egress
+ * other bits - reserved
+ * Return: TC_ACT_REDIRECT
+ */
+ BPF_FUNC_redirect,
+
+ /**
+ * bpf_get_route_realm(skb) - retrieve a dst's tclassid
+ * @skb: pointer to skb
+ * Return: realm if != 0
+ */
+ BPF_FUNC_get_route_realm,
__BPF_FUNC_MAX_ID,
};
@@ -293,6 +308,7 @@
__u32 tc_index;
__u32 cb[5];
__u32 hash;
+ __u32 tc_classid;
};
struct bpf_tunnel_key {
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index f24050b..ee197a3 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -127,6 +127,7 @@
#define BRIDGE_VLAN_INFO_UNTAGGED (1<<2) /* VLAN egresses untagged */
#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
+#define BRIDGE_VLAN_INFO_BRENTRY (1<<5) /* Global bridge VLAN entry */
struct bridge_vlan_info {
__u16 flags;
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 1934566..288d3cd 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -230,11 +230,47 @@
IFLA_BR_PRIORITY,
IFLA_BR_VLAN_FILTERING,
IFLA_BR_VLAN_PROTOCOL,
+ IFLA_BR_GROUP_FWD_MASK,
+ IFLA_BR_ROOT_ID,
+ IFLA_BR_BRIDGE_ID,
+ IFLA_BR_ROOT_PORT,
+ IFLA_BR_ROOT_PATH_COST,
+ IFLA_BR_TOPOLOGY_CHANGE,
+ IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
+ IFLA_BR_HELLO_TIMER,
+ IFLA_BR_TCN_TIMER,
+ IFLA_BR_TOPOLOGY_CHANGE_TIMER,
+ IFLA_BR_GC_TIMER,
+ IFLA_BR_GROUP_ADDR,
+ IFLA_BR_FDB_FLUSH,
+ IFLA_BR_MCAST_ROUTER,
+ IFLA_BR_MCAST_SNOOPING,
+ IFLA_BR_MCAST_QUERY_USE_IFADDR,
+ IFLA_BR_MCAST_QUERIER,
+ IFLA_BR_MCAST_HASH_ELASTICITY,
+ IFLA_BR_MCAST_HASH_MAX,
+ IFLA_BR_MCAST_LAST_MEMBER_CNT,
+ IFLA_BR_MCAST_STARTUP_QUERY_CNT,
+ IFLA_BR_MCAST_LAST_MEMBER_INTVL,
+ IFLA_BR_MCAST_MEMBERSHIP_INTVL,
+ IFLA_BR_MCAST_QUERIER_INTVL,
+ IFLA_BR_MCAST_QUERY_INTVL,
+ IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
+ IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
+ IFLA_BR_NF_CALL_IPTABLES,
+ IFLA_BR_NF_CALL_IP6TABLES,
+ IFLA_BR_NF_CALL_ARPTABLES,
+ IFLA_BR_VLAN_DEFAULT_PVID,
__IFLA_BR_MAX,
};
#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
+struct ifla_bridge_id {
+ __u8 prio[2];
+ __u8 addr[6]; /* ETH_ALEN */
+};
+
enum {
BRIDGE_MODE_UNSPEC,
BRIDGE_MODE_HAIRPIN,
@@ -254,6 +290,19 @@
IFLA_BRPORT_PROXYARP, /* proxy ARP */
IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */
IFLA_BRPORT_PROXYARP_WIFI, /* proxy ARP for Wi-Fi */
+ IFLA_BRPORT_ROOT_ID, /* designated root */
+ IFLA_BRPORT_BRIDGE_ID, /* designated bridge */
+ IFLA_BRPORT_DESIGNATED_PORT,
+ IFLA_BRPORT_DESIGNATED_COST,
+ IFLA_BRPORT_ID,
+ IFLA_BRPORT_NO,
+ IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
+ IFLA_BRPORT_CONFIG_PENDING,
+ IFLA_BRPORT_MESSAGE_AGE_TIMER,
+ IFLA_BRPORT_FORWARD_DELAY_TIMER,
+ IFLA_BRPORT_HOLD_TIMER,
+ IFLA_BRPORT_FLUSH,
+ IFLA_BRPORT_MULTICAST_ROUTER,
__IFLA_BRPORT_MAX
};
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 352b5b8..8a7ca5c 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -54,6 +54,7 @@
#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */
#define NLM_F_ECHO 8 /* Echo this request */
#define NLM_F_DUMP_INTR 16 /* Dump was inconsistent due to sequence change */
+#define NLM_F_DUMP_FILTERED 32 /* Dump was filtered as requested */
/* Modifiers to GET request */
#define NLM_F_ROOT 0x100 /* specify tree root */
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index 25af89f..a323146 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -33,6 +33,7 @@
#define TC_ACT_STOLEN 4
#define TC_ACT_QUEUED 5
#define TC_ACT_REPEAT 6
+#define TC_ACT_REDIRECT 7
#define TC_ACT_JUMP 0x10000000
/* Action type identifiers*/
@@ -319,6 +320,8 @@
/* BPF classifier */
+#define TCA_BPF_FLAG_ACT_DIRECT (1 << 0)
+
enum {
TCA_BPF_UNSPEC,
TCA_BPF_ACT,
@@ -328,6 +331,7 @@
TCA_BPF_OPS,
TCA_BPF_FD,
TCA_BPF_NAME,
+ TCA_BPF_FLAGS,
__TCA_BPF_MAX,
};
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 3fe10b0..10452e0 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -270,6 +270,7 @@
#define RTM_F_CLONED 0x200 /* This route is cloned */
#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */
#define RTM_F_PREFIX 0x800 /* Prefix addresses */
+#define RTM_F_LOOKUP_TABLE 0x1000 /* set rtm_table to FIB lookup result */
/* Reserved table identifiers */
@@ -664,6 +665,7 @@
#define RTEXT_FILTER_VF (1 << 0)
#define RTEXT_FILTER_BRVLAN (1 << 1)
#define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2)
+#define RTEXT_FILTER_SKIP_STATS (1 << 3)
/* End of information exported to user level */
diff --git a/include/utils.h b/include/utils.h
index f77edeb..668d159 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -47,6 +47,7 @@
#define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0)
#define NEXT_ARG_OK() (argc - 1 > 0)
+#define NEXT_ARG_FWD() do { argv++; argc--; } while(0)
#define PREV_ARG() do { argv--; argc++; } while(0)
typedef struct
diff --git a/ip/ipneigh.c b/ip/ipneigh.c
index a9e23f4..ded514d 100644
--- a/ip/ipneigh.c
+++ b/ip/ipneigh.c
@@ -39,6 +39,7 @@
char *flushb;
int flushp;
int flushe;
+ int master;
} filter;
static void usage(void) __attribute__((noreturn));
@@ -193,6 +194,7 @@
int len = n->nlmsg_len;
struct rtattr * tb[NDA_MAX+1];
char abuf[256];
+ static int logit = 1;
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
n->nlmsg_type != RTM_GETNEIGH) {
@@ -220,6 +222,14 @@
(r->ndm_family != AF_DECnet))
return 0;
+ if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) {
+ if (logit) {
+ logit = 0;
+ fprintf(fp,
+ "\nWARNING: Kernel does not support filtering by master device\n\n");
+ }
+ }
+
parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
if (tb[NDA_DST]) {
@@ -327,9 +337,18 @@
static int do_show_or_flush(int argc, char **argv, int flush)
{
+ struct {
+ struct nlmsghdr n;
+ struct ndmsg ndm;
+ char buf[256];
+ } req;
char *filter_dev = NULL;
int state_given = 0;
- struct ndmsg ndm = { 0 };
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_type = RTM_GETNEIGH;
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
ipneigh_reset_filter(0);
@@ -351,6 +370,14 @@
if (filter_dev)
duparg("dev", *argv);
filter_dev = *argv;
+ } else if (strcmp(*argv, "master") == 0) {
+ int ifindex;
+ NEXT_ARG();
+ ifindex = ll_name_to_index(*argv);
+ if (!ifindex)
+ invarg("Device does not exist\n", *argv);
+ addattr32(&req.n, sizeof(req), NDA_MASTER, ifindex);
+ filter.master = ifindex;
} else if (strcmp(*argv, "unused") == 0) {
filter.unused_only = 1;
} else if (strcmp(*argv, "nud") == 0) {
@@ -371,7 +398,7 @@
state = 0x100;
filter.state |= state;
} else if (strcmp(*argv, "proxy") == 0)
- ndm.ndm_flags = NTF_PROXY;
+ req.ndm.ndm_flags = NTF_PROXY;
else {
if (strcmp(*argv, "to") == 0) {
NEXT_ARG();
@@ -392,6 +419,7 @@
fprintf(stderr, "Cannot find device \"%s\"\n", filter_dev);
return -1;
}
+ addattr32(&req.n, sizeof(req), NDA_IFINDEX, filter.index);
}
if (flush) {
@@ -436,9 +464,9 @@
return 1;
}
- ndm.ndm_family = filter.family;
+ req.ndm.ndm_family = filter.family;
- if (rtnl_dump_request(&rth, RTM_GETNEIGH, &ndm, sizeof(struct ndmsg)) < 0) {
+ if (rtnl_dump_request_n(&rth, &req.n) < 0) {
perror("Cannot send dump request");
exit(1);
}
diff --git a/ip/iproute.c b/ip/iproute.c
index da25548..b0cd299 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -424,9 +424,9 @@
if (tb[RTA_OIF] && filter.oifmask != -1)
fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
+ if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
+ fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
if (!(r->rtm_flags&RTM_F_CLONED)) {
- if ((table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
- fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1)
fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1)
@@ -1642,6 +1642,8 @@
if (req.r.rtm_family == AF_UNSPEC)
req.r.rtm_family = AF_INET;
+ req.r.rtm_flags |= RTM_F_LOOKUP_TABLE;
+
if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
exit(2);
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 46cac34..8e3762c 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -191,6 +191,27 @@
return sendmsg(rth->fd, &msg, 0);
}
+int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
+{
+ struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
+ struct iovec iov = {
+ .iov_base = (void*) n,
+ .iov_len = n->nlmsg_len
+ };
+ struct msghdr msg = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+
+ n->nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
+ n->nlmsg_pid = 0;
+ n->nlmsg_seq = rth->dump = ++rth->seq;
+
+ return sendmsg(rth->fd, &msg, 0);
+}
+
int rtnl_dump_filter_l(struct rtnl_handle *rth,
const struct rtnl_dump_filter_arg *arg)
{
diff --git a/tc/f_bpf.c b/tc/f_bpf.c
index 490dc6b..ac77af5 100644
--- a/tc/f_bpf.c
+++ b/tc/f_bpf.c
@@ -41,7 +41,7 @@
fprintf(stderr, "\n");
fprintf(stderr, "eBPF use case:\n");
fprintf(stderr, " object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]");
- fprintf(stderr, " [ verbose ]\n");
+ fprintf(stderr, " [ verbose ] [ direct-action ]\n");
fprintf(stderr, "\n");
fprintf(stderr, "Common remaining options:\n");
fprintf(stderr, " [ action ACTION_SPEC ]\n");
@@ -69,6 +69,7 @@
struct tcmsg *t = NLMSG_DATA(n);
const char *bpf_uds_name = NULL;
const char *bpf_sec_name = NULL;
+ unsigned int bpf_flags = 0;
char *bpf_obj = NULL;
struct rtattr *tail;
bool seen_run = false;
@@ -124,25 +125,28 @@
if (ebpf) {
bpf_uds_name = getenv(BPF_ENV_UDS);
bpf_obj = *argv;
- NEXT_ARG();
- if (strcmp(*argv, "section") == 0 ||
- strcmp(*argv, "sec") == 0) {
+ NEXT_ARG_FWD();
+
+ if (argc > 0 &&
+ (strcmp(*argv, "section") == 0 ||
+ strcmp(*argv, "sec") == 0)) {
NEXT_ARG();
bpf_sec_name = *argv;
- NEXT_ARG();
+ NEXT_ARG_FWD();
}
- if (!bpf_uds_name &&
+ if (argc > 0 && !bpf_uds_name &&
(strcmp(*argv, "export") == 0 ||
strcmp(*argv, "exp") == 0)) {
NEXT_ARG();
bpf_uds_name = *argv;
- NEXT_ARG();
+ NEXT_ARG_FWD();
}
- if (strcmp(*argv, "verbose") == 0 ||
- strcmp(*argv, "verb") == 0) {
+ if (argc > 0 &&
+ (strcmp(*argv, "verbose") == 0 ||
+ strcmp(*argv, "verb") == 0)) {
bpf_verbose = true;
- NEXT_ARG();
+ NEXT_ARG_FWD();
}
PREV_ARG();
@@ -182,7 +186,10 @@
fprintf(stderr, "Illegal \"classid\"\n");
return -1;
}
- addattr_l(n, MAX_MSG, TCA_BPF_CLASSID, &handle, 4);
+ addattr32(n, MAX_MSG, TCA_BPF_CLASSID, handle);
+ } else if (matches(*argv, "direct-action") == 0 ||
+ matches(*argv, "da") == 0) {
+ bpf_flags |= TCA_BPF_FLAG_ACT_DIRECT;
} else if (matches(*argv, "action") == 0) {
NEXT_ARG();
if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) {
@@ -208,10 +215,13 @@
explain();
return -1;
}
- argc--;
- argv++;
+
+ NEXT_ARG_FWD();
}
+ if (bpf_obj && bpf_flags)
+ addattr32(n, MAX_MSG, TCA_BPF_FLAGS, bpf_flags);
+
tail->rta_len = (((void *)n) + n->nlmsg_len) - (void *)tail;
if (bpf_uds_name)
@@ -244,6 +254,13 @@
else if (tb[TCA_BPF_FD])
fprintf(f, "pfd %u ", rta_getattr_u32(tb[TCA_BPF_FD]));
+ if (tb[TCA_BPF_FLAGS]) {
+ unsigned int flags = rta_getattr_u32(tb[TCA_BPF_FLAGS]);
+
+ if (flags & TCA_BPF_FLAG_ACT_DIRECT)
+ fprintf(f, "direct-action ");
+ }
+
if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN]) {
bpf_print_ops(f, tb[TCA_BPF_OPS],
rta_getattr_u16(tb[TCA_BPF_OPS_LEN]));
diff --git a/tc/m_bpf.c b/tc/m_bpf.c
index e1bb6a4..fb4c3c7 100644
--- a/tc/m_bpf.c
+++ b/tc/m_bpf.c
@@ -111,25 +111,28 @@
if (ebpf) {
bpf_uds_name = getenv(BPF_ENV_UDS);
bpf_obj = *argv;
- NEXT_ARG();
- if (strcmp(*argv, "section") == 0 ||
- strcmp(*argv, "sec") == 0) {
+ NEXT_ARG_FWD();
+
+ if (argc > 0 &&
+ (strcmp(*argv, "section") == 0 ||
+ strcmp(*argv, "sec") == 0)) {
NEXT_ARG();
bpf_sec_name = *argv;
- NEXT_ARG();
+ NEXT_ARG_FWD();
}
- if (!bpf_uds_name &&
+ if (argc > 0 && !bpf_uds_name &&
(strcmp(*argv, "export") == 0 ||
strcmp(*argv, "exp") == 0)) {
NEXT_ARG();
bpf_uds_name = *argv;
- NEXT_ARG();
+ NEXT_ARG_FWD();
}
- if (strcmp(*argv, "verbose") == 0 ||
- strcmp(*argv, "verb") == 0) {
+ if (argc > 0 &&
+ (strcmp(*argv, "verbose") == 0 ||
+ strcmp(*argv, "verb") == 0)) {
bpf_verbose = true;
- NEXT_ARG();
+ NEXT_ARG_FWD();
}
PREV_ARG();
@@ -166,33 +169,29 @@
goto opt_bpf;
break;
}
- argc--;
- argv++;
+
+ NEXT_ARG_FWD();
}
parm.action = TC_ACT_PIPE;
if (argc) {
if (matches(*argv, "reclassify") == 0) {
parm.action = TC_ACT_RECLASSIFY;
- argc--;
- argv++;
+ NEXT_ARG_FWD();
} else if (matches(*argv, "pipe") == 0) {
parm.action = TC_ACT_PIPE;
- argc--;
- argv++;
+ NEXT_ARG_FWD();
} else if (matches(*argv, "drop") == 0 ||
matches(*argv, "shot") == 0) {
parm.action = TC_ACT_SHOT;
- argc--;
- argv++;
+ NEXT_ARG_FWD();
} else if (matches(*argv, "continue") == 0) {
parm.action = TC_ACT_UNSPEC;
- argc--;
- argv++;
- } else if (matches(*argv, "pass") == 0) {
+ NEXT_ARG_FWD();
+ } else if (matches(*argv, "pass") == 0 ||
+ matches(*argv, "ok") == 0) {
parm.action = TC_ACT_OK;
- argc--;
- argv++;
+ NEXT_ARG_FWD();
}
}
@@ -203,8 +202,8 @@
fprintf(stderr, "bpf: Illegal \"index\"\n");
return -1;
}
- argc--;
- argv++;
+
+ NEXT_ARG_FWD();
}
}