Netdev List
 help / color / mirror / Atom feed
* [patch iproute2 v7 2/2] tc: Add batchsize feature for filter and actions
From: Chris Mi @ 2018-01-09  6:59 UTC (permalink / raw)
  To: netdev; +Cc: gerlitz.or, stephen, dsahern, marcelo.leitner, phil
In-Reply-To: <20180109065908.19754-1-chrism@mellanox.com>

Currently in tc batch mode, only one command is read from the batch
file and sent to kernel to process. With this support, at most 128
commands can be accumulated before sending to kernel.

Now it only works for the following successive commands:
filter and actions add/delete/change/replace.

Signed-off-by: Chris Mi <chrism@mellanox.com>
---
 tc/m_action.c  |  60 +++++++++++++++++----------
 tc/tc.c        | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 tc/tc_common.h |   5 ++-
 tc/tc_filter.c |  97 +++++++++++++++++++++++++------------------
 4 files changed, 210 insertions(+), 79 deletions(-)

diff --git a/tc/m_action.c b/tc/m_action.c
index fc422364..e5c53a80 100644
--- a/tc/m_action.c
+++ b/tc/m_action.c
@@ -546,40 +546,56 @@ bad_val:
 	return ret;
 }
 
+struct tc_action_req {
+	struct nlmsghdr		n;
+	struct tcamsg		t;
+	char			buf[MAX_MSG];
+};
+
 static int tc_action_modify(int cmd, unsigned int flags,
-			    int *argc_p, char ***argv_p)
+			    int *argc_p, char ***argv_p,
+			    void *buf)
 {
-	int argc = *argc_p;
+	struct tc_action_req *req, action_req;
 	char **argv = *argv_p;
+	struct rtattr *tail;
+	int argc = *argc_p;
+	struct iovec iov;
 	int ret = 0;
-	struct {
-		struct nlmsghdr         n;
-		struct tcamsg           t;
-		char                    buf[MAX_MSG];
-	} req = {
-		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)),
-		.n.nlmsg_flags = NLM_F_REQUEST | flags,
-		.n.nlmsg_type = cmd,
-		.t.tca_family = AF_UNSPEC,
-	};
-	struct rtattr *tail = NLMSG_TAIL(&req.n);
+
+	if (buf)
+		req = buf;
+	else
+		req = &action_req;
+
+	req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg));
+	req->n.nlmsg_flags = NLM_F_REQUEST | flags;
+	req->n.nlmsg_type = cmd;
+	req->t.tca_family = AF_UNSPEC;
+	tail = NLMSG_TAIL(&req->n);
 
 	argc -= 1;
 	argv += 1;
-	if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) {
+	if (parse_action(&argc, &argv, TCA_ACT_TAB, &req->n)) {
 		fprintf(stderr, "Illegal \"action\"\n");
 		return -1;
 	}
-	tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
+	tail->rta_len = (void *) NLMSG_TAIL(&req->n) - (void *) tail;
+
+	*argc_p = argc;
+	*argv_p = argv;
 
-	if (rtnl_talk(&rth, &req.n, NULL) < 0) {
+	iov.iov_base = &req->n;
+	iov.iov_len = req->n.nlmsg_len;
+
+	if (buf)
+		return 0;
+
+	if (rtnl_talk_iov(&rth, &iov, 1, NULL) < 0) {
 		fprintf(stderr, "We have an error talking to the kernel\n");
 		ret = -1;
 	}
 
-	*argc_p = argc;
-	*argv_p = argv;
-
 	return ret;
 }
 
@@ -679,7 +695,7 @@ bad_val:
 	return ret;
 }
 
-int do_action(int argc, char **argv)
+int do_action(int argc, char **argv, void *buf)
 {
 
 	int ret = 0;
@@ -689,12 +705,12 @@ int do_action(int argc, char **argv)
 		if (matches(*argv, "add") == 0) {
 			ret =  tc_action_modify(RTM_NEWACTION,
 						NLM_F_EXCL | NLM_F_CREATE,
-						&argc, &argv);
+						&argc, &argv, buf);
 		} else if (matches(*argv, "change") == 0 ||
 			  matches(*argv, "replace") == 0) {
 			ret = tc_action_modify(RTM_NEWACTION,
 					       NLM_F_CREATE | NLM_F_REPLACE,
-					       &argc, &argv);
+					       &argc, &argv, buf);
 		} else if (matches(*argv, "delete") == 0) {
 			argc -= 1;
 			argv += 1;
diff --git a/tc/tc.c b/tc/tc.c
index ad9f07e9..f32e4978 100644
--- a/tc/tc.c
+++ b/tc/tc.c
@@ -193,16 +193,16 @@ static void usage(void)
 			"                    -nm | -nam[es] | { -cf | -conf } path } | -j[son]\n");
 }
 
-static int do_cmd(int argc, char **argv)
+static int do_cmd(int argc, char **argv, void *buf)
 {
 	if (matches(*argv, "qdisc") == 0)
 		return do_qdisc(argc-1, argv+1);
 	if (matches(*argv, "class") == 0)
 		return do_class(argc-1, argv+1);
 	if (matches(*argv, "filter") == 0)
-		return do_filter(argc-1, argv+1);
+		return do_filter(argc-1, argv+1, buf);
 	if (matches(*argv, "actions") == 0)
-		return do_action(argc-1, argv+1);
+		return do_action(argc-1, argv+1, buf);
 	if (matches(*argv, "monitor") == 0)
 		return do_tcmonitor(argc-1, argv+1);
 	if (matches(*argv, "exec") == 0)
@@ -217,11 +217,39 @@ static int do_cmd(int argc, char **argv)
 	return -1;
 }
 
+static bool batchsize_enabled(int argc, char *argv[])
+{
+	if (argc < 2)
+		return false;
+	if ((strcmp(argv[0], "filter") && strcmp(argv[0], "action"))
+	    || (strcmp(argv[1], "add") && strcmp(argv[1], "delete")
+	    && strcmp(argv[1], "change") && strcmp(argv[1], "replace")))
+		return false;
+
+	return true;
+}
+
+struct batch_buf {
+	struct batch_buf	*next;
+	char			buf[16420];	/* sizeof (struct nlmsghdr) +
+						   sizeof (struct tcmsg) +
+						   MAX_MSG */
+};
+
 static int batch(const char *name)
 {
-	char *line = NULL;
+	struct batch_buf *head = NULL, *tail = NULL, *buf;
+	char *largv[100], *largv_next[100];
+	char *line, *line_next = NULL;
+	bool bs_enabled_next = false;
+	bool bs_enabled = false;
+	bool lastline = false;
+	int largc, largc_next;
+	bool bs_enabled_saved;
+	int batchsize = 0;
 	size_t len = 0;
-	int ret = 0;
+	int ret = 0, i;
+	bool send;
 
 	batch_mode = 1;
 	if (name && strcmp(name, "-") != 0) {
@@ -240,23 +268,92 @@ static int batch(const char *name)
 	}
 
 	cmdlineno = 0;
-	while (getcmdline(&line, &len, stdin) != -1) {
-		char *largv[100];
-		int largc;
+	if (getcmdline(&line, &len, stdin) == -1)
+		goto Exit;
+	largc = makeargs(line, largv, 100);
+	bs_enabled = batchsize_enabled(largc, largv);
+	bs_enabled_saved = bs_enabled;
+	do {
+		if (getcmdline(&line_next, &len, stdin) == -1)
+			lastline = true;
+
+		largc_next = makeargs(line_next, largv_next, 100);
+		bs_enabled_next = batchsize_enabled(largc_next, largv_next);
+		if (bs_enabled) {
+			buf = calloc(1, sizeof (struct batch_buf));
+			if (head == NULL) {
+				head = tail = buf;
+				buf->next = NULL;
+			} else {
+				buf->next = NULL;
+				tail->next = buf;
+				tail = buf;
+			}
+			++batchsize;
+		}
+
+		/*
+		 * In batch mode, if we haven't accumulated enough commands
+		 * and this is not the last command and this command & next
+		 * command both support the batchsize feature, don't send the
+		 * message immediately.
+		 */
+		if (!lastline && bs_enabled && bs_enabled_next
+		    && batchsize != MSG_IOV_MAX)
+			send = false;
+		else
+			send = true;
+
+		line = line_next;
+		line_next = NULL;
+		len = 0;
+		bs_enabled_saved = bs_enabled;
+		bs_enabled = bs_enabled_next;
+		bs_enabled_next = false;
 
-		largc = makeargs(line, largv, 100);
 		if (largc == 0)
 			continue;	/* blank line */
 
-		if (do_cmd(largc, largv)) {
-			fprintf(stderr, "Command failed %s:%d\n", name, cmdlineno);
+		ret = do_cmd(largc, largv, tail == NULL ? NULL : tail->buf);
+		if (ret != 0) {
+			fprintf(stderr, "Command failed %s:%d\n", name,
+				cmdlineno - 1);
 			ret = 1;
 			if (!force)
 				break;
 		}
-	}
-	if (line)
-		free(line);
+		largc = largc_next;
+		for (i = 0; i < largc; i ++)
+			largv[i] = largv_next[i];
+
+		if (send && bs_enabled_saved) {
+			struct iovec *iov, *iovs;
+			struct nlmsghdr *n;
+			iov = iovs = malloc(batchsize * sizeof (struct iovec));
+			for (buf = head; buf != NULL; buf = buf->next, ++iov) {
+				n = (struct nlmsghdr *)&buf->buf;
+				iov->iov_base = n;
+				iov->iov_len = n->nlmsg_len;
+			}
+
+			ret = rtnl_talk_iov(&rth, iovs, batchsize, NULL);
+			if (ret < 0) {
+				fprintf(stderr, "Command failed %s:%d\n", name,
+					cmdlineno - (batchsize + ret) - 1);
+				return 2;
+			}
+			for (buf = head; buf != NULL; buf = head) {
+				head = buf->next;
+				free(buf);
+			}
+			head = tail = NULL;
+			batchsize = 0;
+			free(iovs);
+		}
+	} while (!lastline);
+
+Exit:
+	free(line);
 
 	rtnl_close(&rth);
 	return ret;
@@ -341,7 +438,7 @@ int main(int argc, char **argv)
 		goto Exit;
 	}
 
-	ret = do_cmd(argc-1, argv+1);
+	ret = do_cmd(argc-1, argv+1, NULL);
 Exit:
 	rtnl_close(&rth);
 
diff --git a/tc/tc_common.h b/tc/tc_common.h
index 264fbdac..59018da5 100644
--- a/tc/tc_common.h
+++ b/tc/tc_common.h
@@ -1,13 +1,14 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 
 #define TCA_BUF_MAX	(64*1024)
+#define MSG_IOV_MAX	128
 
 extern struct rtnl_handle rth;
 
 extern int do_qdisc(int argc, char **argv);
 extern int do_class(int argc, char **argv);
-extern int do_filter(int argc, char **argv);
-extern int do_action(int argc, char **argv);
+extern int do_filter(int argc, char **argv, void *buf);
+extern int do_action(int argc, char **argv, void *buf);
 extern int do_tcmonitor(int argc, char **argv);
 extern int do_exec(int argc, char **argv);
 
diff --git a/tc/tc_filter.c b/tc/tc_filter.c
index 545cc3a1..7db4964b 100644
--- a/tc/tc_filter.c
+++ b/tc/tc_filter.c
@@ -42,28 +42,38 @@ static void usage(void)
 		"OPTIONS := ... try tc filter add <desired FILTER_KIND> help\n");
 }
 
-static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
+struct tc_filter_req {
+	struct nlmsghdr		n;
+	struct tcmsg		t;
+	char			buf[MAX_MSG];
+};
+
+static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv,
+			    void *buf)
 {
-	struct {
-		struct nlmsghdr	n;
-		struct tcmsg		t;
-		char			buf[MAX_MSG];
-	} req = {
-		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
-		.n.nlmsg_flags = NLM_F_REQUEST | flags,
-		.n.nlmsg_type = cmd,
-		.t.tcm_family = AF_UNSPEC,
-	};
+	struct tc_filter_req *req, filter_req;
 	struct filter_util *q = NULL;
-	__u32 prio = 0;
-	__u32 protocol = 0;
-	int protocol_set = 0;
-	__u32 chain_index;
+	struct tc_estimator est = {};
+	char k[FILTER_NAMESZ] = {};
 	int chain_index_set = 0;
+	char d[IFNAMSIZ] = {};
+	int protocol_set = 0;
 	char *fhandle = NULL;
-	char  d[IFNAMSIZ] = {};
-	char  k[FILTER_NAMESZ] = {};
-	struct tc_estimator est = {};
+	__u32 protocol = 0;
+	__u32 chain_index;
+	struct iovec iov;
+	__u32 prio = 0;
+	int ret;
+
+	if (buf)
+		req = buf;
+	else
+		req = &filter_req;
+
+	req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
+	req->n.nlmsg_flags = NLM_F_REQUEST | flags;
+	req->n.nlmsg_type = cmd;
+	req->t.tcm_family = AF_UNSPEC;
 
 	if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE)
 		protocol = htons(ETH_P_ALL);
