* Re: [PATCH] netfilter: conntrack: Force inlining of build check to prevent build failure
From: Florian Westphal @ 2017-05-03 12:38 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: David S . Miller, Florian Westphal, Pablo Neira Ayuso,
Jozsef Kadlecsik, Arnd Bergmann, netfilter-devel, coreteam,
netdev, linux-kernel
In-Reply-To: <1493813923-5441-1-git-send-email-geert@linux-m68k.org>
Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> If gcc (e.g. 4.1.2) decides not to inline total_extension_size(), the
> build will fail with:
>
> net/built-in.o: In function `nf_conntrack_init_start':
> (.text+0x9baf6): undefined reference to `__compiletime_assert_1893'
>
> or
>
> ERROR: "__compiletime_assert_1893" [net/netfilter/nf_conntrack.ko] undefined!
>
> Fix this by forcing inlining of total_extension_size().
Sorry about that, thanks for the fix Geert.
Acked-by: Florian Westphal <fw@strlen.de>
^ permalink raw reply
* [PATCH v2 2/2] can: m_can: add deep Suspend/Resume support
From: Quentin Schulz @ 2017-05-03 12:37 UTC (permalink / raw)
To: wg, mkl, mario.huettel, socketcan
Cc: Quentin Schulz, linux-can, netdev, linux-kernel,
alexandre.belloni, thomas.petazzoni
In-Reply-To: <20170503123750.26134-1-quentin.schulz@free-electrons.com>
This adds Power Management deep Suspend/Resume support for Bosch M_CAN
chip.
When the system resumes from deep sleep, the chip needs to be fully
reinitialized (RAM, chip, clocks, irq, candev, ...) to be functional.
Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
drivers/net/can/m_can/m_can.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 3f0445440146..9e0143b528f1 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -1670,12 +1670,10 @@ static __maybe_unused int m_can_suspend(struct device *dev)
struct m_can_priv *priv = netdev_priv(ndev);
if (netif_running(ndev)) {
- netif_stop_queue(ndev);
netif_device_detach(ndev);
+ m_can_close(ndev);
}
- /* TODO: enter low power */
-
priv->can.state = CAN_STATE_SLEEPING;
return 0;
@@ -1686,13 +1684,13 @@ static __maybe_unused int m_can_resume(struct device *dev)
struct net_device *ndev = dev_get_drvdata(dev);
struct m_can_priv *priv = netdev_priv(ndev);
- /* TODO: exit low power */
+ m_can_init_ram(priv);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(ndev)) {
+ m_can_open(ndev);
netif_device_attach(ndev);
- netif_start_queue(ndev);
}
return 0;
--
2.11.0
^ permalink raw reply related
* [PATCH v2 1/2] can: m_can: move Message RAM initialization to function
From: Quentin Schulz @ 2017-05-03 12:37 UTC (permalink / raw)
To: wg, mkl, mario.huettel, socketcan
Cc: Quentin Schulz, linux-can, netdev, linux-kernel,
alexandre.belloni, thomas.petazzoni
To avoid possible ECC/parity checksum errors when reading an
uninitialized buffer, the entire Message RAM is initialized when probing
the driver. This initialization is done in the same function reading the
Device Tree properties.
This patch moves the RAM initialization to a separate function so it can
be called separately from device initialization from Device Tree.
Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
drivers/net/can/m_can/m_can.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index bf8fdaeb955e..3f0445440146 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -1489,6 +1489,20 @@ static int register_m_can_dev(struct net_device *dev)
return register_candev(dev);
}
+static void m_can_init_ram(struct m_can_priv *priv)
+{
+ int end, i, start;
+
+ /* initialize the entire Message RAM in use to avoid possible
+ * ECC/parity checksum errors when reading an uninitialized buffer
+ */
+ start = priv->mcfg[MRAM_SIDF].off;
+ end = priv->mcfg[MRAM_TXB].off +
+ priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
+ for (i = start; i < end; i += 4)
+ writel(0x0, priv->mram_base + i);
+}
+
static void m_can_of_parse_mram(struct m_can_priv *priv,
const u32 *mram_config_vals)
{
@@ -1529,15 +1543,7 @@ static void m_can_of_parse_mram(struct m_can_priv *priv,
priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
- /* initialize the entire Message RAM in use to avoid possible
- * ECC/parity checksum errors when reading an uninitialized buffer
- */
- start = priv->mcfg[MRAM_SIDF].off;
- end = priv->mcfg[MRAM_TXB].off +
- priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
- for (i = start; i < end; i += 4)
- writel(0x0, priv->mram_base + i);
-
+ m_can_init_ram(priv);
}
static int m_can_plat_probe(struct platform_device *pdev)
--
2.11.0
^ permalink raw reply related
* Re: [PATCH] netfilter: conntrack: Force inlining of build check to prevent build failure
From: Arnd Bergmann @ 2017-05-03 12:32 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: David S . Miller, Florian Westphal, Pablo Neira Ayuso,
Jozsef Kadlecsik, netfilter-devel, coreteam, Networking,
Linux Kernel Mailing List
In-Reply-To: <1493813923-5441-1-git-send-email-geert@linux-m68k.org>
On Wed, May 3, 2017 at 2:18 PM, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> If gcc (e.g. 4.1.2) decides not to inline total_extension_size(), the
> build will fail with:
>
> net/built-in.o: In function `nf_conntrack_init_start':
> (.text+0x9baf6): undefined reference to `__compiletime_assert_1893'
>
> or
>
> ERROR: "__compiletime_assert_1893" [net/netfilter/nf_conntrack.ko] undefined!
>
> Fix this by forcing inlining of total_extension_size().
>
> Fixes: b3a5db109e0670d6 ("netfilter: conntrack: use u8 for extension sizes again")
> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
I saw this as well when I tried building with "gcc-7 -Og", and came to the same
conclusion.
Acked-by: Arnd Bergmann <arnd@arndb.de>
With -Og, there were a couple of other instances of BUILD_BUG_ON() failing
to see a compile-time constant, presumably as it fails to inline any functions
that are not explicitly marked inline.
Arnd
^ permalink raw reply
* Re: [PATCH 2/2] can: m_can: add deep Suspend/Resume support
From: Quentin Schulz @ 2017-05-03 12:28 UTC (permalink / raw)
To: Marc Kleine-Budde, wg, mario.huettel, socketcan
Cc: linux-can, netdev, linux-kernel, alexandre.belloni,
thomas.petazzoni
In-Reply-To: <39fcd931-eca6-2e89-ff8b-14a54e9342fc@pengutronix.de>
[-- Attachment #1.1: Type: text/plain, Size: 906 bytes --]
Hi Marc,
On 03/05/2017 14:16, Marc Kleine-Budde wrote:
> On 05/03/2017 02:11 PM, Quentin Schulz wrote:
>> This adds Power Management deep Suspend/Resume support for Bosch M_CAN
>> chip.
>>
>> When the chip resumes from deep sleep, the RAM needs to be initialized
>> as it is done when the driver probes. The net interface also needs to be
>> closed and reopened to be fully functional.
>
> Are you sure it's the closing and opening of the net interface. Maybe
> it's the m_can_start() and/or the subsequent m_can_chip_config()?
>
You're right. The chip needs to be completely reinitialized (clocks,
chip itself) and it also closes and reopens the interface if I'm correct
with close_candev and open_candev.
I'm sending a v2 right away to fix the commit log.
Thanks,
Quentin
--
Quentin Schulz, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* [PATCH] netfilter: conntrack: Force inlining of build check to prevent build failure
From: Geert Uytterhoeven @ 2017-05-03 12:18 UTC (permalink / raw)
To: David S . Miller, Florian Westphal, Pablo Neira Ayuso,
Jozsef Kadlecsik
Cc: Arnd Bergmann, netfilter-devel, coreteam, netdev, linux-kernel,
Geert Uytterhoeven
If gcc (e.g. 4.1.2) decides not to inline total_extension_size(), the
build will fail with:
net/built-in.o: In function `nf_conntrack_init_start':
(.text+0x9baf6): undefined reference to `__compiletime_assert_1893'
or
ERROR: "__compiletime_assert_1893" [net/netfilter/nf_conntrack.ko] undefined!
Fix this by forcing inlining of total_extension_size().
Fixes: b3a5db109e0670d6 ("netfilter: conntrack: use u8 for extension sizes again")
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
net/netfilter/nf_conntrack_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f9245dbfe4356da6..3c8f1ed2f5558fe0 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1853,7 +1853,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize);
module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
&nf_conntrack_htable_size, 0600);
-static unsigned int total_extension_size(void)
+static __always_inline unsigned int total_extension_size(void)
{
/* remember to add new extensions below */
BUILD_BUG_ON(NF_CT_EXT_NUM > 9);
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 2/2] can: m_can: add deep Suspend/Resume support
From: Marc Kleine-Budde @ 2017-05-03 12:16 UTC (permalink / raw)
To: Quentin Schulz, wg, mario.huettel, socketcan
Cc: linux-can, netdev, linux-kernel, alexandre.belloni,
thomas.petazzoni
In-Reply-To: <20170503121143.25090-2-quentin.schulz@free-electrons.com>
[-- Attachment #1.1: Type: text/plain, Size: 756 bytes --]
On 05/03/2017 02:11 PM, Quentin Schulz wrote:
> This adds Power Management deep Suspend/Resume support for Bosch M_CAN
> chip.
>
> When the chip resumes from deep sleep, the RAM needs to be initialized
> as it is done when the driver probes. The net interface also needs to be
> closed and reopened to be fully functional.
Are you sure it's the closing and opening of the net interface. Maybe
it's the m_can_start() and/or the subsequent m_can_chip_config()?
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH 2/2] can: m_can: add deep Suspend/Resume support
From: Quentin Schulz @ 2017-05-03 12:11 UTC (permalink / raw)
To: wg, mkl, mario.huettel, socketcan
Cc: Quentin Schulz, linux-can, netdev, linux-kernel,
alexandre.belloni, thomas.petazzoni
In-Reply-To: <20170503121143.25090-1-quentin.schulz@free-electrons.com>
This adds Power Management deep Suspend/Resume support for Bosch M_CAN
chip.
When the chip resumes from deep sleep, the RAM needs to be initialized
as it is done when the driver probes. The net interface also needs to be
closed and reopened to be fully functional.
Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
drivers/net/can/m_can/m_can.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 3f0445440146..9e0143b528f1 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -1670,12 +1670,10 @@ static __maybe_unused int m_can_suspend(struct device *dev)
struct m_can_priv *priv = netdev_priv(ndev);
if (netif_running(ndev)) {
- netif_stop_queue(ndev);
netif_device_detach(ndev);
+ m_can_close(ndev);
}
- /* TODO: enter low power */
-
priv->can.state = CAN_STATE_SLEEPING;
return 0;
@@ -1686,13 +1684,13 @@ static __maybe_unused int m_can_resume(struct device *dev)
struct net_device *ndev = dev_get_drvdata(dev);
struct m_can_priv *priv = netdev_priv(ndev);
- /* TODO: exit low power */
+ m_can_init_ram(priv);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(ndev)) {
+ m_can_open(ndev);
netif_device_attach(ndev);
- netif_start_queue(ndev);
}
return 0;
--
2.11.0
^ permalink raw reply related
* [PATCH 1/2] can: m_can: move Message RAM initialization to function
From: Quentin Schulz @ 2017-05-03 12:11 UTC (permalink / raw)
To: wg, mkl, mario.huettel, socketcan
Cc: Quentin Schulz, linux-can, netdev, linux-kernel,
alexandre.belloni, thomas.petazzoni
To avoid possible ECC/parity checksum errors when reading an
uninitialized buffer, the entire Message RAM is initialized when probing
the driver. This initialization is done in the same function reading the
Device Tree properties.
This patch moves the RAM initialization to a separate function so it can
be called separately from device initialization from Device Tree.
Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
drivers/net/can/m_can/m_can.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index bf8fdaeb955e..3f0445440146 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -1489,6 +1489,20 @@ static int register_m_can_dev(struct net_device *dev)
return register_candev(dev);
}
+static void m_can_init_ram(struct m_can_priv *priv)
+{
+ int end, i, start;
+
+ /* initialize the entire Message RAM in use to avoid possible
+ * ECC/parity checksum errors when reading an uninitialized buffer
+ */
+ start = priv->mcfg[MRAM_SIDF].off;
+ end = priv->mcfg[MRAM_TXB].off +
+ priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
+ for (i = start; i < end; i += 4)
+ writel(0x0, priv->mram_base + i);
+}
+
static void m_can_of_parse_mram(struct m_can_priv *priv,
const u32 *mram_config_vals)
{
@@ -1529,15 +1543,7 @@ static void m_can_of_parse_mram(struct m_can_priv *priv,
priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
- /* initialize the entire Message RAM in use to avoid possible
- * ECC/parity checksum errors when reading an uninitialized buffer
- */
- start = priv->mcfg[MRAM_SIDF].off;
- end = priv->mcfg[MRAM_TXB].off +
- priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
- for (i = start; i < end; i += 4)
- writel(0x0, priv->mram_base + i);
-
+ m_can_init_ram(priv);
}
static int m_can_plat_probe(struct platform_device *pdev)
--
2.11.0
^ permalink raw reply related
* Re: [net-next PATCH 0/4] Improve bpf ELF-loader under samples/bpf
From: Daniel Borkmann @ 2017-05-03 11:48 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: kafai, netdev, eric, Daniel Borkmann, Alexei Starovoitov
In-Reply-To: <20170503081621.41a141d0@redhat.com>
On 05/03/2017 08:16 AM, Jesper Dangaard Brouer wrote:
> On Tue, 02 May 2017 23:10:04 +0200
> Daniel Borkmann <daniel@iogearbox.net> wrote:
>
>> On 05/02/2017 02:31 PM, Jesper Dangaard Brouer wrote:
>>> This series improves and fixes bpf ELF loader and programs under
>>> samples/bpf. The bpf_load.c created some hard to debug issues when
>>> the struct (bpf_map_def) used in the ELF maps section format changed
>>> in commit fb30d4b71214 ("bpf: Add tests for map-in-map").
>>>
>>> This was hotfixed in commit 409526bea3c3 ("samples/bpf: bpf_load.c
>>> detect and abort if ELF maps section size is wrong") by detecting the
>>> issue and aborting the program.
>>>
>>> In most situations the bpf-loader should be able to handle these kind
>>> of changes to the struct size. This patch series aim to do proper
>>> backward and forward compabilility handling when loading ELF files.
>>>
>>> This series also adjust the callback that was introduced in commit
>>> 9fd63d05f3e8 ("bpf: Allow bpf sample programs (*_user.c) to change
>>> bpf_map_def") to use the new bpf_map_data structure, before more users
>>> start to use this callback.
>>>
>>> Hoping these changes can make the merge window, as above mentioned
>>> commits have not been merged yet, and it would be good to avoid users
>>> hitting these issues.
>>
>> Overall, set looks good to me. The last patch doesn't have a
>> user yet, so probably better to drop it until there is an actual
>> user in the tree.
>
> The reason for simply exporting map_data[] was that in patch 3, the
> data-struct (bpf_map_data) is already exposed, thus users can already
> grab and store those into a separate data structure. Thus, it seemed
> natural to simply export/expose the map_data[] array directly. Guess,
> I could have combined patch 4 and 3. As patch-3 uses the data struct,
> but in an indirect way.
>
> To Daniel, if you still feel we should drop patch 4, then let me know.
> It is only the other patches that are time critical, as patch 4 is
> trivial to introduce once the first sample program uses this directly
> (instead of indirectly through the callback).
Ah, if there's still code coming from your side that will make use
of it, I'm fine with this, though it's usually best to add it with
an actual user. Given it's sample code, I don't mind too much if that
happens at a later point in time.
Thanks,
Daniel
^ permalink raw reply
* RE: [PATCH net-next] net/esp4: Fix invalid esph pointer crash
From: Ilan Tayari @ 2017-05-03 11:45 UTC (permalink / raw)
To: Steffen Klassert; +Cc: netdev@vger.kernel.org
In-Reply-To: <20170503070228.GK2649@secunet.com>
> -----Original Message-----
> From: Steffen Klassert [mailto:steffen.klassert@secunet.com]
>
> On Sun, Apr 30, 2017 at 04:34:38PM +0300, ilant@mellanox.com wrote:
> > From: Ilan Tayari <ilant@mellanox.com>
> >
> > Both esp_output and esp_xmit take a pointer to the ESP header
> > and place it in esp_info struct prior to calling esp_output_head.
> >
> > Inside esp_output_head, the call to esp_output_udp_encap
> > makes sure to update the pointer if it gets invalid.
> > However, if esp_output_head itself calls skb_cow_data, the
> > pointer is not updated and stays invalid, causing a crash
> > after esp_output_head returns.
> >
> > Update the pointer if it becomes invalid in esp_output_head
> >
> > Fixes: fca11ebde3f0 ("esp4: Reorganize esp_output")
> > Signed-off-by: Ilan Tayari <ilant@mellanox.com>
> > ---
> > net/ipv4/esp4.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
> > index 7f2caf71212b..65cc02bd82bc 100644
> > --- a/net/ipv4/esp4.c
> > +++ b/net/ipv4/esp4.c
> > @@ -317,6 +317,7 @@ int esp_output_head(struct xfrm_state *x, struct
> sk_buff *skb, struct esp_info *
> > if (nfrags < 0)
> > goto out;
> > tail = skb_tail_pointer(trailer);
> > + esp->esph = ip_esp_hdr(skb);
>
> This is not quite right for udpencap. It fixes the crash,
> but introduces a bug that we already have in v4.11.
>
> On udpencap the esp header has an offset to skb_transport_header,
> the problem was discussed last week here:
>
> https://lkml.org/lkml/2017/4/25/937
>
> I plan to fix this with the patch below:
>
> Subject: [PATCH RFC] esp4: Fix udpencap for local TCP packets.
>
This patch works for me.
I don't have udp-encap test facilities, though (yet!).
Ilan.
^ permalink raw reply
* sock_create_kern() and (lack of) get_net()
From: David Laight @ 2017-05-03 11:39 UTC (permalink / raw)
To: netdev@vger.kernel.org
sock_create_kern() passes 'kern=1' to __sock_create().
sock_create() passes 'kern=0' and uses current->nsproxy->ns_net.
The 'kern' parameter is passed to security_socket_create() and
security_socket_post_create() - I think this is just checking
whether the call is allowed.
The 'kern' parameter is also passed through to sk_alloc() and
controls whether the socket holds a reference count to the namespace.
The latter 'feature' is there because some sockets are used within
the protocol stack itself and the network namespace needs to be
deleteable while those sockets exits.
Prior to 4.2 get_get() was called when all sockets were created and
a 'dance' was done is a few places to drop the reference.
These sockets are still inside the namespace - so must be deleted
by the code that deletes the namespace.
I suspect that many of the sockets created with 'kern=1' are not 'special'
and should hold a reference to the namespace.
In particular code that calls sock_create_kern() and then uses the
kernel_xxx() socket functions at the bottom of net/socket.c probably
want to hold a reference to the network namespace.
I'm pretty sure the socket can still exist (eg draining data) after
sock_release() is called - so the driver can't hold the namespace
reference on behalf of the socket.
A quick audit shows calls to __sock_create(..., 1) at:
./fs/cifs/connect.c:3176
./net/wireless/nl80211.c:10022
./net/sunrpc/svcsock.c:1516
./net/sunrpc/clnt.c:1247
./net/sunrpc/xprtsock.c:1952
./net/sunrpc/xprtsock.c:2019
./net/9p/trans_fd.c:948
./net/9p/trans_fd.c:996
and calls to sock_create_kern() at:
./drivers/infiniband/sw/rxe/rxe_qp.c:233
./drivers/block/drbd/drbd_receiver.c:631
./drivers/block/drbd/drbd_receiver.c:726
./fs/dlm/lowcomms.c:732
./fs/dlm/lowcomms.c:1053
./fs/dlm/lowcomms.c:1134
./fs/dlm/lowcomms.c:1221
./fs/dlm/lowcomms.c:1303
./fs/afs/rxrpc.c:68
./net/ceph/messenger.c:480
./net/rds/tcp_connect.c
./net/rds/tcp_connect.c:108
./net/rds/tcp_listen.c:128
./net/rds/tcp_listen.c:247
./net/rxrpc/local_object.c:117
./net/smc/af_smc.c:1317
./net/l2tp/l2tp_core.c:1506
./net/l2tp/l2tp_core.c:1534
All of which look to me like code that is using IP connections and
would need to be shut down before any namespace could be deleted.
There are also calls to sock_create_kern() in:
./net/tipc/server.c:330
./net/ipv6/ip6_udp_tunnel.c:22
./net/ipv4/udp_tunnel.c:19
./net/ipv4/af_inet.c:1529
./net/bluetooth/rfcomm/core.c:203
./net/netfilter/ipvs/ip_vs_sync.c:1503
./net/netfilter/ipvs/ip_vs_sync.c:1560
These might all be internal to the protocol stack.
I suspect that the 'kern' parameter to __sock_create() needs changing
to 'flags' with:
1 - traditional 'kernel' socket, pass '1' to security_socket_create().
2 - 'protocol internal' socket, don't hold a net_ns reference count.
The call sites would then need auditing to see which value they should
pass.
As usual I've probably missed something obvious...
David
^ permalink raw reply
* Re: [PATCH] test_bpf: Use ULL suffix for 64-bit constants
From: Daniel Borkmann @ 2017-05-03 11:34 UTC (permalink / raw)
To: Geert Uytterhoeven, David S . Miller, Alexei Starovoitov
Cc: netdev, --cc, linux-kernel
In-Reply-To: <1493811064-24542-1-git-send-email-geert@linux-m68k.org>
On 05/03/2017 01:31 PM, Geert Uytterhoeven wrote:
> On 32-bit:
>
> lib/test_bpf.c:4772: warning: integer constant is too large for ‘unsigned long’ type
> lib/test_bpf.c:4772: warning: integer constant is too large for ‘unsigned long’ type
> lib/test_bpf.c:4773: warning: integer constant is too large for ‘unsigned long’ type
> lib/test_bpf.c:4773: warning: integer constant is too large for ‘unsigned long’ type
> lib/test_bpf.c:4787: warning: integer constant is too large for ‘unsigned long’ type
> lib/test_bpf.c:4787: warning: integer constant is too large for ‘unsigned long’ type
> lib/test_bpf.c:4801: warning: integer constant is too large for ‘unsigned long’ type
> lib/test_bpf.c:4801: warning: integer constant is too large for ‘unsigned long’ type
> lib/test_bpf.c:4802: warning: integer constant is too large for ‘unsigned long’ type
> lib/test_bpf.c:4802: warning: integer constant is too large for ‘unsigned long’ type
>
> On 32-bit systems, "long" is only 32-bit.
> Replace the "UL" suffix by "ULL" to fix this.
>
> Fixes: 85f68fe898320575 ("bpf, arm64: implement jiting of BPF_XADD")
> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Yep, of course, not sure how I missed it! :/ Thanks!
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
^ permalink raw reply
* [PATCH] test_bpf: Use ULL suffix for 64-bit constants
From: Geert Uytterhoeven @ 2017-05-03 11:31 UTC (permalink / raw)
To: David S . Miller, Alexei Starovoitov, Daniel Borkmann
Cc: netdev, --cc, linux-kernel, Geert Uytterhoeven
On 32-bit:
lib/test_bpf.c:4772: warning: integer constant is too large for ‘unsigned long’ type
lib/test_bpf.c:4772: warning: integer constant is too large for ‘unsigned long’ type
lib/test_bpf.c:4773: warning: integer constant is too large for ‘unsigned long’ type
lib/test_bpf.c:4773: warning: integer constant is too large for ‘unsigned long’ type
lib/test_bpf.c:4787: warning: integer constant is too large for ‘unsigned long’ type
lib/test_bpf.c:4787: warning: integer constant is too large for ‘unsigned long’ type
lib/test_bpf.c:4801: warning: integer constant is too large for ‘unsigned long’ type
lib/test_bpf.c:4801: warning: integer constant is too large for ‘unsigned long’ type
lib/test_bpf.c:4802: warning: integer constant is too large for ‘unsigned long’ type
lib/test_bpf.c:4802: warning: integer constant is too large for ‘unsigned long’ type
On 32-bit systems, "long" is only 32-bit.
Replace the "UL" suffix by "ULL" to fix this.
Fixes: 85f68fe898320575 ("bpf, arm64: implement jiting of BPF_XADD")
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
lib/test_bpf.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index a0f66280ea502e63..889bc31785bee579 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -4769,8 +4769,8 @@ static struct bpf_test tests[] = {
BPF_LD_IMM64(R1, 3),
BPF_LD_IMM64(R2, 2),
BPF_JMP_REG(BPF_JGE, R1, R2, 2),
- BPF_LD_IMM64(R0, 0xffffffffffffffffUL),
- BPF_LD_IMM64(R0, 0xeeeeeeeeeeeeeeeeUL),
+ BPF_LD_IMM64(R0, 0xffffffffffffffffULL),
+ BPF_LD_IMM64(R0, 0xeeeeeeeeeeeeeeeeULL),
BPF_EXIT_INSN(),
},
INTERNAL,
@@ -4784,7 +4784,7 @@ static struct bpf_test tests[] = {
BPF_LD_IMM64(R1, 3),
BPF_LD_IMM64(R2, 2),
BPF_JMP_REG(BPF_JGE, R1, R2, 0),
- BPF_LD_IMM64(R0, 0xffffffffffffffffUL),
+ BPF_LD_IMM64(R0, 0xffffffffffffffffULL),
BPF_EXIT_INSN(),
},
INTERNAL,
@@ -4798,8 +4798,8 @@ static struct bpf_test tests[] = {
BPF_LD_IMM64(R1, 3),
BPF_LD_IMM64(R2, 2),
BPF_JMP_REG(BPF_JGE, R1, R2, 4),
- BPF_LD_IMM64(R0, 0xffffffffffffffffUL),
- BPF_LD_IMM64(R0, 0xeeeeeeeeeeeeeeeeUL),
+ BPF_LD_IMM64(R0, 0xffffffffffffffffULL),
+ BPF_LD_IMM64(R0, 0xeeeeeeeeeeeeeeeeULL),
BPF_EXIT_INSN(),
},
INTERNAL,
--
2.7.4
^ permalink raw reply related
* [PATCH] brcmfmac: btcoex: replace init_timer with setup_timer
From: Xie Qirong @ 2017-05-03 11:27 UTC (permalink / raw)
To: Arend van Spriel, Franky Lin, Hante Meuleman, Kalle Valo
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
brcm80211-dev-list.pdl-dY08KVG/lbpWk0Htik3J/w,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Piotr Haber, Xie Qirong
setup_timer.cocci suggested the following improvement:
drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c:383:1-11: Use
setup_timer function for function on line 384.
Signed-off-by: Xie Qirong <cheerx1994-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
Patch was compile checked with: x86_64_defconfig + CONFIG_BRCMFMAC=y +
CONFIG_BRCMFMAC_USB=y + CONFIG_BRCMFMAC_PCIE=y + CONFIG_BRCM_TRACING=y +
CONFIG_BRCMDBG=y
Kernel version: next-20170502 (localversion-next is next-20170502)
Thanks for Arend's advice
drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
index 14a70d4..3559fb5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
@@ -380,9 +380,7 @@ int brcmf_btcoex_attach(struct brcmf_cfg80211_info *cfg)
/* Set up timer for BT */
btci->timer_on = false;
btci->timeout = BRCMF_BTCOEX_OPPR_WIN_TIME;
- init_timer(&btci->timer);
- btci->timer.data = (ulong)btci;
- btci->timer.function = brcmf_btcoex_timerfunc;
+ setup_timer(&btci->timer, brcmf_btcoex_timerfunc, (ulong)btci);
btci->cfg = cfg;
btci->saved_regs_part1 = false;
btci->saved_regs_part2 = false;
--
2.9.3
^ permalink raw reply related
* Re: [PATCH net v3] driver: veth: Fix one possbile memleak when fail to register_netdevice
From: Xin Long @ 2017-05-03 11:25 UTC (permalink / raw)
To: Gao Feng; +Cc: Gao Feng, davem, jarod, Stephen Hemminger, dsa, network dev
In-Reply-To: <006101d2c3d7$bf814230$3e83c690$@foxmail.com>
On Wed, May 3, 2017 at 2:37 PM, Gao Feng <gfree.wind@foxmail.com> wrote:
>> From: Xin Long [mailto:lucien.xin@gmail.com]
>> Sent: Wednesday, May 3, 2017 1:38 PM
>> On Wed, May 3, 2017 at 10:07 AM, Gao Feng <gfree.wind@foxmail.com>
>> wrote:
>> >> From: netdev-owner@vger.kernel.org
>> >> [mailto:netdev-owner@vger.kernel.org]
>> >> On Behalf Of Xin Long
>> >> Sent: Wednesday, May 3, 2017 12:59 AM On Tue, May 2, 2017 at 7:03 PM,
>> >> Gao Feng <gfree.wind@vip.163.com> wrote:
>> >> >> From: Xin Long [mailto:lucien.xin@gmail.com]
>> >> >> Sent: Tuesday, May 2, 2017 3:56 PM On Sat, Apr 29, 2017 at 11:51
>> >> >> AM, <gfree.wind@foxmail.com> wrote:
>> >> >> > From: Gao Feng <gfree.wind@foxmail.com>
> [...]
>> > The fix you mentioned change the original logic.
>> > The dev->vstats is freed in advance in the ndo_uninit, not destructor.
>> > It may break the backward.
>> Sorry, I didn't get your "backward"
>> I can't see there will be any problem caused by it.
>> can you say this patch also break the 'backward' ?
>> https://patchwork.ozlabs.org/patch/748964/
>>
>> It's really weird to do dev->reg_state check in ndo_unint ndo_unint is supposed
>> to free the memory alloced in ndo_init.
>>
>
> I am not sure if it would break the backward, so I said it MAY break.
> I assumed there may be someone would access the dev->vstats after ndo_uninit,
> because current veth driver free the mem in the destructor.
> I selected this approach because I don't want to bring new bugs during fix bug.
>
> If you're sure it is safe to free dev->vstats in ndo_uninit, I would like to update it.
yes, stats are accessed in .ndo_start_xmit waited by synchronize_net() and
.ndo_get_stats64 protected by rtnl_lock().
>
> BTW there are too many drivers which have possible memleak.
> You could find the list by https://www.mail-archive.com/netdev@vger.kernel.org/msg166629.html.
ah, cool.
I'm not sure about other dev's stuff, have to check them for sure later.
>
> Some drivers allocate the resources in ndo_init, free some in ndo_uninit and free left in destructor.
> I think there are some reasons.
> We could not move all free in the ndo_uninit from destructor. What's your opinion?
>
> Best Regards
> Feng
>
>
>
^ permalink raw reply
* [patch iproute2 v2 2/2] devlink: Add support for pipeline debug (dpipe)
From: Jiri Pirko @ 2017-05-03 11:25 UTC (permalink / raw)
To: netdev; +Cc: arkadis, stephen, davem, mlxsw, dsa
In-Reply-To: <1493810723-2536-1-git-send-email-jiri@resnulli.us>
From: Arkadi Sharshevsky <arkadis@mellanox.com>
Add support for pipeline debug (dpipe). The headers are used both the
gain visibillity into the headers supported by the hardware, and to
build the headers/field database which is used by other commands.
Examples:
First we can see the headers supported by the hardware:
$devlink dpipe header show pci/0000:03:00.0
pci/0000:03:00.0:
name mlxsw_meta
field:
name erif_port bitwidth 32 mapping_type ifindex
name l3_forward bitwidth 1
name l3_drop bitwidth 1
Note that mapping_type is presented only if relevant. Also the header/
field id's are reported by the kernel they are not shown by default.
They can be observed by using the -v option. Also the headers scope
(global/local) is specified.
$devlink -v dpipe header show pci/0000:03:00.0
pci/0000:03:00.0:
name mlxsw_meta id 0 global false
field:
name erif_port id 0 bitwidth 32 mapping_type ifindex
name l3_forward id 1 bitwidth 1
name l3_drop id 2 bitwidth 1
Second we can examine the tables supported by the hardware. In order
to dump all the tables no table name should be provided:
$devlink dpipe table show pci/0000:03:00.0
In order to examine specific table its name have to be specified:
$devlink dpipe table show pci/0000:03:00.0 name erif
pci/0000:03:00.0:
name mlxsw_erif size 800 counters_enabled true
match:
type field_exact header mlxsw_meta field erif_port mapping ifindex
action:
type field_modify header mlxsw_meta field l3_forward
type field_modify header mlxsw_meta field l3_drop
To enable/disable counters on the table:
$devlink dpipe table set pci/0000:03:00.0 name erif counters enable
$devlink dpipe table set pci/0000:03:00.0 name erif counters disable
In order to see the current entries in the hardware for specific table:
$devlink dpipe table dump pci/0000:03:00.0 name erif
pci/0000:03:00.0:
index 0 counter 0
match_value:
type field_exact header mlxsw_meta field erif_port mapping ifindex mapping_value 383 value 0
action_value:
type field_modify header mlxsw_meta field l3_forward value 1
index 1 counter 0
match_value:
type field_exact header mlxsw_meta field erif_port mapping ifindex mapping_value 381 value 1
action_value:
type field_modify header mlxsw_meta field l3_forward value 1
In the above example the table contains two entries which does match
on erif port and forwards the packet or drop it (currently only the
forward count is implemented). The counter values are provided for
example. In case the counting is not enabled on the table the counters
will not be available.
Signed-off-by: Arkadi Sharshevsky <arkadis@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
devlink/devlink.c | 1353 +++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 1254 insertions(+), 99 deletions(-)
diff --git a/devlink/devlink.c b/devlink/devlink.c
index 35220d8..e22ee0a 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c
@@ -34,7 +34,15 @@
#define ESWITCH_INLINE_MODE_TRANSPORT "transport"
#define pr_err(args...) fprintf(stderr, ##args)
-#define pr_out(args...) fprintf(stdout, ##args)
+#define pr_out(args...) \
+ do { \
+ if (g_indent_newline) { \
+ fprintf(stdout, "%s", g_indent_str); \
+ g_indent_newline = false; \
+ } \
+ fprintf(stdout, ##args); \
+ } while (0)
+
#define pr_out_sp(num, args...) \
do { \
int ret = fprintf(stdout, ##args); \
@@ -42,6 +50,35 @@
fprintf(stdout, "%*s", num - ret, ""); \
} while (0)
+static int g_indent_level;
+static bool g_indent_newline;
+#define INDENT_STR_STEP 2
+#define INDENT_STR_MAXLEN 32
+static char g_indent_str[INDENT_STR_MAXLEN + 1] = "";
+
+static void __pr_out_indent_inc(void)
+{
+ if (g_indent_level + INDENT_STR_STEP > INDENT_STR_MAXLEN)
+ return;
+ g_indent_level += INDENT_STR_STEP;
+ memset(g_indent_str, ' ', sizeof(g_indent_str));
+ g_indent_str[g_indent_level] = '\0';
+}
+
+static void __pr_out_indent_dec(void)
+{
+ if (g_indent_level - INDENT_STR_STEP < 0)
+ return;
+ g_indent_level -= INDENT_STR_STEP;
+ g_indent_str[g_indent_level] = '\0';
+}
+
+static void __pr_out_newline(void)
+{
+ pr_out("\n");
+ g_indent_newline = true;
+}
+
static int _mnlg_socket_recv_run(struct mnlg_socket *nlg,
mnl_cb_t data_cb, void *data)
{
@@ -137,6 +174,8 @@ static void ifname_map_free(struct ifname_map *ifname_map)
#define DL_OPT_SB_TC BIT(10)
#define DL_OPT_ESWITCH_MODE BIT(11)
#define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
+#define DL_OPT_DPIPE_TABLE_NAME BIT(13)
+#define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
struct dl_opts {
uint32_t present; /* flags of present items */
@@ -154,6 +193,8 @@ struct dl_opts {
uint16_t sb_tc_index;
enum devlink_eswitch_mode eswitch_mode;
enum devlink_eswitch_inline_mode eswitch_inline_mode;
+ const char *dpipe_table_name;
+ bool dpipe_counters_enable;
};
struct dl {
@@ -166,6 +207,7 @@ struct dl {
json_writer_t *jw;
bool json_output;
bool pretty_output;
+ bool verbose;
struct {
bool present;
char *bus_name;
@@ -257,6 +299,38 @@ static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
[DEVLINK_ATTR_SB_OCC_MAX] = MNL_TYPE_U32,
[DEVLINK_ATTR_ESWITCH_MODE] = MNL_TYPE_U16,
[DEVLINK_ATTR_ESWITCH_INLINE_MODE] = MNL_TYPE_U8,
+ [DEVLINK_ATTR_DPIPE_TABLES] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_TABLE] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_TABLE_NAME] = MNL_TYPE_STRING,
+ [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = MNL_TYPE_U64,
+ [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = MNL_TYPE_U8,
+ [DEVLINK_ATTR_DPIPE_ENTRIES] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_ENTRY] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = MNL_TYPE_U64,
+ [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = MNL_TYPE_U64,
+ [DEVLINK_ATTR_DPIPE_MATCH] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_DPIPE_ACTION] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_DPIPE_HEADERS] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_HEADER] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_HEADER_NAME] = MNL_TYPE_STRING,
+ [DEVLINK_ATTR_DPIPE_HEADER_ID] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = MNL_TYPE_U8,
+ [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_DPIPE_FIELD] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_DPIPE_FIELD_NAME] = MNL_TYPE_STRING,
+ [DEVLINK_ATTR_DPIPE_FIELD_ID] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = MNL_TYPE_U32,
};
static int attr_cb(const struct nlattr *attr, void *data)
@@ -666,6 +740,20 @@ static int eswitch_inline_mode_get(const char *typestr,
return 0;
}
+static int dpipe_counters_enable_get(const char *typestr,
+ bool *counters_enable)
+{
+ if (strcmp(typestr, "enable") == 0) {
+ *counters_enable = 1;
+ } else if (strcmp(typestr, "disable") == 0) {
+ *counters_enable = 0;
+ } else {
+ pr_err("Unknown counter_state \"%s\"\n", typestr);
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int dl_argv_parse(struct dl *dl, uint32_t o_required,
uint32_t o_optional)
{
@@ -800,6 +888,27 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
if (err)
return err;
o_found |= DL_OPT_ESWITCH_INLINE_MODE;
+ } else if (dl_argv_match(dl, "name") &&
+ (o_all & DL_OPT_DPIPE_TABLE_NAME)) {
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, &opts->dpipe_table_name);
+ if (err)
+ return err;
+ o_found |= DL_OPT_DPIPE_TABLE_NAME;
+ } else if (dl_argv_match(dl, "counters") &&
+ (o_all & DL_OPT_DPIPE_TABLE_COUNTERS)) {
+ const char *typestr;
+
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, &typestr);
+ if (err)
+ return err;
+ err = dpipe_counters_enable_get(typestr,
+ &opts->dpipe_counters_enable);
+ if (err)
+ return err;
+ o_found |= DL_OPT_DPIPE_TABLE_COUNTERS;
+
} else {
pr_err("Unknown option \"%s\"\n", dl_argv(dl));
return -EINVAL;
@@ -866,6 +975,17 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required,
return -EINVAL;
}
+ if ((o_required & DL_OPT_DPIPE_TABLE_NAME) &&
+ !(o_found & DL_OPT_DPIPE_TABLE_NAME)) {
+ pr_err("Dpipe table name expected\n");
+ return -EINVAL;
+ }
+
+ if ((o_required & DL_OPT_DPIPE_TABLE_COUNTERS) &&
+ !(o_found & DL_OPT_DPIPE_TABLE_COUNTERS)) {
+ pr_err("Dpipe table counter state expected\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -915,6 +1035,12 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
if (opts->present & DL_OPT_ESWITCH_INLINE_MODE)
mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
opts->eswitch_inline_mode);
+ if (opts->present & DL_OPT_DPIPE_TABLE_NAME)
+ mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME,
+ opts->dpipe_table_name);
+ if (opts->present & DL_OPT_DPIPE_TABLE_COUNTERS)
+ mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
+ opts->dpipe_counters_enable);
}
static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
@@ -1033,7 +1159,19 @@ static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb,
jsonw_start_object(dl->jw);
}
} else {
- pr_out("%s%s", buf, content ? ":" : "");
+ if (array) {
+ if (should_arr_last_handle_end(dl, bus_name, dev_name))
+ __pr_out_indent_dec();
+ if (should_arr_last_handle_start(dl, bus_name,
+ dev_name)) {
+ pr_out("%s%s", buf, content ? ":" : "");
+ __pr_out_newline();
+ __pr_out_indent_inc();
+ arr_last_handle_set(dl, bus_name, dev_name);
+ }
+ } else {
+ pr_out("%s%s", buf, content ? ":" : "");
+ }
}
}
@@ -1047,7 +1185,7 @@ static void pr_out_handle_end(struct dl *dl)
if (dl->json_output)
jsonw_end_object(dl->jw);
else
- pr_out("\n");
+ __pr_out_newline();
}
static void pr_out_handle(struct dl *dl, struct nlattr **tb)
@@ -1163,18 +1301,26 @@ static void pr_out_port_handle_end(struct dl *dl)
static void pr_out_str(struct dl *dl, const char *name, const char *val)
{
- if (dl->json_output)
+ if (dl->json_output) {
jsonw_string_field(dl->jw, name, val);
- else
- pr_out(" %s %s", name, val);
+ } else {
+ if (g_indent_newline)
+ pr_out("%s %s", name, val);
+ else
+ pr_out(" %s %s", name, val);
+ }
}
static void pr_out_uint(struct dl *dl, const char *name, unsigned int val)
{
- if (dl->json_output)
+ if (dl->json_output) {
jsonw_uint_field(dl->jw, name, val);
- else
- pr_out(" %s %u", name, val);
+ } else {
+ if (g_indent_newline)
+ pr_out("%s %u", name, val);
+ else
+ pr_out(" %s %u", name, val);
+ }
}
static void pr_out_dev(struct dl *dl, struct nlattr **tb)
@@ -1201,6 +1347,42 @@ static void pr_out_section_end(struct dl *dl)
}
}
+static void pr_out_array_start(struct dl *dl, const char *name)
+{
+ if (dl->json_output) {
+ jsonw_name(dl->jw, name);
+ jsonw_start_array(dl->jw);
+ } else {
+ if (!g_indent_newline)
+ __pr_out_newline();
+ pr_out("%s:", name);
+ __pr_out_newline();
+ __pr_out_indent_inc();
+ }
+}
+
+static void pr_out_array_end(struct dl *dl)
+{
+ if (dl->json_output)
+ jsonw_end_array(dl->jw);
+ else
+ __pr_out_indent_dec();
+}
+
+static void pr_out_entry_start(struct dl *dl)
+{
+ if (dl->json_output)
+ jsonw_start_object(dl->jw);
+}
+
+static void pr_out_entry_end(struct dl *dl)
+{
+ if (dl->json_output)
+ jsonw_end_object(dl->jw);
+ else
+ __pr_out_newline();
+}
+
static const char *eswitch_mode_name(uint32_t mode)
{
switch (mode) {
@@ -2423,129 +2605,1102 @@ static int cmd_mon(struct dl *dl)
return -ENOENT;
}
-static void help(void)
+struct dpipe_field {
+ char *name;
+ unsigned int id;
+ unsigned int bitwidth;
+ enum devlink_dpipe_field_mapping_type mapping_type;
+};
+
+struct dpipe_header {
+ struct list_head list;
+ char *name;
+ unsigned int id;
+ struct dpipe_field *fields;
+ unsigned int fields_count;
+};
+
+struct dpipe_ctx {
+ struct dl *dl;
+ int err;
+ struct list_head global_headers;
+ struct list_head local_headers;
+ bool print_headers;
+};
+
+static struct dpipe_header *dpipe_header_alloc(unsigned int fields_count)
{
- pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
- "where OBJECT := { dev | port | sb | monitor }\n"
- " OPTIONS := { -V[ersion] | -n[no-nice-names] | -j[json] | -p[pretty] }\n");
+ struct dpipe_header *header;
+
+ header = calloc(1, sizeof(struct dpipe_header));
+ if (!header)
+ return NULL;
+ header->fields = calloc(fields_count, sizeof(struct dpipe_field));
+ if (!header->fields)
+ goto err_fields_alloc;
+ header->fields_count = fields_count;
+ return header;
+
+err_fields_alloc:
+ free(header);
+ return NULL;
}
-static int dl_cmd(struct dl *dl)
+static void dpipe_header_free(struct dpipe_header *header)
{
- 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, "sb")) {
- dl_arg_inc(dl);
- return cmd_sb(dl);
- } else if (dl_argv_match(dl, "monitor")) {
- dl_arg_inc(dl);
- return cmd_mon(dl);
+ free(header->fields);
+ free(header);
+}
+
+static void dpipe_header_clear(struct dpipe_header *header)
+{
+ struct dpipe_field *field;
+ int i;
+
+ for (i = 0; i < header->fields_count; i++) {
+ field = &header->fields[i];
+ free(field->name);
}
- pr_err("Object \"%s\" not found\n", dl_argv(dl));
- return -ENOENT;
+ free(header->name);
}
-static int dl_init(struct dl *dl, int argc, char **argv)
+static void dpipe_header_add(struct dpipe_ctx *ctx,
+ struct dpipe_header *header, bool global)
{
- int err;
+ if (global)
+ list_add(&header->list, &ctx->global_headers);
+ else
+ list_add(&header->list, &ctx->local_headers);
+}
- dl->argc = argc;
- dl->argv = argv;
+static void dpipe_header_del(struct dpipe_header *header)
+{
+ list_del(&header->list);
+}
- 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;
+static struct dpipe_ctx *dpipe_ctx_alloc(struct dl *dl)
+{
+ struct dpipe_ctx *ctx;
+
+ ctx = calloc(1, sizeof(struct dpipe_ctx));
+ if (!ctx)
+ return NULL;
+ ctx->dl = dl;
+ INIT_LIST_HEAD(&ctx->global_headers);
+ INIT_LIST_HEAD(&ctx->local_headers);
+ return ctx;
+}
+
+static void dpipe_ctx_free(struct dpipe_ctx *ctx)
+{
+ free(ctx);
+}
+
+static void dpipe_ctx_clear(struct dpipe_ctx *ctx)
+{
+ struct dpipe_header *header, *tmp;
+
+ list_for_each_entry_safe(header, tmp, &ctx->global_headers,
+ list) {
+ dpipe_header_del(header);
+ dpipe_header_clear(header);
+ dpipe_header_free(header);
+ }
+ list_for_each_entry_safe(header, tmp, &ctx->local_headers,
+ list) {
+ dpipe_header_del(header);
+ dpipe_header_clear(header);
+ dpipe_header_free(header);
}
+}
- err = ifname_map_init(dl);
- if (err) {
- pr_err("Failed to create index map\n");
- goto err_ifname_map_create;
+static const char *dpipe_header_id2s(struct dpipe_ctx *ctx,
+ uint32_t header_id, bool global)
+{
+ struct list_head *header_list;
+ struct dpipe_header *header;
+
+ if (global)
+ header_list = &ctx->global_headers;
+ else
+ header_list = &ctx->local_headers;
+ list_for_each_entry(header, header_list, list) {
+ if (header->id != header_id)
+ continue;
+ return header->name;
}
- if (dl->json_output) {
- dl->jw = jsonw_new(stdout);
- if (!dl->jw) {
- pr_err("Failed to create JSON writer\n");
- goto err_json_new;
- }
- jsonw_pretty(dl->jw, dl->pretty_output);
+ return NULL;
+}
+
+static const char *dpipe_field_id2s(struct dpipe_ctx *ctx,
+ uint32_t header_id,
+ uint32_t field_id, bool global)
+{
+ struct list_head *header_list;
+ struct dpipe_header *header;
+
+ if (global)
+ header_list = &ctx->global_headers;
+ else
+ header_list = &ctx->local_headers;
+ list_for_each_entry(header, header_list, list) {
+ if (header->id != header_id)
+ continue;
+ return header->fields[field_id].name;
}
- return 0;
+ return NULL;
+}
-err_json_new:
- ifname_map_fini(dl);
-err_ifname_map_create:
- mnlg_socket_close(dl->nlg);
- return err;
+static const char *
+dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)
+{
+ switch (mapping_type) {
+ case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE:
+ return NULL;
+ case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX:
+ return "ifindex";
+ default:
+ return "<unknown>";
+ }
}
-static void dl_fini(struct dl *dl)
+static const char *
+dpipe_mapping_get(struct dpipe_ctx *ctx, uint32_t header_id,
+ uint32_t field_id, bool global)
{
- if (dl->json_output)
- jsonw_destroy(&dl->jw);
- ifname_map_fini(dl);
- mnlg_socket_close(dl->nlg);
+ enum devlink_dpipe_field_mapping_type mapping_type;
+ struct list_head *header_list;
+ struct dpipe_header *header;
+
+ if (global)
+ header_list = &ctx->global_headers;
+ else
+ header_list = &ctx->local_headers;
+ list_for_each_entry(header, header_list, list) {
+ if (header->id != header_id)
+ continue;
+ mapping_type = header->fields[field_id].mapping_type;
+ return dpipe_field_mapping_e2s(mapping_type);
+ }
+ return NULL;
}
-static struct dl *dl_alloc(void)
+static void pr_out_dpipe_fields(struct dpipe_ctx *ctx,
+ struct dpipe_field *fields,
+ unsigned int field_count)
{
- struct dl *dl;
+ struct dpipe_field *field;
+ int i;
- dl = calloc(1, sizeof(*dl));
- if (!dl)
- return NULL;
- return dl;
+ for (i = 0; i < field_count; i++) {
+ field = &fields[i];
+ pr_out_entry_start(ctx->dl);
+ pr_out_str(ctx->dl, "name", field->name);
+ if (ctx->dl->verbose)
+ pr_out_uint(ctx->dl, "id", field->id);
+ pr_out_uint(ctx->dl, "bitwidth", field->bitwidth);
+ if (field->mapping_type)
+ pr_out_str(ctx->dl, "mapping_type",
+ dpipe_field_mapping_e2s(field->mapping_type));
+ pr_out_entry_end(ctx->dl);
+ }
}
-static void dl_free(struct dl *dl)
+static void
+pr_out_dpipe_header(struct dpipe_ctx *ctx, struct nlattr **tb,
+ struct dpipe_header *header, bool global)
{
- free(dl);
+ pr_out_handle_start_arr(ctx->dl, tb);
+ pr_out_str(ctx->dl, "name", header->name);
+ if (ctx->dl->verbose) {
+ pr_out_uint(ctx->dl, "id", header->id);
+ pr_out_str(ctx->dl, "global",
+ global ? "true" : "false");
+ }
+ pr_out_array_start(ctx->dl, "field");
+ pr_out_dpipe_fields(ctx, header->fields,
+ header->fields_count);
+ pr_out_array_end(ctx->dl);
+ pr_out_handle_end(ctx->dl);
}
-int main(int argc, char **argv)
+static void pr_out_dpipe_headers(struct dpipe_ctx *ctx,
+ struct nlattr **tb)
{
- static const struct option long_options[] = {
- { "Version", no_argument, NULL, 'V' },
- { "no-nice-names", no_argument, NULL, 'n' },
- { "json", no_argument, NULL, 'j' },
- { "pretty", no_argument, NULL, 'p' },
- { NULL, 0, NULL, 0 }
- };
- struct dl *dl;
- int opt;
+ struct dpipe_header *header;
+
+ list_for_each_entry(header, &ctx->local_headers, list)
+ pr_out_dpipe_header(ctx, tb, header, false);
+
+ list_for_each_entry(header, &ctx->global_headers, list)
+ pr_out_dpipe_header(ctx, tb, header, true);
+}
+
+static int dpipe_header_field_get(struct nlattr *nl, struct dpipe_field *field)
+{
+ struct nlattr *nla_field[DEVLINK_ATTR_MAX + 1] = {};
+ const char *name;
int err;
- int ret;
- dl = dl_alloc();
- if (!dl) {
- pr_err("Failed to allocate memory for devlink\n");
- return EXIT_FAILURE;
+ err = mnl_attr_parse_nested(nl, attr_cb, nla_field);
+ if (err != MNL_CB_OK)
+ return -EINVAL;
+ if (!nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID] ||
+ !nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME] ||
+ !nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] ||
+ !nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE])
+ return -EINVAL;
+
+ name = mnl_attr_get_str(nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME]);
+ field->id = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID]);
+ field->bitwidth = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH]);
+ field->name = strdup(name);
+ if (!field->name)
+ return -ENOMEM;
+ field->mapping_type = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE]);
+ return 0;
+}
+
+static int dpipe_header_fields_get(struct nlattr *nla_fields,
+ struct dpipe_field *fields)
+{
+ struct nlattr *nla_field;
+ int count = 0;
+ int err;
+
+ mnl_attr_for_each_nested(nla_field, nla_fields) {
+ err = dpipe_header_field_get(nla_field, &fields[count]);
+ if (err)
+ return err;
+ count++;
}
+ return 0;
+}
- while ((opt = getopt_long(argc, argv, "Vnjp",
- long_options, NULL)) >= 0) {
+static unsigned int dpipe_header_field_count_get(struct nlattr *nla_fields)
+{
+ struct nlattr *nla_field;
+ unsigned int count = 0;
- switch (opt) {
- case 'V':
- printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
- ret = EXIT_SUCCESS;
- goto dl_free;
- case 'n':
- dl->no_nice_names = true;
- break;
- case 'j':
- dl->json_output = true;
- break;
- case 'p':
- dl->pretty_output = true;
+ mnl_attr_for_each_nested(nla_field, nla_fields)
+ count++;
+ return count;
+}
+
+static int dpipe_header_get(struct dpipe_ctx *ctx, struct nlattr *nl)
+{
+ struct nlattr *nla_header[DEVLINK_ATTR_MAX + 1] = {};
+ struct dpipe_header *header;
+ unsigned int fields_count;
+ const char *header_name;
+ bool global;
+ int err;
+
+ err = mnl_attr_parse_nested(nl, attr_cb, nla_header);
+ if (err != MNL_CB_OK)
+ return -EINVAL;
+
+ if (!nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME] ||
+ !nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
+ !nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS])
+ return -EINVAL;
+
+ fields_count = dpipe_header_field_count_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS]);
+ header = dpipe_header_alloc(fields_count);
+ if (!header)
+ return -ENOMEM;
+
+ header_name = mnl_attr_get_str(nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME]);
+ header->name = strdup(header_name);
+ header->id = mnl_attr_get_u32(nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID]);
+ header->fields_count = fields_count;
+ global = !!mnl_attr_get_u8(nla_header[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
+
+ err = dpipe_header_fields_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS],
+ header->fields);
+ if (err)
+ goto err_field_get;
+ dpipe_header_add(ctx, header, global);
+ return 0;
+
+err_field_get:
+ dpipe_header_free(header);
+ return err;
+}
+
+static int dpipe_headers_get(struct dpipe_ctx *ctx, struct nlattr **tb)
+{
+ struct nlattr *nla_headers = tb[DEVLINK_ATTR_DPIPE_HEADERS];
+ struct nlattr *nla_header;
+ int err;
+
+ mnl_attr_for_each_nested(nla_header, nla_headers) {
+ err = dpipe_header_get(ctx, nla_header);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int cmd_dpipe_header_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct dpipe_ctx *ctx = data;
+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+ int err;
+
+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+ !tb[DEVLINK_ATTR_DPIPE_HEADERS])
+ return MNL_CB_ERROR;
+ err = dpipe_headers_get(ctx, tb);
+ if (err) {
+ ctx->err = err;
+ return MNL_CB_ERROR;
+ }
+
+ if (ctx->print_headers)
+ pr_out_dpipe_headers(ctx, tb);
+ return MNL_CB_OK;
+}
+
+static int cmd_dpipe_headers_show(struct dl *dl)
+{
+ struct nlmsghdr *nlh;
+ struct dpipe_ctx *ctx;
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
+ int err;
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
+
+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
+ if (err)
+ return err;
+
+ ctx = dpipe_ctx_alloc(dl);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->print_headers = true;
+
+ pr_out_section_start(dl, "header");
+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, ctx);
+ if (err)
+ pr_err("error get headers %s\n", strerror(ctx->err));
+ pr_out_section_end(dl);
+
+ dpipe_ctx_clear(ctx);
+ dpipe_ctx_free(ctx);
+ return err;
+}
+
+static void cmd_dpipe_header_help(void)
+{
+ pr_err("Usage: devlink dpipe headers show DEV\n");
+}
+
+static int cmd_dpipe_header(struct dl *dl)
+{
+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
+ cmd_dpipe_header_help();
+ return 0;
+ } else if (dl_argv_match(dl, "show")) {
+ dl_arg_inc(dl);
+ return cmd_dpipe_headers_show(dl);
+ }
+ pr_err("Command \"%s\" not found\n", dl_argv(dl));
+ return -ENOENT;
+}
+
+static const char
+*dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)
+{
+ switch (action_type) {
+ case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY:
+ return "field_modify";
+ default:
+ return "<unknown>";
+ }
+}
+
+static void pr_out_dpipe_action(struct dpipe_ctx *ctx,
+ uint32_t header_id, uint32_t field_id,
+ uint32_t action_type, bool global)
+{
+ const char *mapping;
+
+ pr_out_str(ctx->dl, "type", dpipe_action_type_e2s(action_type));
+ pr_out_str(ctx->dl, "header", dpipe_header_id2s(ctx, header_id,
+ global));
+ pr_out_str(ctx->dl, "field", dpipe_field_id2s(ctx, header_id, field_id,
+ global));
+ mapping = dpipe_mapping_get(ctx, header_id, field_id, global);
+ if (mapping)
+ pr_out_str(ctx->dl, "mapping", mapping);
+}
+
+static int dpipe_action_show(struct dpipe_ctx *ctx, struct nlattr *nl)
+{
+ struct nlattr *nla_action[DEVLINK_ATTR_MAX + 1] = {};
+ uint32_t header_id, field_id, action_type;
+ bool global;
+ int err;
+
+ err = mnl_attr_parse_nested(nl, attr_cb, nla_action);
+ if (err != MNL_CB_OK)
+ return -EINVAL;
+
+ if (!nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE] ||
+ !nla_action[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
+ !nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
+ !nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
+ return -EINVAL;
+ }
+
+ header_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID]);
+ field_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]);
+ action_type = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE]);
+ global = !!mnl_attr_get_u8(nla_action[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
+
+ pr_out_dpipe_action(ctx, header_id, field_id, action_type, global);
+ return 0;
+}
+
+static int dpipe_table_actions_show(struct dpipe_ctx *ctx,
+ struct nlattr *nla_actions)
+{
+ struct nlattr *nla_action;
+
+ mnl_attr_for_each_nested(nla_action, nla_actions) {
+ pr_out_entry_start(ctx->dl);
+ if (dpipe_action_show(ctx, nla_action))
+ goto err_action_show;
+ pr_out_entry_end(ctx->dl);
+ }
+ return 0;
+
+err_action_show:
+ pr_out_entry_end(ctx->dl);
+ return -EINVAL;
+}
+
+static const char *
+dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)
+{
+ switch (match_type) {
+ case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT:
+ return "field_exact";
+ default:
+ return "<unknown>";
+ }
+}
+
+static void pr_out_dpipe_match(struct dpipe_ctx *ctx,
+ uint32_t header_id, uint32_t field_id,
+ uint32_t match_type, bool global)
+{
+ const char *mapping;
+
+ pr_out_str(ctx->dl, "type", dpipe_match_type_e2s(match_type));
+ pr_out_str(ctx->dl, "header", dpipe_header_id2s(ctx, header_id,
+ global));
+ pr_out_str(ctx->dl, "field", dpipe_field_id2s(ctx, header_id, field_id,
+ global));
+ mapping = dpipe_mapping_get(ctx, header_id, field_id, global);
+ if (mapping)
+ pr_out_str(ctx->dl, "mapping", mapping);
+
+}
+
+static int dpipe_match_show(struct dpipe_ctx *ctx, struct nlattr *nl)
+{
+ struct nlattr *nla_match[DEVLINK_ATTR_MAX + 1] = {};
+ uint32_t header_id, field_id, match_type;
+ bool global;
+ int err;
+
+ err = mnl_attr_parse_nested(nl, attr_cb, nla_match);
+ if (err != MNL_CB_OK)
+ return -EINVAL;
+
+ if (!nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE] ||
+ !nla_match[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
+ !nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
+ !nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
+ return -EINVAL;
+ }
+
+ match_type = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE]);
+ header_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID]);
+ field_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]);
+ global = !!mnl_attr_get_u8(nla_match[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
+
+ pr_out_dpipe_match(ctx, header_id, field_id, match_type, global);
+ return 0;
+}
+
+static int dpipe_table_matches_show(struct dpipe_ctx *ctx,
+ struct nlattr *nla_matches)
+{
+ struct nlattr *nla_match;
+
+ mnl_attr_for_each_nested(nla_match, nla_matches) {
+ pr_out_entry_start(ctx->dl);
+ if (dpipe_match_show(ctx, nla_match))
+ goto err_match_show;
+ pr_out_entry_end(ctx->dl);
+ }
+ return 0;
+
+err_match_show:
+ pr_out_entry_end(ctx->dl);
+ return -EINVAL;
+}
+
+static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
+{
+ struct nlattr *nla_table[DEVLINK_ATTR_MAX + 1] = {};
+ bool counters_enabled;
+ const char *name;
+ uint32_t size;
+ int err;
+
+ err = mnl_attr_parse_nested(nl, attr_cb, nla_table);
+ if (err != MNL_CB_OK)
+ return -EINVAL;
+
+ if (!nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
+ !nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE] ||
+ !nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] ||
+ !nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] ||
+ !nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) {
+ return -EINVAL;
+ }
+
+ name = mnl_attr_get_str(nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
+ size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
+ counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
+
+ pr_out_str(ctx->dl, "name", name);
+ pr_out_uint(ctx->dl, "size", size);
+ pr_out_str(ctx->dl, "counters_enabled",
+ counters_enabled ? "true" : "false");
+
+ pr_out_array_start(ctx->dl, "match");
+ if (dpipe_table_matches_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES]))
+ goto err_matches_show;
+ pr_out_array_end(ctx->dl);
+
+ pr_out_array_start(ctx->dl, "action");
+ if (dpipe_table_actions_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS]))
+ goto err_actions_show;
+ pr_out_array_end(ctx->dl);
+
+ return 0;
+
+err_actions_show:
+err_matches_show:
+ pr_out_array_end(ctx->dl);
+ return -EINVAL;
+}
+
+static int dpipe_tables_show(struct dpipe_ctx *ctx, struct nlattr **tb)
+{
+ struct nlattr *nla_tables = tb[DEVLINK_ATTR_DPIPE_TABLES];
+ struct nlattr *nla_table;
+
+ mnl_attr_for_each_nested(nla_table, nla_tables) {
+ pr_out_handle_start_arr(ctx->dl, tb);
+ if (dpipe_table_show(ctx, nla_table))
+ goto err_table_show;
+ pr_out_handle_end(ctx->dl);
+ }
+ return 0;
+
+err_table_show:
+ pr_out_handle_end(ctx->dl);
+ return -EINVAL;
+}
+
+static int cmd_dpipe_table_show_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct dpipe_ctx *ctx = 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_DPIPE_TABLES])
+ return MNL_CB_ERROR;
+
+ if (dpipe_tables_show(ctx, tb))
+ return MNL_CB_ERROR;
+ return MNL_CB_OK;
+}
+
+static int cmd_dpipe_table_show(struct dl *dl)
+{
+ struct nlmsghdr *nlh;
+ struct dpipe_ctx *ctx;
+ uint16_t flags = NLM_F_REQUEST;
+ int err;
+
+ ctx = dpipe_ctx_alloc(dl);
+ if (!ctx)
+ return -ENOMEM;
+
+ err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_DPIPE_TABLE_NAME);
+ if (err)
+ goto out;
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
+ dl_opts_put(nlh, dl);
+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, ctx);
+ if (err) {
+ pr_err("error get headers %s\n", strerror(ctx->err));
+ goto out;
+ }
+
+ flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
+ dl_opts_put(nlh, dl);
+
+ pr_out_section_start(dl, "table");
+ _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, ctx);
+ pr_out_section_end(dl);
+out:
+ dpipe_ctx_clear(ctx);
+ dpipe_ctx_free(ctx);
+ return err;
+}
+
+static int cmd_dpipe_table_set(struct dl *dl)
+{
+ struct nlmsghdr *nlh;
+ int err;
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
+ NLM_F_REQUEST | NLM_F_ACK);
+
+ err = dl_argv_parse_put(nlh, dl,
+ DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME |
+ DL_OPT_DPIPE_TABLE_COUNTERS, 0);
+ if (err)
+ return err;
+
+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+}
+
+static int dpipe_entry_value_show(struct dpipe_ctx *ctx,
+ struct nlattr **nla_match_value)
+{
+ uint16_t value_len;
+ bool mask, mapping;
+
+ mask = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK];
+ mapping = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING];
+
+ value_len = mnl_attr_get_payload_len(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
+ if (value_len == sizeof(uint32_t)) {
+ uint32_t value, value_mask, value_mapping;
+
+ if (mapping) {
+ value_mapping = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING]);
+ pr_out_uint(ctx->dl, "mapping_value", value_mapping);
+ }
+
+ if (mask) {
+ value_mask = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK]);
+ pr_out_uint(ctx->dl, "mask_value", value_mask);
+ }
+
+ value = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
+ pr_out_uint(ctx->dl, "value", value);
+
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int dpipe_entry_match_value_show(struct dpipe_ctx *ctx,
+ struct nlattr *nl)
+{
+ struct nlattr *nla_match_value[DEVLINK_ATTR_MAX + 1] = {};
+ int err;
+
+ err = mnl_attr_parse_nested(nl, attr_cb, nla_match_value);
+ if (err != MNL_CB_OK)
+ return -EINVAL;
+
+ if (!nla_match_value[DEVLINK_ATTR_DPIPE_MATCH] ||
+ !nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]) {
+ return -EINVAL;
+ }
+
+ pr_out_entry_start(ctx->dl);
+ if (dpipe_match_show(ctx, nla_match_value[DEVLINK_ATTR_DPIPE_MATCH]))
+ goto err_match_show;
+ if (dpipe_entry_value_show(ctx, nla_match_value))
+ goto err_value_show;
+ pr_out_entry_end(ctx->dl);
+
+ return 0;
+
+err_match_show:
+err_value_show:
+ pr_out_entry_end(ctx->dl);
+ return -EINVAL;
+}
+
+static int dpipe_entry_action_value_show(struct dpipe_ctx *ctx,
+ struct nlattr *nl)
+{
+ struct nlattr *nla_action_value[DEVLINK_ATTR_MAX + 1] = {};
+ int err;
+
+ err = mnl_attr_parse_nested(nl, attr_cb, nla_action_value);
+ if (err != MNL_CB_OK)
+ return -EINVAL;
+
+ if (!nla_action_value[DEVLINK_ATTR_DPIPE_ACTION] ||
+ !nla_action_value[DEVLINK_ATTR_DPIPE_VALUE]) {
+ return -EINVAL;
+ }
+
+ pr_out_entry_start(ctx->dl);
+ if (dpipe_action_show(ctx, nla_action_value[DEVLINK_ATTR_DPIPE_ACTION]))
+ goto err_action_show;
+ if (dpipe_entry_value_show(ctx, nla_action_value))
+ goto err_value_show;
+ pr_out_entry_end(ctx->dl);
+
+ return 0;
+
+err_action_show:
+err_value_show:
+ pr_out_entry_end(ctx->dl);
+ return -EINVAL;
+}
+
+static int
+dpipe_tables_action_values_show(struct dpipe_ctx *ctx,
+ struct nlattr *nla_action_values)
+{
+ struct nlattr *nla_action_value;
+
+ mnl_attr_for_each_nested(nla_action_value, nla_action_values) {
+ if (dpipe_entry_action_value_show(ctx, nla_action_value))
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int
+dpipe_tables_match_values_show(struct dpipe_ctx *ctx,
+ struct nlattr *nla_match_values)
+{
+ struct nlattr *nla_match_value;
+
+ mnl_attr_for_each_nested(nla_match_value, nla_match_values) {
+ if (dpipe_entry_match_value_show(ctx, nla_match_value))
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dpipe_entry_show(struct dpipe_ctx *ctx, struct nlattr *nl)
+{
+ struct nlattr *nla_entry[DEVLINK_ATTR_MAX + 1] = {};
+ uint32_t entry_index;
+ uint64_t counter;
+ int err;
+
+ err = mnl_attr_parse_nested(nl, attr_cb, nla_entry);
+ if (err != MNL_CB_OK)
+ return -EINVAL;
+
+ if (!nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] ||
+ !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] ||
+ !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]) {
+ return -EINVAL;
+ }
+
+ entry_index = mnl_attr_get_u32(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX]);
+ pr_out_uint(ctx->dl, "index", entry_index);
+
+ if (nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]) {
+ counter = mnl_attr_get_u64(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]);
+ pr_out_uint(ctx->dl, "counter", counter);
+ }
+
+ pr_out_array_start(ctx->dl, "match_value");
+ if (dpipe_tables_match_values_show(ctx,
+ nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES]))
+ goto err_match_values_show;
+ pr_out_array_end(ctx->dl);
+
+ pr_out_array_start(ctx->dl, "action_value");
+ if (dpipe_tables_action_values_show(ctx,
+ nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]))
+ goto err_action_values_show;
+ pr_out_array_end(ctx->dl);
+ return 0;
+
+err_action_values_show:
+err_match_values_show:
+ pr_out_array_end(ctx->dl);
+ return -EINVAL;
+}
+
+static int dpipe_table_entries_show(struct dpipe_ctx *ctx, struct nlattr **tb)
+{
+ struct nlattr *nla_entries = tb[DEVLINK_ATTR_DPIPE_ENTRIES];
+ struct nlattr *nla_entry;
+
+ mnl_attr_for_each_nested(nla_entry, nla_entries) {
+ pr_out_handle_start_arr(ctx->dl, tb);
+ if (dpipe_entry_show(ctx, nla_entry))
+ goto err_entry_show;
+ pr_out_handle_end(ctx->dl);
+ }
+ return 0;
+
+err_entry_show:
+ pr_out_handle_end(ctx->dl);
+ return -EINVAL;
+}
+
+static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct dpipe_ctx *ctx = 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_DPIPE_ENTRIES])
+ return MNL_CB_ERROR;
+
+ if (dpipe_table_entries_show(ctx, tb))
+ return MNL_CB_ERROR;
+ return MNL_CB_OK;
+}
+
+static int cmd_dpipe_table_dump(struct dl *dl)
+{
+ struct nlmsghdr *nlh;
+ struct dpipe_ctx *ctx;
+ uint16_t flags = NLM_F_REQUEST;
+ int err;
+
+ ctx = dpipe_ctx_alloc(dl);
+ if (!ctx)
+ return -ENOMEM;
+
+ err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME, 0);
+ if (err)
+ goto out;
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
+ dl_opts_put(nlh, dl);
+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, ctx);
+ if (err) {
+ pr_err("error get headers %s\n", strerror(ctx->err));
+ goto out;
+ }
+
+ flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags);
+ dl_opts_put(nlh, dl);
+
+ pr_out_section_start(dl, "table_entry");
+ _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, ctx);
+ pr_out_section_end(dl);
+out:
+ dpipe_ctx_clear(ctx);
+ dpipe_ctx_free(ctx);
+ return err;
+}
+
+static void cmd_dpipe_table_help(void)
+{
+ pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
+ "where OBJECT-LIST := { show | set | dump }\n");
+}
+
+static int cmd_dpipe_table(struct dl *dl)
+{
+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
+ cmd_dpipe_table_help();
+ return 0;
+ } else if (dl_argv_match(dl, "show")) {
+ dl_arg_inc(dl);
+ return cmd_dpipe_table_show(dl);
+ } else if (dl_argv_match(dl, "set")) {
+ dl_arg_inc(dl);
+ return cmd_dpipe_table_set(dl);
+ } else if (dl_argv_match(dl, "dump")) {
+ dl_arg_inc(dl);
+ return cmd_dpipe_table_dump(dl);
+ }
+ pr_err("Command \"%s\" not found\n", dl_argv(dl));
+ return -ENOENT;
+}
+
+static void cmd_dpipe_help(void)
+{
+ pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
+ "where OBJECT-LIST := { header | table }\n");
+}
+
+static int cmd_dpipe(struct dl *dl)
+{
+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
+ cmd_dpipe_help();
+ return 0;
+ } else if (dl_argv_match(dl, "header")) {
+ dl_arg_inc(dl);
+ return cmd_dpipe_header(dl);
+ } else if (dl_argv_match(dl, "table")) {
+ dl_arg_inc(dl);
+ return cmd_dpipe_table(dl);
+ }
+ pr_err("Command \"%s\" not found\n", dl_argv(dl));
+ return -ENOENT;
+}
+
+static void help(void)
+{
+ pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
+ "where OBJECT := { dev | port | sb | monitor | dpipe }\n"
+ " OPTIONS := { -V[ersion] | -n[no-nice-names] | -j[json] | -p[pretty] | -v[verbose] }\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, "sb")) {
+ dl_arg_inc(dl);
+ return cmd_sb(dl);
+ } else if (dl_argv_match(dl, "monitor")) {
+ dl_arg_inc(dl);
+ return cmd_mon(dl);
+ } else if (dl_argv_match(dl, "dpipe")) {
+ dl_arg_inc(dl);
+ return cmd_dpipe(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;
+ }
+ if (dl->json_output) {
+ dl->jw = jsonw_new(stdout);
+ if (!dl->jw) {
+ pr_err("Failed to create JSON writer\n");
+ goto err_json_new;
+ }
+ jsonw_pretty(dl->jw, dl->pretty_output);
+ }
+ return 0;
+
+err_json_new:
+ ifname_map_fini(dl);
+err_ifname_map_create:
+ mnlg_socket_close(dl->nlg);
+ return err;
+}
+
+static void dl_fini(struct dl *dl)
+{
+ if (dl->json_output)
+ jsonw_destroy(&dl->jw);
+ 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' },
+ { "no-nice-names", no_argument, NULL, 'n' },
+ { "json", no_argument, NULL, 'j' },
+ { "pretty", no_argument, NULL, 'p' },
+ { "verbose", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+ };
+ struct dl *dl;
+ int opt;
+ int err;
+ int ret;
+
+ dl = dl_alloc();
+ if (!dl) {
+ pr_err("Failed to allocate memory for devlink\n");
+ return EXIT_FAILURE;
+ }
+
+ while ((opt = getopt_long(argc, argv, "Vnjpv",
+ long_options, NULL)) >= 0) {
+
+ switch (opt) {
+ case 'V':
+ printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
+ ret = EXIT_SUCCESS;
+ goto dl_free;
+ case 'n':
+ dl->no_nice_names = true;
+ break;
+ case 'j':
+ dl->json_output = true;
+ break;
+ case 'p':
+ dl->pretty_output = true;
+ break;
+ case 'v':
+ dl->verbose = true;
break;
default:
pr_err("Unknown option.\n");
--
2.7.4
^ permalink raw reply related
* [patch iproute2 v2 1/2] devlink: Change netlink attribute validation
From: Jiri Pirko @ 2017-05-03 11:25 UTC (permalink / raw)
To: netdev; +Cc: arkadis, stephen, davem, mlxsw, dsa
In-Reply-To: <1493810723-2536-1-git-send-email-jiri@resnulli.us>
From: Arkadi Sharshevsky <arkadis@mellanox.com>
Currently the netlink attribute resolving is done by a sequence of
if's. Change the attribute resolving to table lookup.
Signed-off-by: Arkadi Sharshevsky <arkadis@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
devlink/devlink.c | 103 ++++++++++++++++--------------------------------------
1 file changed, 30 insertions(+), 73 deletions(-)
diff --git a/devlink/devlink.c b/devlink/devlink.c
index e90226e..35220d8 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c
@@ -232,88 +232,45 @@ static bool dl_no_arg(struct dl *dl)
return dl_argc(dl) == 0;
}
+static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
+ [DEVLINK_ATTR_BUS_NAME] = MNL_TYPE_NUL_STRING,
+ [DEVLINK_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING,
+ [DEVLINK_ATTR_PORT_INDEX] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_PORT_TYPE] = MNL_TYPE_U16,
+ [DEVLINK_ATTR_PORT_DESIRED_TYPE] = MNL_TYPE_U16,
+ [DEVLINK_ATTR_PORT_NETDEV_IFINDEX] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_PORT_NETDEV_NAME] = MNL_TYPE_NUL_STRING,
+ [DEVLINK_ATTR_PORT_IBDEV_NAME] = MNL_TYPE_NUL_STRING,
+ [DEVLINK_ATTR_SB_INDEX] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_SB_SIZE] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] = MNL_TYPE_U16,
+ [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] = MNL_TYPE_U16,
+ [DEVLINK_ATTR_SB_INGRESS_TC_COUNT] = MNL_TYPE_U16,
+ [DEVLINK_ATTR_SB_EGRESS_TC_COUNT] = MNL_TYPE_U16,
+ [DEVLINK_ATTR_SB_POOL_INDEX] = MNL_TYPE_U16,
+ [DEVLINK_ATTR_SB_POOL_TYPE] = MNL_TYPE_U8,
+ [DEVLINK_ATTR_SB_POOL_SIZE] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = MNL_TYPE_U8,
+ [DEVLINK_ATTR_SB_THRESHOLD] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_SB_TC_INDEX] = MNL_TYPE_U16,
+ [DEVLINK_ATTR_SB_OCC_CUR] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_SB_OCC_MAX] = MNL_TYPE_U32,
+ [DEVLINK_ATTR_ESWITCH_MODE] = MNL_TYPE_U16,
+ [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = MNL_TYPE_U8,
+};
+
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;
- if (type == DEVLINK_ATTR_SB_INDEX &&
- mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_SIZE &&
- mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_INGRESS_POOL_COUNT &&
- mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_EGRESS_POOL_COUNT &&
- mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_INGRESS_TC_COUNT &&
- mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_EGRESS_TC_COUNT &&
- mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_POOL_INDEX &&
- mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_POOL_TYPE &&
- mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_POOL_SIZE &&
- mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE &&
- mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_THRESHOLD &&
- mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_TC_INDEX &&
- mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_OCC_CUR &&
- mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_SB_OCC_MAX &&
- mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_ESWITCH_MODE &&
- mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
- return MNL_CB_ERROR;
- if (type == DEVLINK_ATTR_ESWITCH_INLINE_MODE &&
- mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+ type = mnl_attr_get_type(attr);
+ if (mnl_attr_validate(attr, devlink_policy[type]) < 0)
return MNL_CB_ERROR;
+
tb[type] = attr;
return MNL_CB_OK;
}
--
2.7.4
^ permalink raw reply related
* [patch iproute2 v2 0/2] devlink: Add support for pipeline
From: Jiri Pirko @ 2017-05-03 11:25 UTC (permalink / raw)
To: netdev; +Cc: arkadis, stephen, davem, mlxsw, dsa
From: Jiri Pirko <jiri@mellanox.com>
Arkadi says:
Add support for pipeline debug (dpipe). As a preparation step the netlink
attribute validation was changed before adding new dpipe attributes.
---
v1->v2
- Change netlink attribute validation.
- Fix commit message typos
Arkadi Sharshevsky (2):
devlink: Change netlink attribute validation
devlink: Add support for pipeline debug (dpipe)
devlink/devlink.c | 1450 ++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 1281 insertions(+), 169 deletions(-)
--
2.7.4
^ permalink raw reply
* Eine Spende von 1 Million Britische Pfund zu Ihnen in gutem Glauben
From: Mr Neil Trotter @ 2017-05-03 9:53 UTC (permalink / raw)
^ permalink raw reply
* Re: [PATCH 1/1] net: usb: qmi_wwan: add Telit ME910 support
From: Bjørn Mork @ 2017-05-03 9:43 UTC (permalink / raw)
To: Daniele Palmas; +Cc: netdev
In-Reply-To: <1493800211-7758-1-git-send-email-dnlplm@gmail.com>
Daniele Palmas <dnlplm@gmail.com> writes:
> This patch adds support for Telit ME910 PID 0x1100.
>
> Signed-off-by: Daniele Palmas <dnlplm@gmail.com>
Acked-by: Bjørn Mork <bjorn@mork.no>
David, please add this to your stable queue as well. Thanks
Bjørn
^ permalink raw reply
* Re: [PATCH 3/4] net: macb: Add hardware PTP support
From: Richard Cochran @ 2017-05-03 9:43 UTC (permalink / raw)
To: Rafal Ozieblo
Cc: David Miller,
nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org,
netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
harinikatakamlinux-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
harini.katakam-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org,
Andrei.Pistirica-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org
In-Reply-To: <BN3PR07MB2516757CB4EA7367F6623C06C9170-EldUQEzkDQfxGZiqM5fOI+FPX92sqiQdvxpqHgZTriW3zl9H0oFU5g@public.gmane.org>
On Tue, May 02, 2017 at 01:57:15PM +0000, Rafal Ozieblo wrote:
> > What is the point of this wrapper function anyhow? Please remove it.
> gem_ptp_gettime() is assigned in ptp_clock_info and it has to have
> ptp_clock_info pointer as first parameter. gem_tsu_get_time() is used in
> the source code but with macb pointer.
> Do you want me to do something like:
> gem_ptp_gettime(macb->ptp, ts);
> and first would be getting macb pointer from ptp ?
> struct macb *bp = container_of(ptp, struct macb, ptp_clock_info);
Yes. Unless your sub-function is used in more than one place, then it
is wasteful and confusing to wrap the functionality for no apparent
reason.
> > > + switch (rq->type) {
> > > + case PTP_CLK_REQ_EXTTS: /* Toggle TSU match interrupt */
> > > + if (on)
> > > + macb_writel(bp, IER, MACB_BIT(TCI));
> >
> > No locking to protect IER and IDE?
> There is no need.
But what happens when the PTP_CLK_REQ_EXTTS and PTP_CLK_REQ_PPS ioctls
are called at the same time?
You need to ensure that IDR is consistent. If the bits are write
only, then you should comment this fact.
> > > + else
> > > + macb_writel(bp, IDR, MACB_BIT(TCI));
> > > + break;
> > > + case PTP_CLK_REQ_PEROUT: /* Toggle Periodic output */
> > > + return -EOPNOTSUPP;
> > > + /* break; */
> > > + case PTP_CLK_REQ_PPS: /* Toggle TSU periodic (second)
> > interrupt */
> > > + if (on)
> > > + macb_writel(bp, IER, MACB_BIT(SRI));
> > > + else
> > > + macb_writel(bp, IDR, MACB_BIT(SRI));
> > > + break;
> > > + default:
> > > + break;
> > > + }
> > > + return 0;
> > > +}
Thanks,
Richard
--
To unsubscribe from this list: send the line "unsubscribe devicetree" 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 09/16] netfilter: xt_socket: Fix broken IPv6 handling
From: Pablo Neira Ayuso @ 2017-05-03 9:32 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1493803931-2837-1-git-send-email-pablo@netfilter.org>
From: Peter Tirsek <peter@tirsek.com>
Commit 834184b1f3a4 ("netfilter: defrag: only register defrag
functionality if needed") used the outdated XT_SOCKET_HAVE_IPV6 macro
which was removed earlier in commit 8db4c5be88f6 ("netfilter: move
socket lookup infrastructure to nf_socket_ipv{4,6}.c"). With that macro
never being defined, the xt_socket match emits an "Unknown family 10"
warning when used with IPv6:
WARNING: CPU: 0 PID: 1377 at net/netfilter/xt_socket.c:160 socket_mt_enable_defrag+0x47/0x50 [xt_socket]
Unknown family 10
Modules linked in: xt_socket nf_socket_ipv4 nf_socket_ipv6 nf_defrag_ipv4 [...]
CPU: 0 PID: 1377 Comm: ip6tables-resto Not tainted 4.10.10 #1
Hardware name: [...]
Call Trace:
? __warn+0xe7/0x100
? socket_mt_enable_defrag+0x47/0x50 [xt_socket]
? socket_mt_enable_defrag+0x47/0x50 [xt_socket]
? warn_slowpath_fmt+0x39/0x40
? socket_mt_enable_defrag+0x47/0x50 [xt_socket]
? socket_mt_v2_check+0x12/0x40 [xt_socket]
? xt_check_match+0x6b/0x1a0 [x_tables]
? xt_find_match+0x93/0xd0 [x_tables]
? xt_request_find_match+0x20/0x80 [x_tables]
? translate_table+0x48e/0x870 [ip6_tables]
? translate_table+0x577/0x870 [ip6_tables]
? walk_component+0x3a/0x200
? kmalloc_order+0x1d/0x50
? do_ip6t_set_ctl+0x181/0x490 [ip6_tables]
? filename_lookup+0xa5/0x120
? nf_setsockopt+0x3a/0x60
? ipv6_setsockopt+0xb0/0xc0
? sock_common_setsockopt+0x23/0x30
? SyS_socketcall+0x41d/0x630
? vfs_read+0xfa/0x120
? do_fast_syscall_32+0x7a/0x110
? entry_SYSENTER_32+0x47/0x71
This patch brings the conditional back in line with how the rest of the
file handles IPv6.
Fixes: 834184b1f3a4 ("netfilter: defrag: only register defrag functionality if needed")
Signed-off-by: Peter Tirsek <peter@tirsek.com>
Acked-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/xt_socket.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 770bbec878f1..e75ef39669c5 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -152,7 +152,7 @@ static int socket_mt_enable_defrag(struct net *net, int family)
switch (family) {
case NFPROTO_IPV4:
return nf_defrag_ipv4_enable(net);
-#ifdef XT_SOCKET_HAVE_IPV6
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
case NFPROTO_IPV6:
return nf_defrag_ipv6_enable(net);
#endif
--
2.1.4
^ permalink raw reply related
* [PATCH 08/16] netfilter: ctnetlink: acquire ct->lock before operating nf_ct_seqadj
From: Pablo Neira Ayuso @ 2017-05-03 9:32 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1493803931-2837-1-git-send-email-pablo@netfilter.org>
From: Liping Zhang <zlpnobody@gmail.com>
We should acquire the ct->lock before accessing or modifying the
nf_ct_seqadj, as another CPU may modify the nf_ct_seqadj at the same
time during its packet proccessing.
Signed-off-by: Liping Zhang <zlpnobody@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_netlink.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 86deed6a8db4..78f8c9adbd3c 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -417,8 +417,7 @@ dump_ct_seq_adj(struct sk_buff *skb, const struct nf_ct_seqadj *seq, int type)
return -1;
}
-static int ctnetlink_dump_ct_seq_adj(struct sk_buff *skb,
- const struct nf_conn *ct)
+static int ctnetlink_dump_ct_seq_adj(struct sk_buff *skb, struct nf_conn *ct)
{
struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
struct nf_ct_seqadj *seq;
@@ -426,15 +425,20 @@ static int ctnetlink_dump_ct_seq_adj(struct sk_buff *skb,
if (!(ct->status & IPS_SEQ_ADJUST) || !seqadj)
return 0;
+ spin_lock_bh(&ct->lock);
seq = &seqadj->seq[IP_CT_DIR_ORIGINAL];
if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_ORIG) == -1)
- return -1;
+ goto err;
seq = &seqadj->seq[IP_CT_DIR_REPLY];
if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_REPLY) == -1)
- return -1;
+ goto err;
+ spin_unlock_bh(&ct->lock);
return 0;
+err:
+ spin_unlock_bh(&ct->lock);
+ return -1;
}
static int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
@@ -1637,11 +1641,12 @@ ctnetlink_change_seq_adj(struct nf_conn *ct,
if (!seqadj)
return 0;
+ spin_lock_bh(&ct->lock);
if (cda[CTA_SEQ_ADJ_ORIG]) {
ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_ORIGINAL],
cda[CTA_SEQ_ADJ_ORIG]);
if (ret < 0)
- return ret;
+ goto err;
set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
}
@@ -1650,12 +1655,16 @@ ctnetlink_change_seq_adj(struct nf_conn *ct,
ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_REPLY],
cda[CTA_SEQ_ADJ_REPLY]);
if (ret < 0)
- return ret;
+ goto err;
set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
}
+ spin_unlock_bh(&ct->lock);
return 0;
+err:
+ spin_unlock_bh(&ct->lock);
+ return ret;
}
static int
--
2.1.4
^ permalink raw reply related
* [PATCH 04/16] netfilter: nft_set_bitmap: free dummy elements when destroy the set
From: Pablo Neira Ayuso @ 2017-05-03 9:31 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1493803931-2837-1-git-send-email-pablo@netfilter.org>
From: Liping Zhang <zlpnobody@gmail.com>
We forget to free dummy elements when deleting the set. So when I was
running nft-test.py, I saw many kmemleak warnings:
kmemleak: 1344 new suspected memory leaks ...
# cat /sys/kernel/debug/kmemleak
unreferenced object 0xffff8800631345c8 (size 32):
comm "nft", pid 9075, jiffies 4295743309 (age 1354.815s)
hex dump (first 32 bytes):
f8 63 13 63 00 88 ff ff 88 79 13 63 00 88 ff ff .c.c.....y.c....
04 0c 00 00 00 00 00 00 00 00 00 00 08 03 00 00 ................
backtrace:
[<ffffffff819059da>] kmemleak_alloc+0x4a/0xa0
[<ffffffff81288174>] __kmalloc+0x164/0x310
[<ffffffffa061269d>] nft_set_elem_init+0x3d/0x1b0 [nf_tables]
[<ffffffffa06130da>] nft_add_set_elem+0x45a/0x8c0 [nf_tables]
[<ffffffffa0613645>] nf_tables_newsetelem+0x105/0x1d0 [nf_tables]
[<ffffffffa05fe6d4>] nfnetlink_rcv+0x414/0x770 [nfnetlink]
[<ffffffff817f0ca6>] netlink_unicast+0x1f6/0x310
[<ffffffff817f10c6>] netlink_sendmsg+0x306/0x3b0
...
Fixes: e920dde516088 ("netfilter: nft_set_bitmap: keep a list of dummy elements")
Signed-off-by: Liping Zhang <zlpnobody@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nft_set_bitmap.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/netfilter/nft_set_bitmap.c b/net/netfilter/nft_set_bitmap.c
index 8ebbc2940f4c..b988162b5b15 100644
--- a/net/netfilter/nft_set_bitmap.c
+++ b/net/netfilter/nft_set_bitmap.c
@@ -257,6 +257,11 @@ static int nft_bitmap_init(const struct nft_set *set,
static void nft_bitmap_destroy(const struct nft_set *set)
{
+ struct nft_bitmap *priv = nft_set_priv(set);
+ struct nft_bitmap_elem *be, *n;
+
+ list_for_each_entry_safe(be, n, &priv->list, head)
+ nft_set_elem_destroy(set, be, true);
}
static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features,
--
2.1.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox