* [PATCH v4 net-next 01/13] netfilter: nf_flow_table_offload: Add nf_flow_encap_push() for xmit direct
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 02/13] netfilter: bridge: Add conntrack double vlan and pppoe Eric Woudstra
` (11 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
Loosely based on wenxu's patches:
"nf_flow_table_offload: offload the vlan/PPPoE encap in the flowtable".
Fixed double vlan and pppoe packets, almost entirely rewriting the patch.
After this patch, it is possible to transmit packets in the fastpath with
outgoing encaps, without using vlan- and/or pppoe-devices.
This makes it possible to use more different kinds of network setups.
For example, when bridge tagging is used to egress vlan tagged
packets using the forward fastpath. Another example is passing 802.1q
tagged packets through a bridge using the bridge fastpath.
This also makes the software fastpath process more similar to the
hardware offloaded fastpath process, where encaps are also pushed.
After applying this patch, always info->outdev = info->hw_outdev,
so the netfilter code can be further cleaned up by removing:
* hw_outdev from struct nft_forward_info
* out.hw_ifindex from struct nf_flow_route
* out.hw_ifidx from struct flow_offload_tuple
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
net/netfilter/nf_flow_table_ip.c | 96 +++++++++++++++++++++++++++++++-
net/netfilter/nft_flow_offload.c | 6 +-
2 files changed, 96 insertions(+), 6 deletions(-)
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 98edcaa37b38..290d8e10d85b 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -302,6 +302,92 @@ static bool nf_flow_skb_encap_protocol(struct sk_buff *skb, __be16 proto,
return false;
}
+static int nf_flow_vlan_inner_push(struct sk_buff *skb, __be16 proto, u16 id)
+{
+ struct vlan_hdr *vhdr;
+
+ if (skb_cow_head(skb, VLAN_HLEN))
+ return -1;
+
+ __skb_push(skb, VLAN_HLEN);
+ skb_reset_network_header(skb);
+
+ vhdr = (struct vlan_hdr *)(skb->data);
+ vhdr->h_vlan_TCI = htons(id);
+ vhdr->h_vlan_encapsulated_proto = skb->protocol;
+ skb->protocol = proto;
+
+ return 0;
+}
+
+static int nf_flow_ppoe_push(struct sk_buff *skb, u16 id)
+{
+ struct ppp_hdr {
+ struct pppoe_hdr hdr;
+ __be16 proto;
+ } *ph;
+ int data_len = skb->len + 2;
+ __be16 proto;
+
+ if (skb_cow_head(skb, PPPOE_SES_HLEN))
+ return -1;
+
+ if (skb->protocol == htons(ETH_P_IP))
+ proto = htons(PPP_IP);
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ proto = htons(PPP_IPV6);
+ else
+ return -1;
+
+ __skb_push(skb, PPPOE_SES_HLEN);
+ skb_reset_network_header(skb);
+
+ ph = (struct ppp_hdr *)(skb->data);
+ ph->hdr.ver = 1;
+ ph->hdr.type = 1;
+ ph->hdr.code = 0;
+ ph->hdr.sid = htons(id);
+ ph->hdr.length = htons(data_len);
+ ph->proto = proto;
+ skb->protocol = htons(ETH_P_PPP_SES);
+
+ return 0;
+}
+
+static int nf_flow_encap_push(struct sk_buff *skb,
+ struct flow_offload_tuple_rhash *tuplehash,
+ unsigned short *type)
+{
+ int i = 0, ret = 0;
+
+ if (!tuplehash->tuple.encap_num)
+ return 0;
+
+ if (tuplehash->tuple.encap[i].proto == htons(ETH_P_8021Q) ||
+ tuplehash->tuple.encap[i].proto == htons(ETH_P_8021AD)) {
+ __vlan_hwaccel_put_tag(skb, tuplehash->tuple.encap[i].proto,
+ tuplehash->tuple.encap[i].id);
+ i++;
+ if (i >= tuplehash->tuple.encap_num)
+ return 0;
+ }
+
+ switch (tuplehash->tuple.encap[i].proto) {
+ case htons(ETH_P_8021Q):
+ *type = ETH_P_8021Q;
+ ret = nf_flow_vlan_inner_push(skb,
+ tuplehash->tuple.encap[i].proto,
+ tuplehash->tuple.encap[i].id);
+ break;
+ case htons(ETH_P_PPP_SES):
+ *type = ETH_P_PPP_SES;
+ ret = nf_flow_ppoe_push(skb,
+ tuplehash->tuple.encap[i].id);
+ break;
+ }
+ return ret;
+}
+
static void nf_flow_encap_pop(struct sk_buff *skb,
struct flow_offload_tuple_rhash *tuplehash)
{
@@ -331,6 +417,7 @@ static void nf_flow_encap_pop(struct sk_buff *skb,
static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
const struct flow_offload_tuple_rhash *tuplehash,
+ struct flow_offload_tuple_rhash *other_tuplehash,
unsigned short type)
{
struct net_device *outdev;
@@ -339,6 +426,9 @@ static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
if (!outdev)
return NF_DROP;
+ if (nf_flow_encap_push(skb, other_tuplehash, &type) < 0)
+ return NF_DROP;
+
skb->dev = outdev;
dev_hard_header(skb, skb->dev, type, tuplehash->tuple.out.h_dest,
tuplehash->tuple.out.h_source, skb->len);
@@ -458,7 +548,8 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
ret = NF_STOLEN;
break;
case FLOW_OFFLOAD_XMIT_DIRECT:
- ret = nf_flow_queue_xmit(state->net, skb, tuplehash, ETH_P_IP);
+ ret = nf_flow_queue_xmit(state->net, skb, tuplehash,
+ &flow->tuplehash[!dir], ETH_P_IP);
if (ret == NF_DROP)
flow_offload_teardown(flow);
break;
@@ -753,7 +844,8 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
ret = NF_STOLEN;
break;
case FLOW_OFFLOAD_XMIT_DIRECT:
- ret = nf_flow_queue_xmit(state->net, skb, tuplehash, ETH_P_IPV6);
+ ret = nf_flow_queue_xmit(state->net, skb, tuplehash,
+ &flow->tuplehash[!dir], ETH_P_IPV6);
if (ret == NF_DROP)
flow_offload_teardown(flow);
break;
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index 7b84d8d3469c..cdf1771906b8 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -124,13 +124,12 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
info->indev = NULL;
break;
}
- if (!info->outdev)
- info->outdev = path->dev;
info->encap[info->num_encaps].id = path->encap.id;
info->encap[info->num_encaps].proto = path->encap.proto;
info->num_encaps++;
if (path->type == DEV_PATH_PPPOE)
memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
+ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
break;
case DEV_PATH_BRIDGE:
if (is_zero_ether_addr(info->h_source))
@@ -158,8 +157,7 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
break;
}
}
- if (!info->outdev)
- info->outdev = info->indev;
+ info->outdev = info->indev;
info->hw_outdev = info->indev;
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 02/13] netfilter: bridge: Add conntrack double vlan and pppoe
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 01/13] netfilter: nf_flow_table_offload: Add nf_flow_encap_push() for xmit direct Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:33 ` Nikolay Aleksandrov
2025-01-07 9:05 ` [PATCH v4 net-next 03/13] netfilter: nft_chain_filter: Add bridge " Eric Woudstra
` (10 subsequent siblings)
12 siblings, 1 reply; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
This adds the capability to conntrack 802.1ad, QinQ, PPPoE and PPPoE-in-Q
packets that are passing a bridge.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
net/bridge/netfilter/nf_conntrack_bridge.c | 88 ++++++++++++++++++----
1 file changed, 75 insertions(+), 13 deletions(-)
diff --git a/net/bridge/netfilter/nf_conntrack_bridge.c b/net/bridge/netfilter/nf_conntrack_bridge.c
index 816bb0fde718..31e2bcd71735 100644
--- a/net/bridge/netfilter/nf_conntrack_bridge.c
+++ b/net/bridge/netfilter/nf_conntrack_bridge.c
@@ -241,56 +241,118 @@ static unsigned int nf_ct_bridge_pre(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct nf_hook_state bridge_state = *state;
+ __be16 outer_proto, inner_proto;
enum ip_conntrack_info ctinfo;
+ int ret, offset = 0;
struct nf_conn *ct;
- u32 len;
- int ret;
+ u32 len, data_len;
ct = nf_ct_get(skb, &ctinfo);
if ((ct && !nf_ct_is_template(ct)) ||
ctinfo == IP_CT_UNTRACKED)
return NF_ACCEPT;
+ switch (skb->protocol) {
+ case htons(ETH_P_PPP_SES): {
+ struct ppp_hdr {
+ struct pppoe_hdr hdr;
+ __be16 proto;
+ } *ph = (struct ppp_hdr *)(skb->data);
+
+ data_len = ntohs(ph->hdr.length) - 2;
+ offset = PPPOE_SES_HLEN;
+ outer_proto = skb->protocol;
+ switch (ph->proto) {
+ case htons(PPP_IP):
+ inner_proto = htons(ETH_P_IP);
+ break;
+ case htons(PPP_IPV6):
+ inner_proto = htons(ETH_P_IPV6);
+ break;
+ default:
+ return NF_ACCEPT;
+ }
+ break;
+ }
+ case htons(ETH_P_8021Q): {
+ struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data);
+
+ data_len = 0xffffffff;
+ offset = VLAN_HLEN;
+ outer_proto = skb->protocol;
+ inner_proto = vhdr->h_vlan_encapsulated_proto;
+ break;
+ }
+ default:
+ data_len = 0xffffffff;
+ break;
+ }
+
+ if (offset) {
+ switch (inner_proto) {
+ case htons(ETH_P_IP):
+ case htons(ETH_P_IPV6):
+ if (!pskb_may_pull(skb, offset))
+ return NF_ACCEPT;
+ skb_pull_rcsum(skb, offset);
+ skb_reset_network_header(skb);
+ skb->protocol = inner_proto;
+ break;
+ default:
+ return NF_ACCEPT;
+ }
+ }
+
+ ret = NF_ACCEPT;
switch (skb->protocol) {
case htons(ETH_P_IP):
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
- return NF_ACCEPT;
+ goto do_not_track;
len = skb_ip_totlen(skb);
+ if (data_len < len)
+ len = data_len;
if (pskb_trim_rcsum(skb, len))
- return NF_ACCEPT;
+ goto do_not_track;
if (nf_ct_br_ip_check(skb))
- return NF_ACCEPT;
+ goto do_not_track;
bridge_state.pf = NFPROTO_IPV4;
ret = nf_ct_br_defrag4(skb, &bridge_state);
break;
case htons(ETH_P_IPV6):
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
- return NF_ACCEPT;
+ goto do_not_track;
len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
+ if (data_len < len)
+ len = data_len;
if (pskb_trim_rcsum(skb, len))
- return NF_ACCEPT;
+ goto do_not_track;
if (nf_ct_br_ipv6_check(skb))
- return NF_ACCEPT;
+ goto do_not_track;
bridge_state.pf = NFPROTO_IPV6;
ret = nf_ct_br_defrag6(skb, &bridge_state);
break;
default:
nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
- return NF_ACCEPT;
+ goto do_not_track;
}
- if (ret != NF_ACCEPT)
- return ret;
+ if (ret == NF_ACCEPT)
+ ret = nf_conntrack_in(skb, &bridge_state);
- return nf_conntrack_in(skb, &bridge_state);
+do_not_track:
+ if (offset) {
+ skb_push_rcsum(skb, offset);
+ skb_reset_network_header(skb);
+ skb->protocol = outer_proto;
+ }
+ return ret;
}
-
static unsigned int nf_ct_bridge_in(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH v4 net-next 02/13] netfilter: bridge: Add conntrack double vlan and pppoe
2025-01-07 9:05 ` [PATCH v4 net-next 02/13] netfilter: bridge: Add conntrack double vlan and pppoe Eric Woudstra
@ 2025-01-07 9:33 ` Nikolay Aleksandrov
0 siblings, 0 replies; 15+ messages in thread
From: Nikolay Aleksandrov @ 2025-01-07 9:33 UTC (permalink / raw)
To: Eric Woudstra, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Andrew Lunn, Pablo Neira Ayuso,
Jozsef Kadlecsik, Jiri Pirko, Ivan Vecera, Roopa Prabhu,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek
On 1/7/25 11:05, Eric Woudstra wrote:
> This adds the capability to conntrack 802.1ad, QinQ, PPPoE and PPPoE-in-Q
> packets that are passing a bridge.
>
> Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
> ---
> net/bridge/netfilter/nf_conntrack_bridge.c | 88 ++++++++++++++++++----
> 1 file changed, 75 insertions(+), 13 deletions(-)
>
> diff --git a/net/bridge/netfilter/nf_conntrack_bridge.c b/net/bridge/netfilter/nf_conntrack_bridge.c
> index 816bb0fde718..31e2bcd71735 100644
> --- a/net/bridge/netfilter/nf_conntrack_bridge.c
> +++ b/net/bridge/netfilter/nf_conntrack_bridge.c
> @@ -241,56 +241,118 @@ static unsigned int nf_ct_bridge_pre(void *priv, struct sk_buff *skb,
> const struct nf_hook_state *state)
> {
> struct nf_hook_state bridge_state = *state;
> + __be16 outer_proto, inner_proto;
> enum ip_conntrack_info ctinfo;
> + int ret, offset = 0;
> struct nf_conn *ct;
> - u32 len;
> - int ret;
> + u32 len, data_len;
>
> ct = nf_ct_get(skb, &ctinfo);
> if ((ct && !nf_ct_is_template(ct)) ||
> ctinfo == IP_CT_UNTRACKED)
> return NF_ACCEPT;
>
In all cases below I think you should make sure the headers are present
in the linear part of the skb, either do pskb_may_pull() or use
skb_header_pointer(). This is executed in the PRE bridge hook, so nothing
has been pulled yet by it.
> + switch (skb->protocol) {
> + case htons(ETH_P_PPP_SES): {
> + struct ppp_hdr {
> + struct pppoe_hdr hdr;
> + __be16 proto;
> + } *ph = (struct ppp_hdr *)(skb->data);
> +
> + data_len = ntohs(ph->hdr.length) - 2;
> + offset = PPPOE_SES_HLEN;
> + outer_proto = skb->protocol;
> + switch (ph->proto) {
> + case htons(PPP_IP):
> + inner_proto = htons(ETH_P_IP);
> + break;
> + case htons(PPP_IPV6):
> + inner_proto = htons(ETH_P_IPV6);
> + break;
> + default:
> + return NF_ACCEPT;
> + }
> + break;
> + }
> + case htons(ETH_P_8021Q): {
> + struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data);
> +
> + data_len = 0xffffffff;
> + offset = VLAN_HLEN;
> + outer_proto = skb->protocol;
> + inner_proto = vhdr->h_vlan_encapsulated_proto;
> + break;
> + }
> + default:
> + data_len = 0xffffffff;
> + break;
> + }
> +
> + if (offset) {
> + switch (inner_proto) {
> + case htons(ETH_P_IP):
> + case htons(ETH_P_IPV6):
> + if (!pskb_may_pull(skb, offset))
> + return NF_ACCEPT;
> + skb_pull_rcsum(skb, offset);> + skb_reset_network_header(skb);
> + skb->protocol = inner_proto;
> + break;
> + default:
> + return NF_ACCEPT;
> + }
> + }
> +
> + ret = NF_ACCEPT;
> switch (skb->protocol) {
> case htons(ETH_P_IP):
> if (!pskb_may_pull(skb, sizeof(struct iphdr)))
> - return NF_ACCEPT;
> + goto do_not_track;
>
> len = skb_ip_totlen(skb);
> + if (data_len < len)
> + len = data_len;
> if (pskb_trim_rcsum(skb, len))
> - return NF_ACCEPT;
> + goto do_not_track;
>
> if (nf_ct_br_ip_check(skb))
> - return NF_ACCEPT;
> + goto do_not_track;
>
> bridge_state.pf = NFPROTO_IPV4;
> ret = nf_ct_br_defrag4(skb, &bridge_state);
> break;
> case htons(ETH_P_IPV6):
> if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
> - return NF_ACCEPT;
> + goto do_not_track;
>
> len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
> + if (data_len < len)
> + len = data_len;
> if (pskb_trim_rcsum(skb, len))
> - return NF_ACCEPT;
> + goto do_not_track;
>
> if (nf_ct_br_ipv6_check(skb))
> - return NF_ACCEPT;
> + goto do_not_track;
>
> bridge_state.pf = NFPROTO_IPV6;
> ret = nf_ct_br_defrag6(skb, &bridge_state);
> break;
> default:
> nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
> - return NF_ACCEPT;
> + goto do_not_track;
> }
>
> - if (ret != NF_ACCEPT)
> - return ret;
> + if (ret == NF_ACCEPT)
> + ret = nf_conntrack_in(skb, &bridge_state);
>
> - return nf_conntrack_in(skb, &bridge_state);
> +do_not_track:
> + if (offset) {
> + skb_push_rcsum(skb, offset);
> + skb_reset_network_header(skb);
> + skb->protocol = outer_proto;
> + }
> + return ret;
> }
> -
> static unsigned int nf_ct_bridge_in(void *priv, struct sk_buff *skb,
> const struct nf_hook_state *state)
> {
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v4 net-next 03/13] netfilter: nft_chain_filter: Add bridge double vlan and pppoe
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 01/13] netfilter: nf_flow_table_offload: Add nf_flow_encap_push() for xmit direct Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 02/13] netfilter: bridge: Add conntrack double vlan and pppoe Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 04/13] bridge: Add filling forward path from port to port Eric Woudstra
` (9 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
This adds the capability to evaluate 802.1ad, QinQ, PPPoE and PPPoE-in-Q
packets in the bridge filter chain.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
net/netfilter/nft_chain_filter.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nft_chain_filter.c b/net/netfilter/nft_chain_filter.c
index 7010541fcca6..91aa3fa43d31 100644
--- a/net/netfilter/nft_chain_filter.c
+++ b/net/netfilter/nft_chain_filter.c
@@ -232,11 +232,27 @@ nft_do_chain_bridge(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
+ struct ethhdr *ethh = eth_hdr(skb);
struct nft_pktinfo pkt;
+ int thoff;
nft_set_pktinfo(&pkt, skb, state);
- switch (eth_hdr(skb)->h_proto) {
+ switch (ethh->h_proto) {
+ case htons(ETH_P_PPP_SES):
+ thoff = PPPOE_SES_HLEN;
+ ethh += thoff;
+ break;
+ case htons(ETH_P_8021Q):
+ thoff = VLAN_HLEN;
+ ethh += thoff;
+ break;
+ default:
+ thoff = 0;
+ break;
+ }
+
+ switch (ethh->h_proto) {
case htons(ETH_P_IP):
nft_set_pktinfo_ipv4_validate(&pkt);
break;
@@ -248,6 +264,8 @@ nft_do_chain_bridge(void *priv,
break;
}
+ pkt.thoff += thoff;
+
return nft_do_chain(&pkt, priv);
}
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 04/13] bridge: Add filling forward path from port to port
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
` (2 preceding siblings ...)
2025-01-07 9:05 ` [PATCH v4 net-next 03/13] netfilter: nft_chain_filter: Add bridge " Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 05/13] net: core: dev: Add dev_fill_bridge_path() Eric Woudstra
` (8 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
If a port is passed as argument instead of the master, then:
At br_fill_forward_path(): find the master and use it to fill the
forward path.
At br_vlan_fill_forward_path_pvid(): lookup vlan group from port
instead.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
net/bridge/br_device.c | 19 ++++++++++++++-----
net/bridge/br_private.h | 2 ++
net/bridge/br_vlan.c | 6 +++++-
3 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 0ab4613aa07a..c7646afc8b96 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -383,16 +383,25 @@ static int br_del_slave(struct net_device *dev, struct net_device *slave_dev)
static int br_fill_forward_path(struct net_device_path_ctx *ctx,
struct net_device_path *path)
{
+ struct net_bridge_port *src, *dst;
struct net_bridge_fdb_entry *f;
- struct net_bridge_port *dst;
struct net_bridge *br;
- if (netif_is_bridge_port(ctx->dev))
- return -1;
+ if (netif_is_bridge_port(ctx->dev)) {
+ struct net_device *br_dev;
+
+ br_dev = netdev_master_upper_dev_get_rcu((struct net_device *)ctx->dev);
+ if (!br_dev)
+ return -1;
- br = netdev_priv(ctx->dev);
+ src = br_port_get_rcu(ctx->dev);
+ br = netdev_priv(br_dev);
+ } else {
+ src = NULL;
+ br = netdev_priv(ctx->dev);
+ }
- br_vlan_fill_forward_path_pvid(br, ctx, path);
+ br_vlan_fill_forward_path_pvid(br, src, ctx, path);
f = br_fdb_find_rcu(br, ctx->daddr, path->bridge.vlan_id);
if (!f)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 29d6ec45cf41..94603c64fb63 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -1584,6 +1584,7 @@ bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
const struct net_bridge_vlan *range_end);
void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
+ struct net_bridge_port *p,
struct net_device_path_ctx *ctx,
struct net_device_path *path);
int br_vlan_fill_forward_path_mode(struct net_bridge *br,
@@ -1753,6 +1754,7 @@ static inline int nbp_get_num_vlan_infos(struct net_bridge_port *p,
}
static inline void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
+ struct net_bridge_port *p,
struct net_device_path_ctx *ctx,
struct net_device_path *path)
{
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index d9a69ec9affe..07dae3655c26 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -1441,6 +1441,7 @@ int br_vlan_get_pvid_rcu(const struct net_device *dev, u16 *p_pvid)
EXPORT_SYMBOL_GPL(br_vlan_get_pvid_rcu);
void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
+ struct net_bridge_port *p,
struct net_device_path_ctx *ctx,
struct net_device_path *path)
{
@@ -1453,7 +1454,10 @@ void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
if (!br_opt_get(br, BROPT_VLAN_ENABLED))
return;
- vg = br_vlan_group(br);
+ if (p)
+ vg = nbp_vlan_group(p);
+ else
+ vg = br_vlan_group(br);
if (idx >= 0 &&
ctx->vlan[idx].proto == br->vlan_proto) {
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 05/13] net: core: dev: Add dev_fill_bridge_path()
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
` (3 preceding siblings ...)
2025-01-07 9:05 ` [PATCH v4 net-next 04/13] bridge: Add filling forward path from port to port Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 06/13] netfilter :nf_flow_table_offload: Add nf_flow_rule_bridge() Eric Woudstra
` (7 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
New function dev_fill_bridge_path(), similar to dev_fill_forward_path().
It handles starting from a bridge port instead of the bridge master.
The structures ctx and nft_forward_info need to be already filled in with
the (vlan) encaps.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
include/linux/netdevice.h | 2 ++
net/core/dev.c | 66 +++++++++++++++++++++++++++++++--------
2 files changed, 55 insertions(+), 13 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 2593019ad5b1..7d66a73b880c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3187,6 +3187,8 @@ void dev_remove_offload(struct packet_offload *po);
int dev_get_iflink(const struct net_device *dev);
int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
+int dev_fill_bridge_path(struct net_device_path_ctx *ctx,
+ struct net_device_path_stack *stack);
int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
struct net_device_path_stack *stack);
struct net_device *__dev_get_by_flags(struct net *net, unsigned short flags,
diff --git a/net/core/dev.c b/net/core/dev.c
index e7223972b9aa..f41b159ee9c5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -713,44 +713,84 @@ static struct net_device_path *dev_fwd_path(struct net_device_path_stack *stack)
return &stack->path[k];
}
-int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
- struct net_device_path_stack *stack)
+static int dev_fill_forward_path_common(struct net_device_path_ctx *ctx,
+ struct net_device_path_stack *stack)
{
const struct net_device *last_dev;
- struct net_device_path_ctx ctx = {
- .dev = dev,
- };
struct net_device_path *path;
int ret = 0;
- memcpy(ctx.daddr, daddr, sizeof(ctx.daddr));
- stack->num_paths = 0;
- while (ctx.dev && ctx.dev->netdev_ops->ndo_fill_forward_path) {
- last_dev = ctx.dev;
+ while (ctx->dev && ctx->dev->netdev_ops->ndo_fill_forward_path) {
+ last_dev = ctx->dev;
path = dev_fwd_path(stack);
if (!path)
return -1;
memset(path, 0, sizeof(struct net_device_path));
- ret = ctx.dev->netdev_ops->ndo_fill_forward_path(&ctx, path);
+ ret = ctx->dev->netdev_ops->ndo_fill_forward_path(ctx, path);
if (ret < 0)
return -1;
- if (WARN_ON_ONCE(last_dev == ctx.dev))
+ if (WARN_ON_ONCE(last_dev == ctx->dev))
return -1;
}
- if (!ctx.dev)
+ if (!ctx->dev)
return ret;
path = dev_fwd_path(stack);
if (!path)
return -1;
path->type = DEV_PATH_ETHERNET;
- path->dev = ctx.dev;
+ path->dev = ctx->dev;
return ret;
}
+
+int dev_fill_bridge_path(struct net_device_path_ctx *ctx,
+ struct net_device_path_stack *stack)
+{
+ const struct net_device *last_dev, *br_dev;
+ struct net_device_path *path;
+
+ stack->num_paths = 0;
+
+ if (!ctx->dev || !netif_is_bridge_port(ctx->dev))
+ return -1;
+
+ br_dev = netdev_master_upper_dev_get_rcu((struct net_device *)ctx->dev);
+ if (!br_dev || !br_dev->netdev_ops->ndo_fill_forward_path)
+ return -1;
+
+ last_dev = ctx->dev;
+ path = dev_fwd_path(stack);
+ if (!path)
+ return -1;
+
+ memset(path, 0, sizeof(struct net_device_path));
+ if (br_dev->netdev_ops->ndo_fill_forward_path(ctx, path) < 0)
+ return -1;
+
+ if (!ctx->dev || WARN_ON_ONCE(last_dev == ctx->dev))
+ return -1;
+
+ return dev_fill_forward_path_common(ctx, stack);
+}
+EXPORT_SYMBOL_GPL(dev_fill_bridge_path);
+
+int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
+ struct net_device_path_stack *stack)
+{
+ struct net_device_path_ctx ctx = {
+ .dev = dev,
+ };
+
+ memcpy(ctx.daddr, daddr, sizeof(ctx.daddr));
+
+ stack->num_paths = 0;
+
+ return dev_fill_forward_path_common(&ctx, stack);
+}
EXPORT_SYMBOL_GPL(dev_fill_forward_path);
/**
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 06/13] netfilter :nf_flow_table_offload: Add nf_flow_rule_bridge()
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
` (4 preceding siblings ...)
2025-01-07 9:05 ` [PATCH v4 net-next 05/13] net: core: dev: Add dev_fill_bridge_path() Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 07/13] netfilter: nf_flow_table_inet: Add nf_flowtable_type flowtable_bridge Eric Woudstra
` (6 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
Add nf_flow_rule_bridge().
It only calls the common rule and adds the redirect.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
include/net/netfilter/nf_flow_table.h | 3 +++
net/netfilter/nf_flow_table_offload.c | 13 +++++++++++++
2 files changed, 16 insertions(+)
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index b63d53bb9dd6..568019a3898a 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -341,6 +341,9 @@ void nf_flow_table_offload_flush_cleanup(struct nf_flowtable *flowtable);
int nf_flow_table_offload_setup(struct nf_flowtable *flowtable,
struct net_device *dev,
enum flow_block_command cmd);
+int nf_flow_rule_bridge(struct net *net, struct flow_offload *flow,
+ enum flow_offload_tuple_dir dir,
+ struct nf_flow_rule *flow_rule);
int nf_flow_rule_route_ipv4(struct net *net, struct flow_offload *flow,
enum flow_offload_tuple_dir dir,
struct nf_flow_rule *flow_rule);
diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
index e06bc36f49fe..5543ce03a196 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -679,6 +679,19 @@ nf_flow_rule_route_common(struct net *net, const struct flow_offload *flow,
return 0;
}
+int nf_flow_rule_bridge(struct net *net, struct flow_offload *flow,
+ enum flow_offload_tuple_dir dir,
+ struct nf_flow_rule *flow_rule)
+{
+ if (nf_flow_rule_route_common(net, flow, dir, flow_rule) < 0)
+ return -1;
+
+ flow_offload_redirect(net, flow, dir, flow_rule);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nf_flow_rule_bridge);
+
int nf_flow_rule_route_ipv4(struct net *net, struct flow_offload *flow,
enum flow_offload_tuple_dir dir,
struct nf_flow_rule *flow_rule)
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 07/13] netfilter: nf_flow_table_inet: Add nf_flowtable_type flowtable_bridge
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
` (5 preceding siblings ...)
2025-01-07 9:05 ` [PATCH v4 net-next 06/13] netfilter :nf_flow_table_offload: Add nf_flow_rule_bridge() Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 08/13] netfilter: nft_flow_offload: Add NFPROTO_BRIDGE to validate Eric Woudstra
` (5 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
This will allow a flowtable to be added to the nft bridge family.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
net/netfilter/nf_flow_table_inet.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/net/netfilter/nf_flow_table_inet.c b/net/netfilter/nf_flow_table_inet.c
index b0f199171932..80b238196f29 100644
--- a/net/netfilter/nf_flow_table_inet.c
+++ b/net/netfilter/nf_flow_table_inet.c
@@ -65,6 +65,16 @@ static int nf_flow_rule_route_inet(struct net *net,
return err;
}
+static struct nf_flowtable_type flowtable_bridge = {
+ .family = NFPROTO_BRIDGE,
+ .init = nf_flow_table_init,
+ .setup = nf_flow_table_offload_setup,
+ .action = nf_flow_rule_bridge,
+ .free = nf_flow_table_free,
+ .hook = nf_flow_offload_inet_hook,
+ .owner = THIS_MODULE,
+};
+
static struct nf_flowtable_type flowtable_inet = {
.family = NFPROTO_INET,
.init = nf_flow_table_init,
@@ -97,6 +107,7 @@ static struct nf_flowtable_type flowtable_ipv6 = {
static int __init nf_flow_inet_module_init(void)
{
+ nft_register_flowtable_type(&flowtable_bridge);
nft_register_flowtable_type(&flowtable_ipv4);
nft_register_flowtable_type(&flowtable_ipv6);
nft_register_flowtable_type(&flowtable_inet);
@@ -109,6 +120,7 @@ static void __exit nf_flow_inet_module_exit(void)
nft_unregister_flowtable_type(&flowtable_inet);
nft_unregister_flowtable_type(&flowtable_ipv6);
nft_unregister_flowtable_type(&flowtable_ipv4);
+ nft_unregister_flowtable_type(&flowtable_bridge);
}
module_init(nf_flow_inet_module_init);
@@ -118,5 +130,6 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
MODULE_ALIAS_NF_FLOWTABLE(AF_INET);
MODULE_ALIAS_NF_FLOWTABLE(AF_INET6);
+MODULE_ALIAS_NF_FLOWTABLE(AF_BRIDGE);
MODULE_ALIAS_NF_FLOWTABLE(1); /* NFPROTO_INET */
MODULE_DESCRIPTION("Netfilter flow table mixed IPv4/IPv6 module");
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 08/13] netfilter: nft_flow_offload: Add NFPROTO_BRIDGE to validate
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
` (6 preceding siblings ...)
2025-01-07 9:05 ` [PATCH v4 net-next 07/13] netfilter: nf_flow_table_inet: Add nf_flowtable_type flowtable_bridge Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 09/13] netfilter: nft_flow_offload: Add DEV_PATH_MTK_WDMA to nft_dev_path_info() Eric Woudstra
` (4 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
Need to add NFPROTO_BRIDGE to nft_flow_offload_validate() to support
the bridge-fastpath.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
net/netfilter/nft_flow_offload.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index cdf1771906b8..cce4c5980ed5 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -421,7 +421,8 @@ static int nft_flow_offload_validate(const struct nft_ctx *ctx,
if (ctx->family != NFPROTO_IPV4 &&
ctx->family != NFPROTO_IPV6 &&
- ctx->family != NFPROTO_INET)
+ ctx->family != NFPROTO_INET &&
+ ctx->family != NFPROTO_BRIDGE)
return -EOPNOTSUPP;
return nft_chain_validate_hooks(ctx->chain, hook_mask);
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 09/13] netfilter: nft_flow_offload: Add DEV_PATH_MTK_WDMA to nft_dev_path_info()
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
` (7 preceding siblings ...)
2025-01-07 9:05 ` [PATCH v4 net-next 08/13] netfilter: nft_flow_offload: Add NFPROTO_BRIDGE to validate Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 10/13] netfilter: nft_flow_offload: No ingress_vlan forward info for dsa user port Eric Woudstra
` (3 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
In case of using mediatek wireless, in nft_dev_fill_forward_path(), the
forward path is filled, ending with mediatek wlan1.
Because DEV_PATH_MTK_WDMA is unknown inside nft_dev_path_info() it returns
with info.indev = NULL. Then nft_dev_forward_path() returns without
setting the direct transmit parameters.
This results in a neighbor transmit, and direct transmit not possible.
But we want to use it for flow between bridged interfaces.
So this patch adds DEV_PATH_MTK_WDMA to nft_dev_path_info() and makes
direct transmission possible.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
net/netfilter/nft_flow_offload.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index cce4c5980ed5..f7c2692ff3f2 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -106,6 +106,7 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
switch (path->type) {
case DEV_PATH_ETHERNET:
case DEV_PATH_DSA:
+ case DEV_PATH_MTK_WDMA:
case DEV_PATH_VLAN:
case DEV_PATH_PPPOE:
info->indev = path->dev;
@@ -118,6 +119,10 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
i = stack->num_paths;
break;
}
+ if (path->type == DEV_PATH_MTK_WDMA) {
+ i = stack->num_paths;
+ break;
+ }
/* DEV_PATH_VLAN and DEV_PATH_PPPOE */
if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) {
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 10/13] netfilter: nft_flow_offload: No ingress_vlan forward info for dsa user port
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
` (8 preceding siblings ...)
2025-01-07 9:05 ` [PATCH v4 net-next 09/13] netfilter: nft_flow_offload: Add DEV_PATH_MTK_WDMA to nft_dev_path_info() Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 11/13] bridge: No DEV_PATH_BR_VLAN_UNTAG_HW for dsa foreign Eric Woudstra
` (2 subsequent siblings)
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
The bitfield info->ingress_vlans and correcponding vlan encap are used for
a switchdev user port. However, they should not be set for a dsa user port.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
net/netfilter/nft_flow_offload.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index f7c2692ff3f2..387e5574c31f 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -117,6 +117,11 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
break;
if (path->type == DEV_PATH_DSA) {
i = stack->num_paths;
+ if (!info->num_encaps ||
+ !(info->ingress_vlans & BIT(info->num_encaps - 1)))
+ break;
+ info->num_encaps--;
+ info->ingress_vlans &= ~BIT(info->num_encaps - 1);
break;
}
if (path->type == DEV_PATH_MTK_WDMA) {
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 11/13] bridge: No DEV_PATH_BR_VLAN_UNTAG_HW for dsa foreign
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
` (9 preceding siblings ...)
2025-01-07 9:05 ` [PATCH v4 net-next 10/13] netfilter: nft_flow_offload: No ingress_vlan forward info for dsa user port Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 12/13] bridge: Introduce DEV_PATH_BR_VLAN_KEEP_HW for bridge-fastpath Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 13/13] netfilter: nft_flow_offload: Add bridgeflow to nft_flow_offload_eval() Eric Woudstra
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
In network setup as below:
fastpath bypass
.----------------------------------------.
/ \
| IP - forwarding |
| / \ v
| / wan ...
| /
| |
| |
| brlan.1
| |
| +-------------------------------+
| | vlan 1 |
| | |
| | brlan (vlan-filtering) |
| | +---------------+
| | | DSA-SWITCH |
| | vlan 1 | |
| | to | |
| | untagged 1 vlan 1 |
| +---------------+---------------+
. / \
----->wlan1 lan0
. .
. ^
^ vlan 1 tagged packets
untagged packets
br_vlan_fill_forward_path_mode() sets DEV_PATH_BR_VLAN_UNTAG_HW when
filling in from brlan.1 towards wlan1. But it should be set to
DEV_PATH_BR_VLAN_UNTAG in this case. Using BR_VLFLAG_ADDED_BY_SWITCHDEV
is not correct. The dsa switchdev adds it as a foreign port.
The same problem for all foreignly added dsa vlans on the bridge.
First add the vlan, trying only native devices.
If this fails, we know this may be a vlan from a foreign device.
Use BR_VLFLAG_TAGGING_BY_SWITCHDEV to make sure DEV_PATH_BR_VLAN_UNTAG_HW
is set only when there if no foreign device involved.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
include/net/switchdev.h | 1 +
net/bridge/br_private.h | 10 ++++++++++
net/bridge/br_switchdev.c | 15 +++++++++++++++
net/bridge/br_vlan.c | 7 ++++++-
net/switchdev/switchdev.c | 2 +-
5 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index 8346b0d29542..ee500706496b 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -15,6 +15,7 @@
#define SWITCHDEV_F_NO_RECURSE BIT(0)
#define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1)
#define SWITCHDEV_F_DEFER BIT(2)
+#define SWITCHDEV_F_NO_FOREIGN BIT(3)
enum switchdev_attr_id {
SWITCHDEV_ATTR_ID_UNDEFINED,
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 94603c64fb63..f60a7bb7af26 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -180,6 +180,7 @@ enum {
BR_VLFLAG_MCAST_ENABLED = BIT(2),
BR_VLFLAG_GLOBAL_MCAST_ENABLED = BIT(3),
BR_VLFLAG_NEIGH_SUPPRESS_ENABLED = BIT(4),
+ BR_VLFLAG_TAGGING_BY_SWITCHDEV = BIT(5),
};
/**
@@ -2184,6 +2185,8 @@ void br_switchdev_mdb_notify(struct net_device *dev,
int type);
int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
bool changed, struct netlink_ext_ack *extack);
+int br_switchdev_port_vlan_no_foreign_add(struct net_device *dev, u16 vid, u16 flags,
+ bool changed, struct netlink_ext_ack *extack);
int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid);
void br_switchdev_init(struct net_bridge *br);
@@ -2267,6 +2270,13 @@ static inline int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid,
return -EOPNOTSUPP;
}
+static inline int br_switchdev_port_vlan_no_foreign_add(struct net_device *dev, u16 vid,
+ u16 flags, bool changed,
+ struct netlink_ext_ack *extack)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid)
{
return -EOPNOTSUPP;
diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c
index 7b41ee8740cb..efa7a055b8f9 100644
--- a/net/bridge/br_switchdev.c
+++ b/net/bridge/br_switchdev.c
@@ -187,6 +187,21 @@ int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
return switchdev_port_obj_add(dev, &v.obj, extack);
}
+int br_switchdev_port_vlan_no_foreign_add(struct net_device *dev, u16 vid, u16 flags,
+ bool changed, struct netlink_ext_ack *extack)
+{
+ struct switchdev_obj_port_vlan v = {
+ .obj.orig_dev = dev,
+ .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
+ .obj.flags = SWITCHDEV_F_NO_FOREIGN,
+ .flags = flags,
+ .vid = vid,
+ .changed = changed,
+ };
+
+ return switchdev_port_obj_add(dev, &v.obj, extack);
+}
+
int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid)
{
struct switchdev_obj_port_vlan v = {
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 07dae3655c26..3e50adaf8e1b 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -109,6 +109,11 @@ static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br,
/* Try switchdev op first. In case it is not supported, fallback to
* 8021q add.
*/
+ err = br_switchdev_port_vlan_no_foreign_add(dev, v->vid, flags, false, extack);
+ if (err != -EOPNOTSUPP) {
+ v->priv_flags |= BR_VLFLAG_ADDED_BY_SWITCHDEV | BR_VLFLAG_TAGGING_BY_SWITCHDEV;
+ return err;
+ }
err = br_switchdev_port_vlan_add(dev, v->vid, flags, false, extack);
if (err == -EOPNOTSUPP)
return vlan_vid_add(dev, br->vlan_proto, v->vid);
@@ -1491,7 +1496,7 @@ 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)
+ else if (v->priv_flags & BR_VLFLAG_TAGGING_BY_SWITCHDEV)
path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW;
else
path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 6488ead9e464..c48f66643e99 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -749,7 +749,7 @@ static int __switchdev_handle_port_obj_add(struct net_device *dev,
/* Event is neither on a bridge nor a LAG. Check whether it is on an
* interface that is in a bridge with us.
*/
- if (!foreign_dev_check_cb)
+ if (!foreign_dev_check_cb || port_obj_info->obj->flags & SWITCHDEV_F_NO_FOREIGN)
return err;
br = netdev_master_upper_dev_get(dev);
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 12/13] bridge: Introduce DEV_PATH_BR_VLAN_KEEP_HW for bridge-fastpath
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
` (10 preceding siblings ...)
2025-01-07 9:05 ` [PATCH v4 net-next 11/13] bridge: No DEV_PATH_BR_VLAN_UNTAG_HW for dsa foreign Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
2025-01-07 9:05 ` [PATCH v4 net-next 13/13] netfilter: nft_flow_offload: Add bridgeflow to nft_flow_offload_eval() Eric Woudstra
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
This patch introduces DEV_PATH_BR_VLAN_KEEP_HW. It is needed in the
bridge fastpath for switchdevs supporting SWITCHDEV_OBJ_ID_PORT_VLAN.
It is similar to DEV_PATH_BR_VLAN_TAG, with the correcponding bit in
ingress_vlans set.
In the forward fastpath it is not needed.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
include/linux/netdevice.h | 1 +
net/bridge/br_device.c | 4 ++++
net/bridge/br_vlan.c | 18 +++++++++++-------
net/netfilter/nft_flow_offload.c | 3 +++
4 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 7d66a73b880c..cf754ebb19df 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -871,6 +871,7 @@ struct net_device_path {
DEV_PATH_BR_VLAN_TAG,
DEV_PATH_BR_VLAN_UNTAG,
DEV_PATH_BR_VLAN_UNTAG_HW,
+ DEV_PATH_BR_VLAN_KEEP_HW,
} vlan_mode;
u16 vlan_id;
__be16 vlan_proto;
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index c7646afc8b96..112fd8556217 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -430,6 +430,10 @@ static int br_fill_forward_path(struct net_device_path_ctx *ctx,
case DEV_PATH_BR_VLAN_UNTAG:
ctx->num_vlans--;
break;
+ case DEV_PATH_BR_VLAN_KEEP_HW:
+ if (!src)
+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
+ break;
case DEV_PATH_BR_VLAN_KEEP:
break;
}
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 3e50adaf8e1b..8ac1a7a22b2e 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -1494,13 +1494,17 @@ int br_vlan_fill_forward_path_mode(struct net_bridge *br,
if (!(v->flags & BRIDGE_VLAN_INFO_UNTAGGED))
return 0;
- 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_TAGGING_BY_SWITCHDEV)
- path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW;
- else
- path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
-
+ if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG) {
+ if (v->priv_flags & BR_VLFLAG_TAGGING_BY_SWITCHDEV)
+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP_HW;
+ else
+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP;
+ } else {
+ if (v->priv_flags & BR_VLFLAG_TAGGING_BY_SWITCHDEV)
+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW;
+ else
+ path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
+ }
return 0;
}
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index 387e5574c31f..ed0e9b499971 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -149,6 +149,9 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
case DEV_PATH_BR_VLAN_UNTAG_HW:
info->ingress_vlans |= BIT(info->num_encaps - 1);
break;
+ case DEV_PATH_BR_VLAN_KEEP_HW:
+ info->ingress_vlans |= BIT(info->num_encaps);
+ fallthrough;
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;
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v4 net-next 13/13] netfilter: nft_flow_offload: Add bridgeflow to nft_flow_offload_eval()
2025-01-07 9:05 [PATCH v4 net-next 00/13] bridge-fastpath and related improvements Eric Woudstra
` (11 preceding siblings ...)
2025-01-07 9:05 ` [PATCH v4 net-next 12/13] bridge: Introduce DEV_PATH_BR_VLAN_KEEP_HW for bridge-fastpath Eric Woudstra
@ 2025-01-07 9:05 ` Eric Woudstra
12 siblings, 0 replies; 15+ messages in thread
From: Eric Woudstra @ 2025-01-07 9:05 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn, Pablo Neira Ayuso, Jozsef Kadlecsik,
Jiri Pirko, Ivan Vecera, Roopa Prabhu, Nikolay Aleksandrov,
Matthias Brugger, AngeloGioacchino Del Regno, David Ahern,
Sebastian Andrzej Siewior, Lorenzo Bianconi, Joe Damato,
Alexander Lobakin, Vladimir Oltean, Frank Wunderlich,
Daniel Golle
Cc: netdev, linux-kernel, netfilter-devel, coreteam, bridge,
linux-arm-kernel, linux-mediatek, Eric Woudstra
Edit nft_flow_offload_eval() to make it possible to handle a flowtable of
the nft bridge family.
Use nft_flow_offload_bridge_init() to fill the flow tuples. It uses
nft_dev_fill_bridge_path() in each direction.
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
---
net/netfilter/nft_flow_offload.c | 144 +++++++++++++++++++++++++++++--
1 file changed, 139 insertions(+), 5 deletions(-)
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index ed0e9b499971..b17a3ef79852 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -196,6 +196,131 @@ static bool nft_flowtable_find_dev(const struct net_device *dev,
return found;
}
+static int nft_dev_fill_bridge_path(struct flow_offload *flow,
+ struct nft_flowtable *ft,
+ const struct nft_pktinfo *pkt,
+ enum ip_conntrack_dir dir,
+ const struct net_device *src_dev,
+ const struct net_device *dst_dev,
+ unsigned char *src_ha,
+ unsigned char *dst_ha)
+{
+ struct flow_offload_tuple_rhash *th = flow->tuplehash;
+ struct net_device_path_stack stack;
+ struct net_device_path_ctx ctx = {};
+ struct nft_forward_info info = {};
+ int i, j = 0;
+
+ for (i = th[dir].tuple.encap_num - 1; i >= 0 ; i--) {
+ if (info.num_encaps >= NF_FLOW_TABLE_ENCAP_MAX)
+ return -1;
+
+ if (th[dir].tuple.in_vlan_ingress & BIT(i))
+ continue;
+
+ info.encap[info.num_encaps].id = th[dir].tuple.encap[i].id;
+ info.encap[info.num_encaps].proto = th[dir].tuple.encap[i].proto;
+ info.num_encaps++;
+
+ if (th[dir].tuple.encap[i].proto == htons(ETH_P_PPP_SES))
+ continue;
+
+ if (ctx.num_vlans >= NET_DEVICE_PATH_VLAN_MAX)
+ return -1;
+ ctx.vlan[ctx.num_vlans].id = th[dir].tuple.encap[i].id;
+ ctx.vlan[ctx.num_vlans].proto = th[dir].tuple.encap[i].proto;
+ ctx.num_vlans++;
+ }
+ ctx.dev = src_dev;
+ ether_addr_copy(ctx.daddr, dst_ha);
+
+ if (dev_fill_bridge_path(&ctx, &stack) < 0)
+ return -1;
+
+ nft_dev_path_info(&stack, &info, dst_ha, &ft->data);
+
+ if (!info.indev || info.indev != dst_dev)
+ return -1;
+
+ th[!dir].tuple.iifidx = info.indev->ifindex;
+ for (i = info.num_encaps - 1; i >= 0; i--) {
+ th[!dir].tuple.encap[j].id = info.encap[i].id;
+ th[!dir].tuple.encap[j].proto = info.encap[i].proto;
+ if (info.ingress_vlans & BIT(i))
+ th[!dir].tuple.in_vlan_ingress |= BIT(j);
+ j++;
+ }
+ th[!dir].tuple.encap_num = info.num_encaps;
+
+ th[dir].tuple.mtu = dst_dev->mtu;
+ ether_addr_copy(th[dir].tuple.out.h_source, src_ha);
+ ether_addr_copy(th[dir].tuple.out.h_dest, dst_ha);
+ th[dir].tuple.out.ifidx = info.outdev->ifindex;
+ th[dir].tuple.out.hw_ifidx = info.hw_outdev->ifindex;
+ th[dir].tuple.xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
+
+ return 0;
+}
+
+static int nft_flow_offload_bridge_init(struct flow_offload *flow,
+ const struct nft_pktinfo *pkt,
+ enum ip_conntrack_dir dir,
+ struct nft_flowtable *ft)
+{
+ struct ethhdr *eth = eth_hdr(pkt->skb);
+ struct flow_offload_tuple *tuple;
+ const struct net_device *out_dev;
+ const struct net_device *in_dev;
+ struct pppoe_hdr *phdr;
+ struct vlan_hdr *vhdr;
+ int err, i = 0;
+
+ in_dev = nft_in(pkt);
+ if (!in_dev || !nft_flowtable_find_dev(in_dev, ft))
+ return -1;
+
+ out_dev = nft_out(pkt);
+ if (!out_dev || !nft_flowtable_find_dev(out_dev, ft))
+ return -1;
+
+ tuple = &flow->tuplehash[!dir].tuple;
+
+ if (skb_vlan_tag_present(pkt->skb)) {
+ tuple->encap[i].id = skb_vlan_tag_get(pkt->skb);
+ tuple->encap[i].proto = pkt->skb->vlan_proto;
+ i++;
+ }
+ switch (pkt->skb->protocol) {
+ case htons(ETH_P_8021Q):
+ vhdr = (struct vlan_hdr *)skb_network_header(pkt->skb);
+ tuple->encap[i].id = ntohs(vhdr->h_vlan_TCI);
+ tuple->encap[i].proto = pkt->skb->protocol;
+ i++;
+ break;
+ case htons(ETH_P_PPP_SES):
+ phdr = (struct pppoe_hdr *)skb_network_header(pkt->skb);
+ tuple->encap[i].id = ntohs(phdr->sid);
+ tuple->encap[i].proto = pkt->skb->protocol;
+ i++;
+ break;
+ }
+ tuple->encap_num = i;
+
+ err = nft_dev_fill_bridge_path(flow, ft, pkt, !dir, out_dev, in_dev,
+ eth->h_dest, eth->h_source);
+ if (err < 0)
+ return err;
+
+ memset(tuple->encap, 0, sizeof(tuple->encap));
+
+ err = nft_dev_fill_bridge_path(flow, ft, pkt, dir, in_dev, out_dev,
+ eth->h_source, eth->h_dest);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
static void nft_dev_forward_path(struct nf_flow_route *route,
const struct nf_conn *ct,
enum ip_conntrack_dir dir,
@@ -306,6 +431,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
{
struct nft_flow_offload *priv = nft_expr_priv(expr);
struct nf_flowtable *flowtable = &priv->flowtable->data;
+ bool routing = (flowtable->type->family != NFPROTO_BRIDGE);
struct tcphdr _tcph, *tcph = NULL;
struct nf_flow_route route = {};
enum ip_conntrack_info ctinfo;
@@ -359,14 +485,20 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
goto out;
dir = CTINFO2DIR(ctinfo);
- if (nft_flow_route(pkt, ct, &route, dir, priv->flowtable) < 0)
- goto err_flow_route;
+ if (routing) {
+ if (nft_flow_route(pkt, ct, &route, dir, priv->flowtable) < 0)
+ goto err_flow_route;
+ }
flow = flow_offload_alloc(ct);
if (!flow)
goto err_flow_alloc;
- flow_offload_route_init(flow, &route);
+ if (routing)
+ flow_offload_route_init(flow, &route);
+ else
+ if (nft_flow_offload_bridge_init(flow, pkt, dir, priv->flowtable) < 0)
+ goto err_flow_route;
if (tcph) {
ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
@@ -419,8 +551,10 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
err_flow_add:
flow_offload_free(flow);
err_flow_alloc:
- dst_release(route.tuple[dir].dst);
- dst_release(route.tuple[!dir].dst);
+ if (routing) {
+ dst_release(route.tuple[dir].dst);
+ dst_release(route.tuple[!dir].dst);
+ }
err_flow_route:
clear_bit(IPS_OFFLOAD_BIT, &ct->status);
out:
--
2.47.1
^ permalink raw reply related [flat|nested] 15+ messages in thread