netfilter: flowtable: bridge vlan hardware offload and switchdev
authorFelix Fietkau <nbd@nbd.name>
Wed, 24 Mar 2021 01:30:48 +0000 (02:30 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 24 Mar 2021 19:48:39 +0000 (12:48 -0700)
The switch might have already added the VLAN tag through PVID hardware
offload. Keep this extra VLAN in the flowtable but skip it on egress.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/netdevice.h
include/net/netfilter/nf_flow_table.h
net/bridge/br_device.c
net/bridge/br_vlan.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nf_flow_table_offload.c
net/netfilter/nft_flow_offload.c

index 90db741..02fa1da 100644 (file)
@@ -870,6 +870,7 @@ struct net_device_path {
                                DEV_PATH_BR_VLAN_KEEP,
                                DEV_PATH_BR_VLAN_TAG,
                                DEV_PATH_BR_VLAN_UNTAG,
+                               DEV_PATH_BR_VLAN_UNTAG_HW,
                        }               vlan_mode;
                        u16             vlan_id;
                        __be16          vlan_proto;
index 52afcee..4d991c1 100644 (file)
@@ -123,9 +123,10 @@ struct flow_offload_tuple {
        /* All members above are keys for lookups, see flow_offload_hash(). */
        struct { }                      __hash;
 
-       u8                              dir:4,
+       u8                              dir:2,
                                        xmit_type:2,
-                                       encap_num:2;
+                                       encap_num:2,
+                                       in_vlan_ingress:2;
        u16                             mtu;
        union {
                struct dst_entry        *dst_cache;
@@ -185,7 +186,8 @@ struct nf_flow_route {
                                u16             id;
                                __be16          proto;
                        } encap[NF_FLOW_TABLE_ENCAP_MAX];
-                       u8                      num_encaps;
+                       u8                      num_encaps:2,
+                                               ingress_vlans:2;
                } in;
                struct {
                        u32                     ifindex;
index 0c72503..e8b626c 100644 (file)
@@ -422,6 +422,7 @@ static int br_fill_forward_path(struct net_device_path_ctx *ctx,
                ctx->vlan[ctx->num_vlans].proto = path->bridge.vlan_proto;
                ctx->num_vlans++;
                break;
+       case DEV_PATH_BR_VLAN_UNTAG_HW:
        case DEV_PATH_BR_VLAN_UNTAG:
                ctx->num_vlans--;
                break;
index c92240b..da3256a 100644 (file)
@@ -1386,6 +1386,8 @@ int br_vlan_fill_forward_path_mode(struct net_bridge *br,
 
        if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG)
                path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
+       else if (v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)
+               path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW;
        else
                path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
 
index f728c95..8fa7bf9 100644 (file)
@@ -95,6 +95,8 @@ static int flow_offload_fill_route(struct flow_offload *flow,
        for (i = route->tuple[dir].in.num_encaps - 1; i >= 0; i--) {
                flow_tuple->encap[j].id = route->tuple[dir].in.encap[i].id;
                flow_tuple->encap[j].proto = route->tuple[dir].in.encap[i].proto;
+               if (route->tuple[dir].in.ingress_vlans & BIT(i))
+                       flow_tuple->in_vlan_ingress |= BIT(j);
                j++;
        }
        flow_tuple->encap_num = route->tuple[dir].in.num_encaps;
index e0d0796..9326ba7 100644 (file)
@@ -594,8 +594,12 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
        other_tuple = &flow->tuplehash[!dir].tuple;
 
        for (i = 0; i < other_tuple->encap_num; i++) {
-               struct flow_action_entry *entry = flow_action_entry_next(flow_rule);
+               struct flow_action_entry *entry;
 
+               if (other_tuple->in_vlan_ingress & BIT(i))
+                       continue;
+
+               entry = flow_action_entry_next(flow_rule);
                entry->id = FLOW_ACTION_VLAN_PUSH;
                entry->vlan.vid = other_tuple->encap[i].id;
                entry->vlan.proto = other_tuple->encap[i].proto;
index d25b4b1..4843dd2 100644 (file)
@@ -72,6 +72,7 @@ struct nft_forward_info {
                __be16  proto;
        } encap[NF_FLOW_TABLE_ENCAP_MAX];
        u8 num_encaps;
+       u8 ingress_vlans;
        u8 h_source[ETH_ALEN];
        u8 h_dest[ETH_ALEN];
        enum flow_offload_xmit_type xmit_type;
@@ -130,6 +131,9 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
                                memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN);
 
                        switch (path->bridge.vlan_mode) {
+                       case DEV_PATH_BR_VLAN_UNTAG_HW:
+                               info->ingress_vlans |= BIT(info->num_encaps - 1);
+                               break;
                        case DEV_PATH_BR_VLAN_TAG:
                                info->encap[info->num_encaps].id = path->bridge.vlan_id;
                                info->encap[info->num_encaps].proto = path->bridge.vlan_proto;
@@ -198,6 +202,7 @@ static void nft_dev_forward_path(struct nf_flow_route *route,
                route->tuple[!dir].in.encap[i].proto = info.encap[i].proto;
        }
        route->tuple[!dir].in.num_encaps = info.num_encaps;
+       route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
 
        if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
                memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);