Netdev List
 help / color / mirror / Atom feed
* [PATCH v4 0/3] IB/hns: Add HiSilicon RoCE driver
From: Lijun Ou @ 2016-03-22 14:06 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA,
	sean.hefty-ral2JQCrhuEAvxtiuMwx3w,
	hal.rosenstock-Re5JQEeQqe8AvxtiuMwx3w,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	jeffrey.t.kirsher-ral2JQCrhuEAvxtiuMwx3w,
	jiri-VPRAkNaXOzVWk0Htik3J/w, ogerlitz-VPRAkNaXOzVWk0Htik3J/w
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	gongyangming-hv44wF8Li93QT0dZR+AlfA,
	xiaokun-hv44wF8Li93QT0dZR+AlfA,
	tangchaofei-hv44wF8Li93QT0dZR+AlfA,
	oulijun-hv44wF8Li93QT0dZR+AlfA,
	haifeng.wei-hv44wF8Li93QT0dZR+AlfA,
	yisen.zhuang-hv44wF8Li93QT0dZR+AlfA,
	yankejian-hv44wF8Li93QT0dZR+AlfA,
	lisheng011-hv44wF8Li93QT0dZR+AlfA,
	charles.chenxin-hv44wF8Li93QT0dZR+AlfA,
	linuxarm-hv44wF8Li93QT0dZR+AlfA

The HiSilicon Network Substem is a long term evolution IP which is
supposed to be used in HiSilicon ICT SoC. RoCE is a feature of hns.
The driver for HiSilicon RoCE engine is a platform driver.
The driver will support mulitple versions of hns. Currently only "v1"
for hip06 SoC is supported.

Changes v3 -> v4:
1. modify roce.o into hns-roce.o in Makefile and Kconfig file.

Changes v2 -> v3:
1. modify the formats of RoCE driver code base v2 by the experts 
reviewing. also, it used kmalloc_array instead of kmalloc, used kcalloc
instead of kzalloc, when refer to memory allocation for array
2. remove some functions without use and unconnected macros
3. modify the binding document with RoCE DT base v2 which added interrupt-names
4. redesign the port_map and si_map in hns_dsaf_roce_reset
5. add HiSilicon RoCE driver maintainers introduction in MAINTAINERS document

Changes v1 -> v2:
1. modify the formats of roce driver code by the experts reviewing
2. modify the bindings file with roce dts. add the attribute named 
interrput-names.
3. modify the way of defining port mode in hns_dsaf_main.c
4. move the Kconfig file into the hns directory and send it with roce

Lijun Ou (3):
  net: hns: Add reset function support for RoCE driver
  IB/hns: Add HiSilicon RoCE driver support
  IB/hns: Add binding document for HiSilicon RoCE driver

 .../bindings/infiniband/hisilicon-hns-roce.txt     |  107 +
 MAINTAINERS                                        |    8 +
 drivers/infiniband/Kconfig                         |    1 +
 drivers/infiniband/hw/Makefile                     |    1 +
 drivers/infiniband/hw/hisilicon/hns/Kconfig        |   10 +
 drivers/infiniband/hw/hisilicon/hns/Makefile       |    9 +
 drivers/infiniband/hw/hisilicon/hns/hns_roce_ah.c  |  110 +
 .../infiniband/hw/hisilicon/hns/hns_roce_alloc.c   |  239 ++
 drivers/infiniband/hw/hisilicon/hns/hns_roce_cmd.c |  338 +++
 drivers/infiniband/hw/hisilicon/hns/hns_roce_cmd.h |   80 +
 .../infiniband/hw/hisilicon/hns/hns_roce_common.h  |  308 +++
 drivers/infiniband/hw/hisilicon/hns/hns_roce_cq.c  |  436 +++
 .../infiniband/hw/hisilicon/hns/hns_roce_device.h  |  794 ++++++
 drivers/infiniband/hw/hisilicon/hns/hns_roce_eq.c  |  758 ++++++
 drivers/infiniband/hw/hisilicon/hns/hns_roce_eq.h  |  132 +
 drivers/infiniband/hw/hisilicon/hns/hns_roce_icm.c |  578 ++++
 drivers/infiniband/hw/hisilicon/hns/hns_roce_icm.h |  112 +
 .../infiniband/hw/hisilicon/hns/hns_roce_main.c    | 1097 ++++++++
 drivers/infiniband/hw/hisilicon/hns/hns_roce_mr.c  |  605 +++++
 drivers/infiniband/hw/hisilicon/hns/hns_roce_pd.c  |  124 +
 drivers/infiniband/hw/hisilicon/hns/hns_roce_qp.c  |  841 ++++++
 .../infiniband/hw/hisilicon/hns/hns_roce_user.h    |   31 +
 .../infiniband/hw/hisilicon/hns/hns_roce_v1_hw.c   | 2832 ++++++++++++++++++++
 .../infiniband/hw/hisilicon/hns/hns_roce_v1_hw.h   |  985 +++++++
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c |   84 +
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h |   30 +
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c |   62 +-
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h  |   13 +
 28 files changed, 10715 insertions(+), 10 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/Kconfig
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/Makefile
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_ah.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_alloc.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_cmd.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_cmd.h
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_common.h
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_cq.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_device.h
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_eq.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_eq.h
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_icm.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_icm.h
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_main.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_mr.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_pd.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_qp.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_user.h
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_v1_hw.c
 create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_v1_hw.h

-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v4 3/3] IB/hns: Add binding document for HiSilicon RoCE driver
From: Lijun Ou @ 2016-03-22 14:07 UTC (permalink / raw)
  To: dledford, sean.hefty, hal.rosenstock, davem, jeffrey.t.kirsher,
	jiri, ogerlitz
  Cc: linux-rdma, linux-kernel, netdev, gongyangming, xiaokun,
	tangchaofei, oulijun, haifeng.wei, yisen.zhuang, yankejian,
	lisheng011, charles.chenxin, linuxarm
In-Reply-To: <1458655621-3618-1-git-send-email-oulijun@huawei.com>

This patch adds related DTS binding document for HiSilicon RoCE driver.

Signed-off-by: Lijun Ou <oulijun@huawei.com>
Signed-off-by: Wei Hu(Xavier) <xavier.huwei@huawei.com>
---
 .../bindings/infiniband/hisilicon-hns-roce.txt     | 107 +++++++++++++++++++++
 1 file changed, 107 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt

diff --git a/Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt b/Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
new file mode 100644
index 0000000..5180fef
--- /dev/null
+++ b/Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
@@ -0,0 +1,107 @@
+HiSilicon RoCE DT description
+
+HiSilicon RoCE engine is a part of network subsystem.
+It works depending on other part of network wubsytem, such as, gmac and
+dsa fabric.
+
+Additional properties are described here:
+
+Required properties:
+- compatible: Should contain "hisilicon,hns-roce-v1".
+- reg: Physical base address of the roce driver and
+length of memory mapped region.
+- eth-handle: phandle, specifies a reference to a node
+representing a ethernet device.
+- dsaf-handle: phandle, specifies a reference to a node
+representing a dsaf device.
+- #address-cells: must be 2
+- #size-cells: must be 2
+Optional properties:
+- dma-coherent: Present if DMA operations are coherent.
+- interrupt-parent: the interrupt parent of this device.
+- interrupts: should contain 32 completion event irq,1 async event irq
+and 1 event overflow irq.
+- interrupt-names:should be one of 34 irqs for roce device
+  - roce_ce0_irq ~ roce_ce31_irq: 32 complete event irq
+  - roce_ae_irq: 1 async event irq
+  - roce_common_irq: named common exception warning irq
+Example:
+	infiniband@c4000000 {
+			compatible = "hisilicon,hns-roce-v1";
+			reg = <0x0 0xc4000000 0x0 0x100000>;
+			dma-coherent;
+			eth-handle = <&eth2 &eth3 &eth4 &eth5 &eth6 &eth7>;
+			dsaf-handle = <&soc0_dsa>;
+			#address-cells = <2>;
+			#size-cells = <2>;
+			interrupt-parent = <&mbigen_dsa>;
+			interrupts = <722 1>,
+					<723 1>,
+					<724 1>,
+					<725 1>,
+					<726 1>,
+					<727 1>,
+					<728 1>,
+					<729 1>,
+					<730 1>,
+					<731 1>,
+					<732 1>,
+					<733 1>,
+					<734 1>,
+					<735 1>,
+					<736 1>,
+					<737 1>,
+					<738 1>,
+					<739 1>,
+					<740 1>,
+					<741 1>,
+					<742 1>,
+					<743 1>,
+					<744 1>,
+					<745 1>,
+					<746 1>,
+					<747 1>,
+					<748 1>,
+					<749 1>,
+					<750 1>,
+					<751 1>,
+					<752 1>,
+					<753 1>,
+					<785 1>,
+					<754 4>;
+
+			interrupt-names = "roce_ce0_irq",
+					"roce_ce1_irq",
+					"roce_ce2_irq",
+					"roce_ce3_irq",
+					"roce_ce4_irq",
+					"roce_ce5_irq",
+					"roce_ce6_irq",
+					"roce_ce7_irq",
+					"roce_ce8_irq",
+					"roce_ce9_irq",
+					"roce_ce10_irq",
+					"roce_ce11_irq",
+					"roce_ce12_irq",
+					"roce_ce13_irq",
+					"roce_ce14_irq",
+					"roce_ce15_irq",
+					"roce_ce16_irq",
+					"roce_ce17_irq",
+					"roce_ce18_irq",
+					"roce_ce19_irq",
+					"roce_ce20_irq",
+					"roce_ce21_irq",
+					"roce_ce22_irq",
+					"roce_ce23_irq",
+					"roce_ce24_irq",
+					"roce_ce25_irq",
+					"roce_ce26_irq",
+					"roce_ce27_irq",
+					"roce_ce28_irq",
+					"roce_ce29_irq",
+					"roce_ce30_irq",
+					"roce_ce31_irq",
+					"roce_ae_irq",
+					"roce_common_irq";
+		};
-- 
1.9.1

^ permalink raw reply related

* [PATCH iproute2 v1 1/1] lib/utils: fix get_addr() and get_prefix() error messages
From: Varlese, Marco @ 2016-03-22 13:02 UTC (permalink / raw)
  To: netdev@vger.kernel.org
  Cc: davem@davemloft.net, Jiri Pirko, John Fastabend, jhs@mojatatu.com,
	Szczerbik, PrzemyslawX

An attempt to add invalid address to interface would print "???" string
instead of the address family name.

For example:
$ ip address add 256.10.166.1/24 dev ens8
Error: ??? prefix is expected rather than "256.10.166.1/24".

$ ip neighbor add proxy 2001:db8::g dev ens8
Error: ??? address is expected rather than "2001:db8::g".

With this patch the output will look like:
$ ip address add 256.10.166.1/24 dev ens8
Error: inet prefix is expected rather than "256.10.166.1/24".

$ ip neighbor add proxy 2001:db8::g dev ens8
Error: inet6 address is expected rather than "2001:db8::g".

Signed-off-by: Przemyslaw Szczerbik <przemyslawx.szczerbik@intel.com>
Signed-off-by: Marco Varlese <marco.varlese@intel.com>
---
lib/utils.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/utils.c b/lib/utils.c
index fa35f4d..4820de1 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -567,7 +567,7 @@ int get_addr(inet_prefix *dst, const char *arg, int family)
{
        if (get_addr_1(dst, arg, family)) {
                fprintf(stderr, "Error: %s address is expected rather than \"%s\".\n",
-                               family_name(family) ,arg);
+                               family_name(dst->family), arg);
                exit(1);
        }
        return 0;
@@ -581,7 +581,7 @@ int get_prefix(inet_prefix *dst, char *arg, int family)
        }
        if (get_prefix_1(dst, arg, family)) {
                fprintf(stderr, "Error: %s prefix is expected rather than \"%s\".\n",
-                               family_name(family) ,arg);
+                               family_name(dst->family), arg);
                exit(1);
        }
        return 0;

^ permalink raw reply related

* Re: net/bluetooth: workqueue destruction WARNING in hci_unregister_dev
From: Dmitry Vyukov @ 2016-03-22 12:32 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Tejun Heo, Marcel Holtmann, Gustavo Padovan, Johan Hedberg,
	David S. Miller, linux-bluetooth, netdev, LKML, syzkaller,
	Kostya Serebryany, Alexander Potapenko, Sasha Levin, Eric Dumazet,
	Takashi Iwai
In-Reply-To: <56F0FDCE.1040701-AlSwsSmVLrQ@public.gmane.org>

