Netdev List
 help / color / mirror / Atom feed
* [PATCH bpf-next] bpf: libbpf: retry program creation without the name
From: Stanislav Fomichev @ 2018-11-20  0:46 UTC (permalink / raw)
  To: netdev, daniel; +Cc: ast, vladum, Stanislav Fomichev

[Recent commit 23499442c319 ("bpf: libbpf: retry map creation without
the name") fixed this issue for maps, let's do the same for programs.]

Since commit 88cda1c9da02 ("bpf: libbpf: Provide basic API support
to specify BPF obj name"), libbpf unconditionally sets bpf_attr->name
for programs. Pre v4.14 kernels don't know about programs names and
return an error about unexpected non-zero data. Retry sys_bpf without
a program name to cover older kernels.

Signed-off-by: Stanislav Fomichev <sdf@google.com>
---
 tools/lib/bpf/bpf.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 961e1b9fc592..cbe9d757c646 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -212,6 +212,16 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
 	if (fd >= 0 || !log_buf || !log_buf_sz)
 		return fd;
 
+	if (fd < 0 && errno == E2BIG && load_attr->name) {
+		/* Retry the same syscall, but without the name.
+		 * Pre v4.14 kernels don't support prog names.
+		 */
+		memset(attr.prog_name, 0, sizeof(attr.prog_name));
+		fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
+		if (fd >= 0 || !log_buf || !log_buf_sz)
+			return fd;
+	}
+
 	/* Try again with log */
 	attr.log_buf = ptr_to_u64(log_buf);
 	attr.log_size = log_buf_sz;
-- 
2.19.1.1215.g8438c0b245-goog

^ permalink raw reply related

* Re: Guidance required for a crypto requirement
From: gregkh @ 2018-11-20 11:14 UTC (permalink / raw)
  To: Kalyani Akula
  Cc: davem@davemloft.net, kstewart@linuxfoundation.org,
	tglx@linutronix.de, pombredanne@nexb.com,
	linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org,
	netdev@vger.kernel.org, Herbert Xu, Sarat Chand Savitala,
	Mohan Marutirao Dhanawade
In-Reply-To: <BN7PR02MB512445D1DCE200B9B6D6ECD1AFD90@BN7PR02MB5124.namprd02.prod.outlook.com>

On Tue, Nov 20, 2018 at 10:30:56AM +0000, Kalyani Akula wrote:
> This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

Now deleted, sorry.

^ permalink raw reply

* Re: [PATCH 0/3] Fix unsafe BPF_PROG_TEST_RUN interface
From: Daniel Borkmann @ 2018-11-20  0:34 UTC (permalink / raw)
  To: Lorenz Bauer, ys114321; +Cc: Alexei Starovoitov, netdev, linux-api
In-Reply-To: <CACAyw98fu_=WufBrv_7CwO4iJj3jhOu1n6b3Pr0aZxqSk8++Gw@mail.gmail.com>

On 11/19/2018 03:30 PM, Lorenz Bauer wrote:
> On Sun, 18 Nov 2018 at 06:13, Y Song <ys114321@gmail.com> wrote:
>>
>> There is a slight change of user space behavior for this patch.
>> Without this patch, the value bpf_attr.test.data_size_out is output only.
>> For example,
>>    output buffer : out_buf (user allocated size 10)
>>    data_size_out is a random value (e.g., 1),
>>
>> The actual data to copy is 5.
>>
>> In today's implementation, the kernel will copy 5 and set data_size_out is 5.
>>
>> With this patch, the kernel will copy 1 and set data_size_out is 5.
>>
>> I am not 100% sure at this time whether we CAN overload data_size_out
>> since it MAY break existing applications.
> 
> Yes, that's correct. I think that the likelihood of this is low. It would
> affect code that uses bpf_attr without zeroing it first. I had a look around,
> and I could only find code that would keep working:

Agree, it seems like this would be rather unlikely to break the old behavior
and only if some test app forgot to zero it (given data_size_out is also in
the middle and not at the end). I'd rather prefer this approach here and then
push the patch via stable than adding yet another data_size_out-like member.

I think it also makes sense to return a -ENOSPC as Yonghong suggested in order
to indicate to user space that the buffer is not sufficient. Right now this
would have no such indication to the user so it would not be possible to
distinguish whether truncation or not happened. Was thinking whether it makes
sense to indicate through a new flag member that buffer truncation happened,
but I do like -ENOSPC better.

Thanks,
Daniel

^ permalink raw reply

* Re: [PATCH v2] net-next/hinic: add checksum offload and TSO support
From: dann frazier @ 2018-11-20  0:29 UTC (permalink / raw)
  To: Xue Chaojing
  Cc: davem, linux-kernel, netdev, wulike1, chiqijun, fy.wang,
	zhaochen6, tony.qu, luoshaokai, ike.pan
In-Reply-To: <20181018150251.28802-1-xuechaojing@huawei.com>

On Thu, Oct 18, 2018 at 03:02:51PM +0000, Xue Chaojing wrote:
> From: Zhao Chen <zhaochen6@huawei.com>
> 
> This patch adds checksum offload and TSO support for the HiNIC
> driver. Perfomance test (Iperf) shows more than 100% improvement
> in TCP streams.

We're seeing a regression with this patch on the HiSilicon D06
platform (only platform we've tested). With 4.20-rc3, we do see
improved performance initially (~10s), but if we do a longer iperf run
- we're testing w/ 900s - performance drop significantly to around
200Mbps. Correlated with this drop are a flood of messages like:

   [ 1070.047048] ITS queue timeout (65440 65504 1120)
   [ 1070.051658] ITS cmd its_build_inv_cmd failed

I don't know if that's an issue with the patch or a platform issue it
happens to tickle.

  -dann

> Signed-off-by: Zhao Chen <zhaochen6@huawei.com>
> Signed-off-by: Xue Chaojing <xuechaojing@huawei.com>
> ---
> v2: made all the local variables from longest to shortest line.
> 
>  .../net/ethernet/huawei/hinic/hinic_hw_dev.h  |   2 +
>  .../net/ethernet/huawei/hinic/hinic_hw_qp.c   | 121 +++++--
>  .../net/ethernet/huawei/hinic/hinic_hw_qp.h   |  27 ++
>  .../net/ethernet/huawei/hinic/hinic_hw_wq.c   |  14 +
>  .../net/ethernet/huawei/hinic/hinic_hw_wq.h   |   2 +
>  .../net/ethernet/huawei/hinic/hinic_hw_wqe.h  |  97 ++++--
>  .../net/ethernet/huawei/hinic/hinic_main.c    |  23 +-
>  .../net/ethernet/huawei/hinic/hinic_port.c    |  32 ++
>  .../net/ethernet/huawei/hinic/hinic_port.h    |  18 ++
>  drivers/net/ethernet/huawei/hinic/hinic_tx.c  | 295 +++++++++++++++++-
>  10 files changed, 571 insertions(+), 60 deletions(-)
> 
> diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
> index 0f5563f3b779..097b5502603f 100644
> --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
> +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
> @@ -58,6 +58,8 @@ enum hinic_port_cmd {
>  
>  	HINIC_PORT_CMD_GET_GLOBAL_QPN   = 102,
>  
> +	HINIC_PORT_CMD_SET_TSO          = 112,
> +
>  	HINIC_PORT_CMD_GET_CAP          = 170,
>  };
>  
> diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
> index cb239627770f..967c993d5303 100644
> --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
> +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c
> @@ -70,8 +70,6 @@
>  #define SQ_MASKED_IDX(sq, idx)  ((idx) & (sq)->wq->mask)
>  #define RQ_MASKED_IDX(rq, idx)  ((idx) & (rq)->wq->mask)
>  
> -#define TX_MAX_MSS_DEFAULT      0x3E00
> -
>  enum sq_wqe_type {
>  	SQ_NORMAL_WQE = 0,
>  };
> @@ -494,33 +492,16 @@ static void sq_prepare_ctrl(struct hinic_sq_ctrl *ctrl, u16 prod_idx,
>  			  HINIC_SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT)     |
>  			  HINIC_SQ_CTRL_SET(ctrl_size, LEN);
>  
> -	ctrl->queue_info = HINIC_SQ_CTRL_SET(TX_MAX_MSS_DEFAULT,
> -					     QUEUE_INFO_MSS);
> +	ctrl->queue_info = HINIC_SQ_CTRL_SET(HINIC_MSS_DEFAULT,
> +					     QUEUE_INFO_MSS) |
> +			   HINIC_SQ_CTRL_SET(1, QUEUE_INFO_UC);
>  }
>  
>  static void sq_prepare_task(struct hinic_sq_task *task)
>  {
> -	task->pkt_info0 =
> -		HINIC_SQ_TASK_INFO0_SET(0, L2HDR_LEN) |
> -		HINIC_SQ_TASK_INFO0_SET(HINIC_L4_OFF_DISABLE, L4_OFFLOAD) |
> -		HINIC_SQ_TASK_INFO0_SET(HINIC_OUTER_L3TYPE_UNKNOWN,
> -					INNER_L3TYPE) |
> -		HINIC_SQ_TASK_INFO0_SET(HINIC_VLAN_OFF_DISABLE,
> -					VLAN_OFFLOAD) |
> -		HINIC_SQ_TASK_INFO0_SET(HINIC_PKT_NOT_PARSED, PARSE_FLAG);
> -
> -	task->pkt_info1 =
> -		HINIC_SQ_TASK_INFO1_SET(HINIC_MEDIA_UNKNOWN, MEDIA_TYPE) |
> -		HINIC_SQ_TASK_INFO1_SET(0, INNER_L4_LEN) |
> -		HINIC_SQ_TASK_INFO1_SET(0, INNER_L3_LEN);
> -
> -	task->pkt_info2 =
> -		HINIC_SQ_TASK_INFO2_SET(0, TUNNEL_L4_LEN) |
> -		HINIC_SQ_TASK_INFO2_SET(0, OUTER_L3_LEN)  |
> -		HINIC_SQ_TASK_INFO2_SET(HINIC_TUNNEL_L4TYPE_UNKNOWN,
> -					TUNNEL_L4TYPE)    |
> -		HINIC_SQ_TASK_INFO2_SET(HINIC_OUTER_L3TYPE_UNKNOWN,
> -					OUTER_L3TYPE);
> +	task->pkt_info0 = 0;
> +	task->pkt_info1 = 0;
> +	task->pkt_info2 = 0;
>  
>  	task->ufo_v6_identify = 0;
>  
> @@ -529,6 +510,86 @@ static void sq_prepare_task(struct hinic_sq_task *task)
>  	task->zero_pad = 0;
>  }
>  
> +void hinic_task_set_l2hdr(struct hinic_sq_task *task, u32 len)
> +{
> +	task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(len, L2HDR_LEN);
> +}
> +
> +void hinic_task_set_outter_l3(struct hinic_sq_task *task,
> +			      enum hinic_l3_offload_type l3_type,
> +			      u32 network_len)
> +{
> +	task->pkt_info2 |= HINIC_SQ_TASK_INFO2_SET(l3_type, OUTER_L3TYPE) |
> +			   HINIC_SQ_TASK_INFO2_SET(network_len, OUTER_L3LEN);
> +}
> +
> +void hinic_task_set_inner_l3(struct hinic_sq_task *task,
> +			     enum hinic_l3_offload_type l3_type,
> +			     u32 network_len)
> +{
> +	task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l3_type, INNER_L3TYPE);
> +	task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(network_len, INNER_L3LEN);
> +}
> +
> +void hinic_task_set_tunnel_l4(struct hinic_sq_task *task,
> +			      enum hinic_l4_offload_type l4_type,
> +			      u32 tunnel_len)
> +{
> +	task->pkt_info2 |= HINIC_SQ_TASK_INFO2_SET(l4_type, TUNNEL_L4TYPE) |
> +			   HINIC_SQ_TASK_INFO2_SET(tunnel_len, TUNNEL_L4LEN);
> +}
> +
> +void hinic_set_cs_inner_l4(struct hinic_sq_task *task, u32 *queue_info,
> +			   enum hinic_l4_offload_type l4_offload,
> +			   u32 l4_len, u32 offset)
> +{
> +	u32 tcp_udp_cs = 0, sctp = 0;
> +	u32 mss = HINIC_MSS_DEFAULT;
> +
> +	if (l4_offload == TCP_OFFLOAD_ENABLE ||
> +	    l4_offload == UDP_OFFLOAD_ENABLE)
> +		tcp_udp_cs = 1;
> +	else if (l4_offload == SCTP_OFFLOAD_ENABLE)
> +		sctp = 1;
> +
> +	task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l4_offload, L4_OFFLOAD);
> +	task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(l4_len, INNER_L4LEN);
> +
> +	*queue_info |= HINIC_SQ_CTRL_SET(offset, QUEUE_INFO_PLDOFF) |
> +		       HINIC_SQ_CTRL_SET(tcp_udp_cs, QUEUE_INFO_TCPUDP_CS) |
> +		       HINIC_SQ_CTRL_SET(sctp, QUEUE_INFO_SCTP);
> +
> +	*queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
> +	*queue_info |= HINIC_SQ_CTRL_SET(mss, QUEUE_INFO_MSS);
> +}
> +
> +void hinic_set_tso_inner_l4(struct hinic_sq_task *task, u32 *queue_info,
> +			    enum hinic_l4_offload_type l4_offload,
> +			    u32 l4_len, u32 offset, u32 ip_ident, u32 mss)
> +{
> +	u32 tso = 0, ufo = 0;
> +
> +	if (l4_offload == TCP_OFFLOAD_ENABLE)
> +		tso = 1;
> +	else if (l4_offload == UDP_OFFLOAD_ENABLE)
> +		ufo = 1;
> +
> +	task->ufo_v6_identify = ip_ident;
> +
> +	task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(l4_offload, L4_OFFLOAD);
> +	task->pkt_info0 |= HINIC_SQ_TASK_INFO0_SET(tso || ufo, TSO_FLAG);
> +	task->pkt_info1 |= HINIC_SQ_TASK_INFO1_SET(l4_len, INNER_L4LEN);
> +
> +	*queue_info |= HINIC_SQ_CTRL_SET(offset, QUEUE_INFO_PLDOFF) |
> +		       HINIC_SQ_CTRL_SET(tso, QUEUE_INFO_TSO) |
> +		       HINIC_SQ_CTRL_SET(ufo, QUEUE_INFO_UFO) |
> +		       HINIC_SQ_CTRL_SET(!!l4_offload, QUEUE_INFO_TCPUDP_CS);
> +
> +	/* set MSS value */
> +	*queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
> +	*queue_info |= HINIC_SQ_CTRL_SET(mss, QUEUE_INFO_MSS);
> +}
> +
>  /**
>   * hinic_sq_prepare_wqe - prepare wqe before insert to the queue
>   * @sq: send queue
> @@ -612,6 +673,16 @@ struct hinic_sq_wqe *hinic_sq_get_wqe(struct hinic_sq *sq,
>  	return &hw_wqe->sq_wqe;
>  }
>  
> +/**
> + * hinic_sq_return_wqe - return the wqe to the sq
> + * @sq: send queue
> + * @wqe_size: the size of the wqe
> + **/
> +void hinic_sq_return_wqe(struct hinic_sq *sq, unsigned int wqe_size)
> +{
> +	hinic_return_wqe(sq->wq, wqe_size);
> +}
> +
>  /**
>   * hinic_sq_write_wqe - write the wqe to the sq
>   * @sq: send queue
> diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
> index 6c84f83ec283..a0dc63a4bfc7 100644
> --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
> +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
> @@ -149,6 +149,31 @@ int hinic_get_sq_free_wqebbs(struct hinic_sq *sq);
>  
>  int hinic_get_rq_free_wqebbs(struct hinic_rq *rq);
>  
> +void hinic_task_set_l2hdr(struct hinic_sq_task *task, u32 len);
> +
> +void hinic_task_set_outter_l3(struct hinic_sq_task *task,
> +			      enum hinic_l3_offload_type l3_type,
> +			      u32 network_len);
> +
> +void hinic_task_set_inner_l3(struct hinic_sq_task *task,
> +			     enum hinic_l3_offload_type l3_type,
> +			     u32 network_len);
> +
> +void hinic_task_set_tunnel_l4(struct hinic_sq_task *task,
> +			      enum hinic_l4_offload_type l4_type,
> +			      u32 tunnel_len);
> +
> +void hinic_set_cs_inner_l4(struct hinic_sq_task *task,
> +			   u32 *queue_info,
> +			   enum hinic_l4_offload_type l4_offload,
> +			   u32 l4_len, u32 offset);
> +
> +void hinic_set_tso_inner_l4(struct hinic_sq_task *task,
> +			    u32 *queue_info,
> +			    enum hinic_l4_offload_type l4_offload,
> +			    u32 l4_len,
> +			    u32 offset, u32 ip_ident, u32 mss);
> +
>  void hinic_sq_prepare_wqe(struct hinic_sq *sq, u16 prod_idx,
>  			  struct hinic_sq_wqe *wqe, struct hinic_sge *sges,
>  			  int nr_sges);
> @@ -159,6 +184,8 @@ void hinic_sq_write_db(struct hinic_sq *sq, u16 prod_idx, unsigned int wqe_size,
>  struct hinic_sq_wqe *hinic_sq_get_wqe(struct hinic_sq *sq,
>  				      unsigned int wqe_size, u16 *prod_idx);
>  
> +void hinic_sq_return_wqe(struct hinic_sq *sq, unsigned int wqe_size);
> +
>  void hinic_sq_write_wqe(struct hinic_sq *sq, u16 prod_idx,
>  			struct hinic_sq_wqe *wqe, struct sk_buff *skb,
>  			unsigned int wqe_size);
> diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
> index 3e3181c089bd..f92f1bf3901a 100644
> --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
> +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c
> @@ -774,6 +774,20 @@ struct hinic_hw_wqe *hinic_get_wqe(struct hinic_wq *wq, unsigned int wqe_size,
>  	return WQ_PAGE_ADDR(wq, *prod_idx) + WQE_PAGE_OFF(wq, *prod_idx);
>  }
>  
> +/**
> + * hinic_return_wqe - return the wqe when transmit failed
> + * @wq: wq to return wqe
> + * @wqe_size: wqe size
> + **/
> +void hinic_return_wqe(struct hinic_wq *wq, unsigned int wqe_size)
> +{
> +	int num_wqebbs = ALIGN(wqe_size, wq->wqebb_size) / wq->wqebb_size;
> +
> +	atomic_sub(num_wqebbs, &wq->prod_idx);
> +
> +	atomic_add(num_wqebbs, &wq->delta);
> +}
> +
>  /**
>   * hinic_put_wqe - return the wqe place to use for a new wqe
>   * @wq: wq to return wqe
> diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h
> index 9c030a0f035e..9b66545ba563 100644
> --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h
> +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.h
> @@ -104,6 +104,8 @@ void hinic_wq_free(struct hinic_wqs *wqs, struct hinic_wq *wq);
>  struct hinic_hw_wqe *hinic_get_wqe(struct hinic_wq *wq, unsigned int wqe_size,
>  				   u16 *prod_idx);
>  
> +void hinic_return_wqe(struct hinic_wq *wq, unsigned int wqe_size);
> +
>  void hinic_put_wqe(struct hinic_wq *wq, unsigned int wqe_size);
>  
>  struct hinic_hw_wqe *hinic_read_wqe(struct hinic_wq *wq, unsigned int wqe_size,
> diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
> index bc73485483c5..9754d6ed5f4a 100644
> --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
> +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
> @@ -62,19 +62,33 @@
>  			(((val) >> HINIC_CMDQ_WQE_HEADER_##member##_SHIFT) \
>  			 & HINIC_CMDQ_WQE_HEADER_##member##_MASK)
>  
> -#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_SHIFT    0
> -#define HINIC_SQ_CTRL_TASKSECT_LEN_SHIFT        16
> -#define HINIC_SQ_CTRL_DATA_FORMAT_SHIFT         22
> -#define HINIC_SQ_CTRL_LEN_SHIFT                 29
> -
> -#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_MASK     0xFF
> -#define HINIC_SQ_CTRL_TASKSECT_LEN_MASK         0x1F
> -#define HINIC_SQ_CTRL_DATA_FORMAT_MASK          0x1
> -#define HINIC_SQ_CTRL_LEN_MASK                  0x3
> -
> -#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_SHIFT      13
> -
> -#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_MASK       0x3FFF
> +#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_SHIFT           0
> +#define HINIC_SQ_CTRL_TASKSECT_LEN_SHIFT               16
> +#define HINIC_SQ_CTRL_DATA_FORMAT_SHIFT                22
> +#define HINIC_SQ_CTRL_LEN_SHIFT                        29
> +
> +#define HINIC_SQ_CTRL_BUFDESC_SECT_LEN_MASK            0xFF
> +#define HINIC_SQ_CTRL_TASKSECT_LEN_MASK                0x1F
> +#define HINIC_SQ_CTRL_DATA_FORMAT_MASK                 0x1
> +#define HINIC_SQ_CTRL_LEN_MASK                         0x3
> +
> +#define HINIC_SQ_CTRL_QUEUE_INFO_PLDOFF_SHIFT          2
> +#define HINIC_SQ_CTRL_QUEUE_INFO_UFO_SHIFT             10
> +#define HINIC_SQ_CTRL_QUEUE_INFO_TSO_SHIFT             11
> +#define HINIC_SQ_CTRL_QUEUE_INFO_TCPUDP_CS_SHIFT       12
> +#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_SHIFT             13
> +#define HINIC_SQ_CTRL_QUEUE_INFO_SCTP_SHIFT            27
> +#define HINIC_SQ_CTRL_QUEUE_INFO_UC_SHIFT              28
> +#define HINIC_SQ_CTRL_QUEUE_INFO_PRI_SHIFT             29
> +
> +#define HINIC_SQ_CTRL_QUEUE_INFO_PLDOFF_MASK           0xFF
> +#define HINIC_SQ_CTRL_QUEUE_INFO_UFO_MASK              0x1
> +#define HINIC_SQ_CTRL_QUEUE_INFO_TSO_MASK              0x1
> +#define HINIC_SQ_CTRL_QUEUE_INFO_TCPUDP_CS_MASK	       0x1
> +#define HINIC_SQ_CTRL_QUEUE_INFO_MSS_MASK              0x3FFF
> +#define HINIC_SQ_CTRL_QUEUE_INFO_SCTP_MASK             0x1
> +#define HINIC_SQ_CTRL_QUEUE_INFO_UC_MASK               0x1
> +#define HINIC_SQ_CTRL_QUEUE_INFO_PRI_MASK              0x7
>  
>  #define HINIC_SQ_CTRL_SET(val, member)          \
>  		(((u32)(val) & HINIC_SQ_CTRL_##member##_MASK) \
> @@ -84,6 +98,10 @@
>  		(((val) >> HINIC_SQ_CTRL_##member##_SHIFT) \
>  		 & HINIC_SQ_CTRL_##member##_MASK)
>  
> +#define HINIC_SQ_CTRL_CLEAR(val, member)	\
> +		((u32)(val) & (~(HINIC_SQ_CTRL_##member##_MASK \
> +		 << HINIC_SQ_CTRL_##member##_SHIFT)))
> +
>  #define HINIC_SQ_TASK_INFO0_L2HDR_LEN_SHIFT     0
>  #define HINIC_SQ_TASK_INFO0_L4_OFFLOAD_SHIFT    8
>  #define HINIC_SQ_TASK_INFO0_INNER_L3TYPE_SHIFT  10
> @@ -108,28 +126,28 @@
>  
>  /* 8 bits reserved */
>  #define HINIC_SQ_TASK_INFO1_MEDIA_TYPE_SHIFT    8
> -#define HINIC_SQ_TASK_INFO1_INNER_L4_LEN_SHIFT  16
> -#define HINIC_SQ_TASK_INFO1_INNER_L3_LEN_SHIFT  24
> +#define HINIC_SQ_TASK_INFO1_INNER_L4LEN_SHIFT   16
> +#define HINIC_SQ_TASK_INFO1_INNER_L3LEN_SHIFT   24
>  
>  /* 8 bits reserved */
>  #define HINIC_SQ_TASK_INFO1_MEDIA_TYPE_MASK     0xFF
> -#define HINIC_SQ_TASK_INFO1_INNER_L4_LEN_MASK   0xFF
> -#define HINIC_SQ_TASK_INFO1_INNER_L3_LEN_MASK   0xFF
> +#define HINIC_SQ_TASK_INFO1_INNER_L4LEN_MASK    0xFF
> +#define HINIC_SQ_TASK_INFO1_INNER_L3LEN_MASK    0xFF
>  
>  #define HINIC_SQ_TASK_INFO1_SET(val, member)    \
>  		(((u32)(val) & HINIC_SQ_TASK_INFO1_##member##_MASK) <<  \
>  		 HINIC_SQ_TASK_INFO1_##member##_SHIFT)
>  
> -#define HINIC_SQ_TASK_INFO2_TUNNEL_L4_LEN_SHIFT 0
> -#define HINIC_SQ_TASK_INFO2_OUTER_L3_LEN_SHIFT  12
> -#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_SHIFT 19
> +#define HINIC_SQ_TASK_INFO2_TUNNEL_L4LEN_SHIFT  0
> +#define HINIC_SQ_TASK_INFO2_OUTER_L3LEN_SHIFT   8
> +#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_SHIFT 16
>  /* 1 bit reserved */
> -#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_SHIFT  22
> +#define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_SHIFT  24
>  /* 8 bits reserved */
>  
> -#define HINIC_SQ_TASK_INFO2_TUNNEL_L4_LEN_MASK  0xFFF
> -#define HINIC_SQ_TASK_INFO2_OUTER_L3_LEN_MASK   0x7F
> -#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_MASK  0x3
> +#define HINIC_SQ_TASK_INFO2_TUNNEL_L4LEN_MASK   0xFF
> +#define HINIC_SQ_TASK_INFO2_OUTER_L3LEN_MASK    0xFF
> +#define HINIC_SQ_TASK_INFO2_TUNNEL_L4TYPE_MASK  0x7
>  /* 1 bit reserved */
>  #define HINIC_SQ_TASK_INFO2_OUTER_L3TYPE_MASK   0x3
>  /* 8 bits reserved */
> @@ -187,12 +205,15 @@
>  		 sizeof(struct hinic_sq_task) + \
>  		 (nr_sges) * sizeof(struct hinic_sq_bufdesc))
>  
> -#define HINIC_SCMD_DATA_LEN             16
> +#define HINIC_SCMD_DATA_LEN                     16
> +
> +#define HINIC_MAX_SQ_BUFDESCS                   17
>  
> -#define HINIC_MAX_SQ_BUFDESCS           17
> +#define HINIC_SQ_WQE_MAX_SIZE                   320
> +#define HINIC_RQ_WQE_SIZE                       32
>  
> -#define HINIC_SQ_WQE_MAX_SIZE           320
> -#define HINIC_RQ_WQE_SIZE               32
> +#define HINIC_MSS_DEFAULT		        0x3E00
> +#define HINIC_MSS_MIN		                0x50
>  
>  enum hinic_l4offload_type {
>  	HINIC_L4_OFF_DISABLE            = 0,
> @@ -211,6 +232,26 @@ enum hinic_pkt_parsed {
>  	HINIC_PKT_PARSED     = 1,
>  };
>  
> +enum hinic_l3_offload_type {
> +	L3TYPE_UNKNOWN = 0,
> +	IPV6_PKT = 1,
> +	IPV4_PKT_NO_CHKSUM_OFFLOAD = 2,
> +	IPV4_PKT_WITH_CHKSUM_OFFLOAD = 3,
> +};
> +
> +enum hinic_l4_offload_type {
> +	OFFLOAD_DISABLE     = 0,
> +	TCP_OFFLOAD_ENABLE  = 1,
> +	SCTP_OFFLOAD_ENABLE = 2,
> +	UDP_OFFLOAD_ENABLE  = 3,
> +};
> +
> +enum hinic_l4_tunnel_type {
> +	NOT_TUNNEL,
> +	TUNNEL_UDP_NO_CSUM,
> +	TUNNEL_UDP_CSUM,
> +};
> +
>  enum hinic_outer_l3type {
>  	HINIC_OUTER_L3TYPE_UNKNOWN              = 0,
>  	HINIC_OUTER_L3TYPE_IPV6                 = 1,
> diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c
> index 4a8f82938ed5..fdf2bdb6b0d0 100644
> --- a/drivers/net/ethernet/huawei/hinic/hinic_main.c
> +++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c
> @@ -805,7 +805,8 @@ static const struct net_device_ops hinic_netdev_ops = {
>  
>  static void netdev_features_init(struct net_device *netdev)
>  {
> -	netdev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA;
> +	netdev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM |
> +			      NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6;
>  
>  	netdev->vlan_features = netdev->hw_features;
>  
> @@ -863,6 +864,20 @@ static void link_status_event_handler(void *handle, void *buf_in, u16 in_size,
>  	*out_size = sizeof(*ret_link_status);
>  }
>  
> +static int set_features(struct hinic_dev *nic_dev,
> +			netdev_features_t pre_features,
> +			netdev_features_t features, bool force_change)
> +{
> +	netdev_features_t changed = force_change ? ~0 : pre_features ^ features;
> +	int err = 0;
> +
> +	if (changed & NETIF_F_TSO)
> +		err = hinic_port_set_tso(nic_dev, (features & NETIF_F_TSO) ?
> +					 HINIC_TSO_ENABLE : HINIC_TSO_DISABLE);
> +
> +	return err;
> +}
> +
>  /**
>   * nic_dev_init - Initialize the NIC device
>   * @pdev: the NIC pci device
> @@ -963,7 +978,12 @@ static int nic_dev_init(struct pci_dev *pdev)
>  	hinic_hwdev_cb_register(nic_dev->hwdev, HINIC_MGMT_MSG_CMD_LINK_STATUS,
>  				nic_dev, link_status_event_handler);
>  
> +	err = set_features(nic_dev, 0, nic_dev->netdev->features, true);
> +	if (err)
> +		goto err_set_features;
> +
>  	SET_NETDEV_DEV(netdev, &pdev->dev);
> +
>  	err = register_netdev(netdev);
>  	if (err) {
>  		dev_err(&pdev->dev, "Failed to register netdev\n");
> @@ -973,6 +993,7 @@ static int nic_dev_init(struct pci_dev *pdev)
>  	return 0;
>  
>  err_reg_netdev:
> +err_set_features:
>  	hinic_hwdev_cb_unregister(nic_dev->hwdev,
>  				  HINIC_MGMT_MSG_CMD_LINK_STATUS);
>  	cancel_work_sync(&rx_mode_work->work);
> diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c
> index 4d4e3f05fb5f..7575a7d3bd9f 100644
> --- a/drivers/net/ethernet/huawei/hinic/hinic_port.c
> +++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c
> @@ -377,3 +377,35 @@ int hinic_port_get_cap(struct hinic_dev *nic_dev,
>  
>  	return 0;
>  }
> +
> +/**
> + * hinic_port_set_tso - set port tso configuration
> + * @nic_dev: nic device
> + * @state: the tso state to set
> + *
> + * Return 0 - Success, negative - Failure
> + **/
> +int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state)
> +{
> +	struct hinic_hwdev *hwdev = nic_dev->hwdev;
> +	struct hinic_hwif *hwif = hwdev->hwif;
> +	struct hinic_tso_config tso_cfg = {0};
> +	struct pci_dev *pdev = hwif->pdev;
> +	u16 out_size;
> +	int err;
> +
> +	tso_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
> +	tso_cfg.tso_en = state;
> +
> +	err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_TSO,
> +				 &tso_cfg, sizeof(tso_cfg),
> +				 &tso_cfg, &out_size);
> +	if (err || out_size != sizeof(tso_cfg) || tso_cfg.status) {
> +		dev_err(&pdev->dev,
> +			"Failed to set port tso, ret = %d\n",
> +			tso_cfg.status);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.h b/drivers/net/ethernet/huawei/hinic/hinic_port.h
> index 9404365195dd..f6e3220fe28f 100644
> --- a/drivers/net/ethernet/huawei/hinic/hinic_port.h
> +++ b/drivers/net/ethernet/huawei/hinic/hinic_port.h
> @@ -72,6 +72,11 @@ enum hinic_speed {
>  	HINIC_SPEED_UNKNOWN = 0xFF,
>  };
>  
> +enum hinic_tso_state {
> +	HINIC_TSO_DISABLE = 0,
> +	HINIC_TSO_ENABLE  = 1,
> +};
> +
>  struct hinic_port_mac_cmd {
>  	u8              status;
>  	u8              version;
> @@ -167,6 +172,17 @@ struct hinic_port_cap {
>  	u8      rsvd2[3];
>  };
>  
> +struct hinic_tso_config {
> +	u8	status;
> +	u8	version;
> +	u8	rsvd0[6];
> +
> +	u16	func_id;
> +	u16	rsvd1;
> +	u8	tso_en;
> +	u8	resv2[3];
> +};
> +
>  int hinic_port_add_mac(struct hinic_dev *nic_dev, const u8 *addr,
>  		       u16 vlan_id);
>  
> @@ -195,4 +211,6 @@ int hinic_port_set_func_state(struct hinic_dev *nic_dev,
>  int hinic_port_get_cap(struct hinic_dev *nic_dev,
>  		       struct hinic_port_cap *port_cap);
>  
> +int hinic_port_set_tso(struct hinic_dev *nic_dev, enum hinic_tso_state state);
> +
>  #endif
> diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c
> index c5fca0356c9c..11e73e67358d 100644
> --- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c
> +++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c
> @@ -26,6 +26,13 @@
>  #include <linux/skbuff.h>
>  #include <linux/smp.h>
>  #include <asm/byteorder.h>
> +#include <linux/ip.h>
> +#include <linux/tcp.h>
> +#include <linux/sctp.h>
> +#include <linux/ipv6.h>
> +#include <net/ipv6.h>
> +#include <net/checksum.h>
> +#include <net/ip6_checksum.h>
>  
>  #include "hinic_common.h"
>  #include "hinic_hw_if.h"
> @@ -45,9 +52,31 @@
>  #define CI_UPDATE_NO_PENDING            0
>  #define CI_UPDATE_NO_COALESC            0
>  
> -#define HW_CONS_IDX(sq)         be16_to_cpu(*(u16 *)((sq)->hw_ci_addr))
> +#define HW_CONS_IDX(sq)                 be16_to_cpu(*(u16 *)((sq)->hw_ci_addr))
>  
> -#define MIN_SKB_LEN             64
> +#define MIN_SKB_LEN                     17
> +
> +#define	MAX_PAYLOAD_OFFSET	        221
> +#define TRANSPORT_OFFSET(l4_hdr, skb)	((u32)((l4_hdr) - (skb)->data))
> +
> +union hinic_l3 {
> +	struct iphdr *v4;
> +	struct ipv6hdr *v6;
> +	unsigned char *hdr;
> +};
> +
> +union hinic_l4 {
> +	struct tcphdr *tcp;
> +	struct udphdr *udp;
> +	unsigned char *hdr;
> +};
> +
> +enum hinic_offload_type {
> +	TX_OFFLOAD_TSO     = BIT(0),
> +	TX_OFFLOAD_CSUM    = BIT(1),
> +	TX_OFFLOAD_VLAN    = BIT(2),
> +	TX_OFFLOAD_INVALID = BIT(3),
> +};
>  
>  /**
>   * hinic_txq_clean_stats - Clean the statistics of specific queue
> @@ -175,18 +204,263 @@ static void tx_unmap_skb(struct hinic_dev *nic_dev, struct sk_buff *skb,
>  			 DMA_TO_DEVICE);
>  }
>  
> +static void get_inner_l3_l4_type(struct sk_buff *skb, union hinic_l3 *ip,
> +				 union hinic_l4 *l4,
> +				 enum hinic_offload_type offload_type,
> +				 enum hinic_l3_offload_type *l3_type,
> +				 u8 *l4_proto)
> +{
> +	u8 *exthdr;
> +
> +	if (ip->v4->version == 4) {
> +		*l3_type = (offload_type == TX_OFFLOAD_CSUM) ?
> +			   IPV4_PKT_NO_CHKSUM_OFFLOAD :
> +			   IPV4_PKT_WITH_CHKSUM_OFFLOAD;
> +		*l4_proto = ip->v4->protocol;
> +	} else if (ip->v4->version == 6) {
> +		*l3_type = IPV6_PKT;
> +		exthdr = ip->hdr + sizeof(*ip->v6);
> +		*l4_proto = ip->v6->nexthdr;
> +		if (exthdr != l4->hdr) {
> +			int start = exthdr - skb->data;
> +			__be16 frag_off;
> +
> +			ipv6_skip_exthdr(skb, start, l4_proto, &frag_off);
> +		}
> +	} else {
> +		*l3_type = L3TYPE_UNKNOWN;
> +		*l4_proto = 0;
> +	}
> +}
> +
> +static void get_inner_l4_info(struct sk_buff *skb, union hinic_l4 *l4,
> +			      enum hinic_offload_type offload_type, u8 l4_proto,
> +			      enum hinic_l4_offload_type *l4_offload,
> +			      u32 *l4_len, u32 *offset)
> +{
> +	*l4_offload = OFFLOAD_DISABLE;
> +	*offset = 0;
> +	*l4_len = 0;
> +
> +	switch (l4_proto) {
> +	case IPPROTO_TCP:
> +		*l4_offload = TCP_OFFLOAD_ENABLE;
> +		/* doff in unit of 4B */
> +		*l4_len = l4->tcp->doff * 4;
> +		*offset = *l4_len + TRANSPORT_OFFSET(l4->hdr, skb);
> +		break;
> +
> +	case IPPROTO_UDP:
> +		*l4_offload = UDP_OFFLOAD_ENABLE;
> +		*l4_len = sizeof(struct udphdr);
> +		*offset = TRANSPORT_OFFSET(l4->hdr, skb);
> +		break;
> +
> +	case IPPROTO_SCTP:
> +		/* only csum offload support sctp */
> +		if (offload_type != TX_OFFLOAD_CSUM)
> +			break;
> +
> +		*l4_offload = SCTP_OFFLOAD_ENABLE;
> +		*l4_len = sizeof(struct sctphdr);
> +		*offset = TRANSPORT_OFFSET(l4->hdr, skb);
> +		break;
> +
> +	default:
> +		break;
> +	}
> +}
> +
> +static __sum16 csum_magic(union hinic_l3 *ip, unsigned short proto)
> +{
> +	return (ip->v4->version == 4) ?
> +		csum_tcpudp_magic(ip->v4->saddr, ip->v4->daddr, 0, proto, 0) :
> +		csum_ipv6_magic(&ip->v6->saddr, &ip->v6->daddr, 0, proto, 0);
> +}
> +
> +static int offload_tso(struct hinic_sq_task *task, u32 *queue_info,
> +		       struct sk_buff *skb)
> +{
> +	u32 offset, l4_len, ip_identify, network_hdr_len;
> +	enum hinic_l3_offload_type l3_offload;
> +	enum hinic_l4_offload_type l4_offload;
> +	union hinic_l3 ip;
> +	union hinic_l4 l4;
> +	u8 l4_proto;
> +
> +	if (!skb_is_gso(skb))
> +		return 0;
> +
> +	if (skb_cow_head(skb, 0) < 0)
> +		return -EPROTONOSUPPORT;
> +
> +	if (skb->encapsulation) {
> +		u32 gso_type = skb_shinfo(skb)->gso_type;
> +		u32 tunnel_type = 0;
> +		u32 l4_tunnel_len;
> +
> +		ip.hdr = skb_network_header(skb);
> +		l4.hdr = skb_transport_header(skb);
> +		network_hdr_len = skb_inner_network_header_len(skb);
> +
> +		if (ip.v4->version == 4) {
> +			ip.v4->tot_len = 0;
> +			l3_offload = IPV4_PKT_WITH_CHKSUM_OFFLOAD;
> +		} else if (ip.v4->version == 6) {
> +			l3_offload = IPV6_PKT;
> +		} else {
> +			l3_offload = 0;
> +		}
> +
> +		hinic_task_set_outter_l3(task, l3_offload,
> +					 skb_network_header_len(skb));
> +
> +		if (gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
> +			l4.udp->check = ~csum_magic(&ip, IPPROTO_UDP);
> +			tunnel_type = TUNNEL_UDP_CSUM;
> +		} else if (gso_type & SKB_GSO_UDP_TUNNEL) {
> +			tunnel_type = TUNNEL_UDP_NO_CSUM;
> +		}
> +
> +		l4_tunnel_len = skb_inner_network_offset(skb) -
> +				skb_transport_offset(skb);
> +		hinic_task_set_tunnel_l4(task, tunnel_type, l4_tunnel_len);
> +
> +		ip.hdr = skb_inner_network_header(skb);
> +		l4.hdr = skb_inner_transport_header(skb);
> +	} else {
> +		ip.hdr = skb_network_header(skb);
> +		l4.hdr = skb_transport_header(skb);
> +		network_hdr_len = skb_network_header_len(skb);
> +	}
> +
> +	/* initialize inner IP header fields */
> +	if (ip.v4->version == 4)
> +		ip.v4->tot_len = 0;
> +	else
> +		ip.v6->payload_len = 0;
> +
> +	get_inner_l3_l4_type(skb, &ip, &l4, TX_OFFLOAD_TSO, &l3_offload,
> +			     &l4_proto);
> +
> +	hinic_task_set_inner_l3(task, l3_offload, network_hdr_len);
> +
> +	ip_identify = 0;
> +	if (l4_proto == IPPROTO_TCP)
> +		l4.tcp->check = ~csum_magic(&ip, IPPROTO_TCP);
> +
> +	get_inner_l4_info(skb, &l4, TX_OFFLOAD_TSO, l4_proto, &l4_offload,
> +			  &l4_len, &offset);
> +
> +	hinic_set_tso_inner_l4(task, queue_info, l4_offload, l4_len, offset,
> +			       ip_identify, skb_shinfo(skb)->gso_size);
> +
> +	return 1;
> +}
> +
> +static int offload_csum(struct hinic_sq_task *task, u32 *queue_info,
> +			struct sk_buff *skb)
> +{
> +	enum hinic_l4_offload_type l4_offload;
> +	u32 offset, l4_len, network_hdr_len;
> +	enum hinic_l3_offload_type l3_type;
> +	union hinic_l3 ip;
> +	union hinic_l4 l4;
> +	u8 l4_proto;
> +
> +	if (skb->ip_summed != CHECKSUM_PARTIAL)
> +		return 0;
> +
> +	if (skb->encapsulation) {
> +		u32 l4_tunnel_len;
> +
> +		ip.hdr = skb_network_header(skb);
> +
> +		if (ip.v4->version == 4)
> +			l3_type = IPV4_PKT_NO_CHKSUM_OFFLOAD;
> +		else if (ip.v4->version == 6)
> +			l3_type = IPV6_PKT;
> +		else
> +			l3_type = L3TYPE_UNKNOWN;
> +
> +		hinic_task_set_outter_l3(task, l3_type,
> +					 skb_network_header_len(skb));
> +
> +		l4_tunnel_len = skb_inner_network_offset(skb) -
> +				skb_transport_offset(skb);
> +
> +		hinic_task_set_tunnel_l4(task, TUNNEL_UDP_NO_CSUM,
> +					 l4_tunnel_len);
> +
> +		ip.hdr = skb_inner_network_header(skb);
> +		l4.hdr = skb_inner_transport_header(skb);
> +		network_hdr_len = skb_inner_network_header_len(skb);
> +	} else {
> +		ip.hdr = skb_network_header(skb);
> +		l4.hdr = skb_transport_header(skb);
> +		network_hdr_len = skb_network_header_len(skb);
> +	}
> +
> +	get_inner_l3_l4_type(skb, &ip, &l4, TX_OFFLOAD_CSUM, &l3_type,
> +			     &l4_proto);
> +
> +	hinic_task_set_inner_l3(task, l3_type, network_hdr_len);
> +
> +	get_inner_l4_info(skb, &l4, TX_OFFLOAD_CSUM, l4_proto, &l4_offload,
> +			  &l4_len, &offset);
> +
> +	hinic_set_cs_inner_l4(task, queue_info, l4_offload, l4_len, offset);
> +
> +	return 1;
> +}
> +
> +static int hinic_tx_offload(struct sk_buff *skb, struct hinic_sq_task *task,
> +			    u32 *queue_info)
> +{
> +	enum hinic_offload_type offload = 0;
> +	int enabled;
> +
> +	enabled = offload_tso(task, queue_info, skb);
> +	if (enabled > 0) {
> +		offload |= TX_OFFLOAD_TSO;
> +	} else if (enabled == 0) {
> +		enabled = offload_csum(task, queue_info, skb);
> +		if (enabled)
> +			offload |= TX_OFFLOAD_CSUM;
> +	} else {
> +		return -EPROTONOSUPPORT;
> +	}
> +
> +	if (offload)
> +		hinic_task_set_l2hdr(task, skb_network_offset(skb));
> +
> +	/* payload offset should not more than 221 */
> +	if (HINIC_SQ_CTRL_GET(*queue_info, QUEUE_INFO_PLDOFF) >
> +	    MAX_PAYLOAD_OFFSET) {
> +		return -EPROTONOSUPPORT;
> +	}
> +
> +	/* mss should not less than 80 */
> +	if (HINIC_SQ_CTRL_GET(*queue_info, QUEUE_INFO_MSS) < HINIC_MSS_MIN) {
> +		*queue_info = HINIC_SQ_CTRL_CLEAR(*queue_info, QUEUE_INFO_MSS);
> +		*queue_info |= HINIC_SQ_CTRL_SET(HINIC_MSS_MIN, QUEUE_INFO_MSS);
> +	}
> +
> +	return 0;
> +}
> +
>  netdev_tx_t hinic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
>  {
>  	struct hinic_dev *nic_dev = netdev_priv(netdev);
> +	u16 prod_idx, q_id = skb->queue_mapping;
>  	struct netdev_queue *netdev_txq;
>  	int nr_sges, err = NETDEV_TX_OK;
>  	struct hinic_sq_wqe *sq_wqe;
>  	unsigned int wqe_size;
>  	struct hinic_txq *txq;
>  	struct hinic_qp *qp;
> -	u16 prod_idx;
>  
> -	txq = &nic_dev->txqs[skb->queue_mapping];
> +	txq = &nic_dev->txqs[q_id];
>  	qp = container_of(txq->sq, struct hinic_qp, sq);
>  
>  	if (skb->len < MIN_SKB_LEN) {
> @@ -236,15 +510,23 @@ netdev_tx_t hinic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
>  process_sq_wqe:
>  	hinic_sq_prepare_wqe(txq->sq, prod_idx, sq_wqe, txq->sges, nr_sges);
>  
> +	err = hinic_tx_offload(skb, &sq_wqe->task, &sq_wqe->ctrl.queue_info);
> +	if (err)
> +		goto offload_error;
> +
>  	hinic_sq_write_wqe(txq->sq, prod_idx, sq_wqe, skb, wqe_size);
>  
>  flush_skbs:
> -	netdev_txq = netdev_get_tx_queue(netdev, skb->queue_mapping);
> +	netdev_txq = netdev_get_tx_queue(netdev, q_id);
>  	if ((!skb->xmit_more) || (netif_xmit_stopped(netdev_txq)))
>  		hinic_sq_write_db(txq->sq, prod_idx, wqe_size, 0);
>  
>  	return err;
>  
> +offload_error:
> +	hinic_sq_return_wqe(txq->sq, wqe_size);
> +	tx_unmap_skb(nic_dev, skb, txq->sges);
> +
>  skb_error:
>  	dev_kfree_skb_any(skb);
>  
> @@ -252,7 +534,8 @@ netdev_tx_t hinic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
>  	u64_stats_update_begin(&txq->txq_stats.syncp);
>  	txq->txq_stats.tx_dropped++;
>  	u64_stats_update_end(&txq->txq_stats.syncp);
> -	return err;
> +
> +	return NETDEV_TX_OK;
>  }
>  
>  /**

^ permalink raw reply

* RE: [PATCH] bonding:avoid repeated display of same link status change
From: Manish Kumar Singh @ 2018-11-20 10:41 UTC (permalink / raw)
  To: Michal Kubecek, David Miller
  Cc: netdev, eric.dumazet, j.vosburgh, vfalico, andy, linux-kernel
In-Reply-To: <20181104194121.GA29914@unicorn.suse.cz>

> -----Original Message-----
> From: Michal Kubecek [mailto:mkubecek@suse.cz]
> Sent: 05 नवम्बर 2018 01:11
> To: David Miller
> Cc: Manish Kumar Singh; netdev@vger.kernel.org; eric.dumazet@gmail.com;
> j.vosburgh@gmail.com; vfalico@gmail.com; andy@greyhouse.net; linux-
> kernel@vger.kernel.org
> Subject: Re: [PATCH] bonding:avoid repeated display of same link status
> change
> 
> On Fri, Nov 02, 2018 at 11:31:38PM -0700, David Miller wrote:
> > From: mk.singh@oracle.com
> > Date: Wed, 31 Oct 2018 16:27:28 +0530
> >
> > > -			if (slave->delay) {
> > > +			if (slave->delay &&
> > > +			    !atomic64_read(&bond->rtnl_needed)) {
> >  ...
> > > +			    !atomic64_read(&bond->rtnl_needed)) {
> >  ...
> > > +			atomic64_set(&bond->rtnl_needed, 1);
> >  ...
> > > +		atomic64_set(&bond->rtnl_needed, 0);
> >  ...
> > > @@ -229,6 +229,7 @@ struct bonding {
> > >  	struct	 dentry *debug_dir;
> > >  #endif /* CONFIG_DEBUG_FS */
> > >  	struct rtnl_link_stats64 bond_stats;
> > > +	atomic64_t rtnl_needed;
> >
> > There is nothing "atomic" about a value that is only set and read.
> >
> > And using a full 64-bit value for something taking on only '0' and
> > '1' is unnecessary as well.
> 
> Part of the misunderstanding is caused by the fact that this is actually
> a v4 but not marked as such:
> 
>   v1: https://patchwork.ozlabs.org/patch/955789/
>   v2: https://patchwork.ozlabs.org/patch/970421/
>   v3: https://patchwork.ozlabs.org/patch/988241/
> 
> When commenting v3, I didn't know about the v2 discussion where Eric
> Dumazet NACKed the patch because of potential conflict issues:
> 
>   https://patchwork.ozlabs.org/patch/970421/#1992397
>   https://patchwork.ozlabs.org/patch/988241/#2017317
> 
> On the other hand, there is no need for atomic64_t. Simple atomic_t
> (with explaining comment) would suffice. On architectures allowing
> atomic read/write for 32-bit integers, there would be no performance
> penalty. On architectures not allowing it, atomic_read() and
> atomic_set() are implemented to be safe.

Sorry for late response, I was off to work for couple of weeks.

v3: https://patchwork.ozlabs.org/patch/988241/  was sent with atomic_t and after seeing your comment, I sent it with atomic64_t.
Please let me know if v3 was fine ? 

Thanks,
Manish
> 
> Michal Kubecek

^ permalink raw reply

* Re: [PATCH bpf-next v2] bpf: libbpf: retry map creation without the name
From: Stanislav Fomichev @ 2018-11-20  0:12 UTC (permalink / raw)
  To: Daniel Borkmann; +Cc: Stanislav Fomichev, netdev, ast, vladum
In-Reply-To: <ca3840bd-91a9-0780-975d-75740ceea77f@iogearbox.net>

On 11/20, Daniel Borkmann wrote:
> On 11/19/2018 11:49 PM, Stanislav Fomichev wrote:
> > Since commit 88cda1c9da02 ("bpf: libbpf: Provide basic API support
> > to specify BPF obj name"), libbpf unconditionally sets bpf_attr->name
> > for maps. Pre v4.14 kernels don't know about map names and return an
> > error about unexpected non-zero data. Retry sys_bpf without a map
> > name to cover older kernels.
> > 
> > v2 changes:
> > * check for errno == EINVAL as suggested by Daniel Borkmann
> > 
> > Signed-off-by: Stanislav Fomichev <sdf@google.com>
> 
> Applied to bpf-next, thanks!
Great, thanks! It looks like there might be the same problem with the
program's name. I'll probably follow up with another patch soon.

^ permalink raw reply

* [PATCH bpf-next 2/2] bpf: adding tests for mapinmap helpber in libbpf
From: Nikita V. Shirokov @ 2018-11-20  0:06 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Jakub Kicinski
  Cc: netdev, Nikita V. Shirokov
In-Reply-To: <20181120000626.16825-1-tehnerd@tehnerd.com>

adding test/example of bpf_map__add_inner_map_fd usage

Signed-off-by: Nikita V. Shirokov <tehnerd@tehnerd.com>
---
 tools/testing/selftests/bpf/Makefile        |  3 +-
 tools/testing/selftests/bpf/test_mapinmap.c | 53 ++++++++++++++++++++
 tools/testing/selftests/bpf/test_maps.c     | 76 +++++++++++++++++++++++++++++
 3 files changed, 131 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/bpf/test_mapinmap.c

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 57b4712a6276..a3ea69dc9bdf 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -38,7 +38,8 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
 	test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \
 	get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \
 	test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o \
-	test_sk_lookup_kern.o test_xdp_vlan.o test_queue_map.o test_stack_map.o
+	test_sk_lookup_kern.o test_xdp_vlan.o test_queue_map.o test_stack_map.o \
+	test_mapinmap.o
 
 # Order correspond to 'make run_tests' order
 TEST_PROGS := test_kmod.sh \
diff --git a/tools/testing/selftests/bpf/test_mapinmap.c b/tools/testing/selftests/bpf/test_mapinmap.c
new file mode 100644
index 000000000000..8aef6c652c9c
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_mapinmap.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018 Facebook */
+#include <stddef.h>
+#include <linux/bpf.h>
+#include <linux/types.h>
+#include "bpf_helpers.h"
+
+
+struct bpf_map_def SEC("maps") mim_array = {
+	.type = BPF_MAP_TYPE_ARRAY_OF_MAPS,
+	.key_size = sizeof(int),
+	/* must be sizeof(__u32) for map in map */
+	.value_size = sizeof(__u32),
+	.max_entries = 1,
+	.map_flags = 0,
+};
+
+struct bpf_map_def SEC("maps") mim_hash = {
+	.type = BPF_MAP_TYPE_HASH_OF_MAPS,
+	.key_size = sizeof(int),
+	/* must be sizeof(__u32) for map in map */
+	.value_size = sizeof(__u32),
+	.max_entries = 1,
+	.map_flags = 0,
+};
+
+
+
+SEC("xdp_mimtest")
+int xdp_mimtest0(struct xdp_md *ctx)
+{
+	int value = 123;
+	int key = 0;
+	void *map;
+
+	map = bpf_map_lookup_elem(&mim_array, &key);
+	if (!map)
+		return XDP_DROP;
+
+	bpf_map_update_elem(map, &key, &value, 0);
+
+	map = bpf_map_lookup_elem(&mim_hash, &key);
+	if (!map)
+		return XDP_DROP;
+
+	bpf_map_update_elem(map, &key, &value, 0);
+
+	return XDP_PASS;
+}
+
+
+int _version SEC("version") = 1;
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c
index 4db2116e52be..a49ab294971d 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -1080,6 +1080,80 @@ static void test_sockmap(int tasks, void *data)
 	exit(1);
 }
 
+#define MAPINMAP_PROG "./test_mapinmap.o"
+static void test_mapinmap(void)
+{
+	struct bpf_program *prog;
+	struct bpf_object *obj;
+	struct bpf_map *map;
+	int mim_fd, fd;
+	int pos = 0;
+
+	obj = bpf_object__open(MAPINMAP_PROG);
+
+	fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(int), sizeof(int),
+			    2, 0);
+	if (fd < 0) {
+		printf("Failed to create hashmap '%s'!\n", strerror(errno));
+		exit(1);
+	}
+	printf("fd is %d\n", fd);
+
+	map = bpf_object__find_map_by_name(obj, "mim_array");
+	if (IS_ERR(map)) {
+		printf("Failed to load array of maps from test prog\n");
+		goto out_mapinmap;
+	}
+	bpf_map__add_inner_map_fd(map, fd);
+
+	map = bpf_object__find_map_by_name(obj, "mim_hash");
+	if (IS_ERR(map)) {
+		printf("Failed to load hash of maps from test prog\n");
+		goto out_mapinmap;
+	}
+	bpf_map__add_inner_map_fd(map, fd);
+
+
+	bpf_object__for_each_program(prog, obj) {
+		bpf_program__set_xdp(prog);
+	}
+	bpf_object__load(obj);
+
+	map = bpf_object__find_map_by_name(obj, "mim_array");
+	if (IS_ERR(map)) {
+		printf("Failed to load array of maps from test prog\n");
+		goto out_mapinmap;
+	}
+	mim_fd = bpf_map__fd(map);
+	if (mim_fd < 0) {
+		printf("Failed to get descriptor for array of maps\n");
+		goto out_mapinmap;
+	}
+
+	bpf_map_update_elem(mim_fd, &pos, &fd, 0);
+
+	map = bpf_object__find_map_by_name(obj, "mim_hash");
+	if (IS_ERR(map)) {
+		printf("Failed to load hash of maps from test prog\n");
+		goto out_mapinmap;
+	}
+	mim_fd = bpf_map__fd(map);
+	if (mim_fd < 0) {
+		printf("Failed to get descriptor for hash of maps\n");
+		goto out_mapinmap;
+	}
+	bpf_map_update_elem(mim_fd, &pos, &fd, 0);
+
+
+	close(fd);
+	bpf_object__close(obj);
+	return;
+
+out_mapinmap:
+	close(fd);
+	exit(1);
+}
+
 #define MAP_SIZE (32 * 1024)
 
 static void test_map_large(void)
@@ -1554,6 +1628,8 @@ static void run_all_tests(void)
 
 	test_queuemap(0, NULL);
 	test_stackmap(0, NULL);
+
+	test_mapinmap();
 }
 
 int main(void)
-- 
2.15.1

^ permalink raw reply related

* [PATCH bpf-next 1/2] bpf: adding support for map in map in libbpf
From: Nikita V. Shirokov @ 2018-11-20  0:06 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Jakub Kicinski
  Cc: netdev, Nikita V. Shirokov
In-Reply-To: <20181120000626.16825-1-tehnerd@tehnerd.com>

idea is pretty simple. for specified map (pointed by struct bpf_map)
we would provide descriptor of already loaded map, which is going to be
used as a prototype for inner map. proposed workflow:
1) open bpf's object (bpf_object__open)
2) create bpf's map which is going to be used as a prototype
3) find (by name) map-in-map which you want to load and update w/
descriptor of inner map w/ a new helper from this patch
4) load bpf program w/ bpf_object__load

inner_map_fd is ignored by any other maps asidef from (hash|array) of
maps

Signed-off-by: Nikita V. Shirokov <tehnerd@tehnerd.com>
---
 tools/lib/bpf/libbpf.c | 7 +++++++
 tools/lib/bpf/libbpf.h | 2 ++
 2 files changed, 9 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index a01eb9584e52..a2ee1b1a93b6 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -163,6 +163,7 @@ struct bpf_map {
 	char *name;
 	size_t offset;
 	int map_ifindex;
+	int inner_map_fd;
 	struct bpf_map_def def;
 	__u32 btf_key_type_id;
 	__u32 btf_value_type_id;
@@ -1146,6 +1147,7 @@ bpf_object__create_maps(struct bpf_object *obj)
 		create_attr.btf_fd = 0;
 		create_attr.btf_key_type_id = 0;
 		create_attr.btf_value_type_id = 0;
+		create_attr.inner_map_fd = map->inner_map_fd;
 
 		if (obj->btf && !bpf_map_find_btf_info(map, obj->btf)) {
 			create_attr.btf_fd = btf__fd(obj->btf);
@@ -2562,6 +2564,11 @@ void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
 	map->map_ifindex = ifindex;
 }
 
+void bpf_map__add_inner_map_fd(struct bpf_map *map, const int fd)
+{
+	map->inner_map_fd = fd;
+}
+
 static struct bpf_map *
 __bpf_map__iter(struct bpf_map *m, struct bpf_object *obj, int i)
 {
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index b1686a787102..7cb00cd41789 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -293,6 +293,8 @@ LIBBPF_API void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
 LIBBPF_API int bpf_map__pin(struct bpf_map *map, const char *path);
 LIBBPF_API int bpf_map__unpin(struct bpf_map *map, const char *path);
 
+LIBBPF_API void bpf_map__add_inner_map_fd(struct bpf_map *map, const int fd);
+
 LIBBPF_API long libbpf_get_error(const void *ptr);
 
 struct bpf_prog_load_attr {
-- 
2.15.1

^ permalink raw reply related

* [PATCH bpf-next 0/2] bpf: adding support for mapinmap in libbpf
From: Nikita V. Shirokov @ 2018-11-20  0:06 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Jakub Kicinski
  Cc: netdev, Nikita V. Shirokov

in this patch series i'm adding a helper for libbpf which would allow
it to load map-in-map(BPF_MAP_TYPE_ARRAY_OF_MAPS and
BPF_MAP_TYPE_HASH_OF_MAPS).
first patch contains new helper + explains proposed workflow
second patch contains tests which also could be used as example of
usage

Nikita V. Shirokov (2):
  bpf: adding support for map in map in libbpf
  bpf: adding tests for mapinmap helpber in libbpf

 tools/lib/bpf/libbpf.c                      |  7 +++
 tools/lib/bpf/libbpf.h                      |  2 +
 tools/testing/selftests/bpf/Makefile        |  3 +-
 tools/testing/selftests/bpf/test_mapinmap.c | 53 ++++++++++++++++++++
 tools/testing/selftests/bpf/test_maps.c     | 76 +++++++++++++++++++++++++++++
 5 files changed, 140 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/bpf/test_mapinmap.c

-- 
2.15.1

^ permalink raw reply

* Re: [PATCH bpf-next v2] bpf: libbpf: retry map creation without the name
From: Daniel Borkmann @ 2018-11-19 23:57 UTC (permalink / raw)
  To: Stanislav Fomichev, netdev, ast; +Cc: vladum
In-Reply-To: <20181119224901.21214-1-sdf@google.com>

On 11/19/2018 11:49 PM, Stanislav Fomichev wrote:
> Since commit 88cda1c9da02 ("bpf: libbpf: Provide basic API support
> to specify BPF obj name"), libbpf unconditionally sets bpf_attr->name
> for maps. Pre v4.14 kernels don't know about map names and return an
> error about unexpected non-zero data. Retry sys_bpf without a map
> name to cover older kernels.
> 
> v2 changes:
> * check for errno == EINVAL as suggested by Daniel Borkmann
> 
> Signed-off-by: Stanislav Fomichev <sdf@google.com>

Applied to bpf-next, thanks!

^ permalink raw reply

* Re: [PATCH v3 0/4] bpf: allow zero-initialising hash map seed
From: Daniel Borkmann @ 2018-11-19 23:56 UTC (permalink / raw)
  To: Lorenz Bauer, ast; +Cc: netdev, linux-api, songliubraving
In-Reply-To: <20181116114111.31177-1-lmb@cloudflare.com>

On 11/16/2018 12:41 PM, Lorenz Bauer wrote:
> Allow forcing the seed of a hash table to zero, for deterministic
> execution during benchmarking and testing.
> 
> Changes from v2:
> * Change ordering of BPF_F_ZERO_SEED in linux/bpf.h
> 
> Comments adressed from v1:
> * Add comment to discourage production use to linux/bpf.h
> * Require CAP_SYS_ADMIN
> 
> Lorenz Bauer (4):
>   bpf: allow zero-initializing hash map seed
>   bpf: move BPF_F_QUERY_EFFECTIVE after map flags
>   tools: sync linux/bpf.h
>   tools: add selftest for BPF_F_ZERO_SEED
> 
>  include/uapi/linux/bpf.h                |  9 ++--
>  kernel/bpf/hashtab.c                    | 13 ++++-
>  tools/include/uapi/linux/bpf.h          | 13 +++--
>  tools/testing/selftests/bpf/test_maps.c | 68 +++++++++++++++++++++----
>  4 files changed, 84 insertions(+), 19 deletions(-)
> 

Applied to bpf-next, thanks!

^ permalink raw reply

* Re: netns_id in bpf_sk_lookup_{tcp,udp}
From: David Ahern @ 2018-11-19 23:46 UTC (permalink / raw)
  To: Joe Stringer; +Cc: nicolas.dichtel, netdev, daniel
In-Reply-To: <CAOftzPgviq+J6kCCXEiWjtpR25ZPhZYFaWpNOFJ3i9pOoDg6cg@mail.gmail.com>

On 11/19/18 2:59 PM, Joe Stringer wrote:
> @@ -2221,12 +2222,13 @@ union bpf_attr {
>  *             **sizeof**\ (*tuple*\ **->ipv6**)
>  *                     Look for an IPv6 socket.
>  *
> - *             If the *netns* is zero, then the socket lookup table in the
> - *             netns associated with the *ctx* will be used. For the TC hooks,
> - *             this in the netns of the device in the skb. For socket hooks,
> - *             this in the netns of the socket. If *netns* is non-zero, then
> - *             it specifies the ID of the netns relative to the netns
> - *             associated with the *ctx*.
> + *             If the *netns* is **BPF_F_SK_CURRENT_NS** or greater, then the
> + *             socket lookup table in the netns associated with the *ctx* will
> + *             will be used. For the TC hooks, this is the netns of the device
> + *             in the skb. For socket hooks, this is the netns of the socket.
> + *             If *netns* is less than **BPF_F_SK_CURRENT_NS**, then it
> + *             specifies the ID of the netns relative to the netns associated
> + *             with the *ctx*.
>  *
>  *             All values for *flags* are reserved for future usage, and must
>  *             be left at zero.
> @@ -2409,6 +2411,9 @@ enum bpf_func_id {
> /* BPF_FUNC_perf_event_output for sk_buff input context. */
> #define BPF_F_CTXLEN_MASK              (0xfffffULL << 32)
> 
> +/* BPF_FUNC_sk_lookup_tcp and BPF_FUNC_sk_lookup_udp flags. */
> +#define BPF_F_SK_CURRENT_NS            0x80000000 /* For netns argument */
> +
> /* Mode for BPF_FUNC_skb_adjust_room helper. */
> enum bpf_adj_room_mode {
>        BPF_ADJ_ROOM_NET,
> 
> Plus adjusting all of the internal types and the helper headers to use
> u32. With the highest bit used to specify that the netns should be the
> current netns, all other netns IDs should be available.
> 

That seems reasonable if the nsid limit is s32.

That revelation shows another hole:
$ ip netns add foo
$ ip netns set foo 0xffffffff
$ ip netns list
foo (id: 0)

Seems like alloc_netid() should error out if reqid < -1 (-1 being the
NETNSA_NSID_NOT_ASSIGNED flag) as opposed to blindly ignoring it.

^ permalink raw reply

* [net 13/13] net/mlx5e: Fix failing ethtool query on FEC query error
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Shay Agroskin, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Shay Agroskin <shayag@mellanox.com>

If FEC caps query fails when executing 'ethtool <interface>'
the whole callback fails unnecessarily, fixed that by replacing the
error return code with debug logging only.

Fixes: 6cfa94605091 ("net/mlx5e: Ethtool driver callback for query/set FEC policy")
Signed-off-by: Shay Agroskin <shayag@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index 3e770abfd802..25c1c4f96841 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -843,8 +843,7 @@ static int mlx5e_get_link_ksettings(struct net_device *netdev,
 	ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
 					     Autoneg);
 
-	err = get_fec_supported_advertised(mdev, link_ksettings);
-	if (err)
+	if (get_fec_supported_advertised(mdev, link_ksettings))
 		netdev_dbg(netdev, "%s: FEC caps query failed: %d\n",
 			   __func__, err);
 
-- 
2.19.1

^ permalink raw reply related

* [net 12/13] net/mlx5e: Removed unnecessary warnings in FEC caps query
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Shay Agroskin, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Shay Agroskin <shayag@mellanox.com>

Querying interface FEC caps with 'ethtool [int]' after link reset
throws warning regading link speed.
This warning is not needed as there is already an indication in
user space that the link is not up.

Fixes: 0696d60853d5 ("net/mlx5e: Receive buffer configuration")
Signed-off-by: Shay Agroskin <shayag@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en/port.c        | 4 +---
 drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c | 4 +++-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
index 83ba9ea201d8..4a37713023be 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
@@ -88,10 +88,8 @@ int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
 
 	eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
 	*speed = mlx5e_port_ptys2speed(eth_proto_oper);
-	if (!(*speed)) {
-		mlx5_core_warn(mdev, "cannot get port speed\n");
+	if (!(*speed))
 		err = -EINVAL;
-	}
 
 	return err;
 }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
index c047da8752da..eac245a93f91 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
@@ -130,8 +130,10 @@ static u32 calculate_xoff(struct mlx5e_priv *priv, unsigned int mtu)
 	int err;
 
 	err = mlx5e_port_linkspeed(priv->mdev, &speed);
-	if (err)
+	if (err) {
+		mlx5_core_warn(priv->mdev, "cannot get port speed\n");
 		return 0;
+	}
 
 	xoff = (301 + 216 * priv->dcbx.cable_len / 100) * speed / 1000 + 272 * mtu / 100;
 
-- 
2.19.1

^ permalink raw reply related

* [net 11/13] net/mlx5e: Fix wrong field name in FEC related functions
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Shay Agroskin, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Shay Agroskin <shayag@mellanox.com>

This bug would result in reading wrong FEC capabilities for 10G/40G.

Fixes: 2095b2641477 ("net/mlx5e: Add port FEC get/set functions")
Signed-off-by: Shay Agroskin <shayag@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en/port.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
index c16351eb9e54..83ba9ea201d8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
@@ -258,7 +258,7 @@ static int mlx5e_fec_admin_field(u32 *pplm,
 	case 40000:
 		if (!write)
 			*fec_policy = MLX5_GET(pplm_reg, pplm,
-					       fec_override_cap_10g_40g);
+					       fec_override_admin_10g_40g);
 		else
 			MLX5_SET(pplm_reg, pplm,
 				 fec_override_admin_10g_40g, *fec_policy);
@@ -310,7 +310,7 @@ static int mlx5e_get_fec_cap_field(u32 *pplm,
 	case 10000:
 	case 40000:
 		*fec_cap = MLX5_GET(pplm_reg, pplm,
-				    fec_override_admin_10g_40g);
+				    fec_override_cap_10g_40g);
 		break;
 	case 25000:
 		*fec_cap = MLX5_GET(pplm_reg, pplm,
-- 
2.19.1

^ permalink raw reply related

* [net 10/13] net/mlx5e: Fix a bug in turning off FEC policy in unsupported speeds
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Shay Agroskin, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Shay Agroskin <shayag@mellanox.com>

Some speeds don't support turning FEC policy off. In case a requested
FEC policy is not supported for a speed (including current speed), its new
FEC policy would be:
	no FEC - if disabling FEC is supported for that speed
	unchanged - else

Fixes: 2095b2641477 ("net/mlx5e: Add port FEC get/set functions")
Signed-off-by: Shay Agroskin <shayag@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/en/port.c | 28 ++++++++-----------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
index 023dc4bccd28..c16351eb9e54 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
@@ -394,12 +394,12 @@ int mlx5e_get_fec_mode(struct mlx5_core_dev *dev, u32 *fec_mode_active,
 
 int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
 {
+	u8 fec_policy_nofec = BIT(MLX5E_FEC_NOFEC);
 	bool fec_mode_not_supp_in_speed = false;
-	u8 no_fec_policy = BIT(MLX5E_FEC_NOFEC);
 	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
 	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
 	int sz = MLX5_ST_SZ_BYTES(pplm_reg);
-	u32 current_fec_speed;
+	u8 fec_policy_auto = 0;
 	u8 fec_caps = 0;
 	int err;
 	int i;
@@ -415,23 +415,19 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
 	if (err)
 		return err;
 
-	err = mlx5e_port_linkspeed(dev, &current_fec_speed);
-	if (err)
-		return err;
+	MLX5_SET(pplm_reg, out, local_port, 1);
 
-	memset(in, 0, sz);
-	MLX5_SET(pplm_reg, in, local_port, 1);
-	for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS && !!fec_policy; i++) {
+	for (i = 0; i < MLX5E_FEC_SUPPORTED_SPEEDS; i++) {
 		mlx5e_get_fec_cap_field(out, &fec_caps, fec_supported_speeds[i]);
-		/* policy supported for link speed */
-		if (!!(fec_caps & fec_policy)) {
-			mlx5e_fec_admin_field(in, &fec_policy, 1,
+		/* policy supported for link speed, or policy is auto */
+		if (fec_caps & fec_policy || fec_policy == fec_policy_auto) {
+			mlx5e_fec_admin_field(out, &fec_policy, 1,
 					      fec_supported_speeds[i]);
 		} else {
-			if (fec_supported_speeds[i] == current_fec_speed)
-				return -EOPNOTSUPP;
-			mlx5e_fec_admin_field(in, &no_fec_policy, 1,
-					      fec_supported_speeds[i]);
+			/* turn off FEC if supported. Else, leave it the same */
+			if (fec_caps & fec_policy_nofec)
+				mlx5e_fec_admin_field(out, &fec_policy_nofec, 1,
+						      fec_supported_speeds[i]);
 			fec_mode_not_supp_in_speed = true;
 		}
 	}
@@ -441,5 +437,5 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u8 fec_policy)
 			      "FEC policy 0x%x is not supported for some speeds",
 			      fec_policy);
 
-	return mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1);
+	return mlx5_core_access_reg(dev, out, sz, out, sz, MLX5_REG_PPLM, 0, 1);
 }
-- 
2.19.1

^ permalink raw reply related

* [net 08/13] net/mlx5e: RX, verify received packet size in Linear Striding RQ
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Moshe Shemesh, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Moshe Shemesh <moshe@mellanox.com>

In case of striding RQ, we use  MPWRQ (Multi Packet WQE RQ), which means
that WQE (RX descriptor) can be used for many packets and so the WQE is
much bigger than MTU.  In virtualization setups where the port mtu can
be larger than the vf mtu, if received packet is bigger than MTU, it
won't be dropped by HW on too small receive WQE. If we use linear SKB in
striding RQ, since each stride has room for mtu size payload and skb
info, an oversized packet can lead to crash for crossing allocated page
boundary upon the call to build_skb. So driver needs to check packet
size and drop it.

Introduce new SW rx counter, rx_oversize_pkts_sw_drop, which counts the
number of packets dropped by the driver for being too large.

As a new field is added to the RQ struct, re-open the channels whenever
this field is being used in datapath (i.e., in the case of linear
Striding RQ).

Fixes: 619a8f2a42f1 ("net/mlx5e: Use linear SKB in Striding RQ")
Signed-off-by: Moshe Shemesh <moshe@mellanox.com>
Reviewed-by: Tariq Toukan <tariqt@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en.h       | 1 +
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c  | 4 +++-
 drivers/net/ethernet/mellanox/mlx5/core/en_rx.c    | 6 ++++++
 drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 3 +++
 drivers/net/ethernet/mellanox/mlx5/core/en_stats.h | 2 ++
 5 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index d7fbd5b6ac95..118324802926 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -569,6 +569,7 @@ struct mlx5e_rq {
 
 	unsigned long          state;
 	int                    ix;
+	unsigned int           hw_mtu;
 
 	struct net_dim         dim; /* Dynamic Interrupt Moderation */
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 25b09bb68e8b..871313d6b34d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -502,6 +502,7 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
 	rq->channel = c;
 	rq->ix      = c->ix;
 	rq->mdev    = mdev;
+	rq->hw_mtu  = MLX5E_SW2HW_MTU(params, params->sw_mtu);
 	rq->stats   = &c->priv->channel_stats[c->ix].rq;
 
 	rq->xdp_prog = params->xdp_prog ? bpf_prog_inc(params->xdp_prog) : NULL;
@@ -3766,10 +3767,11 @@ int mlx5e_change_mtu(struct net_device *netdev, int new_mtu,
 	}
 
 	if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
+		bool is_linear = mlx5e_rx_mpwqe_is_linear_skb(priv->mdev, &new_channels.params);
 		u8 ppw_old = mlx5e_mpwqe_log_pkts_per_wqe(params);
 		u8 ppw_new = mlx5e_mpwqe_log_pkts_per_wqe(&new_channels.params);
 
-		reset = reset && (ppw_old != ppw_new);
+		reset = reset && (is_linear || (ppw_old != ppw_new));
 	}
 
 	if (!reset) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 79638dcbae78..16985ca3248d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -1104,6 +1104,12 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
 	u32 frag_size;
 	bool consumed;
 
+	/* Check packet size. Note LRO doesn't use linear SKB */
+	if (unlikely(cqe_bcnt > rq->hw_mtu)) {
+		rq->stats->oversize_pkts_sw_drop++;
+		return NULL;
+	}
+
 	va             = page_address(di->page) + head_offset;
 	data           = va + rx_headroom;
 	frag_size      = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt32);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index 1e55b9c27ffc..3e99d0728b2f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -83,6 +83,7 @@ static const struct counter_desc sw_stats_desc[] = {
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_wqe_err) },
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_mpwqe_filler_cqes) },
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_mpwqe_filler_strides) },
+	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_oversize_pkts_sw_drop) },
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_buff_alloc_err) },
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_blks) },
 	{ MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_pkts) },
