All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jamal Hadi Salim <jhs@mojatatu.com>
To: Paul Blakey <paulb@nvidia.com>
Cc: netdev@vger.kernel.org, Saeed Mahameed <saeedm@nvidia.com>,
	Paolo Abeni <pabeni@redhat.com>, Jakub Kicinski <kuba@kernel.org>,
	Eric Dumazet <edumazet@google.com>,
	Cong Wang <xiyou.wangcong@gmail.com>,
	"David S. Miller" <davem@davemloft.net>,
	Oz Shlomo <ozsh@nvidia.com>, Jiri Pirko <jiri@nvidia.com>,
	Roi Dayan <roid@nvidia.com>, Vlad Buslov <vladbu@nvidia.com>
Subject: Re: [PATCH net-next v5 1/6] net/sched: cls_api: Support hardware miss to tc action
Date: Sat, 28 Jan 2023 08:56:41 -0500	[thread overview]
Message-ID: <CAM0EoMkh5xf5i3m3FVNL_0U27Q32CtVKDM8iOoe82LWwOxOFQQ@mail.gmail.com> (raw)
In-Reply-To: <20230125153218.7230-2-paulb@nvidia.com>

For the cls parts:
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>

cheers,
jamal

On Wed, Jan 25, 2023 at 10:32 AM Paul Blakey <paulb@nvidia.com> wrote:
>
> For drivers to support partial offload of a filter's action list,
> add support for action miss to specify an action instance to
> continue from in sw.
>
> CT action in particular can't be fully offloaded, as new connections
> need to be handled in software. This imposes other limitations on
> the actions that can be offloaded together with the CT action, such
> as packet modifications.
>
> Assign each action on a filter's action list a unique miss_cookie
> which drivers can then use to fill action_miss part of the tc skb
> extension. On getting back this miss_cookie, find the action
> instance with relevant cookie and continue classifying from there.
>
> Signed-off-by: Paul Blakey <paulb@nvidia.com>
> Reviewed-by: Jiri Pirko <jiri@nvidia.com>
> ---
>  include/linux/skbuff.h     |   6 +-
>  include/net/flow_offload.h |   1 +
>  include/net/pkt_cls.h      |  34 +++---
>  include/net/sch_generic.h  |   2 +
>  net/openvswitch/flow.c     |   2 +-
>  net/sched/act_api.c        |   2 +-
>  net/sched/cls_api.c        | 214 +++++++++++++++++++++++++++++++++++--
>  7 files changed, 234 insertions(+), 27 deletions(-)
>
> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> index 4c8492401a10..348673dcb6bb 100644
> --- a/include/linux/skbuff.h
> +++ b/include/linux/skbuff.h
> @@ -316,12 +316,16 @@ struct nf_bridge_info {
>   * and read by ovs to recirc_id.
>   */
>  struct tc_skb_ext {
> -       __u32 chain;
> +       union {
> +               u64 act_miss_cookie;
> +               __u32 chain;
> +       };
>         __u16 mru;
>         __u16 zone;
>         u8 post_ct:1;
>         u8 post_ct_snat:1;
>         u8 post_ct_dnat:1;
> +       u8 act_miss:1; /* Set if act_miss_cookie is used */
>  };
>  #endif
>
> diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
> index 0400a0ac8a29..88db7346eb7a 100644
> --- a/include/net/flow_offload.h
> +++ b/include/net/flow_offload.h
> @@ -228,6 +228,7 @@ void flow_action_cookie_destroy(struct flow_action_cookie *cookie);
>  struct flow_action_entry {
>         enum flow_action_id             id;
>         u32                             hw_index;
> +       u64                             miss_cookie;
>         enum flow_action_hw_stats       hw_stats;
>         action_destr                    destructor;
>         void                            *destructor_priv;
> diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
> index 4cabb32a2ad9..344f2ca02ebd 100644
> --- a/include/net/pkt_cls.h
> +++ b/include/net/pkt_cls.h
> @@ -59,6 +59,8 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
>  void tcf_block_put(struct tcf_block *block);
>  void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
>                        struct tcf_block_ext_info *ei);
> +int tcf_exts_init_ex(struct tcf_exts *exts, struct net *net, int action, int police,
> +                    struct tcf_proto *tp, u32 handle, bool used_action_miss);
>
>  static inline bool tcf_block_shared(struct tcf_block *block)
>  {
> @@ -229,6 +231,7 @@ struct tcf_exts {
>         struct tc_action **actions;
>         struct net      *net;
>         netns_tracker   ns_tracker;
> +       struct tcf_exts_miss_cookie_node *miss_cookie_node;
>  #endif
>         /* Map to export classifier specific extension TLV types to the
>          * generic extensions API. Unsupported extensions must be set to 0.
> @@ -240,21 +243,11 @@ struct tcf_exts {
>  static inline int tcf_exts_init(struct tcf_exts *exts, struct net *net,
>                                 int action, int police)
>  {
> -#ifdef CONFIG_NET_CLS_ACT
> -       exts->type = 0;
> -       exts->nr_actions = 0;
> -       /* Note: we do not own yet a reference on net.
> -        * This reference might be taken later from tcf_exts_get_net().
> -        */
> -       exts->net = net;
> -       exts->actions = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *),
> -                               GFP_KERNEL);
> -       if (!exts->actions)
> -               return -ENOMEM;
> +#ifdef CONFIG_NET_CLS
> +       return tcf_exts_init_ex(exts, net, action, police, NULL, 0, false);
> +#else
> +       return -EOPNOTSUPP;
>  #endif
> -       exts->action = action;
> -       exts->police = police;
> -       return 0;
>  }
>
>  /* Return false if the netns is being destroyed in cleanup_net(). Callers
> @@ -353,6 +346,18 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
>         return TC_ACT_OK;
>  }
>
> +static inline int
> +tcf_exts_exec_ex(struct sk_buff *skb, struct tcf_exts *exts, int act_index,
> +                struct tcf_result *res)
> +{
> +#ifdef CONFIG_NET_CLS_ACT
> +       return tcf_action_exec(skb, exts->actions + act_index,
> +                              exts->nr_actions - act_index, res);
> +#else
> +       return TC_ACT_OK;
> +#endif
> +}
> +
>  int tcf_exts_validate(struct net *net, struct tcf_proto *tp,
>                       struct nlattr **tb, struct nlattr *rate_tlv,
>                       struct tcf_exts *exts, u32 flags,
> @@ -577,6 +582,7 @@ int tc_setup_offload_action(struct flow_action *flow_action,
>  void tc_cleanup_offload_action(struct flow_action *flow_action);
>  int tc_setup_action(struct flow_action *flow_action,
>                     struct tc_action *actions[],
> +                   u32 miss_cookie_base,
>                     struct netlink_ext_ack *extack);
>
>  int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
> diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
> index af4aa66aaa4e..fab5ba3e61b7 100644
> --- a/include/net/sch_generic.h
> +++ b/include/net/sch_generic.h
> @@ -369,6 +369,8 @@ struct tcf_proto_ops {
>                                                 struct nlattr **tca,
>                                                 struct netlink_ext_ack *extack);
>         void                    (*tmplt_destroy)(void *tmplt_priv);
> +       struct tcf_exts *       (*get_exts)(const struct tcf_proto *tp,
> +                                           u32 handle);
>
>         /* rtnetlink specific */
>         int                     (*dump)(struct net*, struct tcf_proto*, void *,
> diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
> index e20d1a973417..b1a5eed8d1a9 100644
> --- a/net/openvswitch/flow.c
> +++ b/net/openvswitch/flow.c
> @@ -1038,7 +1038,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
>  #if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
>         if (tc_skb_ext_tc_enabled()) {
>                 tc_ext = skb_ext_find(skb, TC_SKB_EXT);
> -               key->recirc_id = tc_ext ? tc_ext->chain : 0;
> +               key->recirc_id = tc_ext && !tc_ext->act_miss ? tc_ext->chain : 0;
>                 OVS_CB(skb)->mru = tc_ext ? tc_ext->mru : 0;
>                 post_ct = tc_ext ? tc_ext->post_ct : false;
>                 post_ct_snat = post_ct ? tc_ext->post_ct_snat : false;
> diff --git a/net/sched/act_api.c b/net/sched/act_api.c
> index cd09ef49df22..16fd3d30eb12 100644
> --- a/net/sched/act_api.c
> +++ b/net/sched/act_api.c
> @@ -272,7 +272,7 @@ static int tcf_action_offload_add_ex(struct tc_action *action,
>         if (err)
>                 goto fl_err;
>
> -       err = tc_setup_action(&fl_action->action, actions, extack);
> +       err = tc_setup_action(&fl_action->action, actions, 0, extack);
>         if (err) {
>                 NL_SET_ERR_MSG_MOD(extack,
>                                    "Failed to setup tc actions for offload");
> diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
> index 5b4a95e8a1ee..f3576f261289 100644
> --- a/net/sched/cls_api.c
> +++ b/net/sched/cls_api.c
> @@ -22,6 +22,7 @@
>  #include <linux/idr.h>
>  #include <linux/jhash.h>
>  #include <linux/rculist.h>
> +#include <linux/rhashtable.h>
>  #include <net/net_namespace.h>
>  #include <net/sock.h>
>  #include <net/netlink.h>
> @@ -50,6 +51,110 @@ static LIST_HEAD(tcf_proto_base);
>  /* Protects list of registered TC modules. It is pure SMP lock. */
>  static DEFINE_RWLOCK(cls_mod_lock);
>
> +static struct xarray tcf_exts_miss_cookies_xa;
> +struct tcf_exts_miss_cookie_node {
> +       const struct tcf_chain *chain;
> +       const struct tcf_proto *tp;
> +       const struct tcf_exts *exts;
> +       u32 chain_index;
> +       u32 tp_prio;
> +       u32 handle;
> +       u32 miss_cookie_base;
> +       struct rcu_head rcu;
> +};
> +
> +/* Each tc action entry cookie will be comprised of 32bit miss_cookie_base +
> + * action index in the exts tc actions array.
> + */
> +union tcf_exts_miss_cookie {
> +       struct {
> +               u32 miss_cookie_base;
> +               u32 act_index;
> +       };
> +       u64 miss_cookie;
> +};
> +
> +#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
> +static int
> +tcf_exts_miss_cookie_base_alloc(struct tcf_exts *exts, struct tcf_proto *tp,
> +                               u32 handle)
> +{
> +       struct tcf_exts_miss_cookie_node *n;
> +       static u32 next;
> +       int err;
> +
> +       if (WARN_ON(!handle || !tp->ops->get_exts))
> +               return -EINVAL;
> +
> +       n = kzalloc(sizeof(*n), GFP_KERNEL);
> +       if (!n)
> +               return -ENOMEM;
> +
> +       n->chain_index = tp->chain->index;
> +       n->chain = tp->chain;
> +       n->tp_prio = tp->prio;
> +       n->tp = tp;
> +       n->exts = exts;
> +       n->handle = handle;
> +
> +       err = xa_alloc_cyclic(&tcf_exts_miss_cookies_xa, &n->miss_cookie_base,
> +                             n, xa_limit_32b, &next, GFP_KERNEL);
> +       if (err)
> +               goto err_xa_alloc;
> +
> +       exts->miss_cookie_node = n;
> +       return 0;
> +
> +err_xa_alloc:
> +       kfree(n);
> +       return err;
> +}
> +
> +static void tcf_exts_miss_cookie_base_destroy(struct tcf_exts *exts)
> +{
> +       struct tcf_exts_miss_cookie_node *n;
> +
> +       if (!exts->miss_cookie_node)
> +               return;
> +
> +       n = exts->miss_cookie_node;
> +       xa_erase(&tcf_exts_miss_cookies_xa, n->miss_cookie_base);
> +       kfree_rcu(n, rcu);
> +}
> +
> +static struct tcf_exts_miss_cookie_node *
> +tcf_exts_miss_cookie_lookup(u64 miss_cookie, int *act_index)
> +{
> +       union tcf_exts_miss_cookie mc = { .miss_cookie = miss_cookie, };
> +
> +       *act_index = mc.act_index;
> +       return xa_load(&tcf_exts_miss_cookies_xa, mc.miss_cookie_base);
> +}
> +#else /* IS_ENABLED(CONFIG_NET_TC_SKB_EXT) */
> +static inline int
> +tcf_exts_miss_cookie_base_alloc(struct tcf_exts *exts, struct tcf_proto *tp,
> +                               u32 handle)
> +{
> +       return 0;
> +}
> +
> +static inline void tcf_exts_miss_cookie_base_destroy(struct tcf_exts *exts)
> +{
> +       return;
> +}
> +#endif /* IS_ENABLED(CONFIG_NET_TC_SKB_EXT) */
> +
> +static u64 tcf_exts_miss_cookie_get(u32 miss_cookie_base, int act_index)
> +{
> +       union tcf_exts_miss_cookie mc = { .act_index = act_index, };
> +
> +       if (!miss_cookie_base)
> +               return 0;
> +
> +       mc.miss_cookie_base = miss_cookie_base;
> +       return mc.miss_cookie;
> +}
> +
>  #ifdef CONFIG_NET_CLS_ACT
>  DEFINE_STATIC_KEY_FALSE(tc_skb_ext_tc);
>  EXPORT_SYMBOL(tc_skb_ext_tc);
> @@ -1549,6 +1654,8 @@ static inline int __tcf_classify(struct sk_buff *skb,
>                                  const struct tcf_proto *orig_tp,
>                                  struct tcf_result *res,
>                                  bool compat_mode,
> +                                struct tcf_exts_miss_cookie_node *n,
> +                                int act_index,
>                                  u32 *last_executed_chain)
>  {
>  #ifdef CONFIG_NET_CLS_ACT
> @@ -1560,13 +1667,36 @@ static inline int __tcf_classify(struct sk_buff *skb,
>  #endif
>         for (; tp; tp = rcu_dereference_bh(tp->next)) {
>                 __be16 protocol = skb_protocol(skb, false);
> -               int err;
> +               int err = 0;
>
> -               if (tp->protocol != protocol &&
> -                   tp->protocol != htons(ETH_P_ALL))
> -                       continue;
> +               if (n) {
> +                       struct tcf_exts *exts;
> +
> +                       if (n->tp_prio != tp->prio)
> +                               continue;
> +
> +                       /* We re-lookup the tp and chain based on index instead
> +                        * of having hard refs and locks to them, so do a sanity
> +                        * check if any of tp,chain,exts was replaced by the
> +                        * time we got here with a cookie from hardware.
> +                        */
> +                       if (unlikely(n->tp != tp || n->tp->chain != n->chain ||
> +                                    !tp->ops->get_exts))
> +                               return TC_ACT_SHOT;
> +
> +                       exts = tp->ops->get_exts(tp, n->handle);
> +                       if (unlikely(!exts || n->exts != exts))
> +                               return TC_ACT_SHOT;
>
> -               err = tc_classify(skb, tp, res);
> +                       n = NULL;
> +                       err = tcf_exts_exec_ex(skb, exts, act_index, res);
> +               } else {
> +                       if (tp->protocol != protocol &&
> +                           tp->protocol != htons(ETH_P_ALL))
> +                               continue;
> +
> +                       err = tc_classify(skb, tp, res);
> +               }
>  #ifdef CONFIG_NET_CLS_ACT
>                 if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode)) {
>                         first_tp = orig_tp;
> @@ -1582,6 +1712,9 @@ static inline int __tcf_classify(struct sk_buff *skb,
>                         return err;
>         }
>
> +       if (unlikely(n))
> +               return TC_ACT_SHOT;
> +
>         return TC_ACT_UNSPEC; /* signal: continue lookup */
>  #ifdef CONFIG_NET_CLS_ACT
>  reset:
> @@ -1606,21 +1739,33 @@ int tcf_classify(struct sk_buff *skb,
>  #if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
>         u32 last_executed_chain = 0;
>
> -       return __tcf_classify(skb, tp, tp, res, compat_mode,
> +       return __tcf_classify(skb, tp, tp, res, compat_mode, NULL, 0,
>                               &last_executed_chain);
>  #else
>         u32 last_executed_chain = tp ? tp->chain->index : 0;
> +       struct tcf_exts_miss_cookie_node *n = NULL;
>         const struct tcf_proto *orig_tp = tp;
>         struct tc_skb_ext *ext;
> +       int act_index = 0;
>         int ret;
>
>         if (block) {
>                 ext = skb_ext_find(skb, TC_SKB_EXT);
>
> -               if (ext && ext->chain) {
> +               if (ext && (ext->chain || ext->act_miss)) {
>                         struct tcf_chain *fchain;
> +                       u32 chain = ext->chain;
>
> -                       fchain = tcf_chain_lookup_rcu(block, ext->chain);
> +                       if (ext->act_miss) {
> +                               n = tcf_exts_miss_cookie_lookup(ext->act_miss_cookie,
> +                                                               &act_index);
> +                               if (!n)
> +                                       return TC_ACT_SHOT;
> +
> +                               chain = n->chain_index;
> +                       }
> +
> +                       fchain = tcf_chain_lookup_rcu(block, chain);
>                         if (!fchain)
>                                 return TC_ACT_SHOT;
>
> @@ -1632,7 +1777,7 @@ int tcf_classify(struct sk_buff *skb,
>                 }
>         }
>
> -       ret = __tcf_classify(skb, tp, orig_tp, res, compat_mode,
> +       ret = __tcf_classify(skb, tp, orig_tp, res, compat_mode, n, act_index,
>                              &last_executed_chain);
>
>         if (tc_skb_ext_tc_enabled()) {
> @@ -3056,9 +3201,48 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
>         return skb->len;
>  }
>
> +int tcf_exts_init_ex(struct tcf_exts *exts, struct net *net, int action,
> +                    int police, struct tcf_proto *tp, u32 handle,
> +                    bool use_action_miss)
> +{
> +       int err = 0;
> +
> +#ifdef CONFIG_NET_CLS_ACT
> +       exts->type = 0;
> +       exts->nr_actions = 0;
> +       /* Note: we do not own yet a reference on net.
> +        * This reference might be taken later from tcf_exts_get_net().
> +        */
> +       exts->net = net;
> +       exts->actions = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *),
> +                               GFP_KERNEL);
> +       if (!exts->actions)
> +               return -ENOMEM;
> +#endif
> +
> +       exts->action = action;
> +       exts->police = police;
> +
> +       if (!use_action_miss)
> +               return 0;
> +
> +       err = tcf_exts_miss_cookie_base_alloc(exts, tp, handle);
> +       if (err)
> +               goto err_miss_alloc;
> +
> +       return 0;
> +
> +err_miss_alloc:
> +       tcf_exts_destroy(exts);
> +       return err;
> +}
> +EXPORT_SYMBOL(tcf_exts_init_ex);
> +
>  void tcf_exts_destroy(struct tcf_exts *exts)
>  {
>  #ifdef CONFIG_NET_CLS_ACT
> +       tcf_exts_miss_cookie_base_destroy(exts);
> +
>         if (exts->actions) {
>                 tcf_action_destroy(exts->actions, TCA_ACT_UNBIND);
>                 kfree(exts->actions);
> @@ -3547,6 +3731,7 @@ static int tc_setup_offload_act(struct tc_action *act,
>
>  int tc_setup_action(struct flow_action *flow_action,
>                     struct tc_action *actions[],
> +                   u32 miss_cookie_base,
>                     struct netlink_ext_ack *extack)
>  {
>         int i, j, k, index, err = 0;
> @@ -3577,6 +3762,8 @@ int tc_setup_action(struct flow_action *flow_action,
>                 for (k = 0; k < index ; k++) {
>                         entry[k].hw_stats = tc_act_hw_stats(act->hw_stats);
>                         entry[k].hw_index = act->tcfa_index;
> +                       entry[k].miss_cookie =
> +                               tcf_exts_miss_cookie_get(miss_cookie_base, i);
>                 }
>
>                 j += index;
> @@ -3599,10 +3786,15 @@ int tc_setup_offload_action(struct flow_action *flow_action,
>                             struct netlink_ext_ack *extack)
>  {
>  #ifdef CONFIG_NET_CLS_ACT
> +       u32 miss_cookie_base;
> +
>         if (!exts)
>                 return 0;
>
> -       return tc_setup_action(flow_action, exts->actions, extack);
> +       miss_cookie_base = exts->miss_cookie_node ?
> +                          exts->miss_cookie_node->miss_cookie_base : 0;
> +       return tc_setup_action(flow_action, exts->actions, miss_cookie_base,
> +                              extack);
>  #else
>         return 0;
>  #endif
> @@ -3770,6 +3962,8 @@ static int __init tc_filter_init(void)
>         if (err)
>                 goto err_register_pernet_subsys;
>
> +       xa_init_flags(&tcf_exts_miss_cookies_xa, XA_FLAGS_ALLOC1);
> +
>         rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_new_tfilter, NULL,
>                       RTNL_FLAG_DOIT_UNLOCKED);
>         rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_del_tfilter, NULL,
> --
> 2.30.1
>

  reply	other threads:[~2023-01-28 13:56 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-25 15:32 [PATCH net-next v5 0/6] net/sched: cls_api: Support hardware miss to tc action Paul Blakey
2023-01-25 15:32 ` [PATCH net-next v5 1/6] " Paul Blakey
2023-01-28 13:56   ` Jamal Hadi Salim [this message]
2023-01-28 16:45   ` Simon Horman
2023-01-28 16:52   ` Simon Horman
2023-01-25 15:32 ` [PATCH net-next v5 2/6] net/sched: flower: Move filter handle initialization earlier Paul Blakey
2023-01-28 16:45   ` Simon Horman
2023-01-25 15:32 ` [PATCH net-next v5 3/6] net/sched: flower: Support hardware miss to tc action Paul Blakey
2023-01-28 16:45   ` Simon Horman
2023-01-25 15:32 ` [PATCH net-next v5 4/6] net/mlx5: Refactor tc miss handling to a single function Paul Blakey
2023-01-25 15:32 ` [PATCH net-next v5 5/6] net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG Paul Blakey
2023-01-25 15:32 ` [PATCH net-next v5 6/6] net/mlx5e: TC, Set CT miss to the specific ct action instance Paul Blakey
2023-01-28  8:16 ` [PATCH net-next v5 0/6] net/sched: cls_api: Support hardware miss to tc action Jakub Kicinski
2023-01-28  8:18   ` Jakub Kicinski
2023-01-28  8:59     ` Vlad Buslov
2023-01-28 15:12       ` Vlad Buslov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAM0EoMkh5xf5i3m3FVNL_0U27Q32CtVKDM8iOoe82LWwOxOFQQ@mail.gmail.com \
    --to=jhs@mojatatu.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=jiri@nvidia.com \
    --cc=kuba@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=ozsh@nvidia.com \
    --cc=pabeni@redhat.com \
    --cc=paulb@nvidia.com \
    --cc=roid@nvidia.com \
    --cc=saeedm@nvidia.com \
    --cc=vladbu@nvidia.com \
    --cc=xiyou.wangcong@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.