Skip to content

Commit efa5356

Browse files
roopa-prabhudavem330
authored andcommitted
bridge: per vlan dst_metadata netlink support
This patch adds support to attach per vlan tunnel info dst metadata. This enables bridge driver to map vlan to tunnel_info at ingress and egress. It uses the kernel dst_metadata infrastructure. The initial use case is vlan to vni bridging, but the api is generic to extend to any tunnel_info in the future: - Uapi to configure/unconfigure/dump per vlan tunnel data - netlink functions to configure vlan and tunnel_info mapping - Introduces bridge port flag BR_LWT_VLAN to enable attach/detach dst_metadata to bridged packets on ports. off by default. - changes to existing code is mainly refactor some existing vlan handling netlink code + hooks for new vlan tunnel code - I have kept the vlan tunnel code isolated in separate files. - most of the netlink vlan tunnel code is handling of vlan-tunid ranges (follows the vlan range handling code). To conserve space vlan-tunid by default are always dumped in ranges if applicable. Use case: example use for this is a vxlan bridging gateway or vtep which maps vlans to vn-segments (or vnis). iproute2 example (patched and pruned iproute2 output to just show relevant fdb entries): example shows same host mac learnt on two vni's and vlan 100 maps to vni 1000, vlan 101 maps to vni 1001 before (netdev per vni): $bridge fdb show | grep "00:02:00:00:00:03" 00:02:00:00:00:03 dev vxlan1001 vlan 101 master bridge 00:02:00:00:00:03 dev vxlan1001 dst 12.0.0.8 self 00:02:00:00:00:03 dev vxlan1000 vlan 100 master bridge 00:02:00:00:00:03 dev vxlan1000 dst 12.0.0.8 self after this patch with collect metdata in bridged mode (single netdev): $bridge fdb show | grep "00:02:00:00:00:03" 00:02:00:00:00:03 dev vxlan0 vlan 101 master bridge 00:02:00:00:00:03 dev vxlan0 src_vni 1001 dst 12.0.0.8 self 00:02:00:00:00:03 dev vxlan0 vlan 100 master bridge 00:02:00:00:00:03 dev vxlan0 src_vni 1000 dst 12.0.0.8 self CC: Nikolay Aleksandrov <[email protected]> Signed-off-by: Roopa Prabhu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b3c7ef0 commit efa5356

File tree

7 files changed

+641
-48
lines changed

7 files changed

+641
-48
lines changed

net/bridge/Makefile

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ obj-$(CONFIG_BRIDGE) += bridge.o
66

77
bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
88
br_ioctl.o br_stp.o br_stp_bpdu.o \
9-
br_stp_if.o br_stp_timer.o br_netlink.o
9+
br_stp_if.o br_stp_timer.o br_netlink.o \
10+
br_netlink_tunnel.o
1011

1112
bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o
1213

@@ -18,7 +19,7 @@ obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
1819

1920
bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o
2021

21-
bridge-$(CONFIG_BRIDGE_VLAN_FILTERING) += br_vlan.o
22+
bridge-$(CONFIG_BRIDGE_VLAN_FILTERING) += br_vlan.o br_vlan_tunnel.o
2223

2324
bridge-$(CONFIG_NET_SWITCHDEV) += br_switchdev.o
2425

net/bridge/br_netlink.c

+95-45
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "br_private.h"
2222
#include "br_private_stp.h"
23+
#include "br_private_tunnel.h"
2324

