netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alexander Duyck <alexander.duyck@gmail.com>
To: Tony Nguyen <anthony.l.nguyen@intel.com>
Cc: David Miller <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>,
	Real Valiquette <real.valiquette@intel.com>,
	Netdev <netdev@vger.kernel.org>,
	Stefan Assmann <sassmann@redhat.com>,
	Chinh Cao <chinh.t.cao@intel.com>,
	Brijesh Behera <brijeshx.behera@intel.com>
Subject: Re: [net-next v3 05/15] ice: create flow profile
Date: Fri, 13 Nov 2020 15:56:07 -0800	[thread overview]
Message-ID: <CAKgT0UeQ5q2M-uiR0-1G=30syPiO8S5OFHvDuN1XtQg5700hCg@mail.gmail.com> (raw)
In-Reply-To: <20201113214429.2131951-6-anthony.l.nguyen@intel.com>

On Fri, Nov 13, 2020 at 1:46 PM Tony Nguyen <anthony.l.nguyen@intel.com> wrote:
>
> From: Real Valiquette <real.valiquette@intel.com>
>
> Implement the initial steps for creating an ACL filter to support ntuple
> masks. Create a flow profile based on a given mask rule and program it to
> the hardware. Though the profile is written to hardware, no actions are
> associated with the profile yet.
>
> Co-developed-by: Chinh Cao <chinh.t.cao@intel.com>
> Signed-off-by: Chinh Cao <chinh.t.cao@intel.com>
> Signed-off-by: Real Valiquette <real.valiquette@intel.com>
> Co-developed-by: Tony Nguyen <anthony.l.nguyen@intel.com>
> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
> Tested-by: Brijesh Behera <brijeshx.behera@intel.com>

So I see two big issues with the patch.

First it looks like there is an anti-pattern of defensive NULL pointer
checks throughout. Those can probably all go since all of the callers
either use the pointer, or verify it is non-NULL before calling the
function in question.

In addition the mask handling doens't look right to me. It is calling
out a partial mask as being the only time you need an ACL and I would
think it is any time you don't have a full mask for all
ports/addresses since a flow director rule normally pulls in the full
4 tuple based on ice_ntuple_set_input_set() .

I commented on what I saw below.

Thanks.

- Alex