On Tue, Mar 22, 2016 at 9:09 AM, Jiri Slaby <jslaby-AlSwsSmVLrQ@public.gmane.org> wrote:
> On 03/21/2016, 04:58 PM, Jiri Slaby wrote:
>> Hello,
>>
>> On 03/18/2016, 09:52 PM, Tejun Heo wrote:
>>> On Thu, Mar 17, 2016 at 01:00:13PM +0100, Jiri Slaby wrote:
>>>>>> I have not done that yet, but today, I see:
>>>>>> destroy_workqueue: name='req_hci0' pwq=ffff88002f590300
>>>>>> wq->dfl_pwq=ffff88002f591e00 pwq->refcnt=2 pwq->nr_active=0 delayed_works:
>>>>>>    pwq 12: cpus=0-1 node=0 flags=0x4 nice=-20 active=0/1
>>>>>>      in-flight: 18568:wq_barrier_func
>>>>>
>>>>> So, this means that there's flush_work() racing against workqueue
>>>>> destruction, which can't be safe. :(
>>>>
>>>> But I cannot trigger the WARN_ONs in the attached patch, so I am
>>>> confused how this can happen :(. (While I am still seeing the destroy
>>>> WARNINGs.)
>>>
>>> So, no operations should be in progress when destroy_workqueue() is
>>> called.  If somebody was flushing a work item, the flush call must
>>> have returned before destroy_workqueue() was invoked, which doesn't
>>> seem to be the case here.  Can you trigger BUG_ON() or sysrq-t when
>>> the above triggers?  There must be a task which is flushing a work
>>> item there and it shouldn't be difficult to pinpoint what's going on
>>> from it.
>>
>> The output of sysrq-t is here (> 200k), but I cannot see anything
>> suspicious in it:
>> http://www.fi.muni.cz/~xslaby/sklad/panics/jctl.txt
>
> Hmm, so I seem I cannot reproduce with this hunk:
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -3139,10 +3139,10 @@ void hci_unregister_dev(struct hci_dev *hdev)
>         list_del(&hdev->list);
>         write_unlock(&hci_dev_list_lock);
>
> -       hci_dev_do_close(hdev);
> -
>         cancel_work_sync(&hdev->power_on);
>
> +       hci_dev_do_close(hdev);
> +
>         if (!test_bit(HCI_INIT, &hdev->flags) &&
>             !hci_dev_test_flag(hdev, HCI_SETUP) &&
>             !hci_dev_test_flag(hdev, HCI_CONFIG)) {
>
>
>
> I cannot explain why though. I do not see how it matters in this
> particular case...
>
> Dmitry, could you apply it too? But I don't know how often you see the
> warning.

I've seen it only several times in several months, so I don't it will
be helpful.

^ permalink raw reply

* Re: [Y2038] [PATCH] prism54: isl_38xx: Replace 'struct timeval'
From: Arnd Bergmann @ 2016-03-22 11:51 UTC (permalink / raw)
  To: y2038-cunTk1MwBs8s++Sfvej+rw
  Cc: Tina Ruchandani, Kalle Valo, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20160322095522.GA35392@localhost>

On Tuesday 22 March 2016 02:55:22 Tina Ruchandani wrote:
> Truly fixing this would 
> require changing the debug print to print more than 8 digits and using 
> a different specifier from %li.

Why not just change it to %lli, and a cast to s64? I don't think the
format string or the number of digits is important here because it's just
debug output that is normally disabled.

I also see an existing bug in the format string: "%08li.%08li" means we
end up printing a six digit microsecond value with two leading zeros,
which is rather confusing. I think using "%lld.%06ld" would be best
here, or possibly "%lld.%09ld" to print the whole nanoseconds so we
can skip the division.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH net v2] ipv4: fix broadcast packets reception
From: Hannes Frederic Sowa @ 2016-03-22 10:27 UTC (permalink / raw)
  To: Paolo Abeni, netdev; +Cc: David S. Miller, Alexey Kuznetsov, Shawn Bohrer
In-Reply-To: <c8ad97bbb6f1c9ec8c523209c1203d1982faab6f.1458634653.git.pabeni@redhat.com>

On 22.03.2016 09:19, Paolo Abeni wrote:
> Currently, ingress ipv4 broadcast datagrams are dropped since,
> in udp_v4_early_demux(), ip_check_mc_rcu() is invoked even on
> bcast packets.
>
> This patch addresses the issue, invoking ip_check_mc_rcu()
> only for mcast packets.
>
> Fixes: 6e5403093261 ("ipv4/udp: Verify multicast group is ours in upd_v4_early_demux()")
> Signed-off-by: Paolo Abeni <pabeni@redhat.com>

Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>

^ permalink raw reply

* [PATCH] prism54: isl_38xx: Replace 'struct timeval'
From: Tina Ruchandani @ 2016-03-22  9:55 UTC (permalink / raw)
  To: y2038-cunTk1MwBs8s++Sfvej+rw
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Kalle Valo

'struct timeval' uses a 32-bit seconds field which will overflow in
year 2038 and beyond. This patch is part of a larger effort to remove
all instances of 'struct timeval' from the kernel and replace them
with 64-bit timekeeping variables.
The correctness of the code isn't affected by this patch - the seconds
value being printed would earlier be wrong due to overflow in timeval,
and now it gets truncated to 32-bit due to the 'long' cast used on
tv.sec field to prevent compiler warnings. Truly fixing this would 
require changing the debug print to print more than 8 digits and using 
a different specifier from %li.
The patch was build-tested / debugged by removing the
"if VERBOSE > SHOW_ERROR_MESSAGES" guards.

Signed-off-by: Tina Ruchandani <ruchandani.tina-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/net/wireless/intersil/prism54/isl_38xx.c | 29 +++++++++++++++---------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/intersil/prism54/isl_38xx.c b/drivers/net/wireless/intersil/prism54/isl_38xx.c
index 333c1a2..e510375 100644
--- a/drivers/net/wireless/intersil/prism54/isl_38xx.c
+++ b/drivers/net/wireless/intersil/prism54/isl_38xx.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/delay.h>
+#include <linux/ktime.h>

 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -113,7 +114,7 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)

 #if VERBOSE > SHOW_ERROR_MESSAGES
 	u32 counter = 0;
-	struct timeval current_time;
+	struct timespec64 current_ts64;
 	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
 #endif

@@ -121,22 +122,25 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
 	if (asleep) {
 		/* device is in powersave, trigger the device for wakeup */
 #if VERBOSE > SHOW_ERROR_MESSAGES
-		do_gettimeofday(&current_time);
+		ktime_get_real_ts64(&current_ts64);
 		DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
-		      current_time.tv_sec, (long)current_time.tv_usec);
+		      (long)current_ts64.tv_sec,
+		      (long)(current_ts64.tv_nsec / NSEC_PER_USEC));

 		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
-		      current_time.tv_sec, (long)current_time.tv_usec,
+		      (long)current_ts64.tv_sec,
+		      (long)(current_ts64.tv_nsec / NSEC_PER_USEC),
 		      readl(device_base + ISL38XX_CTRL_STAT_REG));
 #endif

 		reg = readl(device_base + ISL38XX_INT_IDENT_REG);
 		if (reg == 0xabadface) {
 #if VERBOSE > SHOW_ERROR_MESSAGES
-			do_gettimeofday(&current_time);
+			ktime_get_real_ts64(&current_ts64);
 			DEBUG(SHOW_TRACING,
 			      "%08li.%08li Device register abadface\n",
-			      current_time.tv_sec, (long)current_time.tv_usec);
+			      (long)current_ts64.tv_sec,
+			      (long)(current_ts64.tv_nsec / NSEC_PER_USEC));
 #endif
 			/* read the Device Status Register until Sleepmode bit is set */
 			while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
@@ -150,12 +154,14 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
 #if VERBOSE > SHOW_ERROR_MESSAGES
 			DEBUG(SHOW_TRACING,
 			      "%08li.%08li Device register read %08x\n",
-			      current_time.tv_sec, (long)current_time.tv_usec,
+			      (long)current_ts64.tv_sec,
+			      (long)(current_ts64.tv_nsec / NSEC_PER_USEC),
 			      readl(device_base + ISL38XX_CTRL_STAT_REG));
-			do_gettimeofday(&current_time);
+			ktime_get_real_ts64(&current_ts64);
 			DEBUG(SHOW_TRACING,
 			      "%08li.%08li Device asleep counter %i\n",
-			      current_time.tv_sec, (long)current_time.tv_usec,
+			      (long)current_ts64.tv_sec,
+			      (long)(current_ts64.tv_nsec / NSEC_PER_USEC),
 			      counter);
 #endif
 		}
@@ -168,9 +174,10 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)

 		/* perform another read on the Device Status Register */
 		reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
-		do_gettimeofday(&current_time);
+		ktime_get_real_ts64(&current_ts64);
 		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
-		      current_time.tv_sec, (long)current_time.tv_usec, reg);
+		      (long)current_ts64.tv_sec,
+		      (long)(current_ts64.tv_nsec / NSEC_PER_USEC), reg);
 #endif
 	} else {
 		/* device is (still) awake  */
--
2.8.0.rc3.226.g39d4020

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [RFCv2 0/3] mac80211: implement fq codel
From: Toke Høiland-Jørgensen @ 2016-03-22  9:51 UTC (permalink / raw)
  To: Michal Kazior
  Cc: Network Development, linux-wireless, ath10k@lists.infradead.org,
	Jasmine Strong, codel@lists.bufferbloat.net, make-wifi-fast
In-Reply-To: <CA+BoTQ=hgkm2AwMb=kinx+Ezf3vjduCKNH4LNRcV_goDWH4_Vg@mail.gmail.com>

Michal Kazior <michal.kazior@tieto.com> writes:

> traffic-gen generates only BE traffic. Everything else runs UDP_RR
> which doesn't generate a lot of traffic.

Good point. Fixed that: the newest git version of traffic-gen supports a
-t parameter which will be set as the TOS byte on outgoing traffic
(literal; no smart diffserv handling, so you can override the ECN bits
as well).

Added support for a burst-tos test parameter in the Flent burst test
configs which will use this new parameter if set.

-Toke
_______________________________________________
Codel mailing list
Codel@lists.bufferbloat.net
https://lists.bufferbloat.net/listinfo/codel

^ permalink raw reply

* Re: [PATCH] lan78xx: Protect runtime_auto check by #ifdef CONFIG_PM
From: Oliver Neukum @ 2016-03-22  9:50 UTC (permalink / raw)
  To: Alan Stern
  Cc: David S. Miller, Geert Uytterhoeven,
	Microchip Linux Driver Support, Woojung Huh, Rafael J. Wysocki,
	Guenter Roeck, linux-kernel, linux-pm, linux-usb, netdev
In-Reply-To: <Pine.LNX.4.44L0.1603211527570.1708-100000@iolanthe.rowland.org>

On Mon, 2016-03-21 at 15:30 -0400, Alan Stern wrote:
> On Mon, 21 Mar 2016, Oliver Neukum wrote:
> 

> > We have an autosuspend timeout because we think that IO, if it will
> > come at all, is likeliest to come soon. If, however, the IO is
> > periodic that heuristics is false.
> > To save most power the driver must either decide that the interval
> > is too short or suspend immediately. So if we are lucky enough
> > to have the frequency in the kernel, we should use that information.
> 
> The autosuspend timeout is set by userspace.  The kernel may assign a

Thus it should apply to all IO originating in user space.
But only to that IO.

> default value, but the user can always override it.  Given this, I 
> don't see how the kernel can use frequency information (and I'm not 
> sure where that information would come from in the first place).

It can ignore internal IO for the purpose of the timeout.
If such IO is performed while the device is active, don't
alter the timer. Otherwise resume the device and look at
the provided hint and suspend again immediately if the period is long
enough.
If IO is generated periodically in the kernel, the kernel must know that
period.

	Regards
		Oliver
 

^ permalink raw reply

* [patch iproute2 v2 2/2] add devlink tool
From: Jiri Pirko @ 2016-03-22  9:02 UTC (permalink / raw)
  To: netdev
  Cc: stephen, davem, idosch, eladr, yotamg, ogerlitz, yishaih,
	dledford, sean.hefty, hal.rosenstock, eugenia, roopa, nikolay,
	hadarh, jhs, john.fastabend, jeffrey.t.kirsher, brouer, ivecera,
	rami.rosen, hannes, gospo
In-Reply-To: <1458637341-3434-1-git-send-email-jiri@resnulli.us>

From: Jiri Pirko <jiri@mellanox.com>

Add new tool called devlink which is userspace counterpart of devlink
Netlink socket.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
v1->v2:
    - fix some checkpatch issues
---
 Makefile                   |   2 +-
 devlink/Makefile           |  20 +
 devlink/devlink.c          | 987 +++++++++++++++++++++++++++++++++++++++++++++
 devlink/mnlg.c             | 274 +++++++++++++
 devlink/mnlg.h             |  27 ++
 include/linux/devlink.h    |  72 ++++
 man/man8/devlink-dev.8     |  58 +++
 man/man8/devlink-monitor.8 |  36 ++
 man/man8/devlink-port.8    | 126 ++++++
 man/man8/devlink.8         |  83 ++++
 10 files changed, 1684 insertions(+), 1 deletion(-)
 create mode 100644 devlink/Makefile
 create mode 100644 devlink/devlink.c
 create mode 100644 devlink/mnlg.c
 create mode 100644 devlink/mnlg.h
 create mode 100644 include/linux/devlink.h
 create mode 100644 man/man8/devlink-dev.8
 create mode 100644 man/man8/devlink-monitor.8
 create mode 100644 man/man8/devlink-port.8
 create mode 100644 man/man8/devlink.8

diff --git a/Makefile b/Makefile
index 67176be..0190aa0 100644
--- a/Makefile
+++ b/Makefile
@@ -41,7 +41,7 @@ WFLAGS += -Wmissing-declarations -Wold-style-definition -Wformat=2
 CFLAGS := $(WFLAGS) $(CCOPTS) -I../include $(DEFINES) $(CFLAGS)
 YACCFLAGS = -d -t -v
 
-SUBDIRS=lib ip tc bridge misc netem genl tipc man
+SUBDIRS=lib ip tc bridge misc netem genl tipc devlink man
 
 LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a
 LDLIBS += $(LIBNETLINK)