@@ -161,6 +162,7 @@ void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
 		s->rx_wqe_err   += rq_stats->wqe_err;
 		s->rx_mpwqe_filler_cqes    += rq_stats->mpwqe_filler_cqes;
 		s->rx_mpwqe_filler_strides += rq_stats->mpwqe_filler_strides;
+		s->rx_oversize_pkts_sw_drop += rq_stats->oversize_pkts_sw_drop;
 		s->rx_buff_alloc_err += rq_stats->buff_alloc_err;
 		s->rx_cqe_compress_blks += rq_stats->cqe_compress_blks;
 		s->rx_cqe_compress_pkts += rq_stats->cqe_compress_pkts;
@@ -1189,6 +1191,7 @@ static const struct counter_desc rq_stats_desc[] = {
 	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, wqe_err) },
 	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, mpwqe_filler_cqes) },
 	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, mpwqe_filler_strides) },
+	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, oversize_pkts_sw_drop) },
 	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, buff_alloc_err) },
 	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cqe_compress_blks) },
 	{ MLX5E_DECLARE_RX_STAT(struct mlx5e_rq_stats, cqe_compress_pkts) },
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
index 77f74ce11280..3f8e870ef4c9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -96,6 +96,7 @@ struct mlx5e_sw_stats {
 	u64 rx_wqe_err;
 	u64 rx_mpwqe_filler_cqes;
 	u64 rx_mpwqe_filler_strides;
+	u64 rx_oversize_pkts_sw_drop;
 	u64 rx_buff_alloc_err;
 	u64 rx_cqe_compress_blks;
 	u64 rx_cqe_compress_pkts;
@@ -193,6 +194,7 @@ struct mlx5e_rq_stats {
 	u64 wqe_err;
 	u64 mpwqe_filler_cqes;
 	u64 mpwqe_filler_strides;
+	u64 oversize_pkts_sw_drop;
 	u64 buff_alloc_err;
 	u64 cqe_compress_blks;
 	u64 cqe_compress_pkts;
-- 
2.19.1

^ permalink raw reply related

* [net 07/13] net/mlx5e: Apply the correct check for supporting TC esw rules split
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Roi Dayan, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Roi Dayan <roid@mellanox.com>

The mirror and not the output count is the one denoting a split.
Fix to condition the offload attempt on the mirror count being > 0
along the firmware to have the related capability.

Fixes: 592d36515969 ("net/mlx5e: Parse mirroring action for offloaded TC eswitch flows")
Signed-off-by: Roi Dayan <roid@mellanox.com>
Reviewed-by: Yossi Kuperman <yossiku@mellanox.com>
Reviewed-by: Chris Mi <chrism@mellanox.com>
Acked-by: Or Gerlitz <ogerlitz@mellanox.com>
Reviewed-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 0409767237a7..fca6f4132c91 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -2980,7 +2980,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
 	if (!actions_match_supported(priv, exts, parse_attr, flow, extack))
 		return -EOPNOTSUPP;
 
-	if (attr->out_count > 1 && !mlx5_esw_has_fwd_fdb(priv->mdev)) {
+	if (attr->mirror_count > 0 && !mlx5_esw_has_fwd_fdb(priv->mdev)) {
 		NL_SET_ERR_MSG_MOD(extack,
 				   "current firmware doesn't support split rule for port mirroring");
 		netdev_warn_once(priv->netdev, "current firmware doesn't support split rule for port mirroring\n");
-- 
2.19.1

^ permalink raw reply related

* [net 09/13] net/mlx5e: Fix selftest for small MTUs
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Valentine Fatiev, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Valentine Fatiev <valentinef@mellanox.com>

Loopback test had fixed packet size, which can be bigger than configured
MTU. Shorten the loopback packet size to be bigger than minimal MTU
allowed by the device. Text field removed from struct 'mlx5ehdr'
as redundant to allow send small packets as minimal allowed MTU.

Fixes: d605d66 ("net/mlx5e: Add support for ethtool self diagnostics test")
Signed-off-by: Valentine Fatiev <valentinef@mellanox.com>
Reviewed-by: Eran Ben Elisha <eranbe@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 .../ethernet/mellanox/mlx5/core/en_selftest.c | 26 +++++++------------
 1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
index 35ded91203f5..4382ef85488c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c
@@ -98,18 +98,17 @@ static int mlx5e_test_link_speed(struct mlx5e_priv *priv)
 	return 1;
 }
 
-#ifdef CONFIG_INET
-/* loopback test */
-#define MLX5E_TEST_PKT_SIZE (MLX5E_RX_MAX_HEAD - NET_IP_ALIGN)
-static const char mlx5e_test_text[ETH_GSTRING_LEN] = "MLX5E SELF TEST";
-#define MLX5E_TEST_MAGIC 0x5AEED15C001ULL
-
 struct mlx5ehdr {
 	__be32 version;
 	__be64 magic;
-	char   text[ETH_GSTRING_LEN];
 };
 
+#ifdef CONFIG_INET
+/* loopback test */
+#define MLX5E_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) +\
+			     sizeof(struct udphdr) + sizeof(struct mlx5ehdr))
+#define MLX5E_TEST_MAGIC 0x5AEED15C001ULL
+
 static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
 {
 	struct sk_buff *skb = NULL;
@@ -117,10 +116,7 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
 	struct ethhdr *ethh;
 	struct udphdr *udph;
 	struct iphdr *iph;
-	int datalen, iplen;
-
-	datalen = MLX5E_TEST_PKT_SIZE -
-		  (sizeof(*ethh) + sizeof(*iph) + sizeof(*udph));
+	int    iplen;
 
 	skb = netdev_alloc_skb(priv->netdev, MLX5E_TEST_PKT_SIZE);
 	if (!skb) {
@@ -149,7 +145,7 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
 	/* Fill UDP header */
 	udph->source = htons(9);
 	udph->dest = htons(9); /* Discard Protocol */
-	udph->len = htons(datalen + sizeof(struct udphdr));
+	udph->len = htons(sizeof(struct mlx5ehdr) + sizeof(struct udphdr));
 	udph->check = 0;
 
 	/* Fill IP header */
@@ -157,7 +153,8 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
 	iph->ttl = 32;
 	iph->version = 4;
 	iph->protocol = IPPROTO_UDP;
-	iplen = sizeof(struct iphdr) + sizeof(struct udphdr) + datalen;
+	iplen = sizeof(struct iphdr) + sizeof(struct udphdr) +
+		sizeof(struct mlx5ehdr);
 	iph->tot_len = htons(iplen);
 	iph->frag_off = 0;
 	iph->saddr = 0;
@@ -170,9 +167,6 @@ static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
 	mlxh = skb_put(skb, sizeof(*mlxh));
 	mlxh->version = 0;
 	mlxh->magic = cpu_to_be64(MLX5E_TEST_MAGIC);
-	strlcpy(mlxh->text, mlx5e_test_text, sizeof(mlxh->text));
-	datalen -= sizeof(*mlxh);
-	skb_put_zero(skb, datalen);
 
 	skb->csum = 0;
 	skb->ip_summed = CHECKSUM_PARTIAL;
-- 
2.19.1

^ permalink raw reply related

* [net 06/13] net/mlx5e: Adjust to max number of channles when re-attaching
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Yuval Avnery, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Yuval Avnery <yuvalav@mellanox.com>

When core driver enters deattach/attach flow after pci reset,
Number of logical CPUs may have changed.
As a result we need to update the cpu affiliated resource tables.
	1. indirect rqt list
	2. eq table

Reproduction (PowerPC):
	echo 1000 > /sys/kernel/debug/powerpc/eeh_max_freezes
	ppc64_cpu --smt=on
	# Restart driver
	modprobe -r ... ; modprobe ...
	# Link up
	ifconfig ...
	# Only physical CPUs
	ppc64_cpu --smt=off
	# Inject PCI errors so PCI will reset - calling the pci error handler
	echo 0x8000000000000000 > /sys/kernel/debug/powerpc/<PCI BUS>/err_injct_inboundA

Call trace when trying to add non-existing rqs to an indirect rqt:
	mlx5e_redirect_rqt+0x84/0x260 [mlx5_core] (unreliable)
	mlx5e_redirect_rqts+0x188/0x190 [mlx5_core]
	mlx5e_activate_priv_channels+0x488/0x570 [mlx5_core]
	mlx5e_open_locked+0xbc/0x140 [mlx5_core]
	mlx5e_open+0x50/0x130 [mlx5_core]
	mlx5e_nic_enable+0x174/0x1b0 [mlx5_core]
	mlx5e_attach_netdev+0x154/0x290 [mlx5_core]
	mlx5e_attach+0x88/0xd0 [mlx5_core]
	mlx5_attach_device+0x168/0x1e0 [mlx5_core]
	mlx5_load_one+0x1140/0x1210 [mlx5_core]
	mlx5_pci_resume+0x6c/0xf0 [mlx5_core]

Create cq will fail when trying to use non-existing EQ.

Fixes: 89d44f0a6c73 ("net/mlx5_core: Add pci error handlers to mlx5_core driver")
Signed-off-by: Yuval Avnery <yuvalav@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/en_main.c | 27 +++++++++++++++----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index fb3b2d9c352b..25b09bb68e8b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -1623,13 +1623,15 @@ static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev,
 	int err;
 	u32 i;
 
+	err = mlx5_vector2eqn(mdev, param->eq_ix, &eqn_not_used, &irqn);
+	if (err)
+		return err;
+
 	err = mlx5_cqwq_create(mdev, &param->wq, param->cqc, &cq->wq,
 			       &cq->wq_ctrl);
 	if (err)
 		return err;
 
-	mlx5_vector2eqn(mdev, param->eq_ix, &eqn_not_used, &irqn);
-
 	mcq->cqe_sz     = 64;
 	mcq->set_ci_db  = cq->wq_ctrl.db.db;
 	mcq->arm_db     = cq->wq_ctrl.db.db + 1;
@@ -1687,6 +1689,10 @@ static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
 	int eqn;
 	int err;
 
+	err = mlx5_vector2eqn(mdev, param->eq_ix, &eqn, &irqn_not_used);
+	if (err)
+		return err;
+
 	inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
 		sizeof(u64) * cq->wq_ctrl.buf.npages;
 	in = kvzalloc(inlen, GFP_KERNEL);
@@ -1700,8 +1706,6 @@ static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
 	mlx5_fill_page_frag_array(&cq->wq_ctrl.buf,
 				  (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas));
 
-	mlx5_vector2eqn(mdev, param->eq_ix, &eqn, &irqn_not_used);
-
 	MLX5_SET(cqc,   cqc, cq_period_mode, param->cq_period_mode);
 	MLX5_SET(cqc,   cqc, c_eqn,         eqn);
 	MLX5_SET(cqc,   cqc, uar_page,      mdev->priv.uar->index);
@@ -1921,6 +1925,10 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
 	int err;
 	int eqn;
 
+	err = mlx5_vector2eqn(priv->mdev, ix, &eqn, &irq);
+	if (err)
+		return err;
+
 	c = kvzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu));
 	if (!c)
 		return -ENOMEM;
@@ -1937,7 +1945,6 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
 	c->xdp      = !!params->xdp_prog;
 	c->stats    = &priv->channel_stats[ix].ch;
 
-	mlx5_vector2eqn(priv->mdev, ix, &eqn, &irq);
 	c->irq_desc = irq_to_desc(irq);
 
 	netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64);
@@ -5010,11 +5017,21 @@ struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
 int mlx5e_attach_netdev(struct mlx5e_priv *priv)
 {
 	const struct mlx5e_profile *profile;
+	int max_nch;
 	int err;
 
 	profile = priv->profile;
 	clear_bit(MLX5E_STATE_DESTROYING, &priv->state);
 
+	/* max number of channels may have changed */
+	max_nch = mlx5e_get_max_num_channels(priv->mdev);
+	if (priv->channels.params.num_channels > max_nch) {
+		mlx5_core_warn(priv->mdev, "MLX5E: Reducing number of channels to %d\n", max_nch);
+		priv->channels.params.num_channels = max_nch;
+		mlx5e_build_default_indir_rqt(priv->channels.params.indirection_rqt,
+					      MLX5E_INDIR_RQT_SIZE, max_nch);
+	}
+
 	err = profile->init_tx(priv);
 	if (err)
 		goto out;
-- 
2.19.1

^ permalink raw reply related

* [net 05/13] net/mlx5e: Always use the match level enum when parsing TC rule match
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Or Gerlitz, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Or Gerlitz <ogerlitz@mellanox.com>

We get the match level (none, l2, l3, l4) while going over the match
dissectors of an offloaded tc rule. When doing this, the match level
enum and the not min inline enum values should be used, fix that.

This worked accidentally b/c both enums have the same numerical values.

Fixes: d708f902989b ('net/mlx5e: Get the required HW match level while parsing TC flow matches')
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 84eb6939e69a..0409767237a7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -1587,10 +1587,10 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
 
 			/* the HW doesn't need L3 inline to match on frag=no */
 			if (!(key->flags & FLOW_DIS_IS_FRAGMENT))
-				*match_level = MLX5_INLINE_MODE_L2;
+				*match_level = MLX5_MATCH_L2;
 	/* ***  L2 attributes parsing up to here *** */
 			else
-				*match_level = MLX5_INLINE_MODE_IP;
+				*match_level = MLX5_MATCH_L3;
 		}
 	}
 