> ---
>  drivers/net/ethernet/intel/ice/Makefile       |   1 +
>  drivers/net/ethernet/intel/ice/ice.h          |   9 +
>  drivers/net/ethernet/intel/ice/ice_acl_main.c | 260 ++++++++++++++++
>  .../net/ethernet/intel/ice/ice_adminq_cmd.h   |  39 +++
>  .../net/ethernet/intel/ice/ice_ethtool_fdir.c | 290 ++++++++++++++----
>  .../net/ethernet/intel/ice/ice_flex_pipe.c    |  12 +-
>  drivers/net/ethernet/intel/ice/ice_flow.c     | 178 ++++++++++-
>  drivers/net/ethernet/intel/ice/ice_flow.h     |  17 +
>  8 files changed, 727 insertions(+), 79 deletions(-)
>  create mode 100644 drivers/net/ethernet/intel/ice/ice_acl_main.c
>
> diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
> index 0747976622cf..36a787b5ad8d 100644
> --- a/drivers/net/ethernet/intel/ice/Makefile
> +++ b/drivers/net/ethernet/intel/ice/Makefile
> @@ -20,6 +20,7 @@ ice-y := ice_main.o   \
>          ice_fltr.o     \
>          ice_fdir.o     \
>          ice_ethtool_fdir.o \
> +        ice_acl_main.o \
>          ice_acl.o      \
>          ice_acl_ctrl.o \
>          ice_flex_pipe.o \
> diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
> index 1008a6785e55..d813a5c765d0 100644
> --- a/drivers/net/ethernet/intel/ice/ice.h
> +++ b/drivers/net/ethernet/intel/ice/ice.h
> @@ -601,16 +601,25 @@ int ice_del_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd);
>  int ice_get_ethtool_fdir_entry(struct ice_hw *hw, struct ethtool_rxnfc *cmd);
>  u32 ice_ntuple_get_max_fltr_cnt(struct ice_hw *hw);
>  int
> +ice_ntuple_l4_proto_to_port(enum ice_flow_seg_hdr l4_proto,
> +                           enum ice_flow_field *src_port,
> +                           enum ice_flow_field *dst_port);
> +int ice_ntuple_check_ip4_seg(struct ethtool_tcpip4_spec *tcp_ip4_spec);
> +int ice_ntuple_check_ip4_usr_seg(struct ethtool_usrip4_spec *usr_ip4_spec);
> +int
>  ice_get_fdir_fltr_ids(struct ice_hw *hw, struct ethtool_rxnfc *cmd,
>                       u32 *rule_locs);
>  void ice_fdir_release_flows(struct ice_hw *hw);
>  void ice_fdir_replay_flows(struct ice_hw *hw);
>  void ice_fdir_replay_fltrs(struct ice_pf *pf);
>  int ice_fdir_create_dflt_rules(struct ice_pf *pf);
> +enum ice_fltr_ptype ice_ethtool_flow_to_fltr(int eth);
>  int ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout,
>                           struct ice_rq_event_info *event);
>  int ice_open(struct net_device *netdev);
>  int ice_stop(struct net_device *netdev);
>  void ice_service_task_schedule(struct ice_pf *pf);
> +int
> +ice_acl_add_rule_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd);
>
>  #endif /* _ICE_H_ */
> diff --git a/drivers/net/ethernet/intel/ice/ice_acl_main.c b/drivers/net/ethernet/intel/ice/ice_acl_main.c
> new file mode 100644
> index 000000000000..be97dfb94652
> --- /dev/null
> +++ b/drivers/net/ethernet/intel/ice/ice_acl_main.c
> @@ -0,0 +1,260 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (C) 2018-2020, Intel Corporation. */
> +
> +/* ACL support for ice */
> +
> +#include "ice.h"
> +#include "ice_lib.h"
> +
> +/* Number of action */
> +#define ICE_ACL_NUM_ACT                1
> +
> +/**
> + * ice_acl_set_ip4_addr_seg
> + * @seg: flow segment for programming
> + *
> + * Set the IPv4 source and destination address mask for the given flow segment
> + */
> +static void ice_acl_set_ip4_addr_seg(struct ice_flow_seg_info *seg)
> +{
> +       u16 val_loc, mask_loc;
> +
> +       /* IP source address */
> +       val_loc = offsetof(struct ice_fdir_fltr, ip.v4.src_ip);
> +       mask_loc = offsetof(struct ice_fdir_fltr, mask.v4.src_ip);
> +
> +       ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_SA, val_loc,
> +                        mask_loc, ICE_FLOW_FLD_OFF_INVAL, false);
> +
> +       /* IP destination address */
> +       val_loc = offsetof(struct ice_fdir_fltr, ip.v4.dst_ip);
> +       mask_loc = offsetof(struct ice_fdir_fltr, mask.v4.dst_ip);
> +
> +       ice_flow_set_fld(seg, ICE_FLOW_FIELD_IDX_IPV4_DA, val_loc,
> +                        mask_loc, ICE_FLOW_FLD_OFF_INVAL, false);
> +}
> +
> +/**
> + * ice_acl_set_ip4_port_seg
> + * @seg: flow segment for programming
> + * @l4_proto: Layer 4 protocol to program
> + *
> + * Set the source and destination port for the given flow segment based on the
> + * provided layer 4 protocol
> + */
> +static int
> +ice_acl_set_ip4_port_seg(struct ice_flow_seg_info *seg,
> +                        enum ice_flow_seg_hdr l4_proto)
> +{
> +       enum ice_flow_field src_port, dst_port;
> +       u16 val_loc, mask_loc;
> +       int err;
> +
> +       err = ice_ntuple_l4_proto_to_port(l4_proto, &src_port, &dst_port);
> +       if (err)
> +               return err;
> +
> +       /* Layer 4 source port */
> +       val_loc = offsetof(struct ice_fdir_fltr, ip.v4.src_port);
> +       mask_loc = offsetof(struct ice_fdir_fltr, mask.v4.src_port);
> +
> +       ice_flow_set_fld(seg, src_port, val_loc, mask_loc,
> +                        ICE_FLOW_FLD_OFF_INVAL, false);
> +
> +       /* Layer 4 destination port */
> +       val_loc = offsetof(struct ice_fdir_fltr, ip.v4.dst_port);
> +       mask_loc = offsetof(struct ice_fdir_fltr, mask.v4.dst_port);
> +
> +       ice_flow_set_fld(seg, dst_port, val_loc, mask_loc,
> +                        ICE_FLOW_FLD_OFF_INVAL, false);
> +
> +       return 0;
> +}
> +
> +/**
> + * ice_acl_set_ip4_seg
> + * @seg: flow segment for programming
> + * @tcp_ip4_spec: mask data from ethtool
> + * @l4_proto: Layer 4 protocol to program
> + *
> + * Set the mask data into the flow segment to be used to program HW
> + * table based on provided L4 protocol for IPv4
> + */
> +static int
> +ice_acl_set_ip4_seg(struct ice_flow_seg_info *seg,
> +                   struct ethtool_tcpip4_spec *tcp_ip4_spec,
> +                   enum ice_flow_seg_hdr l4_proto)
> +{
> +       int err;
> +
> +       if (!seg)
> +               return -EINVAL;
> +

Unnecessary NULL pointer check. This is a static function and all
callers check the value before calling this function. You would likely
be better off just letting a NULL pointer dereference catch this.

> +       err = ice_ntuple_check_ip4_seg(tcp_ip4_spec);
> +       if (err)
> +               return err;
> +
> +       ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 | l4_proto);
> +       ice_acl_set_ip4_addr_seg(seg);
> +
> +       return ice_acl_set_ip4_port_seg(seg, l4_proto);
> +}
> +
> +/**
> + * ice_acl_set_ip4_usr_seg
> + * @seg: flow segment for programming
> + * @usr_ip4_spec: ethtool userdef packet offset
> + *
> + * Set the offset data into the flow segment to be used to program HW
> + * table for IPv4
> + */
> +static int
> +ice_acl_set_ip4_usr_seg(struct ice_flow_seg_info *seg,
> +                       struct ethtool_usrip4_spec *usr_ip4_spec)
> +{
> +       int err;
> +
> +       if (!seg)
> +               return -EINVAL;
> +

and here..

> +       err = ice_ntuple_check_ip4_usr_seg(usr_ip4_spec);
> +       if (err)
> +               return err;
> +
> +       ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4);
> +       ice_acl_set_ip4_addr_seg(seg);
> +
> +       return 0;
> +}
> +
> +/**
> + * ice_acl_check_input_set - Checks that a given ACL input set is valid
> + * @pf: ice PF structure
> + * @fsp: pointer to ethtool Rx flow specification
> + *
> + * Returns 0 on success and negative values for failure
> + */
> +static int
> +ice_acl_check_input_set(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp)
> +{
> +       struct ice_fd_hw_prof *hw_prof = NULL;
> +       struct ice_flow_prof *prof = NULL;
> +       struct ice_flow_seg_info *old_seg;
> +       struct ice_flow_seg_info *seg;
> +       enum ice_fltr_ptype fltr_type;
> +       struct ice_hw *hw = &pf->hw;
> +       enum ice_status status;
> +       struct device *dev;
> +       int err;
> +
> +       if (!fsp)
> +               return -EINVAL;
> +

and here...

> +       dev = ice_pf_to_dev(pf);
> +       seg = devm_kzalloc(dev, sizeof(*seg), GFP_KERNEL);
> +       if (!seg)
> +               return -ENOMEM;
> +

This check of seg covers the next 4 functions. So all of the functions
you call out below don't need to check for seg being NULL as you
already did it here.

> +       switch (fsp->flow_type & ~FLOW_EXT) {
> +       case TCP_V4_FLOW:
> +               err = ice_acl_set_ip4_seg(seg, &fsp->m_u.tcp_ip4_spec,
> +                                         ICE_FLOW_SEG_HDR_TCP);
> +               break;
> +       case UDP_V4_FLOW:
> +               err = ice_acl_set_ip4_seg(seg, &fsp->m_u.tcp_ip4_spec,
> +                                         ICE_FLOW_SEG_HDR_UDP);
> +               break;
> +       case SCTP_V4_FLOW:
> +               err = ice_acl_set_ip4_seg(seg, &fsp->m_u.tcp_ip4_spec,
> +                                         ICE_FLOW_SEG_HDR_SCTP);
> +               break;
> +       case IPV4_USER_FLOW:
> +               err = ice_acl_set_ip4_usr_seg(seg, &fsp->m_u.usr_ip4_spec);
> +               break;
> +       default:
> +               err = -EOPNOTSUPP;
> +       }
> +       if (err)
> +               goto err_exit;
> +
> +       fltr_type = ice_ethtool_flow_to_fltr(fsp->flow_type & ~FLOW_EXT);
> +
> +       if (!hw->acl_prof) {
> +               hw->acl_prof = devm_kcalloc(dev, ICE_FLTR_PTYPE_MAX,
> +                                           sizeof(*hw->acl_prof), GFP_KERNEL);
> +               if (!hw->acl_prof) {
> +                       err = -ENOMEM;
> +                       goto err_exit;
> +               }
> +       }
> +       if (!hw->acl_prof[fltr_type]) {
> +               hw->acl_prof[fltr_type] = devm_kzalloc(dev,
> +                                                      sizeof(**hw->acl_prof),
> +                                                      GFP_KERNEL);
> +               if (!hw->acl_prof[fltr_type]) {
> +                       err = -ENOMEM;
> +                       goto err_acl_prof_exit;
> +               }
> +               hw->acl_prof[fltr_type]->cnt = 0;
> +       }
> +
> +       hw_prof = hw->acl_prof[fltr_type];
> +       old_seg = hw_prof->fdir_seg[0];
> +       if (old_seg) {
> +               /* This flow_type already has an input set.
> +                * If it matches the requested input set then we are
> +                * done. If it's different then it's an error.
> +                */
> +               if (!memcmp(old_seg, seg, sizeof(*seg))) {
> +                       devm_kfree(dev, seg);
> +                       return 0;
> +               }
> +
> +               err = -EINVAL;
> +               goto err_acl_prof_flow_exit;
> +       }
> +
> +       /* Adding a profile for the given flow specification with no
> +        * actions (NULL) and zero actions 0.
> +        */
> +       status = ice_flow_add_prof(hw, ICE_BLK_ACL, ICE_FLOW_RX, fltr_type,
> +                                  seg, 1, &prof);
> +       if (status) {
> +               err = ice_status_to_errno(status);
> +               goto err_exit;
> +       }
> +
> +       hw_prof->fdir_seg[0] = seg;
> +       return 0;
> +
> +err_acl_prof_flow_exit:
> +       devm_kfree(dev, hw->acl_prof[fltr_type]);
> +err_acl_prof_exit:
> +       devm_kfree(dev, hw->acl_prof);
> +err_exit:
> +       devm_kfree(dev, seg);
> +
> +       return err;
> +}
> +
> +/**
> + * ice_acl_add_rule_ethtool - Adds an ACL rule
> + * @vsi: pointer to target VSI
> + * @cmd: command to add or delete ACL rule
> + *
> + * Returns 0 on success and negative values for failure
> + */
> +int ice_acl_add_rule_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
> +{
> +       struct ethtool_rx_flow_spec *fsp;
> +       struct ice_pf *pf;
> +
> +       if (!vsi || !cmd)
> +               return -EINVAL;
> +

This is unneeded. The one caller of this has already referenced cmd
and vsi in multiple spots so this is a redundant check.

Actually there are so many redundant NULL pointer checks throughout I
would suggest going through and everywhere where the function starts
with one of these checks you should evaluate if you really need it or
not, rather than me going through and calling out all of them.

<snip>

> +       ret = ice_ntuple_check_ip6_usr_seg(usr_ip6_spec);
> +       if (ret)
> +               return ret;
> +
>         *perfect_fltr = true;
>         ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6);
>
> @@ -1489,6 +1583,64 @@ int ice_del_ntuple_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
>         return val;
>  }
>
> +/**
> + * ice_is_acl_filter - Checks if it's a FD or ACL filter
> + * @fsp: pointer to ethtool Rx flow specification
> + *
> + * If any field of the provided filter is using a partial mask then this is
> + * an ACL filter.
> + *

I'm not sure this logic is correct. Can the flow director rules handle
a field that is removed? Last I knew it couldn't. If that is the case
you should be using ACL for any case in which a full mask is not
provided. So in your tests below you could probably drop the check for
zero as I don't think that is a valid case in which flow director
would work.

> + * Returns true if ACL filter otherwise false.
> + */
> +static bool ice_is_acl_filter(struct ethtool_rx_flow_spec *fsp)
> +{
> +       struct ethtool_tcpip4_spec *tcp_ip4_spec;
> +       struct ethtool_usrip4_spec *usr_ip4_spec;
> +
> +       switch (fsp->flow_type & ~FLOW_EXT) {
> +       case TCP_V4_FLOW:
> +       case UDP_V4_FLOW:
> +       case SCTP_V4_FLOW:
> +               tcp_ip4_spec = &fsp->m_u.tcp_ip4_spec;
> +
> +               /* IP source address */
> +               if (tcp_ip4_spec->ip4src &&
> +                   tcp_ip4_spec->ip4src != htonl(0xFFFFFFFF))
> +                       return true;
> +
> +               /* IP destination address */
> +               if (tcp_ip4_spec->ip4dst &&
> +                   tcp_ip4_spec->ip4dst != htonl(0xFFFFFFFF))
> +                       return true;
> +

Instead of testing this up here you could just skip the break and fall
through since the source and destination IP addresses occupy the same
spots on usr_ip4_spec and tcp_ip4_spec. You could probably also just
use tcp_ip4_spec for the entire test.

> +               /* Layer 4 source port */
> +               if (tcp_ip4_spec->psrc && tcp_ip4_spec->psrc != htons(0xFFFF))
> +                       return true;
> +
> +               /* Layer 4 destination port */
> +               if (tcp_ip4_spec->pdst && tcp_ip4_spec->pdst != htons(0xFFFF))
> +                       return true;
> +
> +               break;
> +       case IPV4_USER_FLOW:
> +               usr_ip4_spec = &fsp->m_u.usr_ip4_spec;
> +
> +               /* IP source address */
> +               if (usr_ip4_spec->ip4src &&
> +                   usr_ip4_spec->ip4src != htonl(0xFFFFFFFF))
> +                       return true;
> +
> +               /* IP destination address */
> +               if (usr_ip4_spec->ip4dst &&
> +                   usr_ip4_spec->ip4dst != htonl(0xFFFFFFFF))
> +                       return true;
> +
> +               break;
> +       }
> +
> +       return false;
> +}
> +

  reply	other threads:[~2020-11-13 23:56 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-13 21:44 [net-next v3 00/15][pull request] 100GbE Intel Wired LAN Driver Updates 2020-11-13 Tony Nguyen
2020-11-13 21:44 ` [net-next v3 01/15] ice: cleanup stack hog Tony Nguyen
2020-11-13 21:44 ` [net-next v3 02/15] ice: rename shared Flow Director functions Tony Nguyen
2020-11-13 21:44 ` [net-next v3 03/15] ice: initialize ACL table Tony Nguyen
2020-11-13 21:44 ` [net-next v3 04/15] ice: initialize ACL scenario Tony Nguyen
2020-11-13 21:44 ` [net-next v3 05/15] ice: create flow profile Tony Nguyen
2020-11-13 23:56   ` Alexander Duyck [this message]
2020-11-21  0:42     ` Nguyen, Anthony L
2020-11-21  1:49       ` Alexander Duyck
2020-11-23 23:21         ` Jesse Brandeburg
2020-11-24  1:11           ` Alexander Duyck
2020-12-08 16:58             ` Nguyen, Anthony L
2020-12-08 19:00               ` Alexander Duyck
2020-12-08 22:01                 ` Nguyen, Anthony L
2020-12-08 22:22                   ` Alexander Duyck
2020-12-09 18:23                     ` Nguyen, Anthony L
2020-11-13 21:44 ` [net-next v3 06/15] ice: create ACL entry Tony Nguyen
2020-11-13 21:44 ` [net-next v3 07/15] ice: program " Tony Nguyen
2020-11-13 21:44 ` [net-next v3 08/15] ice: don't always return an error for Get PHY Abilities AQ command Tony Nguyen
2020-11-14  1:25   ` Alexander Duyck
2020-11-21  0:43     ` Nguyen, Anthony L
2020-11-13 21:44 ` [net-next v3 09/15] ice: Enable Support for FW Override (E82X) Tony Nguyen
2020-11-13 21:44 ` [net-next v3 10/15] ice: Remove gate to OROM init Tony Nguyen
2020-11-13 21:44 ` [net-next v3 11/15] ice: Remove vlan_ena from vsi structure Tony Nguyen
2020-11-13 21:44 ` [net-next v3 12/15] ice: cleanup misleading comment Tony Nguyen
2020-11-13 21:44 ` [net-next v3 13/15] ice: silence static analysis warning Tony Nguyen
2020-11-13 21:44 ` [net-next v3 14/15] ice: join format strings to same line as ice_debug Tony Nguyen
2020-11-13 21:44 ` [net-next v3 15/15] ice: Add space to unknown speed Tony Nguyen

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='CAKgT0UeQ5q2M-uiR0-1G=30syPiO8S5OFHvDuN1XtQg5700hCg@mail.gmail.com' \
    --to=alexander.duyck@gmail.com \
    --cc=anthony.l.nguyen@intel.com \
    --cc=brijeshx.behera@intel.com \
    --cc=chinh.t.cao@intel.com \
    --cc=davem@davemloft.net \
    --cc=kuba@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=real.valiquette@intel.com \
    --cc=sassmann@redhat.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).