@@ -75,37 +85,37 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
 				duparg("dev", *argv);
 			strncpy(d, *argv, sizeof(d)-1);
 		} else if (strcmp(*argv, "root") == 0) {
-			if (req.t.tcm_parent) {
+			if (req->t.tcm_parent) {
 				fprintf(stderr,
 					"Error: \"root\" is duplicate parent ID\n");
 				return -1;
 			}
-			req.t.tcm_parent = TC_H_ROOT;
+			req->t.tcm_parent = TC_H_ROOT;
 		} else if (strcmp(*argv, "ingress") == 0) {
-			if (req.t.tcm_parent) {
+			if (req->t.tcm_parent) {
 				fprintf(stderr,
 					"Error: \"ingress\" is duplicate parent ID\n");
 				return -1;
 			}
-			req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
+			req->t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
 						     TC_H_MIN_INGRESS);
 		} else if (strcmp(*argv, "egress") == 0) {
-			if (req.t.tcm_parent) {
+			if (req->t.tcm_parent) {
 				fprintf(stderr,
 					"Error: \"egress\" is duplicate parent ID\n");
 				return -1;
 			}
-			req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
+			req->t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
 						     TC_H_MIN_EGRESS);
 		} else if (strcmp(*argv, "parent") == 0) {
 			__u32 handle;
 
 			NEXT_ARG();
-			if (req.t.tcm_parent)
+			if (req->t.tcm_parent)
 				duparg("parent", *argv);
 			if (get_tc_classid(&handle, *argv))
 				invarg("Invalid parent ID", *argv);
-			req.t.tcm_parent = handle;
+			req->t.tcm_parent = handle;
 		} else if (strcmp(*argv, "handle") == 0) {
 			NEXT_ARG();
 			if (fhandle)
@@ -152,26 +162,26 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
 		argc--; argv++;
 	}
 
-	req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
+	req->t.tcm_info = TC_H_MAKE(prio<<16, protocol);
 
 	if (chain_index_set)
-		addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
+		addattr32(&req->n, sizeof(*req), TCA_CHAIN, chain_index);
 
 	if (k[0])
-		addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
+		addattr_l(&req->n, sizeof(*req), TCA_KIND, k, strlen(k)+1);
 
 	if (d[0])  {
 		ll_init_map(&rth);
 
-		req.t.tcm_ifindex = ll_name_to_index(d);
-		if (req.t.tcm_ifindex == 0) {
+		req->t.tcm_ifindex = ll_name_to_index(d);
+		if (req->t.tcm_ifindex == 0) {
 			fprintf(stderr, "Cannot find device \"%s\"\n", d);
 			return 1;
 		}
 	}
 
 	if (q) {
-		if (q->parse_fopt(q, fhandle, argc, argv, &req.n))
+		if (q->parse_fopt(q, fhandle, argc, argv, &req->n))
 			return 1;
 	} else {
 		if (fhandle) {
@@ -190,10 +200,17 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
 	}
 
 	if (est.ewma_log)
-		addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));
+		addattr_l(&req->n, sizeof(*req), TCA_RATE, &est, sizeof(est));
 
-	if (rtnl_talk(&rth, &req.n, NULL) < 0) {
-		fprintf(stderr, "We have an error talking to the kernel\n");
+	iov.iov_base = &req->n;
+	iov.iov_len = req->n.nlmsg_len;
+
+	if (buf)
+		return 0;
+
+	ret = rtnl_talk_iov(&rth, &iov, 1, NULL);
+	if (ret < 0) {
+		fprintf(stderr, "We have an error talking to the kernel, %d\n", ret);
 		return 2;
 	}
 
@@ -636,20 +653,20 @@ static int tc_filter_list(int argc, char **argv)
 	return 0;
 }
 
-int do_filter(int argc, char **argv)
+int do_filter(int argc, char **argv, void *buf)
 {
 	if (argc < 1)
 		return tc_filter_list(0, NULL);
 	if (matches(*argv, "add") == 0)
 		return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE,
-					argc-1, argv+1);
+					argc-1, argv+1, buf);
 	if (matches(*argv, "change") == 0)
-		return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1);
+		return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1, buf);
 	if (matches(*argv, "replace") == 0)
 		return tc_filter_modify(RTM_NEWTFILTER, NLM_F_CREATE, argc-1,
-					argv+1);
+					argv+1, buf);
 	if (matches(*argv, "delete") == 0)
-		return tc_filter_modify(RTM_DELTFILTER, 0,  argc-1, argv+1);
+		return tc_filter_modify(RTM_DELTFILTER, 0, argc-1, argv+1, buf);
 	if (matches(*argv, "get") == 0)
 		return tc_filter_get(RTM_GETTFILTER, 0,  argc-1, argv+1);
 	if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
-- 
2.14.3

^ permalink raw reply related

* Re: [PATCH net-next 1/3] ethtool: Ensure new ring parameters are within bounds during SRINGPARAM
From: Tariq Toukan @ 2018-01-09  7:30 UTC (permalink / raw)
  To: Jakub Kicinski, Tariq Toukan
  Cc: David S. Miller, netdev, Eran Ben Elisha, Eugenia Emantayev
In-Reply-To: <20180108182342.084c5d60@cakuba.netronome.com>



On 09/01/2018 4:23 AM, Jakub Kicinski wrote:
> On Mon,  8 Jan 2018 16:00:24 +0200, Tariq Toukan wrote:
>> From: Eugenia Emantayev <eugenia@mellanox.com>
>>
>> Add a sanity check to ensure that all requested ring parameters
>> are within bounds, which should reduce errors in driver implementation.
> 
> (y)
> 
>> Signed-off-by: Eugenia Emantayev <eugenia@mellanox.com>
>> Signed-off-by: Tariq Toukan <tariqt@mellanox.com>
>> ---
>>   net/core/ethtool.c | 13 +++++++++++--
>>   1 file changed, 11 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/core/ethtool.c b/net/core/ethtool.c
>> index 50a79203043b..9ea7cd52fde0 100644
>> --- a/net/core/ethtool.c
>> +++ b/net/core/ethtool.c
>> @@ -1704,14 +1704,23 @@ static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
>>   
>>   static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr)
>>   {
>> -	struct ethtool_ringparam ringparam;
>> +	struct ethtool_ringparam ringparam, max = { .cmd = ETHTOOL_GRINGPARAM };
>>   
>> -	if (!dev->ethtool_ops->set_ringparam)
>> +	if (!dev->ethtool_ops->set_ringparam || !dev->ethtool_ops->get_ringparam)
>>   		return -EOPNOTSUPP;
>>   
>>   	if (copy_from_user(&ringparam, useraddr, sizeof(ringparam)))
>>   		return -EFAULT;
>>   
>> +	dev->ethtool_ops->get_ringparam(dev, &max);
> 
> Perhaps check the return value here?  It's pretty unlikely but
> get_ringparam may fail.
> 

get_ringparam NDO returns void.

>> +	/* ensure new ring parameters are within the maximums */
>> +	if (ringparam.rx_pending > max.rx_max_pending ||
>> +	    ringparam.rx_mini_pending > max.rx_mini_max_pending ||
>> +	    ringparam.rx_jumbo_pending > max.rx_jumbo_max_pending ||
>> +	    ringparam.tx_pending > max.tx_max_pending)
>> +		return -EINVAL;
>> +
>>   	return dev->ethtool_ops->set_ringparam(dev, &ringparam);
>>   }
>>   

^ permalink raw reply

* Re: [PATCH] ath9k: add a quirk to set use_msi automatically
From: Kalle Valo @ 2018-01-09  7:29 UTC (permalink / raw)
  To: AceLan Kao, Larry.Finger
  Cc: QCA ath9k Development, linux-wireless, netdev, linux-kernel
In-Reply-To: <1515461962-27129-1-git-send-email-acelan.kao@canonical.com>

AceLan Kao <acelan.kao@canonical.com> writes:

> Some platform(BIOS) blocks legacy interrupts (INTx), and only allows MSI
> for WLAN device. So adding a quirk to list those machines and set
> use_msi automatically.
> Adding the following platforms to the quirk.
>    Dell Inspiron 24-3460
>    Dell Inspiron 3472
>    Dell Inspiron 14-3473
>    Dell Vostro 3262
>    Dell Vostro 15-3572
>
> Signed-off-by: AceLan Kao <acelan.kao@canonical.com>

[...]

> @@ -96,6 +97,56 @@ static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = {
>  };
>  #endif
>  
> +static int __init set_use_msi(const struct dmi_system_id *dmi)
> +{
> +	ath9k_use_msi = 1;
> +	return 1;
> +}
> +
> +static const struct dmi_system_id ath9k_quirks[] __initconst = {
> +	{
> +		.callback = set_use_msi,
> +		.ident = "Dell Inspiron 24-3460",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 24-3460"),
> +		},
> +	},

Larry, didn't rtlwifi have similar situation that with certain laptops
users were required to enable a module parameter to get the device
working? I think rtlwifi should do the same as AceLan does here as then
the user would not need to manually set the module parameter.

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCH net-next v3 06/10] net/mlx5e: Change Mellanox references in DIM code
From: Saeed Mahameed @ 2018-01-09  7:09 UTC (permalink / raw)
  To: Andy Gospodarek, netdev; +Cc: mchan, talgi, ogerlitz, Andy Gospodarek
In-Reply-To: <47ddff01-23f9-5364-0dd4-b7c921512812@mellanox.com>



On 01/08/2018 11:06 PM, Saeed Mahameed wrote:
> 
> 
> On 01/08/2018 10:13 PM, Andy Gospodarek wrote:
>> From: Andy Gospodarek <gospo@broadcom.com>
>>
>> Change all appropriate mlx5_am* and MLX5_AM* references to net_dim and
>> NET_DIM, respectively, in code that handles dynamic interrupt
>> moderation.  Also change all references from 'am' to 'dim' when used as
>> local variables and add generic profile references.
>>
>> Signed-off-by: Andy Gospodarek <gospo@broadcom.com>
>> Acked-by: Tal Gilboa <talgi@mellanox.com>
>> Acked-by: Saeed Mahameed <saeedm@mellanox.com>
>> ---
>>   drivers/net/ethernet/mellanox/mlx5/core/en.h       |   9 +-
>>   drivers/net/ethernet/mellanox/mlx5/core/en_dim.c   |  14 +-
>>   .../net/ethernet/mellanox/mlx5/core/en_ethtool.c   |   6 +-
>>   drivers/net/ethernet/mellanox/mlx5/core/en_main.c  |  40 ++-
>>   drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c  |   8 +-
>>   drivers/net/ethernet/mellanox/mlx5/core/net_dim.c  | 286 
>> ++++++++++-----------
>>   drivers/net/ethernet/mellanox/mlx5/core/net_dim.h  |  63 ++---
>>   7 files changed, 225 insertions(+), 201 deletions(-)
>>
> 
> [...]
> 
>>   #define IS_SIGNIFICANT_DIFF(val, ref) \
>>       (((100 * abs((val) - (ref))) / (ref)) > 10) /* more than 10% 
>> difference */
>> -static int mlx5e_am_stats_compare(struct mlx5e_rx_am_stats *curr,
>> -                  struct mlx5e_rx_am_stats *prev)
>> +static int net_dim_stats_compare(struct net_dim_stats *curr,
>> +                 struct net_dim_stats *prev)
>>   {
>>       if (!prev->bpms)
>> -        return curr->bpms ? MLX5E_AM_STATS_BETTER :
>> -                    MLX5E_AM_STATS_SAME;
>> +        return curr->bpms ? NET_DIM_STATS_BETTER :
>> +                    NET_DIM_STATS_SAME;
>>       if (IS_SIGNIFICANT_DIFF(curr->bpms, prev->bpms))
>> -        return (curr->bpms > prev->bpms) ? MLX5E_AM_STATS_BETTER :
>> -                           MLX5E_AM_STATS_WORSE;
>> +        return (curr->bpms > prev->bpms) ? NET_DIM_STATS_BETTER :
>> +                           NET_DIM_STATS_WORSE;
> 
> Hey Andy,
> 
> I am currently reviewing a patch internally that fixes a bug in this 
> area, prev->ppms can be 0 and could cause IS_SIGNIFICANT_DIFF ouch !

I meant cause division by 0 in "IS_SIGNIFICANT_DIFF"

> same goes for prev->eppm, for some reason we had a broken assumption 
> that if ppms is 0 for some reason then the bpms is 0 and the above 
> condition will cover us.
> 
> Anyway the patch will go to net, which means when this series gets 
> accepted then net-next will fail to merge with net and we need to 
> manually push the fix to the new DIM library.
> 
> But for now I don't think anything is required for this series other 
> than bringing this division by 0 issue and the future merge conflict to 
> your attention.
> 
>>       if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms))
>> -        return (curr->ppms > prev->ppms) ? MLX5E_AM_STATS_BETTER :
>> -                           MLX5E_AM_STATS_WORSE;
>> +        return (curr->ppms > prev->ppms) ? NET_DIM_STATS_BETTER :
>> +                           NET_DIM_STATS_WORSE;
>>       if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms))
>> -        return (curr->epms < prev->epms) ? MLX5E_AM_STATS_BETTER :
>> -                           MLX5E_AM_STATS_WORSE;
>> +        return (curr->epms < prev->epms) ? NET_DIM_STATS_BETTER :
>> +                           NET_DIM_STATS_WORSE;
>> -    return MLX5E_AM_STATS_SAME;
>> +    return NET_DIM_STATS_SAME;
>>   }

^ permalink raw reply

* Re: [PATCH net-next v3 09/10] bnxt_en: add support for software dynamic interrupt moderation
From: Michael Chan @ 2018-01-09  7:07 UTC (permalink / raw)
  To: Andy Gospodarek
  Cc: Netdev, michael.chan@broadcom.com, talgi, ogerlitz,
	Andy Gospodarek
In-Reply-To: <1515478402-6048-10-git-send-email-andy@greyhouse.net>

On Mon, Jan 8, 2018 at 10:13 PM, Andy Gospodarek <andy@greyhouse.net> wrote:
> From: Andy Gospodarek <gospo@broadcom.com>
>
> This implements the changes needed for the bnxt_en driver to add support
> for dynamic interrupt moderation per ring.
>
> This does add additional counters in the receive path, but testing shows
> that any additional instructions are offset by throughput gain when the
> default configuration is for low latency.
>
> Signed-off-by: Andy Gospodarek <gospo@broadcom.com>
> Cc: Michael Chan <mchan@broadcom.com>

Acked-by: Michael Chan <michael.chan@broadcom.com>

^ permalink raw reply

* Re: [PATCH net-next v3 06/10] net/mlx5e: Change Mellanox references in DIM code
From: Saeed Mahameed @ 2018-01-09  7:06 UTC (permalink / raw)
  To: Andy Gospodarek, netdev; +Cc: mchan, talgi, ogerlitz, Andy Gospodarek
In-Reply-To: <1515478402-6048-7-git-send-email-andy@greyhouse.net>



On 01/08/2018 10:13 PM, Andy Gospodarek wrote:
> From: Andy Gospodarek <gospo@broadcom.com>
> 
> Change all appropriate mlx5_am* and MLX5_AM* references to net_dim and
> NET_DIM, respectively, in code that handles dynamic interrupt
> moderation.  Also change all references from 'am' to 'dim' when used as
> local variables and add generic profile references.
> 
> Signed-off-by: Andy Gospodarek <gospo@broadcom.com>
> Acked-by: Tal Gilboa <talgi@mellanox.com>
> Acked-by: Saeed Mahameed <saeedm@mellanox.com>
> ---
>   drivers/net/ethernet/mellanox/mlx5/core/en.h       |   9 +-
>   drivers/net/ethernet/mellanox/mlx5/core/en_dim.c   |  14 +-
>   .../net/ethernet/mellanox/mlx5/core/en_ethtool.c   |   6 +-
>   drivers/net/ethernet/mellanox/mlx5/core/en_main.c  |  40 ++-
>   drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c  |   8 +-
>   drivers/net/ethernet/mellanox/mlx5/core/net_dim.c  | 286 ++++++++++-----------
>   drivers/net/ethernet/mellanox/mlx5/core/net_dim.h  |  63 ++---
>   7 files changed, 225 insertions(+), 201 deletions(-)
> 