-- 
2.19.1

^ permalink raw reply related

* [net 04/13] net/mlx5e: Claim TC hw offloads support only under a proper build config
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Or Gerlitz, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Or Gerlitz <ogerlitz@mellanox.com>

Currently, we are only supporting tc hw offloads when the eswitch
support is compiled in, but we are not gating the adevertizment
of the NETIF_F_HW_TC feature on this config being set.

Fix it, and while doing that, also avoid dealing with the feature
on ethtool when the config is not set.

Fixes: e8f887ac6a45 ('net/mlx5e: Introduce tc offload support')
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 1243edbedc9e..fb3b2d9c352b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -3574,6 +3574,7 @@ static int set_feature_cvlan_filter(struct net_device *netdev, bool enable)
 	return 0;
 }
 
+#ifdef CONFIG_MLX5_ESWITCH
 static int set_feature_tc_num_filters(struct net_device *netdev, bool enable)
 {
 	struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -3586,6 +3587,7 @@ static int set_feature_tc_num_filters(struct net_device *netdev, bool enable)
 
 	return 0;
 }
+#endif
 
 static int set_feature_rx_all(struct net_device *netdev, bool enable)
 {
@@ -3684,7 +3686,9 @@ static int mlx5e_set_features(struct net_device *netdev,
 	err |= MLX5E_HANDLE_FEATURE(NETIF_F_LRO, set_feature_lro);
 	err |= MLX5E_HANDLE_FEATURE(NETIF_F_HW_VLAN_CTAG_FILTER,
 				    set_feature_cvlan_filter);
+#ifdef CONFIG_MLX5_ESWITCH
 	err |= MLX5E_HANDLE_FEATURE(NETIF_F_HW_TC, set_feature_tc_num_filters);
+#endif
 	err |= MLX5E_HANDLE_FEATURE(NETIF_F_RXALL, set_feature_rx_all);
 	err |= MLX5E_HANDLE_FEATURE(NETIF_F_RXFCS, set_feature_rx_fcs);
 	err |= MLX5E_HANDLE_FEATURE(NETIF_F_HW_VLAN_CTAG_RX, set_feature_rx_vlan);
@@ -4678,7 +4682,9 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
 	    FT_CAP(modify_root) &&
 	    FT_CAP(identified_miss_table_mode) &&
 	    FT_CAP(flow_table_modify)) {
+#ifdef CONFIG_MLX5_ESWITCH
 		netdev->hw_features      |= NETIF_F_HW_TC;
+#endif
 #ifdef CONFIG_MLX5_EN_ARFS
 		netdev->hw_features	 |= NETIF_F_NTUPLE;
 #endif
-- 
2.19.1

^ permalink raw reply related

* [net 03/13] net/mlx5e: Don't match on vlan non-existence if ethertype is wildcarded
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Or Gerlitz, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Or Gerlitz <ogerlitz@mellanox.com>

For the "all" ethertype we should not care whether the packet has
vlans. Besides being wrong, the way we did it caused FW error
for rules such as:

tc filter add dev eth0 protocol all parent ffff: \
	prio 1 flower skip_sw action drop

b/c the matching meta-data (outer headers bit in struct mlx5_flow_spec)
wasn't set. Fix that by matching on vlan non-existence only if we were
also told to match on the ethertype.

Fixes: cee26487620b ('net/mlx5e: Set vlan masks for all offloaded TC rules')
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Reported-by: Slava Ovsiienko <viacheslavo@mellanox.com>
Reviewed-by: Jianbo Liu <jianbol@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 .../net/ethernet/mellanox/mlx5/core/en_tc.c   | 63 ++++++++++---------
 1 file changed, 32 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 608025ca5c04..84eb6939e69a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -1447,31 +1447,21 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
 					 inner_headers);
 	}
 
