diff options
| author | Vlad Yasevich <vyasevic@redhat.com> | 2013-02-13 07:00:12 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-02-13 19:41:46 -0500 |
| commit | 407af3299ef1ac7e87ce3fb530e32a009d1a9efd (patch) | |
| tree | 9572e0b02eb9f6c2952b490f3a79f4b790fcea3c | |
| parent | 85f46c6baef1486ce20e13dd7cdea5dd15be2a90 (diff) | |
bridge: Add netlink interface to configure vlans on bridge ports
Add a netlink interface to add and remove vlan configuration on bridge port.
The interface uses the RTM_SETLINK message and encodes the vlan
configuration inside the IFLA_AF_SPEC. It is possble to include multiple
vlans to either add or remove in a single message.
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/linux/netdevice.h | 2 | ||||
| -rw-r--r-- | include/uapi/linux/if_bridge.h | 9 | ||||
| -rw-r--r-- | net/bridge/br_device.c | 1 | ||||
| -rw-r--r-- | net/bridge/br_if.c | 1 | ||||
| -rw-r--r-- | net/bridge/br_netlink.c | 139 | ||||
| -rw-r--r-- | net/bridge/br_private.h | 1 | ||||
| -rw-r--r-- | net/core/rtnetlink.c | 72 |
7 files changed, 207 insertions, 18 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 25bd46f52877..1b90f9401000 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
| @@ -1020,6 +1020,8 @@ struct net_device_ops { | |||
| 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 | int (*ndo_bridge_dellink)(struct net_device *dev, | ||
| 1024 | struct nlmsghdr *nlh); | ||
| 1023 | int (*ndo_change_carrier)(struct net_device *dev, | 1025 | int (*ndo_change_carrier)(struct net_device *dev, |
| 1024 | bool new_carrier); | 1026 | bool new_carrier); |
| 1025 | }; | 1027 | }; |
diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index 5db297514aec..3ca9817ca7e8 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h | |||
| @@ -108,15 +108,24 @@ struct __fdb_entry { | |||
| 108 | * [IFLA_AF_SPEC] = { | 108 | * [IFLA_AF_SPEC] = { |
| 109 | * [IFLA_BRIDGE_FLAGS] | 109 | * [IFLA_BRIDGE_FLAGS] |
| 110 | * [IFLA_BRIDGE_MODE] | 110 | * [IFLA_BRIDGE_MODE] |
| 111 | * [IFLA_BRIDGE_VLAN_INFO] | ||
| 111 | * } | 112 | * } |
| 112 | */ | 113 | */ |
| 113 | enum { | 114 | enum { |
| 114 | IFLA_BRIDGE_FLAGS, | 115 | IFLA_BRIDGE_FLAGS, |
| 115 | IFLA_BRIDGE_MODE, | 116 | IFLA_BRIDGE_MODE, |
| 117 | IFLA_BRIDGE_VLAN_INFO, | ||
| 116 | __IFLA_BRIDGE_MAX, | 118 | __IFLA_BRIDGE_MAX, |
| 117 | }; | 119 | }; |
| 118 | #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) | 120 | #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) |
| 119 | 121 | ||
| 122 | #define BRIDGE_VLAN_INFO_MASTER (1<<0) /* Operate on Bridge device as well */ | ||
| 123 | |||
| 124 | struct bridge_vlan_info { | ||
| 125 | u16 flags; | ||
| 126 | u16 vid; | ||
| 127 | }; | ||
| 128 | |||
| 120 | /* Bridge multicast database attributes | 129 | /* Bridge multicast database attributes |
| 121 | * [MDBA_MDB] = { | 130 | * [MDBA_MDB] = { |
| 122 | * [MDBA_MDB_ENTRY] = { | 131 | * [MDBA_MDB_ENTRY] = { |
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 35a2c2c84f33..091bedf266a0 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
| @@ -316,6 +316,7 @@ static const struct net_device_ops br_netdev_ops = { | |||
| 316 | .ndo_fdb_dump = br_fdb_dump, | 316 | .ndo_fdb_dump = br_fdb_dump, |
| 317 | .ndo_bridge_getlink = br_getlink, | 317 | .ndo_bridge_getlink = br_getlink, |
| 318 | .ndo_bridge_setlink = br_setlink, | 318 | .ndo_bridge_setlink = br_setlink, |
| 319 | .ndo_bridge_dellink = br_dellink, | ||
| 319 | }; | 320 | }; |
| 320 | 321 | ||
| 321 | static void br_dev_free(struct net_device *dev) | 322 | static void br_dev_free(struct net_device *dev) |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index af9d65ab4001..335c60cebfd1 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/if_ether.h> | 23 | #include <linux/if_ether.h> |
| 24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 25 | #include <net/sock.h> | 25 | #include <net/sock.h> |
| 26 | #include <linux/if_vlan.h> | ||
| 26 | 27 | ||
| 27 | #include "br_private.h" | 28 | #include "br_private.h" |
| 28 | 29 | ||
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 39ca9796f3f7..534a9f4587a9 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <net/rtnetlink.h> | 16 | #include <net/rtnetlink.h> |
| 17 | #include <net/net_namespace.h> | 17 | #include <net/net_namespace.h> |
| 18 | #include <net/sock.h> | 18 | #include <net/sock.h> |
| 19 | #include <uapi/linux/if_bridge.h> | ||
| 19 | 20 | ||
| 20 | #include "br_private.h" | 21 | #include "br_private.h" |
| 21 | #include "br_private_stp.h" | 22 | #include "br_private_stp.h" |
| @@ -119,10 +120,14 @@ nla_put_failure: | |||
| 119 | */ | 120 | */ |
| 120 | void br_ifinfo_notify(int event, struct net_bridge_port *port) | 121 | void br_ifinfo_notify(int event, struct net_bridge_port *port) |
| 121 | { | 122 | { |
| 122 | struct net *net = dev_net(port->dev); | 123 | struct net *net; |
| 123 | struct sk_buff *skb; | 124 | struct sk_buff *skb; |
| 124 | int err = -ENOBUFS; | 125 | int err = -ENOBUFS; |
| 125 | 126 | ||
| 127 | if (!port) | ||
| 128 | return; | ||
| 129 | |||
| 130 | net = dev_net(port->dev); | ||
| 126 | br_debug(port->br, "port %u(%s) event %d\n", | 131 | br_debug(port->br, "port %u(%s) event %d\n", |
| 127 | (unsigned int)port->port_no, port->dev->name, event); | 132 | (unsigned int)port->port_no, port->dev->name, event); |
| 128 | 133 | ||
| @@ -144,6 +149,7 @@ errout: | |||
| 144 | rtnl_set_sk_err(net, RTNLGRP_LINK, err); | 149 | rtnl_set_sk_err(net, RTNLGRP_LINK, err); |
| 145 | } | 150 | } |
| 146 | 151 | ||
| 152 | |||
| 147 | /* | 153 | /* |
| 148 | * Dump information about all ports, in response to GETLINK | 154 | * Dump information about all ports, in response to GETLINK |
| 149 | */ | 155 | */ |
| @@ -162,6 +168,64 @@ out: | |||
| 162 | return err; | 168 | return err; |
| 163 | } | 169 | } |
| 164 | 170 | ||
| 171 | const struct nla_policy ifla_br_policy[IFLA_MAX+1] = { | ||
| 172 | [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 }, | ||
| 173 | [IFLA_BRIDGE_MODE] = { .type = NLA_U16 }, | ||
| 174 | [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY, | ||
| 175 | .len = sizeof(struct bridge_vlan_info), }, | ||
| 176 | }; | ||
| 177 | |||
| 178 | static int br_afspec(struct net_bridge *br, | ||
| 179 | struct net_bridge_port *p, | ||
| 180 | struct nlattr *af_spec, | ||
| 181 | int cmd) | ||
| 182 | { | ||
| 183 | struct nlattr *tb[IFLA_BRIDGE_MAX+1]; | ||
| 184 | int err = 0; | ||
| 185 | |||
| 186 | err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, af_spec, ifla_br_policy); | ||
| 187 | if (err) | ||
| 188 | return err; | ||
| 189 | |||
| 190 | if (tb[IFLA_BRIDGE_VLAN_INFO]) { | ||
| 191 | struct bridge_vlan_info *vinfo; | ||
| 192 | |||
| 193 | vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); | ||
| 194 | |||
| 195 | if (vinfo->vid >= VLAN_N_VID) | ||
| 196 | return -EINVAL; | ||
| 197 | |||
| 198 | switch (cmd) { | ||
| 199 | case RTM_SETLINK: | ||
| 200 | if (p) { | ||
| 201 | err = nbp_vlan_add(p, vinfo->vid); | ||
| 202 | if (err) | ||
| 203 | break; | ||
| 204 | |||
| 205 | if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER) | ||
| 206 | err = br_vlan_add(p->br, vinfo->vid); | ||
| 207 | } else | ||
| 208 | err = br_vlan_add(br, vinfo->vid); | ||
| 209 | |||
| 210 | if (err) | ||
| 211 | break; | ||
| 212 | |||
| 213 | break; | ||
| 214 | |||
| 215 | case RTM_DELLINK: | ||
| 216 | if (p) { | ||
| 217 | nbp_vlan_delete(p, vinfo->vid); | ||
| 218 | if (vinfo->flags & BRIDGE_VLAN_INFO_MASTER) | ||
| 219 | br_vlan_delete(p->br, vinfo->vid); | ||
| 220 | } else | ||
| 221 | br_vlan_delete(br, vinfo->vid); | ||
| 222 | break; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | return err; | ||
| 227 | } | ||
| 228 | |||
| 165 | static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { | 229 | static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { |
| 166 | [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, | 230 | [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, |
| 167 | [IFLA_BRPORT_COST] = { .type = NLA_U32 }, | 231 | [IFLA_BRPORT_COST] = { .type = NLA_U32 }, |
| @@ -241,6 +305,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh) | |||
| 241 | { | 305 | { |
| 242 | struct ifinfomsg *ifm; | 306 | struct ifinfomsg *ifm; |
| 243 | struct nlattr *protinfo; | 307 | struct nlattr *protinfo; |
| 308 | struct nlattr *afspec; | ||
| 244 | struct net_br | ||
