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>
This commit is contained in:
Vlad Yasevich
2013-02-13 12:00:12 +00:00
committed by David S. Miller
parent 85f46c6bae
commit 407af3299e
7 changed files with 207 additions and 18 deletions

View File

@@ -2464,6 +2464,77 @@ out:
return err;
}
static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
void *arg)
{
struct net *net = sock_net(skb->sk);
struct ifinfomsg *ifm;
struct net_device *dev;
struct nlattr *br_spec, *attr = NULL;
int rem, err = -EOPNOTSUPP;
u16 oflags, flags = 0;
bool have_flags = false;
if (nlmsg_len(nlh) < sizeof(*ifm))
return -EINVAL;
ifm = nlmsg_data(nlh);
if (ifm->ifi_family != AF_BRIDGE)
return -EPFNOSUPPORT;
dev = __dev_get_by_index(net, ifm->ifi_index);
if (!dev) {
pr_info("PF_BRIDGE: RTM_SETLINK with unknown ifindex\n");
return -ENODEV;
}
br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
if (br_spec) {
nla_for_each_nested(attr, br_spec, rem) {
if (nla_type(attr) == IFLA_BRIDGE_FLAGS) {
have_flags = true;
flags = nla_get_u16(attr);
break;
}
}
}
oflags = flags;
if (!flags || (flags & BRIDGE_FLAGS_MASTER)) {
struct net_device *br_dev = netdev_master_upper_dev_get(dev);
if (!br_dev || !br_dev->netdev_ops->ndo_bridge_dellink) {
err = -EOPNOTSUPP;
goto out;
}
err = br_dev->netdev_ops->ndo_bridge_dellink(dev, nlh);
if (err)
goto out;
flags &= ~BRIDGE_FLAGS_MASTER;
}
if ((flags & BRIDGE_FLAGS_SELF)) {
if (!dev->netdev_ops->ndo_bridge_dellink)
err = -EOPNOTSUPP;
else
err = dev->netdev_ops->ndo_bridge_dellink(dev, nlh);
if (!err)
flags &= ~BRIDGE_FLAGS_SELF;
}
if (have_flags)
memcpy(nla_data(attr), &flags, sizeof(flags));
/* Generate event to notify upper layer of bridge change */
if (!err)
err = rtnl_bridge_notify(dev, oflags);
out:
return err;
}
/* Protected by RTNL sempahore. */
static struct rtattr **rta_buf;
static int rtattr_max;
@@ -2647,6 +2718,7 @@ void __init rtnetlink_init(void)
rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL);
rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, NULL);
rtnl_register(PF_BRIDGE, RTM_DELLINK, rtnl_bridge_dellink, NULL, NULL);
rtnl_register(PF_BRIDGE, RTM_SETLINK, rtnl_bridge_setlink, NULL, NULL);
}