Skip to content

Commit 8e8cda6

Browse files
anycmarckleinebudde
authored andcommitted
can: initial support for network namespaces
This patch adds initial support for network namespaces. The changes only enable support in the CAN raw, proc and af_can code. GW and BCM still have their checks that ensure that they are used only from the main namespace. The patch boils down to moving the global structures, i.e. the global filter list and their /proc stats, into a per-namespace structure and passing around the corresponding "struct net" in a lot of different places. Changes since v1: - rebased on current HEAD (2bfe01e) - fixed overlong line Signed-off-by: Mario Kicherer <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent dabf54d commit 8e8cda6

File tree

9 files changed

+242
-179
lines changed

9 files changed

+242
-179
lines changed

include/linux/can/core.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@ struct can_proto {
4545
extern int can_proto_register(const struct can_proto *cp);
4646
extern void can_proto_unregister(const struct can_proto *cp);
4747

48-
int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
48+
int can_rx_register(struct net *net, struct net_device *dev,
49+
canid_t can_id, canid_t mask,
4950
void (*func)(struct sk_buff *, void *),
5051
void *data, char *ident, struct sock *sk);
5152

52-
extern void can_rx_unregister(struct net_device *dev, canid_t can_id,
53-
canid_t mask,
53+
extern void can_rx_unregister(struct net *net, struct net_device *dev,
54+
canid_t can_id, canid_t mask,
5455
void (*func)(struct sk_buff *, void *),
5556
void *data);
5657

include/net/net_namespace.h

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <net/netns/nftables.h>
2828
#include <net/netns/xfrm.h>
2929
#include <net/netns/mpls.h>
30+
#include <net/netns/can.h>
3031
#include <linux/ns_common.h>
3132
#include <linux/idr.h>
3233
#include <linux/skbuff.h>
@@ -140,6 +141,9 @@ struct net {
140141
#endif
141142
#if IS_ENABLED(CONFIG_MPLS)
142143
struct netns_mpls mpls;
144+
#endif
145+
#if IS_ENABLED(CONFIG_CAN)
146+
struct netns_can can;
143147
#endif
144148
struct sock *diag_nlsk;
145149
atomic_t fnhe_genid;

include/net/netns/can.h

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* can in net namespaces
3+
*/
4+
5+
#ifndef __NETNS_CAN_H__
6+
#define __NETNS_CAN_H__
7+
8+
#include <linux/spinlock.h>
9+
10+
struct dev_rcv_lists;
11+
12+
struct netns_can {
13+
#if IS_ENABLED(CONFIG_PROC_FS)
14+
struct proc_dir_entry *proc_dir;
15+
struct proc_dir_entry *pde_version;
16+
struct proc_dir_entry *pde_stats;
17+
struct proc_dir_entry *pde_reset_stats;
18+
struct proc_dir_entry *pde_rcvlist_all;
19+
struct proc_dir_entry *pde_rcvlist_fil;
20+
struct proc_dir_entry *pde_rcvlist_inv;
21+
struct proc_dir_entry *pde_rcvlist_sff;
22+
struct proc_dir_entry *pde_rcvlist_eff;
23+
struct proc_dir_entry *pde_rcvlist_err;
24+
#endif
25+
26+
/* receive filters subscribed for 'all' CAN devices */
27+
struct dev_rcv_lists *can_rx_alldev_list;
28+
spinlock_t can_rcvlists_lock;
29+
};
30+
31+
#endif /* __NETNS_CAN_H__ */

net/can/af_can.c

+70-52
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,7 @@ static int stats_timer __read_mostly = 1;
7575
module_param(stats_timer, int, S_IRUGO);
7676
MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)");
7777

78-
/* receive filters subscribed for 'all' CAN devices */
79-
struct dev_rcv_lists can_rx_alldev_list;
80-
static DEFINE_SPINLOCK(can_rcvlists_lock);
78+
static int can_net_id;
8179

8280
static struct kmem_cache *rcv_cache __read_mostly;
8381

@@ -145,9 +143,6 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
145143
if (protocol < 0 || protocol >= CAN_NPROTO)
146144
return -EINVAL;
147145

148-
if (!net_eq(net, &init_net))
149-
return -EAFNOSUPPORT;
150-
151146
cp = can_get_proto(protocol);
152147

153148
#ifdef CONFIG_MODULES
@@ -331,10 +326,11 @@ EXPORT_SYMBOL(can_send);
331326
* af_can rx path
332327
*/
333328

334-
static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
329+
static struct dev_rcv_lists *find_dev_rcv_lists(struct net *net,
330+
struct net_device *dev)
335331
{
336332
if (!dev)
337-
return &can_rx_alldev_list;
333+
return net->can.can_rx_alldev_list;
338334
else
339335
return (struct dev_rcv_lists *)dev->ml_priv;
340336
}
@@ -467,9 +463,9 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
467463
* -ENOMEM on missing cache mem to create subscription entry
468464
* -ENODEV unknown device
469465
*/
470-
int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
471-
void (*func)(struct sk_buff *, void *), void *data,
472-
char *ident, struct sock *sk)
466+
int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
467+
canid_t mask, void (*func)(struct sk_buff *, void *),
468+
void *data, char *ident, struct sock *sk)
473469
{
474470
struct receiver *r;
475471
struct hlist_head *rl;
@@ -481,13 +477,16 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
481477
if (dev && dev->type != ARPHRD_CAN)
482478
return -ENODEV;
483479

480+
if (dev && !net_eq(net, dev_net(dev)))
481+
return -ENODEV;
482+
484483
r = kmem_cache_alloc(rcv_cache, GFP_KERNEL);
485484
if (!r)
486485
return -ENOMEM;
487486

488-
spin_lock(&can_rcvlists_lock);
487+
spin_lock(&net->can.can_rcvlists_lock);
489488

490-
d = find_dev_rcv_lists(dev);
489+
d = find_dev_rcv_lists(net, dev);
491490
if (d) {
492491
rl = find_rcv_list(&can_id, &mask, d);
493492

@@ -510,7 +509,7 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
510509
err = -ENODEV;
511510
}
512511

513-
spin_unlock(&can_rcvlists_lock);
512+
spin_unlock(&net->can.can_rcvlists_lock);
514513

515514
return err;
516515
}
@@ -540,8 +539,9 @@ static void can_rx_delete_receiver(struct rcu_head *rp)
540539
* Description:
541540
* Removes subscription entry depending on given (subscription) values.
542541
*/
543-
void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
544-
void (*func)(struct sk_buff *, void *), void *data)
542+
void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
543+
canid_t mask, void (*func)(struct sk_buff *, void *),
544+
void *data)
545545
{
546546
struct receiver *r = NULL;
547547
struct hlist_head *rl;
@@ -550,9 +550,12 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
550550
if (dev && dev->type != ARPHRD_CAN)
551551
return;
552552

553-
spin_lock(&can_rcvlists_lock);
553+
if (dev && !net_eq(net, dev_net(dev)))
554+
return;
554555

555-
d = find_dev_rcv_lists(dev);
556+
spin_lock(&net->can.can_rcvlists_lock);
557+
558+
d = find_dev_rcv_lists(net, dev);
556559
if (!d) {
557560
pr_err("BUG: receive list not found for "
558561
"dev %s, id %03X, mask %03X\n",
@@ -598,7 +601,7 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
598601
}
599602

600603
out:
601-
spin_unlock(&can_rcvlists_lock);
604+
spin_unlock(&net->can.can_rcvlists_lock);
602605

603606
/* schedule the receiver item for deletion */
604607
if (r) {
@@ -696,10 +699,10 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
696699
rcu_read_lock();
697700

698701
/* deliver the packet to sockets listening on all devices */
699-
matches = can_rcv_filter(&can_rx_alldev_list, skb);
702+
matches = can_rcv_filter(dev_net(dev)->can.can_rx_alldev_list, skb);
700703

701704
/* find receive list for this device */
702-
d = find_dev_rcv_lists(dev);
705+
d = find_dev_rcv_lists(dev_net(dev), dev);
703706
if (d)
704707
matches += can_rcv_filter(d, skb);
705708

@@ -719,9 +722,6 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
719722
{
720723
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
721724

722-
if (unlikely(!net_eq(dev_net(dev), &init_net)))
723-
goto drop;
724-
725725
if (WARN_ONCE(dev->type != ARPHRD_CAN ||
726726
skb->len != CAN_MTU ||
727727
cfd->len > CAN_MAX_DLEN,
@@ -743,9 +743,6 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
743743
{
744744
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
745745

746-
if (unlikely(!net_eq(dev_net(dev), &init_net)))
747-
goto drop;
748-
749746
if (WARN_ONCE(dev->type != ARPHRD_CAN ||
750747
skb->len != CANFD_MTU ||
751748
cfd->len > CANFD_MAX_DLEN,
@@ -835,9 +832,6 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
835832
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
836833
struct dev_rcv_lists *d;
837834

838-
if (!net_eq(dev_net(dev), &init_net))
839-
return NOTIFY_DONE;
840-
841835
if (dev->type != ARPHRD_CAN)
842836
return NOTIFY_DONE;
843837

@@ -855,7 +849,7 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
855849
break;
856850

857851
case NETDEV_UNREGISTER:
858-
spin_lock(&can_rcvlists_lock);
852+
spin_lock(&dev_net(dev)->can.can_rcvlists_lock);
859853

860854
d = dev->ml_priv;
861855
if (d) {
@@ -869,14 +863,48 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
869863
pr_err("can: notifier: receive list not found for dev "
870864
"%s\n", dev->name);
871865

872-
spin_unlock(&can_rcvlists_lock);
866+
spin_unlock(&dev_net(dev)->can.can_rcvlists_lock);
873867

874868
break;
875869
}
876870

877871
return NOTIFY_DONE;
878872
}
879873

874+
static int can_pernet_init(struct net *net)
875+
{
876+
net->can.can_rcvlists_lock =
877+
__SPIN_LOCK_UNLOCKED(net->can.can_rcvlists_lock);
878+
net->can.can_rx_alldev_list =
879+
kzalloc(sizeof(struct dev_rcv_lists), GFP_KERNEL);
880+
881+
if (IS_ENABLED(CONFIG_PROC_FS))
882+
can_init_proc(net);
883+
884+
return 0;
885+
}
886+
887+
static void can_pernet_exit(struct net *net)
888+
{
889+
struct net_device *dev;
890+
891+
if (IS_ENABLED(CONFIG_PROC_FS))
892+
can_remove_proc(net);
893+
894+
/* remove created dev_rcv_lists from still registered CAN devices */
895+
rcu_read_lock();
896+
for_each_netdev_rcu(net, dev) {
897+
if (dev->type == ARPHRD_CAN && dev->ml_priv) {
898+
struct dev_rcv_lists *d = dev->ml_priv;
899+
900+
BUG_ON(d->entries);
901+
kfree(d);
902+
dev->ml_priv = NULL;
903+
}
904+
}
905+
rcu_read_unlock();
906+
}
907+
880908
/*
881909
* af_can module init/exit functions
882910
*/
@@ -902,6 +930,13 @@ static struct notifier_block can_netdev_notifier __read_mostly = {
902930
.notifier_call = can_notifier,
903931
};
904932

933+
static struct pernet_operations can_pernet_ops __read_mostly = {
934+
.init = can_pernet_init,
935+
.exit = can_pernet_exit,
936+
.id = &can_net_id,
937+
.size = 0,
938+
};
939+
905940
static __init int can_init(void)
906941
{
907942
/* check for correct padding to be able to use the structs similarly */
@@ -912,8 +947,6 @@ static __init int can_init(void)
912947

913948
pr_info("can: controller area network core (" CAN_VERSION_STRING ")\n");
914949

915-
memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list));
916-
917950
rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver),
918951
0, 0, NULL);
919952
if (!rcv_cache)
@@ -925,9 +958,10 @@ static __init int can_init(void)
925958
setup_timer(&can_stattimer, can_stat_update, 0);
926959
mod_timer(&can_stattimer, round_jiffies(jiffies + HZ));
927960
}
928-
can_init_proc();
929961
}
930962

963+
register_pernet_subsys(&can_pernet_ops);
964+
931965
/* protocol register */
932966
sock_register(&can_family_ops);
933967
register_netdevice_notifier(&can_netdev_notifier);
@@ -939,13 +973,9 @@ static __init int can_init(void)
939973

940974
static __exit void can_exit(void)
941975
{
942-
struct net_device *dev;
943-
944976
if (IS_ENABLED(CONFIG_PROC_FS)) {
945977
if (stats_timer)
946978
del_timer_sync(&can_stattimer);
947-
948-
can_remove_proc();
949979
}
950980

951981
/* protocol unregister */
@@ -954,19 +984,7 @@ static __exit void can_exit(void)
954984
unregister_netdevice_notifier(&can_netdev_notifier);
955985
sock_unregister(PF_CAN);
956986

957-
/* remove created dev_rcv_lists from still registered CAN devices */
958-
rcu_read_lock();
959-
for_each_netdev_rcu(&init_net, dev) {
960-
if (dev->type == ARPHRD_CAN && dev->ml_priv) {
961-
962-
struct dev_rcv_lists *d = dev->ml_priv;
963-
964-
BUG_ON(d->entries);
965-
kfree(d);
966-
dev->ml_priv = NULL;
967-
}
968-
}
969-
rcu_read_unlock();
987+
unregister_pernet_subsys(&can_pernet_ops);
970988

971989
rcu_barrier(); /* Wait for completion of call_rcu()'s */
972990

net/can/af_can.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ struct s_pstats {
114114
extern struct dev_rcv_lists can_rx_alldev_list;
115115

116116
/* function prototypes for the CAN networklayer procfs (proc.c) */
117-
void can_init_proc(void);
118-
void can_remove_proc(void);
117+
void can_init_proc(struct net *net);
118+
void can_remove_proc(struct net *net);
119119
void can_stat_update(unsigned long data);
120120

121121
/* structures and variables from af_can.c needed in proc.c for reading */

0 commit comments

Comments
 (0)