Skip to content

Commit bcf2766

Browse files
nbd168davem330
authored andcommitted
net: bridge: resolve forwarding path for VLAN tag actions in bridge devices
Depending on the VLAN settings of the bridge and the port, the bridge can either add or remove a tag. When vlan filtering is enabled, the fdb lookup also needs to know the VLAN tag/proto for the destination address To provide this, keep track of the stack of VLAN tags for the path in the lookup context Signed-off-by: Felix Fietkau <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ec9d16b commit bcf2766

File tree

5 files changed

+117
-1
lines changed

5 files changed

+117
-1
lines changed

include/linux/netdevice.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,10 +862,20 @@ struct net_device_path {
862862
u16 id;
863863
__be16 proto;
864864
} encap;
865+
struct {
866+
enum {
867+
DEV_PATH_BR_VLAN_KEEP,
868+
DEV_PATH_BR_VLAN_TAG,
869+
DEV_PATH_BR_VLAN_UNTAG,
870+
} vlan_mode;
871+
u16 vlan_id;
872+
__be16 vlan_proto;
873+
} bridge;
865874
};
866875
};
867876

868877
#define NET_DEVICE_PATH_STACK_MAX 5
878+
#define NET_DEVICE_PATH_VLAN_MAX 2
869879

870880
struct net_device_path_stack {
871881
int num_paths;
@@ -875,6 +885,12 @@ struct net_device_path_stack {
875885
struct net_device_path_ctx {
876886
const struct net_device *dev;
877887
const u8 *daddr;
888+
889+
int num_vlans;
890+
struct {
891+
u16 id;
892+
__be16 proto;
893+
} vlan[NET_DEVICE_PATH_VLAN_MAX];
878894
};
879895

880896
enum tc_setup_type {

net/8021q/vlan_dev.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,12 @@ static int vlan_dev_fill_forward_path(struct net_device_path_ctx *ctx,
786786
path->encap.proto = vlan->vlan_proto;
787787
path->dev = ctx->dev;
788788
ctx->dev = vlan->real_dev;
789+
if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan))
790+
return -ENOSPC;
791+
792+
ctx->vlan[ctx->num_vlans].id = vlan->vlan_id;
793+
ctx->vlan[ctx->num_vlans].proto = vlan->vlan_proto;
794+
ctx->num_vlans++;
789795

790796
return 0;
791797
}

net/bridge/br_device.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,18 +396,39 @@ static int br_fill_forward_path(struct net_device_path_ctx *ctx,
396396
return -1;
397397

398398
br = netdev_priv(ctx->dev);
399-
f = br_fdb_find_rcu(br, ctx->daddr, 0);
399+
400+
br_vlan_fill_forward_path_pvid(br, ctx, path);
401+
402+
f = br_fdb_find_rcu(br, ctx->daddr, path->bridge.vlan_id);
400403
if (!f || !f->dst)
401404
return -1;
402405

403406
dst = READ_ONCE(f->dst);
404407
if (!dst)
405408
return -1;
406409

410+
if (br_vlan_fill_forward_path_mode(br, dst, path))
411+
return -1;
412+
407413
path->type = DEV_PATH_BRIDGE;
408414
path->dev = dst->br->dev;
409415
ctx->dev = dst->dev;
410416

417+
switch (path->bridge.vlan_mode) {
418+
case DEV_PATH_BR_VLAN_TAG:
419+
if (ctx->num_vlans >= ARRAY_SIZE(ctx->vlan))
420+
return -ENOSPC;
421+
ctx->vlan[ctx->num_vlans].id = path->bridge.vlan_id;
422+
ctx->vlan[ctx->num_vlans].proto = path->bridge.vlan_proto;
423+
ctx->num_vlans++;
424+
break;
425+
case DEV_PATH_BR_VLAN_UNTAG:
426+
ctx->num_vlans--;
427+
break;
428+
case DEV_PATH_BR_VLAN_KEEP:
429+
break;
430+
}
431+
411432
return 0;
412433
}
413434

net/bridge/br_private.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,13 @@ void br_vlan_notify(const struct net_bridge *br,
11181118
bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
11191119
const struct net_bridge_vlan *range_end);
11201120

1121+
void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
1122+
struct net_device_path_ctx *ctx,
1123+
struct net_device_path *path);
1124+
int br_vlan_fill_forward_path_mode(struct net_bridge *br,
1125+
struct net_bridge_port *dst,
1126+
struct net_device_path *path);
1127+
11211128
static inline struct net_bridge_vlan_group *br_vlan_group(
11221129
const struct net_bridge *br)
11231130
{
@@ -1277,6 +1284,19 @@ static inline int nbp_get_num_vlan_infos(struct net_bridge_port *p,
12771284
return 0;
12781285
}
12791286

1287+
static inline void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
1288+
struct net_device_path_ctx *ctx,
1289+
struct net_device_path *path)
1290+
{
1291+
}
1292+
1293+
static inline int br_vlan_fill_forward_path_mode(struct net_bridge *br,
1294+
struct net_bridge_port *dst,
1295+
struct net_device_path *path)
1296+
{
1297+
return 0;
1298+
}
1299+
12801300
static inline struct net_bridge_vlan_group *br_vlan_group(
12811301
const struct net_bridge *br)
12821302
{

net/bridge/br_vlan.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,59 @@ int br_vlan_get_pvid_rcu(const struct net_device *dev, u16 *p_pvid)
13391339
}
13401340
EXPORT_SYMBOL_GPL(br_vlan_get_pvid_rcu);
13411341

1342+
void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
1343+
struct net_device_path_ctx *ctx,
1344+
struct net_device_path *path)
1345+
{
1346+
struct net_bridge_vlan_group *vg;
1347+
int idx = ctx->num_vlans - 1;
1348+
u16 vid;
1349+
1350+
path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
1351+
1352+
if (!br_opt_get(br, BROPT_VLAN_ENABLED))
1353+
return;
1354+
1355+
vg = br_vlan_group(br);
1356+
1357+
if (idx >= 0 &&
1358+
ctx->vlan[idx].proto == br->vlan_proto) {
1359+
vid = ctx->vlan[idx].id;
1360+
} else {
1361+
path->bridge.vlan_mode = DEV_PATH_BR_VLAN_TAG;
1362+
vid = br_get_pvid(vg);
1363+
}
1364+
1365+
path->bridge.vlan_id = vid;
1366+
path->bridge.vlan_proto = br->vlan_proto;
1367+
}
1368+
1369+
int br_vlan_fill_forward_path_mode(struct net_bridge *br,
1370+
struct net_bridge_port *dst,
1371+
struct net_device_path *path)
1372+
{
1373+
struct net_bridge_vlan_group *vg;
1374+
struct net_bridge_vlan *v;
1375+
1376+
if (!br_opt_get(br, BROPT_VLAN_ENABLED))
1377+
return 0;
1378+
1379+
vg = nbp_vlan_group_rcu(dst);
1380+
v = br_vlan_find(vg, path->bridge.vlan_id);
1381+
if (!v || !br_vlan_should_use(v))
1382+
return -EINVAL;
1383+
1384+
if (!(v->flags & BRIDGE_VLAN_INFO_UNTAGGED))
1385+
return 0;
1386+
1387+
if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG)
1388+
path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
1389+
else
1390+
path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
1391+
1392+
return 0;
1393+
}
1394+
13421395
int br_vlan_get_info(const struct net_device *dev, u16 vid,
13431396
struct bridge_vlan_info *p_vinfo)
13441397
{

0 commit comments

Comments
 (0)