mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-07-05 21:35:46 +02:00
net: bridge: vlan: add new rtm message support
Add initial RTM_NEWVLAN support which can only create vlans, operating similar to the current br_afspec(). We will use it later to also change per-vlan options. Old-style (flag-based) vlan ranges are not allowed when using RTM messages, we will introduce vlan ranges later via a new nested attribute which would allow us to have all the information about a range encapsulated into a single nl attribute. Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
8dcea18708
commit
f26b296585
|
@ -561,12 +561,12 @@ static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int br_process_vlan_info(struct net_bridge *br,
|
int br_process_vlan_info(struct net_bridge *br,
|
||||||
struct net_bridge_port *p, int cmd,
|
struct net_bridge_port *p, int cmd,
|
||||||
struct bridge_vlan_info *vinfo_curr,
|
struct bridge_vlan_info *vinfo_curr,
|
||||||
struct bridge_vlan_info **vinfo_last,
|
struct bridge_vlan_info **vinfo_last,
|
||||||
bool *changed,
|
bool *changed,
|
||||||
struct netlink_ext_ack *extack)
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
if (!br_vlan_valid_id(vinfo_curr->vid, extack))
|
if (!br_vlan_valid_id(vinfo_curr->vid, extack))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -1237,6 +1237,12 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags,
|
||||||
int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags);
|
int br_dellink(struct net_device *dev, struct nlmsghdr *nlmsg, u16 flags);
|
||||||
int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev,
|
int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev,
|
||||||
u32 filter_mask, int nlflags);
|
u32 filter_mask, int nlflags);
|
||||||
|
int br_process_vlan_info(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *p, int cmd,
|
||||||
|
struct bridge_vlan_info *vinfo_curr,
|
||||||
|
struct bridge_vlan_info **vinfo_last,
|
||||||
|
bool *changed,
|
||||||
|
struct netlink_ext_ack *extack);
|
||||||
|
|
||||||
#ifdef CONFIG_SYSFS
|
#ifdef CONFIG_SYSFS
|
||||||
/* br_sysfs_if.c */
|
/* br_sysfs_if.c */
|
||||||
|
|
|
@ -1643,13 +1643,124 @@ out_err:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct nla_policy br_vlan_db_policy[BRIDGE_VLANDB_ENTRY_MAX + 1] = {
|
||||||
|
[BRIDGE_VLANDB_ENTRY_INFO] = { .type = NLA_EXACT_LEN,
|
||||||
|
.len = sizeof(struct bridge_vlan_info) },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int br_vlan_rtm_process_one(struct net_device *dev,
|
||||||
|
const struct nlattr *attr,
|
||||||
|
int cmd, struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
struct bridge_vlan_info *vinfo, *vinfo_last = NULL;
|
||||||
|
struct nlattr *tb[BRIDGE_VLANDB_ENTRY_MAX + 1];
|
||||||
|
struct net_bridge_vlan_group *vg;
|
||||||
|
struct net_bridge_port *p = NULL;
|
||||||
|
int err = 0, cmdmap = 0;
|
||||||
|
struct net_bridge *br;
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
if (netif_is_bridge_master(dev)) {
|
||||||
|
br = netdev_priv(dev);
|
||||||
|
vg = br_vlan_group(br);
|
||||||
|
} else {
|
||||||
|
p = br_port_get_rtnl(dev);
|
||||||
|
if (WARN_ON(!p))
|
||||||
|
return -ENODEV;
|
||||||
|
br = p->br;
|
||||||
|
vg = nbp_vlan_group(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WARN_ON(!vg))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
err = nla_parse_nested(tb, BRIDGE_VLANDB_ENTRY_MAX, attr,
|
||||||
|
br_vlan_db_policy, extack);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!tb[BRIDGE_VLANDB_ENTRY_INFO]) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "Missing vlan entry info");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
vinfo = nla_data(tb[BRIDGE_VLANDB_ENTRY_INFO]);
|
||||||
|
if (vinfo->flags & (BRIDGE_VLAN_INFO_RANGE_BEGIN |
|
||||||
|
BRIDGE_VLAN_INFO_RANGE_END)) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "Old-style vlan ranges are not allowed when using RTM vlan calls");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (!br_vlan_valid_id(vinfo->vid, extack))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case RTM_NEWVLAN:
|
||||||
|
cmdmap = RTM_SETLINK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = br_process_vlan_info(br, p, cmdmap, vinfo, &vinfo_last, &changed,
|
||||||
|
extack);
|
||||||
|
if (changed)
|
||||||
|
br_ifinfo_notify(cmdmap, br, p);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int br_vlan_rtm_process(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||||
|
struct netlink_ext_ack *extack)
|
||||||
|
{
|
||||||
|
struct net *net = sock_net(skb->sk);
|
||||||
|
struct br_vlan_msg *bvm;
|
||||||
|
struct net_device *dev;
|
||||||
|
struct nlattr *attr;
|
||||||
|
int err, vlans = 0;
|
||||||
|
int rem;
|
||||||
|
|
||||||
|
/* this should validate the header and check for remaining bytes */
|
||||||
|
err = nlmsg_parse(nlh, sizeof(*bvm), NULL, BRIDGE_VLANDB_MAX, NULL,
|
||||||
|
extack);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
bvm = nlmsg_data(nlh);
|
||||||
|
dev = __dev_get_by_index(net, bvm->ifindex);
|
||||||
|
if (!dev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev)) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "The device is not a valid bridge or bridge port");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlmsg_for_each_attr(attr, nlh, sizeof(*bvm), rem) {
|
||||||
|
if (nla_type(attr) != BRIDGE_VLANDB_ENTRY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
vlans++;
|
||||||
|
err = br_vlan_rtm_process_one(dev, attr, nlh->nlmsg_type,
|
||||||
|
extack);
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!vlans) {
|
||||||
|
NL_SET_ERR_MSG_MOD(extack, "No vlans found to process");
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
void br_vlan_rtnl_init(void)
|
void br_vlan_rtnl_init(void)
|
||||||
{
|
{
|
||||||
rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETVLAN, NULL,
|
rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETVLAN, NULL,
|
||||||
br_vlan_rtm_dump, 0);
|
br_vlan_rtm_dump, 0);
|
||||||
|
rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_NEWVLAN,
|
||||||
|
br_vlan_rtm_process, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void br_vlan_rtnl_uninit(void)
|
void br_vlan_rtnl_uninit(void)
|
||||||
{
|
{
|
||||||
rtnl_unregister(PF_BRIDGE, RTM_GETVLAN);
|
rtnl_unregister(PF_BRIDGE, RTM_GETVLAN);
|
||||||
|
rtnl_unregister(PF_BRIDGE, RTM_NEWVLAN);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user