Skip to content
This repository was archived by the owner on Oct 31, 2024. It is now read-only.

Commit 8dcea18

Browse files
Nikolay Aleksandrovdavem330
Nikolay Aleksandrov
authored andcommitted
net: bridge: vlan: add rtm definitions and dump support
This patch adds vlan rtm definitions: - NEWVLAN: to be used for creating vlans, setting options and notifications - DELVLAN: to be used for deleting vlans - GETVLAN: used for dumping vlan information Dumping vlans which can span multiple messages is added now with basic information (vid and flags). We use nlmsg_parse() to validate the header length in order to be able to extend the message with filtering attributes later. Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 8f4cc94 commit 8dcea18

File tree

6 files changed

+203
-1
lines changed

6 files changed

+203
-1
lines changed

include/uapi/linux/if_bridge.h

+28
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,34 @@ struct bridge_stp_xstats {
165165
__u64 tx_tcn;
166166
};
167167

168+
/* Bridge vlan RTM header */
169+
struct br_vlan_msg {
170+
__u8 family;
171+
__u8 reserved1;
172+
__u16 reserved2;
173+
__u32 ifindex;
174+
};
175+
176+
/* Bridge vlan RTM attributes
177+
* [BRIDGE_VLANDB_ENTRY] = {
178+
* [BRIDGE_VLANDB_ENTRY_INFO]
179+
* ...
180+
* }
181+
*/
182+
enum {
183+
BRIDGE_VLANDB_UNSPEC,
184+
BRIDGE_VLANDB_ENTRY,
185+
__BRIDGE_VLANDB_MAX,
186+
};
187+
#define BRIDGE_VLANDB_MAX (__BRIDGE_VLANDB_MAX - 1)
188+
189+
enum {
190+
BRIDGE_VLANDB_ENTRY_UNSPEC,
191+
BRIDGE_VLANDB_ENTRY_INFO,
192+
__BRIDGE_VLANDB_ENTRY_MAX,
193+
};
194+
#define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1)
195+
168196
/* Bridge multicast database attributes
169197
* [MDBA_MDB] = {
170198
* [MDBA_MDB_ENTRY] = {

include/uapi/linux/rtnetlink.h

+7
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,13 @@ enum {
171171
RTM_GETLINKPROP,
172172
#define RTM_GETLINKPROP RTM_GETLINKPROP
173173

174+
RTM_NEWVLAN = 112,
175+
#define RTM_NEWNVLAN RTM_NEWVLAN
176+
RTM_DELVLAN,
177+
#define RTM_DELVLAN RTM_DELVLAN
178+
RTM_GETVLAN,
179+
#define RTM_GETVLAN RTM_GETVLAN
180+
174181
__RTM_MAX,
175182
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
176183
};

net/bridge/br_netlink.c

+2
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,7 @@ int __init br_netlink_init(void)
16571657
int err;
16581658

16591659
br_mdb_init();
1660+
br_vlan_rtnl_init();
16601661
rtnl_af_register(&br_af_ops);
16611662

16621663
err = rtnl_link_register(&br_link_ops);
@@ -1674,6 +1675,7 @@ int __init br_netlink_init(void)
16741675
void br_netlink_fini(void)
16751676
{
16761677
br_mdb_uninit();
1678+
br_vlan_rtnl_uninit();
16771679
rtnl_af_unregister(&br_af_ops);
16781680
rtnl_link_unregister(&br_link_ops);
16791681
}

net/bridge/br_private.h

+14
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,8 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v,
958958
void br_vlan_port_event(struct net_bridge_port *p, unsigned long event);
959959
int br_vlan_bridge_event(struct net_device *dev, unsigned long event,
960960
void *ptr);
961+
void br_vlan_rtnl_init(void);
962+
void br_vlan_rtnl_uninit(void);
961963

962964
static inline struct net_bridge_vlan_group *br_vlan_group(
963965
const struct net_bridge *br)
@@ -1009,6 +1011,10 @@ static inline u16 br_get_pvid(const struct net_bridge_vlan_group *vg)
10091011
return vg->pvid;
10101012
}
10111013

1014+
static inline u16 br_vlan_flags(const struct net_bridge_vlan *v, u16 pvid)
1015+
{
1016+
return v->vid == pvid ? v->flags | BRIDGE_VLAN_INFO_PVID : v->flags;
1017+
}
10121018
#else
10131019
static inline bool br_allowed_ingress(const struct net_bridge *br,
10141020
struct net_bridge_vlan_group *vg,
@@ -1152,6 +1158,14 @@ static inline int br_vlan_bridge_event(struct net_device *dev,
11521158
{
11531159
return 0;
11541160
}
1161+
1162+
static inline void br_vlan_rtnl_init(void)
1163+
{
1164+
}
1165+
1166+
static inline void br_vlan_rtnl_uninit(void)
1167+
{
1168+
}
11551169
#endif
11561170

11571171
struct nf_br_ops {

net/bridge/br_vlan.c

+148
Original file line numberDiff line numberDiff line change
@@ -1505,3 +1505,151 @@ void br_vlan_port_event(struct net_bridge_port *p, unsigned long event)
15051505
break;
15061506
}
15071507
}
1508+
1509+
static bool br_vlan_fill_vids(struct sk_buff *skb, u16 vid, u16 flags)
1510+
{
1511+
struct bridge_vlan_info info;
1512+
struct nlattr *nest;
1513+
1514+
nest = nla_nest_start(skb, BRIDGE_VLANDB_ENTRY);
1515+
if (!nest)
1516+
return false;
1517+
1518+
memset(&info, 0, sizeof(info));
1519+
info.vid = vid;
1520+
if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
1521+
info.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
1522+
if (flags & BRIDGE_VLAN_INFO_PVID)
1523+
info.flags |= BRIDGE_VLAN_INFO_PVID;
1524+
1525+
if (nla_put(skb, BRIDGE_VLANDB_ENTRY_INFO, sizeof(info), &info))
1526+
goto out_err;
1527+
1528+
nla_nest_end(skb, nest);
1529+
1530+
return true;
1531+
1532+
out_err:
1533+
nla_nest_cancel(skb, nest);
1534+
return false;
1535+
}
1536+
1537+
static int br_vlan_dump_dev(const struct net_device *dev,
1538+
struct sk_buff *skb,
1539+
struct netlink_callback *cb)
1540+
{
1541+
struct net_bridge_vlan_group *vg;
1542+
int idx = 0, s_idx = cb->args[1];
1543+
struct nlmsghdr *nlh = NULL;
1544+
struct net_bridge_vlan *v;
1545+
struct net_bridge_port *p;
1546+
struct br_vlan_msg *bvm;
1547+
struct net_bridge *br;
1548+
int err = 0;
1549+
u16 pvid;
1550+
1551+
if (!netif_is_bridge_master(dev) && !netif_is_bridge_port(dev))
1552+
return -EINVAL;
1553+
1554+
if (netif_is_bridge_master(dev)) {
1555+
br = netdev_priv(dev);
1556+
vg = br_vlan_group_rcu(br);
1557+
p = NULL;
1558+
} else {
1559+
p = br_port_get_rcu(dev);
1560+
if (WARN_ON(!p))
1561+
return -EINVAL;
1562+
vg = nbp_vlan_group_rcu(p);
1563+
br = p->br;
1564+
}
1565+
1566+
if (!vg)
1567+
return 0;
1568+
1569+
nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
1570+
RTM_NEWVLAN, sizeof(*bvm), NLM_F_MULTI);
1571+
if (!nlh)
1572+
return -EMSGSIZE;
1573+
bvm = nlmsg_data(nlh);
1574+
memset(bvm, 0, sizeof(*bvm));
1575+
bvm->family = PF_BRIDGE;
1576+
bvm->ifindex = dev->ifindex;
1577+
pvid = br_get_pvid(vg);
1578+
1579+
list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
1580+
if (!br_vlan_should_use(v))
1581+
continue;
1582+
if (idx < s_idx)
1583+
goto skip;
1584+
if (!br_vlan_fill_vids(skb, v->vid, br_vlan_flags(v, pvid))) {
1585+
err = -EMSGSIZE;
1586+
break;
1587+
}
1588+
skip:
1589+
idx++;
1590+
}
1591+
if (err)
1592+
cb->args[1] = idx;
1593+
else
1594+
cb->args[1] = 0;
1595+
nlmsg_end(skb, nlh);
1596+
1597+
return err;
1598+
}
1599+
1600+
static int br_vlan_rtm_dump(struct sk_buff *skb, struct netlink_callback *cb)
1601+
{
1602+
int idx = 0, err = 0, s_idx = cb->args[0];
1603+
struct net *net = sock_net(skb->sk);
1604+
struct br_vlan_msg *bvm;
1605+
struct net_device *dev;
1606+
1607+
err = nlmsg_parse(cb->nlh, sizeof(*bvm), NULL, 0, NULL, cb->extack);
1608+
if (err < 0)
1609+
return err;
1610+
1611+
bvm = nlmsg_data(cb->nlh);
1612+
1613+
rcu_read_lock();
1614+
if (bvm->ifindex) {
1615+
dev = dev_get_by_index_rcu(net, bvm->ifindex);
1616+
if (!dev) {
1617+
err = -ENODEV;
1618+
goto out_err;
1619+
}
1620+
err = br_vlan_dump_dev(dev, skb, cb);
1621+
if (err && err != -EMSGSIZE)
1622+
goto out_err;
1623+
} else {
1624+
for_each_netdev_rcu(net, dev) {
1625+
if (idx < s_idx)
1626+
goto skip;
1627+
1628+
err = br_vlan_dump_dev(dev, skb, cb);
1629+
if (err == -EMSGSIZE)
1630+
break;
1631+
skip:
1632+
idx++;
1633+
}
1634+
}
1635+
cb->args[0] = idx;
1636+
rcu_read_unlock();
1637+
1638+
return skb->len;
1639+
1640+
out_err:
1641+
rcu_read_unlock();
1642+
1643+
return err;
1644+
}
1645+
1646+
void br_vlan_rtnl_init(void)
1647+
{
1648+
rtnl_register_module(THIS_MODULE, PF_BRIDGE, RTM_GETVLAN, NULL,
1649+
br_vlan_rtm_dump, 0);
1650+
}
1651+
1652+
void br_vlan_rtnl_uninit(void)
1653+
{
1654+
rtnl_unregister(PF_BRIDGE, RTM_GETVLAN);
1655+
}

security/selinux/nlmsgtab.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
8585
{ RTM_GETNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_READ },
8686
{ RTM_NEWLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
8787
{ RTM_DELLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
88+
{ RTM_NEWVLAN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
89+
{ RTM_DELVLAN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
90+
{ RTM_GETVLAN, NETLINK_ROUTE_SOCKET__NLMSG_READ },
8891
};
8992

9093
static const struct nlmsg_perm nlmsg_tcpdiag_perms[] =
@@ -168,7 +171,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
168171
* structures at the top of this file with the new mappings
169172
* before updating the BUILD_BUG_ON() macro!
170173
*/
171-
BUILD_BUG_ON(RTM_MAX != (RTM_NEWLINKPROP + 3));
174+
BUILD_BUG_ON(RTM_MAX != (RTM_NEWVLAN + 3));
172175
err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
173176
sizeof(nlmsg_route_perms));
174177
break;

0 commit comments

Comments
 (0)