diff --git a/devlink/Makefile b/devlink/Makefile
new file mode 100644
index 0000000..3fdaa69
--- /dev/null
+++ b/devlink/Makefile
@@ -0,0 +1,20 @@
+include ../Config
+ifeq ($(HAVE_MNL),y)
+
+DEVLINKOBJ = devlink.o mnlg.o
+TARGETS=devlink
+
+CFLAGS += $(shell $(PKG_CONFIG) libmnl --cflags)
+LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs)
+
+endif
+
+all: $(TARGETS) $(LIBS)
+
+devlink: $(DEVLINKOBJ)
+
+install: all
+	install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR)
+
+clean:
+	rm -f $(DEVLINKOBJ) $(TARGETS)
diff --git a/devlink/devlink.c b/devlink/devlink.c
new file mode 100644
index 0000000..6bda925
--- /dev/null
+++ b/devlink/devlink.c
@@ -0,0 +1,987 @@
+/*
+ * devlink.c	Devlink tool
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Authors:     Jiri Pirko <jiri@mellanox.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <limits.h>
+#include <errno.h>
+#include <linux/genetlink.h>
+#include <linux/devlink.h>
+#include <libmnl/libmnl.h>
+
+#include "SNAPSHOT.h"
+#include "list.h"
+#include "mnlg.h"
+
+#define pr_err(args...) fprintf(stderr, ##args)
+#define pr_out(args...) fprintf(stdout, ##args)
+
+static int _mnlg_socket_recv_run(struct mnlg_socket *nlg,
+				 mnl_cb_t data_cb, void *data)
+{
+	int err;
+
+	err = mnlg_socket_recv_run(nlg, data_cb, data);
+	if (err < 0) {
+		pr_err("devlink answers: %s\n", strerror(errno));
+		return -errno;
+	}
+	return 0;
+}
+
+static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg,
+			       const struct nlmsghdr *nlh,
+			       mnl_cb_t data_cb, void *data)
+{
+	int err;
+
+	err = mnlg_socket_send(nlg, nlh);
+	if (err < 0) {
+		pr_err("Failed to call mnlg_socket_send\n");
+		return -errno;
+	}
+	return _mnlg_socket_recv_run(nlg, data_cb, data);
+}
+
+static int _mnlg_socket_group_add(struct mnlg_socket *nlg,
+				  const char *group_name)
+{
+	int err;
+
+	err = mnlg_socket_group_add(nlg, group_name);
+	if (err < 0) {
+		pr_err("Failed to call mnlg_socket_group_add\n");
+		return -errno;
+	}
+	return 0;
+}
+
+struct ifname_map {
+	struct list_head list;
+	char *bus_name;
+	char *dev_name;
+	uint32_t port_index;
+	char *ifname;
+};
+
+static struct ifname_map *ifname_map_alloc(const char *bus_name,
+					   const char *dev_name,
+					   uint32_t port_index,
+					   const char *ifname)
+{
+	struct ifname_map *ifname_map;
+
+	ifname_map = calloc(1, sizeof(*ifname_map));
+	if (!ifname_map)
+		return NULL;
+	ifname_map->bus_name = strdup(bus_name);
+	ifname_map->dev_name = strdup(dev_name);
+	ifname_map->port_index = port_index;
+	ifname_map->ifname = strdup(ifname);
+	if (!ifname_map->bus_name || !ifname_map->dev_name ||
+	    !ifname_map->ifname) {
+		free(ifname_map->ifname);
+		free(ifname_map->dev_name);
+		free(ifname_map->bus_name);
+		free(ifname_map);
+		return NULL;
+	}
+	return ifname_map;
+}
+
+static void ifname_map_free(struct ifname_map *ifname_map)
+{
+	free(ifname_map->ifname);
+	free(ifname_map->dev_name);
+	free(ifname_map->bus_name);
+	free(ifname_map);
+}
+
+struct dl {
+	struct mnlg_socket *nlg;
+	struct list_head ifname_map_list;
+	int argc;
+	char **argv;
+};
+
+static int dl_argc(struct dl *dl)
+{
+	return dl->argc;
+}
+
+static char *dl_argv(struct dl *dl)
+{
+	if (dl_argc(dl) == 0)
+		return NULL;
+	return *dl->argv;
+}
+
+static void dl_arg_inc(struct dl *dl)
+{
+	if (dl_argc(dl) == 0)
+		return;
+	dl->argc--;
+	dl->argv++;
+}
+
+static char *dl_argv_next(struct dl *dl)
+{
+	char *ret;
+
+	if (dl_argc(dl) == 0)
+		return NULL;
+
+	ret = *dl->argv;
+	dl_arg_inc(dl);
+	return ret;
+}
+
+static char *dl_argv_index(struct dl *dl, unsigned int index)
+{
+	if (index >= dl_argc(dl))
+		return NULL;
+	return dl->argv[index];
+}
+
+static int strcmpx(const char *str1, const char *str2)
+{
+	if (strlen(str1) > strlen(str2))
+		return -1;
+	return strncmp(str1, str2, strlen(str1));
+}
+
+static bool dl_argv_match(struct dl *dl, const char *pattern)
+{
+	if (dl_argc(dl) == 0)
+		return false;
+	return strcmpx(dl_argv(dl), pattern) == 0;
+}
+
+static bool dl_no_arg(struct dl *dl)
+{
+	return dl_argc(dl) == 0;
+}
+
+static int attr_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type;
+
+	type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, DEVLINK_ATTR_MAX) < 0)
+		return MNL_CB_ERROR;
+
+	if (type == DEVLINK_ATTR_BUS_NAME &&
+	    mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+		return MNL_CB_ERROR;
+	if (type == DEVLINK_ATTR_DEV_NAME &&
+	    mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+		return MNL_CB_ERROR;
+	if (type == DEVLINK_ATTR_PORT_INDEX &&
+	    mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+		return MNL_CB_ERROR;
+	if (type == DEVLINK_ATTR_PORT_TYPE &&
+	    mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
+		return MNL_CB_ERROR;
+	if (type == DEVLINK_ATTR_PORT_DESIRED_TYPE &&
+	    mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
+		return MNL_CB_ERROR;
+	if (type == DEVLINK_ATTR_PORT_NETDEV_IFINDEX &&
+	    mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+		return MNL_CB_ERROR;
+	if (type == DEVLINK_ATTR_PORT_NETDEV_NAME &&
+	    mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+		return MNL_CB_ERROR;
+	if (type == DEVLINK_ATTR_PORT_IBDEV_NAME &&
+	    mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+		return MNL_CB_ERROR;
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static int ifname_map_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+	struct dl *dl = data;
+	struct ifname_map *ifname_map;
+	const char *bus_name;
+	const char *dev_name;
+	uint32_t port_ifindex;
+	const char *port_ifname;
+
+	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+	    !tb[DEVLINK_ATTR_PORT_INDEX])
+		return MNL_CB_ERROR;
+
+	if (!tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
+		return MNL_CB_OK;
+
+	bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
+	dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
+	port_ifindex = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
+	port_ifname = mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]);
+	ifname_map = ifname_map_alloc(bus_name, dev_name,
+				      port_ifindex, port_ifname);
+	if (!ifname_map)
+		return MNL_CB_ERROR;
+	list_add(&ifname_map->list, &dl->ifname_map_list);
+
+	return MNL_CB_OK;
+}
+
+static void ifname_map_fini(struct dl *dl)
+{
+	struct ifname_map *ifname_map, *tmp;
+
+	list_for_each_entry_safe(ifname_map, tmp,
+				 &dl->ifname_map_list, list) {
+		list_del(&ifname_map->list);
+		ifname_map_free(ifname_map);
+	}
+}
+
+static int ifname_map_init(struct dl *dl)
+{
+	struct nlmsghdr *nlh;
+	int err;
+
+	INIT_LIST_HEAD(&dl->ifname_map_list);
+
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET,
+			       NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
+
+	err = _mnlg_socket_sndrcv(dl->nlg, nlh, ifname_map_cb, dl);
+	if (err) {
+		ifname_map_fini(dl);
+		return err;
+	}
+	return 0;
+}
+
+static int ifname_map_lookup(struct dl *dl, const char *ifname,
+			     char **p_bus_name, char **p_dev_name,
+			     uint32_t *p_port_index)
+{
+	struct ifname_map *ifname_map;
+
+	list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
+		if (strcmp(ifname, ifname_map->ifname) == 0) {
+			*p_bus_name = ifname_map->bus_name;
+			*p_dev_name = ifname_map->dev_name;
+			*p_port_index = ifname_map->port_index;
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+static unsigned int strslashcount(char *str)
+{
+	unsigned int count = 0;
+	char *pos = str;
+
+	while ((pos = strchr(pos, '/'))) {
+		count++;
+		pos++;
+	}
+	return count;
+}
+
+static int strslashrsplit(char *str, char **before, char **after)
+{
+	char *slash;
+
+	slash = strrchr(str, '/');
+	if (!slash)
+		return -EINVAL;
+	*slash = '\0';
+	*before = str;
+	*after = slash + 1;
+	return 0;
+}
+
+static int strtouint32_t(const char *str, uint32_t *p_val)
+{
+	char *endptr;
+	unsigned long int val;
+
+	val = strtoul(str, &endptr, 10);
+	if (endptr == str || *endptr != '\0')
+		return -EINVAL;
+	if (val > UINT_MAX)
+		return -ERANGE;
+	*p_val = val;
+	return 0;
+}
+
+static int dl_argv_put_handle(struct nlmsghdr *nlh, struct dl *dl)
+{
+	char *str = dl_argv_next(dl);
+	char *bus_name = bus_name;
+	char *dev_name = dev_name;
+
+	if (!str) {
+		pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
+		return -EINVAL;
+	}
+	if (strslashcount(str) != 1) {
+		pr_err("Wrong devlink identification string format.\n");
+		pr_err("Expected \"bus_name/dev_name\".\n");
+		return -EINVAL;
+	}
+
+	strslashrsplit(str, &bus_name, &dev_name);
+	mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, bus_name);
+	mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, dev_name);
+	return 0;
+}
+
+static int dl_argv_put_handle_port(struct nlmsghdr *nlh, struct dl *dl)
+{
+	char *str = dl_argv_next(dl);
+	unsigned int slash_count;
+	char *bus_name = bus_name;
+	char *dev_name = dev_name;
+	uint32_t port_index = port_index;
+	int err;
+
+	if (!str) {
+		pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
+		return -EINVAL;
+	}
+	slash_count = strslashcount(str);
+	if (slash_count != 2 && slash_count != 0) {
+		pr_err("Wrong port identification string format.\n");
+		pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
+		return -EINVAL;
+	}
+
+	if (slash_count == 2) {
+		char *handlestr = handlestr;
+		char *portstr = portstr;
+
+		err = strslashrsplit(str, &handlestr, &portstr);
+		err = strtouint32_t(portstr, &port_index);
+		if (err) {
+			pr_err("Port index \"%s\" is not a number or not within range\n",
+			       portstr);
+			return err;
+		}
+		strslashrsplit(handlestr, &bus_name, &dev_name);
+	} else if (slash_count == 0) {
+		err = ifname_map_lookup(dl, str, &bus_name, &dev_name,
+					&port_index);
+		if (err) {
+			pr_err("Netdevice \"%s\" not found\n", str);
+			return err;
+		}
+	}
+	mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, bus_name);
+	mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, dev_name);
+	mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, port_index);
+	return 0;
+}
+
+static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val)
+{
+	char *str = dl_argv_next(dl);
+	int err;
+
+	if (!str) {
+		pr_err("Unsigned number argument expected\n");
+		return -EINVAL;
+	}
+
+	err = strtouint32_t(str, p_val);
+	if (err) {
+		pr_err("\"%s\" is not a number or not within range\n", str);
+		return err;
+	}
+	return 0;
+}
+
+static int dl_argv_str(struct dl *dl, const char **p_str)
+{
+	const char *str = dl_argv_next(dl);
+
+	if (!str) {
+		pr_err("String parameter expected\n");
+		return -EINVAL;
+	}
+	*p_str = str;
+	return 0;
+}
+
+static int port_type_get(const char *typestr, enum devlink_port_type *p_type)
+{
+	if (strcmp(typestr, "auto") == 0) {
+		*p_type = DEVLINK_PORT_TYPE_AUTO;
+	} else if (strcmp(typestr, "eth") == 0) {
+		*p_type = DEVLINK_PORT_TYPE_ETH;
+	} else if (strcmp(typestr, "ib") == 0) {
+		*p_type = DEVLINK_PORT_TYPE_IB;
+	} else {
+		pr_err("Unknown port type \"%s\"\n", typestr);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#define BIT(nr)                 (1UL << (nr))
+#define DL_OPT_HANDLE		BIT(0)
+#define DL_OPT_HANDLEP		BIT(1)
+#define DL_OPT_PORT_TYPE	BIT(2)
+#define DL_OPT_PORT_COUNT	BIT(3)
+
+static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
+			     uint32_t o_required, uint32_t o_optional)
+{
+	uint32_t o_all = o_required | o_optional;
+	uint32_t o_found = 0;
+	int err;
+
+	if (o_required & DL_OPT_HANDLE) {
+		err = dl_argv_put_handle(nlh, dl);
+		if (err)
+			return err;
+	} else if (o_required & DL_OPT_HANDLEP) {
+		err = dl_argv_put_handle_port(nlh, dl);
+		if (err)
+			return err;
+	}
+
+	while (dl_argc(dl)) {
+		if (dl_argv_match(dl, "type") &&
+		    (o_all & DL_OPT_PORT_TYPE)) {
+			enum devlink_port_type port_type;
+			const char *typestr;
+
+			dl_arg_inc(dl);
+			err = dl_argv_str(dl, &typestr);
+			if (err)
+				return err;
+			err = port_type_get(typestr, &port_type);
+			if (err)
+				return err;
+			mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
+					 port_type);
+			o_found |= DL_OPT_PORT_TYPE;
+		} else if (dl_argv_match(dl, "count") &&
+			   (o_all & DL_OPT_PORT_COUNT)) {
+			uint32_t count;
+
+			dl_arg_inc(dl);
+			err = dl_argv_uint32_t(dl, &count);
+			if (err)
+				return err;
+			mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT,
+					 count);
+			o_found |= DL_OPT_PORT_COUNT;
+		} else {
+			pr_err("Unknown option \"%s\"\n", dl_argv(dl));
+			return -EINVAL;
+		}
+	}
+
+	if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) {
+		pr_err("Port type option expected.\n");
+		return -EINVAL;
+	}
+
+	if ((o_required & DL_OPT_PORT_COUNT) &&
+	    !(o_found & DL_OPT_PORT_COUNT)) {
+		pr_err("Port split count option expected.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void cmd_dev_help(void)
+{
+	pr_out("Usage: devlink dev show [ DEV ]\n");
+}
+
+static void pr_out_handle(struct nlattr **tb)
+{
+	pr_out("%s/%s", mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]),
+			mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]));
+}
+
+static void pr_out_dev(struct nlattr **tb)
+{
+	pr_out_handle(tb);
+	pr_out("\n");
+}
+
+static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+
+	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
+		return MNL_CB_ERROR;
+	pr_out_dev(tb);
+	return MNL_CB_OK;
+}
+
+static int cmd_dev_show(struct dl *dl)
+{
+	struct nlmsghdr *nlh;
+	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
+	int err;
+
+	if (dl_argc(dl) == 0)
+		flags |= NLM_F_DUMP;
+
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
+
+	if (dl_argc(dl) > 0) {
+		err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
+		if (err)
+			return err;
+	}
+
+	return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL);
+}
+
+static int cmd_dev(struct dl *dl)
+{
+	if (dl_argv_match(dl, "help")) {
+		cmd_dev_help();
+		return 0;
+	} else if (dl_argv_match(dl, "show") ||
+		   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
+		dl_arg_inc(dl);
+		return cmd_dev_show(dl);
+	}
+	pr_err("Command \"%s\" not found\n", dl_argv(dl));
+	return -ENOENT;
+}
+
+static void cmd_port_help(void)
+{
+	pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
+	pr_out("       dl port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
+	pr_out("       dl port split DEV/PORT_INDEX count COUNT\n");
+	pr_out("       dl port unsplit DEV/PORT_INDEX\n");
+}
+
+static const char *port_type_name(uint32_t type)
+{
+	switch (type) {
+	case DEVLINK_PORT_TYPE_NOTSET: return "notset";
+	case DEVLINK_PORT_TYPE_AUTO: return "auto";
+	case DEVLINK_PORT_TYPE_ETH: return "eth";
+	case DEVLINK_PORT_TYPE_IB: return "ib";
+	default: return "<unknown type>";
+	}
+}
+
+static void pr_out_port(struct nlattr **tb)
+{
+	struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
+	struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
+
+	pr_out_handle(tb);
+	pr_out("/%d:", mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]));
+	if (pt_attr) {
+		uint16_t port_type = mnl_attr_get_u16(pt_attr);
+
+		pr_out(" type %s", port_type_name(port_type));
+		if (dpt_attr) {
+			uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
+
+			if (port_type != des_port_type)
+				pr_out("(%s)", port_type_name(des_port_type));
+		}
+	}
+	if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
+		pr_out(" netdev %s",
+		       mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
+	if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
+		pr_out(" ibdev %s",
+		       mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
+	if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
+		pr_out(" split_group %u",
+		       mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
+	pr_out("\n");
+}
+
+static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+
+	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+	    !tb[DEVLINK_ATTR_PORT_INDEX])
+		return MNL_CB_ERROR;
+	pr_out_port(tb);
+	return MNL_CB_OK;
+}
+
+static int cmd_port_show(struct dl *dl)
+{
+	struct nlmsghdr *nlh;
+	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
+	int err;
+
+	if (dl_argc(dl) == 0)
+		flags |= NLM_F_DUMP;
+
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
+
+	if (dl_argc(dl) > 0) {
+		err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
+		if (err)
+			return err;
+	}
+
+	return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL);
+}
+
+static int cmd_port_set(struct dl *dl)
+{
+	struct nlmsghdr *nlh;
+	int err;
+
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
+			       NLM_F_REQUEST | NLM_F_ACK);
+
+	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
+	if (err)
+		return err;
+
+	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+}
+
+static int cmd_port_split(struct dl *dl)
+{
+	struct nlmsghdr *nlh;
+	int err;
+
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
+			       NLM_F_REQUEST | NLM_F_ACK);
+
+	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
+	if (err)
+		return err;
+
+	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+}
+
+static int cmd_port_unsplit(struct dl *dl)
+{
+	struct nlmsghdr *nlh;
+	int err;
+
+	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
+			       NLM_F_REQUEST | NLM_F_ACK);
+
+	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
+	if (err)
+		return err;
+
+	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+}
+
+static int cmd_port(struct dl *dl)
+{
+	if (dl_argv_match(dl, "help")) {
+		cmd_port_help();
+		return 0;
+	} else if (dl_argv_match(dl, "show") ||
+		   dl_argv_match(dl, "list") ||  dl_no_arg(dl)) {
+		dl_arg_inc(dl);
+		return cmd_port_show(dl);
+	} else if (dl_argv_match(dl, "set")) {
+		dl_arg_inc(dl);
+		return cmd_port_set(dl);
+	} else if (dl_argv_match(dl, "split")) {
+		dl_arg_inc(dl);
+		return cmd_port_split(dl);
+	} else if (dl_argv_match(dl, "unsplit")) {
+		dl_arg_inc(dl);
+		return cmd_port_unsplit(dl);
+	}
+	pr_err("Command \"%s\" not found\n", dl_argv(dl));
+	return -ENOENT;
+}
+
+static const char *cmd_name(uint8_t cmd)
+{
+	switch (cmd) {
+	case DEVLINK_CMD_UNSPEC: return "unspec";
+	case DEVLINK_CMD_GET: return "get";
+	case DEVLINK_CMD_SET: return "set";
+	case DEVLINK_CMD_NEW: return "new";
+	case DEVLINK_CMD_DEL: return "del";
+	case DEVLINK_CMD_PORT_GET: return "get";
+	case DEVLINK_CMD_PORT_SET: return "set";
+	case DEVLINK_CMD_PORT_NEW: return "net";
+	case DEVLINK_CMD_PORT_DEL: return "del";
+	default: return "<unknown cmd>";
+	}
+}
+
+static const char *cmd_obj(uint8_t cmd)
+{
+	switch (cmd) {
+	case DEVLINK_CMD_UNSPEC: return "unspec";
+	case DEVLINK_CMD_GET:
+	case DEVLINK_CMD_SET:
+	case DEVLINK_CMD_NEW:
+	case DEVLINK_CMD_DEL:
+		return "dev";
+	case DEVLINK_CMD_PORT_GET:
+	case DEVLINK_CMD_PORT_SET:
+	case DEVLINK_CMD_PORT_NEW:
+	case DEVLINK_CMD_PORT_DEL:
+		return "port";
+	default: return "<unknown obj>";
+	}
+}
+
+static void pr_out_mon_header(uint8_t cmd)
+{
+	pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
+}
+
+static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
+{
+	const char *obj = cmd_obj(cmd);
+	unsigned int index = 0;
+	const char *cur_obj;
+
+	if (dl_no_arg(dl))
+		return true;
+	while ((cur_obj = dl_argv_index(dl, index++))) {
+		if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
+			return true;
+	}
+	return false;
+}
+
+static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct dl *dl = data;
+	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+	uint8_t cmd = genl->cmd;
+
+	if (!cmd_filter_check(dl, cmd))
+		return MNL_CB_OK;
+
+	switch (cmd) {
+	case DEVLINK_CMD_GET: /* fall through */
+	case DEVLINK_CMD_SET: /* fall through */
+	case DEVLINK_CMD_NEW: /* fall through */
+	case DEVLINK_CMD_DEL:
+		mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+		if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
+			return MNL_CB_ERROR;
+		pr_out_mon_header(genl->cmd);
+		pr_out_dev(tb);
+		break;
+	case DEVLINK_CMD_PORT_GET: /* fall through */
+	case DEVLINK_CMD_PORT_SET: /* fall through */
+	case DEVLINK_CMD_PORT_NEW: /* fall through */
+	case DEVLINK_CMD_PORT_DEL:
+		mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+		if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+		    !tb[DEVLINK_ATTR_PORT_INDEX])
+			return MNL_CB_ERROR;
+		pr_out_mon_header(genl->cmd);
+		pr_out_port(tb);
+		break;
+	}
+	return MNL_CB_OK;
+}
+
+static int cmd_mon_show(struct dl *dl)
+{
+	int err;
+	unsigned int index = 0;
+	const char *cur_obj;
+
+	while ((cur_obj = dl_argv_index(dl, index++))) {
+		if (strcmp(cur_obj, "all") != 0 &&
+		    strcmp(cur_obj, "dev") != 0 &&
+		    strcmp(cur_obj, "port") != 0) {
+			pr_err("Unknown object \"%s\"\n", cur_obj);
+			return -EINVAL;
+		}
+	}
+	err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
+	if (err)
+		return err;
+	err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
+	if (err)
+		return err;
+	return 0;
+}
+
+static void cmd_mon_help(void)
+{
+	pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
+	       "where  OBJECT-LIST := { dev | port }\n");
+}
+
+static int cmd_mon(struct dl *dl)
+{
+	if (dl_argv_match(dl, "help")) {
+		cmd_mon_help();
+		return 0;
+	} else if (dl_no_arg(dl)) {
+		dl_arg_inc(dl);
+		return cmd_mon_show(dl);
+	}
+	pr_err("Command \"%s\" not found\n", dl_argv(dl));
+	return -ENOENT;
+}
+
+static void help(void)
+{
+	pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
+	       "where  OBJECT := { dev | port | monitor }\n"
+	       "       OPTIONS := { -V[ersion] }\n");
+}
+
+static int dl_cmd(struct dl *dl)
+{
+	if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
+		help();
+		return 0;
+	} else if (dl_argv_match(dl, "dev")) {
+		dl_arg_inc(dl);
+		return cmd_dev(dl);
+	} else if (dl_argv_match(dl, "port")) {
+		dl_arg_inc(dl);
+		return cmd_port(dl);
+	} else if (dl_argv_match(dl, "monitor")) {
+		dl_arg_inc(dl);
+		return cmd_mon(dl);
+	}
+	pr_err("Object \"%s\" not found\n", dl_argv(dl));
+	return -ENOENT;
+}
+
+static int dl_init(struct dl *dl, int argc, char **argv)
+{
+	int err;
+
+	dl->argc = argc;
+	dl->argv = argv;
+
+	dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
+	if (!dl->nlg) {
+		pr_err("Failed to connect to devlink Netlink\n");
+		return -errno;
+	}
+
+	err = ifname_map_init(dl);
+	if (err) {
+		pr_err("Failed to create index map\n");
+		goto err_ifname_map_create;
+	}
+	return 0;
+
+err_ifname_map_create:
+	mnlg_socket_close(dl->nlg);
+	return err;
+}
+
+static void dl_fini(struct dl *dl)
+{
+	ifname_map_fini(dl);
+	mnlg_socket_close(dl->nlg);
+}
+
+static struct dl *dl_alloc(void)
+{
+	struct dl *dl;
+
+	dl = calloc(1, sizeof(*dl));
+	if (!dl)
+		return NULL;
+	return dl;
+}
+
+static void dl_free(struct dl *dl)
+{
+	free(dl);
+}
+
+int main(int argc, char **argv)
+{
+	static const struct option long_options[] = {
+		{ "Version",		no_argument,		NULL, 'V' },
+		{ NULL, 0, NULL, 0 }
+	};
+	struct dl *dl;
+	int opt;
+	int err;
+	int ret;
+
+	while ((opt = getopt_long(argc, argv, "V",
+				  long_options, NULL)) >= 0) {
+
+		switch (opt) {
+		case 'V':
+			printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
+			return EXIT_SUCCESS;
+		default:
+			pr_err("Unknown option.\n");
+			help();
+			return EXIT_FAILURE;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	dl = dl_alloc();
+	if (!dl) {
+		pr_err("Failed to allocate memory for devlink\n");
+		return EXIT_FAILURE;
+	}
+
+	err = dl_init(dl, argc, argv);
+	if (err) {
+		ret = EXIT_FAILURE;
+		goto dl_free;
+	}
+
+	err = dl_cmd(dl);
+	if (err) {
+		ret = EXIT_FAILURE;
+		goto dl_fini;
+	}
+
+	ret = EXIT_SUCCESS;
+
+dl_fini:
+	dl_fini(dl);
+dl_free:
+	dl_free(dl);
+
+	return ret;
+}
+
diff --git a/devlink/mnlg.c b/devlink/mnlg.c
new file mode 100644
index 0000000..9e27de2
--- /dev/null
+++ b/devlink/mnlg.c
@@ -0,0 +1,274 @@
+/*
+ *   mnlg.c	Generic Netlink helpers for libmnl
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Authors:     Jiri Pirko <jiri@mellanox.com>
+ */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <libmnl/libmnl.h>
+#include <linux/genetlink.h>
+
+#include "mnlg.h"
+
+struct mnlg_socket {
+	struct mnl_socket *nl;
+	char *buf;
+	uint32_t id;
+	uint8_t version;
+	unsigned int seq;
+	unsigned int portid;
+};
+
+static struct nlmsghdr *__mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
+					   uint16_t flags, uint32_t id,
+					   uint8_t version)
+{
+	struct nlmsghdr *nlh;
+	struct genlmsghdr *genl;
+
+	nlh = mnl_nlmsg_put_header(nlg->buf);
+	nlh->nlmsg_type	= id;
+	nlh->nlmsg_flags = flags;
+	nlg->seq = time(NULL);
+	nlh->nlmsg_seq = nlg->seq;
+
+	genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
+	genl->cmd = cmd;
+	genl->version = version;
+
+	return nlh;
+}
+
+struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
+				  uint16_t flags)
+{
+	return __mnlg_msg_prepare(nlg, cmd, flags, nlg->id, nlg->version);
+}
+
+int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh)
+{
+	return mnl_socket_sendto(nlg->nl, nlh, nlh->nlmsg_len);
+}
+
+int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data)
+{
+	int err;
+
+	do {
+		err = mnl_socket_recvfrom(nlg->nl, nlg->buf,
+					  MNL_SOCKET_BUFFER_SIZE);
+		if (err <= 0)
+			break;
+		err = mnl_cb_run(nlg->buf, err, nlg->seq, nlg->portid,
+				 data_cb, data);
+	} while (err > 0);
+
+	return err;
+}
+
+struct group_info {
+	bool found;
+	uint32_t id;
+	const char *name;
+};
+
+static int parse_mc_grps_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, CTRL_ATTR_MCAST_GRP_MAX) < 0)
+		return MNL_CB_OK;
+
+	switch (type) {
+	case CTRL_ATTR_MCAST_GRP_ID:
+		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+			return MNL_CB_ERROR;
+		break;
+	case CTRL_ATTR_MCAST_GRP_NAME:
+		if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+			return MNL_CB_ERROR;
+		break;
+	}
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static void parse_genl_mc_grps(struct nlattr *nested,
+			       struct group_info *group_info)
+{
+	struct nlattr *pos;
+	const char *name;
+
+	mnl_attr_for_each_nested(pos, nested) {
+		struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1] = {};
+
+		mnl_attr_parse_nested(pos, parse_mc_grps_cb, tb);
+		if (!tb[CTRL_ATTR_MCAST_GRP_NAME] ||
+		    !tb[CTRL_ATTR_MCAST_GRP_ID])
+			continue;
+
+		name = mnl_attr_get_str(tb[CTRL_ATTR_MCAST_GRP_NAME]);
+		if (strcmp(name, group_info->name) != 0)
+			continue;
+
+		group_info->id = mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
+		group_info->found = true;
+	}
+}
+
+static int get_group_id_attr_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
+		return MNL_CB_ERROR;
+
+	if (type == CTRL_ATTR_MCAST_GROUPS &&
+	    mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+		return MNL_CB_ERROR;
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static int get_group_id_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct group_info *group_info = data;
+	struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
+	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+
+	mnl_attr_parse(nlh, sizeof(*genl), get_group_id_attr_cb, tb);
+	if (!tb[CTRL_ATTR_MCAST_GROUPS])
+		return MNL_CB_ERROR;
+	parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS], group_info);
+	return MNL_CB_OK;
+}
+
+int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name)
+{
+	struct nlmsghdr *nlh;
+	struct group_info group_info;
+	int err;
+
+	nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY,
+				 NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1);
+	mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, nlg->id);
+
+	err = mnlg_socket_send(nlg, nlh);
+	if (err < 0)
+		return err;
+
+	group_info.found = false;
+	group_info.name = group_name;
+	err = mnlg_socket_recv_run(nlg, get_group_id_cb, &group_info);
+	if (err < 0)
+		return err;
+
+	if (!group_info.found) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	err = mnl_socket_setsockopt(nlg->nl, NETLINK_ADD_MEMBERSHIP,
+				    &group_info.id, sizeof(group_info.id));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int get_family_id_attr_cb(const struct nlattr *attr, void *data)
+{
+	const struct nlattr **tb = data;
+	int type = mnl_attr_get_type(attr);
+
+	if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
+		return MNL_CB_ERROR;
+
+	if (type == CTRL_ATTR_FAMILY_ID &&
+	    mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
+		return MNL_CB_ERROR;
+	tb[type] = attr;
+	return MNL_CB_OK;
+}
+
+static int get_family_id_cb(const struct nlmsghdr *nlh, void *data)
+{
+	uint32_t *p_id = data;
+	struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
+	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+
+	mnl_attr_parse(nlh, sizeof(*genl), get_family_id_attr_cb, tb);
+	if (!tb[CTRL_ATTR_FAMILY_ID])
+		return MNL_CB_ERROR;
+	*p_id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
+	return MNL_CB_OK;
+}
+
+struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version)
+{
+	struct mnlg_socket *nlg;
+	struct nlmsghdr *nlh;
+	int err;
+
+	nlg = malloc(sizeof(*nlg));
+	if (!nlg)
+		return NULL;
+
+	nlg->buf = malloc(MNL_SOCKET_BUFFER_SIZE);
+	if (!nlg->buf)
+		goto err_buf_alloc;
+
+	nlg->nl = mnl_socket_open(NETLINK_GENERIC);
+	if (!nlg->nl)
+		goto err_mnl_socket_open;
+
+	err = mnl_socket_bind(nlg->nl, 0, MNL_SOCKET_AUTOPID);
+	if (err < 0)
+		goto err_mnl_socket_bind;
+
+	nlg->portid = mnl_socket_get_portid(nlg->nl);
+
+	nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY,
+				 NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1);
+	mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name);
+
+	err = mnlg_socket_send(nlg, nlh);
+	if (err < 0)
+		goto err_mnlg_socket_send;
+
+	err = mnlg_socket_recv_run(nlg, get_family_id_cb, &nlg->id);
+	if (err < 0)
+		goto err_mnlg_socket_recv_run;
+
+	nlg->version = version;
+	return nlg;
+
+err_mnlg_socket_recv_run:
+err_mnlg_socket_send:
+err_mnl_socket_bind:
+	mnl_socket_close(nlg->nl);
+err_mnl_socket_open:
+	free(nlg->buf);
+err_buf_alloc:
+	free(nlg);
+	return NULL;
+}
+
+void mnlg_socket_close(struct mnlg_socket *nlg)
+{
+	mnl_socket_close(nlg->nl);
+	free(nlg->buf);
+	free(nlg);
+}
diff --git a/devlink/mnlg.h b/devlink/mnlg.h
new file mode 100644
index 0000000..4d1babf
--- /dev/null
+++ b/devlink/mnlg.h
@@ -0,0 +1,27 @@
+/*
+ *   mnlg.h	Generic Netlink helpers for libmnl
+ *
+ *              This program is free software; you can redistribute it and/or
+ *              modify it under the terms of the GNU General Public License
+ *              as published by the Free Software Foundation; either version
+ *              2 of the License, or (at your option) any later version.
+ *
+ * Authors:     Jiri Pirko <jiri@mellanox.com>
+ */
+
+#ifndef _MNLG_H_
+#define _MNLG_H_
+
+#include <libmnl/libmnl.h>
+
+struct mnlg_socket;
+
+struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
+				  uint16_t flags);
+int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh);
+int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data);
+int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name);
+struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version);
+void mnlg_socket_close(struct mnlg_socket *nlg);
+
+#endif /* _MNLG_H_ */
diff --git a/include/linux/devlink.h b/include/linux/devlink.h
new file mode 100644
index 0000000..c9fee57
--- /dev/null
+++ b/include/linux/devlink.h
@@ -0,0 +1,72 @@
+/*
+ * include/uapi/linux/devlink.h - Network physical device Netlink interface
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _UAPI_LINUX_DEVLINK_H_
+#define _UAPI_LINUX_DEVLINK_H_
+
+#define DEVLINK_GENL_NAME "devlink"
+#define DEVLINK_GENL_VERSION 0x1
+#define DEVLINK_GENL_MCGRP_CONFIG_NAME "config"
+
+enum devlink_command {
+	/* don't change the order or add anything between, this is ABI! */
+	DEVLINK_CMD_UNSPEC,
+
+	DEVLINK_CMD_GET,		/* can dump */
+	DEVLINK_CMD_SET,
+	DEVLINK_CMD_NEW,
+	DEVLINK_CMD_DEL,
+
+	DEVLINK_CMD_PORT_GET,		/* can dump */
+	DEVLINK_CMD_PORT_SET,
+	DEVLINK_CMD_PORT_NEW,
+	DEVLINK_CMD_PORT_DEL,
+
+	DEVLINK_CMD_PORT_SPLIT,
+	DEVLINK_CMD_PORT_UNSPLIT,
+
+	/* add new commands above here */
+
+	__DEVLINK_CMD_MAX,
+	DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
+};
+
+enum devlink_port_type {
+	DEVLINK_PORT_TYPE_NOTSET,
+	DEVLINK_PORT_TYPE_AUTO,
+	DEVLINK_PORT_TYPE_ETH,
+	DEVLINK_PORT_TYPE_IB,
+};
+
+enum devlink_attr {
+	/* don't change the order or add anything between, this is ABI! */
+	DEVLINK_ATTR_UNSPEC,
+
+	/* bus name + dev name together are a handle for devlink entity */
+	DEVLINK_ATTR_BUS_NAME,			/* string */
+	DEVLINK_ATTR_DEV_NAME,			/* string */
+
+	DEVLINK_ATTR_PORT_INDEX,		/* u32 */
+	DEVLINK_ATTR_PORT_TYPE,			/* u16 */
+	DEVLINK_ATTR_PORT_DESIRED_TYPE,		/* u16 */
+	DEVLINK_ATTR_PORT_NETDEV_IFINDEX,	/* u32 */
+	DEVLINK_ATTR_PORT_NETDEV_NAME,		/* string */
+	DEVLINK_ATTR_PORT_IBDEV_NAME,		/* string */
+	DEVLINK_ATTR_PORT_SPLIT_COUNT,		/* u32 */
+	DEVLINK_ATTR_PORT_SPLIT_GROUP,		/* u32 */
+
+	/* add new attributes above here, update the policy in devlink.c */
+
+	__DEVLINK_ATTR_MAX,
+	DEVLINK_ATTR_MAX = __DEVLINK_ATTR_MAX - 1
+};
+
+#endif /* _UAPI_LINUX_DEVLINK_H_ */
diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8
new file mode 100644
index 0000000..7878d89
--- /dev/null
+++ b/man/man8/devlink-dev.8
@@ -0,0 +1,58 @@
+.TH DEVLINK\-DEV 8 "14 Mar 2016" "iproute2" "Linux"
+.SH NAME
+devlink-dev \- devlink device configuration
+.SH SYNOPSIS
+.sp
+.ad l
+.in +8
+.ti -8
+.B devlink
+.RI "[ " OPTIONS " ]"
+.B dev
+.RI  " { " COMMAND " | "
+.BR help " }"
+.sp
+
+.ti -8
+.IR OPTIONS " := { "
+\fB\-V\fR[\fIersion\fR] |
+
+.ti -8
+.B devlink dev show
+.RI "[ " DEV " ]"
+
+.ti -8
+.B devlink dev help
+
+.SH "DESCRIPTION"
+.SS devlink dev show - display devlink device attributes
+
+.PP
+.I "DEV"
+- specifies the devlink device to show.
+If this argument is omitted all devices are listed.
+
+.in +4
+Format is:
+.in +2
+BUS_NAME/BUS_ADDRESS
+
+.SH "EXAMPLES"
+.PP
+devlink dev show
+.RS 4
+Shows the state of all devlink devices on the system.
+.RE
+.PP
+devlink dev show pci/0000:01:00.0
+.RS 4
+Shows the state of specified devlink device.
+
+.SH SEE ALSO
+.BR devlink (8),
+.BR devlink-port (8),
+.BR devlink-monitor (8),
+.br
+
+.SH AUTHOR
+Jiri Pirko <jiri@mellanox.com>
diff --git a/man/man8/devlink-monitor.8 b/man/man8/devlink-monitor.8
new file mode 100644
index 0000000..98134c3
--- /dev/null
+++ b/man/man8/devlink-monitor.8
@@ -0,0 +1,36 @@
+.TH DEVLINK\-MONITOR 8 "14 Mar 2016" "iproute2" "Linux"
+.SH "NAME"
+devlink-monitor \- state monitoring
+.SH SYNOPSIS
+.sp
+.ad l
+.in +8
+.ti -8
+.BR "devlink monitor" " [ " all " |"
+.IR OBJECT-LIST " ]"
+.sp
+
+.SH DESCRIPTION
+The
+.B devlink
+utility can monitor the state of devlink devices and ports
+continuously. This option has a slightly different format. Namely, the
+.B monitor
+command is the first in the command line and then the object list.
+
+.I OBJECT-LIST
+is the list of object types that we want to monitor.
+It may contain
+.BR dev ", " port ".
+
+.B devlink
+opens Devlink Netlink socket, listens on it and dumps state changes.
+
+.SH SEE ALSO
+.BR devlink (8),
+.BR devlink-dev (8),
+.BR devlink-port (8),
+.br
+
+.SH AUTHOR
+Jiri Pirko <jiri@mellanox.com>
diff --git a/man/man8/devlink-port.8 b/man/man8/devlink-port.8
new file mode 100644
index 0000000..e6ae686
--- /dev/null
+++ b/man/man8/devlink-port.8
@@ -0,0 +1,126 @@
+.TH DEVLINK\-PORT 8 "14 Mar 2016" "iproute2" "Linux"
+.SH NAME
+devlink-port \- devlink port configuration
+.SH SYNOPSIS
+.sp
+.ad l
+.in +8
+.ti -8
+.B devlink
+.RI "[ " OPTIONS " ]"
+.B port
+.RI  " { " COMMAND " | "
+.BR help " }"
+.sp
+
+.ti -8
+.IR OPTIONS " := { "
+\fB\-V\fR[\fIersion\fR] |
+
+.ti -8
+.BR "devlink port set "
+.IR DEV/PORT_INDEX
+.RI "[ "
+.BR type " { " eth " | " ib " | " auto " }"
+.RI "]"
+
+.ti -8
+.BR "devlink port split "
+.IR DEV/PORT_INDEX
+.BR count
+.IR COUNT
+
+.ti -8
+.BR "devlink port unsplit "
+.IR DEV/PORT_INDEX
+
+.ti -8
+.B devlink port show
+.RI "[ " DEV/PORT_INDEX " ]"
+
+.ti -8
+.B devlink port help
+
+.SH "DESCRIPTION"
+.SS devlink port set - change devlink port attributes
+
+.PP
+.B "DEV/PORT_INDEX"
+- specifies the devlink port to operate on.
+
+.in +4
+Format is:
+.in +2
+BUS_NAME/BUS_ADDRESS/PORT_INDEX
+
+.TP
+.BR type " { " eth " | " ib " | " auto " } "
+set port type
+
+.I eth
+- Ethernet
+
+.I ib
+- Infiniband
+
+.I auto
+- autoselect
+
+.SS devlink port split - split devlink port into more
+
+.PP
+.B "DEV/PORT_INDEX"
+- specifies the devlink port to operate on.
+
+.TP
+.BI count " COUNT"
+number of ports to split to.
+
+.SS devlink port unsplit - unsplit previously split devlink port
+Could be performed on any split port of the same split group.
+
+.PP
+.B "DEV/PORT_INDEX"
+- specifies the devlink port to operate on.
+
+.SS devlink port show - display devlink port attributes
+
+.PP
+.I "DEV/PORT_INDEX"
+- specifies the devlink port to show.
+If this argument is omitted all ports are listed.
+
+.SH "EXAMPLES"
+.PP
+devlink port show
+.RS 4
+Shows the state of all devlink ports on the system.
+.RE
+.PP
+devlink port show pci/0000:01:00.0/1
+.RS 4
+Shows the state of specified devlink port.
+.RE
+.PP
+devlink port set pci/0000:01:00.0/1 type eth
+.RS 4
+Set type of specified devlink port to Ethernet.
+.RE
+.PP
+devlink port split pci/0000:01:00.0/1 count 4
+.RS 4
+Split the specified devlink port into four ports.
+.RE
+.PP
+devlink port unsplit pci/0000:01:00.0/1
+.RS 4
+Unplit the specified previously split devlink port.
+
+.SH SEE ALSO
+.BR devlink (8),
+.BR devlink-dev (8),
+.BR devlink-monitor (8),
+.br
+
+.SH AUTHOR
+Jiri Pirko <jiri@mellanox.com>
diff --git a/man/man8/devlink.8 b/man/man8/devlink.8
new file mode 100644
index 0000000..f608ccc
--- /dev/null
+++ b/man/man8/devlink.8
@@ -0,0 +1,83 @@
+.TH DEVLINK 8 "14 Mar 2016" "iproute2" "Linux"
+.SH NAME
+devlink \- Devlink tool
+.SH SYNOPSIS
+.sp
+.ad l
+.in +8
+.ti -8
+.B devlink
+.RI "[ " OPTIONS " ] " OBJECT " { " COMMAND " | "
+.BR help " }"
+.sp
+
+.ti -8
+.IR OBJECT " := { "
+.BR dev " | " port " | " monitor " }"
+.sp
+
+.ti -8
+.IR OPTIONS " := { "
+\fB\-V\fR[\fIersion\fR] |
+
+.SH OPTIONS
+
+.TP
+.BR "\-V" , " -Version"
+Print the version of the
+.B devlink
+utility and exit.
+
+.SS
+.I OBJECT
+
+.TP
+.B dev
+- devlink device.
+
+.TP
+.B port
+- devlink port.
+
+.TP
+.B monitor
+- watch for netlink messages.
+
+.SS
+.I COMMAND
+
+Specifies the action to perform on the object.
+The set of possible actions depends on the object type.
+As a rule, it is possible to
+.B show
+(or
+.B list
+) objects, but some objects do not allow all of these operations
+or have some additional commands. The
+.B help
+command is available for all objects. It prints
+out a list of available commands and argument syntax conventions.
+.sp
+If no command is given, some default command is assumed.
+Usually it is
+.B list
+or, if the objects of this class cannot be listed,
+.BR "help" .
+
+.SH EXIT STATUS
+Exit status is 0 if command was successful or a positive integer upon failure.
+
+.SH SEE ALSO
+.BR devlink-dev (8),
+.BR devlink-port (8),
+.BR devlink-monitor (8),
+.br
+
+.SH REPORTING BUGS
+Report any bugs to the Network Developers mailing list
+.B <netdev@vger.kernel.org>
+where the development and maintenance is primarily done.
+You do not have to be subscribed to the list to send a message there.
+
+.SH AUTHOR
+Jiri Pirko <jiri@mellanox.com>
-- 
2.5.5