-	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
-		struct flow_dissector_key_eth_addrs *key =
+	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
+		struct flow_dissector_key_basic *key =
 			skb_flow_dissector_target(f->dissector,
-						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
+						  FLOW_DISSECTOR_KEY_BASIC,
 						  f->key);
-		struct flow_dissector_key_eth_addrs *mask =
+		struct flow_dissector_key_basic *mask =
 			skb_flow_dissector_target(f->dissector,
-						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
+						  FLOW_DISSECTOR_KEY_BASIC,
 						  f->mask);
+		MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype,
+			 ntohs(mask->n_proto));
+		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype,
+			 ntohs(key->n_proto));
 
-		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
-					     dmac_47_16),
-				mask->dst);
-		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
-					     dmac_47_16),
-				key->dst);
-
-		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
-					     smac_47_16),
-				mask->src);
-		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
-					     smac_47_16),
-				key->src);
-
-		if (!is_zero_ether_addr(mask->src) || !is_zero_ether_addr(mask->dst))
+		if (mask->n_proto)
 			*match_level = MLX5_MATCH_L2;
 	}
 
@@ -1505,9 +1495,10 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
 
 			*match_level = MLX5_MATCH_L2;
 		}
-	} else {
+	} else if (*match_level != MLX5_MATCH_NONE) {
 		MLX5_SET(fte_match_set_lyr_2_4, headers_c, svlan_tag, 1);
 		MLX5_SET(fte_match_set_lyr_2_4, headers_c, cvlan_tag, 1);
+		*match_level = MLX5_MATCH_L2;
 	}
 
 	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CVLAN)) {
@@ -1545,21 +1536,31 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
 		}
 	}
 