[...]

>   
>   #define IS_SIGNIFICANT_DIFF(val, ref) \
>   	(((100 * abs((val) - (ref))) / (ref)) > 10) /* more than 10% difference */
>   
> -static int mlx5e_am_stats_compare(struct mlx5e_rx_am_stats *curr,
> -				  struct mlx5e_rx_am_stats *prev)
> +static int net_dim_stats_compare(struct net_dim_stats *curr,
> +				 struct net_dim_stats *prev)
>   {
>   	if (!prev->bpms)
> -		return curr->bpms ? MLX5E_AM_STATS_BETTER :
> -				    MLX5E_AM_STATS_SAME;
> +		return curr->bpms ? NET_DIM_STATS_BETTER :
> +				    NET_DIM_STATS_SAME;
>   
>   	if (IS_SIGNIFICANT_DIFF(curr->bpms, prev->bpms))
> -		return (curr->bpms > prev->bpms) ? MLX5E_AM_STATS_BETTER :
> -						   MLX5E_AM_STATS_WORSE;
> +		return (curr->bpms > prev->bpms) ? NET_DIM_STATS_BETTER :
> +						   NET_DIM_STATS_WORSE;
>   

Hey Andy,

I am currently reviewing a patch internally that fixes a bug in this 
area, prev->ppms can be 0 and could cause IS_SIGNIFICANT_DIFF ouch !
same goes for prev->eppm, for some reason we had a broken assumption 
that if ppms is 0 for some reason then the bpms is 0 and the above 
condition will cover us.

Anyway the patch will go to net, which means when this series gets 
accepted then net-next will fail to merge with net and we need to 
manually push the fix to the new DIM library.

But for now I don't think anything is required for this series other 
than bringing this division by 0 issue and the future merge conflict to 
your attention.

>   	if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms))
> -		return (curr->ppms > prev->ppms) ? MLX5E_AM_STATS_BETTER :
> -						   MLX5E_AM_STATS_WORSE;
> +		return (curr->ppms > prev->ppms) ? NET_DIM_STATS_BETTER :
> +						   NET_DIM_STATS_WORSE;
>   
>   	if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms))
> -		return (curr->epms < prev->epms) ? MLX5E_AM_STATS_BETTER :
> -						   MLX5E_AM_STATS_WORSE;
> +		return (curr->epms < prev->epms) ? NET_DIM_STATS_BETTER :
> +						   NET_DIM_STATS_WORSE;
>   
> -	return MLX5E_AM_STATS_SAME;
> +	return NET_DIM_STATS_SAME;
>   }
>   

^ permalink raw reply

* [patch iproute2 v7 1/2] lib/libnetlink: Add functions rtnl_talk_msg and rtnl_talk_iov
From: Chris Mi @ 2018-01-09  6:59 UTC (permalink / raw)
  To: netdev; +Cc: gerlitz.or, stephen, dsahern, marcelo.leitner, phil
In-Reply-To: <20180109065908.19754-1-chrism@mellanox.com>

rtnl_talk can only send a single message to kernel. Add two functions
rtnl_talk_msg and rtnl_talk_iov that can send multiple messages to kernel.
rtnl_talk_msg takes struct msghdr * as argument.
rtnl_talk_iov takes struct iovec * and iovlen as arguments.

Signed-off-by: Chris Mi <chrism@mellanox.com>
---
 include/libnetlink.h |  6 ++++
 lib/libnetlink.c     | 84 ++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 71 insertions(+), 19 deletions(-)

diff --git a/include/libnetlink.h b/include/libnetlink.h
index a4d83b9e..e9a63dbc 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -96,6 +96,12 @@ int rtnl_dump_filter_nc(struct rtnl_handle *rth,
 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 	      struct nlmsghdr **answer)
 	__attribute__((warn_unused_result));
+int rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
+		  struct nlmsghdr **answer)
+	__attribute__((warn_unused_result));
+int rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iovec, size_t iovlen,
+		  struct nlmsghdr **answer)
+	__attribute__((warn_unused_result));
 int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 	      struct nlmsghdr **answer, nl_ext_ack_fn_t errfn)
 	__attribute__((warn_unused_result));
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 00e6ce0c..ae0059f9 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -581,39 +581,43 @@ static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
 		strerror(-err->error));
 }
 
-static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
-		       struct nlmsghdr **answer,
-		       bool show_rtnl_err, nl_ext_ack_fn_t errfn)
+static int __rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
+			   struct nlmsghdr **answer,
+			   bool show_rtnl_err, nl_ext_ack_fn_t errfn)
 {
-	int status;
-	unsigned int seq;
-	struct nlmsghdr *h;
 	struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
-	struct iovec iov = {
-		.iov_base = n,
-		.iov_len = n->nlmsg_len
-	};
+	int i, status, iovlen = m->msg_iovlen;
+	struct iovec iov;
 	struct msghdr msg = {
 		.msg_name = &nladdr,
 		.msg_namelen = sizeof(nladdr),
 		.msg_iov = &iov,
 		.msg_iovlen = 1,
 	};
-	char *buf;
-
-	n->nlmsg_seq = seq = ++rtnl->seq;
+	unsigned int seq = 0;
+	struct nlmsghdr *h;
 
-	if (answer == NULL)
-		n->nlmsg_flags |= NLM_F_ACK;
+	for (i = 0; i < iovlen; i++) {
+		struct iovec *v;
+		v = &m->msg_iov[i];
+		h = v->iov_base;
+		h->nlmsg_seq = seq = ++rtnl->seq;
+		if (answer == NULL)
+			h->nlmsg_flags |= NLM_F_ACK;
+	}
 
-	status = sendmsg(rtnl->fd, &msg, 0);
+	status = sendmsg(rtnl->fd, m, 0);
 	if (status < 0) {
 		perror("Cannot talk to rtnetlink");
 		return -1;
 	}
 
+	i = 0;
 	while (1) {
+		char *buf;
+next:
 		status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
+		++i;
 
 		if (status < 0)
 			return status;
@@ -642,7 +646,7 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 
 			if (nladdr.nl_pid != 0 ||
 			    h->nlmsg_pid != rtnl->local.nl_pid ||
-			    h->nlmsg_seq != seq) {
+			    h->nlmsg_seq > seq || h->nlmsg_seq < seq - iovlen) {
 				/* Don't forget to skip that message. */
 				status -= NLMSG_ALIGN(len);
 				h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
@@ -662,7 +666,10 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 						*answer = (struct nlmsghdr *)buf;
 					else
 						free(buf);
-					return 0;
+					if (h->nlmsg_seq == seq)
+						return 0;
+					else
+						goto next;
 				}
 
 				if (rtnl->proto != NETLINK_SOCK_DIAG &&
@@ -671,7 +678,7 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 
 				errno = -err->error;
 				free(buf);
-				return -1;
+				return -i;
 			}
 
 			if (answer) {
@@ -698,12 +705,51 @@ static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 	}
 }
 
+static int __rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *msg_iov,
+			   size_t iovlen, struct nlmsghdr **answer,
+			   bool show_rtnl_err, nl_ext_ack_fn_t errfn)
+{
+	struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
+	struct msghdr msg = {
+		.msg_name = &nladdr,
+		.msg_namelen = sizeof(nladdr),
+		.msg_iov = msg_iov,
+		.msg_iovlen = iovlen,
+	};
+
+	return __rtnl_talk_msg(rtnl, &msg, answer, show_rtnl_err, errfn);
+}
+
+static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
+		       struct nlmsghdr **answer,
+		       bool show_rtnl_err, nl_ext_ack_fn_t errfn)
+{
+	struct iovec iov = {
+		.iov_base = n,
+		.iov_len = n->nlmsg_len
+	};
+
+	return __rtnl_talk_iov(rtnl, &iov, 1, answer, show_rtnl_err, errfn);
+}
+
 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 	      struct nlmsghdr **answer)
 {
 	return __rtnl_talk(rtnl, n, answer, true, NULL);
 }
 
+int rtnl_talk_msg(struct rtnl_handle *rtnl, struct msghdr *m,
+		  struct nlmsghdr **answer)
+{
+	return __rtnl_talk_msg(rtnl, m, answer, true, NULL);
+}
+
+int rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iovec, size_t iovlen,
+		  struct nlmsghdr **answer)
+{
+	return __rtnl_talk_iov(rtnl, iovec, iovlen, answer, true, NULL);
+}
+
 int rtnl_talk_extack(struct rtnl_handle *rtnl, struct nlmsghdr *n,
 		     struct nlmsghdr **answer,
 		     nl_ext_ack_fn_t errfn)
-- 
2.14.3

^ permalink raw reply related

* [patch iproute2 v7 0/2] tc: Add batchsize feature to batch mode
From: Chris Mi @ 2018-01-09  6:59 UTC (permalink / raw)
  To: netdev; +Cc: gerlitz.or, stephen, dsahern, marcelo.leitner, phil

Currently in tc batch mode, only one command is read from the batch
file and sent to kernel to process. With this patchset, at most 128
commands can be accumulated before sending to kernel.

We introduced two new functions in patch 1 to support for sending
multiple messages. In patch 2, we add this support for filter and
actions add/delete/change/replace commands.

But please note that kernel still processes the requests one by one.
To process the requests in parallel in kernel is another effort.
The time we're saving in this patchset is the user mode and kernel mode
context switch. So this patchset works on top of the current kernel.

Using the following script in kernel, we can generate 1,000,000 rules.
	tools/testing/selftests/tc-testing/tdc_batch.py

Without this patchset, 'tc -b $file' exection time is:

real    0m15.555s
user    0m7.211s
sys     0m8.284s

With this patchset, 'tc -b $file' exection time is:

real    0m13.562s
user    0m6.463s
sys     0m7.031s

The insertion rate is improved more than 10%.

v3
==
1. Instead of hacking function rtnl_talk directly, add a new function
   rtnl_talk_msg.
2. remove most of global variables to use parameter passing
3. divide the previous patch into 4 patches.

v4
==
1. Remove function setcmdlinetotal. Now in function batch, we read one
   more line to determine if we are reaching the end of file.
2. Remove function __rtnl_check_ack. Now __rtnl_talk calls __rtnl_talk_msg
   directly.
3. if (batch_size < 1)
        batch_size = 1;

v5
==
1. Fix a bug that can't deal with batch file with blank line.
2. Describe the limitation in man page.

v6
==
1. Add support for mixed commands.
2. Fix a bug that not all messages are acked if batch size > 1.

v7
==
1. We can tell exactly which command fails.
2. Add a new function rtnl_talk_iov
3. Allocate the memory in function batch() instead of each client.
4. Remove option -bs.


Chris Mi (2):
  lib/libnetlink: Add functions rtnl_talk_msg and rtnl_talk_iov
  tc: Add batchsize feature to batch mode

 include/libnetlink.h |   6 +++
 lib/libnetlink.c     |  84 ++++++++++++++++++++++++++--------
 tc/m_action.c        |  60 +++++++++++++++---------
 tc/tc.c              | 127 +++++++++++++++++++++++++++++++++++++++++++++------
 tc/tc_common.h       |   5 +-
 tc/tc_filter.c       |  97 +++++++++++++++++++++++----------------
 6 files changed, 281 insertions(+), 98 deletions(-)

-- 
2.14.3

^ permalink raw reply

* Re: [PATCH net-next v3 00/10] net: create dynamic software irq moderation library
From: Tal Gilboa @ 2018-01-09  6:54 UTC (permalink / raw)
  To: Andy Gospodarek, netdev; +Cc: mchan, ogerlitz, Andy Gospodarek
In-Reply-To: <1515478402-6048-1-git-send-email-andy@greyhouse.net>

On 1/9/2018 8:13 AM, Andy Gospodarek wrote:
> From: Andy Gospodarek <gospo@broadcom.com>
> 
> This converts the dynamic interrupt moderation library from the mlx5e
> driver into a library so it can be used by any driver.  The penultimate
> patch in this set adds support for thiw new dynamic interrupt moderation
> library in the bnxt_en driver and the last patch creates an entry in the
> MAINTAINERS file for this library.

thiw->this.

^ permalink raw reply

* [PATCH net-next 2/2] net: hns3: report the function type the same line with hns3_nic_get_stats64
From: Peng Li @ 2018-01-09  6:50 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-kernel, linuxarm, salil.mehta, lipeng321
In-Reply-To: <1515480659-119303-1-git-send-email-lipeng321@huawei.com>

The function type should be on the same line with the function
name, or it may cause display error if a patch edit the
function. There is am example following:
https://www.spinics.net/lists/netdev/msg476141.html

Signed-off-by: Peng Li <lipeng321@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index b23107d..14c7625 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -1126,8 +1126,8 @@ static int hns3_nic_set_features(struct net_device *netdev,
 	return 0;
 }
 
