Skip to content

Commit 1ef8331

Browse files
hartkoppmarckleinebudde
authored andcommitted
can: network namespace support for CAN gateway
The CAN gateway was not implemented as per-net in the initial network namespace support by Mario Kicherer (8e8cda6). This patch enables the CAN gateway to be used in different namespaces. Signed-off-by: Oliver Hartkopp <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent 384317e commit 1ef8331

File tree

2 files changed

+47
-28
lines changed

2 files changed

+47
-28
lines changed

include/net/netns/can.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ struct netns_can {
3232
struct timer_list can_stattimer;/* timer for statistics update */
3333
struct s_stats *can_stats; /* packet statistics */
3434
struct s_pstats *can_pstats; /* receive list statistics */
35+
36+
/* CAN GW per-net gateway jobs */
37+
struct hlist_head cgw_list;
3538
};
3639

3740
#endif /* __NETNS_CAN_H__ */

net/can/gw.c

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* gw.c - CAN frame Gateway/Router/Bridge with netlink interface
33
*
4-
* Copyright (c) 2011 Volkswagen Group Electronic Research
4+
* Copyright (c) 2017 Volkswagen Group Electronic Research
55
* All rights reserved.
66
*
77
* Redistribution and use in source and binary forms, with or without
@@ -59,7 +59,7 @@
5959
#include <net/net_namespace.h>
6060
#include <net/sock.h>
6161

62-
#define CAN_GW_VERSION "20130117"
62+
#define CAN_GW_VERSION "20170425"
6363
#define CAN_GW_NAME "can-gw"
6464

6565
MODULE_DESCRIPTION("PF_CAN netlink gateway");
@@ -79,9 +79,7 @@ MODULE_PARM_DESC(max_hops,
7979
__stringify(CGW_MAX_HOPS) " hops, "
8080
"default: " __stringify(CGW_DEFAULT_HOPS) ")");
8181

82-
static HLIST_HEAD(cgw_list);
8382
static struct notifier_block notifier;
84-
8583
static struct kmem_cache *cgw_cache __read_mostly;
8684

8785
/* structure that contains the (on-the-fly) CAN frame modifications */
@@ -438,26 +436,25 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
438436
gwj->handled_frames++;
439437
}
440438

