* Re: net/ipv6: slab-out-of-bounds in ip6_tnl_xmit
From: Cong Wang @ 2017-04-25 5:04 UTC (permalink / raw)
To: Andrey Konovalov
Cc: David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, netdev, LKML, Eric Dumazet,
Dmitry Vyukov, Kostya Serebryany, syzkaller
In-Reply-To: <CAM_iQpXLHx=NhSNYU_o4F_V6nNXUHGBSdV=QQnML0B+HD7MbBQ@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 889 bytes --]
On Mon, Apr 24, 2017 at 9:47 AM, Cong Wang <xiyou.wangcong@gmail.com> wrote:
>
> We use ipv4 dst in ip6_tunnel and cast an IPv4 neigh key as an
> IPv6 address...
>
>
> neigh = dst_neigh_lookup(skb_dst(skb),
> &ipv6_hdr(skb)->daddr);
> if (!neigh)
> goto tx_err_link_failure;
>
> addr6 = (struct in6_addr *)&neigh->primary_key; // <=== HERE
> addr_type = ipv6_addr_type(addr6);
>
> if (addr_type == IPV6_ADDR_ANY)
> addr6 = &ipv6_hdr(skb)->daddr;
>
> memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
>
> Also the network header of the skb at this point should be still IPv4?
Please try the attached patch.
I am not sure how we could handle 4in6 case better than just relying on
the config of ip6 tunnel.
[-- Attachment #2: ip6_tunnel.diff --]
[-- Type: text/plain, Size: 1888 bytes --]
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 75fac93..a9692ec 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1037,7 +1037,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
struct ip6_tnl *t = netdev_priv(dev);
struct net *net = t->net;
struct net_device_stats *stats = &t->dev->stats;
- struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ struct ipv6hdr *ipv6h;
struct ipv6_tel_txoption opt;
struct dst_entry *dst = NULL, *ndst = NULL;
struct net_device *tdev;
@@ -1057,26 +1057,28 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
/* NBMA tunnel */
if (ipv6_addr_any(&t->parms.raddr)) {
- struct in6_addr *addr6;
- struct neighbour *neigh;
- int addr_type;
+ if (skb->protocol == htons(ETH_P_IPV6)) {
+ struct in6_addr *addr6;
+ struct neighbour *neigh;
+ int addr_type;
- if (!skb_dst(skb))
- goto tx_err_link_failure;
+ if (!skb_dst(skb))
+ goto tx_err_link_failure;
- neigh = dst_neigh_lookup(skb_dst(skb),
- &ipv6_hdr(skb)->daddr);
- if (!neigh)
- goto tx_err_link_failure;
+ neigh = dst_neigh_lookup(skb_dst(skb),
+ &ipv6_hdr(skb)->daddr);
+ if (!neigh)
+ goto tx_err_link_failure;
- addr6 = (struct in6_addr *)&neigh->primary_key;
- addr_type = ipv6_addr_type(addr6);
+ addr6 = (struct in6_addr *)&neigh->primary_key;
+ addr_type = ipv6_addr_type(addr6);
- if (addr_type == IPV6_ADDR_ANY)
- addr6 = &ipv6_hdr(skb)->daddr;
+ if (addr_type == IPV6_ADDR_ANY)
+ addr6 = &ipv6_hdr(skb)->daddr;
- memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
- neigh_release(neigh);
+ memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
+ neigh_release(neigh);
+ }
} else if (!(t->parms.flags &
(IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) {
/* enable the cache only only if the routing decision does
^ permalink raw reply related
* Re: [PATCH] stmmac: Add support for SIMATIC IOT2000 platform
From: Jan Kiszka @ 2017-04-25 5:44 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Giuseppe Cavallaro, Alexandre Torgue, netdev,
Linux Kernel Mailing List, Sascha Weisenberger
In-Reply-To: <CAHp75VcdpOXa+aQ6-iKamTAbX9KGZOWpukygSUS7Ef_E3UNvuw@mail.gmail.com>
On 2017-04-24 23:27, Andy Shevchenko wrote:
> On Mon, Apr 24, 2017 at 10:27 PM, Jan Kiszka <jan.kiszka@siemens.com> wrote:
>> The IOT2000 is industrial controller platform, derived from the Intel
>> Galileo Gen2 board. The variant IOT2020 comes with one LAN port, the
>> IOT2040 has two of them. They can be told apart based on the board asset
>> tag in the DMI table.
>>
>> Based on patch by Sascha Weisenberger.
>>
>
>> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
>> Signed-off-by: Sascha Weisenberger <sascha.weisenberger@siemens.com>
>
> Shoudn't be ordered other way around?
Nope. My changes invalidated Sascha's signed-off on the original patch,
but he signed off again on the final version.
>
>> + const char *asset_tag;
>
> I guess this is redundant. See below.
>
>> + {
>> + .name = "SIMATIC IOT2000",
>> + .asset_tag = "6ES7647-0AA00-0YA2",
>> + .func = 6,
>> + .phy_addr = 1,
>> + },
>
> The below has same definition disregard on asset_tag.
>
There is a small difference in the asset tag, just not at the last digit
where one may expect it, look:
...-0YA2 -> IOT2020
...-1YA2 -> IOT2040
>> + {
>> + .name = "SIMATIC IOT2000",
>> + .asset_tag = "6ES7647-0AA00-1YA2",
>> + .func = 6,
>> + .phy_addr = 1,
>> + },
>> + {
>> + .name = "SIMATIC IOT2000",
>> + .asset_tag = "6ES7647-0AA00-1YA2",
>> + .func = 7,
>> + .phy_addr = 1,
>> + },
>
> How this supposed to work if phy_addr is the same?
>
That address space is MAC-local, and we have two different MACs here.
Jan
--
Siemens AG, Corporate Technology, CT RDA ITP SES-DE
Corporate Competence Center Embedded Linux
^ permalink raw reply
* [PATCH 0/8] Fix and complete CAN namespace support
From: Oliver Hartkopp @ 2017-04-25 6:19 UTC (permalink / raw)
To: linux-can, davem; +Cc: Oliver Hartkopp, mkl, dev, netdev
Hello Dave,
unfortunately the initial network namespace support by Mario Kicherer
(8e8cda6d737d) slipped into net-next without further review and Marc pushed
the code without my Acked-by. Due to the fact that this code was in net-next
now I spent some nights to fix, clean up, finalize and test the missing pieces
for the namespace support for the CAN subsystem in net/can.
As Marc is currently *VERY* unresponsive on the mailing list due to his 'real'
job I send this patch set directly to you to make sure it gets through the
current merge window. We are already in -rc8 and I would like to avoid to push
an incomplete functionality - that has to be fixed - to Linus.
This patch set is based on the latest net-next.
Thanks,
Oliver
Oliver Hartkopp (8):
can: fix memory leak in initial namespace support
can: remove obsolete pernet_operations definitions
can: remove obsolete definitions
can: complete initial namespace support
can: network namespace support for CAN_BCM protocol
can: network namespace support for CAN gateway
can: add Virtual CAN Tunnel driver (vxcan)
can: enable module auto loading for virtual CAN interfaces
drivers/net/can/Kconfig | 18 +++
drivers/net/can/Makefile | 1 +
drivers/net/can/vcan.c | 7 +-
drivers/net/can/vxcan.c | 316 +++++++++++++++++++++++++++++++++++++++++
include/linux/can/core.h | 4 +-
include/net/netns/can.h | 9 ++
include/uapi/linux/can/vxcan.h | 12 ++
net/can/af_can.c | 77 +++++-----
net/can/af_can.h | 9 --
net/can/bcm.c | 90 +++++++-----
net/can/gw.c | 72 ++++++----
net/can/proc.c | 141 +++++++++---------
12 files changed, 580 insertions(+), 176 deletions(-)
create mode 100644 drivers/net/can/vxcan.c
create mode 100644 include/uapi/linux/can/vxcan.h
--
2.11.0
^ permalink raw reply
* [PATCH 1/8] can: fix memory leak in initial namespace support
From: Oliver Hartkopp @ 2017-04-25 6:19 UTC (permalink / raw)
To: linux-can, davem; +Cc: Oliver Hartkopp, mkl, dev, netdev
In-Reply-To: <20170425061945.28722-1-socketcan@hartkopp.net>
The can_rx_alldev_list is a per-net data structure now and allocated in
can_pernet_init(). Make sure the memory is free'd in can_pernet_exit() too.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
net/can/af_can.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/can/af_can.c b/net/can/af_can.c
index abf7d854a94d..2c935babe466 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -903,6 +903,8 @@ static void can_pernet_exit(struct net *net)
}
}
rcu_read_unlock();
+
+ kfree(net->can.can_rx_alldev_list);
}
/*
--
2.11.0
^ permalink raw reply related
* [PATCH 2/8] can: remove obsolete pernet_operations definitions
From: Oliver Hartkopp @ 2017-04-25 6:19 UTC (permalink / raw)
To: linux-can, davem; +Cc: Oliver Hartkopp, mkl, dev, netdev
In-Reply-To: <20170425061945.28722-1-socketcan@hartkopp.net>
The namespace support for the CAN subsystem does not need any additional
memory. So when ".size = 0" there's no extra memory allocated by the system.
And therefore ".id" is obsolete too.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
net/can/af_can.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 2c935babe466..421b60fc42c3 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -75,8 +75,6 @@ static int stats_timer __read_mostly = 1;
module_param(stats_timer, int, S_IRUGO);
MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)");
-static int can_net_id;
-
static struct kmem_cache *rcv_cache __read_mostly;
/* table of registered CAN protocols */
@@ -935,8 +933,6 @@ static struct notifier_block can_netdev_notifier __read_mostly = {
static struct pernet_operations can_pernet_ops __read_mostly = {
.init = can_pernet_init,
.exit = can_pernet_exit,
- .id = &can_net_id,
- .size = 0,
};
static __init int can_init(void)
--
2.11.0
^ permalink raw reply related
* [PATCH 3/8] can: remove obsolete definitions
From: Oliver Hartkopp @ 2017-04-25 6:19 UTC (permalink / raw)
To: linux-can, davem; +Cc: Oliver Hartkopp, mkl, dev, netdev
In-Reply-To: <20170425061945.28722-1-socketcan@hartkopp.net>
can_rx_alldev_list is a per-net data structure now. Remove it's definition
here and can_rx_dev_list too.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
net/can/af_can.h | 4 ----
1 file changed, 4 deletions(-)
diff --git a/net/can/af_can.h b/net/can/af_can.h
index f273c9d9b129..84a35e97c5e0 100644
--- a/net/can/af_can.h
+++ b/net/can/af_can.h
@@ -110,9 +110,6 @@ struct s_pstats {
unsigned long rcv_entries_max;
};
-/* receive filters subscribed for 'all' CAN devices */
-extern struct dev_rcv_lists can_rx_alldev_list;
-
/* function prototypes for the CAN networklayer procfs (proc.c) */
void can_init_proc(struct net *net);
void can_remove_proc(struct net *net);
@@ -122,6 +119,5 @@ void can_stat_update(unsigned long data);
extern struct timer_list can_stattimer; /* timer for statistics update */
extern struct s_stats can_stats; /* packet statistics */
extern struct s_pstats can_pstats; /* receive list statistics */
-extern struct hlist_head can_rx_dev_list; /* rx dispatcher structures */
#endif /* AF_CAN_H */
--
2.11.0
^ permalink raw reply related
* [PATCH 6/8] can: network namespace support for CAN gateway
From: Oliver Hartkopp @ 2017-04-25 6:19 UTC (permalink / raw)
To: linux-can, davem; +Cc: Oliver Hartkopp, mkl, dev, netdev
In-Reply-To: <20170425061945.28722-1-socketcan@hartkopp.net>
The CAN gateway was not implemented as per-net in the initial network
namespace support by Mario Kicherer (8e8cda6d737d).
This patch enables the CAN gateway to be used in different namespaces.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
include/net/netns/can.h | 3 +++
net/can/gw.c | 72 ++++++++++++++++++++++++++++++-------------------
2 files changed, 47 insertions(+), 28 deletions(-)
diff --git a/include/net/netns/can.h b/include/net/netns/can.h
index 0f3c31aab8a8..b106e6ae2e5b 100644
--- a/include/net/netns/can.h
+++ b/include/net/netns/can.h
@@ -32,6 +32,9 @@ struct netns_can {
struct timer_list can_stattimer;/* timer for statistics update */
struct s_stats *can_stats; /* packet statistics */
struct s_pstats *can_pstats; /* receive list statistics */
+
+ /* CAN GW per-net gateway jobs */
+ struct hlist_head cgw_list;
};
#endif /* __NETNS_CAN_H__ */
diff --git a/net/can/gw.c b/net/can/gw.c
index ad5bf5d508d3..29748d844c3f 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -1,7 +1,7 @@
/*
* gw.c - CAN frame Gateway/Router/Bridge with netlink interface
*
- * Copyright (c) 2011 Volkswagen Group Electronic Research
+ * Copyright (c) 2017 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -59,7 +59,7 @@
#include <net/net_namespace.h>
#include <net/sock.h>
-#define CAN_GW_VERSION "20130117"
+#define CAN_GW_VERSION "20170425"
#define CAN_GW_NAME "can-gw"
MODULE_DESCRIPTION("PF_CAN netlink gateway");
@@ -79,9 +79,7 @@ MODULE_PARM_DESC(max_hops,
__stringify(CGW_MAX_HOPS) " hops, "
"default: " __stringify(CGW_DEFAULT_HOPS) ")");
-static HLIST_HEAD(cgw_list);
static struct notifier_block notifier;
-
static struct kmem_cache *cgw_cache __read_mostly;
/* structure that contains the (on-the-fly) CAN frame modifications */
@@ -438,16 +436,16 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
gwj->handled_frames++;
}
-static inline int cgw_register_filter(struct cgw_job *gwj)
+static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj)
{
- return can_rx_register(&init_net, gwj->src.dev, gwj->ccgw.filter.can_id,
+ return can_rx_register(net, gwj->src.dev, gwj->ccgw.filter.can_id,
gwj->ccgw.filter.can_mask, can_can_gw_rcv,
gwj, "gw", NULL);
}
-static inline void cgw_unregister_filter(struct cgw_job *gwj)
+static inline void cgw_unregister_filter(struct net *net, struct cgw_job *gwj)
{
- can_rx_unregister(&init_net, gwj->src.dev, gwj->ccgw.filter.can_id,
+ can_rx_unregister(net, gwj->src.dev, gwj->ccgw.filter.can_id,
gwj->ccgw.filter.can_mask, can_can_gw_rcv, gwj);
}
@@ -455,9 +453,8 @@ static int cgw_notifier(struct notifier_block *nb,
unsigned long msg, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct net *net = dev_net(dev);
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
@@ -468,11 +465,11 @@ static int cgw_notifier(struct notifier_block *nb,
ASSERT_RTNL();
- hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) {
+ hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
if (gwj->src.dev == dev || gwj->dst.dev == dev) {
hlist_del(&gwj->list);
- cgw_unregister_filter(gwj);
+ cgw_unregister_filter(net, gwj);
kmem_cache_free(cgw_cache, gwj);
}
}
@@ -592,12 +589,13 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
/* Dump information about all CAN gateway jobs, in response to RTM_GETROUTE */
static int cgw_dump_jobs(struct sk_buff *skb, struct netlink_callback *cb)
{
+ struct net *net = sock_net(skb->sk);
struct cgw_job *gwj = NULL;
int idx = 0;
int s_idx = cb->args[0];
rcu_read_lock();
- hlist_for_each_entry_rcu(gwj, &cgw_list, list) {
+ hlist_for_each_entry_rcu(gwj, &net->can.cgw_list, list) {
if (idx < s_idx)
goto cont;
@@ -812,6 +810,7 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
+ struct net *net = sock_net(skb->sk);
struct rtcanmsg *r;
struct cgw_job *gwj;
struct cf_mod mod;
@@ -842,7 +841,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
ASSERT_RTNL();
/* check for updating an existing job with identical uid */
- hlist_for_each_entry(gwj, &cgw_list, list) {
+ hlist_for_each_entry(gwj, &net->can.cgw_list, list) {
if (gwj->mod.uid != mod.uid)
continue;
@@ -880,7 +879,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
err = -ENODEV;
- gwj->src.dev = __dev_get_by_index(&init_net, gwj->ccgw.src_idx);
+ gwj->src.dev = __dev_get_by_index(net, gwj->ccgw.src_idx);
if (!gwj->src.dev)
goto out;
@@ -888,7 +887,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
if (gwj->src.dev->type != ARPHRD_CAN)
goto out;
- gwj->dst.dev = __dev_get_by_index(&init_net, gwj->ccgw.dst_idx);
+ gwj->dst.dev = __dev_get_by_index(net, gwj->ccgw.dst_idx);
if (!gwj->dst.dev)
goto out;
@@ -898,9 +897,9 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
ASSERT_RTNL();
- err = cgw_register_filter(gwj);
+ err = cgw_register_filter(net, gwj);
if (!err)
- hlist_add_head_rcu(&gwj->list, &cgw_list);
+ hlist_add_head_rcu(&gwj->list, &net->can.cgw_list);
out:
if (err)
kmem_cache_free(cgw_cache, gwj);
@@ -908,16 +907,16 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
return err;
}
-static void cgw_remove_all_jobs(void)
+static void cgw_remove_all_jobs(struct net *net)
{
struct cgw_job *gwj = NULL;
struct hlist_node *nx;
ASSERT_RTNL();
- hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) {
+ hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
hlist_del(&gwj->list);
- cgw_unregister_filter(gwj);
+ cgw_unregister_filter(net, gwj);
kmem_cache_free(cgw_cache, gwj);
}
}
@@ -925,6 +924,7 @@ static void cgw_remove_all_jobs(void)
static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
+ struct net *net = sock_net(skb->sk);
struct cgw_job *gwj = NULL;
struct hlist_node *nx;
struct rtcanmsg *r;
@@ -953,7 +953,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
/* two interface indices both set to 0 => remove all entries */
if (!ccgw.src_idx && !ccgw.dst_idx) {
- cgw_remove_all_jobs();
+ cgw_remove_all_jobs(net);
return 0;
}
@@ -962,7 +962,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
ASSERT_RTNL();
/* remove only the first matching entry */
- hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) {
+ hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
if (gwj->flags != r->flags)
continue;
@@ -985,7 +985,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
continue;
hlist_del(&gwj->list);
- cgw_unregister_filter(gwj);
+ cgw_unregister_filter(net, gwj);
kmem_cache_free(cgw_cache, gwj);
err = 0;
break;
@@ -994,6 +994,24 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
return err;
}
+static int __net_init cangw_pernet_init(struct net *net)
+{
+ INIT_HLIST_HEAD(&net->can.cgw_list);
+ return 0;
+}
+
+static void __net_exit cangw_pernet_exit(struct net *net)
+{
+ rtnl_lock();
+ cgw_remove_all_jobs(net);
+ rtnl_unlock();
+}
+
+static struct pernet_operations cangw_pernet_ops = {
+ .init = cangw_pernet_init,
+ .exit = cangw_pernet_exit,
+};
+
static __init int cgw_module_init(void)
{
/* sanitize given module parameter */
@@ -1002,6 +1020,7 @@ static __init int cgw_module_init(void)
pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n",
max_hops);
+ register_pernet_subsys(&cangw_pernet_ops);
cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
0, 0, NULL);
@@ -1031,10 +1050,7 @@ static __exit void cgw_module_exit(void)
unregister_netdevice_notifier(¬ifier);
- rtnl_lock();
- cgw_remove_all_jobs();
- rtnl_unlock();
-
+ unregister_pernet_subsys(&cangw_pernet_ops);
rcu_barrier(); /* Wait for completion of call_rcu()'s */
kmem_cache_destroy(cgw_cache);
--
2.11.0
^ permalink raw reply related
* [PATCH 7/8] can: add Virtual CAN Tunnel driver (vxcan)
From: Oliver Hartkopp @ 2017-04-25 6:19 UTC (permalink / raw)
To: linux-can, davem; +Cc: Oliver Hartkopp, mkl, dev, netdev
In-Reply-To: <20170425061945.28722-1-socketcan@hartkopp.net>
Similar to the virtual ethernet driver veth, vxcan implements a
local CAN traffic tunnel between two virtual CAN network devices.
See Kconfig entry for details.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
drivers/net/can/Kconfig | 18 +++
drivers/net/can/Makefile | 1 +
drivers/net/can/vxcan.c | 316 +++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/can/vxcan.h | 12 ++
4 files changed, 347 insertions(+)
create mode 100644 drivers/net/can/vxcan.c
create mode 100644 include/uapi/linux/can/vxcan.h
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 22570ea3a8d2..61c2fcf7f880 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -9,6 +9,24 @@ config CAN_VCAN
This driver can also be built as a module. If so, the module
will be called vcan.
+config CAN_VXCAN
+ tristate "Virtual CAN Tunnel (vxcan)"
+ ---help---
+ Similar to the virtual ethernet driver veth, vxcan implements a
+ local CAN traffic tunnel between two virtual CAN network devices.
+ When creating a vxcan, two vxcan devices are created as pair.
+ When one end receives the packet it appears on its pair and vice
+ versa. The vxcan can be used for cross namespace communication.
+
+ In opposite to vcan loopback devices the vxcan only forwards CAN
+ frames to its pair and does *not* provide a local echo of sent
+ CAN frames. To disable a potential echo in af_can.c the vxcan driver
+ announces IFF_ECHO in the interface flags. To have a clean start
+ in each namespace the CAN GW hop counter is set to zero.
+
+ This driver can also be built as a module. If so, the module
+ will be called vxcan.
+
config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)"
depends on TTY
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 0da4f2f5c7e3..18cc6543b711 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_CAN_VCAN) += vcan.o
+obj-$(CONFIG_CAN_VXCAN) += vxcan.o
obj-$(CONFIG_CAN_SLCAN) += slcan.o
obj-$(CONFIG_CAN_DEV) += can-dev.o
diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c
new file mode 100644
index 000000000000..7fbb24795681
--- /dev/null
+++ b/drivers/net/can/vxcan.c
@@ -0,0 +1,316 @@
+/*
+ * vxcan.c - Virtual CAN Tunnel for cross namespace communication
+ *
+ * This code is derived from drivers/net/can/vcan.c for the virtual CAN
+ * specific parts and from drivers/net/veth.c to implement the netlink API
+ * for network interface pairs in a common and established way.
+ *
+ * Copyright (c) 2017 Oliver Hartkopp <socketcan@hartkopp.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/skb.h>
+#include <linux/can/vxcan.h>
+#include <linux/slab.h>
+#include <net/rtnetlink.h>
+
+#define DRV_NAME "vxcan"
+
+MODULE_DESCRIPTION("Virtual CAN Tunnel");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Oliver Hartkopp <socketcan@hartkopp.net>");
+MODULE_ALIAS_RTNL_LINK(DRV_NAME);
+
+struct vxcan_priv {
+ struct net_device __rcu *peer;
+};
+
+static netdev_tx_t vxcan_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct vxcan_priv *priv = netdev_priv(dev);
+ struct net_device *peer;
+ struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+ struct net_device_stats *peerstats, *srcstats = &dev->stats;
+
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
+
+ rcu_read_lock();
+ peer = rcu_dereference(priv->peer);
+ if (unlikely(!peer)) {
+ kfree_skb(skb);
+ dev->stats.tx_dropped++;
+ goto out_unlock;
+ }
+
+ skb = can_create_echo_skb(skb);
+ if (!skb)
+ goto out_unlock;
+
+ /* reset CAN GW hop counter */
+ skb->csum_start = 0;
+ skb->pkt_type = PACKET_BROADCAST;
+ skb->dev = peer;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ if (netif_rx_ni(skb) == NET_RX_SUCCESS) {
+ srcstats->tx_packets++;
+ srcstats->tx_bytes += cfd->len;
+ peerstats = &peer->stats;
+ peerstats->rx_packets++;
+ peerstats->rx_bytes += cfd->len;
+ }
+
+out_unlock:
+ rcu_read_unlock();
+ return NETDEV_TX_OK;
+}
+
+
+static int vxcan_open(struct net_device *dev)
+{
+ struct vxcan_priv *priv = netdev_priv(dev);
+ struct net_device *peer = rtnl_dereference(priv->peer);
+
+ if (!peer)
+ return -ENOTCONN;
+
+ if (peer->flags & IFF_UP) {
+ netif_carrier_on(dev);
+ netif_carrier_on(peer);
+ }
+ return 0;
+}
+
+static int vxcan_close(struct net_device *dev)
+{
+ struct vxcan_priv *priv = netdev_priv(dev);
+ struct net_device *peer = rtnl_dereference(priv->peer);
+
+ netif_carrier_off(dev);
+ if (peer)
+ netif_carrier_off(peer);
+
+ return 0;
+}
+
+static int vxcan_get_iflink(const struct net_device *dev)
+{
+ struct vxcan_priv *priv = netdev_priv(dev);
+ struct net_device *peer;
+ int iflink;
+
+ rcu_read_lock();
+ peer = rcu_dereference(priv->peer);
+ iflink = peer ? peer->ifindex : 0;
+ rcu_read_unlock();
+
+ return iflink;
+}
+
+static int vxcan_change_mtu(struct net_device *dev, int new_mtu)
+{
+ /* Do not allow changing the MTU while running */
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (new_mtu != CAN_MTU && new_mtu != CANFD_MTU)
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+static const struct net_device_ops vxcan_netdev_ops = {
+ .ndo_open = vxcan_open,
+ .ndo_stop = vxcan_close,
+ .ndo_start_xmit = vxcan_xmit,
+ .ndo_get_iflink = vxcan_get_iflink,
+ .ndo_change_mtu = vxcan_change_mtu,
+};
+
+static void vxcan_setup(struct net_device *dev)
+{
+ dev->type = ARPHRD_CAN;
+ dev->mtu = CAN_MTU;
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ dev->tx_queue_len = 0;
+ dev->flags = (IFF_NOARP|IFF_ECHO);
+ dev->netdev_ops = &vxcan_netdev_ops;
+ dev->destructor = free_netdev;
+}
+
+/* forward declaration for rtnl_create_link() */
+static struct rtnl_link_ops vxcan_link_ops;
+
+static int vxcan_newlink(struct net *net, struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ struct vxcan_priv *priv;
+ struct net_device *peer;
+ struct net *peer_net;
+
+ struct nlattr *peer_tb[IFLA_MAX + 1], **tbp = tb;
+ char ifname[IFNAMSIZ];
+ unsigned char name_assign_type;
+ struct ifinfomsg *ifmp = NULL;
+ int err;
+
+ /* register peer device */
+ if (data && data[VXCAN_INFO_PEER]) {
+ struct nlattr *nla_peer;
+
+ nla_peer = data[VXCAN_INFO_PEER];
+ ifmp = nla_data(nla_peer);
+ err = rtnl_nla_parse_ifla(peer_tb,
+ nla_data(nla_peer) +
+ sizeof(struct ifinfomsg),
+ nla_len(nla_peer) -
+ sizeof(struct ifinfomsg),
+ NULL);
+ if (err < 0)
+ return err;
+
+ tbp = peer_tb;
+ }
+
+ if (tbp[IFLA_IFNAME]) {
+ nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ);
+ name_assign_type = NET_NAME_USER;
+ } else {
+ snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d");
+ name_assign_type = NET_NAME_ENUM;
+ }
+
+ peer_net = rtnl_link_get_net(net, tbp);
+ if (IS_ERR(peer_net))
+ return PTR_ERR(peer_net);
+
+ peer = rtnl_create_link(peer_net, ifname, name_assign_type,
+ &vxcan_link_ops, tbp);
+ if (IS_ERR(peer)) {
+ put_net(peer_net);
+ return PTR_ERR(peer);
+ }
+
+ if (ifmp && dev->ifindex)
+ peer->ifindex = ifmp->ifi_index;
+
+ err = register_netdevice(peer);
+ put_net(peer_net);
+ peer_net = NULL;
+ if (err < 0) {
+ free_netdev(peer);
+ return err;
+ }
+
+ netif_carrier_off(peer);
+
+ err = rtnl_configure_link(peer, ifmp);
+ if (err < 0) {
+ unregister_netdevice(peer);
+ return err;
+ }
+
+ /* register first device */
+ if (tb[IFLA_IFNAME])
+ nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ);
+ else
+ snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d");
+
+ err = register_netdevice(dev);
+ if (err < 0) {
+ unregister_netdevice(peer);
+ return err;
+ }
+
+ netif_carrier_off(dev);
+
+ /* cross link the device pair */
+ priv = netdev_priv(dev);
+ rcu_assign_pointer(priv->peer, peer);
+
+ priv = netdev_priv(peer);
+ rcu_assign_pointer(priv->peer, dev);
+
+ return 0;
+}
+
+static void vxcan_dellink(struct net_device *dev, struct list_head *head)
+{
+ struct vxcan_priv *priv;
+ struct net_device *peer;
+
+ priv = netdev_priv(dev);
+ peer = rtnl_dereference(priv->peer);
+
+ /* Note : dellink() is called from default_device_exit_batch(),
+ * before a rcu_synchronize() point. The devices are guaranteed
+ * not being freed before one RCU grace period.
+ */
+ RCU_INIT_POINTER(priv->peer, NULL);
+ unregister_netdevice_queue(dev, head);
+
+ if (peer) {
+ priv = netdev_priv(peer);
+ RCU_INIT_POINTER(priv->peer, NULL);
+ unregister_netdevice_queue(peer, head);
+ }
+}
+
+static const struct nla_policy vxcan_policy[VXCAN_INFO_MAX + 1] = {
+ [VXCAN_INFO_PEER] = { .len = sizeof(struct ifinfomsg) },
+};
+
+static struct net *vxcan_get_link_net(const struct net_device *dev)
+{
+ struct vxcan_priv *priv = netdev_priv(dev);
+ struct net_device *peer = rtnl_dereference(priv->peer);
+
+ return peer ? dev_net(peer) : dev_net(dev);
+}
+
+static struct rtnl_link_ops vxcan_link_ops = {
+ .kind = DRV_NAME,
+ .priv_size = sizeof(struct vxcan_priv),
+ .setup = vxcan_setup,
+ .newlink = vxcan_newlink,
+ .dellink = vxcan_dellink,
+ .policy = vxcan_policy,
+ .maxtype = VXCAN_INFO_MAX,
+ .get_link_net = vxcan_get_link_net,
+};
+
+static __init int vxcan_init(void)
+{
+ pr_info("vxcan: Virtual CAN Tunnel driver\n");
+
+ return rtnl_link_register(&vxcan_link_ops);
+}
+
+static __exit void vxcan_exit(void)
+{
+ rtnl_link_unregister(&vxcan_link_ops);
+}
+
+module_init(vxcan_init);
+module_exit(vxcan_exit);
diff --git a/include/uapi/linux/can/vxcan.h b/include/uapi/linux/can/vxcan.h
new file mode 100644
index 000000000000..ffb0b7156f7e
--- /dev/null
+++ b/include/uapi/linux/can/vxcan.h
@@ -0,0 +1,12 @@
+#ifndef _UAPI_CAN_VXCAN_H
+#define _UAPI_CAN_VXCAN_H
+
+enum {
+ VXCAN_INFO_UNSPEC,
+ VXCAN_INFO_PEER,
+
+ __VXCAN_INFO_MAX
+#define VXCAN_INFO_MAX (__VXCAN_INFO_MAX - 1)
+};
+
+#endif
--
2.11.0
^ permalink raw reply related
* [PATCH 8/8] can: enable module auto loading for virtual CAN interfaces
From: Oliver Hartkopp @ 2017-04-25 6:19 UTC (permalink / raw)
To: linux-can, davem; +Cc: Oliver Hartkopp, mkl, dev, netdev
In-Reply-To: <20170425061945.28722-1-socketcan@hartkopp.net>
Autoload the vcan module when a vcan instance is to be created by
'ip link add type vcan'
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
drivers/net/can/vcan.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index 674f367087c5..facca33d53e9 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -1,7 +1,7 @@
/*
* vcan.c - Virtual CAN interface
*
- * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * Copyright (c) 2002-2017 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,9 +50,12 @@
#include <linux/slab.h>
#include <net/rtnetlink.h>
+#define DRV_NAME "vcan"
+
MODULE_DESCRIPTION("virtual CAN interface");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
+MODULE_ALIAS_RTNL_LINK(DRV_NAME);
/*
@@ -164,7 +167,7 @@ static void vcan_setup(struct net_device *dev)
}
static struct rtnl_link_ops vcan_link_ops __read_mostly = {
- .kind = "vcan",
+ .kind = DRV_NAME,
.setup = vcan_setup,
};
--
2.11.0
^ permalink raw reply related
* [PATCH 4/8] can: complete initial namespace support
From: Oliver Hartkopp @ 2017-04-25 6:19 UTC (permalink / raw)
To: linux-can, davem; +Cc: Oliver Hartkopp, mkl, dev, netdev
In-Reply-To: <20170425061945.28722-1-socketcan@hartkopp.net>
The statistics and its proc output was not implemented as per-net in the
initial network namespace support by Mario Kicherer (8e8cda6d737d).
This patch adds the missing per-net statistics for the CAN subsystem.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
include/linux/can/core.h | 4 +-
include/net/netns/can.h | 5 ++
net/can/af_can.c | 71 +++++++++++++-----------
net/can/af_can.h | 5 --
net/can/proc.c | 141 +++++++++++++++++++++++++----------------------
5 files changed, 121 insertions(+), 105 deletions(-)
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index 319a0da827b8..c9a17bb1221c 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -5,7 +5,7 @@
*
* Authors: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
* Urs Thuermann <urs.thuermann@volkswagen.de>
- * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * Copyright (c) 2002-2017 Volkswagen Group Electronic Research
* All rights reserved.
*
*/
@@ -17,7 +17,7 @@
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#define CAN_VERSION "20120528"
+#define CAN_VERSION "20170425"
/* increment this number each time you change some user-space interface */
#define CAN_ABI_VERSION "9"
diff --git a/include/net/netns/can.h b/include/net/netns/can.h
index e8beba772f1a..574157dbc43a 100644
--- a/include/net/netns/can.h
+++ b/include/net/netns/can.h
@@ -8,6 +8,8 @@
#include <linux/spinlock.h>
struct dev_rcv_lists;
+struct s_stats;
+struct s_pstats;
struct netns_can {
#if IS_ENABLED(CONFIG_PROC_FS)
@@ -26,6 +28,9 @@ struct netns_can {
/* receive filters subscribed for 'all' CAN devices */
struct dev_rcv_lists *can_rx_alldev_list;
spinlock_t can_rcvlists_lock;
+ struct timer_list can_stattimer;/* timer for statistics update */
+ struct s_stats *can_stats; /* packet statistics */
+ struct s_pstats *can_pstats; /* receive list statistics */
};
#endif /* __NETNS_CAN_H__ */
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 421b60fc42c3..b6406fe33c76 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -2,7 +2,7 @@
* af_can.c - Protocol family CAN core module
* (used by different CAN protocol modules)
*
- * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * Copyright (c) 2002-2017 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -81,10 +81,6 @@ static struct kmem_cache *rcv_cache __read_mostly;
static const struct can_proto *proto_tab[CAN_NPROTO] __read_mostly;
static DEFINE_MUTEX(proto_tab_lock);
-struct timer_list can_stattimer; /* timer for statistics update */
-struct s_stats can_stats; /* packet statistics */
-struct s_pstats can_pstats; /* receive list statistics */
-
static atomic_t skbcounter = ATOMIC_INIT(0);
/*
@@ -221,6 +217,7 @@ int can_send(struct sk_buff *skb, int loop)
{
struct sk_buff *newskb = NULL;
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+ struct s_stats *can_stats = dev_net(skb->dev)->can.can_stats;
int err = -EINVAL;
if (skb->len == CAN_MTU) {
@@ -309,8 +306,8 @@ int can_send(struct sk_buff *skb, int loop)
netif_rx_ni(newskb);
/* update statistics */
- can_stats.tx_frames++;
- can_stats.tx_frames_delta++;
+ can_stats->tx_frames++;
+ can_stats->tx_frames_delta++;
return 0;
@@ -468,6 +465,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
struct receiver *r;
struct hlist_head *rl;
struct dev_rcv_lists *d;
+ struct s_pstats *can_pstats = net->can.can_pstats;
int err = 0;
/* insert new receiver (dev,canid,mask) -> (func,data) */
@@ -499,9 +497,9 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
hlist_add_head_rcu(&r->list, rl);
d->entries++;
- can_pstats.rcv_entries++;
- if (can_pstats.rcv_entries_max < can_pstats.rcv_entries)
- can_pstats.rcv_entries_max = can_pstats.rcv_entries;
+ can_pstats->rcv_entries++;
+ if (can_pstats->rcv_entries_max < can_pstats->rcv_entries)
+ can_pstats->rcv_entries_max = can_pstats->rcv_entries;
} else {
kmem_cache_free(rcv_cache, r);
err = -ENODEV;
@@ -543,6 +541,7 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
{
struct receiver *r = NULL;
struct hlist_head *rl;
+ struct s_pstats *can_pstats = net->can.can_pstats;
struct dev_rcv_lists *d;
if (dev && dev->type != ARPHRD_CAN)
@@ -589,8 +588,8 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
hlist_del_rcu(&r->list);
d->entries--;
- if (can_pstats.rcv_entries > 0)
- can_pstats.rcv_entries--;
+ if (can_pstats->rcv_entries > 0)
+ can_pstats->rcv_entries--;
/* remove device structure requested by NETDEV_UNREGISTER */
if (d->remove_on_zero_entries && !d->entries) {
@@ -684,11 +683,13 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
static void can_receive(struct sk_buff *skb, struct net_device *dev)
{
struct dev_rcv_lists *d;
+ struct net *net = dev_net(dev);
+ struct s_stats *can_stats = net->can.can_stats;
int matches;
/* update statistics */
- can_stats.rx_frames++;
- can_stats.rx_frames_delta++;
+ can_stats->rx_frames++;
+ can_stats->rx_frames_delta++;
/* create non-zero unique skb identifier together with *skb */
while (!(can_skb_prv(skb)->skbcnt))
@@ -697,10 +698,10 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
rcu_read_lock();
/* deliver the packet to sockets listening on all devices */
- matches = can_rcv_filter(dev_net(dev)->can.can_rx_alldev_list, skb);
+ matches = can_rcv_filter(net->can.can_rx_alldev_list, skb);
/* find receive list for this device */
- d = find_dev_rcv_lists(dev_net(dev), dev);
+ d = find_dev_rcv_lists(net, dev);
if (d)
matches += can_rcv_filter(d, skb);
@@ -710,8 +711,8 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
consume_skb(skb);
if (matches > 0) {
- can_stats.matches++;
- can_stats.matches_delta++;
+ can_stats->matches++;
+ can_stats->matches_delta++;
}
}
@@ -876,8 +877,20 @@ static int can_pernet_init(struct net *net)
net->can.can_rx_alldev_list =
kzalloc(sizeof(struct dev_rcv_lists), GFP_KERNEL);
- if (IS_ENABLED(CONFIG_PROC_FS))
+ net->can.can_stats = kzalloc(sizeof(struct s_stats), GFP_KERNEL);
+ net->can.can_pstats = kzalloc(sizeof(struct s_pstats), GFP_KERNEL);
+
+ if (IS_ENABLED(CONFIG_PROC_FS)) {
+ /* the statistics are updated every second (timer triggered) */
+ if (stats_timer) {
+ setup_timer(&net->can.can_stattimer, can_stat_update,
+ (unsigned long)net);
+ mod_timer(&net->can.can_stattimer,
+ round_jiffies(jiffies + HZ));
+ }
+ net->can.can_stats->jiffies_init = jiffies;
can_init_proc(net);
+ }
return 0;
}
@@ -886,8 +899,11 @@ static void can_pernet_exit(struct net *net)
{
struct net_device *dev;
- if (IS_ENABLED(CONFIG_PROC_FS))
+ if (IS_ENABLED(CONFIG_PROC_FS)) {
can_remove_proc(net);
+ if (stats_timer)
+ del_timer_sync(&net->can.can_stattimer);
+ }
/* remove created dev_rcv_lists from still registered CAN devices */
rcu_read_lock();
@@ -903,6 +919,8 @@ static void can_pernet_exit(struct net *net)
rcu_read_unlock();
kfree(net->can.can_rx_alldev_list);
+ kfree(net->can.can_stats);
+ kfree(net->can.can_pstats);
}
/*
@@ -950,14 +968,6 @@ static __init int can_init(void)
if (!rcv_cache)
return -ENOMEM;
- if (IS_ENABLED(CONFIG_PROC_FS)) {
- if (stats_timer) {
- /* the statistics are updated every second (timer triggered) */
- setup_timer(&can_stattimer, can_stat_update, 0);
- mod_timer(&can_stattimer, round_jiffies(jiffies + HZ));
- }
- }
-
register_pernet_subsys(&can_pernet_ops);
/* protocol register */
@@ -971,11 +981,6 @@ static __init int can_init(void)
static __exit void can_exit(void)
{
- if (IS_ENABLED(CONFIG_PROC_FS)) {
- if (stats_timer)
- del_timer_sync(&can_stattimer);
- }
-
/* protocol unregister */
dev_remove_pack(&canfd_packet);
dev_remove_pack(&can_packet);
diff --git a/net/can/af_can.h b/net/can/af_can.h
index 84a35e97c5e0..d0ef45bb2a72 100644
--- a/net/can/af_can.h
+++ b/net/can/af_can.h
@@ -115,9 +115,4 @@ void can_init_proc(struct net *net);
void can_remove_proc(struct net *net);
void can_stat_update(unsigned long data);
-/* structures and variables from af_can.c needed in proc.c for reading */
-extern struct timer_list can_stattimer; /* timer for statistics update */
-extern struct s_stats can_stats; /* packet statistics */
-extern struct s_pstats can_pstats; /* receive list statistics */
-
#endif /* AF_CAN_H */
diff --git a/net/can/proc.c b/net/can/proc.c
index 9a8d54d57b22..83045f00c63c 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -75,21 +75,23 @@ static const char rx_list_name[][8] = {
* af_can statistics stuff
*/
-static void can_init_stats(void)
+static void can_init_stats(struct net *net)
{
+ struct s_stats *can_stats = net->can.can_stats;
+ struct s_pstats *can_pstats = net->can.can_pstats;
/*
* This memset function is called from a timer context (when
* can_stattimer is active which is the default) OR in a process
* context (reading the proc_fs when can_stattimer is disabled).
*/
- memset(&can_stats, 0, sizeof(can_stats));
- can_stats.jiffies_init = jiffies;
+ memset(can_stats, 0, sizeof(struct s_stats));
+ can_stats->jiffies_init = jiffies;
- can_pstats.stats_reset++;
+ can_pstats->stats_reset++;
if (user_reset) {
user_reset = 0;
- can_pstats.user_reset++;
+ can_pstats->user_reset++;
}
}
@@ -115,64 +117,66 @@ static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif,
void can_stat_update(unsigned long data)
{
+ struct net *net = (struct net *)data;
+ struct s_stats *can_stats = net->can.can_stats;
unsigned long j = jiffies; /* snapshot */
/* restart counting in timer context on user request */
if (user_reset)
- can_init_stats();
+ can_init_stats(net);
/* restart counting on jiffies overflow */
- if (j < can_stats.jiffies_init)
- can_init_stats();
+ if (j < can_stats->jiffies_init)
+ can_init_stats(net);
/* prevent overflow in calc_rate() */
- if (can_stats.rx_frames > (ULONG_MAX / HZ))
- can_init_stats();
+ if (can_stats->rx_frames > (ULONG_MAX / HZ))
+ can_init_stats(net);
/* prevent overflow in calc_rate() */
- if (can_stats.tx_frames > (ULONG_MAX / HZ))
- can_init_stats();
+ if (can_stats->tx_frames > (ULONG_MAX / HZ))
+ can_init_stats(net);
/* matches overflow - very improbable */
- if (can_stats.matches > (ULONG_MAX / 100))
- can_init_stats();
+ if (can_stats->matches > (ULONG_MAX / 100))
+ can_init_stats(net);
/* calc total values */
- if (can_stats.rx_frames)
- can_stats.total_rx_match_ratio = (can_stats.matches * 100) /
- can_stats.rx_frames;
+ if (can_stats->rx_frames)
+ can_stats->total_rx_match_ratio = (can_stats->matches * 100) /
+ can_stats->rx_frames;
- can_stats.total_tx_rate = calc_rate(can_stats.jiffies_init, j,
- can_stats.tx_frames);
- can_stats.total_rx_rate = calc_rate(can_stats.jiffies_init, j,
- can_stats.rx_frames);
+ can_stats->total_tx_rate = calc_rate(can_stats->jiffies_init, j,
+ can_stats->tx_frames);
+ can_stats->total_rx_rate = calc_rate(can_stats->jiffies_init, j,
+ can_stats->rx_frames);
/* calc current values */
- if (can_stats.rx_frames_delta)
- can_stats.current_rx_match_ratio =
- (can_stats.matches_delta * 100) /
- can_stats.rx_frames_delta;
+ if (can_stats->rx_frames_delta)
+ can_stats->current_rx_match_ratio =
+ (can_stats->matches_delta * 100) /
+ can_stats->rx_frames_delta;
- can_stats.current_tx_rate = calc_rate(0, HZ, can_stats.tx_frames_delta);
- can_stats.current_rx_rate = calc_rate(0, HZ, can_stats.rx_frames_delta);
+ can_stats->current_tx_rate = calc_rate(0, HZ, can_stats->tx_frames_delta);
+ can_stats->current_rx_rate = calc_rate(0, HZ, can_stats->rx_frames_delta);
/* check / update maximum values */
- if (can_stats.max_tx_rate < can_stats.current_tx_rate)
- can_stats.max_tx_rate = can_stats.current_tx_rate;
+ if (can_stats->max_tx_rate < can_stats->current_tx_rate)
+ can_stats->max_tx_rate = can_stats->current_tx_rate;
- if (can_stats.max_rx_rate < can_stats.current_rx_rate)
- can_stats.max_rx_rate = can_stats.current_rx_rate;
+ if (can_stats->max_rx_rate < can_stats->current_rx_rate)
+ can_stats->max_rx_rate = can_stats->current_rx_rate;
- if (can_stats.max_rx_match_ratio < can_stats.current_rx_match_ratio)
- can_stats.max_rx_match_ratio = can_stats.current_rx_match_ratio;
+ if (can_stats->max_rx_match_ratio < can_stats->current_rx_match_ratio)
+ can_stats->max_rx_match_ratio = can_stats->current_rx_match_ratio;
/* clear values for 'current rate' calculation */
- can_stats.tx_frames_delta = 0;
- can_stats.rx_frames_delta = 0;
- can_stats.matches_delta = 0;
+ can_stats->tx_frames_delta = 0;
+ can_stats->rx_frames_delta = 0;
+ can_stats->matches_delta = 0;
/* restart timer (one second) */
- mod_timer(&can_stattimer, round_jiffies(jiffies + HZ));
+ mod_timer(&net->can.can_stattimer, round_jiffies(jiffies + HZ));
}
/*
@@ -206,57 +210,61 @@ static void can_print_recv_banner(struct seq_file *m)
static int can_stats_proc_show(struct seq_file *m, void *v)
{
+ struct net *net = m->private;
+ struct s_stats *can_stats = net->can.can_stats;
+ struct s_pstats *can_pstats = net->can.can_pstats;
+
seq_putc(m, '\n');
- seq_printf(m, " %8ld transmitted frames (TXF)\n", can_stats.tx_frames);
- seq_printf(m, " %8ld received frames (RXF)\n", can_stats.rx_frames);
- seq_printf(m, " %8ld matched frames (RXMF)\n", can_stats.matches);
+ seq_printf(m, " %8ld transmitted frames (TXF)\n", can_stats->tx_frames);
+ seq_printf(m, " %8ld received frames (RXF)\n", can_stats->rx_frames);
+ seq_printf(m, " %8ld matched frames (RXMF)\n", can_stats->matches);
seq_putc(m, '\n');
- if (can_stattimer.function == can_stat_update) {
+ if (net->can.can_stattimer.function == can_stat_update) {
seq_printf(m, " %8ld %% total match ratio (RXMR)\n",
- can_stats.total_rx_match_ratio);
+ can_stats->total_rx_match_ratio);
seq_printf(m, " %8ld frames/s total tx rate (TXR)\n",
- can_stats.total_tx_rate);
+ can_stats->total_tx_rate);
seq_printf(m, " %8ld frames/s total rx rate (RXR)\n",
- can_stats.total_rx_rate);
+ can_stats->total_rx_rate);
seq_putc(m, '\n');
seq_printf(m, " %8ld %% current match ratio (CRXMR)\n",
- can_stats.current_rx_match_ratio);
+ can_stats->current_rx_match_ratio);
seq_printf(m, " %8ld frames/s current tx rate (CTXR)\n",
- can_stats.current_tx_rate);
+ can_stats->current_tx_rate);
seq_printf(m, " %8ld frames/s current rx rate (CRXR)\n",
- can_stats.current_rx_rate);
+ can_stats->current_rx_rate);
seq_putc(m, '\n');
seq_printf(m, " %8ld %% max match ratio (MRXMR)\n",
- can_stats.max_rx_match_ratio);
+ can_stats->max_rx_match_ratio);
seq_printf(m, " %8ld frames/s max tx rate (MTXR)\n",
- can_stats.max_tx_rate);
+ can_stats->max_tx_rate);
seq_printf(m, " %8ld frames/s max rx rate (MRXR)\n",
- can_stats.max_rx_rate);
+ can_stats->max_rx_rate);
seq_putc(m, '\n');
}
seq_printf(m, " %8ld current receive list entries (CRCV)\n",
- can_pstats.rcv_entries);
+ can_pstats->rcv_entries);
seq_printf(m, " %8ld maximum receive list entries (MRCV)\n",
- can_pstats.rcv_entries_max);
+ can_pstats->rcv_entries_max);
- if (can_pstats.stats_reset)
+ if (can_pstats->stats_reset)
seq_printf(m, "\n %8ld statistic resets (STR)\n",
- can_pstats.stats_reset);
+ can_pstats->stats_reset);
- if (can_pstats.user_reset)
+ if (can_pstats->user_reset)
seq_printf(m, " %8ld user statistic resets (USTR)\n",
- can_pstats.user_reset);
+ can_pstats->user_reset);
seq_putc(m, '\n');
return 0;
@@ -264,7 +272,7 @@ static int can_stats_proc_show(struct seq_file *m, void *v)
static int can_stats_proc_open(struct inode *inode, struct file *file)
{
- return single_open(file, can_stats_proc_show, NULL);
+ return single_open_net(inode, file, can_stats_proc_show);
}
static const struct file_operations can_stats_proc_fops = {
@@ -277,25 +285,28 @@ static const struct file_operations can_stats_proc_fops = {
static int can_reset_stats_proc_show(struct seq_file *m, void *v)
{
+ struct net *net = m->private;
+ struct s_pstats *can_pstats = net->can.can_pstats;
+ struct s_stats *can_stats = net->can.can_stats;
+
user_reset = 1;
- if (can_stattimer.function == can_stat_update) {
+ if (net->can.can_stattimer.function == can_stat_update) {
seq_printf(m, "Scheduled statistic reset #%ld.\n",
- can_pstats.stats_reset + 1);
-
+ can_pstats->stats_reset + 1);
} else {
- if (can_stats.jiffies_init != jiffies)
- can_init_stats();
+ if (can_stats->jiffies_init != jiffies)
+ can_init_stats(net);
seq_printf(m, "Performed statistic reset #%ld.\n",
- can_pstats.stats_reset);
+ can_pstats->stats_reset);
}
return 0;
}
static int can_reset_stats_proc_open(struct inode *inode, struct file *file)
{
- return single_open(file, can_reset_stats_proc_show, NULL);
+ return single_open_net(inode, file, can_reset_stats_proc_show);
}
static const struct file_operations can_reset_stats_proc_fops = {
@@ -314,7 +325,7 @@ static int can_version_proc_show(struct seq_file *m, void *v)
static int can_version_proc_open(struct inode *inode, struct file *file)
{
- return single_open(file, can_version_proc_show, NULL);
+ return single_open_net(inode, file, can_version_proc_show);
}
static const struct file_operations can_version_proc_fops = {
--
2.11.0
^ permalink raw reply related
* [PATCH 5/8] can: network namespace support for CAN_BCM protocol
From: Oliver Hartkopp @ 2017-04-25 6:19 UTC (permalink / raw)
To: linux-can, davem; +Cc: Oliver Hartkopp, mkl, dev, netdev
In-Reply-To: <20170425061945.28722-1-socketcan@hartkopp.net>
The CAN_BCM protocol and its procfs entries were not implemented as per-net
in the initial network namespace support by Mario Kicherer (8e8cda6d737d).
This patch adds the missing per-net functionality for the CAN BCM.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
include/net/netns/can.h | 1 +
net/can/bcm.c | 90 +++++++++++++++++++++++++++++++------------------
2 files changed, 58 insertions(+), 33 deletions(-)
diff --git a/include/net/netns/can.h b/include/net/netns/can.h
index 574157dbc43a..0f3c31aab8a8 100644
--- a/include/net/netns/can.h
+++ b/include/net/netns/can.h
@@ -23,6 +23,7 @@ struct netns_can {
struct proc_dir_entry *pde_rcvlist_sff;
struct proc_dir_entry *pde_rcvlist_eff;
struct proc_dir_entry *pde_rcvlist_err;
+ struct proc_dir_entry *bcmproc_dir;
#endif
/* receive filters subscribed for 'all' CAN devices */
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 1976629a8463..0e855917b7e1 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1,7 +1,7 @@
/*
* bcm.c - Broadcast Manager to filter/send (cyclic) CAN content
*
- * Copyright (c) 2002-2016 Volkswagen Group Electronic Research
+ * Copyright (c) 2002-2017 Volkswagen Group Electronic Research
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,7 +77,7 @@
(CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG) : \
(CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG))
-#define CAN_BCM_VERSION "20161123"
+#define CAN_BCM_VERSION "20170425"
MODULE_DESCRIPTION("PF_CAN broadcast manager protocol");
MODULE_LICENSE("Dual BSD/GPL");
@@ -118,8 +118,6 @@ struct bcm_op {
struct net_device *rx_reg_dev;
};
-static struct proc_dir_entry *proc_dir;
-
struct bcm_sock {
struct sock sk;
int bound;
@@ -149,7 +147,7 @@ static inline ktime_t bcm_timeval_to_ktime(struct bcm_timeval tv)
/*
* procfs functions
*/
-static char *bcm_proc_getifname(char *result, int ifindex)
+static char *bcm_proc_getifname(struct net *net, char *result, int ifindex)
{
struct net_device *dev;
@@ -157,7 +155,7 @@ static char *bcm_proc_getifname(char *result, int ifindex)
return "any";
rcu_read_lock();
- dev = dev_get_by_index_rcu(&init_net, ifindex);
+ dev = dev_get_by_index_rcu(net, ifindex);
if (dev)
strcpy(result, dev->name);
else
@@ -170,7 +168,8 @@ static char *bcm_proc_getifname(char *result, int ifindex)
static int bcm_proc_show(struct seq_file *m, void *v)
{
char ifname[IFNAMSIZ];
- struct sock *sk = (struct sock *)m->private;
+ struct net *net = m->private;
+ struct sock *sk = (struct sock *)PDE_DATA(m->file->f_inode);
struct bcm_sock *bo = bcm_sk(sk);
struct bcm_op *op;
@@ -178,7 +177,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
seq_printf(m, " / sk %pK", sk);
seq_printf(m, " / bo %pK", bo);
seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs);
- seq_printf(m, " / bound %s", bcm_proc_getifname(ifname, bo->ifindex));
+ seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex));
seq_printf(m, " <<<\n");
list_for_each_entry(op, &bo->rx_ops, list) {
@@ -190,7 +189,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
continue;
seq_printf(m, "rx_op: %03X %-5s ", op->can_id,
- bcm_proc_getifname(ifname, op->ifindex));
+ bcm_proc_getifname(net, ifname, op->ifindex));
if (op->flags & CAN_FD_FRAME)
seq_printf(m, "(%u)", op->nframes);
@@ -219,7 +218,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
list_for_each_entry(op, &bo->tx_ops, list) {
seq_printf(m, "tx_op: %03X %s ", op->can_id,
- bcm_proc_getifname(ifname, op->ifindex));
+ bcm_proc_getifname(net, ifname, op->ifindex));
if (op->flags & CAN_FD_FRAME)
seq_printf(m, "(%u) ", op->nframes);
@@ -242,7 +241,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
static int bcm_proc_open(struct inode *inode, struct file *file)
{
- return single_open(file, bcm_proc_show, PDE_DATA(inode));
+ return single_open_net(inode, file, bcm_proc_show);
}
static const struct file_operations bcm_proc_fops = {
@@ -267,7 +266,7 @@ static void bcm_can_tx(struct bcm_op *op)
if (!op->ifindex)
return;
- dev = dev_get_by_index(&init_net, op->ifindex);
+ dev = dev_get_by_index(sock_net(op->sk), op->ifindex);
if (!dev) {
/* RFC: should this bcm_op remove itself here? */
return;
@@ -764,7 +763,7 @@ static void bcm_remove_op(struct bcm_op *op)
static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
{
if (op->rx_reg_dev == dev) {
- can_rx_unregister(&init_net, dev, op->can_id,
+ can_rx_unregister(dev_net(dev), dev, op->can_id,
REGMASK(op->can_id), bcm_rx_handler, op);
/* mark as removed subscription */
@@ -800,7 +799,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
if (op->rx_reg_dev) {
struct net_device *dev;
- dev = dev_get_by_index(&init_net,
+ dev = dev_get_by_index(sock_net(op->sk),
op->ifindex);
if (dev) {
bcm_rx_unreg(dev, op);
@@ -808,7 +807,8 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
}
}
} else
- can_rx_unregister(&init_net, NULL, op->can_id,
+ can_rx_unregister(sock_net(op->sk), NULL,
+ op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op);
@@ -1220,9 +1220,9 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
if (ifindex) {
struct net_device *dev;
- dev = dev_get_by_index(&init_net, ifindex);
+ dev = dev_get_by_index(sock_net(sk), ifindex);
if (dev) {
- err = can_rx_register(&init_net, dev,
+ err = can_rx_register(sock_net(sk), dev,
op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op,
@@ -1233,7 +1233,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
}
} else
- err = can_rx_register(&init_net, NULL, op->can_id,
+ err = can_rx_register(sock_net(sk), NULL, op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op, "bcm", sk);
if (err) {
@@ -1273,7 +1273,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk,
return err;
}
- dev = dev_get_by_index(&init_net, ifindex);
+ dev = dev_get_by_index(sock_net(sk), ifindex);
if (!dev) {
kfree_skb(skb);
return -ENODEV;
@@ -1338,7 +1338,7 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
if (ifindex) {
struct net_device *dev;
- dev = dev_get_by_index(&init_net, ifindex);
+ dev = dev_get_by_index(sock_net(sk), ifindex);
if (!dev)
return -ENODEV;
@@ -1419,7 +1419,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
struct bcm_op *op;
int notify_enodev = 0;
- if (!net_eq(dev_net(dev), &init_net))
+ if (!net_eq(dev_net(dev), sock_net(sk)))
return NOTIFY_DONE;
if (dev->type != ARPHRD_CAN)
@@ -1491,6 +1491,7 @@ static int bcm_init(struct sock *sk)
static int bcm_release(struct socket *sock)
{
struct sock *sk = sock->sk;
+ struct net *net = sock_net(sk);
struct bcm_sock *bo;
struct bcm_op *op, *next;
@@ -1522,14 +1523,14 @@ static int bcm_release(struct socket *sock)
if (op->rx_reg_dev) {
struct net_device *dev;
- dev = dev_get_by_index(&init_net, op->ifindex);
+ dev = dev_get_by_index(net, op->ifindex);
if (dev) {
bcm_rx_unreg(dev, op);
dev_put(dev);
}
}
} else
- can_rx_unregister(&init_net, NULL, op->can_id,
+ can_rx_unregister(net, NULL, op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op);
@@ -1537,8 +1538,8 @@ static int bcm_release(struct socket *sock)
}
/* remove procfs entry */
- if (proc_dir && bo->bcm_proc_read)
- remove_proc_entry(bo->procname, proc_dir);
+ if (net->can.bcmproc_dir && bo->bcm_proc_read)
+ remove_proc_entry(bo->procname, net->can.bcmproc_dir);
/* remove device reference */
if (bo->bound) {
@@ -1561,6 +1562,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
struct sock *sk = sock->sk;
struct bcm_sock *bo = bcm_sk(sk);
+ struct net *net = sock_net(sk);
int ret = 0;
if (len < sizeof(*addr))
@@ -1577,7 +1579,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
if (addr->can_ifindex) {
struct net_device *dev;
- dev = dev_get_by_index(&init_net, addr->can_ifindex);
+ dev = dev_get_by_index(net, addr->can_ifindex);
if (!dev) {
ret = -ENODEV;
goto fail;
@@ -1596,11 +1598,11 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
bo->ifindex = 0;
}
- if (proc_dir) {
+ if (net->can.bcmproc_dir) {
/* unique socket address as filename */
sprintf(bo->procname, "%lu", sock_i_ino(sk));
bo->bcm_proc_read = proc_create_data(bo->procname, 0644,
- proc_dir,
+ net->can.bcmproc_dir,
&bcm_proc_fops, sk);
if (!bo->bcm_proc_read) {
ret = -ENOMEM;
@@ -1687,6 +1689,31 @@ static const struct can_proto bcm_can_proto = {
.prot = &bcm_proto,
};
+static int canbcm_pernet_init(struct net *net)
+{
+ /* create /proc/net/can-bcm directory */
+ if (IS_ENABLED(CONFIG_PROC_FS)) {
+ net->can.bcmproc_dir =
+ proc_net_mkdir(net, "can-bcm", net->proc_net);
+ }
+
+ return 0;
+}
+
+static void canbcm_pernet_exit(struct net *net)
+{
+ /* remove /proc/net/can-bcm directory */
+ if (IS_ENABLED(CONFIG_PROC_FS)) {
+ if (net->can.bcmproc_dir)
+ remove_proc_entry("can-bcm", net->proc_net);
+ }
+}
+
+static struct pernet_operations canbcm_pernet_ops __read_mostly = {
+ .init = canbcm_pernet_init,
+ .exit = canbcm_pernet_exit,
+};
+
static int __init bcm_module_init(void)
{
int err;
@@ -1699,17 +1726,14 @@ static int __init bcm_module_init(void)
return err;
}
- /* create /proc/net/can-bcm directory */
- proc_dir = proc_mkdir("can-bcm", init_net.proc_net);
+ register_pernet_subsys(&canbcm_pernet_ops);
return 0;
}
static void __exit bcm_module_exit(void)
{
can_proto_unregister(&bcm_can_proto);
-
- if (proc_dir)
- remove_proc_entry("can-bcm", init_net.proc_net);
+ unregister_pernet_subsys(&canbcm_pernet_ops);
}
module_init(bcm_module_init);
--
2.11.0
^ permalink raw reply related
* [PATCH net-next] can: ti_hecc: fix return value check in ti_hecc_probe()
From: Wei Yongjun @ 2017-04-25 6:44 UTC (permalink / raw)
To: Wolfgang Grandegger, Marc Kleine-Budde, Anton Glukhov,
Yegor Yefremov
Cc: Wei Yongjun, linux-can, netdev
From: Wei Yongjun <weiyongjun1@huawei.com>
In case of error, the function devm_ioremap_resource() returns ERR_PTR()
and never returns NULL. The NULL test in the return value check should
be replaced with IS_ERR().
Fixes: dabf54dd1c63 ("can: ti_hecc: Convert TI HECC driver to DT only driver")
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
---
drivers/net/can/ti_hecc.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index b8aac53..4d49414 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -898,9 +898,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
}
priv->base = devm_ioremap_resource(&pdev->dev, res);
- if (!priv->base) {
+ if (IS_ERR(priv->base)) {
dev_err(&pdev->dev, "hecc ioremap failed\n");
- return -ENOMEM;
+ return PTR_ERR(priv->base);
}
/* handle hecc-ram memory */
@@ -911,9 +911,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
}
priv->hecc_ram = devm_ioremap_resource(&pdev->dev, res);
- if (!priv->hecc_ram) {
+ if (IS_ERR(priv->hecc_ram)) {
dev_err(&pdev->dev, "hecc-ram ioremap failed\n");
- return -ENOMEM;
+ return PTR_ERR(priv->hecc_ram);
}
/* handle mbx memory */
@@ -924,9 +924,9 @@ static int ti_hecc_probe(struct platform_device *pdev)
}
priv->mbx = devm_ioremap_resource(&pdev->dev, res);
- if (!priv->mbx) {
+ if (IS_ERR(priv->mbx)) {
dev_err(&pdev->dev, "mbx ioremap failed\n");
- return -ENOMEM;
+ return PTR_ERR(priv->mbx);
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
^ permalink raw reply related
* Re: [PATCH 0/8] Fix and complete CAN namespace support
From: Marc Kleine-Budde @ 2017-04-25 6:48 UTC (permalink / raw)
To: Oliver Hartkopp, linux-can, davem; +Cc: dev, netdev
In-Reply-To: <20170425061945.28722-1-socketcan@hartkopp.net>
[-- Attachment #1.1: Type: text/plain, Size: 870 bytes --]
On 04/25/2017 08:19 AM, Oliver Hartkopp wrote:
> Hello Dave,
>
> unfortunately the initial network namespace support by Mario Kicherer
> (8e8cda6d737d) slipped into net-next without further review and Marc pushed
> the code without my Acked-by. Due to the fact that this code was in net-next
> now I spent some nights to fix, clean up, finalize and test the missing pieces
> for the namespace support for the CAN subsystem in net/can.
>
> As Marc is currently *VERY* unresponsive on the mailing list due to his 'real'
... and holidays :) But I'm back in the office now.
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 net-next] qed: fix invalid use of sizeof in qed_alloc_qm_data()
From: Wei Yongjun @ 2017-04-25 7:07 UTC (permalink / raw)
To: Yuval Mintz, Ariel Elior; +Cc: Wei Yongjun, everest-linux-l2, netdev
From: Wei Yongjun <weiyongjun1@huawei.com>
sizeof() when applied to a pointer typed expression gives the
size of the pointer, not that of the pointed data.
Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
---
drivers/net/ethernet/qlogic/qed/qed_dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index 2498785..4fa5a1e 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -820,7 +820,7 @@ static int qed_alloc_qm_data(struct qed_hwfn *p_hwfn)
if (!qm_info->qm_vport_params)
goto alloc_err;
- qm_info->qm_port_params = kzalloc(sizeof(qm_info->qm_port_params) *
+ qm_info->qm_port_params = kzalloc(sizeof(*qm_info->qm_port_params) *
p_hwfn->cdev->num_ports_in_engines,
GFP_KERNEL);
if (!qm_info->qm_port_params)
^ permalink raw reply related
* RE: [Intel-wired-lan] [PATCH 1/2] e1000e: Don't return uninitialized stats
From: Brown, Aaron F @ 2017-04-25 7:10 UTC (permalink / raw)
To: Benjamin Poirier, Neftin, Sasha
Cc: Kirsher@f1.synalogic.ca, Stefan Priebe, netdev@vger.kernel.org,
intel-wired-lan@lists.osuosl.org
In-Reply-To: <20170424191026.wpnpyhdaurfjixl7@f1.synalogic.ca>
> From: Intel-wired-lan [mailto:intel-wired-lan-bounces@lists.osuosl.org] On
> Behalf Of Benjamin Poirier
> Sent: Monday, April 24, 2017 12:10 PM
> To: Neftin, Sasha <sasha.neftin@intel.com>
> Cc: Kirsher@f1.synalogic.ca; Stefan Priebe <s.priebe@profihost.ag>;
> netdev@vger.kernel.org; intel-wired-lan@lists.osuosl.org
> Subject: Re: [Intel-wired-lan] [PATCH 1/2] e1000e: Don't return uninitialized
> stats
>
> Sasha, please use reply-all to keep everyone in cc (including me...).
>
> On 2017/04/24 11:17, Neftin, Sasha wrote:
> > On 4/23/2017 15:53, Neftin, Sasha wrote:
> > > -----Original Message-----
> > > From: Intel-wired-lan [mailto:intel-wired-lan-bounces@lists.osuosl.org]
> On Behalf Of Benjamin Poirier
> > > Sent: Saturday, April 22, 2017 00:20
> > > To: Kirsher, Jeffrey T <jeffrey.t.kirsher@intel.com>
> > > Cc: netdev@vger.kernel.org; intel-wired-lan@lists.osuosl.org; Stefan
> Priebe <s.priebe@profihost.ag>
> > > Subject: [Intel-wired-lan] [PATCH 1/2] e1000e: Don't return uninitialized
> stats
> > >
> > > Some statistics passed to ethtool are garbage because
> e1000e_get_stats64() doesn't write them, for example: tx_heartbeat_errors.
> This leaks kernel memory to userspace and confuses users.
> > >
> > > Do like ixgbe and use dev_get_stats() which first zeroes out
> rtnl_link_stats64.
> > >
> > > Reported-by: Stefan Priebe <s.priebe@profihost.ag>
> > > Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
> > > ---
> > > drivers/net/ethernet/intel/e1000e/ethtool.c | 2 +-
> > > 1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c
> b/drivers/net/ethernet/intel/e1000e/ethtool.c
> > > index 7aff68a4a4df..f117b90cdc2f 100644
> > > --- a/drivers/net/ethernet/intel/e1000e/ethtool.c
> > > +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
> > > @@ -2063,7 +2063,7 @@ static void e1000_get_ethtool_stats(struct
> net_device *netdev,
> > > pm_runtime_get_sync(netdev->dev.parent);
> > > - e1000e_get_stats64(netdev, &net_stats);
> > > + dev_get_stats(netdev, &net_stats);
> > > pm_runtime_put_sync(netdev->dev.parent);
> > > --
> > > 2.12.2
> > >
> > > _______________________________________________
> > > Intel-wired-lan mailing list
> > > Intel-wired-lan@lists.osuosl.org
> > > http://lists.osuosl.org/mailman/listinfo/intel-wired-lan
> >
> > Hello,
> >
> > We would like to not accept this patch. Suggested generic method
> > '*dev_get_stats' (net/core/dev.c) calls 'ops->ndo_get_stats64' method
> which
> > eventually calls e1000e_get_stats64 (netdev.c) - so there is same
> > functionality. Also, see that 'e1000e_get_stats64' method in netdev.c (line
>
> No, it's not the same functionality because dev_get_stats() does a
> memset on the rtnl_link_stats64 struct.
>
> > 5928) calls 'memset' with 0's before update statistics. Local sanity check
>
> I don't see any memset in e1000e_get_stats64(). What kernel version are
> you looking at?
The call to memset was removed from the upstream kernel with:
------------------------------------------------------------------------------------
commit 5944701df90d9577658e2354cc27c4ceaeca30fe
Author: stephen hemminger <stephen@networkplumber.org>
Date: Fri Jan 6 19:12:53 2017 -0800
net: remove useless memset's in drivers get_stats64
In dev_get_stats() the statistic structure storage has already been
zeroed. Therefore network drivers do not need to call memset() again.
...
< changes to other drivers snipped out >
...
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/int
index 723025b..79651eb 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -5925,7 +5925,6 @@ void e1000e_get_stats64(struct net_device *netdev,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- memset(stats, 0, sizeof(struct rtnl_link_stats64));
spin_lock(&adapter->stats64_lock);
e1000e_update_stats(adapter);
/* Fill out the OS statistics structure */
------------------------------------------------------------------------------------
This also is where the bad counters start to show up for e1000e for my test systems. From this driver on I see (very) large values for tx_dropped, rx_over_errors and tx_fifo_errors on driver load (even before bringing the interface up. It seems the memset is not so useless for this driver after all. Would simply reverting the e1000e portion of this patch resolve the issue?
>
> > in our lab shows 'tx_heartbeat_errors' counter reported as 0.
> >
>
> Please see the mail I just sent to Paul Menzel <pmenzel@molgen.mpg.de>
> for more information about the issue and how to reproduce it.
> _______________________________________________
> Intel-wired-lan mailing list
> Intel-wired-lan@lists.osuosl.org
> http://lists.osuosl.org/mailman/listinfo/intel-wired-lan
^ permalink raw reply related
* Re: [PATCH] stmmac: Add support for SIMATIC IOT2000 platform
From: Andy Shevchenko @ 2017-04-25 7:30 UTC (permalink / raw)
To: Jan Kiszka
Cc: Giuseppe Cavallaro, Alexandre Torgue, netdev,
Linux Kernel Mailing List, Sascha Weisenberger
In-Reply-To: <feb4856b-fb66-3861-2121-d2834fb01899@siemens.com>
On Tue, Apr 25, 2017 at 8:44 AM, Jan Kiszka <jan.kiszka@siemens.com> wrote:
> On 2017-04-24 23:27, Andy Shevchenko wrote:
>> On Mon, Apr 24, 2017 at 10:27 PM, Jan Kiszka <jan.kiszka@siemens.com> wrote:
>>> The IOT2000 is industrial controller platform, derived from the Intel
>>> Galileo Gen2 board. The variant IOT2020 comes with one LAN port, the
>>> IOT2040 has two of them. They can be told apart based on the board asset
>>> tag in the DMI table.
>>> + const char *asset_tag;
>>
>> I guess this is redundant. See below.
>>
>>> + {
>>> + .name = "SIMATIC IOT2000",
>>> + .asset_tag = "6ES7647-0AA00-0YA2",
>>> + .func = 6,
>>> + .phy_addr = 1,
>>> + },
>>
>> The below has same definition disregard on asset_tag.
>>
>
> There is a small difference in the asset tag, just not at the last digit
> where one may expect it, look:
>
> ...-0YA2 -> IOT2020
> ...-1YA2 -> IOT2040
Yes. And how does it change my statement? You may use one record here
instead of two.
>
>>> + {
>>> + .name = "SIMATIC IOT2000",
>>> + .asset_tag = "6ES7647-0AA00-1YA2",
>>> + .func = 6,
>>> + .phy_addr = 1,
>>> + },
>>> + {
>>> + .name = "SIMATIC IOT2000",
>>> + .asset_tag = "6ES7647-0AA00-1YA2",
>>> + .func = 7,
>>> + .phy_addr = 1,
>>> + },
>>
>> How this supposed to work if phy_addr is the same?
> That address space is MAC-local, and we have two different MACs here.
Got it, though asset_tag here is redundant as well.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2] brcmfmac: Make skb header writable before use
From: Arend Van Spriel @ 2017-04-25 7:38 UTC (permalink / raw)
To: James Hughes, Franky Lin, Hante Meuleman, Kalle Valo,
linux-wireless, brcm80211-dev-list.pdl, netdev
In-Reply-To: <20170424130322.476-1-james.hughes@raspberrypi.org>
On 24-4-2017 15:03, James Hughes wrote:
> The driver was making changes to the skb_header without
> ensuring it was writable (i.e. uncloned).
> This patch also removes some boiler plate header size
> checking/adjustment code as that is also handled by the
> skb_cow_header function used to make header writable.
>
> This patch depends on
> brcmfmac: Ensure pointer correctly set if skb data location changes
>
> Signed-off-by: James Hughes <james.hughes@raspberrypi.org>
> ---
> Changes in v2
> Makes the _cow_ call at the entry point of the skb in to the
> stack, means only needs to be done once, and error handling
> is easier.
> Split a separate minor bug fix off to a separate patch (which
> this patch depends on)
Hi James,
Can you please indicate in this section that you want it applied for
4.12 as it is an important fix. Probably will have to wait until after
the merge window before it can get in the wireless-drivers repo.
Regards,
Arend
> .../net/wireless/broadcom/brcm80211/brcmfmac/core.c | 19 ++++---------------
> 1 file changed, 4 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> index 9b7c19a508ac..88f8675a94c2 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> @@ -211,22 +211,11 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
> goto done;
> }
>
> - /* Make sure there's enough room for any header */
> - if (skb_headroom(skb) < drvr->hdrlen) {
> - struct sk_buff *skb2;
> -
> - brcmf_dbg(INFO, "%s: insufficient headroom\n",
> - brcmf_ifname(ifp));
> - drvr->bus_if->tx_realloc++;
> - skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
> + /* Make sure there's enough room for any header, and make it writable */
> + if (skb_cow_head(skb, drvr->hdrlen)) {
> dev_kfree_skb(skb);
> - skb = skb2;
> - if (skb == NULL) {
> - brcmf_err("%s: skb_realloc_headroom failed\n",
> - brcmf_ifname(ifp));
> - ret = -ENOMEM;
> - goto done;
> - }
> + ret = -ENOMEM;
> + goto done;
> }
>
> /* validate length for ether packet */
>
^ permalink raw reply
* [RFC PATCH] netxen_nic: null-terminate serial number string in netxen_check_options()
From: Jerome Marchand @ 2017-04-25 7:42 UTC (permalink / raw)
To: Manish Chopra, Rahul Verma, Dept-GELinuxNICDev; +Cc: netdev, linux-kernel
The serial_num string in netxen_check_options() is not always properly
null-terminated. I couldn't find the documention on the serial number
format and I suspect a proper integer to string conversion is in
order, but this patch a least prevents the out-of-bound access.
It solves the following kasan warning:
[ 36.127074] ==================================================================
[ 36.168472] BUG: KASAN: stack-out-of-bounds in strnlen+0x38/0x60 at addr ffff8800360e7a50
[ 36.216956] Read of size 1 by task kworker/0:1/188
[ 36.244451] page:ffffea0000d839c0 count:0 mapcount:0 mapping: (null) index:0x2
[ 36.291475] page flags: 0x1fffff00000000()
[ 36.314980] page dumped because: kasan: bad access detected
[ 36.348117] CPU: 0 PID: 188 Comm: kworker/0:1 Not tainted 3.10.0-650.el7.test.kasan.x86_64 #1
[ 36.397065] Hardware name: HP ProLiant DL585 G7, BIOS A16 03/19/2012
[ 36.434443] Workqueue: events work_for_cpu_fn
[ 36.459452] ffff8800360e7a30 00000000e4708e04 ffff8800360e7538 ffffffffb37748bf
[ 36.503442] ffff8800360e75c0 ffffffffb2f4a7e7 ffff8800360d8948 0000000600000007
[ 36.546616] ffff8800360d8950 0000000000000086 ffffffffb3782086 0000000000000004
[ 36.589439] Call Trace:
[ 36.603611] [<ffffffffb37748bf>] dump_stack+0x19/0x1b
[ 36.633970] [<ffffffffb2f4a7e7>] kasan_report_error+0x507/0x540
[ 36.668472] [<ffffffffb3782086>] ? _raw_spin_unlock_irqrestore+0x36/0x80
[ 36.708967] [<ffffffffb2f4ae48>] kasan_report+0x58/0x60
[ 36.740311] [<ffffffffb2d5bf00>] ? cpu_clock+0x10/0x20
[ 36.771532] [<ffffffffb3182e68>] ? strnlen+0x38/0x60
[ 36.800430] [<ffffffffb2f48e6d>] __asan_load1+0x4d/0x50
[ 36.831977] [<ffffffffb3182e68>] strnlen+0x38/0x60
[ 36.859995] [<ffffffffb3186e4f>] string.isra.7+0x3f/0x130
[ 36.891531] [<ffffffffb3189b60>] vsnprintf+0x620/0xd70
[ 36.922997] [<ffffffffb2eba659>] ? __free_pages_ok+0xe9/0x160
[ 36.956467] [<ffffffffb3189540>] ? pointer.isra.19+0x780/0x780
[ 36.991095] [<ffffffffb2ce6ecf>] ? vprintk_emit+0x12f/0x730
[ 37.023440] [<ffffffffb318a2bd>] vscnprintf+0xd/0x40
[ 37.053146] [<ffffffffb2ce6efd>] vprintk_emit+0x15d/0x730
[ 37.084983] [<ffffffffc01afea1>] ? netxen_setup_minidump+0x621/0x780 [netxen_nic]
[ 37.129435] [<ffffffffb2ce784e>] vprintk_default+0x3e/0x60
[ 37.161962] [<ffffffffb376f32a>] printk+0xa1/0xc8
[ 37.189446] [<ffffffffb376f289>] ? panic+0x28d/0x28d
[ 37.219447] [<ffffffffc01a0014>] netxen_start_firmware+0x1124/0x1170 [netxen_nic]
[ 37.262989] [<ffffffffc019eef0>] ? netxen_show_diag_mode+0x50/0x50 [netxen_nic]
[ 37.306968] [<ffffffffc019a960>] ? netxen_nic_hw_write_wx_2M+0x180/0x180 [netxen_nic]
[ 37.352621] [<ffffffffc019a9dc>] ? netxen_nic_hw_read_wx_2M+0x7c/0x180 [netxen_nic]
[ 37.397967] [<ffffffffc01a2863>] netxen_nic_probe+0x6f3/0x15f0 [netxen_nic]
[ 37.439351] [<ffffffffb2c5a3c7>] ? native_sched_clock+0xf7/0x190
[ 37.474980] [<ffffffffb2daf726>] ? mark_lock+0xd6/0x860
[ 37.505439] [<ffffffffc01a2170>] ? netxen_nic_open+0xc0/0xc0 [netxen_nic]
[ 37.545988] [<ffffffffb3782086>] ? _raw_spin_unlock_irqrestore+0x36/0x80
[ 37.584974] [<ffffffffb2db01e7>] ? trace_hardirqs_on_caller+0x187/0x2b0
[ 37.625444] [<ffffffffb2db031d>] ? trace_hardirqs_on+0xd/0x10
[ 37.658978] [<ffffffffb37820a9>] ? _raw_spin_unlock_irqrestore+0x59/0x80
[ 37.698937] [<ffffffffc01a2170>] ? netxen_nic_open+0xc0/0xc0 [netxen_nic]
[ 37.738975] [<ffffffffb31edffa>] local_pci_probe+0x7a/0xd0
[ 37.771447] [<ffffffffb2d21d4f>] ? process_one_work+0x36f/0xb80
[ 37.806447] [<ffffffffb31edf80>] ? pci_device_shutdown+0xa0/0xa0
[ 37.841483] [<ffffffffb2d1a3dc>] work_for_cpu_fn+0x2c/0x50
[ 37.873443] [<ffffffffb2d21df6>] process_one_work+0x416/0xb80
[ 37.908116] [<ffffffffb2d21d4f>] ? process_one_work+0x36f/0xb80
[ 37.943456] [<ffffffffb2d219e0>] ? flush_delayed_work+0x80/0x80
[ 37.977968] [<ffffffffb2d1b2d3>] ? move_linked_works+0x83/0xb0
[ 38.013461] [<ffffffffb2d2292c>] worker_thread+0x3cc/0x580
[ 38.045479] [<ffffffffb2d22560>] ? process_one_work+0xb80/0xb80
[ 38.081445] [<ffffffffb2d2fcce>] kthread+0x16e/0x180
[ 38.110450] [<ffffffffb2d2fb60>] ? flush_kthread_work+0x280/0x280
[ 38.145996] [<ffffffffb2c5a589>] ? sched_clock+0x9/0x10
[ 38.177466] [<ffffffffb2d48bc9>] ? finish_task_switch+0x59/0x200
[ 38.212477] [<ffffffffb2d2fb60>] ? flush_kthread_work+0x280/0x280
[ 38.248158] [<ffffffffb3792b98>] ret_from_fork+0x58/0x90
[ 38.279982] [<ffffffffb2d2fb60>] ? flush_kthread_work+0x280/0x280
[ 38.315480] Memory state around the buggy address:
[ 38.344557] ffff8800360e7900: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 04 f4
[ 38.386125] ffff8800360e7980: f4 f4 f2 f2 f2 f2 04 f4 f4 f4 f2 f2 f2 f2 00 00
[ 38.428978] >ffff8800360e7a00: 00 00 f2 f2 f2 f2 00 00 00 00 f3 f3 f3 f3 00 00
[ 38.470442] ^
[ 38.505984] ffff8800360e7a80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 38.547465] ffff8800360e7b00: 00 00 00 00 00 f1 f1 f1 f1 04 f4 f4 f4 f2 f2 f2
[ 38.590467] ==================================================================
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
---
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 827de83..4d9cefc 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -842,7 +842,7 @@ netxen_check_options(struct netxen_adapter *adapter)
{
u32 fw_major, fw_minor, fw_build, prev_fw_version;
char brd_name[NETXEN_MAX_SHORT_NAME];
- char serial_num[32];
+ char serial_num[33];
int i, offset, val, err;
__le32 *ptr32;
struct pci_dev *pdev = adapter->pdev;
@@ -861,6 +861,7 @@ netxen_check_options(struct netxen_adapter *adapter)
ptr32[i] = cpu_to_le32(val);
offset += sizeof(u32);
}
+ serial_num[32] = 0;
fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
--
2.9.3
^ permalink raw reply related
* Re: [PATCH v2] brcmfmac: Make skb header writable before use
From: Arend Van Spriel @ 2017-04-25 7:46 UTC (permalink / raw)
To: Kalle Valo
Cc: James Hughes, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
brcm80211-dev-list.pdl-dY08KVG/lbpWk0Htik3J/w,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <ef75a194-2e0b-6586-7b31-2eb83128d2bc-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
On 25-4-2017 9:38, Arend Van Spriel wrote:
> On 24-4-2017 15:03, James Hughes wrote:
>> The driver was making changes to the skb_header without
>> ensuring it was writable (i.e. uncloned).
>> This patch also removes some boiler plate header size
>> checking/adjustment code as that is also handled by the
>> skb_cow_header function used to make header writable.
>>
>> This patch depends on
>> brcmfmac: Ensure pointer correctly set if skb data location changes
>>
>> Signed-off-by: James Hughes <james.hughes-FnsA7b+Nu9XbIbC87yuRow@public.gmane.org>
>> ---
>> Changes in v2
>> Makes the _cow_ call at the entry point of the skb in to the
>> stack, means only needs to be done once, and error handling
>> is easier.
>> Split a separate minor bug fix off to a separate patch (which
>> this patch depends on)
>
> Hi James,
>
> Can you please indicate in this section that you want it applied for
> 4.12 as it is an important fix. Probably will have to wait until after
> the merge window before it can get in the wireless-drivers repo.
Hi Kalle,
I should have checked kernel mailing list first as Linus added another
rc cycle. So can this patch still go in wireless-drivers-next for 4.12
kernel. I want it for stable as well, but I will look at that when it
lands upstream.
Regards,
Arend
> Regards,
> Arend
>
>> .../net/wireless/broadcom/brcm80211/brcmfmac/core.c | 19 ++++---------------
>> 1 file changed, 4 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
>> index 9b7c19a508ac..88f8675a94c2 100644
>> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
>> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
>> @@ -211,22 +211,11 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
>> goto done;
>> }
>>
>> - /* Make sure there's enough room for any header */
>> - if (skb_headroom(skb) < drvr->hdrlen) {
>> - struct sk_buff *skb2;
>> -
>> - brcmf_dbg(INFO, "%s: insufficient headroom\n",
>> - brcmf_ifname(ifp));
>> - drvr->bus_if->tx_realloc++;
>> - skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
>> + /* Make sure there's enough room for any header, and make it writable */
>> + if (skb_cow_head(skb, drvr->hdrlen)) {
>> dev_kfree_skb(skb);
>> - skb = skb2;
>> - if (skb == NULL) {
>> - brcmf_err("%s: skb_realloc_headroom failed\n",
>> - brcmf_ifname(ifp));
>> - ret = -ENOMEM;
>> - goto done;
>> - }
>> + ret = -ENOMEM;
>> + goto done;
>> }
>>
>> /* validate length for ether packet */
>>
^ permalink raw reply
* Re: [PATCH v2] brcmfmac: Make skb header writable before use
From: Kalle Valo @ 2017-04-25 7:49 UTC (permalink / raw)
To: Arend Van Spriel
Cc: James Hughes, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
brcm80211-dev-list.pdl-dY08KVG/lbpWk0Htik3J/w,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <ddb49ce2-9968-534e-dd17-b1bf21513c5d-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Arend Van Spriel <arend.vanspriel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org> writes:
> On 25-4-2017 9:38, Arend Van Spriel wrote:
>> On 24-4-2017 15:03, James Hughes wrote:
>>> The driver was making changes to the skb_header without
>>> ensuring it was writable (i.e. uncloned).
>>> This patch also removes some boiler plate header size
>>> checking/adjustment code as that is also handled by the
>>> skb_cow_header function used to make header writable.
>>>
>>> This patch depends on
>>> brcmfmac: Ensure pointer correctly set if skb data location changes
>>>
>>> Signed-off-by: James Hughes <james.hughes-FnsA7b+Nu9XbIbC87yuRow@public.gmane.org>
>>> ---
>>> Changes in v2
>>> Makes the _cow_ call at the entry point of the skb in to the
>>> stack, means only needs to be done once, and error handling
>>> is easier.
>>> Split a separate minor bug fix off to a separate patch (which
>>> this patch depends on)
>>
>> Hi James,
>>
>> Can you please indicate in this section that you want it applied for
>> 4.12 as it is an important fix. Probably will have to wait until after
>> the merge window before it can get in the wireless-drivers repo.
>
> Hi Kalle,
>
> I should have checked kernel mailing list first as Linus added another
> rc cycle. So can this patch still go in wireless-drivers-next for 4.12
> kernel.
Yup, I'll queue it for 4.12.
> I want it for stable as well, but I will look at that when it lands
> upstream.
Ok, so I don't add any stable tag during commit.
--
Kalle Valo
^ permalink raw reply
* Re: qed*: debug infrastructures
From: Jiri Pirko @ 2017-04-25 7:51 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Elior, Ariel, David Miller, netdev@vger.kernel.org, Mintz, Yuval,
Tayar, Tomer, Dupuis, Chad
In-Reply-To: <20170424204410.538fdabc@cakuba.netronome.com>
Tue, Apr 25, 2017 at 05:44:10AM CEST, kubakici@wp.pl wrote:
>On Mon, 24 Apr 2017 17:38:57 +0000, Elior, Ariel wrote:
>> Hi Dave,
>
>Hi Ariel!
>
>I'm not Dave but let me share my perspective :)
>
>> According to the recent messages on the list indicating debugfs is not the way
>> to go, I am looking for some guidance on what is. dpipe approach was
>> mentioned as favorable, but I wanted to make sure molding our debug features to
>> this infrastructure will result in something acceptable. A few points:
>>
>> 1.
>> One of our HW debug features is a signal recording feature. HW is configured to
>> output specific signals, which are then continuously dumped into a cyclic
>> buffer on host. There are ~8000 signals, which can be logically divided to ~100
>> groups. I believe this can be modeled in dpipe (or similar tool) as a set of
>> ~100 tables with ~80 entries each, and user would be able to see them all and
>> choose what they like. The output data itself is binary, and meaningless to
>> "the user". The amount of data is basically as large a contiguous buffer as
>> driver can allocate, i.e. usually 4MB. When user selects the signals, and sets
>> meta data regarding to mode of operations, some device configuration will have
>> to take place. Does that sound reasonable?
>> This debug feature already exists out of tree for bnx2x and qed* drivers and is
>> *very* effective in field deployments. I would very much like to see this as an
>> in-tree feature via some infrastructure or another.
>
>Sorry for even mentioning it, new debug interfaces would be cool, but
>for FW/HW state dumps which are meaningless to the user why not just
>use ethtool get-dump/set-dump? Do you really need the ability to
>toggle those 8k signals one-by-one or are there reasonable sets you
>could provide from the driver that you could encode on the available
>32bits of flags?
>
>What could be useful would be some form of start/stop commands for
>debugging to tell the driver/FW when to record events selected by
>set-dump and maybe a way for the user to discover what dumps the driver
>can provide (a'la ethtool private flags).
>
>> 2.
>> Sometimes we want to debug the probe or removal flow of the driver. ethtool has
>> the disadvantage of only being available once network device is available. If a
>> bug stops the load flow before the ethtool debug paths are available, there is
>> no way to collect a dump. Similarly, removal flows which hit a bug but do remove
>> the network device, can't be debugged from ethtool. Does dpipe suffer from the
>> same problem? qed* (like mlx*) has a common-functionality module. This allows
>> creating debugfs nodes even before the network drivers are probed, providing a
>> solution for this (debug nodes are also available after network driver removal).
>> If dpipe does hold an answer here (e.g. provide preconfiguration which would
>> kick in when network device registers) then we might want to port all of our
>> register dump logic over there for this advantage. Does that sound reasonable?
>
>Porting the debug/dump infrastructure to devlink would be very much
>appreciated. I'm not sure it would fit into dpipe or be a separate
>command.
Yeah. dpipe was designed to provide HW pipeline abstraction, based on
match/action model. I think that for stats and debugging, it would make
sense to introduce another devlink object.
>
>> 3.
>> Yuval mentioned this, but I wanted to reiterate that the same is necessary for
>> our storage drivers (qedi/qedf). debugfs does have the advantage of being non
>> sub-system specific. Is there perhaps another non subsystem specific debug
>> infrastructure which *is* acceptable to the networking subsystem? My guess is
>> that the storage drivers will turn to debugfs (in their own subsystem).
>
>devlink is not ethernet-specific, it should be a good fit for iSCSI and
>FCOE drivers, too.
Yes. During the devlink design, I had the non-network usecase in mind.
Devlink is the iface to be used for all who need it.
^ permalink raw reply
* Re: [PATCH v2] brcmfmac: Ensure pointer correctly set if skb data location changes
From: Arend Van Spriel @ 2017-04-25 7:56 UTC (permalink / raw)
To: Kalle Valo
Cc: James Hughes, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
brcm80211-dev-list.pdl-dY08KVG/lbpWk0Htik3J/w,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170424114050.24948-1-james.hughes-FnsA7b+Nu9XbIbC87yuRow@public.gmane.org>
On 24-4-2017 13:40, James Hughes wrote:
> The incoming skb header may be resized if header space is
> insufficient, which might change the data adddress in the skb.
> Ensure that a cached pointer to that data is correctly set by
> moving assignment to after any possible changes.
Hi Kalle,
This one should go on 4.12 queue as well.
Thanks,
Arend
> Signed-off-by: James Hughes <james.hughes-FnsA7b+Nu9XbIbC87yuRow@public.gmane.org>
>
> Acked-by: Arend van Spriel <arend.vanspriel-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
> ---
^ permalink raw reply
* [RFC 0/4] xdp: use netlink extended ACK reporting
From: Jakub Kicinski @ 2017-04-25 8:06 UTC (permalink / raw)
To: netdev
Cc: davem, johannes, dsa, daniel, alexei.starovoitov, bblanco,
john.fastabend, kubakici, oss-drivers, Jakub Kicinski
Hi!
This series is an attempt to make XDP more user friendly by
enabling exploiting the recently added netlink extended ACK
reporting to carry messages to user space.
I made iproute2 parse the extended messages and have it showing
the errors like this:
# ip link set dev p4p1 xdp obj ipip_prepend.o sec ".text"
RTNETLINK answers: Invalid argument (MTU too large w/ XDP enabled)
Where the message is coming directly from the driver. There could
still be a bit of a leap for a complete novice from the message
above to the right settings. I wonder if it would be worthwhile
adding #defines for the most common configuration conflicts?
Sharing the messages verbatim between drivers could make them easier
to google.
Also - is anyone working on adding proper extack support to iproute2?
The code I have right now is a bit of a hack...
Jakub Kicinski (4):
netlink: make extended ACK setting NULL-friendly
xdp: propagate extended ack to XDP setup
nfp: make use of extended ack message reporting
virtio_net: make use of extended ack message reporting
drivers/net/ethernet/netronome/nfp/nfp_net.h | 3 ++-
.../net/ethernet/netronome/nfp/nfp_net_common.c | 22 +++++++++++++---------
.../net/ethernet/netronome/nfp/nfp_net_ethtool.c | 4 ++--
drivers/net/virtio_net.c | 11 +++++++----
include/linux/netdevice.h | 10 ++++++++--
include/linux/netlink.h | 12 ++++++++----
net/core/dev.c | 5 ++++-
net/core/rtnetlink.c | 13 ++++++++-----
8 files changed, 52 insertions(+), 28 deletions(-)
--
2.11.0
^ permalink raw reply
* [RFC 1/4] netlink: make extended ACK setting NULL-friendly
From: Jakub Kicinski @ 2017-04-25 8:06 UTC (permalink / raw)
To: netdev
Cc: davem, johannes, dsa, daniel, alexei.starovoitov, bblanco,
john.fastabend, kubakici, oss-drivers, Jakub Kicinski
In-Reply-To: <20170425080644.122536-1-jakub.kicinski@netronome.com>
As we propagate extended ack reporting throughout various paths in
the kernel it may happen that the same function is called with the
extended ack parameter passed as NULL. Make the NL_SET_ERR_MSG()
macro simply print the message to the logs if that happens.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
include/linux/netlink.h | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 8d2a8924705c..b59cfbf2e2c7 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -86,10 +86,14 @@ struct netlink_ext_ack {
* Currently string formatting is not supported (due
* to the lack of an output buffer.)
*/
-#define NL_SET_ERR_MSG(extack, msg) do { \
- static const char _msg[] = (msg); \
- \
- (extack)->_msg = _msg; \
+#define NL_SET_ERR_MSG(extack, msg) do { \
+ struct netlink_ext_ack *_extack = (extack); \
+ static const char _msg[] = (msg); \
+ \
+ if (_extack) \
+ _extack->_msg = _msg; \
+ else \
+ pr_info("%s\n", _msg); \
} while (0)
extern void netlink_kernel_release(struct sock *sk);
--
2.11.0
^ permalink raw reply related
* [RFC 2/4] xdp: propagate extended ack to XDP setup
From: Jakub Kicinski @ 2017-04-25 8:06 UTC (permalink / raw)
To: netdev
Cc: davem, johannes, dsa, daniel, alexei.starovoitov, bblanco,
john.fastabend, kubakici, oss-drivers, Jakub Kicinski
In-Reply-To: <20170425080644.122536-1-jakub.kicinski@netronome.com>
Drivers usually have a number of restrictions for running XDP
- most common being buffer sizes, LRO and number of rings.
Even though some drivers try to be helpful and print error
messages experience shows that users don't often consult
kernel logs on netlink errors. Try to use the new extended
ack mechanism to carry the message back to user space.
For now the extack is only set for XDP_SETUP_PROG, adding it
to dump/XDP_QUERY_PROG didn't make much sense.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
include/linux/netdevice.h | 10 ++++++++--
net/core/dev.c | 5 ++++-
net/core/rtnetlink.c | 13 ++++++++-----
3 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5d5267febd56..41667f4238d2 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -813,11 +813,16 @@ enum xdp_netdev_command {
XDP_QUERY_PROG,
};
+struct netlink_ext_ack;
+
struct netdev_xdp {
enum xdp_netdev_command command;
union {
/* XDP_SETUP_PROG */
- struct bpf_prog *prog;
+ struct {
+ struct bpf_prog *prog;
+ struct netlink_ext_ack *extack;
+ };
/* XDP_QUERY_PROG */
bool prog_attached;
};
@@ -3283,7 +3288,8 @@ int dev_get_phys_port_id(struct net_device *dev,
int dev_get_phys_port_name(struct net_device *dev,
char *name, size_t len);
int dev_change_proto_down(struct net_device *dev, bool proto_down);
-int dev_change_xdp_fd(struct net_device *dev, int fd, u32 flags);
+int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
+ int fd, u32 flags);
struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev);
struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq, int *ret);
diff --git a/net/core/dev.c b/net/core/dev.c
index db6e31564d06..ca4633af5448 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6716,12 +6716,14 @@ EXPORT_SYMBOL(dev_change_proto_down);
/**
* dev_change_xdp_fd - set or clear a bpf program for a device rx path
* @dev: device
+ * @extact: netlink extended ack
* @fd: new program fd or negative value to clear
* @flags: xdp-related flags
*
* Set or clear a bpf program for a device
*/
-int dev_change_xdp_fd(struct net_device *dev, int fd, u32 flags)
+int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
+ int fd, u32 flags)
{
const struct net_device_ops *ops = dev->netdev_ops;
struct bpf_prog *prog = NULL;
@@ -6751,6 +6753,7 @@ int dev_change_xdp_fd(struct net_device *dev, int fd, u32 flags)
memset(&xdp, 0, sizeof(xdp));
xdp.command = XDP_SETUP_PROG;
+ xdp.extack = extack;
xdp.prog = prog;
err = ops->ndo_xdp(dev, &xdp);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 088f9c8b4196..1723dbb9e3dd 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1909,6 +1909,7 @@ static int do_set_master(struct net_device *dev, int ifindex)
#define DO_SETLINK_NOTIFY 0x03
static int do_setlink(const struct sk_buff *skb,
struct net_device *dev, struct ifinfomsg *ifm,
+ struct netlink_ext_ack *extack,
struct nlattr **tb, char *ifname, int status)
{
const struct net_device_ops *ops = dev->netdev_ops;
@@ -2191,7 +2192,7 @@ static int do_setlink(const struct sk_buff *skb,
}
if (xdp[IFLA_XDP_FD]) {
- err = dev_change_xdp_fd(dev,
+ err = dev_change_xdp_fd(dev, extack,
nla_get_s32(xdp[IFLA_XDP_FD]),
xdp_flags);
if (err)
@@ -2251,7 +2252,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err < 0)
goto errout;
- err = do_setlink(skb, dev, ifm, tb, ifname, 0);
+ err = do_setlink(skb, dev, ifm, extack, tb, ifname, 0);
errout:
return err;
}
@@ -2413,6 +2414,7 @@ EXPORT_SYMBOL(rtnl_create_link);
static int rtnl_group_changelink(const struct sk_buff *skb,
struct net *net, int group,
struct ifinfomsg *ifm,
+ struct netlink_ext_ack *extack,
struct nlattr **tb)
{
struct net_device *dev, *aux;
@@ -2420,7 +2422,7 @@ static int rtnl_group_changelink(const struct sk_buff *skb,
for_each_netdev_safe(net, dev, aux) {
if (dev->group == group) {
- err = do_setlink(skb, dev, ifm, tb, NULL, 0);
+ err = do_setlink(skb, dev, ifm, extack, tb, NULL, 0);
if (err < 0)
return err;
}
@@ -2566,14 +2568,15 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
status |= DO_SETLINK_NOTIFY;
}
- return do_setlink(skb, dev, ifm, tb, ifname, status);
+ return do_setlink(skb, dev, ifm, extack, tb, ifname,
+ status);
}
if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
if (ifm->ifi_index == 0 && tb[IFLA_GROUP])
return rtnl_group_changelink(skb, net,
nla_get_u32(tb[IFLA_GROUP]),
- ifm, tb);
+ ifm, extack, tb);
return -ENODEV;
}
--
2.11.0
^ 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