-static void
-hns3_nic_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
+static void hns3_nic_get_stats64(struct net_device *netdev,
+				 struct rtnl_link_stats64 *stats)
 {
 	struct hns3_nic_priv *priv = netdev_priv(netdev);
 	int queue_num = priv->ae_handle->kinfo.num_tqps;
-- 
1.9.1

^ permalink raw reply related

* [PATCH net-next 0/2] code improvements in HNS3 driver
From: Peng Li @ 2018-01-09  6:50 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-kernel, linuxarm, salil.mehta, lipeng321

This patchset fixes 2 comments for community review.
[patch 1/2] reverts "net: hns3: Add packet statistics of netdev"
reported by Jakub Kicinski and David Miller.
[patch 2/2] reports the function type the same line with
hns3_nic_get_stats64, reported by Andrew Lunn.

Peng Li (2):
  Revert "net: hns3: Add packet statistics of netdev"
  net: hns3: report the function type the same line with
    hns3_nic_get_stats64

 drivers/net/ethernet/hisilicon/hns3/hns3_enet.c    |  4 +-
 drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 80 +---------------------
 2 files changed, 3 insertions(+), 81 deletions(-)

-- 
1.9.1

^ permalink raw reply

* [PATCH] ipvlan: fix ipvlan MTU limits
From: liuqifa @ 2018-01-09  6:48 UTC (permalink / raw)
  To: davem, dsahern, maheshb, mschiffer, idosch, fw, kjlx,
	girish.moodalbail, sainath.grandhi
  Cc: netdev

From: Keefe Liu <liuqifa@huawei.com>

The MTU of ipvlan interface should not bigger than the phy device, When we
run following scripts, we will find there are some problems.
Step1:
	ip link add link eth0 name ipv1 type ipvlan mode l2
	ip netns add net1
	ip link set dev ipv1 netns net1
Step2:
	ip netns exec net1 ip link set dev ipv1 mtu 1501
	RTNETLINK answers: Invalid argument
	dmesg info: "ipv1: Invalid MTU 1501 requested, hw max 1500"
Step3:
	ip link set dev eth0 mtu 1600
	ip netns exec net1 ip link set dev ipv1 mtu 1501
	RTNETLINK answers: Invalid argument
	dmesg info: "ipv1: Invalid MTU 1501 requested, hw max 1500"
Step4:
	ip link set dev eth0 mtu 1400
	ip netns exec net1 ip link set dev ipv1 mtu 1500
The result of Step2 is we expected, but the result of Step3 and Step4
are not.

This patch set ipvlan's maximum MTU to ETH_MAX_MTU, and when we change
the ipvlan device's MTU, ipvlan_change_mtu() will make sure the new MTU
no larger than the phy device's MTU.

Signed-off-by: Keefe Liu <liuqifa@huawei.com>
---
 drivers/net/ipvlan/ipvlan_main.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index 30cb803..84c007d 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -380,12 +380,24 @@ static int ipvlan_get_iflink(const struct net_device *dev)
 	return ipvlan->phy_dev->ifindex;
 }
 
+static int ipvlan_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct ipvl_dev *ipvlan = netdev_priv(dev);
+
+	if (ipvlan->phy_dev->mtu < new_mtu)
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+
 static const struct net_device_ops ipvlan_netdev_ops = {
 	.ndo_init		= ipvlan_init,
 	.ndo_uninit		= ipvlan_uninit,
 	.ndo_open		= ipvlan_open,
 	.ndo_stop		= ipvlan_stop,
 	.ndo_start_xmit		= ipvlan_start_xmit,
+	.ndo_change_mtu		= ipvlan_change_mtu,
 	.ndo_fix_features	= ipvlan_fix_features,
 	.ndo_change_rx_flags	= ipvlan_change_rx_flags,
 	.ndo_set_rx_mode	= ipvlan_set_multicast_mac_filter,
@@ -680,6 +692,8 @@ void ipvlan_link_setup(struct net_device *dev)
 {
 	ether_setup(dev);
 
+	dev->min_mtu = 0;
+	dev->max_mtu = ETH_MAX_MTU;
 	dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
 	dev->priv_flags |= IFF_UNICAST_FLT | IFF_NO_QUEUE;
 	dev->netdev_ops = &ipvlan_netdev_ops;
-- 
1.8.3.1

^ permalink raw reply related

* RE: [patch iproute2 v6 2/3] tc: Add -bs option to batch mode
From: Chris Mi @ 2018-01-09  6:45 UTC (permalink / raw)
  To: Marcelo Ricardo Leitner, David Ahern
  Cc: netdev@vger.kernel.org, gerlitz.or@gmail.com,
	stephen@networkplumber.org
In-Reply-To: <20180105191445.GG725@localhost.localdomain>

> -----Original Message-----
> From: Marcelo Ricardo Leitner [mailto:marcelo.leitner@gmail.com]
> Sent: Saturday, January 6, 2018 3:15 AM
> To: David Ahern <dsahern@gmail.com>
> Cc: Chris Mi <chrism@mellanox.com>; netdev@vger.kernel.org;
> gerlitz.or@gmail.com; stephen@networkplumber.org
> Subject: Re: [patch iproute2 v6 2/3] tc: Add -bs option to batch mode
> 
> On Fri, Jan 05, 2018 at 11:15:59AM -0700, David Ahern wrote:
> > On 1/4/18 12:34 AM, Chris Mi wrote:
> > > Currently in tc batch mode, only one command is read from the batch
> > > file and sent to kernel to process. With this support, we can
> > > accumulate several commands before sending to kernel.
> > >
> > > Now it only works for the following successive rules, 1. filter add
> > > 2. filter delete 3. actions add 4. actions delete
> > >
> > > Otherwise, the batch size is still 1.
> > >
> > > Signed-off-by: Chris Mi <chrism@mellanox.com>
> > > ---
> > >  tc/m_action.c  |  93 ++++++++++++++++++++++++++++++----------
> > >  tc/tc.c        |  96 +++++++++++++++++++++++++++++++++++------
> > >  tc/tc_common.h |   8 +++-
> > >  tc/tc_filter.c | 132
> > > ++++++++++++++++++++++++++++++++++++++++-----------------
> > >  4 files changed, 252 insertions(+), 77 deletions(-)
> > >
> > > diff --git a/tc/m_action.c b/tc/m_action.c index fc422364..cf5cc95d
> > > 100644
> > > --- a/tc/m_action.c
> > > +++ b/tc/m_action.c
> > > @@ -23,6 +23,7 @@
> > >  #include <arpa/inet.h>
> > >  #include <string.h>
> > >  #include <dlfcn.h>
> > > +#include <errno.h>
> > >
> > >  #include "utils.h"
> > >  #include "tc_common.h"
> > > @@ -546,40 +547,86 @@ bad_val:
> > >  	return ret;
> > >  }
> > >
> > > +typedef struct {
> > > +	struct nlmsghdr		n;
> > > +	struct tcamsg		t;
> > > +	char			buf[MAX_MSG];
> > > +} tc_action_req;
> > > +
> > > +static tc_action_req *action_reqs;
> > > +static struct iovec msg_iov[MSG_IOV_MAX];
> > > +
> > > +void free_action_reqs(void)
> > > +{
> > > +	free(action_reqs);
> > > +}
> > > +
> > > +static tc_action_req *get_action_req(int batch_size, int index) {
> > > +	tc_action_req *req;
> > > +
> > > +	if (action_reqs == NULL) {
> > > +		action_reqs = malloc(batch_size * sizeof (tc_action_req));
> > > +		if (action_reqs == NULL)
> > > +			return NULL;
> > > +	}
> > > +	req = &action_reqs[index];
> > > +	memset(req, 0, sizeof (*req));
> > > +
> > > +	return req;
> > > +}
> > > +
> > >  static int tc_action_modify(int cmd, unsigned int flags,
> > > -			    int *argc_p, char ***argv_p)
> > > +			    int *argc_p, char ***argv_p,
> > > +			    int batch_size, int index, bool send)
> > >  {
> > > -	int argc = *argc_p;
> > > +	struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
> > > +	struct iovec *iov = &msg_iov[index];
> > >  	char **argv = *argv_p;
> > > -	int ret = 0;
> > > -	struct {
> > > -		struct nlmsghdr         n;
> > > -		struct tcamsg           t;
> > > -		char                    buf[MAX_MSG];
> > > -	} req = {
> > > -		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)),
> > > -		.n.nlmsg_flags = NLM_F_REQUEST | flags,
> > > -		.n.nlmsg_type = cmd,
> > > -		.t.tca_family = AF_UNSPEC,
> > > +	struct msghdr msg = {
> > > +		.msg_name = &nladdr,
> > > +		.msg_namelen = sizeof(nladdr),
> > > +		.msg_iov = msg_iov,
> > > +		.msg_iovlen = index + 1,
> > >  	};
> > > -	struct rtattr *tail = NLMSG_TAIL(&req.n);
> > > +	struct rtattr *tail;
> > > +	tc_action_req *req;
> > > +	int argc = *argc_p;
> > > +	int ret = 0;
> > > +
> > > +	req = get_action_req(batch_size, index);
> > > +	if (req == NULL) {
> > > +		fprintf(stderr, "get_action_req error: not enough buffer\n");
> > > +		return -ENOMEM;
> > > +	}
> > > +	req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg));
> > > +	req->n.nlmsg_flags = NLM_F_REQUEST | flags;
> > > +	req->n.nlmsg_type = cmd;
> > > +	req->t.tca_family = AF_UNSPEC;
> > > +	tail = NLMSG_TAIL(&req->n);
> > >
> > >  	argc -= 1;
> > >  	argv += 1;
> > > -	if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) {
> > > +	if (parse_action(&argc, &argv, TCA_ACT_TAB, &req->n)) {
> > >  		fprintf(stderr, "Illegal \"action\"\n");
> > >  		return -1;
> > >  	}
> > > -	tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
> > > +	tail->rta_len = (void *) NLMSG_TAIL(&req->n) - (void *) tail;
> > >
> > > -	if (rtnl_talk(&rth, &req.n, NULL) < 0) {
> > > +	*argc_p = argc;
> > > +	*argv_p = argv;
> > > +
> > > +	iov->iov_base = &req->n;
> > > +	iov->iov_len = req->n.nlmsg_len;
> > > +
> > > +	if (!send)
> > > +		return 0;
> > > +
> > > +	if (rtnl_talk_msg(&rth, &msg, NULL) < 0) {
> > >  		fprintf(stderr, "We have an error talking to the kernel\n");
> > >  		ret = -1;
> > >  	}
> > >
> > > -	*argc_p = argc;
> > > -	*argv_p = argv;
> > > -
> > >  	return ret;
> > >  }
> > >
> > > @@ -679,7 +726,7 @@ bad_val:
> > >  	return ret;
> > >  }
> > >
> > > -int do_action(int argc, char **argv)
> > > +int do_action(int argc, char **argv, int batch_size, int index,
> > > +bool send)
> > >  {
> > >
> > >  	int ret = 0;
> > > @@ -689,12 +736,14 @@ int do_action(int argc, char **argv)
> > >  		if (matches(*argv, "add") == 0) {
> > >  			ret =  tc_action_modify(RTM_NEWACTION,
> > >  						NLM_F_EXCL |
> NLM_F_CREATE,
> > > -						&argc, &argv);
> > > +						&argc, &argv, batch_size,
> > > +						index, send);
> > >  		} else if (matches(*argv, "change") == 0 ||
> > >  			  matches(*argv, "replace") == 0) {
> > >  			ret = tc_action_modify(RTM_NEWACTION,
> > >  					       NLM_F_CREATE |
> NLM_F_REPLACE,
> > > -					       &argc, &argv);
> > > +					       &argc, &argv, batch_size,
> > > +					       index, send);
> > >  		} else if (matches(*argv, "delete") == 0) {
> > >  			argc -= 1;
> > >  			argv += 1;
> > > diff --git a/tc/tc.c b/tc/tc.c
> > > index ad9f07e9..67c6bfb4 100644
> > > --- a/tc/tc.c
> > > +++ b/tc/tc.c
> > > @@ -189,20 +189,20 @@ static void usage(void)
> > >  	fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND |
> help }\n"
> > >  			"       tc [-force] -batch filename\n"
> > >  			"where  OBJECT := { qdisc | class | filter | action |
> monitor | exec }\n"
> > > -	                "       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] |
> -b[atch] [filename] | -n[etns] name |\n"
> > > +	                "       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] |
> -b[atch] [filename] | -bs | -batchsize [size] | -n[etns] name |\n"
> > >  			"                    -nm | -nam[es] | { -cf | -conf } path } | -
> j[son]\n");
> > >  }
> > >
> > > -static int do_cmd(int argc, char **argv)
> > > +static int do_cmd(int argc, char **argv, int batch_size, int index,
> > > +bool send)
> > >  {
> > >  	if (matches(*argv, "qdisc") == 0)
> > >  		return do_qdisc(argc-1, argv+1);
> > >  	if (matches(*argv, "class") == 0)
> > >  		return do_class(argc-1, argv+1);
> > >  	if (matches(*argv, "filter") == 0)
> > > -		return do_filter(argc-1, argv+1);
> > > +		return do_filter(argc-1, argv+1, batch_size, index, send);
> > >  	if (matches(*argv, "actions") == 0)
> > > -		return do_action(argc-1, argv+1);
> > > +		return do_action(argc-1, argv+1, batch_size, index, send);
> > >  	if (matches(*argv, "monitor") == 0)
> > >  		return do_tcmonitor(argc-1, argv+1);
> > >  	if (matches(*argv, "exec") == 0)
> > > @@ -217,11 +217,25 @@ static int do_cmd(int argc, char **argv)
> > >  	return -1;
> > >  }
> > >
> > > -static int batch(const char *name)
> > > +static bool batchsize_enabled(int argc, char *argv[])
> > >  {
> > > +	if (argc < 2)
> > > +		return false;
> > > +	if (((strcmp(argv[0], "filter") != 0) && strcmp(argv[0], "action") != 0)
> > > +	    || ((strcmp(argv[1], "add") != 0) && strcmp(argv[1], "delete") != 0))
> > > +		return false;
> > > +	return true;
> > > +}
> > > +
> > > +static int batch(const char *name, int batch_size) {
> > > +	bool lastline = false;
> > > +	int msg_iov_index = 0;
> > > +	char *line2 = NULL;
> > >  	char *line = NULL;
> > >  	size_t len = 0;
> > >  	int ret = 0;
> > > +	bool send;
> > >
> > >  	batch_mode = 1;
> > >  	if (name && strcmp(name, "-") != 0) { @@ -240,23 +254,66 @@ static
> > > int batch(const char *name)
> > >  	}
> > >
> > >  	cmdlineno = 0;
> > > -	while (getcmdline(&line, &len, stdin) != -1) {
> > > +	if (getcmdline(&line, &len, stdin) == -1)
> > > +		goto Exit;
> > > +	do {
> > > +		char *largv2[100];
> > >  		char *largv[100];
> > > +		int largc2;
> > >  		int largc;
> > >
> > > +		if (getcmdline(&line2, &len, stdin) == -1)
> > > +			lastline = true;
> > > +
> > > +		if (batch_size > 1)
> > > +			largc2 = makeargs(line2, largv2, 100);
> > >  		largc = makeargs(line, largv, 100);
> > > +
> > > +		/*
> > > +		 * In batch mode, if we haven't accumulated enough
> commands
> > > +		 * and this is not the last command and this command & next
> > > +		 * command both support the batchsize feature, don't send
> the
> > > +		 * message immediately.
> > > +		 */
> > > +		if (batch_size > 1 && msg_iov_index + 1 != batch_size
> > > +		    && !lastline && batchsize_enabled(largc, largv)
> > > +		    && batchsize_enabled(largc2, largv2))
> > > +			send = false;
> > > +		else
> > > +			send = true;
> > > +
> > > +		line = line2;
> > > +		line2 = NULL;
> > > +		len = 0;
> > > +
> > >  		if (largc == 0)
> > >  			continue;	/* blank line */
> > >
> > > -		if (do_cmd(largc, largv)) {
> > > -			fprintf(stderr, "Command failed %s:%d\n", name,
> cmdlineno);
> > > +		ret = do_cmd(largc, largv, batch_size, msg_iov_index, send);
> >
> > Perhaps I am missing something, but this design seems to assume the
> > file contains a series of filters or actions. What happens if actions
> > and filters are interlaced in the file?
> >
> > I think you need to look at having do_cmd return the generated request
> > as a buffer and length or have this batch function supply a buffer
> > that do_cmd fills instead of using its local req variable. The latter
> > would have better memory management. Then this batch function puts
> the
> > buffer into the iov and calls rtnl_talk_iov when it is ready to send the
> message.
> 
> Yes!   (That's pretty much what I tried to mean on Dec 27th)
> and then when rtnl_talk_iov returns, it knows all those buffers can be
> returned to the pool, regardless of the type of cmd.
> With this change, 'index' doesn't need to be here but somewhere below this
> function.
Done.

^ permalink raw reply

* [net-next 10/10] net/mlx5e: E-switch, Add steering drop counters
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Eugenia Emantayev, Saeed Mahameed
In-Reply-To: <20180109064434.12726-1-saeedm@mellanox.com>

From: Eugenia Emantayev <eugenia@mellanox.com>

Add flow counters to count packets dropped due to drop rules
configured in eswitch egress and ingress ACLs.
These counters will count VFs violations and incoming traffic drops.
Will be presented on hypervisor via standard 'ip -s link show' command.

Example: "ip -s link show dev enp5s0f0"

6: enp5s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 24:8a:07:a5:28:f0 brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast
    0          0        0       0       0       2
    TX: bytes  packets  errors  dropped carrier collsns
    1406       17       0       0       0       0
    vf 0 MAC 00:00:ca:fe:ca:fe, vlan 5, spoof checking off, link-state auto, trust off, query_rss off
    RX: bytes  packets  mcast   bcast   dropped
    1666       29       14         32      0
    TX: bytes  packets   dropped
    2880       44       2412

Signed-off-by: Eugenia Emantayev <eugenia@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/eswitch.c  | 99 +++++++++++++++++++++-
 drivers/net/ethernet/mellanox/mlx5/core/eswitch.h  |  7 ++
 drivers/net/ethernet/mellanox/mlx5/core/fs_core.h  |  2 +
 .../net/ethernet/mellanox/mlx5/core/fs_counters.c  |  6 ++
 4 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 7649e36653d9..5ecf2cddc16d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -37,6 +37,7 @@
 #include <linux/mlx5/fs.h>
 #include "mlx5_core.h"
 #include "eswitch.h"
+#include "fs_core.h"
 
 #define UPLINK_VPORT 0xFFFF
 
@@ -1123,8 +1124,12 @@ static void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw,
 static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
 				    struct mlx5_vport *vport)
 {
+	struct mlx5_fc *counter = vport->ingress.drop_counter;
+	struct mlx5_flow_destination drop_ctr_dst = {0};
+	struct mlx5_flow_destination *dst = NULL;
 	struct mlx5_flow_act flow_act = {0};
 	struct mlx5_flow_spec *spec;
+	int dest_num = 0;
 	int err = 0;
 	u8 *smac_v;
 
@@ -1188,9 +1193,18 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
 
 	memset(spec, 0, sizeof(*spec));
 	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
+
+	/* Attach drop flow counter */
+	if (counter) {
+		flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
+		drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+		drop_ctr_dst.counter = counter;
+		dst = &drop_ctr_dst;
+		dest_num++;
+	}
 	vport->ingress.drop_rule =
 		mlx5_add_flow_rules(vport->ingress.acl, spec,
-				    &flow_act, NULL, 0);
+				    &flow_act, dst, dest_num);
 	if (IS_ERR(vport->ingress.drop_rule)) {
 		err = PTR_ERR(vport->ingress.drop_rule);
 		esw_warn(esw->dev,
@@ -1210,8 +1224,12 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
 static int esw_vport_egress_config(struct mlx5_eswitch *esw,
 				   struct mlx5_vport *vport)
 {
+	struct mlx5_fc *counter = vport->egress.drop_counter;
+	struct mlx5_flow_destination drop_ctr_dst = {0};
+	struct mlx5_flow_destination *dst = NULL;
 	struct mlx5_flow_act flow_act = {0};
 	struct mlx5_flow_spec *spec;
+	int dest_num = 0;
 	int err = 0;
 
 	esw_vport_cleanup_egress_rules(esw, vport);
@@ -1262,9 +1280,18 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw,
 	/* Drop others rule (star rule) */
 	memset(spec, 0, sizeof(*spec));
 	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
+
+	/* Attach egress drop flow counter */
+	if (counter) {
+		flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
+		drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+		drop_ctr_dst.counter = counter;
+		dst = &drop_ctr_dst;
+		dest_num++;
+	}
 	vport->egress.drop_rule =
 		mlx5_add_flow_rules(vport->egress.acl, spec,
-				    &flow_act, NULL, 0);
+				    &flow_act, dst, dest_num);
 	if (IS_ERR(vport->egress.drop_rule)) {
 		err = PTR_ERR(vport->egress.drop_rule);
 		esw_warn(esw->dev,
@@ -1457,6 +1484,41 @@ static void esw_apply_vport_conf(struct mlx5_eswitch *esw,
 	}
 }
 
+static void esw_vport_create_drop_counters(struct mlx5_vport *vport)
+{
+	struct mlx5_core_dev *dev = vport->dev;
+
+	if (MLX5_CAP_ESW_INGRESS_ACL(dev, flow_counter)) {
+		vport->ingress.drop_counter = mlx5_fc_create(dev, false);
+		if (IS_ERR(vport->ingress.drop_counter)) {
+			esw_warn(dev,
+				 "vport[%d] configure ingress drop rule counter failed\n",
+				 vport->vport);
+			vport->ingress.drop_counter = NULL;
+		}
+	}
+
+	if (MLX5_CAP_ESW_EGRESS_ACL(dev, flow_counter)) {
+		vport->egress.drop_counter = mlx5_fc_create(dev, false);
+		if (IS_ERR(vport->egress.drop_counter)) {
+			esw_warn(dev,
+				 "vport[%d] configure egress drop rule counter failed\n",
+				 vport->vport);
+			vport->egress.drop_counter = NULL;
+		}
+	}
+}
+
+static void esw_vport_destroy_drop_counters(struct mlx5_vport *vport)
+{
+	struct mlx5_core_dev *dev = vport->dev;
+
+	if (vport->ingress.drop_counter)
+		mlx5_fc_destroy(dev, vport->ingress.drop_counter);
+	if (vport->egress.drop_counter)
+		mlx5_fc_destroy(dev, vport->egress.drop_counter);
+}
+
 static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num,
 			     int enable_events)
 {
@@ -1483,6 +1545,10 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num,
 	if (!vport_num)
 		vport->info.trusted = true;
 
+	/* create steering drop counters for ingress and egress ACLs */
+	if (vport_num && esw->mode == SRIOV_LEGACY)
+		esw_vport_create_drop_counters(vport);
+
 	esw_vport_change_handle_locked(vport);
 
 	esw->enabled_vports++;
@@ -1521,6 +1587,7 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num)
 					      MLX5_ESW_VPORT_ADMIN_STATE_DOWN);
 		esw_vport_disable_egress_acl(esw, vport);
 		esw_vport_disable_ingress_acl(esw, vport);
+		esw_vport_destroy_drop_counters(vport);
 	}
 	esw->enabled_vports--;
 	mutex_unlock(&esw->state_lock);
@@ -2016,12 +2083,36 @@ int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, int vport,
 	return err;
 }
 
+static void mlx5_eswitch_query_vport_drop_stats(struct mlx5_core_dev *dev,
+						int vport_idx,
+						struct mlx5_vport_drop_stats *stats)
+{
+	struct mlx5_eswitch *esw = dev->priv.eswitch;
+	struct mlx5_vport *vport = &esw->vports[vport_idx];
+	u64 bytes = 0;
+	u16 idx = 0;
+
+	if (!vport->enabled || esw->mode != SRIOV_LEGACY)
+		return;
+
+	if (vport->egress.drop_counter) {
+		idx = vport->egress.drop_counter->id;
+		mlx5_fc_query(dev, idx, &stats->rx_dropped, &bytes);
+	}
+
+	if (vport->ingress.drop_counter) {
+		idx = vport->ingress.drop_counter->id;
+		mlx5_fc_query(dev, idx, &stats->tx_dropped, &bytes);
+	}
+}
+
 int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
 				 int vport,
 				 struct ifla_vf_stats *vf_stats)
 {
 	int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out);
 	u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)] = {0};