-	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
-		struct flow_dissector_key_basic *key =
+	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+		struct flow_dissector_key_eth_addrs *key =
 			skb_flow_dissector_target(f->dissector,
-						  FLOW_DISSECTOR_KEY_BASIC,
+						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
 						  f->key);
-		struct flow_dissector_key_basic *mask =
+		struct flow_dissector_key_eth_addrs *mask =
 			skb_flow_dissector_target(f->dissector,
-						  FLOW_DISSECTOR_KEY_BASIC,
+						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
 						  f->mask);
-		MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype,
-			 ntohs(mask->n_proto));
-		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype,
-			 ntohs(key->n_proto));
 
-		if (mask->n_proto)
+		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
+					     dmac_47_16),
+				mask->dst);
+		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
+					     dmac_47_16),
+				key->dst);
+
+		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
+					     smac_47_16),
+				mask->src);
+		ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
+					     smac_47_16),
+				key->src);
+
+		if (!is_zero_ether_addr(mask->src) || !is_zero_ether_addr(mask->dst))
 			*match_level = MLX5_MATCH_L2;
 	}
 
-- 
2.19.1

^ permalink raw reply related

* [net 02/13] net/mlx5e: IPoIB, Reset QP after channels are closed
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Denis Drozdov, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Denis Drozdov <denisd@mellanox.com>