441-
static inline int cgw_register_filter(struct cgw_job *gwj)
439+
static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj)
442440
{
443-
return can_rx_register(&init_net, gwj->src.dev, gwj->ccgw.filter.can_id,
441+
return can_rx_register(net, gwj->src.dev, gwj->ccgw.filter.can_id,
444442
gwj->ccgw.filter.can_mask, can_can_gw_rcv,
445443
gwj, "gw", NULL);
446444
}
447445

448-
static inline void cgw_unregister_filter(struct cgw_job *gwj)
446+
static inline void cgw_unregister_filter(struct net *net, struct cgw_job *gwj)
449447
{
450-
can_rx_unregister(&init_net, gwj->src.dev, gwj->ccgw.filter.can_id,
448+
can_rx_unregister(net, gwj->src.dev, gwj->ccgw.filter.can_id,
451449
gwj->ccgw.filter.can_mask, can_can_gw_rcv, gwj);
452450
}
453451

454452
static int cgw_notifier(struct notifier_block *nb,
455453
unsigned long msg, void *ptr)
456454
{
457455
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
456+
struct net *net = dev_net(dev);
458457

459-
if (!net_eq(dev_net(dev), &init_net))
460-
return NOTIFY_DONE;
461458
if (dev->type != ARPHRD_CAN)
462459
return NOTIFY_DONE;
463460

@@ -468,11 +465,11 @@ static int cgw_notifier(struct notifier_block *nb,
468465

469466
ASSERT_RTNL();
470467

471-
hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) {
468+
hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
472469

473470
if (gwj->src.dev == dev || gwj->dst.dev == dev) {
474471
hlist_del(&gwj->list);
475-
cgw_unregister_filter(gwj);
472+
cgw_unregister_filter(net, gwj);
476473
kmem_cache_free(cgw_cache, gwj);
477474
}
478475
}
@@ -592,12 +589,13 @@ static int cgw_put_job(struct sk_buff *skb, struct cgw_job *gwj, int type,
592589
/* Dump information about all CAN gateway jobs, in response to RTM_GETROUTE */
593590
static int cgw_dump_jobs(struct sk_buff *skb, struct netlink_callback *cb)
594591
{
592+
struct net *net = sock_net(skb->sk);
595593
struct cgw_job *gwj = NULL;
596594
int idx = 0;
597595
int s_idx = cb->args[0];
598596

599597
rcu_read_lock();
600-
hlist_for_each_entry_rcu(gwj, &cgw_list, list) {
598+
hlist_for_each_entry_rcu(gwj, &net->can.cgw_list, list) {
601599
if (idx < s_idx)
602600
goto cont;
603601

@@ -812,6 +810,7 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
812810
static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
813811
struct netlink_ext_ack *extack)
814812
{
813+
struct net *net = sock_net(skb->sk);
815814
struct rtcanmsg *r;
816815
struct cgw_job *gwj;
817816
struct cf_mod mod;
@@ -842,7 +841,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
842841
ASSERT_RTNL();
843842

844843
/* check for updating an existing job with identical uid */
845-
hlist_for_each_entry(gwj, &cgw_list, list) {
844+
hlist_for_each_entry(gwj, &net->can.cgw_list, list) {
846845

847846
if (gwj->mod.uid != mod.uid)
848847
continue;
@@ -880,15 +879,15 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
880879

881880
err = -ENODEV;
882881

883-
gwj->src.dev = __dev_get_by_index(&init_net, gwj->ccgw.src_idx);
882+
gwj->src.dev = __dev_get_by_index(net, gwj->ccgw.src_idx);
884883

885884
if (!gwj->src.dev)
886885
goto out;
887886

888887
if (gwj->src.dev->type != ARPHRD_CAN)
889888
goto out;
890889

891-
gwj->dst.dev = __dev_get_by_index(&init_net, gwj->ccgw.dst_idx);
890+
gwj->dst.dev = __dev_get_by_index(net, gwj->ccgw.dst_idx);
892891

893892
if (!gwj->dst.dev)
894893
goto out;
@@ -898,33 +897,34 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
898897

899898
ASSERT_RTNL();
900899

901-
err = cgw_register_filter(gwj);
900+
err = cgw_register_filter(net, gwj);
902901
if (!err)
903-
hlist_add_head_rcu(&gwj->list, &cgw_list);
902+
hlist_add_head_rcu(&gwj->list, &net->can.cgw_list);
904903
out:
905904
if (err)
906905
kmem_cache_free(cgw_cache, gwj);
907906

908907
return err;
909908
}
910909

911-
static void cgw_remove_all_jobs(void)
910+
static void cgw_remove_all_jobs(struct net *net)
912911
{
913912
struct cgw_job *gwj = NULL;
914913
struct hlist_node *nx;
915914

916915
ASSERT_RTNL();
917916

918-
hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) {
917+
hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
919918
hlist_del(&gwj->list);
920-
cgw_unregister_filter(gwj);
919+
cgw_unregister_filter(net, gwj);
921920
kmem_cache_free(cgw_cache, gwj);
922921
}
923922
}
924923

925924
static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
926925
struct netlink_ext_ack *extack)
927926
{
927+
struct net *net = sock_net(skb->sk);
928928
struct cgw_job *gwj = NULL;
929929
struct hlist_node *nx;
930930
struct rtcanmsg *r;
@@ -953,7 +953,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
953953

954954
/* two interface indices both set to 0 => remove all entries */
955955
if (!ccgw.src_idx && !ccgw.dst_idx) {
956-
cgw_remove_all_jobs();
956+
cgw_remove_all_jobs(net);
957957
return 0;
958958
}
959959

@@ -962,7 +962,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
962962
ASSERT_RTNL();
963963

964964
/* remove only the first matching entry */
965-
hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) {
965+
hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
966966

967967
if (gwj->flags != r->flags)
968968
continue;
@@ -985,7 +985,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
985985
continue;
986986

987987
hlist_del(&gwj->list);
988-
cgw_unregister_filter(gwj);
988+
cgw_unregister_filter(net, gwj);
989989
kmem_cache_free(cgw_cache, gwj);
990990
err = 0;
991991
break;
@@ -994,6 +994,24 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
994994
return err;
995995
}
996996

997+
static int __net_init cangw_pernet_init(struct net *net)
998+
{
999+
INIT_HLIST_HEAD(&net->can.cgw_list);
1000+
return 0;
1001+
}
1002+
1003+
static void __net_exit cangw_pernet_exit(struct net *net)
1004+
{
1005+
rtnl_lock();
1006+
cgw_remove_all_jobs(net);
1007+
rtnl_unlock();
1008+
}
1009+
1010+
static struct pernet_operations cangw_pernet_ops = {
1011+
.init = cangw_pernet_init,
1012+
.exit = cangw_pernet_exit,
1013+
};
1014+
9971015
static __init int cgw_module_init(void)
9981016
{
9991017
/* sanitize given module parameter */
@@ -1002,6 +1020,7 @@ static __init int cgw_module_init(void)
10021020
pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n",
10031021
max_hops);
10041022

1023+
register_pernet_subsys(&cangw_pernet_ops);
10051024
cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job),
10061025
0, 0, NULL);
10071026

@@ -1031,10 +1050,7 @@ static __exit void cgw_module_exit(void)
10311050

10321051
unregister_netdevice_notifier(&notifier);
10331052

1034-
rtnl_lock();
1035-
cgw_remove_all_jobs();
1036-
rtnl_unlock();
1037-
1053+
unregister_pernet_subsys(&cangw_pernet_ops);
10381054
rcu_barrier(); /* Wait for completion of call_rcu()'s */
10391055

10401056
kmem_cache_destroy(cgw_cache);

0 commit comments

Comments
 (0)