+	struct mlx5_vport_drop_stats stats = {0};
 	int err = 0;
 	u32 *out;
 
@@ -2076,6 +2167,10 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
 	vf_stats->broadcast =
 		MLX5_GET_CTR(out, received_eth_broadcast.packets);
 
+	mlx5_eswitch_query_vport_drop_stats(esw->dev, vport, &stats);
+	vf_stats->rx_dropped = stats.rx_dropped;
+	vf_stats->tx_dropped = stats.tx_dropped;
+
 free_out:
 	kvfree(out);
 	return err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 3b481182f13a..2fa037066b2f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -73,6 +73,7 @@ struct vport_ingress {
 	struct mlx5_flow_group *drop_grp;
 	struct mlx5_flow_handle  *allow_rule;
 	struct mlx5_flow_handle  *drop_rule;
+	struct mlx5_fc           *drop_counter;
 };
 
 struct vport_egress {
@@ -81,6 +82,12 @@ struct vport_egress {
 	struct mlx5_flow_group *drop_grp;
 	struct mlx5_flow_handle  *allowed_vlan;
 	struct mlx5_flow_handle  *drop_rule;
+	struct mlx5_fc           *drop_counter;
+};
+
+struct mlx5_vport_drop_stats {
+	u64 rx_dropped;
+	u64 tx_dropped;
 };
 
 struct mlx5_vport_info {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
index 3e571045626f..05262708f14b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
@@ -233,6 +233,8 @@ void mlx5_fc_queue_stats_work(struct mlx5_core_dev *dev,
 			      unsigned long delay);
 void mlx5_fc_update_sampling_interval(struct mlx5_core_dev *dev,
 				      unsigned long interval);
+int mlx5_fc_query(struct mlx5_core_dev *dev, u16 id,
+		  u64 *packets, u64 *bytes);
 
 int mlx5_init_fs(struct mlx5_core_dev *dev);
 void mlx5_cleanup_fs(struct mlx5_core_dev *dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
index 89d1f8650033..b7ab929d5f8e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
@@ -312,6 +312,12 @@ void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev)
 	}
 }
 