^ permalink raw reply related

* [patch iproute2 v2 1/2] include: add linked list implementation from kernel
From: Jiri Pirko @ 2016-03-22  9:02 UTC (permalink / raw)
  To: netdev
  Cc: stephen, davem, idosch, eladr, yotamg, ogerlitz, yishaih,
	dledford, sean.hefty, hal.rosenstock, eugenia, roopa, nikolay,
	hadarh, jhs, john.fastabend, jeffrey.t.kirsher, brouer, ivecera,
	rami.rosen, hannes, gospo

From: Jiri Pirko <jiri@mellanox.com>

Rename hlist.h to list.h while adding it to be aligned with kernel

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
v1->v2:
- fix some checkpatch issues
---
 include/hlist.h |  56 ----------------------------
 include/list.h  | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ip/ipnetns.c    |   2 +-
 lib/ll_map.c    |   2 +-
 tc/tc_class.c   |   2 +-
 5 files changed, 115 insertions(+), 59 deletions(-)
 delete mode 100644 include/hlist.h
 create mode 100644 include/list.h

diff --git a/include/hlist.h b/include/hlist.h
deleted file mode 100644
index 4e8de9e..0000000
--- a/include/hlist.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __HLIST_H__
-#define __HLIST_H__ 1
-/* Hash list stuff from kernel */
-
-#include <stddef.h>
-
-#define container_of(ptr, type, member) ({			\
-	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
-	(type *)( (char *)__mptr - offsetof(type,member) );})
-
-struct hlist_head {
-	struct hlist_node *first;
-};
-
-struct hlist_node {
-	struct hlist_node *next, **pprev;
-};
-
-static inline void hlist_del(struct hlist_node *n)
-{
-	struct hlist_node *next = n->next;
-	struct hlist_node **pprev = n->pprev;
-	*pprev = next;
-	if (next)
-		next->pprev = pprev;
-}
-
-static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
-{
-	struct hlist_node *first = h->first;
-	n->next = first;
-	if (first)
-		first->pprev = &n->next;
-	h->first = n;
-	n->pprev = &h->first;
-}
-
-#define hlist_for_each(pos, head) \
-	for (pos = (head)->first; pos ; pos = pos->next)
-
-
-#define hlist_for_each_safe(pos, n, head) \
-	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
-	     pos = n)
-
-#define hlist_entry_safe(ptr, type, member) \
-	({ typeof(ptr) ____ptr = (ptr); \
-	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
-	})
-
-#define hlist_for_each_entry(pos, head, member)				\
-	for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
-	     pos;							\
-	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
-
-#endif /* __HLIST_H__ */
diff --git a/include/list.h b/include/list.h
new file mode 100644
index 0000000..cdebe4d
--- /dev/null
+++ b/include/list.h
@@ -0,0 +1,112 @@
+#ifndef __LIST_H__
+#define __LIST_H__ 1
+/* List and hash list stuff from kernel */
+
+#include <stddef.h>
+
+#define container_of(ptr, type, member) ({			\
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+#define list_first_entry(ptr, type, member) \
+	list_entry((ptr)->next, type, member)
+
+#define list_next_entry(pos, member) \
+	list_entry((pos)->member.next, typeof(*(pos)), member)
+
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_first_entry(head, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = list_next_entry(pos, member))
+
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_first_entry(head, typeof(*pos), member),	\
+		n = list_next_entry(pos, member);			\
+	     &pos->member != (head);					\
+	     pos = n, n = list_next_entry(n, member))
+
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+struct hlist_node {
+	struct hlist_node *next, **pprev;
+};
+
+static inline void hlist_del(struct hlist_node *n)
+{
+	struct hlist_node *next = n->next;
+	struct hlist_node **pprev = n->pprev;
+	*pprev = next;
+	if (next)
+		next->pprev = pprev;
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+	struct hlist_node *first = h->first;
+	n->next = first;
+	if (first)
+		first->pprev = &n->next;
+	h->first = n;
+	n->pprev = &h->first;
+}
+
+#define hlist_for_each(pos, head) \
+	for (pos = (head)->first; pos ; pos = pos->next)
+
+
+#define hlist_for_each_safe(pos, n, head) \
+	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+	     pos = n)
+
+#define hlist_entry_safe(ptr, type, member) \
+	({ typeof(ptr) ____ptr = (ptr); \
+	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
+	})
+
+#define hlist_for_each_entry(pos, head, member)				\
+	for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
+	     pos;							\
+	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#endif /* __LIST_H__ */
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 4ce5989..0596b2c 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -18,7 +18,7 @@
 #include <linux/net_namespace.h>
 
 #include "utils.h"
