lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAH-L+nMLUUxg9=NgonGHveNogAiqf3s_-Qb0TMm8G+tMh4g3WA@mail.gmail.com>
Date: Thu, 8 Jan 2026 21:37:44 +0530
From: Kalesh Anakkur Purayil <kalesh-anakkur.purayil@...adcom.com>
To: Ratheesh Kannoth <rkannoth@...vell.com>
Cc: netdev@...r.kernel.org, linux-kernel@...r.kernel.org, 
	andrew+netdev@...n.ch, sgoutham@...vell.com, davem@...emloft.net, 
	edumazet@...gle.com, kuba@...nel.org, pabeni@...hat.com
Subject: Re: [PATCH net-next v2 09/10] octeontx2: switch: Flow offload support

On Wed, Jan 7, 2026 at 7:23 PM Ratheesh Kannoth <rkannoth@...vell.com> wrote:
>
> OVS/NFT pushed HW acceleration rules to pf driver thru .ndo_tc().
> Switchdev HW flow table is filled with this information.
> Once populated, flow will be accelerated.
>
> Signed-off-by: Ratheesh Kannoth <rkannoth@...vell.com>
> ---
>  .../marvell/octeontx2/af/switch/rvu_sw.c      |   4 +
>  .../marvell/octeontx2/af/switch/rvu_sw_fl.c   | 278 ++++++++++
>  .../marvell/octeontx2/af/switch/rvu_sw_fl.h   |   2 +
>  .../ethernet/marvell/octeontx2/nic/otx2_tc.c  |  17 +-
>  .../marvell/octeontx2/nic/switch/sw_fl.c      | 520 ++++++++++++++++++
>  .../marvell/octeontx2/nic/switch/sw_fl.h      |   2 +
>  .../marvell/octeontx2/nic/switch/sw_nb.c      |   1 -
>  7 files changed, 822 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c
> index fe91b0a6baf5..10aed0ca5934 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw.c
> @@ -37,6 +37,10 @@ int rvu_mbox_handler_swdev2af_notify(struct rvu *rvu,
>         case SWDEV2AF_MSG_TYPE_REFRESH_FDB:
>                 rc = rvu_sw_l2_fdb_list_entry_add(rvu, req->pcifunc, req->mac);
>                 break;
> +
> +       case SWDEV2AF_MSG_TYPE_REFRESH_FL:
> +               rc = rvu_sw_fl_stats_sync2db(rvu, req->fl, req->cnt);
> +               break;
>         }
>
>         return rc;
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.c b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.c
> index 1f8b82a84a5d..3cca0672d9cf 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.c
> @@ -4,12 +4,260 @@
>   * Copyright (C) 2026 Marvell.
>   *
>   */
> +
> +#include <linux/bitfield.h>
>  #include "rvu.h"
> +#include "rvu_sw.h"
> +#include "rvu_sw_fl.h"
> +
> +#define M(_name, _id, _fn_name, _req_type, _rsp_type)                  \
> +static struct _req_type __maybe_unused                                 \
> +*otx2_mbox_alloc_msg_ ## _fn_name(struct rvu *rvu, int devid)          \
> +{                                                                      \
> +       struct _req_type *req;                                          \
> +                                                                       \
> +       req = (struct _req_type *)otx2_mbox_alloc_msg_rsp(              \
> +               &rvu->afpf_wq_info.mbox_up, devid, sizeof(struct _req_type), \
> +               sizeof(struct _rsp_type));                              \
> +       if (!req)                                                       \
> +               return NULL;                                            \
> +       req->hdr.sig = OTX2_MBOX_REQ_SIG;                               \
> +       req->hdr.id = _id;                                              \
> +       return req;                                                     \
> +}
> +
> +MBOX_UP_AF2SWDEV_MESSAGES
> +#undef M
> +
> +static struct workqueue_struct *sw_fl_offl_wq;
> +
> +struct fl_entry {
> +       struct list_head list;
> +       struct rvu *rvu;
> +       u32 port_id;
> +       unsigned long cookie;
> +       struct fl_tuple tuple;
> +       u64 flags;
> +       u64 features;
> +};
> +
> +static DEFINE_MUTEX(fl_offl_llock);
> +static LIST_HEAD(fl_offl_lh);
> +static bool fl_offl_work_running;
> +
> +static struct workqueue_struct *sw_fl_offl_wq;
> +static void sw_fl_offl_work_handler(struct work_struct *work);
> +static DECLARE_DELAYED_WORK(fl_offl_work, sw_fl_offl_work_handler);
> +
> +struct sw_fl_stats_node {
> +       struct list_head list;
> +       unsigned long cookie;
> +       u16 mcam_idx[2];
> +       u64 opkts, npkts;
> +       bool uni_di;
> +};
> +
> +static LIST_HEAD(sw_fl_stats_lh);
> +static DEFINE_MUTEX(sw_fl_stats_lock);
> +
> +static int
> +rvu_sw_fl_stats_sync2db_one_entry(unsigned long cookie, u8 disabled,
> +                                 u16 mcam_idx[2], bool uni_di, u64 pkts)
> +{
> +       struct sw_fl_stats_node *snode, *tmp;
> +
> +       mutex_lock(&sw_fl_stats_lock);
> +       list_for_each_entry_safe(snode, tmp, &sw_fl_stats_lh, list) {
> +               if (snode->cookie != cookie)
> +                       continue;
> +
> +               if (disabled) {
> +                       list_del_init(&snode->list);
> +                       mutex_unlock(&sw_fl_stats_lock);
> +                       kfree(snode);
> +                       return 0;
> +               }
> +
> +               if (snode->uni_di != uni_di) {
> +                       snode->uni_di = uni_di;
> +                       snode->mcam_idx[1] = mcam_idx[1];
> +               }
> +
> +               if (snode->opkts == pkts) {
> +                       mutex_unlock(&sw_fl_stats_lock);
> +                       return 0;
> +               }
> +
> +               snode->npkts = pkts;
> +               mutex_unlock(&sw_fl_stats_lock);
> +               return 0;
> +       }
> +       mutex_unlock(&sw_fl_stats_lock);
> +
> +       snode = kcalloc(1, sizeof(*snode), GFP_KERNEL);
Why not kzalloc() instead of kcalloc with size 1?
> +       if (!snode)
> +               return -ENOMEM;
> +
> +       snode->cookie = cookie;
> +       snode->mcam_idx[0] = mcam_idx[0];
> +       if (!uni_di)
> +               snode->mcam_idx[1] = mcam_idx[1];
> +
> +       snode->npkts = pkts;
> +       snode->uni_di = uni_di;
> +       INIT_LIST_HEAD(&snode->list);
> +
> +       mutex_lock(&sw_fl_stats_lock);
> +       list_add_tail(&snode->list, &sw_fl_stats_lh);
> +       mutex_unlock(&sw_fl_stats_lock);
> +
> +       return 0;
> +}
> +
> +int rvu_sw_fl_stats_sync2db(struct rvu *rvu, struct fl_info *fl, int cnt)
> +{
> +       struct npc_mcam_get_mul_stats_req *req = NULL;
> +       struct npc_mcam_get_mul_stats_rsp *rsp = NULL;
there is no need to initialize these two variables
> +       int tot = 0;
> +       u16 i2idx_map[256];
follow RCT order
> +       int rc = 0;
> +       u64 pkts;
> +       int idx;
> +
> +       cnt = min(cnt, 64);
> +
> +       for (int i = 0; i < cnt; i++) {
I think you can move the declaration of i at the beginning of the
function. it is repeated in the for loops below as well
> +               tot++;
> +               if (fl[i].uni_di)
> +                       continue;
> +
> +               tot++;
> +       }
> +
> +       req = kcalloc(1, sizeof(*req), GFP_KERNEL);
I think you can use kzalloc kere
> +       if (!req) {
> +               rc = -ENOMEM;
You can return directly here
> +               goto fail;
> +       }
> +
> +       rsp = kcalloc(1, sizeof(*rsp), GFP_KERNEL);
> +       if (!rsp) {
> +               rc = -ENOMEM;
> +               goto fail;
better do individual cleanup by adding a label and use goto free_req
> +       }
> +
> +       req->cnt = tot;
> +       idx = 0;
> +       for (int i = 0; i < tot; idx++) {
> +               i2idx_map[i] = idx;
> +               req->entry[i++] = fl[idx].mcam_idx[0];
> +               if (fl[idx].uni_di)
> +                       continue;
> +
> +               i2idx_map[i] = idx;
> +               req->entry[i++] = fl[idx].mcam_idx[1];
> +       }
> +
> +       if (rvu_mbox_handler_npc_mcam_mul_stats(rvu, req, rsp)) {
> +               dev_err(rvu->dev, "Error to get multiple stats\n");
> +               rc = -EFAULT;
You can add a new label and use goto free_resp

> +               goto fail;
> +       }
> +
> +       for (int i = 0; i < tot;) {
> +               idx = i2idx_map[i];
> +               pkts =  rsp->stat[i++];
> +
> +               if (!fl[idx].uni_di)
> +                       pkts += rsp->stat[i++];
> +
> +               rc |= rvu_sw_fl_stats_sync2db_one_entry(fl[idx].cookie, fl[idx].dis,
> +                                                       fl[idx].mcam_idx,
> +                                                       fl[idx].uni_di, pkts);
> +       }
> +
> +fail:
> +       kfree(req);
> +       kfree(rsp);
> +       return rc;
> +}
> +
> +static void sw_fl_offl_dump(struct fl_entry *fl_entry)
> +{
> +       struct fl_tuple *tuple = &fl_entry->tuple;
> +
> +       pr_debug("%pI4 to %pI4\n", &tuple->ip4src, &tuple->ip4dst);
> +}
> +
> +static int rvu_sw_fl_offl_rule_push(struct fl_entry *fl_entry)
> +{
> +       struct af2swdev_notify_req *req;
> +       struct rvu *rvu;
> +       int swdev_pf;
> +
> +       rvu = fl_entry->rvu;
> +       swdev_pf = rvu_get_pf(rvu->pdev, rvu->rswitch.pcifunc);
> +
> +       mutex_lock(&rvu->mbox_lock);
> +       req = otx2_mbox_alloc_msg_af2swdev_notify(rvu, swdev_pf);
> +       if (!req) {
> +               mutex_unlock(&rvu->mbox_lock);
> +               return -ENOMEM;
> +       }
> +
> +       req->tuple = fl_entry->tuple;
> +       req->flags = fl_entry->flags;
> +       req->cookie = fl_entry->cookie;
> +       req->features = fl_entry->features;
> +
> +       sw_fl_offl_dump(fl_entry);
> +
> +       otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, swdev_pf);
> +       otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, swdev_pf);
> +
> +       mutex_unlock(&rvu->mbox_lock);
> +       return 0;
> +}
> +
> +static void sw_fl_offl_work_handler(struct work_struct *work)
> +{
> +       struct fl_entry *fl_entry;
> +
> +       mutex_lock(&fl_offl_llock);
> +       fl_entry = list_first_entry_or_null(&fl_offl_lh, struct fl_entry, list);
> +       if (!fl_entry) {
> +               mutex_unlock(&fl_offl_llock);
> +               return;
> +       }
> +
> +       list_del_init(&fl_entry->list);
> +       mutex_unlock(&fl_offl_llock);
> +
> +       rvu_sw_fl_offl_rule_push(fl_entry);
> +       kfree(fl_entry);
> +
> +       mutex_lock(&fl_offl_llock);
> +       if (!list_empty(&fl_offl_lh))
> +               queue_delayed_work(sw_fl_offl_wq, &fl_offl_work, msecs_to_jiffies(10));
> +       mutex_unlock(&fl_offl_llock);
> +}
>
>  int rvu_mbox_handler_fl_get_stats(struct rvu *rvu,
>                                   struct fl_get_stats_req *req,
>                                   struct fl_get_stats_rsp *rsp)
>  {
> +       struct sw_fl_stats_node *snode, *tmp;
> +
> +       mutex_lock(&sw_fl_stats_lock);
> +       list_for_each_entry_safe(snode, tmp, &sw_fl_stats_lh, list) {
> +               if (snode->cookie != req->cookie)
> +                       continue;
> +
> +               rsp->pkts_diff = snode->npkts - snode->opkts;
> +               snode->opkts = snode->npkts;
> +               break;
> +       }
> +       mutex_unlock(&sw_fl_stats_lock);
>         return 0;
>  }
>
> @@ -17,5 +265,35 @@ int rvu_mbox_handler_fl_notify(struct rvu *rvu,
>                                struct fl_notify_req *req,
>                                struct msg_rsp *rsp)
>  {
> +       struct fl_entry *fl_entry;
> +
> +       if (!(rvu->rswitch.flags & RVU_SWITCH_FLAG_FW_READY))
> +               return 0;
> +
> +       fl_entry = kcalloc(1, sizeof(*fl_entry), GFP_KERNEL);
> +       if (!fl_entry)
> +               return -ENOMEM;
> +
> +       fl_entry->port_id = rvu_sw_port_id(rvu, req->hdr.pcifunc);
> +       fl_entry->rvu = rvu;
> +       INIT_LIST_HEAD(&fl_entry->list);
> +       fl_entry->tuple = req->tuple;
> +       fl_entry->cookie = req->cookie;
> +       fl_entry->flags = req->flags;
> +       fl_entry->features = req->features;
> +
> +       mutex_lock(&fl_offl_llock);
> +       list_add_tail(&fl_entry->list, &fl_offl_lh);
> +       mutex_unlock(&fl_offl_llock);
> +
> +       if (!fl_offl_work_running) {
> +               sw_fl_offl_wq = alloc_workqueue("sw_af_fl_wq", 0, 0);
> +               if (!sw_fl_offl_wq)
free fl_entry here? also, do you want to move list_add_tail() after
this if() condition?
> +                       return -ENOMEM;
> +
> +               fl_offl_work_running = true;
> +       }
> +       queue_delayed_work(sw_fl_offl_wq, &fl_offl_work, msecs_to_jiffies(10));
> +
>         return 0;
>  }
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.h b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.h
> index cf3e5b884f77..aa375413bc14 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.h
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/switch/rvu_sw_fl.h
> @@ -8,4 +8,6 @@
>  #ifndef RVU_SW_FL_H
>  #define RVU_SW_FL_H
>
> +int rvu_sw_fl_stats_sync2db(struct rvu *rvu, struct fl_info *fl, int cnt);
> +
>  #endif
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
> index 26a08d2cfbb1..716764d74e6a 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
> @@ -20,6 +20,7 @@
>  #include "cn10k.h"
>  #include "otx2_common.h"
>  #include "qos.h"
> +#include "switch/sw_fl.h"
>
>  #define CN10K_MAX_BURST_MANTISSA       0x7FFFULL
>  #define CN10K_MAX_BURST_SIZE           8453888ULL
> @@ -1238,7 +1239,6 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
>                 mutex_unlock(&nic->mbox.lock);
>         }
>
> -
>  free_mcam_flow:
>         otx2_del_mcam_flow_entry(nic, flow_node->entry, NULL);
>         otx2_tc_update_mcam_table(nic, flow_cfg, flow_node, false);
> @@ -1595,11 +1595,26 @@ static int otx2_setup_tc_block(struct net_device *netdev,
>  int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type,
>                   void *type_data)
>  {
> +       struct otx2_nic *nic = netdev_priv(netdev);
> +
>         switch (type) {
>         case TC_SETUP_BLOCK:
> +               if (netif_is_ovs_port(netdev)) {
> +                       return flow_block_cb_setup_simple(type_data,
> +                                                         &otx2_block_cb_list,
> +                                                         sw_fl_setup_ft_block_ingress_cb,
> +                                                         nic, nic, true);
> +               }
braces are not required here
> +
>                 return otx2_setup_tc_block(netdev, type_data);
>         case TC_SETUP_QDISC_HTB:
>                 return otx2_setup_tc_htb(netdev, type_data);
> +
> +       case TC_SETUP_FT:
> +               return flow_block_cb_setup_simple(type_data,
> +                                                 &otx2_block_cb_list,
> +                                                 sw_fl_setup_ft_block_ingress_cb,
> +                                                 nic, nic, true);
>         default:
>                 return -EOPNOTSUPP;
>         }
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.c b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.c
> index 36a2359a0a48..fbb56f9bede9 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.c
> @@ -4,13 +4,533 @@
>   * Copyright (C) 2026 Marvell.
>   *
>   */
> +#include <linux/kernel.h>
> +#include <linux/netdevice.h>
> +#include <linux/etherdevice.h>
> +#include <net/switchdev.h>
> +#include <net/netevent.h>
> +#include <net/arp.h>
> +#include <net/nexthop.h>
> +#include <net/netfilter/nf_flow_table.h>
> +
> +#include "../otx2_reg.h"
> +#include "../otx2_common.h"
> +#include "../otx2_struct.h"
> +#include "../cn10k.h"
> +#include "sw_nb.h"
>  #include "sw_fl.h"
>
> +#if !IS_ENABLED(CONFIG_OCTEONTX_SWITCH)
> +int sw_fl_setup_ft_block_ingress_cb(enum tc_setup_type type,
> +                                   void *type_data, void *cb_priv)
> +{
> +       return -EOPNOTSUPP;
> +}
> +
> +#else
> +
> +static DEFINE_SPINLOCK(sw_fl_lock);
> +static LIST_HEAD(sw_fl_lh);
> +
> +struct sw_fl_list_entry {
> +       struct list_head list;
> +       u64 flags;
> +       unsigned long cookie;
> +       struct otx2_nic *pf;
> +       struct fl_tuple tuple;
> +};
> +
> +static struct workqueue_struct *sw_fl_wq;
> +static struct work_struct sw_fl_work;
> +
> +static int sw_fl_msg_send(struct otx2_nic *pf,
> +                         struct fl_tuple *tuple,
> +                         u64 flags,
> +                         unsigned long cookie)
> +{
> +       struct fl_notify_req *req;
> +       int rc;
> +
> +       mutex_lock(&pf->mbox.lock);
> +       req = otx2_mbox_alloc_msg_fl_notify(&pf->mbox);
> +       if (!req) {
> +               rc = -ENOMEM;
> +               goto out;
> +       }
> +
> +       req->tuple = *tuple;
> +       req->flags = flags;
> +       req->cookie = cookie;
> +
> +       rc = otx2_sync_mbox_msg(&pf->mbox);
> +out:
> +       mutex_unlock(&pf->mbox.lock);
> +       return rc;
> +}
> +
> +static void sw_fl_wq_handler(struct work_struct *work)
> +{
> +       struct sw_fl_list_entry *entry;
> +       LIST_HEAD(tlist);
> +
> +       spin_lock(&sw_fl_lock);
> +       list_splice_init(&sw_fl_lh, &tlist);
> +       spin_unlock(&sw_fl_lock);
> +
> +       while ((entry =
> +               list_first_entry_or_null(&tlist,
> +                                        struct sw_fl_list_entry,
> +                                        list)) != NULL) {
> +               list_del_init(&entry->list);
> +               sw_fl_msg_send(entry->pf, &entry->tuple,
> +                              entry->flags, entry->cookie);
> +               kfree(entry);
> +       }
> +
> +       spin_lock(&sw_fl_lock);
> +       if (!list_empty(&sw_fl_lh))
> +               queue_work(sw_fl_wq, &sw_fl_work);
> +       spin_unlock(&sw_fl_lock);
> +}
> +
> +static int
> +sw_fl_add_to_list(struct otx2_nic *pf, struct fl_tuple *tuple,
> +                 unsigned long cookie, bool add_fl)
> +{
> +       struct sw_fl_list_entry *entry;
> +
> +       entry = kcalloc(1, sizeof(*entry), GFP_ATOMIC);
> +       if (!entry)
> +               return -ENOMEM;
> +
> +       entry->pf = pf;
> +       entry->flags = add_fl ? FL_ADD : FL_DEL;
> +       if (add_fl)
> +               entry->tuple = *tuple;
> +       entry->cookie = cookie;
> +       entry->tuple.uni_di = netif_is_ovs_port(pf->netdev);
> +
> +       spin_lock(&sw_fl_lock);
> +       list_add_tail(&entry->list, &sw_fl_lh);
> +       queue_work(sw_fl_wq, &sw_fl_work);
> +       spin_unlock(&sw_fl_lock);
> +
> +       return 0;
> +}
> +
> +static int sw_fl_parse_actions(struct otx2_nic *nic,
> +                              struct flow_action *flow_action,
> +                              struct flow_cls_offload *f,
> +                              struct fl_tuple *tuple, u64 *op)
> +{
> +       struct flow_action_entry *act;
> +       struct otx2_nic *out_nic;
> +       int err;
> +       int used = 0;
RCT order here
> +       int i;
> +
> +       if (!flow_action_has_entries(flow_action))
> +               return -EINVAL;
> +
> +       flow_action_for_each(i, act, flow_action) {
> +               WARN_ON(used >= MANGLE_ARR_SZ);
> +
> +               switch (act->id) {
> +               case FLOW_ACTION_REDIRECT:
> +                       tuple->in_pf = nic->pcifunc;
> +                       out_nic = netdev_priv(act->dev);
> +                       tuple->xmit_pf = out_nic->pcifunc;
> +                       *op |= BIT_ULL(FLOW_ACTION_REDIRECT);
> +                       break;
> +
> +               case FLOW_ACTION_CT:
> +                       err = nf_flow_table_offload_add_cb(act->ct.flow_table,
> +                                                          sw_fl_setup_ft_block_ingress_cb,
> +                                                          nic);
> +                       if (err != -EEXIST && err) {
> +                               pr_err("%s:%d Error to offload flow, err=%d\n",
> +                                      __func__, __LINE__, err);
> +                               break;
> +                       }
> +
> +                       *op |= BIT_ULL(FLOW_ACTION_CT);
> +                       break;
> +
> +               case FLOW_ACTION_MANGLE:
> +                       tuple->mangle[used].type = act->mangle.htype;
> +                       tuple->mangle[used].val = act->mangle.val;
> +                       tuple->mangle[used].mask = act->mangle.mask;
> +                       tuple->mangle[used].offset = act->mangle.offset;
> +                       tuple->mangle_map[act->mangle.htype] |= BIT(used);
> +                       used++;
> +                       break;
> +
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       tuple->mangle_cnt = used;
> +
> +       if (!*op) {
> +               pr_debug("%s:%d Op is not valid\n", __func__, __LINE__);
> +               return -EOPNOTSUPP;
> +       }
> +
> +       return 0;
> +}
> +
> +static int sw_fl_get_route(struct fib_result *res, __be32 addr)
> +{
> +       struct flowi4 fl4;
> +
> +       memset(&fl4, 0, sizeof(fl4));
> +       fl4.daddr = addr;
> +       return fib_lookup(&init_net, &fl4, res, 0);
> +}
> +
> +static int sw_fl_get_pcifunc(__be32 dst, u16 *pcifunc, struct fl_tuple *ftuple, bool is_in_dev)
> +{
> +       struct fib_nh_common *fib_nhc;
> +       struct net_device *dev, *br;
> +       struct otx2_nic *nic;
> +       struct fib_result res;
> +       struct list_head *lh;
> +       int err;
> +
> +       rcu_read_lock();
> +
> +       err = sw_fl_get_route(&res, dst);
> +       if (err) {
> +               pr_err("%s:%d Failed to find route to dst %pI4\n",
> +                      __func__, __LINE__, &dst);
> +               goto done;
> +       }
> +
> +       if (res.fi->fib_type != RTN_UNICAST) {
> +               pr_err("%s:%d Not unicast  route to dst %pi4\n",
> +                      __func__, __LINE__, &dst);
> +               err = -EFAULT;
> +               goto done;
> +       }
> +
> +       fib_nhc = fib_info_nhc(res.fi, 0);
> +       if (!fib_nhc) {
> +               err = -EINVAL;
> +               pr_err("%s:%d Could not get fib_nhc for %pI4\n",
> +                      __func__, __LINE__, &dst);
> +               goto done;
> +       }
> +
> +       if (unlikely(netif_is_bridge_master(fib_nhc->nhc_dev))) {
> +               br = fib_nhc->nhc_dev;
> +
> +               if (is_in_dev)
> +                       ftuple->is_indev_br = 1;
> +               else
> +                       ftuple->is_xdev_br = 1;
> +
> +               lh = &br->adj_list.lower;
> +               if (list_empty(lh)) {
> +                       pr_err("%s:%d Unable to find any slave device\n",
> +                              __func__, __LINE__);
> +                       err = -EINVAL;
> +                       goto done;
> +               }
> +               dev = netdev_next_lower_dev_rcu(br, &lh);
> +
> +       } else {
> +               dev = fib_nhc->nhc_dev;
> +       }
> +
> +       if (!sw_nb_is_valid_dev(dev)) {
> +               pr_err("%s:%d flow acceleration support is only for cavium devices\n",
> +                      __func__, __LINE__);
> +               err = -EOPNOTSUPP;
> +               goto done;
> +       }
> +
> +       nic = netdev_priv(dev);
> +       *pcifunc = nic->pcifunc;
> +
> +done:
> +       rcu_read_unlock();
> +       return err;
> +}
> +
> +static int sw_fl_parse_flow(struct otx2_nic *nic, struct flow_cls_offload *f,
> +                           struct fl_tuple *tuple, u64 *features)
> +{
> +       struct flow_rule *rule;
> +       u8 ip_proto = 0;
> +
> +       *features = 0;
> +
> +       rule = flow_cls_offload_flow_rule(f);
> +
> +       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
> +               struct flow_match_basic match;
> +
> +               flow_rule_match_basic(rule, &match);
> +
> +               /* All EtherTypes can be matched, no hw limitation */
> +
> +               if (match.mask->n_proto) {
> +                       tuple->eth_type = match.key->n_proto;
> +                       tuple->m_eth_type = match.mask->n_proto;
> +                       *features |= BIT_ULL(NPC_ETYPE);
> +               }
> +
> +               if (match.mask->ip_proto &&
> +                   (match.key->ip_proto != IPPROTO_TCP &&
> +                    match.key->ip_proto != IPPROTO_UDP)) {
> +                       netdev_dbg(nic->netdev,
> +                                  "ip_proto=%u not supported\n",
> +                                  match.key->ip_proto);
> +               }
> +
> +               if (match.mask->ip_proto)
> +                       ip_proto = match.key->ip_proto;
> +
> +               if (ip_proto == IPPROTO_UDP) {
> +                       *features |= BIT_ULL(NPC_IPPROTO_UDP);
> +               } else if (ip_proto == IPPROTO_TCP) {
> +                       *features |= BIT_ULL(NPC_IPPROTO_TCP);
> +               } else {
> +                       netdev_dbg(nic->netdev,
> +                                  "ip_proto=%u not supported\n",
> +                                  match.key->ip_proto);
> +               }
> +
> +               tuple->proto = ip_proto;
> +       }
> +
> +       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
> +               struct flow_match_eth_addrs match;
> +
> +               flow_rule_match_eth_addrs(rule, &match);
> +
> +               if (!is_zero_ether_addr(match.key->dst) &&
> +                   is_unicast_ether_addr(match.key->dst)) {
> +                       ether_addr_copy(tuple->dmac,
> +                                       match.key->dst);
> +
> +                       ether_addr_copy(tuple->m_dmac,
> +                                       match.mask->dst);
> +
> +                       *features |= BIT_ULL(NPC_DMAC);
> +               }
> +
> +               if (!is_zero_ether_addr(match.key->src) &&
> +                   is_unicast_ether_addr(match.key->src)) {
> +                       ether_addr_copy(tuple->smac,
> +                                       match.key->src);
> +                       ether_addr_copy(tuple->m_smac,
> +                                       match.mask->src);
> +                       *features |= BIT_ULL(NPC_SMAC);
> +               }
> +       }
> +
> +       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
> +               struct flow_match_ipv4_addrs match;
> +
> +               flow_rule_match_ipv4_addrs(rule, &match);
> +
> +               if (match.key->dst) {
> +                       tuple->ip4dst = match.key->dst;
> +                       tuple->m_ip4dst = match.mask->dst;
> +                       *features |= BIT_ULL(NPC_DIP_IPV4);
> +               }
> +
> +               if (match.key->src) {
> +                       tuple->ip4src = match.key->src;
> +                       tuple->m_ip4src = match.mask->src;
> +                       *features |= BIT_ULL(NPC_SIP_IPV4);
> +               }
> +       }
> +
> +       if (!(*features & BIT_ULL(NPC_DMAC))) {
> +               if (!tuple->ip4src || !tuple->ip4dst) {
> +                       pr_err("%s:%d Invalid src=%pI4 and dst=%pI4 addresses\n",
> +                              __func__, __LINE__, &tuple->ip4src, &tuple->ip4dst);
> +                       return -EINVAL;
> +               }
> +
> +               if ((tuple->ip4src & tuple->m_ip4src) == (tuple->ip4dst & tuple->m_ip4dst)) {
> +                       pr_err("%s:%d Masked values are same; Invalid src=%pI4 and dst=%pI4 addresses\n",
> +                              __func__, __LINE__, &tuple->ip4src, &tuple->ip4dst);
> +                       return -EINVAL;
> +               }
> +       }
> +
> +       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
> +               struct flow_match_ports match;
> +
> +               flow_rule_match_ports(rule, &match);
> +
> +               if (ip_proto == IPPROTO_UDP) {
> +                       if (match.key->dst)
> +                               *features |= BIT_ULL(NPC_DPORT_UDP);
> +
> +                       if (match.key->src)
> +                               *features |= BIT_ULL(NPC_SPORT_UDP);
> +               } else if (ip_proto == IPPROTO_TCP) {
> +                       if (match.key->dst)
> +                               *features |= BIT_ULL(NPC_DPORT_TCP);
> +
> +                       if (match.key->src)
> +                               *features |= BIT_ULL(NPC_SPORT_TCP);
> +               }
> +
> +               if (match.mask->src) {
> +                       tuple->sport = match.key->src;
> +                       tuple->m_sport = match.mask->src;
> +               }
> +
> +               if (match.mask->dst) {
> +                       tuple->dport = match.key->dst;
> +                       tuple->m_dport = match.mask->dst;
> +               }
> +       }
> +
> +       if (!(*features & (BIT_ULL(NPC_DMAC) |
> +                          BIT_ULL(NPC_SMAC) |
> +                          BIT_ULL(NPC_DIP_IPV4) |
> +                          BIT_ULL(NPC_SIP_IPV4) |
> +                          BIT_ULL(NPC_DPORT_UDP) |
> +                          BIT_ULL(NPC_SPORT_UDP) |
> +                          BIT_ULL(NPC_DPORT_TCP) |
> +                          BIT_ULL(NPC_SPORT_TCP)))) {
> +               return -EINVAL;
> +       }
> +
> +       tuple->features = *features;
> +
> +       return 0;
> +}
> +
> +static int sw_fl_add(struct otx2_nic *nic, struct flow_cls_offload *f)
> +{
> +       struct fl_tuple tuple = { 0 };
> +       struct flow_rule *rule;
> +       u64 features = 0;
> +       u64 op = 0;
> +       int rc;
> +
> +       rule = flow_cls_offload_flow_rule(f);
> +
> +       rc = sw_fl_parse_actions(nic, &rule->action, f, &tuple, &op);
> +       if (rc)
> +               return rc;
> +
> +       if (op & BIT_ULL(FLOW_ACTION_CT))
> +               return 0;
> +
> +       rc  = sw_fl_parse_flow(nic, f, &tuple, &features);
> +       if (rc)
> +               return -EFAULT;
> +
> +       if (!netif_is_ovs_port(nic->netdev)) {
> +               rc = sw_fl_get_pcifunc(tuple.ip4src, &tuple.in_pf, &tuple, true);
> +               if (rc)
> +                       return rc;
> +
> +               rc = sw_fl_get_pcifunc(tuple.ip4dst, &tuple.xmit_pf, &tuple, false);
> +               if (rc)
> +                       return rc;
> +       }
> +
> +       sw_fl_add_to_list(nic, &tuple, f->cookie, true);
> +       return 0;
> +}
> +
> +static int sw_fl_del(struct otx2_nic *nic, struct flow_cls_offload *f)
function prototype can be changed to void?
> +{
> +       sw_fl_add_to_list(nic, NULL, f->cookie, false);
> +       return 0;
> +}
> +
> +static int sw_fl_stats(struct otx2_nic *nic, struct flow_cls_offload *f)
> +{
> +       struct fl_get_stats_req *req;
> +       struct fl_get_stats_rsp *rsp;
> +       u64 pkts_diff;
> +       int rc = 0;
> +
> +       mutex_lock(&nic->mbox.lock);
> +
> +       req = otx2_mbox_alloc_msg_fl_get_stats(&nic->mbox);
> +       if (!req) {
> +               pr_err("%s:%d Error happened while mcam alloc req\n", __func__, __LINE__);
> +               rc = -ENOMEM;
> +               goto fail;
> +       }
> +       req->cookie = f->cookie;
> +
> +       rc = otx2_sync_mbox_msg(&nic->mbox);
> +       if (rc)
> +               goto fail;
> +
> +       rsp = (struct fl_get_stats_rsp *)otx2_mbox_get_rsp
> +               (&nic->mbox.mbox, 0, &req->hdr);
> +       if (IS_ERR(rsp)) {
> +               rc = PTR_ERR(rsp);
> +               goto fail;
> +       }
> +
> +       pkts_diff = rsp->pkts_diff;
> +       mutex_unlock(&nic->mbox.lock);
> +
> +       if (pkts_diff) {
> +               flow_stats_update(&f->stats, 0x0, pkts_diff,
> +                                 0x0, jiffies,
> +                                 FLOW_ACTION_HW_STATS_IMMEDIATE);
> +       }
> +       return 0;
> +fail:
> +       mutex_unlock(&nic->mbox.lock);
> +       return rc;
> +}
> +
> +static bool init_done;
> +
> +int sw_fl_setup_ft_block_ingress_cb(enum tc_setup_type type,
> +                                   void *type_data, void *cb_priv)
> +{
> +       struct flow_cls_offload *cls = type_data;
> +       struct otx2_nic *nic = cb_priv;
> +
> +       if (!init_done)
> +               return 0;
> +
> +       switch (cls->command) {
> +       case FLOW_CLS_REPLACE:
> +               return sw_fl_add(nic, cls);
> +       case FLOW_CLS_DESTROY:
> +               return sw_fl_del(nic, cls);
> +       case FLOW_CLS_STATS:
> +               return sw_fl_stats(nic, cls);
> +       default:
> +               break;
> +       }
> +
> +       return -EOPNOTSUPP;
> +}
> +
>  int sw_fl_init(void)
>  {
> +       INIT_WORK(&sw_fl_work, sw_fl_wq_handler);
> +       sw_fl_wq = alloc_workqueue("sw_fl_wq", 0, 0);
> +       if (!sw_fl_wq)
> +               return -ENOMEM;
> +
> +       init_done = true;
>         return 0;
>  }
>
>  void sw_fl_deinit(void)
>  {
> +       cancel_work_sync(&sw_fl_work);
> +       destroy_workqueue(sw_fl_wq);
>  }
> +#endif
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.h b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.h
> index cd018d770a8a..8dd816eb17d2 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.h
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_fl.h
> @@ -9,5 +9,7 @@
>
>  void sw_fl_deinit(void);
>  int sw_fl_init(void);
> +int sw_fl_setup_ft_block_ingress_cb(enum tc_setup_type type,
> +                                   void *type_data, void *cb_priv);
>
>  #endif // SW_FL_H
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c
> index 7a0ed52eae95..c316aeac2e81 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/switch/sw_nb.c
> @@ -21,7 +21,6 @@
>  #include "sw_fdb.h"
>  #include "sw_fib.h"
>  #include "sw_fl.h"
> -#include "sw_nb.h"
>
>  static const char *sw_nb_cmd2str[OTX2_CMD_MAX] = {
>         [OTX2_DEV_UP]  = "OTX2_DEV_UP",
> --
> 2.43.0
>
>


--
Regards,
Kalesh AP

Download attachment "smime.p7s" of type "application/pkcs7-signature" (5509 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