+int mlx5_fc_query(struct mlx5_core_dev *dev, u16 id,
+		  u64 *packets, u64 *bytes)
+{
+	return mlx5_cmd_fc_query(dev, id, packets, bytes);
+}
+
 void mlx5_fc_query_cached(struct mlx5_fc *counter,
 			  u64 *bytes, u64 *packets, u64 *lastuse)
 {
-- 
2.13.0

^ permalink raw reply related

* [net-next 07/10] net/mlx5e: IPoIB, Add ethtool support to get child time stamping parameters
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Feras Daoud, Saeed Mahameed
In-Reply-To: <20180109064434.12726-1-saeedm@mellanox.com>

From: Feras Daoud <ferasda@mellanox.com>

Add support to get time stamping capabilities using ethtool for
child interface.
Usage example:
	ethtool -T CHILD-DEVNAME

This change reuses the functionality of parent devices and does not
introduce any new logic.

Signed-off-by: Feras Daoud <ferasda@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
index 6f338a9219c8..90cb50fe17fd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
@@ -254,4 +254,5 @@ const struct ethtool_ops mlx5i_ethtool_ops = {
 const struct ethtool_ops mlx5i_pkey_ethtool_ops = {
 	.get_drvinfo        = mlx5i_get_drvinfo,
 	.get_link           = ethtool_op_get_link,
+	.get_ts_info        = mlx5i_get_ts_info,
 };
-- 
2.13.0

^ permalink raw reply related

* [net-next 05/10] net/mlx5e: IPoIB, Use correct timestamp in child receive flow
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Feras Daoud, Saeed Mahameed
In-Reply-To: <20180109064434.12726-1-saeedm@mellanox.com>

From: Feras Daoud <ferasda@mellanox.com>

The current implementation takes the child timestamp object from
the parent since the rq in mlx5i_complete_rx_cqe belongs to the parent.
This change fixes the issue by taking the correct timestamp.

Fixes: 7e7f4780c340 ("net/mlx5e: IPoIB, Use hash-table to map between QPN to child netdev")
Signed-off-by: Feras Daoud <ferasda@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 90354e676f0d..ff234dfefc27 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -1175,7 +1175,9 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
 					 u32 cqe_bcnt,
 					 struct sk_buff *skb)
 {
+	struct hwtstamp_config *tstamp;
 	struct net_device *netdev;
+	struct mlx5e_priv *priv;
 	char *pseudo_header;
 	u32 qpn;
 	u8 *dgid;
@@ -1194,6 +1196,9 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
 		return;
 	}
 
+	priv = mlx5i_epriv(netdev);
+	tstamp = &priv->tstamp;
+
 	g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3;
 	dgid = skb->data + MLX5_IB_GRH_DGID_OFFSET;
 	if ((!g) || dgid[0] != 0xff)
@@ -1214,7 +1219,7 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
 	skb->ip_summed = CHECKSUM_COMPLETE;
 	skb->csum = csum_unfold((__force __sum16)cqe->check_sum);
 
-	if (unlikely(mlx5e_rx_hw_stamp(rq->tstamp)))
+	if (unlikely(mlx5e_rx_hw_stamp(tstamp)))
 		skb_hwtstamps(skb)->hwtstamp =
 				mlx5_timecounter_cyc2time(rq->clock, get_cqe_ts(cqe));
 
-- 
2.13.0

^ permalink raw reply related

* [net-next 06/10] net/mlx5e: IPoIB, Add PTP ioctl support for child interface
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Feras Daoud, Saeed Mahameed
In-Reply-To: <20180109064434.12726-1-saeedm@mellanox.com>

From: Feras Daoud <ferasda@mellanox.com>

Add support to control precision time protocol on child interfaces
using ioctl.

This commit changes the following:
- Change parent ioctl function to be non static
- Reuse the parent ioctl function in child devices

Signed-off-by: Feras Daoud <ferasda@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c      | 3 +--
 drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h      | 1 +
 drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c | 7 +++++++
 3 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
index 8812d7208e8f..3b2363e93ba5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
@@ -41,7 +41,6 @@
 static int mlx5i_open(struct net_device *netdev);
 static int mlx5i_close(struct net_device *netdev);
 static int mlx5i_change_mtu(struct net_device *netdev, int new_mtu);
-static int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 
 static const struct net_device_ops mlx5i_netdev_ops = {
 	.ndo_open                = mlx5i_open,
@@ -396,7 +395,7 @@ int mlx5i_dev_init(struct net_device *dev)
 	return 0;
 }
 
-static int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct mlx5e_priv *priv = mlx5i_epriv(dev);
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
index 49008022c306..5e87d04652d2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
@@ -79,6 +79,7 @@ struct net_device *mlx5i_pkey_get_netdev(struct net_device *netdev, u32 qpn);
 /* Shared ndo functionts */
 int mlx5i_dev_init(struct net_device *dev);
 void mlx5i_dev_cleanup(struct net_device *dev);
+int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 
 /* Parent profile functions */
 void mlx5i_init(struct mlx5_core_dev *mdev,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
index 531b02cc979b..b69e9d847a6b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
@@ -140,6 +140,7 @@ static int mlx5i_pkey_close(struct net_device *netdev);
 static int mlx5i_pkey_dev_init(struct net_device *dev);
 static void mlx5i_pkey_dev_cleanup(struct net_device *netdev);
 static int mlx5i_pkey_change_mtu(struct net_device *netdev, int new_mtu);
+static int mlx5i_pkey_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 
 static const struct net_device_ops mlx5i_pkey_netdev_ops = {
 	.ndo_open                = mlx5i_pkey_open,
@@ -147,6 +148,7 @@ static const struct net_device_ops mlx5i_pkey_netdev_ops = {
 	.ndo_init                = mlx5i_pkey_dev_init,
 	.ndo_uninit              = mlx5i_pkey_dev_cleanup,
 	.ndo_change_mtu          = mlx5i_pkey_change_mtu,
+	.ndo_do_ioctl            = mlx5i_pkey_ioctl,
 };
 
 /* Child NDOs */
@@ -174,6 +176,11 @@ static int mlx5i_pkey_dev_init(struct net_device *dev)
 	return mlx5i_dev_init(dev);
 }
 
+static int mlx5i_pkey_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	return mlx5i_ioctl(dev, ifr, cmd);
+}
+
 static void mlx5i_pkey_dev_cleanup(struct net_device *netdev)
 {
 	return mlx5i_dev_cleanup(netdev);
-- 
2.13.0

^ permalink raw reply related

* [net-next 09/10] net/core: Add drop counters to VF statistics
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Eugenia Emantayev, Saeed Mahameed
In-Reply-To: <20180109064434.12726-1-saeedm@mellanox.com>

From: Eugenia Emantayev <eugenia@mellanox.com>

Modern hardware can decide to drop packets going to/from a VF.
Add receive and transmit drop counters to be displayed at hypervisor
layer in iproute2 per VF statistics.

Signed-off-by: Eugenia Emantayev <eugenia@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 include/linux/if_link.h      |  2 ++
 include/uapi/linux/if_link.h |  2 ++
 net/core/rtnetlink.c         | 10 +++++++++-
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 4c54611e03e9..622658dfbf0a 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -13,6 +13,8 @@ struct ifla_vf_stats {
 	__u64 tx_bytes;
 	__u64 broadcast;
 	__u64 multicast;
+	__u64 rx_dropped;
+	__u64 tx_dropped;
 };
 
 struct ifla_vf_info {
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 19fc02660e0c..f8f04fed6186 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -732,6 +732,8 @@ enum {
 	IFLA_VF_STATS_BROADCAST,
 	IFLA_VF_STATS_MULTICAST,
 	IFLA_VF_STATS_PAD,
+	IFLA_VF_STATS_RX_DROPPED,
+	IFLA_VF_STATS_TX_DROPPED,
 	__IFLA_VF_STATS_MAX,
 };
 
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index c688dc564b11..5421a3fd3ba1 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -904,6 +904,10 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev,
 			 nla_total_size_64bit(sizeof(__u64)) +
 			 /* IFLA_VF_STATS_MULTICAST */
 			 nla_total_size_64bit(sizeof(__u64)) +
+			 /* IFLA_VF_STATS_RX_DROPPED */
+			 nla_total_size_64bit(sizeof(__u64)) +
+			 /* IFLA_VF_STATS_TX_DROPPED */
+			 nla_total_size_64bit(sizeof(__u64)) +
 			 nla_total_size(sizeof(struct ifla_vf_trust)));
 		return size;
 	} else
@@ -1258,7 +1262,11 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb,
 	    nla_put_u64_64bit(skb, IFLA_VF_STATS_BROADCAST,
 			      vf_stats.broadcast, IFLA_VF_STATS_PAD) ||
 	    nla_put_u64_64bit(skb, IFLA_VF_STATS_MULTICAST,
-			      vf_stats.multicast, IFLA_VF_STATS_PAD)) {
+			      vf_stats.multicast, IFLA_VF_STATS_PAD) ||
+	    nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_DROPPED,
+			      vf_stats.rx_dropped, IFLA_VF_STATS_PAD) ||
+	    nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_DROPPED,
+			      vf_stats.tx_dropped, IFLA_VF_STATS_PAD)) {
 		nla_nest_cancel(skb, vfstats);
 		goto nla_put_vf_failure;
 	}
-- 
2.13.0

^ permalink raw reply related

* [net-next 02/10] net/mlx5: Hairpin pair core object setup
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Or Gerlitz, Saeed Mahameed
In-Reply-To: <20180109064434.12726-1-saeedm@mellanox.com>

From: Or Gerlitz <ogerlitz@mellanox.com>

Low level code to setup hairpin pair core object, deals with:
 - create hairpin RQs/SQs
 - destroy hairpin RQs/SQs
 - modifying hairpin RQs/SQs - pairing (rst2rdy) and unpairing (rdy2rst)

Unlike conventional RQs/SQs, the memory used for the packet and descriptor
buffers is allocated by the firmware and not the driver. The driver sets
the overall data size (log).

Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/transobj.c | 184 +++++++++++++++++++++
 include/linux/mlx5/transobj.h                      |  19 +++
 2 files changed, 203 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c
index 5e128d7a9ffd..a09ebbaf3b68 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c
@@ -398,3 +398,187 @@ void mlx5_core_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn)
 	mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 }
 EXPORT_SYMBOL(mlx5_core_destroy_rqt);
+
+static int mlx5_hairpin_create_rq(struct mlx5_core_dev *mdev,
+				  struct mlx5_hairpin_params *params, u32 *rqn)
+{
+	u32 in[MLX5_ST_SZ_DW(create_rq_in)] = {0};
+	void *rqc, *wq;
+
+	rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
+	wq  = MLX5_ADDR_OF(rqc, rqc, wq);
+
+	MLX5_SET(rqc, rqc, hairpin, 1);
+	MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST);
+	MLX5_SET(rqc, rqc, counter_set_id, params->q_counter);
+
+	MLX5_SET(wq, wq, log_hairpin_data_sz, params->log_data_size);
+
+	return mlx5_core_create_rq(mdev, in, MLX5_ST_SZ_BYTES(create_rq_in), rqn);
+}
+
+static int mlx5_hairpin_create_sq(struct mlx5_core_dev *mdev,
+				  struct mlx5_hairpin_params *params, u32 *sqn)
+{
+	u32 in[MLX5_ST_SZ_DW(create_sq_in)] = {0};
+	void *sqc, *wq;
+
+	sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
+	wq  = MLX5_ADDR_OF(sqc, sqc, wq);
+
+	MLX5_SET(sqc, sqc, hairpin, 1);
+	MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST);
+
+	MLX5_SET(wq, wq, log_hairpin_data_sz, params->log_data_size);
+
+	return mlx5_core_create_sq(mdev, in, MLX5_ST_SZ_BYTES(create_sq_in), sqn);
+}
+
+static int mlx5_hairpin_create_queues(struct mlx5_hairpin *hp,
+				      struct mlx5_hairpin_params *params)
+{
+	int err;
+
+	err = mlx5_hairpin_create_rq(hp->func_mdev, params, &hp->rqn);
+	if (err)
+		goto out_err_rq;
+
+	err = mlx5_hairpin_create_sq(hp->peer_mdev, params, &hp->sqn);
+	if (err)
+		goto out_err_sq;
+
+	return 0;
+
+out_err_sq:
+	mlx5_core_destroy_rq(hp->func_mdev, hp->rqn);
+out_err_rq:
+	return err;
+}
+
+static void mlx5_hairpin_destroy_queues(struct mlx5_hairpin *hp)
+{
+	mlx5_core_destroy_rq(hp->func_mdev, hp->rqn);
+	mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn);
+}
+
+static int mlx5_hairpin_modify_rq(struct mlx5_core_dev *func_mdev, u32 rqn,
+				  int curr_state, int next_state,
+				  u16 peer_vhca, u32 peer_sq)
+{
+	u32 in[MLX5_ST_SZ_DW(modify_rq_in)] = {0};
+	void *rqc;
+
+	rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
+
+	if (next_state == MLX5_RQC_STATE_RDY) {
+		MLX5_SET(rqc, rqc, hairpin_peer_sq, peer_sq);
+		MLX5_SET(rqc, rqc, hairpin_peer_vhca, peer_vhca);
+	}
+
+	MLX5_SET(modify_rq_in, in, rq_state, curr_state);
+	MLX5_SET(rqc, rqc, state, next_state);
+
+	return mlx5_core_modify_rq(func_mdev, rqn,
+				   in, MLX5_ST_SZ_BYTES(modify_rq_in));
+}
+
+static int mlx5_hairpin_modify_sq(struct mlx5_core_dev *peer_mdev, u32 sqn,
+				  int curr_state, int next_state,
+				  u16 peer_vhca, u32 peer_rq)
+{
+	u32 in[MLX5_ST_SZ_DW(modify_sq_in)] = {0};
+	void *sqc;
+
+	sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
+
+	if (next_state == MLX5_RQC_STATE_RDY) {
+		MLX5_SET(sqc, sqc, hairpin_peer_rq, peer_rq);
+		MLX5_SET(sqc, sqc, hairpin_peer_vhca, peer_vhca);
+	}
+
+	MLX5_SET(modify_sq_in, in, sq_state, curr_state);
+	MLX5_SET(sqc, sqc, state, next_state);
+
+	return mlx5_core_modify_sq(peer_mdev, sqn,
+				   in, MLX5_ST_SZ_BYTES(modify_sq_in));
+}
+
+static int mlx5_hairpin_pair_queues(struct mlx5_hairpin *hp)
+{
+	int err;
+
+	/* set peer SQ */
+	err = mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn,
+				     MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY,
+				     MLX5_CAP_GEN(hp->func_mdev, vhca_id), hp->rqn);
+	if (err)
+		goto err_modify_sq;
+
+	/* set func RQ */
+	err = mlx5_hairpin_modify_rq(hp->func_mdev, hp->rqn,
+				     MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY,
+				     MLX5_CAP_GEN(hp->peer_mdev, vhca_id), hp->sqn);
+
+	if (err)
+		goto err_modify_rq;
+
+	return 0;
+
+err_modify_rq:
+	mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn, MLX5_SQC_STATE_RDY,
+			       MLX5_SQC_STATE_RST, 0, 0);
+err_modify_sq:
+	return err;
+}
+
+static void mlx5_hairpin_unpair_queues(struct mlx5_hairpin *hp)
+{
+	/* unset func RQ */
+	mlx5_hairpin_modify_rq(hp->func_mdev, hp->rqn, MLX5_RQC_STATE_RDY,
+			       MLX5_RQC_STATE_RST, 0, 0);
+
+	/* unset peer SQ */
+	mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn, MLX5_SQC_STATE_RDY,
+			       MLX5_SQC_STATE_RST, 0, 0);
+}
+
+struct mlx5_hairpin *
+mlx5_core_hairpin_create(struct mlx5_core_dev *func_mdev,
+			 struct mlx5_core_dev *peer_mdev,
+			 struct mlx5_hairpin_params *params)
+{
+	struct mlx5_hairpin *hp;
+	int size, err;
+
+	size = sizeof(*hp);
+	hp = kzalloc(size, GFP_KERNEL);
+	if (!hp)
+		return ERR_PTR(-ENOMEM);
+
+	hp->func_mdev = func_mdev;
+	hp->peer_mdev = peer_mdev;
+
+	/* alloc and pair func --> peer hairpin */
+	err = mlx5_hairpin_create_queues(hp, params);
+	if (err)
+		goto err_create_queues;
+
+	err = mlx5_hairpin_pair_queues(hp);
+	if (err)
+		goto err_pair_queues;
+
+	return hp;
+
+err_pair_queues:
+	mlx5_hairpin_destroy_queues(hp);
+err_create_queues:
+	kfree(hp);
+	return ERR_PTR(err);
+}
+
+void mlx5_core_hairpin_destroy(struct mlx5_hairpin *hp)
+{
+	mlx5_hairpin_unpair_queues(hp);
+	mlx5_hairpin_destroy_queues(hp);
+	kfree(hp);
+}
diff --git a/include/linux/mlx5/transobj.h b/include/linux/mlx5/transobj.h
index 88441f5ece25..a228310c1968 100644
--- a/include/linux/mlx5/transobj.h
+++ b/include/linux/mlx5/transobj.h
@@ -75,4 +75,23 @@ int mlx5_core_modify_rqt(struct mlx5_core_dev *dev, u32 rqtn, u32 *in,
 			 int inlen);
 void mlx5_core_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn);
 
