diff options
| author | Vlad Yasevich <vyasevic@redhat.com> | 2013-02-13 07:00:13 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-02-13 19:41:46 -0500 |
| commit | 6cbdceeb1cb12c7d620161925a8c3e81daadb2e4 (patch) | |
| tree | 81852fee23a380456cce4d2c1bb5ec52c7ff0013 | |
| parent | 407af3299ef1ac7e87ce3fb530e32a009d1a9efd (diff) | |
bridge: Dump vlan information from a bridge port
Using the RTM_GETLINK dump the vlan filter list of a given
bridge port. The information depends on setting the filter
flag similar to how nic VF info is dumped.
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 | ||||
| -rw-r--r-- | include/linux/netdevice.h | 3 | ||||
| -rw-r--r-- | include/uapi/linux/rtnetlink.h | 1 | ||||
| -rw-r--r-- | net/bridge/br_netlink.c | 94 | ||||
| -rw-r--r-- | net/bridge/br_private.h | 3 | ||||
| -rw-r--r-- | net/bridge/br_vlan.c | 2 | ||||
| -rw-r--r-- | net/core/rtnetlink.c | 16 |
7 files changed, 104 insertions, 18 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 6999269b3a4a..4e2aa47193cb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | |||
| @@ -7079,7 +7079,8 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev, | |||
| 7079 | } | 7079 | } |
| 7080 | 7080 | ||
| 7081 | static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, | 7081 | static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, |
| 7082 | struct net_device *dev) | 7082 | struct net_device *dev, |
| 7083 | u32 filter_mask) | ||
| 7083 | { | 7084 | { |
| 7084 | struct ixgbe_adapter *adapter = netdev_priv(dev); | 7085 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
| 7085 | u16 mode; | 7086 | u16 mode; |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1b90f9401000..1964ca66df56 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
| @@ -1019,7 +1019,8 @@ struct net_device_ops { | |||
| 1019 | struct nlmsghdr *nlh); | 1019 | struct nlmsghdr *nlh); |
| 1020 | int (*ndo_bridge_getlink)(struct sk_buff *skb, | 1020 | int (*ndo_bridge_getlink)(struct sk_buff *skb, |
| 1021 | u32 pid, u32 seq, | 1021 | u32 pid, u32 seq, |
| 1022 | struct net_device *dev); | 1022 | struct net_device *dev, |
| 1023 | u32 filter_mask); | ||
| 1023 | int (*ndo_bridge_dellink)(struct net_device *dev, | 1024 | int (*ndo_bridge_dellink)(struct net_device *dev, |
| 1024 | struct nlmsghdr *nlh); | 1025 | struct nlmsghdr *nlh); |
| 1025 | int (*ndo_change_carrier)(struct net_device *dev, | 1026 | int (*ndo_change_carrier)(struct net_device *dev, |
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 7a5eb196ade9..7a2144e1afae 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h | |||
| @@ -630,6 +630,7 @@ struct tcamsg { | |||
| 630 | 630 | ||
| 631 | /* New extended info filters for IFLA_EXT_MASK */ | 631 | /* New extended info filters for IFLA_EXT_MASK */ |
| 632 | #define RTEXT_FILTER_VF (1 << 0) | 632 | #define RTEXT_FILTER_VF (1 << 0) |
| 633 | #define RTEXT_FILTER_BRVLAN (1 << 1) | ||
| 633 | 634 | ||
| 634 | /* End of information exported to user level */ | 635 | /* End of information exported to user level */ |
| 635 | 636 | ||
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 534a9f4587a9..fe1980d5a7e4 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
| @@ -65,15 +65,21 @@ static int br_port_fill_attrs(struct sk_buff *skb, | |||
| 65 | * Create one netlink message for one interface | 65 | * Create one netlink message for one interface |
| 66 | * Contains port and master info as well as carrier and bridge state. | 66 | * Contains port and master info as well as carrier and bridge state. |
| 67 | */ | 67 | */ |
| 68 | static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *port, | 68 | static int br_fill_ifinfo(struct sk_buff *skb, |
| 69 | u32 pid, u32 seq, int event, unsigned int flags) | 69 | const struct net_bridge_port *port, |
| 70 | u32 pid, u32 seq, int event, unsigned int flags, | ||
| 71 | u32 filter_mask, const struct net_device *dev) | ||
| 70 | { | 72 | { |
| 71 | const struct net_bridge *br = port->br; | 73 | const struct net_bridge *br; |
| 72 | const struct net_device *dev = port->dev; | ||
| 73 | struct ifinfomsg *hdr; | 74 | struct ifinfomsg *hdr; |
| 74 | struct nlmsghdr *nlh; | 75 | struct nlmsghdr *nlh; |
| 75 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; | 76 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; |
| 76 | 77 | ||
| 78 | if (port) | ||
| 79 | br = port->br; | ||
| 80 | else | ||
| 81 | br = netdev_priv(dev); | ||
| 82 | |||
| 77 | br_debug(br, "br_fill_info event %d port %s master %s\n", | 83 | br_debug(br, "br_fill_info event %d port %s master %s\n", |
| 78 | event, dev->name, br->dev->name); | 84 | event, dev->name, br->dev->name); |
| 79 | 85 | ||
| @@ -99,7 +105,7 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por | |||
| 99 | nla_put_u32(skb, IFLA_LINK, dev->iflink))) | 105 | nla_put_u32(skb, IFLA_LINK, dev->iflink))) |
| 100 | goto nla_put_failure; | 106 | goto nla_put_failure; |
| 101 | 107 | ||
| 102 | if (event == RTM_NEWLINK) { | 108 | if (event == RTM_NEWLINK && port) { |
| 103 | struct nlattr *nest | 109 | struct nlattr *nest |
| 104 | = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); | 110 | = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); |
| 105 | 111 | ||
| @@ -108,6 +114,40 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por | |||
| 108 | nla_nest_end(skb, nest); | 114 | nla_nest_end(skb, nest); |
| 109 | } | 115 | } |
| 110 | 116 | ||
| 117 | /* Check if the VID information is requested */ | ||
| 118 | if (filter_mask & RTEXT_FILTER_BRVLAN) { | ||
| 119 | struct nlattr *af; | ||
| 120 | const struct net_port_vlans *pv; | ||
| 121 | struct bridge_vlan_info vinfo; | ||
| 122 | u16 vid; | ||
| 123 | |||
| 124 | if (port) | ||
| 125 | pv = nbp_get_vlan_info(port); | ||
| 126 | else | ||
| 127 | pv = br_get_vlan_info(br); | ||
| 128 | |||
| 129 | if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN)) | ||
| 130 | goto done; | ||
| 131 | |||
| 132 | af = nla_nest_start(skb, IFLA_AF_SPEC); | ||
| 133 | if (!af) | ||
| 134 | goto nla_put_failure; | ||
| 135 | |||
| 136 | for (vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN); | ||
| 137 | vid < BR_VLAN_BITMAP_LEN; | ||
| 138 | vid = find_next_bit(pv->vlan_bitmap, | ||
| 139 | BR_VLAN_BITMAP_LEN, vid+1)) { | ||
| 140 | vinfo.vid = vid; | ||
| 141 | vinfo.flags = 0; | ||
| 142 | if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO, | ||
| 143 | sizeof(vinfo), &vinfo)) | ||
| 144 | goto nla_put_failure; | ||
| 145 | } | ||
| 146 | |||
| 147 | nla_nest_end(skb, af); | ||
| 148 | } | ||
| 149 | |||
| 150 | done: | ||
| 111 | return nlmsg_end(skb, nlh); | 151 | return nlmsg_end(skb, nlh); |
| 112 | 152 | ||
| 113 | nla_put_failure: | 153 | nla_put_failure: |
| @@ -135,7 +175,7 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port) | |||
| 135 | if (skb == NULL) | 175 | if (skb == NULL) |
| 136 | goto errout; | 176 | goto errout; |
| 137 | 177 | ||
| 138 | err = br_fill_ifinfo(skb, port, 0, 0, event, 0); | 178 | err = br_fill_ifinfo(skb, port, 0, 0, event, 0, 0, port->dev); |
| 139 | if (err < 0) { | 179 | if (err < 0) { |
| 140 | /* -EMSGSIZE implies BUG in br_nlmsg_size() */ | 180 | /* -EMSGSIZE implies BUG in br_nlmsg_size() */ |
| 141 | WARN_ON(err == -EMSGSIZE); | 181 | WARN_ON(err == -EMSGSIZE); |
| @@ -154,16 +194,17 @@ errout: | |||
| 154 | * Dump information about all ports, in response to GETLINK | 194 | * Dump information about all ports, in response to GETLINK |
| 155 | */ | 195 | */ |
| 156 | int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, | 196 | int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, |
| 157 | struct net_device *dev) | 197 | struct net_device *dev, u32 filter_mask) |
| 158 | { | 198 | { |
| 159 | int err = 0; | 199 | int err = 0; |
| 160 | struct net_bridge_port *port = br_port_get_rcu(dev); | 200 | struct net_bridge_port *port = br_port_get_rcu(dev); |
| 161 | 201 | ||
| 162 | /* not a bridge port */ | 202 | /* not a bridge port and */ |
| 163 | if (!port) | 203 | if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN)) |
| 164 | goto out; | 204 | goto out; |
| 165 | 205 | ||
| 166 | err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI); | 206 | err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI, |
| 207 | filter_mask, dev); | ||
| 167 | out: | 208 | out: |
| 168 | return err; | 209 | return err; |
| 169 | } | 210 | } |
| @@ -395,6 +436,29 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
| 395 | return 0; | 436 | return 0; |
| 396 | } | 437 | } |
| 397 | 438 | ||
| 439 | static size_t br_get_link_af_size(const struct net_device *dev) | ||
| 440 | { | ||
| 441 | struct net_port_vlans *pv; | ||
| 442 | |||
| 443 | if (br_port_exists(dev)) | ||
| 444 | pv = nbp_get_vlan_info(br_port_get_rcu(dev)); | ||
| 445 | else if (dev->priv_flags & IFF_EBRIDGE) | ||
| 446 | pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev)); | ||
| 447 | else | ||
| 448 | return 0; | ||
| 449 | |||
| 450 | if (!pv) | ||
| 451 | return 0; | ||
| 452 | |||
| 453 | /* Each VLAN is returned in bridge_vlan_info along with flags */ | ||
| 454 | return pv->num_vlans * nla_total_size(sizeof(struct bridge_vlan_info)); | ||
| 455 | } | ||
| 456 | |||
| 457 | struct rtnl_af_ops br_af_ops = { | ||
| 458 | .family = AF_BRIDGE, | ||
| 459 | .get_link_af_size = br_get_link_af_size, | ||
| 460 | }; | ||
| 461 | |||
| 398 | struct rtnl_link_ops br_link_ops __read_mostly = { | 462 | struct rtnl_link_ops br_link_ops __read_mostly = { |
| 399 | .kind = "bridge", | 463 | .kind = "bridge", |
| 400 | .priv_size = sizeof(struct net_bridge), | ||
