]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
airoha: Add the capability to offload dscp field via netfilter flowtable 23423/head
authorLorenzo Bianconi <lorenzo@kernel.org>
Mon, 18 May 2026 10:25:41 +0000 (12:25 +0200)
committerChristian Marangi <ansuelsmth@gmail.com>
Mon, 18 May 2026 13:51:29 +0000 (15:51 +0200)
Introduce the capability to hw offload via netfilter flowtable APIs the
IP TOS info. Implement the sw offloading for DSCP field via the
netfilter flowtable APIs.

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://github.com/openwrt/openwrt/pull/23423
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
target/linux/airoha/patches-6.12/915-01-net-netfilter-flowtable-Add-the-capability-to-offloa.patch [new file with mode: 0644]
target/linux/airoha/patches-6.12/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch [new file with mode: 0644]

diff --git a/target/linux/airoha/patches-6.12/915-01-net-netfilter-flowtable-Add-the-capability-to-offloa.patch b/target/linux/airoha/patches-6.12/915-01-net-netfilter-flowtable-Add-the-capability-to-offloa.patch
new file mode 100644 (file)
index 0000000..e11d368
--- /dev/null
@@ -0,0 +1,150 @@
+From 6408cdca652b1f85e5b8582c283203d11f4dedcb Mon Sep 17 00:00:00 2001
+Message-ID: <6408cdca652b1f85e5b8582c283203d11f4dedcb.1779086987.git.lorenzo@kernel.org>
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sun, 17 May 2026 21:11:27 +0200
+Subject: [PATCH net-next 1/2] net: netfilter: flowtable: Add the capability to
+ offload dscp field
+
+Introduce the capability to hw offload via netfilter flowtable APIs the
+IP TOS info. Implement the sw offloading for DSCP field via the
+netfilter flowtable APIs.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ include/net/netfilter/nf_flow_table.h |  2 ++
+ net/netfilter/nf_flow_table_ip.c      | 12 ++++++++++++
+ net/netfilter/nf_flow_table_offload.c |  5 +++++
+ net/netfilter/nft_flow_offload.c      | 22 ++++++++++++++++++++++
+ 4 files changed, 41 insertions(+)
+
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -29,6 +29,7 @@ struct nf_flow_key {
+               struct flow_dissector_key_ipv4_addrs    ipv4;
+               struct flow_dissector_key_ipv6_addrs    ipv6;
+       };
++      struct flow_dissector_key_ip                    ip;
+       struct flow_dissector_key_keyid                 enc_key_id;
+       union {
+               struct flow_dissector_key_ipv4_addrs    enc_ipv4;
+@@ -138,6 +139,7 @@ struct flow_offload_tuple {
+                                       encap_num:2,
+                                       in_vlan_ingress:2;
+       u16                             mtu;
++      u8                              dscp;
+       union {
+               struct {
+                       struct dst_entry *dst_cache;
+--- a/net/netfilter/nf_flow_table_ip.c
++++ b/net/netfilter/nf_flow_table_ip.c
+@@ -372,6 +372,7 @@ static int nf_flow_offload_forward(struc
+       struct flow_offload *flow;
+       unsigned int thoff, mtu;
+       struct iphdr *iph;
++      u8 dscp;
+       dir = tuplehash->tuple.dir;
+       flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
+@@ -401,6 +402,12 @@ static int nf_flow_offload_forward(struc
+       iph = ip_hdr(skb);
+       nf_flow_nat_ip(flow, skb, thoff, dir, iph);
++      dscp = FIELD_GET(INET_DSCP_MASK, ipv4_get_dsfield(iph));
++      if (tuplehash->tuple.dscp != dscp)
++              ipv4_change_dsfield(iph, INET_ECN_MASK,
++                                  FIELD_PREP(INET_DSCP_MASK,
++                                             tuplehash->tuple.dscp));
++
+       ip_decrease_ttl(iph);
+       skb_clear_tstamp(skb);
+@@ -651,6 +658,7 @@ static int nf_flow_offload_ipv6_forward(
+       struct flow_offload *flow;
+       unsigned int thoff, mtu;
+       struct ipv6hdr *ip6h;
++      u8 dscp;
+       dir = tuplehash->tuple.dir;
+       flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
+@@ -679,6 +687,12 @@ static int nf_flow_offload_ipv6_forward(
+       ip6h = ipv6_hdr(skb);
+       nf_flow_nat_ipv6(flow, skb, dir, ip6h);
++      dscp = FIELD_GET(INET_DSCP_MASK, ipv6_get_dsfield(ip6h));
++      if (tuplehash->tuple.dscp != dscp)
++              ipv6_change_dsfield(ip6h, INET_ECN_MASK,
++                                  FIELD_PREP(INET_DSCP_MASK,
++                                             tuplehash->tuple.dscp));
++
+       ip6h->hop_limit--;
+       skb_clear_tstamp(skb);
+--- a/net/netfilter/nf_flow_table_offload.c
++++ b/net/netfilter/nf_flow_table_offload.c
+@@ -103,6 +103,7 @@ static int nf_flow_rule_match(struct nf_
+       NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_BASIC, basic);
+       NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
+       NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
++      NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IP, ip);
+       NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_TCP, tcp);
+       NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_PORTS, tp);
+@@ -168,6 +169,10 @@ static int nf_flow_rule_match(struct nf_
+       match->dissector.used_keys |= BIT_ULL(key->control.addr_type);
+       mask->basic.n_proto = 0xffff;
++      key->ip.tos = FIELD_PREP(INET_DSCP_MASK, tuple->dscp);
++      mask->ip.tos = 0xff;
++      match->dissector.used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IP);
++
+       switch (tuple->l4proto) {
+       case IPPROTO_TCP:
+               key->tcp.flags = 0;
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -8,6 +8,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/netfilter/nf_conntrack_common.h>
+ #include <linux/netfilter/nf_tables.h>
++#include <net/dsfield.h>
+ #include <net/ip.h> /* for ipv4 options. */
+ #include <net/inet_dscp.h>
+ #include <net/netfilter/nf_tables.h>
+@@ -279,6 +280,27 @@ static int nft_flow_route(const struct n
+       return 0;
+ }
++static void nft_flow_set_dscp(const struct nft_pktinfo *pkt,
++                            struct flow_offload *flow,
++                            enum ip_conntrack_dir dir)
++{
++      struct flow_offload_tuple *tuple = &flow->tuplehash[dir].tuple;
++      struct sk_buff *skb = pkt->skb;
++
++      switch (skb->protocol) {
++      case htons(ETH_P_IP):
++              tuple->dscp = FIELD_GET(INET_DSCP_MASK,
++                                      ipv4_get_dsfield(ip_hdr(skb)));
++              break;
++      case htons(ETH_P_IPV6):
++              tuple->dscp = FIELD_GET(INET_DSCP_MASK,
++                                      ipv6_get_dsfield(ipv6_hdr(skb)));
++              break;
++      default:
++              break;
++      }
++}
++
+ static bool nft_flow_offload_skip(struct sk_buff *skb, int family)
+ {
+       if (skb_sec_path(skb))
+@@ -371,6 +393,9 @@ static void nft_flow_offload_eval(const
+       if (!flow)
+               goto err_flow_alloc;
++      nft_flow_set_dscp(pkt, flow, dir);
++      nft_flow_set_dscp(pkt, flow, !dir);
++
+       flow_offload_route_init(flow, &route);
+       if (tcph)
+               flow_offload_ct_tcp(ct);
diff --git a/target/linux/airoha/patches-6.12/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch b/target/linux/airoha/patches-6.12/915-02-net-airoha-Set-hw-QoS-parameter-according-to-the-pac.patch
new file mode 100644 (file)
index 0000000..15eded8
--- /dev/null
@@ -0,0 +1,94 @@
+From b9870ade9498f4119d3f8f8368fcd13e1fa0c7c9 Mon Sep 17 00:00:00 2001
+Message-ID: <b9870ade9498f4119d3f8f8368fcd13e1fa0c7c9.1779086987.git.lorenzo@kernel.org>
+In-Reply-To: <6408cdca652b1f85e5b8582c283203d11f4dedcb.1779086987.git.lorenzo@kernel.org>
+References: <6408cdca652b1f85e5b8582c283203d11f4dedcb.1779086987.git.lorenzo@kernel.org>
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Mon, 18 May 2026 08:36:20 +0200
+Subject: [PATCH net-next 2/2] net: airoha: Set hw QoS parameter according to
+ the packet dscp
+
+Introduce the capability to hw offload via netfilter flowtable APIs the
+IP TOS info in order to configure hw queue and dscp field.
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ drivers/net/ethernet/airoha/airoha_ppe.c | 24 ++++++++++++++++++------
+ 1 file changed, 18 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/airoha/airoha_ppe.c
++++ b/drivers/net/ethernet/airoha/airoha_ppe.c
+@@ -11,6 +11,7 @@
+ #include <linux/rhashtable.h>
+ #include <net/ipv6.h>
+ #include <net/pkt_cls.h>
++#include <net/route.h>
+ #include "airoha_regs.h"
+ #include "airoha_eth.h"
+@@ -298,7 +299,7 @@ static int airoha_ppe_foe_entry_prepare(
+                                       struct airoha_foe_entry *hwe,
+                                       struct net_device *dev, int type,
+                                       struct airoha_flow_data *data,
+-                                      int l4proto)
++                                      int l4proto, u8 dsfield)
+ {
+       u32 qdata = FIELD_PREP(AIROHA_FOE_SHAPER_ID, 0x7f), ports_pad, val;
+       int wlan_etype = -EINVAL, dsa_port = airoha_get_dsa_port(&dev);
+@@ -331,7 +332,7 @@ static int airoha_ppe_foe_entry_prepare(
+                                               info.wcid);
+               } else {
+                       struct airoha_gdm_port *port = netdev_priv(dev);
+-                      u8 pse_port, channel;
++                      u8 pse_port, channel, priority;
+                       if (!airoha_is_valid_gdm_port(eth, port))
+                               return -EINVAL;
+@@ -350,9 +351,13 @@ static int airoha_ppe_foe_entry_prepare(
+                        */
+                       channel = dsa_port >= 0 ? dsa_port : port->id;
+                       channel = channel % AIROHA_NUM_QOS_CHANNELS;
+-                      qdata |= FIELD_PREP(AIROHA_FOE_CHANNEL, channel);
++                      priority = rt_tos2priority(dsfield);
++                      priority = priority % AIROHA_NUM_QOS_QUEUES;
++                      qdata |= FIELD_PREP(AIROHA_FOE_CHANNEL, channel) |
++                               FIELD_PREP(AIROHA_FOE_QID, priority);
+                       val |= FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT, pse_port) |
++                             FIELD_PREP(AIROHA_FOE_IB2_DSCP, dsfield) |
+                              AIROHA_FOE_IB2_PSE_QOS;
+                       /* For downlink traffic consume SRAM memory for hw
+                        * forwarding descriptors queue.
+@@ -1044,9 +1049,9 @@ static int airoha_ppe_flow_offload_repla
+       struct net_device *odev = NULL;
+       struct flow_action_entry *act;
+       struct airoha_foe_entry hwe;
++      u8 dsfield = 0, l4proto = 0;
+       int err, i, offload_type;
+       u16 addr_type = 0;
+-      u8 l4proto = 0;
+       if (rhashtable_lookup(&eth->flow_table, &f->cookie,
+                             airoha_flow_table_params))
+@@ -1076,6 +1081,13 @@ static int airoha_ppe_flow_offload_repla
+               return -EOPNOTSUPP;
+       }
++      if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
++              struct flow_match_ip match;
++
++              flow_rule_match_ip(rule, &match);
++              dsfield = match.key->tos;
++      }
++
+       switch (addr_type) {
+       case 0:
+               offload_type = PPE_PKT_TYPE_BRIDGE;
+@@ -1141,7 +1153,7 @@ static int airoha_ppe_flow_offload_repla
+               return -EINVAL;
+       err = airoha_ppe_foe_entry_prepare(eth, &hwe, odev, offload_type,
+-                                         &data, l4proto);
++                                         &data, l4proto, dsfield);
+       if (err)
+               return err;