2425
static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg,
2526
u32 filter_mask)
@@ -95,9 +96,10 @@ static size_t br_get_link_af_size_filtered(const struct net_device *dev,
9596
u32 filter_mask)
9697
{
9798
struct net_bridge_vlan_group *vg = NULL;
98-
struct net_bridge_port *p;
99+
struct net_bridge_port *p = NULL;
99100
struct net_bridge *br;
100101
int num_vlan_infos;
102+
size_t vinfo_sz = 0;
101103

102104
rcu_read_lock();
103105
if (br_port_exists(dev)) {
@@ -110,8 +112,13 @@ static size_t br_get_link_af_size_filtered(const struct net_device *dev,
110112
num_vlan_infos = br_get_num_vlan_infos(vg, filter_mask);
111113
rcu_read_unlock();
112114

115+
if (p && (p->flags & BR_VLAN_TUNNEL))
116+
vinfo_sz += br_get_vlan_tunnel_info_size(vg);
117+
113118
/* Each VLAN is returned in bridge_vlan_info along with flags */
114-
return num_vlan_infos * nla_total_size(sizeof(struct bridge_vlan_info));
119+
vinfo_sz += num_vlan_infos * nla_total_size(sizeof(struct bridge_vlan_info));
120+
121+
return vinfo_sz;
115122
}
116123

117124
static inline size_t br_port_info_size(void)
@@ -128,6 +135,7 @@ static inline size_t br_port_info_size(void)
128135
+ nla_total_size(1) /* IFLA_BRPORT_UNICAST_FLOOD */
129136
+ nla_total_size(1) /* IFLA_BRPORT_PROXYARP */
130137
+ nla_total_size(1) /* IFLA_BRPORT_PROXYARP_WIFI */
138+
+ nla_total_size(1) /* IFLA_BRPORT_VLAN_TUNNEL */
131139
+ nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */
132140
+ nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */
133141
+ nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_PORT */
@@ -194,7 +202,9 @@ static int br_port_fill_attrs(struct sk_buff *skb,
194202
nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) ||
195203
nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
196204
p->topology_change_ack) ||
197-
nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending))
205+
nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending) ||
206+
nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(p->flags &
207+
BR_VLAN_TUNNEL)))
198208
return -EMSGSIZE;
199209

200210
timerval = br_timer_value(&p->message_age_timer);
@@ -417,6 +427,9 @@ static int br_fill_ifinfo(struct sk_buff *skb,
417427
err = br_fill_ifvlaninfo_compressed(skb, vg);
418428
else
419429
err = br_fill_ifvlaninfo(skb, vg);
430+
431+
if (port && (port->flags & BR_VLAN_TUNNEL))
432+
err = br_fill_vlan_tunnel_info(skb, vg);
420433
rcu_read_unlock();
421434
if (err)
422435
goto nla_put_failure;
@@ -517,60 +530,91 @@ static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p,
517530
return err;
518531
}
519532