The mlx5e channels should be closed before mlx5i_uninit_underlay_qp
puts the QP into RST (reset) state during mlx5i_close. Currently QP
state incorrectly set to RST before channels got deactivated and closed,
since mlx5_post_send request expects QP in RTS (Ready To Send) state.

The fix is to keep QP in RTS state until mlx5e channels get closed
and to reset QP afterwards.

Also this fix is simply correct in order to keep the open/close flow
symmetric, i.e mlx5i_init_underlay_qp() is called first thing at open,
the correct thing to do is to call mlx5i_uninit_underlay_qp() last thing
at close, which is exactly what this patch is doing.

Fixes: dae37456c8ac ("net/mlx5: Support for attaching multiple underlay QPs to root flow table")
Signed-off-by: Denis Drozdov <denisd@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
index b59953daf8b4..11dabd62e2c7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
@@ -560,9 +560,9 @@ static int mlx5i_close(struct net_device *netdev)
 
 	netif_carrier_off(epriv->netdev);
 	mlx5_fs_remove_rx_underlay_qpn(mdev, ipriv->qp.qpn);
-	mlx5i_uninit_underlay_qp(epriv);
 	mlx5e_deactivate_priv_channels(epriv);
 	mlx5e_close_channels(&epriv->channels);
+	mlx5i_uninit_underlay_qp(epriv);
 unlock:
 	mutex_unlock(&epriv->state_lock);
 	return 0;