-#include "hlist.h"
+#include "list.h"
 #include "ip_common.h"
 #include "namespace.h"
 
diff --git a/lib/ll_map.c b/lib/ll_map.c
index c6f7027..fa14a77 100644
--- a/lib/ll_map.c
+++ b/lib/ll_map.c
@@ -22,7 +22,7 @@
 
 #include "libnetlink.h"
 #include "ll_map.h"
-#include "hlist.h"
+#include "list.h"
 
 struct ll_cache {
 	struct hlist_node idx_hash;
diff --git a/tc/tc_class.c b/tc/tc_class.c
index 3acd030..7d3b009 100644
--- a/tc/tc_class.c
+++ b/tc/tc_class.c
@@ -24,7 +24,7 @@
 #include "utils.h"
 #include "tc_util.h"
 #include "tc_common.h"
-#include "hlist.h"
+#include "list.h"
 
 struct graph_node {
 	struct hlist_node hlist;
-- 
2.5.5

^ permalink raw reply related

* [PATCH net v2] ipv4: fix broadcast packets reception
From: Paolo Abeni @ 2016-03-22  8:19 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Alexey Kuznetsov, Shawn Bohrer,
	Hannes Frederic Sowa

Currently, ingress ipv4 broadcast datagrams are dropped since,
in udp_v4_early_demux(), ip_check_mc_rcu() is invoked even on
bcast packets.

This patch addresses the issue, invoking ip_check_mc_rcu()
only for mcast packets.

Fixes: 6e5403093261 ("ipv4/udp: Verify multicast group is ours in upd_v4_early_demux()")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

--
 v1 -> v2 droped the route related bits, the fib_validate_source()
  failures are triggered by the in_device configuration
---
 net/ipv4/udp.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 836abe5..08eed5e 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2070,10 +2070,14 @@ void udp_v4_early_demux(struct sk_buff *skb)
 		if (!in_dev)
 			return;
 
-		ours = ip_check_mc_rcu(in_dev, iph->daddr, iph->saddr,
-				       iph->protocol);
-		if (!ours)
-			return;
+		/* we are supposed to accept bcast packets */
+		if (skb->pkt_type == PACKET_MULTICAST) {
+			ours = ip_check_mc_rcu(in_dev, iph->daddr, iph->saddr,
+					       iph->protocol);
+			if (!ours)
+				return;
+		}
+
 		sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr,
 						   uh->source, iph->saddr, dif);
 	} else if (skb->pkt_type == PACKET_HOST) {
-- 
1.8.3.1

^ permalink raw reply related

* Re: [PATCH v2] openvswitch: call only into reachable nf-nat code
From: Pablo Neira Ayuso @ 2016-03-22  8:10 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: dev-yBygre7rU0TnMu66kgdUjQ, netdev-u79uwXL29TY76Z2rM5mHXA,
	Florian Westphal, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	Joe Stringer, Eric W. Biederman, Paolo Abeni, David S. Miller
In-Reply-To: <1458308044-246105-1-git-send-email-arnd-r2nGTMty4D4@public.gmane.org>

On Fri, Mar 18, 2016 at 02:33:45PM +0100, Arnd Bergmann wrote:
> The openvswitch code has gained support for calling into the
> nf-nat-ipv4/ipv6 modules, however those can be loadable modules
> in a configuration in which openvswitch is built-in, leading
> to link errors:
> 
> net/built-in.o: In function `__ovs_ct_lookup':
> :(.text+0x2cc2c8): undefined reference to `nf_nat_icmp_reply_translation'
> :(.text+0x2cc66c): undefined reference to `nf_nat_icmpv6_reply_translation'
> 
> The dependency on (!NF_NAT || NF_NAT) prevents similar issues,
> but NF_NAT is set to 'y' if any of the symbols selecting
> it are built-in, but the link error happens when any of them
> are modular.
> 
> A second issue is that even if CONFIG_NF_NAT_IPV6 is built-in,
> CONFIG_NF_NAT_IPV4 might be completely disabled. This is unlikely
> to be useful in practice, but the driver currently only handles
> IPv6 being optional.
> 
> This patch improves the Kconfig dependency so that openvswitch
> cannot be built-in if either of the two other symbols are set
> to 'm', and it replaces the incorrect #ifdef in ovs_ct_nat_execute()
> with two "if (IS_ENABLED())" checks that should catch all corner
> cases also make the code more readable.
> 
> The same #ifdef exists ovs_ct_nat_to_attr(), where it does not
> cause a link error, but for consistency I'm changing it the same
> way.

Applied, thanks Arnd.
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

^ permalink raw reply

* Re: net/bluetooth: workqueue destruction WARNING in hci_unregister_dev
From: Jiri Slaby @ 2016-03-22  8:09 UTC (permalink / raw)
  To: Tejun Heo, Dmitry Vyukov
  Cc: Marcel Holtmann, Gustavo Padovan, Johan Hedberg, David S. Miller,
	linux-bluetooth-u79uwXL29TY76Z2rM5mHXA, netdev, LKML, syzkaller,
	Kostya Serebryany, Alexander Potapenko, Sasha Levin, Eric Dumazet,
	Takashi Iwai
In-Reply-To: <56F01A1C.40208-AlSwsSmVLrQ@public.gmane.org>

On 03/21/2016, 04:58 PM, Jiri Slaby wrote:
> Hello,
> 
> On 03/18/2016, 09:52 PM, Tejun Heo wrote:
>> On Thu, Mar 17, 2016 at 01:00:13PM +0100, Jiri Slaby wrote:
>>>>> I have not done that yet, but today, I see:
>>>>> destroy_workqueue: name='req_hci0' pwq=ffff88002f590300
>>>>> wq->dfl_pwq=ffff88002f591e00 pwq->refcnt=2 pwq->nr_active=0 delayed_works:
>>>>>    pwq 12: cpus=0-1 node=0 flags=0x4 nice=-20 active=0/1
>>>>>      in-flight: 18568:wq_barrier_func
>>>>
>>>> So, this means that there's flush_work() racing against workqueue
>>>> destruction, which can't be safe. :(
>>>
>>> But I cannot trigger the WARN_ONs in the attached patch, so I am
>>> confused how this can happen :(. (While I am still seeing the destroy
>>> WARNINGs.)
>>
>> So, no operations should be in progress when destroy_workqueue() is
>> called.  If somebody was flushing a work item, the flush call must
>> have returned before destroy_workqueue() was invoked, which doesn't
>> seem to be the case here.  Can you trigger BUG_ON() or sysrq-t when
>> the above triggers?  There must be a task which is flushing a work
>> item there and it shouldn't be difficult to pinpoint what's going on
>> from it.
> 
> The output of sysrq-t is here (> 200k), but I cannot see anything
> suspicious in it:
> http://www.fi.muni.cz/~xslaby/sklad/panics/jctl.txt

Hmm, so I seem I cannot reproduce with this hunk:
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3139,10 +3139,10 @@ void hci_unregister_dev(struct hci_dev *hdev)
        list_del(&hdev->list);
        write_unlock(&hci_dev_list_lock);

-       hci_dev_do_close(hdev);
-
        cancel_work_sync(&hdev->power_on);

+       hci_dev_do_close(hdev);
+
        if (!test_bit(HCI_INIT, &hdev->flags) &&
            !hci_dev_test_flag(hdev, HCI_SETUP) &&
            !hci_dev_test_flag(hdev, HCI_CONFIG)) {



I cannot explain why though. I do not see how it matters in this
particular case...

Dmitry, could you apply it too? But I don't know how often you see the
warning.

PS. next on the table is the gsm tty warning.

thanks,
-- 
js
suse labs

^ permalink raw reply

* [PATCH V2 net 07/10] net: hns: fixes a bug of RSS
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Kejian Yan <yankejian@huawei.com>

If trying to get receive flow hash indirection table by ethtool, it needs
to call .get_rxnfc to get ring number first. So this patch implements the
.get_rxnfc of ethtool. And the data type of rss_indir_table is u32, it has
to be multiply by the width of data type when using memcpy.

Signed-off-by: Kejian Yan <yankejian@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c |  6 ++++--
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c  | 18 ++++++++++++++++++
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index 648b31a..285c893 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -791,7 +791,8 @@ static int hns_ae_get_rss(struct hnae_handle *handle, u32 *indir, u8 *key,
 		memcpy(key, ppe_cb->rss_key, HNS_PPEV2_RSS_KEY_SIZE);
 
 	/* update the current hash->queue mappings from the shadow RSS table */
-	memcpy(indir, ppe_cb->rss_indir_table, HNS_PPEV2_RSS_IND_TBL_SIZE);
+	memcpy(indir, ppe_cb->rss_indir_table,
+	       HNS_PPEV2_RSS_IND_TBL_SIZE * sizeof(*indir));
 
 	return 0;
 }
@@ -806,7 +807,8 @@ static int hns_ae_set_rss(struct hnae_handle *handle, const u32 *indir,
 		hns_ppe_set_rss_key(ppe_cb, (u32 *)key);
 
 	/* update the shadow RSS table with user specified qids */
-	memcpy(ppe_cb->rss_indir_table, indir, HNS_PPEV2_RSS_IND_TBL_SIZE);
+	memcpy(ppe_cb->rss_indir_table, indir,
+	       HNS_PPEV2_RSS_IND_TBL_SIZE * sizeof(*indir));
 
 	/* now update the hardware */
 	hns_ppe_set_indir_table(ppe_cb, ppe_cb->rss_indir_table);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index 2229905..9c3ba65 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -1245,6 +1245,23 @@ hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key,
 	return ops->set_rss(priv->ae_handle, indir, key, hfunc);
 }
 
+static int hns_get_rxnfc(struct net_device *netdev,
+			 struct ethtool_rxnfc *cmd,
+			 u32 *rule_locs)
+{
+	struct hns_nic_priv *priv = netdev_priv(netdev);
+
+	switch (cmd->cmd) {
+	case ETHTOOL_GRXRINGS:
+		cmd->data = priv->ae_handle->q_num;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
 static struct ethtool_ops hns_ethtool_ops = {
 	.get_drvinfo = hns_nic_get_drvinfo,
 	.get_link  = hns_nic_get_link,
@@ -1268,6 +1285,7 @@ static struct ethtool_ops hns_ethtool_ops = {
 	.get_rxfh_indir_size = hns_get_rss_indir_size,
 	.get_rxfh = hns_get_rss,
 	.set_rxfh = hns_set_rss,
+	.get_rxnfc = hns_get_rxnfc,
 };
 
 void hns_ethtool_set_ops(struct net_device *ndev)
-- 
1.9.1

^ permalink raw reply related

* [PATCH V2 net 04/10] net: hns: fixed the bug about GMACs mac setting
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Sheng Li <lisheng011@huawei.com>

When sending a pause frame out from GMACs, the packets' source MAC address
does not match the GMACs' MAC address. It causes by the condition before
the mac address setting routine for GMACs, the mac address cannot be set
into loacal mac table for service ports. It obviously the condition needs
to be deleted.

Signed-off-by: Sheng Li <lisheng011@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
index b8cf0e4..6e2b76e 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
@@ -422,19 +422,17 @@ static void hns_gmac_set_mac_addr(void *mac_drv, char *mac_addr)
 {
 	struct mac_driver *drv = (struct mac_driver *)mac_drv;
 
-	if (drv->mac_id >= DSAF_SERVICE_NW_NUM) {
-		u32 high_val = mac_addr[1] | (mac_addr[0] << 8);
+	u32 high_val = mac_addr[1] | (mac_addr[0] << 8);
 
-		u32 low_val = mac_addr[5] | (mac_addr[4] << 8)
-			| (mac_addr[3] << 16) | (mac_addr[2] << 24);
+	u32 low_val = mac_addr[5] | (mac_addr[4] << 8)
+		| (mac_addr[3] << 16) | (mac_addr[2] << 24);
 
-		u32 val = dsaf_read_dev(drv, GMAC_STATION_ADDR_HIGH_2_REG);
-		u32 sta_addr_en = dsaf_get_bit(val, GMAC_ADDR_EN_B);
+	u32 val = dsaf_read_dev(drv, GMAC_STATION_ADDR_HIGH_2_REG);
+	u32 sta_addr_en = dsaf_get_bit(val, GMAC_ADDR_EN_B);
 
-		dsaf_write_dev(drv, GMAC_STATION_ADDR_LOW_2_REG, low_val);
-		dsaf_write_dev(drv, GMAC_STATION_ADDR_HIGH_2_REG,
-			       high_val | (sta_addr_en << GMAC_ADDR_EN_B));
-	}
+	dsaf_write_dev(drv, GMAC_STATION_ADDR_LOW_2_REG, low_val);
+	dsaf_write_dev(drv, GMAC_STATION_ADDR_HIGH_2_REG,
+		       high_val | (sta_addr_en << GMAC_ADDR_EN_B));
 }
 
 static int hns_gmac_config_loopback(void *mac_drv, enum hnae_loop loop_mode,
-- 
1.9.1

^ permalink raw reply related

* [PATCH V2 net 03/10] net: hns: add uc match for debug ports
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Kejian Yan <yankejian@huawei.com>

Debug ports receives lots of packets with dest mac addr does not match
local mac addr, because the filter is close, and it does not drop the
useless packets. This patch adds ON/OFF switch of filtering the packets
whose dest mac addr do not match the local addr in  mac table. And the
switch is ON in initialization.

Signed-off-by: Kejian Yan <yankejian@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
change log:
 PATCH v2:
  - fix the comments like unnecessary casts

 PATCH v1:
  - first submit

  Link: https://lkml.org/lkml/2016/3/21/224
---
 drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c  |  3 +++
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c | 28 +++++++++++++++++++++-
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c  |  8 +++++++
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h  |  4 +++-
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h  |  2 ++
 5 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index 90352d6..a7427b8 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -420,7 +420,10 @@ static int hns_ae_set_autoneg(struct hnae_handle *handle, u8 enable)
 
 static void hns_ae_set_promisc_mode(struct hnae_handle *handle, u32 en)
 {
+	struct hns_mac_cb *mac_cb = hns_get_mac_cb(handle);
+
 	hns_dsaf_set_promisc_mode(hns_ae_get_dsaf_dev(handle->dev), en);
+	hns_mac_set_promisc(mac_cb, (u8)!!en);
 }
 
 static int hns_ae_get_autoneg(struct hnae_handle *handle)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
index b8517b0..b8cf0e4 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
@@ -290,6 +290,24 @@ static int hns_gmac_adjust_link(void *mac_drv, enum mac_speed speed,
 	return 0;
 }
 
+static void hns_gmac_set_uc_match(void *mac_drv, u16 en)
+{
+	struct mac_driver *drv = mac_drv;
+
+	dsaf_set_dev_bit(drv, GMAC_REC_FILT_CONTROL_REG,
+			 GMAC_UC_MATCH_EN_B, !en);
+	dsaf_set_dev_bit(drv, GMAC_STATION_ADDR_HIGH_2_REG,
+			 GMAC_ADDR_EN_B, !en);
+}
+
+static void hns_gmac_set_promisc(void *mac_drv, u8 en)
+{
+	struct mac_driver *drv = mac_drv;
+
+	if (drv->mac_cb->mac_type == HNAE_PORT_DEBUG)
+		hns_gmac_set_uc_match(mac_drv, en);
+}
+
 static void hns_gmac_init(void *mac_drv)
 {
 	u32 port;
@@ -305,6 +323,8 @@ static void hns_gmac_init(void *mac_drv)
 	mdelay(10);
 	hns_gmac_disable(mac_drv, MAC_COMM_MODE_RX_AND_TX);
 	hns_gmac_tx_loop_pkt_dis(mac_drv);
+	if (drv->mac_cb->mac_type == HNAE_PORT_DEBUG)
+		hns_gmac_set_uc_match(mac_drv, 0);
 }
 
 void hns_gmac_update_stats(void *mac_drv)
@@ -407,8 +427,13 @@ static void hns_gmac_set_mac_addr(void *mac_drv, char *mac_addr)
 
 		u32 low_val = mac_addr[5] | (mac_addr[4] << 8)
 			| (mac_addr[3] << 16) | (mac_addr[2] << 24);
+
+		u32 val = dsaf_read_dev(drv, GMAC_STATION_ADDR_HIGH_2_REG);
+		u32 sta_addr_en = dsaf_get_bit(val, GMAC_ADDR_EN_B);
+
 		dsaf_write_dev(drv, GMAC_STATION_ADDR_LOW_2_REG, low_val);
-		dsaf_write_dev(drv, GMAC_STATION_ADDR_HIGH_2_REG, high_val);
+		dsaf_write_dev(drv, GMAC_STATION_ADDR_HIGH_2_REG,
+			       high_val | (sta_addr_en << GMAC_ADDR_EN_B));
 	}
 }
 
@@ -699,6 +724,7 @@ void *hns_gmac_config(struct hns_mac_cb *mac_cb, struct mac_params *mac_param)
 	mac_drv->get_sset_count = hns_gmac_get_sset_count;
 	mac_drv->get_strings = hns_gmac_get_strings;
 	mac_drv->update_stats = hns_gmac_update_stats;
+	mac_drv->set_promiscuous = hns_gmac_set_promisc;
 
 	return (void *)mac_drv;
 }
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index 5ef0e96..138737d 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -861,6 +861,14 @@ int hns_mac_get_sset_count(struct hns_mac_cb *mac_cb, int stringset)
 	return mac_ctrl_drv->get_sset_count(stringset);
 }
 
+void hns_mac_set_promisc(struct hns_mac_cb *mac_cb, u8 en)
+{
+	struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
+
+	if (mac_ctrl_drv->set_promiscuous)
+		mac_ctrl_drv->set_promiscuous(mac_ctrl_drv, en);
+}
+
 int hns_mac_get_regs_count(struct hns_mac_cb *mac_cb)
 {
 	struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
index 0b05219..0f60968 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
@@ -365,7 +365,7 @@ struct mac_driver {
 	/*config rx pause enable*/
 	void (*set_rx_ignore_pause_frames)(void *mac_drv, u32 enable);
 	/* config rx mode for promiscuous*/
-	int (*set_promiscuous)(void *mac_drv, u8 enable);
+	void (*set_promiscuous)(void *mac_drv, u8 enable);
 	/* get mac id */
 	void (*mac_get_id)(void *mac_drv, u8 *mac_id);
 	void (*mac_pausefrm_cfg)(void *mac_drv, u32 rx_en, u32 tx_en);
@@ -453,4 +453,6 @@ int hns_mac_get_regs_count(struct hns_mac_cb *mac_cb);
 void hns_set_led_opt(struct hns_mac_cb *mac_cb);
 int hns_cpld_led_set_id(struct hns_mac_cb *mac_cb,
 			enum hnae_led_state status);
+void hns_mac_set_promisc(struct hns_mac_cb *mac_cb, u8 en);
+
 #endif /* _HNS_DSAF_MAC_H */
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
index 60d695d..bf62687 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
@@ -922,6 +922,8 @@
 #define GMAC_LP_REG_CF2MI_LP_EN_B	2
 
 #define GMAC_MODE_CHANGE_EB_B	0
+#define GMAC_UC_MATCH_EN_B	0
+#define GMAC_ADDR_EN_B		16
 
 #define GMAC_RECV_CTRL_STRIP_PAD_EN_B	3
 #define GMAC_RECV_CTRL_RUNT_PKT_EN_B	4
-- 
1.9.1

^ permalink raw reply related

* [PATCH V2 net 02/10] net: hns: fixed portid bug in sending manage pkt
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Sheng Li <lisheng011@huawei.com>

In chip V2, the default value of port id in tx BD is Zero. If it is not
configurated to the other value, all management packets will be sent out
from port0. So port_id in the tx BD needs to be updated when sending a
management packet.

In V2 chip, when sending mamagement packets, the driver should
config the port id to BD descs.

Signed-off-by: Sheng Li <lisheng011@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hnae.h         | 3 +++
 drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 1 +
 drivers/net/ethernet/hisilicon/hns/hns_enet.c     | 6 +++++-
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h
index 1cbcb9f..37d0cce 100644
--- a/drivers/net/ethernet/hisilicon/hns/hnae.h
+++ b/drivers/net/ethernet/hisilicon/hns/hnae.h
@@ -147,6 +147,8 @@ enum hnae_led_state {
 
 #define HNSV2_TXD_BUFNUM_S 0
 #define HNSV2_TXD_BUFNUM_M (0x7 << HNSV2_TXD_BUFNUM_S)
+#define HNSV2_TXD_PORTID_S	4
+#define HNSV2_TXD_PORTID_M	(0X7 << HNSV2_TXD_PORTID_S)
 #define HNSV2_TXD_RI_B   1
 #define HNSV2_TXD_L4CS_B   2
 #define HNSV2_TXD_L3CS_B   3
@@ -516,6 +518,7 @@ struct hnae_handle {
 	int q_num;
 	int vf_id;
 	u32 eport_id;
+	u32 dport_id;	/* v2 tx bd should fill the dport_id */
 	enum hnae_port_type port_type;
 	struct list_head node;    /* list to hnae_ae_dev->handle_list */
 	struct hnae_buf_ops *bops; /* operation for the buffer */
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
index d4f92ed..90352d6 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
@@ -175,6 +175,7 @@ struct hnae_handle *hns_ae_get_handle(struct hnae_ae_dev *dev,
 	ae_handle->phy_node = vf_cb->mac_cb->phy_node;
 	ae_handle->if_support = vf_cb->mac_cb->if_support;
 	ae_handle->port_type = vf_cb->mac_cb->mac_type;
+	ae_handle->dport_id = port_idx;
 
 	return ae_handle;
 vf_id_err:
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index ef84bd7..ef517af 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -66,10 +66,14 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
 	desc->addr = cpu_to_le64(dma);
 	desc->tx.send_size = cpu_to_le16((u16)size);
 
-	/*config bd buffer end */
+	/* config bd buffer end */
 	hnae_set_bit(rrcfv, HNSV2_TXD_VLD_B, 1);
 	hnae_set_field(bn_pid, HNSV2_TXD_BUFNUM_M, 0, buf_num - 1);
 
+	/* fill port_id in the tx bd for sending management pkts */
+	hnae_set_field(bn_pid, HNSV2_TXD_PORTID_M,
+		       HNSV2_TXD_PORTID_S, ring->q->handle->dport_id);
+
 	if (type == DESC_TYPE_SKB) {
 		skb = (struct sk_buff *)priv;
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH V2 net 01/10] net: hns: bug fix about ping6
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Kejian Yan <yankejian@huawei.com>

The current upstreaming code fails to ping other IPv6 net device, because
the enet receives the multicast packets with the src mac addr which is the
same as its mac addr. These packets need to be dropped.

Signed-off-by: Kejian Yan <yankejian@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
change log:
 PATCH v2:
 - modifies the wrong charator "whick" to "which" in commit log
 - use the "eth_hdr()" help to get source mac of packets

 PATCH v1:
 - first submit

 Link: https://lkml.org/lkml/2016/3/21/215
---
---
 drivers/net/ethernet/hisilicon/hns/hns_enet.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index 3f77ff7..ef84bd7 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -564,6 +564,7 @@ static int hns_nic_poll_rx_skb(struct hns_nic_ring_data *ring_data,
 	struct sk_buff *skb;
 	struct hnae_desc *desc;
 	struct hnae_desc_cb *desc_cb;
+	struct ethhdr *eh;
 	unsigned char *va;
 	int bnum, length, i;
 	int pull_len;
@@ -670,6 +671,14 @@ out_bnum_err:
 		return -EFAULT;
 	}
 
+	/* filter out multicast pkt with the same src mac as this port */
+	eh = eth_hdr(skb);
+	if (unlikely(is_multicast_ether_addr(eh->h_dest) &&
+		     ether_addr_equal(ndev->dev_addr, eh->h_source))) {
+		dev_kfree_skb_any(skb);
+		return -EFAULT;
+	}
+
 	ring->stats.rx_pkts++;
 	ring->stats.rx_bytes += skb->len;
 
-- 
1.9.1

^ permalink raw reply related

* Re: [RFCv2 0/3] mac80211: implement fq codel
From: Michal Kazior @ 2016-03-22  8:05 UTC (permalink / raw)
  To: Dave Taht
  Cc: Network Development, linux-wireless, ath10k@lists.infradead.org,
	Jasmine Strong, codel@lists.bufferbloat.net, make-wifi-fast
In-Reply-To: <CAA93jw5AAWua23TbQHZX47XcFLEqU6T=NpxuLqa6FiffBf91Fw@mail.gmail.com>

On 21 March 2016 at 18:10, Dave Taht <dave.taht@gmail.com> wrote:
> thx.
>
> a lot to digest.
>
> A) quick notes on "flent-gui bursts_11e-2016-03-21T09*.gz"
>
> 1) the new bursts_11e test *should* have stuck stuff in the VI and VO
> queues, and there *should* have been some sort of difference shown on
> the plots with it. There wasn't.

traffic-gen generates only BE traffic. Everything else runs UDP_RR
which doesn't generate a lot of traffic.


> For diffserv markings I used BE=CS0, BK=CS1, VI=CS5, and VO=EF.
> CS6/CS7 should also land in VO (at least with the soft mac handler
> last I looked). Is there a way to check if you are indeed exercising
> all four 802.11e hardware queues in this test? in ath9k it is the
> "xmit" sysfs var....

Hmm.. there are no txq stats. I guess it makes sense to have them?

There is /sys/kernel/debug/ieee80211/phy*/fq which dumps state of all
queues which will be mostly empty with UDP_RR. You can run netperf UDP
stream with diffserv marking to see onto which tid they are mapped.
You can see tid-AC mappings here:
https://wireless.wiki.kernel.org/en/developers/documentation/mac80211/queues

I just checked and EF ends up as tid5 which is VI. It's actually the
same as CS5. You can use CS7 to run on tid7 which is VO.


> 2) In all the old cases the BE UDP_RR flow died on the first burst
> (why?), and the fullpatch preserved it.

I think it's related to my setup which involves veth pairs. I use them
to simulate bridging/AP behavior but maybe it's not doing the job
right, hmm..


> (I would have kind of hoped to
> have seen the BK flow die, actually, in the fullpatch)

There's no extra weight priority to BK. The difference between BE and
BK in 802.11 is contention window access time so BK gets less txops
statistically. Both share the same txop, which is 5.484ms in most
cases.


> 3) I am also confused on 802.11ac - can VO aggregate? ( can't in in 802.11n).

Yes, it should be albeit VI and VO have shorter txop compared to
BE/BK: 3.008ms and 1.504ms respectively.

UDP_RR doesn't really create a lot of opportunities for aggregation.
If you want to see how different queues behave when loaded you'll need
to modify traffic-gen and add bursts across different ACs in the
bursts_11e test.


Michał
_______________________________________________
Codel mailing list
Codel@lists.bufferbloat.net
https://lists.bufferbloat.net/listinfo/codel

^ permalink raw reply

* [PATCH V2 net 09/10] net: hns: adds limitation for debug port mtu
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Kejian Yan <yankejian@huawei.com>

If mtu for debug port is set more than 1500, it may cause that packets
are dropped by ppe. So maximum value for debug port should be 1500.

Signed-off-by: Kejian Yan <yankejian@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
change log:
 PATCH V2:
  - use tabs instead of spaces to indent the value

 PATCH V1:
  - first submit

  Link: https://lkml.org/lkml/2016/3/21/217
---
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 3 +++
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index 50237fb..a38084a 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -470,6 +470,9 @@ int hns_mac_set_mtu(struct hns_mac_cb *mac_cb, u32 new_mtu)
 	u32 max_frm = AE_IS_VER1(mac_cb->dsaf_dev->dsaf_ver) ?
 			MAC_MAX_MTU : MAC_MAX_MTU_V2;
 
+	if (mac_cb->mac_type == HNAE_PORT_DEBUG)
+		max_frm = MAC_MAX_MTU_DBG;
+
 	if ((new_mtu < MAC_MIN_MTU) || (new_frm > max_frm) ||
 	    (new_frm > HNS_RCB_RING_MAX_BD_PER_PKT * buf_size))
 		return -EINVAL;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
index 7b47701..823b6e7 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
@@ -28,6 +28,7 @@ struct dsaf_device;
 #define MAC_MAX_MTU		9600
 #define MAC_MAX_MTU_V2		9728
 #define MAC_MIN_MTU		68
+#define MAC_MAX_MTU_DBG		MAC_DEFAULT_MTU
 
 #define MAC_DEFAULT_PAUSE_TIME 0xff
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH V2 net 05/10] net: hns: set xge statistic reg as read only
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Qianqian Xie <xieqianqian@huawei.com>

As the user manual of HNS V2 describs, XGE_DFX_CTRL_CFG.xge_dfx_ctrl_cfg
should be configed as zero if we want xge statistic reg to be read only.
But HNS V1 gets the other meanings. It needs to be identified the process
and then config it rightly.

Signed-off-by: Qianqian Xie <xieqianqian@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
index 38fc5be..5c1ac9b 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
@@ -748,8 +748,9 @@ static void hns_dsaf_tbl_stat_en(struct dsaf_device *dsaf_dev)
  */
 static void hns_dsaf_rocee_bp_en(struct dsaf_device *dsaf_dev)
 {
-	dsaf_set_dev_bit(dsaf_dev, DSAF_XGE_CTRL_SIG_CFG_0_REG,
-			 DSAF_FC_XGE_TX_PAUSE_S, 1);
+	if (AE_IS_VER1(dsaf_dev->dsaf_ver))
+		dsaf_set_dev_bit(dsaf_dev, DSAF_XGE_CTRL_SIG_CFG_0_REG,
+				 DSAF_FC_XGE_TX_PAUSE_S, 1);
 }
 
 /* set msk for dsaf exception irq*/
-- 
1.9.1

^ permalink raw reply related

* [PATCH V2 net 08/10] net: hns: fix the bug about mtu setting
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Kejian Yan <yankejian@huawei.com>

In chip V1, the maximum mtu value is 9600. But in chip V2, it is 9728.
And it is always configurates as 9600 before this patch.

Signed-off-by: Kejian Yan <yankejian@huawei.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c | 4 +++-
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h | 1 +
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c | 3 +++
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h | 2 ++
 4 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
index 138737d..50237fb 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c
@@ -467,8 +467,10 @@ int hns_mac_set_mtu(struct hns_mac_cb *mac_cb, u32 new_mtu)
 	struct mac_driver *drv = hns_mac_get_drv(mac_cb);
 	u32 buf_size = mac_cb->dsaf_dev->buf_size;
 	u32 new_frm = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+	u32 max_frm = AE_IS_VER1(mac_cb->dsaf_dev->dsaf_ver) ?
+			MAC_MAX_MTU : MAC_MAX_MTU_V2;
 
-	if ((new_mtu < MAC_MIN_MTU) || (new_frm > MAC_MAX_MTU) ||
+	if ((new_mtu < MAC_MIN_MTU) || (new_frm > max_frm) ||
 	    (new_frm > HNS_RCB_RING_MAX_BD_PER_PKT * buf_size))
 		return -EINVAL;
 
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
index 0f60968..7b47701 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h
@@ -26,6 +26,7 @@ struct dsaf_device;
 
 #define MAC_DEFAULT_MTU	(ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN + ETH_DATA_LEN)
 #define MAC_MAX_MTU		9600
+#define MAC_MAX_MTU_V2		9728
 #define MAC_MIN_MTU		68
 
 #define MAC_DEFAULT_PAUSE_TIME 0xff
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
index 06422c2..5b7ae5f 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
@@ -343,6 +343,9 @@ static void hns_ppe_init_hw(struct hns_ppe_cb *ppe_cb)
 	if (!AE_IS_VER1(dsaf_dev->dsaf_ver)) {
 		hns_ppe_set_vlan_strip(ppe_cb, 0);
 
+		dsaf_write_dev(ppe_cb, PPE_CFG_MAX_FRAME_LEN_REG,
+			       HNS_PPEV2_MAX_FRAME_LEN);
+
 		/* set default RSS key in h/w */
 		hns_ppe_set_rss_key(ppe_cb, ppe_cb->rss_key);
 
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h
index 0f5cb69..e9c0ec2 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h
@@ -30,6 +30,8 @@
 #define HNS_PPEV2_RSS_KEY_SIZE 40 /* in bytes or 320 bits */
 #define HNS_PPEV2_RSS_KEY_NUM (HNS_PPEV2_RSS_KEY_SIZE / sizeof(u32))
 
+#define HNS_PPEV2_MAX_FRAME_LEN 0X980
+
 enum ppe_qid_mode {
 	PPE_QID_MODE0 = 0, /* fixed queue id mode */
 	PPE_QID_MODE1,	   /* switch:128VM non switch:6Port/4VM/4TC */
-- 
1.9.1

^ permalink raw reply related

* [PATCH V2 net 00/10] net: hns: bugs fixed for hns
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm

This series includes some bug fixes and updates for hns driver.

>from Daode, one fix about mss.

>from Kejian, one fix about ping6 issue, one fix about mac address setting,
two fix for RSS setting, two fix about mtu setting.

>from qianqian, fixed HNS v2 xge statistic reg issue.

>from Sheng, one fix about manage packets sending, one fix about GMACs mac
setting.

For more details, please see individual patches.

Thanks a lot!

---
change log:
 Series V2:
  - fix the comments as below:
    1) modifies the wrong charator "whick" to "which" in commit log
    2) use the "eth_hdr()" help to get source mac of packets
    3) fix the wrong cast
    4) use tabs instead of spaces to indent the value

 Series V1:
  - first submit

Daode Huang (1):
  net: hns: bug fix about the overflow of mss

Kejian Yan (6):
  net: hns: bug fix about ping6
  net: hns: add uc match for debug ports
  net: hns: fix return value of the function about rss
  net: hns: fixes a bug of RSS
  net: hns: fix the bug about mtu setting
  net: hns: adds limitation for debug port mtu

Qianqian Xie (1):
  net: hns: set xge statistic reg as read only

Sheng Li (2):
  net: hns: fixed portid bug in sending manage pkt
  net: hns: fixed the bug about GMACs mac setting

 drivers/net/ethernet/hisilicon/hns/hnae.h          |  3 ++
 drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c  | 12 +++++--
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c | 38 ++++++++++++++++++----
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c  | 15 ++++++++-
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h  |  6 +++-
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c |  5 +--
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c  |  5 ++-
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h  |  2 ++
 drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h  |  2 ++
 drivers/net/ethernet/hisilicon/hns/hns_enet.c      | 32 ++++++++++++------
 drivers/net/ethernet/hisilicon/hns/hns_ethtool.c   | 38 +++++++++++++---------
 11 files changed, 117 insertions(+), 41 deletions(-)

-- 
1.9.1

^ permalink raw reply

* [PATCH V2 net 10/10] net: hns: bug fix about the overflow of mss
From: Yisen Zhuang @ 2016-03-22  8:06 UTC (permalink / raw)
  To: davem
  Cc: yankejian, huangdaode, salil.mehta, lisheng011, lipeng321,
	liguozhu, arnd, sergei.shtylyov, xieqianqian, andrew, ivecera,
	netdev, linux-kernel, linuxarm
In-Reply-To: <1458633991-64313-1-git-send-email-Yisen.Zhuang@huawei.com>

From: Daode Huang <huangdaode@hisilicon.com>

When set MTU to the minimum value 68, there are increasing number
of error packets occur, which is caused by the overflowed value of
mss. This patch fix the bug.

Signed-off-by: Daode Huang <huangdaode@hisilicon.com>
Signed-off-by: Yisen Zhuang <Yisen.Zhuang@huawei.com>
---
 drivers/net/ethernet/hisilicon/hns/hns_enet.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
index ef517af..71aa37b 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c
@@ -48,7 +48,6 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
 	struct iphdr *iphdr;
 	struct ipv6hdr *ipv6hdr;
 	struct sk_buff *skb;
-	int skb_tmp_len;
 	__be16 protocol;
 	u8 bn_pid = 0;
 	u8 rrcfv = 0;
@@ -94,13 +93,13 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
 				hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B, 1);
 
 				/* check for tcp/udp header */
-				if (iphdr->protocol == IPPROTO_TCP) {
+				if (iphdr->protocol == IPPROTO_TCP &&
+				    skb_is_gso(skb)) {
 					hnae_set_bit(tvsvsn,
 						     HNSV2_TXD_TSE_B, 1);
-					skb_tmp_len = SKB_TMP_LEN(skb);
 					l4_len = tcp_hdrlen(skb);
-					mss = mtu - skb_tmp_len - ETH_FCS_LEN;
-					paylen = skb->len - skb_tmp_len;
+					mss = skb_shinfo(skb)->gso_size;
+					paylen = skb->len - SKB_TMP_LEN(skb);
 				}
 			} else if (skb->protocol == htons(ETH_P_IPV6)) {
 				hnae_set_bit(tvsvsn, HNSV2_TXD_IPV6_B, 1);
@@ -108,13 +107,13 @@ static void fill_v2_desc(struct hnae_ring *ring, void *priv,
 				hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B, 1);
 
 				/* check for tcp/udp header */
-				if (ipv6hdr->nexthdr == IPPROTO_TCP) {
+				if (ipv6hdr->nexthdr == IPPROTO_TCP &&
+				    skb_is_gso(skb) && skb_is_gso_v6(skb)) {
 					hnae_set_bit(tvsvsn,
 						     HNSV2_TXD_TSE_B, 1);
-					skb_tmp_len = SKB_TMP_LEN(skb);
 					l4_len = tcp_hdrlen(skb);
-					mss = mtu - skb_tmp_len - ETH_FCS_LEN;
-					paylen = skb->len - skb_tmp_len;
+					mss = skb_shinfo(skb)->gso_size;
+					paylen = skb->len - SKB_TMP_LEN(skb);
 				}
 			}
 			desc->tx.ip_offset = ip_offset;
-- 
1.9.1

^ permalink raw reply related


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