+struct mlx5_hairpin_params {
+	u8  log_data_size;
+	u16 q_counter;
+};
+
+struct mlx5_hairpin {
+	struct mlx5_core_dev *func_mdev;
+	struct mlx5_core_dev *peer_mdev;
+
+	u32 rqn;
+	u32 sqn;
+};
+
+struct mlx5_hairpin *
+mlx5_core_hairpin_create(struct mlx5_core_dev *func_mdev,
+			 struct mlx5_core_dev *peer_mdev,
+			 struct mlx5_hairpin_params *params);
+
+void mlx5_core_hairpin_destroy(struct mlx5_hairpin *pair);
 #endif /* __TRANSOBJ_H__ */
-- 
2.13.0

^ permalink raw reply related

* [net-next 04/10] net/mlx5e: Support offloading TC NIC hairpin flows
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Or Gerlitz, Saeed Mahameed
In-Reply-To: <20180109064434.12726-1-saeedm@mellanox.com>

From: Or Gerlitz <ogerlitz@mellanox.com>

We refer to TC NIC rule that involves forwarding as "hairpin".

All hairpin rules from the current NIC device (called "func" in
the code) to a given NIC device ("peer") are steered into the
same hairpin RQ/SQ pair.

The hairpin pair is set on demand and removed when there are no
TC rules that need it.

Here's a TC rule that matches on icmp, does header re-write of the
dst mac and hairpin from RX/enp1s2f1 to TX/enp1s2f2 (enp1s2f1/2 are
two mlx5 devices):

tc filter add dev enp1s2f1 protocol ip parent ffff: prio 2
    flower skip_sw ip_proto icmp
     action pedit ex munge eth dst set 10:22:33:44:55:66 pipe
     action mirred egress redirect dev enp1s2f2

Signed-off-by: Or Gerlitz <ogerlitz@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_tc.c | 183 ++++++++++++++++++++++--
 2 files changed, 172 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 5299310f2481..72bab8d3f4b0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -659,6 +659,7 @@ struct mlx5e_tc_table {
 	struct rhashtable               ht;
 
 	DECLARE_HASHTABLE(mod_hdr_tbl, 8);
+	DECLARE_HASHTABLE(hairpin_tbl, 8);
 };
 
 struct mlx5e_vlan_table {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 55a527bda2e5..cf528da51243 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -56,12 +56,14 @@ struct mlx5_nic_flow_attr {
 	u32 action;
 	u32 flow_tag;
 	u32 mod_hdr_id;
+	u32 hairpin_tirn;
 };
 
 enum {
 	MLX5E_TC_FLOW_ESWITCH	= BIT(0),
 	MLX5E_TC_FLOW_NIC	= BIT(1),
 	MLX5E_TC_FLOW_OFFLOADED	= BIT(2),
+	MLX5E_TC_FLOW_HAIRPIN	= BIT(3),
 };
 
 struct mlx5e_tc_flow {
@@ -71,6 +73,7 @@ struct mlx5e_tc_flow {
 	struct mlx5_flow_handle *rule;
 	struct list_head	encap;   /* flows sharing the same encap ID */
 	struct list_head	mod_hdr; /* flows sharing the same mod hdr ID */
+	struct list_head	hairpin; /* flows sharing the same hairpin */
 	union {
 		struct mlx5_esw_flow_attr esw_attr[0];
 		struct mlx5_nic_flow_attr nic_attr[0];
@@ -101,6 +104,17 @@ struct mlx5e_hairpin {
 	u32 tirn;
 };
 
+struct mlx5e_hairpin_entry {
+	/* a node of a hash table which keeps all the  hairpin entries */
+	struct hlist_node hairpin_hlist;
+
+	/* flows sharing the same hairpin */
+	struct list_head flows;
+
+	int peer_ifindex;
+	struct mlx5e_hairpin *hp;
+};
+
 struct mod_hdr_key {
 	int num_actions;
 	void *actions;
@@ -319,6 +333,98 @@ static void mlx5e_hairpin_destroy(struct mlx5e_hairpin *hp)
 	kvfree(hp);
 }
 
+static struct mlx5e_hairpin_entry *mlx5e_hairpin_get(struct mlx5e_priv *priv,
+						     int peer_ifindex)
+{
+	struct mlx5e_hairpin_entry *hpe;
+
+	hash_for_each_possible(priv->fs.tc.hairpin_tbl, hpe,
+			       hairpin_hlist, peer_ifindex) {
+		if (hpe->peer_ifindex == peer_ifindex)
+			return hpe;
+	}
+
+	return NULL;
+}
+
+static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
+				  struct mlx5e_tc_flow *flow,
+				  struct mlx5e_tc_flow_parse_attr *parse_attr)
+{
+	int peer_ifindex = parse_attr->mirred_ifindex;
+	struct mlx5_hairpin_params params;
+	struct mlx5e_hairpin_entry *hpe;
+	struct mlx5e_hairpin *hp;
+	int err;
+
+	if (!MLX5_CAP_GEN(priv->mdev, hairpin)) {
+		netdev_warn(priv->netdev, "hairpin is not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	hpe = mlx5e_hairpin_get(priv, peer_ifindex);
+	if (hpe)
+		goto attach_flow;
+
+	hpe = kzalloc(sizeof(*hpe), GFP_KERNEL);
+	if (!hpe)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&hpe->flows);
+	hpe->peer_ifindex = peer_ifindex;
+
+	params.log_data_size = 15;
+	params.log_data_size = min_t(u8, params.log_data_size,
+				     MLX5_CAP_GEN(priv->mdev, log_max_hairpin_wq_data_sz));
+	params.log_data_size = max_t(u8, params.log_data_size,
+				     MLX5_CAP_GEN(priv->mdev, log_min_hairpin_wq_data_sz));
+	params.q_counter = priv->q_counter;
+
+	hp = mlx5e_hairpin_create(priv, &params, peer_ifindex);
+	if (IS_ERR(hp)) {
+		err = PTR_ERR(hp);
+		goto create_hairpin_err;
+	}
+
+	netdev_dbg(priv->netdev, "add hairpin: tirn %x rqn %x peer %s sqn %x log data size %d\n",
+		   hp->tirn, hp->pair->rqn, hp->pair->peer_mdev->priv.name,
+		   hp->pair->sqn, params.log_data_size);
+
+	hpe->hp = hp;
+	hash_add(priv->fs.tc.hairpin_tbl, &hpe->hairpin_hlist, peer_ifindex);
+
+attach_flow:
+	flow->nic_attr->hairpin_tirn = hpe->hp->tirn;
+	list_add(&flow->hairpin, &hpe->flows);
+	return 0;
+
+create_hairpin_err:
+	kfree(hpe);
+	return err;
+}
+
+static void mlx5e_hairpin_flow_del(struct mlx5e_priv *priv,
+				   struct mlx5e_tc_flow *flow)
+{
+	struct list_head *next = flow->hairpin.next;
+
+	list_del(&flow->hairpin);
+
+	/* no more hairpin flows for us, release the hairpin pair */
+	if (list_empty(next)) {
+		struct mlx5e_hairpin_entry *hpe;
+
+		hpe = list_entry(next, struct mlx5e_hairpin_entry, flows);
+
+		netdev_dbg(priv->netdev, "del hairpin: peer %s\n",
+			   hpe->hp->pair->peer_mdev->priv.name);
+
+		mlx5e_hairpin_destroy(hpe->hp);
+		hash_del(&hpe->hairpin_hlist);
+		kfree(hpe);
+	}
+}
+
 static struct mlx5_flow_handle *
 mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
 		      struct mlx5e_tc_flow_parse_attr *parse_attr,
@@ -326,7 +432,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
 {
 	struct mlx5_nic_flow_attr *attr = flow->nic_attr;
 	struct mlx5_core_dev *dev = priv->mdev;
-	struct mlx5_flow_destination dest = {};
+	struct mlx5_flow_destination dest[2] = {};
 	struct mlx5_flow_act flow_act = {
 		.action = attr->action,
 		.flow_tag = attr->flow_tag,
@@ -335,18 +441,33 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
 	struct mlx5_fc *counter = NULL;
 	struct mlx5_flow_handle *rule;
 	bool table_created = false;
-	int err;
+	int err, dest_ix = 0;
 
 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
-		dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
-		dest.ft = priv->fs.vlan.ft.t;
-	} else if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
-		counter = mlx5_fc_create(dev, true);
-		if (IS_ERR(counter))
-			return ERR_CAST(counter);
+		if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) {
+			err = mlx5e_hairpin_flow_add(priv, flow, parse_attr);
+			if (err) {
+				rule = ERR_PTR(err);
+				goto err_add_hairpin_flow;
+			}
+			dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_TIR;
+			dest[dest_ix].tir_num = attr->hairpin_tirn;
+		} else {
+			dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+			dest[dest_ix].ft = priv->fs.vlan.ft.t;
+		}
+		dest_ix++;
+	}
 
-		dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
-		dest.counter = counter;
+	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
+		counter = mlx5_fc_create(dev, true);
+		if (IS_ERR(counter)) {
+			rule = ERR_CAST(counter);
+			goto err_fc_create;
+		}
+		dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+		dest[dest_ix].counter = counter;
+		dest_ix++;
 	}
 
 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
@@ -389,7 +510,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
 
 	parse_attr->spec.match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
 	rule = mlx5_add_flow_rules(priv->fs.tc.t, &parse_attr->spec,
-				   &flow_act, &dest, 1);
+				   &flow_act, dest, dest_ix);
 
 	if (IS_ERR(rule))
 		goto err_add_rule;
@@ -406,7 +527,10 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
 		mlx5e_detach_mod_hdr(priv, flow);
 err_create_mod_hdr_id:
 	mlx5_fc_destroy(dev, counter);
-
+err_fc_create:
+	if (flow->flags & MLX5E_TC_FLOW_HAIRPIN)
+		mlx5e_hairpin_flow_del(priv, flow);
+err_add_hairpin_flow:
 	return rule;
 }
 
@@ -427,6 +551,9 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
 
 	if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
 		mlx5e_detach_mod_hdr(priv, flow);
+
+	if (flow->flags & MLX5E_TC_FLOW_HAIRPIN)
+		mlx5e_hairpin_flow_del(priv, flow);
 }
 
 static void mlx5e_detach_encap(struct mlx5e_priv *priv,
@@ -1519,6 +1646,20 @@ static bool actions_match_supported(struct mlx5e_priv *priv,
 	return true;
 }
 
+static bool same_hw_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv)
+{
+	struct mlx5_core_dev *fmdev, *pmdev;
+	u16 func_id, peer_id;
+
+	fmdev = priv->mdev;
+	pmdev = peer_priv->mdev;
+
+	func_id = (u16)((fmdev->pdev->bus->number << 8) | PCI_SLOT(fmdev->pdev->devfn));
+	peer_id = (u16)((pmdev->pdev->bus->number << 8) | PCI_SLOT(pmdev->pdev->devfn));
+
+	return (func_id == peer_id);
+}
+
 static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
 				struct mlx5e_tc_flow_parse_attr *parse_attr,
 				struct mlx5e_tc_flow *flow)
@@ -1563,6 +1704,23 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
 			return -EOPNOTSUPP;
 		}
 