533+
static int br_process_vlan_info(struct net_bridge *br,
534+
struct net_bridge_port *p, int cmd,
535+
struct bridge_vlan_info *vinfo_curr,
536+
struct bridge_vlan_info **vinfo_last)
537+
{
538+
if (!vinfo_curr->vid || vinfo_curr->vid >= VLAN_VID_MASK)
539+
return -EINVAL;
540+
541+
if (vinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
542+
/* check if we are already processing a range */
543+
if (*vinfo_last)
544+
return -EINVAL;
545+
*vinfo_last = vinfo_curr;
546+
/* don't allow range of pvids */
547+
if ((*vinfo_last)->flags & BRIDGE_VLAN_INFO_PVID)
548+
return -EINVAL;
549+
return 0;
550+
}
551+
552+
if (*vinfo_last) {
553+
struct bridge_vlan_info tmp_vinfo;
554+
int v, err;
555+
556+
if (!(vinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END))
557+
return -EINVAL;
558+
559+
if (vinfo_curr->vid <= (*vinfo_last)->vid)
560+
return -EINVAL;
561+
562+
memcpy(&tmp_vinfo, *vinfo_last,
563+
sizeof(struct bridge_vlan_info));
564+
for (v = (*vinfo_last)->vid; v <= vinfo_curr->vid; v++) {
565+
tmp_vinfo.vid = v;
566+
err = br_vlan_info(br, p, cmd, &tmp_vinfo);
567+
if (err)
568+
break;
569+
}
570+
*vinfo_last = NULL;
571+
572+
return 0;
573+
}
574+
575+
return br_vlan_info(br, p, cmd, vinfo_curr);
576+
}
577+
520578
static int br_afspec(struct net_bridge *br,
521579
struct net_bridge_port *p,
522580
struct nlattr *af_spec,
523581
int cmd)
524582
{
525-
struct bridge_vlan_info *vinfo_start = NULL;
526-
struct bridge_vlan_info *vinfo = NULL;
583+
struct bridge_vlan_info *vinfo_curr = NULL;
584+
struct bridge_vlan_info *vinfo_last = NULL;
527585
struct nlattr *attr;
528-
int err = 0;
529-
int rem;
586+
struct vtunnel_info tinfo_last = {};
587+
struct vtunnel_info tinfo_curr = {};
588+
int err = 0, rem;
530589

531590
nla_for_each_nested(attr, af_spec, rem) {
532-
if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
533-
continue;
534-
if (nla_len(attr) != sizeof(struct bridge_vlan_info))
535-
return -EINVAL;
536-
vinfo = nla_data(attr);
537-
if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
538-
return -EINVAL;
539-
if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
540-
if (vinfo_start)
591+
err = 0;
592+
switch (nla_type(attr)) {
593+
case IFLA_BRIDGE_VLAN_TUNNEL_INFO:
594+
if (!(p->flags & BR_VLAN_TUNNEL))
541595
return -EINVAL;
542-
vinfo_start = vinfo;
543-
/* don't allow range of pvids */
544-
if (vinfo_start->flags & BRIDGE_VLAN_INFO_PVID)
596+
err = br_parse_vlan_tunnel_info(attr, &tinfo_curr);
597+
if (err)
598+
return err;
599+
err = br_process_vlan_tunnel_info(br, p, cmd,
600+
&tinfo_curr,
601+
&tinfo_last);
602+
if (err)
603+
return err;
604+
break;
605+
case IFLA_BRIDGE_VLAN_INFO:
606+
if (nla_len(attr) != sizeof(struct bridge_vlan_info))
545607
return -EINVAL;
546-
continue;
608+
vinfo_curr = nla_data(attr);
609+
err = br_process_vlan_info(br, p, cmd, vinfo_curr,
610+
&vinfo_last);
611+
if (err)
612+
return err;
613+
break;
547614
}
548615

549-
if (vinfo_start) {
550-
struct bridge_vlan_info tmp_vinfo;
551-
int v;
552-
553-
if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
554-
return -EINVAL;
555-
556-
if (vinfo->vid <= vinfo_start->vid)
557-
return -EINVAL;
558-
559-
memcpy(&tmp_vinfo, vinfo_start,
560-
sizeof(struct bridge_vlan_info));
561-
562-
for (v = vinfo_start->vid; v <= vinfo->vid; v++) {
563-
tmp_vinfo.vid = v;
564-
err = br_vlan_info(br, p, cmd, &tmp_vinfo);
565-
if (err)
566-
break;
567-
}
568-
vinfo_start = NULL;
569-
} else {
570-
err = br_vlan_info(br, p, cmd, vinfo);
571-
}
572616
if (err)
573-
break;
617+
return err;
574618
}
575619

576620
return err;
@@ -630,8 +674,9 @@ static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[],
630674
/* Process bridge protocol info on port */
631675
static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
632676
{
633-
int err;
634677
unsigned long old_flags = p->flags;
678+
bool br_vlan_tunnel_old = false;
679+
int err;
635680

636681
br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE);
637682
br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD);
@@ -644,6 +689,11 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
644689
br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
645690
br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);
646691

692+
br_vlan_tunnel_old = (p->flags & BR_VLAN_TUNNEL) ? true : false;
693+
br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL);
694+
if (br_vlan_tunnel_old && !(p->flags & BR_VLAN_TUNNEL))
695+
nbp_vlan_tunnel_info_flush(p);
696+
647697
if (tb[IFLA_BRPORT_COST]) {
648698
err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
649699
if (err)

0 commit comments

Comments
 (0)