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:
committed by
David S. Miller
parent
85f46c6bae
commit
407af3299e
@@ -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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user