Cong Wang
2012-Nov-30 09:58 UTC
[Bridge] [PATCH net-next v1 1/2] bridge: export port_no and port_id via IFA_INFO_DATA
port_no will be used to get ifindex of a port in user-space, export it togather with port_id. Cc: Herbert Xu <herbert at gondor.apana.org.au> Cc: Stephen Hemminger <shemminger at vyatta.com> Cc: "David S. Miller" <davem at davemloft.net> Cc: Thomas Graf <tgraf at suug.ch> Cc: Jesper Dangaard Brouer <brouer at redhat.com> Signed-off-by: Cong Wang <amwang at redhat.com> Acked-by: Thomas Graf <tgraf at suug.ch> Signed-off-by: Cong Wang <amwang at redhat.com> --- include/uapi/linux/if_link.h | 2 ++ net/bridge/br_netlink.c | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletions(-) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index bb58aeb..9cd91a9 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -218,6 +218,8 @@ enum { IFLA_BRPORT_MODE, /* mode (hairpin) */ IFLA_BRPORT_GUARD, /* bpdu guard */ IFLA_BRPORT_PROTECT, /* root port protection */ + IFLA_BRPORT_NO, /* port no */ + IFLA_BRPORT_ID, /* port id */ __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 65429b9..7b7414e 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -28,6 +28,8 @@ static inline size_t br_port_info_size(void) + nla_total_size(1) /* IFLA_BRPORT_MODE */ + nla_total_size(1) /* IFLA_BRPORT_GUARD */ + nla_total_size(1) /* IFLA_BRPORT_PROTECT */ + + nla_total_size(2) /* IFLA_BRPORT_NO */ + + nla_total_size(2) /* IFLA_BRPORT_ID */ + 0; } @@ -53,7 +55,9 @@ static int br_port_fill_attrs(struct sk_buff *skb, nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) || nla_put_u8(skb, IFLA_BRPORT_MODE, mode) || nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) || - nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK))) + nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) || + nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) || + nla_put_u16(skb, IFLA_BRPORT_ID, p->port_id)) return -EMSGSIZE; return 0; @@ -168,6 +172,8 @@ static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, + [IFLA_BRPORT_NO] = { .type = NLA_U16 }, + [IFLA_BRPORT_ID] = { .type = NLA_U16 }, }; /* Change the state of the port and notify spanning tree */
Cong Wang
2012-Nov-30 09:58 UTC
[Bridge] [PATCH net-next v1 2/2] bridge: export multicast database via netlink
This patch exports bridge multicast database via netlink message type RTM_GETMDB. Similar to fdb, but currently bridge-specific. We may need to support modify multicast database too (RTM_{ADD,DEL}MDB). Cc: Herbert Xu <herbert at gondor.apana.org.au> Cc: Stephen Hemminger <shemminger at vyatta.com> Cc: "David S. Miller" <davem at davemloft.net> Cc: Thomas Graf <tgraf at suug.ch> Cc: Jesper Dangaard Brouer <brouer at redhat.com> Signed-off-by: Cong Wang <amwang at redhat.com> --- include/uapi/linux/if_bridge.h | 26 ++++++ include/uapi/linux/rtnetlink.h | 3 + net/bridge/Makefile | 2 +- net/bridge/br_mdb.c | 166 ++++++++++++++++++++++++++++++++++++++++ net/bridge/br_multicast.c | 2 + net/bridge/br_private.h | 2 + 6 files changed, 200 insertions(+), 1 deletions(-) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index b388579..c30c236 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -116,4 +116,30 @@ enum { __IFLA_BRIDGE_MAX, }; #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) + +/* Bridge multicast database attributes + * [MDBA_MDB] = { + * [MDBA_MCADDR] + * [MDBA_BRPORT_NO] + * } + * [MDBA_ROUTER] = { + * [MDBA_BRPORT_NO] + * } + */ +enum { + MDBA_UNSPEC, + MDBA_MDB, + MDBA_ROUTER, + __MDBA_MAX, +}; +#define MDBA_MAX (__MDBA_MAX - 1) + +enum { + MDBA_MDB_UNSPEC, + MDBA_MCADDR, + MDBA_BRPORT_NO, + __MDBA_MDB_MAX, +}; +#define MDBA_MDB_MAX (__MDBA_MDB_MAX - 1) + #endif /* _UAPI_LINUX_IF_BRIDGE_H */ diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 3dee071..0df623f 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -125,6 +125,9 @@ enum { RTM_GETNETCONF = 82, #define RTM_GETNETCONF RTM_GETNETCONF + RTM_GETMDB = 86, +#define RTM_GETMDB RTM_GETMDB + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; diff --git a/net/bridge/Makefile b/net/bridge/Makefile index d0359ea..e859098 100644 --- a/net/bridge/Makefile +++ b/net/bridge/Makefile @@ -12,6 +12,6 @@ bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o bridge-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o -bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o +bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o obj-$(CONFIG_BRIDGE_NF_EBTABLES) += netfilter/ diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c new file mode 100644 index 0000000..3751f7d --- /dev/null +++ b/net/bridge/br_mdb.c @@ -0,0 +1,166 @@ +#include <linux/err.h> +#include <linux/if_ether.h> +#include <linux/igmp.h> +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/rculist.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <net/ip.h> +#if IS_ENABLED(CONFIG_IPV6) +#include <net/ipv6.h> +#include <net/mld.h> +#include <net/addrconf.h> +#include <net/ip6_checksum.h> +#endif + +#include "br_private.h" + +struct br_port_msg { + int ifindex; +}; + +static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb, + u32 seq, struct net_device *dev) +{ + struct net_bridge *br = netdev_priv(dev); + struct net_bridge_port *p; + struct hlist_node *n; + struct nlattr *nest; + + if (!br->multicast_router || hlist_empty(&br->router_list)) { + printk(KERN_INFO "no router on bridge\n"); + return 0; + } + + nest = nla_nest_start(skb, MDBA_ROUTER); + if (nest == NULL) + return -EMSGSIZE; + + hlist_for_each_entry_rcu(p, n, &br->router_list, rlist) { + if (p && nla_put_u16(skb, MDBA_BRPORT_NO, p->port_no)) + goto fail; + } + + nla_nest_end(skb, nest); + return 0; +fail: + nla_nest_cancel(skb, nest); + return -EMSGSIZE; +} + +static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb, + u32 seq, struct net_device *dev) +{ + struct net_bridge *br = netdev_priv(dev); + struct net_bridge_mdb_htable *mdb; + struct nlattr *nest; + unsigned int i; + int s_idx; + + if (br->multicast_disabled) { + printk(KERN_INFO "multicast is disabled on bridge\n"); + return 0; + } + + mdb = rcu_dereference(br->mdb); + if (!mdb) { + printk(KERN_INFO "no mdb on bridge\n"); + return 0; + } + + cb->seq = mdb->seq; + s_idx = cb->args[1]; + if (s_idx >= mdb->max) + return 0; + + nest = nla_nest_start(skb, MDBA_MDB); + if (nest == NULL) + return -EMSGSIZE; + + for (i = s_idx; i < mdb->max; i++) { + struct hlist_node *h; + struct net_bridge_mdb_entry *mp; + struct net_bridge_port_group *p, **pp; + struct net_bridge_port *port; + + hlist_for_each_entry_rcu(mp, h, &mdb->mhash[i], hlist[mdb->ver]) { + for (pp = &mp->ports; + (p = rcu_dereference(*pp)) != NULL; + pp = &p->next) { + port = p->port; + if (port) { + printk(KERN_INFO "port %u, mcaddr: %pI4\n", port->port_no, &mp->addr.u.ip4); + if (nla_put_u16(skb, MDBA_BRPORT_NO, port->port_no) || + nla_put_be32(skb, MDBA_MCADDR, p->addr.u.ip4)) + goto fail; + } + } + } + } + + cb->args[1] = i; + nla_nest_end(skb, nest); + return 0; +fail: + cb->args[1] = i; + nla_nest_cancel(skb, nest); + return -EMSGSIZE; +} + +static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net_device *dev; + struct net *net = sock_net(skb->sk); + struct nlmsghdr *nlh; + u32 seq = cb->nlh->nlmsg_seq; + int idx = 0, s_idx; + + s_idx = cb->args[0]; + + rcu_read_lock(); + + for_each_netdev_rcu(net, dev) { + if (dev->priv_flags & IFF_EBRIDGE) { + struct br_port_msg *bpm; + + if (idx < s_idx) + goto cont; + + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, + seq, RTM_GETMDB, + sizeof(*bpm), NLM_F_MULTI); + if (nlh == NULL) + break; + + bpm = nlmsg_data(nlh); + bpm->ifindex = dev->ifindex; + if (br_mdb_fill_info(skb, cb, seq, dev) < 0) { + printk(KERN_INFO "br_mdb_fill_info failed\n"); + goto fail; + } + if (br_rports_fill_info(skb, cb, seq, dev) < 0) { + printk(KERN_INFO "br_rports_fill_info failed\n"); + goto fail; + } + + nlmsg_end(skb, nlh); +cont: + idx++; + } + } + + rcu_read_unlock(); + cb->args[0] = idx; + return skb->len; + +fail: + rcu_read_unlock(); + nlmsg_cancel(skb, nlh); + return skb->len; +} + +void br_mdb_init(void) +{ + rtnl_register(PF_BRIDGE, RTM_GETMDB, NULL, br_mdb_dump, NULL); +} diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 2417434..d53e4f4 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -322,6 +322,7 @@ static int br_mdb_rehash(struct net_bridge_mdb_htable __rcu **mdbp, int max, mdb->size = old ? old->size : 0; mdb->ver = old ? old->ver ^ 1 : 0; + mdb->seq = old ? (old->seq + 1): 0; if (!old || elasticity) get_random_bytes(&mdb->secret, sizeof(mdb->secret)); @@ -1584,6 +1585,7 @@ void br_multicast_init(struct net_bridge *br) br_multicast_querier_expired, (unsigned long)br); setup_timer(&br->multicast_query_timer, br_multicast_query_expired, (unsigned long)br); + br_mdb_init(); } void br_multicast_open(struct net_bridge *br) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index eb9cd42..6484069 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -105,6 +105,7 @@ struct net_bridge_mdb_htable u32 max; u32 secret; u32 ver; + u32 seq; }; struct net_bridge_port @@ -432,6 +433,7 @@ extern int br_multicast_set_port_router(struct net_bridge_port *p, extern int br_multicast_toggle(struct net_bridge *br, unsigned long val); extern int br_multicast_set_querier(struct net_bridge *br, unsigned long val); extern int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val); +extern void br_mdb_init(void); static inline bool br_multicast_is_router(struct net_bridge *br) {
Sample output: # ./bridge/bridge mdb bridge dev br0 multicast database: port no 1, multicast addr 224.8.8.9 port no 2, multicast addr 224.8.8.8 router ports: 2 TODO: display device name too Cc: Herbert Xu <herbert at gondor.apana.org.au> Cc: Stephen Hemminger <shemminger at vyatta.com> Cc: "David S. Miller" <davem at davemloft.net> Cc: Thomas Graf <tgraf at suug.ch> Cc: Jesper Dangaard Brouer <brouer at redhat.com> Signed-off-by: Cong Wang <amwang at redhat.com> --- bridge/Makefile | 2 +- bridge/br_common.h | 35 ++++++++++ bridge/bridge.c | 1 + bridge/mdb.c | 157 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/rtnetlink.h | 3 + 5 files changed, 197 insertions(+), 1 deletions(-) diff --git a/bridge/Makefile b/bridge/Makefile index 9a6743e..67aceb4 100644 --- a/bridge/Makefile +++ b/bridge/Makefile @@ -1,4 +1,4 @@ -BROBJ = bridge.o fdb.o monitor.o link.o +BROBJ = bridge.o fdb.o monitor.o link.o mdb.o include ../Config diff --git a/bridge/br_common.h b/bridge/br_common.h index 718ecb9..83b2b9f 100644 --- a/bridge/br_common.h +++ b/bridge/br_common.h @@ -5,6 +5,7 @@ extern int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); extern int do_fdb(int argc, char **argv); +extern int do_mdb(int argc, char **argv); extern int do_monitor(int argc, char **argv); extern int preferred_family; @@ -12,3 +13,37 @@ extern int show_stats; extern int show_detail; extern int timestamp; extern struct rtnl_handle rth; + +/* Bridge multicast database attributes + * [MDBA_MDB] = { + * [MDBA_MCADDR] + * [MDBA_BRPORT_NO] + * } + * [MDBA_ROUTER] = { + * [MDBA_BRPORT_NO] + * } + */ +enum { + MDBA_UNSPEC, + MDBA_MDB, + MDBA_ROUTER, + __MDBA_MAX, +}; +#define MDBA_MAX (__MDBA_MAX - 1) + +enum { + MDBA_MDB_UNSPEC, + MDBA_MCADDR, + MDBA_BRPORT_NO, + __MDBA_MDB_MAX, +}; +#define MDBA_MDB_MAX (__MDBA_MDB_MAX - 1) + +struct br_port_msg { + int ifindex; +}; + +#ifndef MDBA_RTA +#define MDBA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg)))) +#endif diff --git a/bridge/bridge.c b/bridge/bridge.c index e2c33b0..1fcd365 100644 --- a/bridge/bridge.c +++ b/bridge/bridge.c @@ -43,6 +43,7 @@ static const struct cmd { int (*func)(int argc, char **argv); } cmds[] = { { "fdb", do_fdb }, + { "mdb", do_mdb }, { "monitor", do_monitor }, { "help", do_help }, { 0 } diff --git a/bridge/mdb.c b/bridge/mdb.c new file mode 100644 index 0000000..f2f4ff2 --- /dev/null +++ b/bridge/mdb.c @@ -0,0 +1,157 @@ +/* + * Get mdb table with netlink + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <net/if.h> +#include <netinet/in.h> +#include <linux/if_bridge.h> +#include <linux/if_ether.h> +#include <linux/neighbour.h> +#include <string.h> +#include <arpa/inet.h> + +#include "libnetlink.h" +#include "br_common.h" +#include "rt_names.h" +#include "utils.h" + +int filter_index; + +static void usage(void) +{ + fprintf(stderr, " bridge mdb {show} [ dev DEV ]\n"); + exit(-1); +} + +static void br_print_router_ports(FILE *f, struct rtattr *attr) +{ + uint16_t *port_no; + struct rtattr *i; + int rem; + + fprintf(f, "router ports: "); + + rem = RTA_PAYLOAD(attr); + for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { + port_no = RTA_DATA(i); + fprintf(f, "%u ", *port_no); + } + fprintf(f, "\n"); +} + +static void br_print_mdb_entry(FILE *f, struct rtattr *attr) +{ + uint32_t addr; + uint16_t port_no; + struct rtattr *i; + int rem; + SPRINT_BUF(abuf); + + fprintf(f, "multicast database:\n"); + + rem = RTA_PAYLOAD(attr); + for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { + port_no = rta_getattr_u16(i); + i = RTA_NEXT(i, rem); + addr = rta_getattr_u32(i); + fprintf(f, "port no %u, multicast addr %s\n", port_no, inet_ntop(AF_INET, &addr, abuf, sizeof(abuf))); + } +} + +int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +{ + FILE *fp = arg; + struct br_port_msg *r = NLMSG_DATA(n); + int len = n->nlmsg_len; + struct rtattr * tb[MDBA_MAX+1]; + + if (n->nlmsg_type != RTM_GETMDB) { + fprintf(stderr, "Not RTM_MDB: %08x %08x %08x\n", + n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); + + return 0; + } + + len -= NLMSG_LENGTH(sizeof(*r)); + if (len < 0) { + fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); + return -1; + } + + if (filter_index && filter_index != r->ifindex) + return 0; + + if (!filter_index && r->ifindex) + fprintf(fp, "bridge dev %s\n", ll_index_to_name(r->ifindex)); + + parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); + + if (tb[MDBA_MDB]) + br_print_mdb_entry(fp, tb[MDBA_MDB]); + + if (tb[MDBA_ROUTER]) + br_print_router_ports(fp, tb[MDBA_ROUTER]); + + return 0; +} + +static int mdb_show(int argc, char **argv) +{ + char *filter_dev = NULL; + + while (argc > 0) { + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + if (filter_dev) + duparg("dev", *argv); + filter_dev = *argv; + } + argc--; argv++; + } + + if (filter_dev) { + filter_index = if_nametoindex(filter_dev); + if (filter_index == 0) { + fprintf(stderr, "Cannot find device \"%s\"\n", + filter_dev); + return -1; + } + } + + if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) { + perror("Cannot send dump request"); + exit(1); + } + + if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); + exit(1); + } + + return 0; +} + +int do_mdb(int argc, char **argv) +{ + ll_init_map(&rth); + + if (argc > 0) { + if (matches(*argv, "show") == 0 || + matches(*argv, "lst") == 0 || + matches(*argv, "list") == 0) + return mdb_show(argc-1, argv+1); + if (matches(*argv, "help") == 0) + usage(); + } else + return mdb_show(0, NULL); + + fprintf(stderr, "Command \"%s\" is unknown, try \"bridge mdb help\".\n", *argv); + exit(-1); +} diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 0e3e0c1..f400b5e 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -120,6 +120,9 @@ enum { RTM_SETDCB, #define RTM_SETDCB RTM_SETDCB + RTM_GETMDB = 86, +#define RTM_GETMDB RTM_GETMDB + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) };
Thomas Graf
2012-Nov-30 10:18 UTC
[Bridge] [PATCH net-next v1 1/2] bridge: export port_no and port_id via IFA_INFO_DATA
On 11/30/12 at 05:58pm, Cong Wang wrote:> @@ -168,6 +172,8 @@ static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { > [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, > [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, > [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, > + [IFLA_BRPORT_NO] = { .type = NLA_U16 }, > + [IFLA_BRPORT_ID] = { .type = NLA_U16 }, > }; > > /* Change the state of the port and notify spanning tree */I missed this in the first round. Not much of a point in adding policy entries if the attributes are read-only as in this case.
Cong Wang
2012-Nov-30 14:51 UTC
[Bridge] [PATCH net-next v1 1/2] bridge: export port_no and port_id via IFA_INFO_DATA
On Fri, 2012-11-30 at 10:18 +0000, Thomas Graf wrote:> On 11/30/12 at 05:58pm, Cong Wang wrote: > > @@ -168,6 +172,8 @@ static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { > > [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, > > [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, > > [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, > > + [IFLA_BRPORT_NO] = { .type = NLA_U16 }, > > + [IFLA_BRPORT_ID] = { .type = NLA_U16 }, > > }; > > > > /* Change the state of the port and notify spanning tree */ > > I missed this in the first round. Not much of a point in adding policy > entries if the attributes are read-only as in this case.Yeah, remove these lines now.
Stephen Hemminger
2012-Nov-30 15:52 UTC
[Bridge] [PATCH net-next v1 1/2] bridge: export port_no and port_id via IFA_INFO_DATA
On Fri, 30 Nov 2012 17:58:32 +0800 Cong Wang <amwang at redhat.com> wrote:> port_no will be used to get ifindex of a port in user-space, > export it togather with port_id. > > Cc: Herbert Xu <herbert at gondor.apana.org.au> > Cc: Stephen Hemminger <shemminger at vyatta.com> > Cc: "David S. Miller" <davem at davemloft.net> > Cc: Thomas Graf <tgraf at suug.ch> > Cc: Jesper Dangaard Brouer <brouer at redhat.com> > Signed-off-by: Cong Wang <amwang at redhat.com> > Acked-by: Thomas Graf <tgraf at suug.ch> > Signed-off-by: Cong Wang <amwang at redhat.com> > --- > include/uapi/linux/if_link.h | 2 ++ > net/bridge/br_netlink.c | 8 +++++++- > 2 files changed, 9 insertions(+), 1 deletions(-) > > diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h > index bb58aeb..9cd91a9 100644 > --- a/include/uapi/linux/if_link.h > +++ b/include/uapi/linux/if_link.h > @@ -218,6 +218,8 @@ enum { > IFLA_BRPORT_MODE, /* mode (hairpin) */ > IFLA_BRPORT_GUARD, /* bpdu guard */ > IFLA_BRPORT_PROTECT, /* root port protection */ > + IFLA_BRPORT_NO, /* port no */ > + IFLA_BRPORT_ID, /* port id */ > __IFLA_BRPORT_MAX > }; > #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) > diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c > index 65429b9..7b7414e 100644 > --- a/net/bridge/br_netlink.c > +++ b/net/bridge/br_netlink.c > @@ -28,6 +28,8 @@ static inline size_t br_port_info_size(void) > + nla_total_size(1) /* IFLA_BRPORT_MODE */ > + nla_total_size(1) /* IFLA_BRPORT_GUARD */ > + nla_total_size(1) /* IFLA_BRPORT_PROTECT */ > + + nla_total_size(2) /* IFLA_BRPORT_NO */ > + + nla_total_size(2) /* IFLA_BRPORT_ID */ > + 0; > } > > @@ -53,7 +55,9 @@ static int br_port_fill_attrs(struct sk_buff *skb, > nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) || > nla_put_u8(skb, IFLA_BRPORT_MODE, mode) || > nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) || > - nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK))) > + nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) || > + nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) || > + nla_put_u16(skb, IFLA_BRPORT_ID, p->port_id)) > return -EMSGSIZE; > > return 0; > @@ -168,6 +172,8 @@ static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { > [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, > [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, > [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, > + [IFLA_BRPORT_NO] = { .type = NLA_U16 }, > + [IFLA_BRPORT_ID] = { .type = NLA_U16 }, > }; > > /* Change the state of the port and notify spanning tree */I don't think these are necessary. The device is already available and the relationship can be determined from other messages. This is what RSTP daemon does.