+		if (is_tcf_mirred_egress_redirect(a)) {
+			struct net_device *peer_dev = tcf_mirred_dev(a);
+
+			if (priv->netdev->netdev_ops == peer_dev->netdev_ops &&
+			    same_hw_devs(priv, netdev_priv(peer_dev))) {
+				parse_attr->mirred_ifindex = peer_dev->ifindex;
+				flow->flags |= MLX5E_TC_FLOW_HAIRPIN;
+				attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
+						MLX5_FLOW_CONTEXT_ACTION_COUNT;
+			} else {
+				netdev_warn(priv->netdev, "device %s not on same HW, can't offload\n",
+					    peer_dev->name);
+				return -EINVAL;
+			}
+			continue;
+		}
+
 		if (is_tcf_skbedit_mark(a)) {
 			u32 mark = tcf_skbedit_mark(a);
 
@@ -2285,6 +2443,7 @@ int mlx5e_tc_init(struct mlx5e_priv *priv)
 	struct mlx5e_tc_table *tc = &priv->fs.tc;
 
 	hash_init(tc->mod_hdr_tbl);
+	hash_init(tc->hairpin_tbl);
 
 	tc->ht_params = mlx5e_tc_flow_ht_params;
 	return rhashtable_init(&tc->ht, &tc->ht_params);
-- 
2.13.0

^ permalink raw reply related

* [net-next 03/10] net/mlx5e: Basic setup of hairpin object
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Or Gerlitz, Saeed Mahameed
In-Reply-To: <20180109064434.12726-1-saeedm@mellanox.com>

From: Or Gerlitz <ogerlitz@mellanox.com>

Add the code to do basic setup for hairpin object which
will later serve offloading TC flows.

This includes calling the mlx5 core to create/destroy the hairpin
pair object and setting the HW transport objects that will be used
for steering matched flows to go through hairpin.

Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 97 +++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 933275fe03b2..55a527bda2e5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -93,6 +93,14 @@ enum {
 #define MLX5E_TC_TABLE_NUM_GROUPS 4
 #define MLX5E_TC_TABLE_MAX_GROUP_SIZE (1 << 16)
 
+struct mlx5e_hairpin {
+	struct mlx5_hairpin *pair;
+
+	struct mlx5_core_dev *func_mdev;
+	u32 tdn;
+	u32 tirn;
+};
+
 struct mod_hdr_key {
 	int num_actions;
 	void *actions;
@@ -222,6 +230,95 @@ static void mlx5e_detach_mod_hdr(struct mlx5e_priv *priv,
 	}
 }
 
+static
+struct mlx5_core_dev *mlx5e_hairpin_get_mdev(struct net *net, int ifindex)
+{
+	struct net_device *netdev;
+	struct mlx5e_priv *priv;
+
+	netdev = __dev_get_by_index(net, ifindex);
+	priv = netdev_priv(netdev);
+	return priv->mdev;
+}
+
+static int mlx5e_hairpin_create_transport(struct mlx5e_hairpin *hp)
+{
+	u32 in[MLX5_ST_SZ_DW(create_tir_in)] = {0};
+	void *tirc;
+	int err;
+
+	err = mlx5_core_alloc_transport_domain(hp->func_mdev, &hp->tdn);
+	if (err)
+		goto alloc_tdn_err;
+
+	tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
+
+	MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT);
+	MLX5_SET(tirc, tirc, inline_rqn, hp->pair->rqn);
+	MLX5_SET(tirc, tirc, transport_domain, hp->tdn);
+
+	err = mlx5_core_create_tir(hp->func_mdev, in, MLX5_ST_SZ_BYTES(create_tir_in), &hp->tirn);
+	if (err)
+		goto create_tir_err;
+
+	return 0;
+
+create_tir_err:
+	mlx5_core_dealloc_transport_domain(hp->func_mdev, hp->tdn);
+alloc_tdn_err:
+	return err;
+}
+
+static void mlx5e_hairpin_destroy_transport(struct mlx5e_hairpin *hp)
+{
+	mlx5_core_destroy_tir(hp->func_mdev, hp->tirn);
+	mlx5_core_dealloc_transport_domain(hp->func_mdev, hp->tdn);
+}
+
+static struct mlx5e_hairpin *
+mlx5e_hairpin_create(struct mlx5e_priv *priv, struct mlx5_hairpin_params *params,
+		     int peer_ifindex)
+{
+	struct mlx5_core_dev *func_mdev, *peer_mdev;
+	struct mlx5e_hairpin *hp;
+	struct mlx5_hairpin *pair;
+	int err;
+
+	hp = kzalloc(sizeof(*hp), GFP_KERNEL);
+	if (!hp)
+		return ERR_PTR(-ENOMEM);
+
+	func_mdev = priv->mdev;
+	peer_mdev = mlx5e_hairpin_get_mdev(dev_net(priv->netdev), peer_ifindex);
+
+	pair = mlx5_core_hairpin_create(func_mdev, peer_mdev, params);
+	if (IS_ERR(pair)) {
+		err = PTR_ERR(pair);
+		goto create_pair_err;
+	}
+	hp->pair = pair;
+	hp->func_mdev = func_mdev;
+
+	err = mlx5e_hairpin_create_transport(hp);
+	if (err)
+		goto create_transport_err;
+
+	return hp;
+
+create_transport_err:
+	mlx5_core_hairpin_destroy(hp->pair);
+create_pair_err:
+	kfree(hp);
+	return ERR_PTR(err);
+}
+
+static void mlx5e_hairpin_destroy(struct mlx5e_hairpin *hp)
+{
+	mlx5e_hairpin_destroy_transport(hp);
+	mlx5_core_hairpin_destroy(hp->pair);
+	kvfree(hp);
+}
+
 static struct mlx5_flow_handle *
 mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
 		      struct mlx5e_tc_flow_parse_attr *parse_attr,
-- 
2.13.0

^ permalink raw reply related

* [net-next 08/10] net/mlx5e: IPoIB, Fix spelling mistake "functionts" -> "functions"
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Gal Pressman, Saeed Mahameed
In-Reply-To: <20180109064434.12726-1-saeedm@mellanox.com>

From: Gal Pressman <galp@mellanox.com>

Fix trivial spelling mistake: "functionts" -> "functions".

Signed-off-by: Gal Pressman <galp@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
index 5e87d04652d2..6d9053bcbe95 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
@@ -76,7 +76,7 @@ int mlx5i_pkey_del_qpn(struct net_device *netdev, u32 qpn);
 /* Get the net-device corresponding to the given underlay QPN */
 struct net_device *mlx5i_pkey_get_netdev(struct net_device *netdev, u32 qpn);
 
-/* Shared ndo functionts */
+/* Shared ndo functions */
 int mlx5i_dev_init(struct net_device *dev);
 void mlx5i_dev_cleanup(struct net_device *dev);
 int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-- 
2.13.0

^ permalink raw reply related

* [net-next 01/10] net/mlx5: Add hairpin definitions to the FW API
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Or Gerlitz, Saeed Mahameed
In-Reply-To: <20180109064434.12726-1-saeedm@mellanox.com>

From: Or Gerlitz <ogerlitz@mellanox.com>

Add hairpin definitions to the IFC file.

This includes the HCA ID, few HCA hairpin capabilities, new
fields in RQ/SQ used later for the pairing and the WQ hairpin
data size attribute.

Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
 include/linux/mlx5/mlx5_ifc.h | 43 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index d44ec5f41d4a..78e36fc2609e 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -794,7 +794,10 @@ enum {
 };
 
 struct mlx5_ifc_cmd_hca_cap_bits {
-	u8         reserved_at_0[0x80];
+	u8         reserved_at_0[0x30];
+	u8         vhca_id[0x10];
+
+	u8         reserved_at_40[0x40];
 
 	u8         log_max_srq_sz[0x8];
 	u8         log_max_qp_sz[0x8];
@@ -1023,12 +1026,19 @@ struct mlx5_ifc_cmd_hca_cap_bits {
 	u8         reserved_at_3b8[0x3];
 	u8         log_min_stride_sz_sq[0x5];
 
-	u8         reserved_at_3c0[0x1b];
+	u8         hairpin[0x1];
+	u8         reserved_at_3c1[0x2];
+	u8         log_max_hairpin_queues[0x5];
+	u8         reserved_at_3c8[0x3];
+	u8         log_max_hairpin_wq_data_sz[0x5];
+	u8         reserved_at_3d0[0xb];
 	u8         log_max_wq_sz[0x5];
 
 	u8         nic_vport_change_event[0x1];
 	u8         disable_local_lb[0x1];
-	u8         reserved_at_3e2[0x9];
+	u8         reserved_at_3e2[0x1];
+	u8         log_min_hairpin_wq_data_sz[0x5];
+	u8         reserved_at_3e8[0x3];
 	u8         log_max_vlan_list[0x5];
 	u8         reserved_at_3f0[0x3];
 	u8         log_max_current_mc_list[0x5];
@@ -1162,7 +1172,10 @@ struct mlx5_ifc_wq_bits {
 	u8         reserved_at_118[0x3];
 	u8         log_wq_sz[0x5];
 
-	u8         reserved_at_120[0x15];
+	u8         reserved_at_120[0xb];
+	u8         log_hairpin_data_sz[0x5];
+	u8         reserved_at_130[0x5];
+
 	u8         log_wqe_num_of_strides[0x3];
 	u8         two_byte_shift_en[0x1];
 	u8         reserved_at_139[0x4];
@@ -2482,7 +2495,8 @@ struct mlx5_ifc_sqc_bits {
 	u8         state[0x4];
 	u8         reg_umr[0x1];
 	u8         allow_swp[0x1];
-	u8         reserved_at_e[0x12];
+	u8         hairpin[0x1];
+	u8         reserved_at_f[0x11];
 
 	u8         reserved_at_20[0x8];
 	u8         user_index[0x18];
@@ -2490,7 +2504,13 @@ struct mlx5_ifc_sqc_bits {
 	u8         reserved_at_40[0x8];
 	u8         cqn[0x18];
 
-	u8         reserved_at_60[0x90];
+	u8         reserved_at_60[0x8];
+	u8         hairpin_peer_rq[0x18];
+
+	u8         reserved_at_80[0x10];
+	u8         hairpin_peer_vhca[0x10];
+
+	u8         reserved_at_a0[0x50];
 
 	u8         packet_pacing_rate_limit_index[0x10];
 	u8         tis_lst_sz[0x10];
@@ -2562,7 +2582,8 @@ struct mlx5_ifc_rqc_bits {
 	u8         state[0x4];
 	u8         reserved_at_c[0x1];
 	u8         flush_in_error_en[0x1];
-	u8         reserved_at_e[0x12];
+	u8         hairpin[0x1];
+	u8         reserved_at_f[0x11];
 
 	u8         reserved_at_20[0x8];
 	u8         user_index[0x18];
@@ -2576,7 +2597,13 @@ struct mlx5_ifc_rqc_bits {
 	u8         reserved_at_80[0x8];
 	u8         rmpn[0x18];
 
-	u8         reserved_at_a0[0xe0];
+	u8         reserved_at_a0[0x8];
+	u8         hairpin_peer_sq[0x18];
+
+	u8         reserved_at_c0[0x10];
+	u8         hairpin_peer_vhca[0x10];
+
+	u8         reserved_at_e0[0xa0];
 
 	struct mlx5_ifc_wq_bits wq;
 };
-- 
2.13.0

^ permalink raw reply related

* [pull request][net-next 00/10] Mellanox, mlx5 updates 2018-01-08
From: Saeed Mahameed @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Saeed Mahameed

Hi Dave,

This series includes updates for mlx5 driver, for full information please
see tag log message below.

The series doesn't cause any conflict with Andy's
"net: create dynamic software irq moderation library".  Both merge together
seamlessly.

Please pull and let me know if there's any problem.

Thanks,
Saeed.

---

The following changes since commit f4803f1b73f877a571be4c8e531dfcf190acc691:

  net: tipc: remove unused hardirq.h (2018-01-08 20:59:25 -0500)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux.git tags/mlx5-updates-2018-01-08

for you to fetch changes up to b8a0dbe3a90b2debd72cd9a304eacac55c44e5a4:

  net/mlx5e: E-switch, Add steering drop counters (2018-01-09 07:40:48 +0200)

----------------------------------------------------------------
mlx5-updates-2018-01-08

Four patches from Or that add Hairpin support to mlx5:
===========================================================
From:  Or Gerlitz <ogerlitz@mellanox.com>

We refer the ability of NIC HW to fwd packet received on one port to
the other port (also from a port to itself) as hairpin. The application API
is based
on ingress tc/flower rules set on the NIC with the mirred redirect
action. Other actions can apply to packets during the redirect.

Hairpin allows to offload the data-path of various SW DDoS gateways,
load-balancers, etc to HW. Packets go through all the required
processing in HW (header re-write, encap/decap, push/pop vlan) and
then forwarded, CPU stays at practically zero usage. HW Flow counters
are used by the control plane for monitoring and accounting.

Hairpin is implemented by pairing a receive queue (RQ) to send queue (SQ).
All the flows that share <recv NIC, mirred NIC> are redirected through
the same hairpin pair. Currently, only header-rewrite is supported as a
packet modification action.

I'd like to thanks Elijah Shakkour <elijahs@mellanox.com> for implementing this
functionality
on HW simulator, before it was avail in the FW so the driver code could be
tested early.
===========================================================

>From Feras three patches that provide very small changes that allow IPoIB
to support RX timestamping for child interfaces, simply by hooking the mlx5e
timestamping PTP ioctl to IPoIB child interface netdev profile.

One patch from Gal to fix a spilling mistake.

Two patches from Eugenia adds drop counters to VF statistics
to be reported as part of VF statistics in netlink (iproute2) and
implemented them in mlx5 eswitch.

----------------------------------------------------------------
Eugenia Emantayev (2):
      net/core: Add drop counters to VF statistics
      net/mlx5e: E-switch, Add steering drop counters

Feras Daoud (3):
      net/mlx5e: IPoIB, Use correct timestamp in child receive flow
      net/mlx5e: IPoIB, Add PTP ioctl support for child interface
      net/mlx5e: IPoIB, Add ethtool support to get child time stamping parameters

Gal Pressman (1):
      net/mlx5e: IPoIB, Fix spelling mistake "functionts" -> "functions"

Or Gerlitz (4):
      net/mlx5: Add hairpin definitions to the FW API
      net/mlx5: Hairpin pair core object setup
      net/mlx5e: Basic setup of hairpin object
      net/mlx5e: Support offloading TC NIC hairpin flows

 drivers/net/ethernet/mellanox/mlx5/core/en.h       |   1 +
 drivers/net/ethernet/mellanox/mlx5/core/en_rx.c    |   7 +-
 drivers/net/ethernet/mellanox/mlx5/core/en_tc.c    | 280 ++++++++++++++++++++-
 drivers/net/ethernet/mellanox/mlx5/core/eswitch.c  |  99 +++++++-
 drivers/net/ethernet/mellanox/mlx5/core/eswitch.h  |   7 +
 drivers/net/ethernet/mellanox/mlx5/core/fs_core.h  |   2 +
 .../net/ethernet/mellanox/mlx5/core/fs_counters.c  |   6 +
 .../ethernet/mellanox/mlx5/core/ipoib/ethtool.c    |   1 +
 .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c  |   3 +-
 .../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h  |   3 +-
 .../ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c |   7 +
 drivers/net/ethernet/mellanox/mlx5/core/transobj.c | 184 ++++++++++++++
 include/linux/if_link.h                            |   2 +
 include/linux/mlx5/mlx5_ifc.h                      |  43 +++-
 include/linux/mlx5/transobj.h                      |  19 ++
 include/uapi/linux/if_link.h                       |   2 +
 net/core/rtnetlink.c                               |  10 +-
 17 files changed, 649 insertions(+), 27 deletions(-)

^ permalink raw reply

* RE: [patch iproute2 v6 1/3] lib/libnetlink: Add a function rtnl_talk_msg
From: Chris Mi @ 2018-01-09  6:44 UTC (permalink / raw)
  To: David Ahern, netdev@vger.kernel.org
  Cc: gerlitz.or@gmail.com, stephen@networkplumber.org,
	marcelo.leitner@gmail.com
In-Reply-To: <6562fc22-4161-5efc-488a-79a62db1cd4f@gmail.com>

> -----Original Message-----
> From: David Ahern [mailto:dsahern@gmail.com]
> Sent: Saturday, January 6, 2018 1:51 AM
> To: Chris Mi <chrism@mellanox.com>; netdev@vger.kernel.org
> Cc: gerlitz.or@gmail.com; stephen@networkplumber.org;
> marcelo.leitner@gmail.com
> Subject: Re: [patch iproute2 v6 1/3] lib/libnetlink: Add a function
> rtnl_talk_msg
> 
> On 1/4/18 12:34 AM, Chris Mi wrote:
> > rtnl_talk can only send a single message to kernel. Add a new function
> > rtnl_talk_msg that can send multiple messages to kernel.
> >
> > Signed-off-by: Chris Mi <chrism@mellanox.com>
> > ---
> >  include/libnetlink.h |  3 +++
> >  lib/libnetlink.c     | 66 ++++++++++++++++++++++++++++++++++++++----
> ----------
> >  2 files changed, 51 insertions(+), 18 deletions(-)
> >
> 
> I think you should add an argument to rtnl_talk_msg to return the number of
> messages processed. That can be used to refine which line failed. As batch
> size increases the current design puts the burden on the user to scan a lot of
> lines to find the one that fails:
> 
> tc -b tc.batch  -bs 50
> RTNETLINK answers: File exists
> We have an error talking to the kernel, -1 Command failed tc.batch:2-51
> 
> We should be able to tell them exactly which line failed.
Done.
> 
> Also, it would be better to call this rtnl_talk_iov, take an iov as an argument
> and have a common rtnl_talk_msg for existing code and this new one.
> 
> As it stands you are having to add:
>    struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
> 
> to tc functions when it really only needs to know about iov's.
Done.

^ permalink raw reply


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