-- 
2.19.1

^ permalink raw reply related

* [net 01/13] net/mlx5: IPSec, Fix the SA context hash key
From: Saeed Mahameed @ 2018-11-19 23:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Raed Salem, Saeed Mahameed
In-Reply-To: <20181119234128.6948-1-saeedm@mellanox.com>

From: Raed Salem <raeds@mellanox.com>

The commit "net/mlx5: Refactor accel IPSec code" introduced a
bug where asynchronous short time change in hash key value
by create/release SA context might happen during an asynchronous
hash resize operation this could cause a subsequent remove SA
context operation to fail as the key value used during resize is
not the same key value used when remove SA context operation is
invoked.

This commit fixes the bug by defining the SA context hash key
such that it includes only fields that never change during the
lifetime of the SA context object.

Fixes: d6c4f0298cec ("net/mlx5: Refactor accel IPSec code")
Signed-off-by: Raed Salem <raeds@mellanox.com>
Reviewed-by: Aviad Yehezkel <aviadye@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
index 515e3d6de051..5a22c5874f3b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/ipsec.c
@@ -83,8 +83,14 @@ struct mlx5_fpga_ipsec_rule {
 };
 
 static const struct rhashtable_params rhash_sa = {
-	.key_len = FIELD_SIZEOF(struct mlx5_fpga_ipsec_sa_ctx, hw_sa),
-	.key_offset = offsetof(struct mlx5_fpga_ipsec_sa_ctx, hw_sa),
+	/* Keep out "cmd" field from the key as it's
+	 * value is not constant during the lifetime
+	 * of the key object.
+	 */
+	.key_len = FIELD_SIZEOF(struct mlx5_fpga_ipsec_sa_ctx, hw_sa) -
+		   FIELD_SIZEOF(struct mlx5_ifc_fpga_ipsec_sa_v1, cmd),
+	.key_offset = offsetof(struct mlx5_fpga_ipsec_sa_ctx, hw_sa) +
+		      FIELD_SIZEOF(struct mlx5_ifc_fpga_ipsec_sa_v1, cmd),
 	.head_offset = offsetof(struct mlx5_fpga_ipsec_sa_ctx, hash),
 	.automatic_shrinking = true,
 	.min_size = 1,
-- 
2.19.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox