1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Wed, 24 Mar 2021 02:30:48 +0100
3 Subject: [PATCH] netfilter: flowtable: bridge vlan hardware offload and
6 The switch might have already added the VLAN tag through PVID hardware
7 offload. Keep this extra VLAN in the flowtable but skip it on egress.
9 Signed-off-by: Felix Fietkau <nbd@nbd.name>
10 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
13 --- a/include/linux/netdevice.h
14 +++ b/include/linux/netdevice.h
15 @@ -872,6 +872,7 @@ struct net_device_path {
16 DEV_PATH_BR_VLAN_KEEP,
18 DEV_PATH_BR_VLAN_UNTAG,
19 + DEV_PATH_BR_VLAN_UNTAG_HW,
23 --- a/include/net/netfilter/nf_flow_table.h
24 +++ b/include/net/netfilter/nf_flow_table.h
25 @@ -123,9 +123,10 @@ struct flow_offload_tuple {
26 /* All members above are keys for lookups, see flow_offload_hash(). */
37 struct dst_entry *dst_cache;
38 @@ -184,7 +185,8 @@ struct nf_flow_route {
41 } encap[NF_FLOW_TABLE_ENCAP_MAX];
48 --- a/net/bridge/br_device.c
49 +++ b/net/bridge/br_device.c
50 @@ -435,6 +435,7 @@ static int br_fill_forward_path(struct n
51 ctx->vlan[ctx->num_vlans].proto = path->bridge.vlan_proto;
54 + case DEV_PATH_BR_VLAN_UNTAG_HW:
55 case DEV_PATH_BR_VLAN_UNTAG:
58 --- a/net/bridge/br_vlan.c
59 +++ b/net/bridge/br_vlan.c
60 @@ -1397,6 +1397,8 @@ int br_vlan_fill_forward_path_mode(struc
62 if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG)
63 path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
64 + else if (v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
65 + path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW;
67 path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
69 --- a/net/netfilter/nf_flow_table_core.c
70 +++ b/net/netfilter/nf_flow_table_core.c
71 @@ -95,6 +95,8 @@ static int flow_offload_fill_route(struc
72 for (i = route->tuple[dir].in.num_encaps - 1; i >= 0; i--) {
73 flow_tuple->encap[j].id = route->tuple[dir].in.encap[i].id;
74 flow_tuple->encap[j].proto = route->tuple[dir].in.encap[i].proto;
75 + if (route->tuple[dir].in.ingress_vlans & BIT(i))
76 + flow_tuple->in_vlan_ingress |= BIT(j);
79 flow_tuple->encap_num = route->tuple[dir].in.num_encaps;
80 --- a/net/netfilter/nf_flow_table_offload.c
81 +++ b/net/netfilter/nf_flow_table_offload.c
82 @@ -594,8 +594,12 @@ nf_flow_rule_route_common(struct net *ne
83 other_tuple = &flow->tuplehash[!dir].tuple;
85 for (i = 0; i < other_tuple->encap_num; i++) {
86 - struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
87 + struct flow_action_entry *entry;
89 + if (other_tuple->in_vlan_ingress & BIT(i))
92 + entry = flow_action_entry_next(flow_rule);
93 entry->id = FLOW_ACTION_VLAN_PUSH;
94 entry->vlan.vid = other_tuple->encap[i].id;
95 entry->vlan.proto = other_tuple->encap[i].proto;
96 --- a/net/netfilter/nft_flow_offload.c
97 +++ b/net/netfilter/nft_flow_offload.c
98 @@ -72,6 +72,7 @@ struct nft_forward_info {
100 } encap[NF_FLOW_TABLE_ENCAP_MAX];
103 u8 h_source[ETH_ALEN];
105 enum flow_offload_xmit_type xmit_type;
106 @@ -130,6 +131,9 @@ static void nft_dev_path_info(const stru
107 memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
109 switch (path->bridge.vlan_mode) {
110 + case DEV_PATH_BR_VLAN_UNTAG_HW:
111 + info->ingress_vlans |= BIT(info->num_encaps - 1);
113 case DEV_PATH_BR_VLAN_TAG:
114 info->encap[info->num_encaps].id = path->bridge.vlan_id;
115 info->encap[info->num_encaps].proto = path->bridge.vlan_proto;
116 @@ -198,6 +202,7 @@ static void nft_dev_forward_path(struct
117 route->tuple[!dir].in.encap[i].proto = info.encap[i].proto;
119 route->tuple[!dir].in.num_encaps = info.num_encaps;
120 + route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
122 if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
123 memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);