Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 (8e8cda6d737d).
This patch enables the CAN gateway to be used in different namespaces.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
1ef83310 384317ef

+47 -28
+3
include/net/netns/can.h
··· 32 32 struct timer_list can_stattimer;/* timer for statistics update */ 33 33 struct s_stats *can_stats; /* packet statistics */ 34 34 struct s_pstats *can_pstats; /* receive list statistics */ 35 + 36 + /* CAN GW per-net gateway jobs */ 37 + struct hlist_head cgw_list; 35 38 }; 36 39 37 40 #endif /* __NETNS_CAN_H__ */
+44 -28
net/can/gw.c
··· 1 1 /* 2 2 * gw.c - CAN frame Gateway/Router/Bridge with netlink interface 3 3 * 4 - * Copyright (c) 2011 Volkswagen Group Electronic Research 4 + * Copyright (c) 2017 Volkswagen Group Electronic Research 5 5 * All rights reserved. 6 6 * 7 7 * Redistribution and use in source and binary forms, with or without ··· 59 59 #include <net/net_namespace.h> 60 60 #include <net/sock.h> 61 61 62 - #define CAN_GW_VERSION "20130117" 62 + #define CAN_GW_VERSION "20170425" 63 63 #define CAN_GW_NAME "can-gw" 64 64 65 65 MODULE_DESCRIPTION("PF_CAN netlink gateway"); ··· 79 79 __stringify(CGW_MAX_HOPS) " hops, " 80 80 "default: " __stringify(CGW_DEFAULT_HOPS) ")"); 81 81 82 - static HLIST_HEAD(cgw_list); 83 82 static struct notifier_block notifier; 84 - 85 83 static struct kmem_cache *cgw_cache __read_mostly; 86 84 87 85 /* structure that contains the (on-the-fly) CAN frame modifications */ ··· 436 438 gwj->handled_frames++; 437 439 } 438 440 439 - static inline int cgw_register_filter(struct cgw_job *gwj) 441 + static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj) 440 442 { 441 - return can_rx_register(&init_net, gwj->src.dev, gwj->ccgw.filter.can_id, 443 + return can_rx_register(net, gwj->src.dev, gwj->ccgw.filter.can_id, 442 444 gwj->ccgw.filter.can_mask, can_can_gw_rcv, 443 445 gwj, "gw", NULL); 444 446 } 445 447 446 - static inline void cgw_unregister_filter(struct cgw_job *gwj) 448 + static inline void cgw_unregister_filter(struct net *net, struct cgw_job *gwj) 447 449 { 448 - can_rx_unregister(&init_net, gwj->src.dev, gwj->ccgw.filter.can_id, 450 + can_rx_unregister(net, gwj->src.dev, gwj->ccgw.filter.can_id, 449 451 gwj->ccgw.filter.can_mask, can_can_gw_rcv, gwj); 450 452 } 451 453 ··· 453 455 unsigned long msg, void *ptr) 454 456 { 455 457 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 458 + struct net *net = dev_net(dev); 456 459 457 - if (!net_eq(dev_net(dev), &init_net)) 458 - return NOTIFY_DONE; 459 460 if (dev->type != ARPHRD_CAN) 460 461 return NOTIFY_DONE; 461 462 ··· 465 468 466 469 ASSERT_RTNL(); 467 470 468 - hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) { 471 + hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) { 469 472 470 473 if (gwj->src.dev == dev || gwj->dst.dev == dev) { 471 474 hlist_del(&gwj->list); 472 - cgw_unregister_filter(gwj); 475 + cgw_unregister_filter(net, gwj); 473 476 kmem_cache_free(cgw_cache, gwj); 474 477 } 475 478 } ··· 589 592 /* Dump information about all CAN gateway jobs, in response to RTM_GETROUTE */ 590 593 static int cgw_dump_jobs(struct sk_buff *skb, struct netlink_callback *cb) 591 594 { 595 + struct net *net = sock_net(skb->sk); 592 596 struct cgw_job *gwj = NULL; 593 597 int idx = 0; 594 598 int s_idx = cb->args[0]; 595 599 596 600 rcu_read_lock(); 597 - hlist_for_each_entry_rcu(gwj, &cgw_list, list) { 601 + hlist_for_each_entry_rcu(gwj, &net->can.cgw_list, list) { 598 602 if (idx < s_idx) 599 603 goto cont; 600 604 ··· 810 812 static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, 811 813 struct netlink_ext_ack *extack) 812 814 { 815 + struct net *net = sock_net(skb->sk); 813 816 struct rtcanmsg *r; 814 817 struct cgw_job *gwj; 815 818 struct cf_mod mod; ··· 841 842 ASSERT_RTNL(); 842 843 843 844 /* check for updating an existing job with identical uid */ 844 - hlist_for_each_entry(gwj, &cgw_list, list) { 845 + hlist_for_each_entry(gwj, &net->can.cgw_list, list) { 845 846 846 847 if (gwj->mod.uid != mod.uid) 847 848 continue; ··· 879 880 880 881 err = -ENODEV; 881 882 882 - gwj->src.dev = __dev_get_by_index(&init_net, gwj->ccgw.src_idx); 883 + gwj->src.dev = __dev_get_by_index(net, gwj->ccgw.src_idx); 883 884 884 885 if (!gwj->src.dev) 885 886 goto out; ··· 887 888 if (gwj->src.dev->type != ARPHRD_CAN) 888 889 goto out; 889 890 890 - gwj->dst.dev = __dev_get_by_index(&init_net, gwj->ccgw.dst_idx); 891 + gwj->dst.dev = __dev_get_by_index(net, gwj->ccgw.dst_idx); 891 892 892 893 if (!gwj->dst.dev) 893 894 goto out; ··· 897 898 898 899 ASSERT_RTNL(); 899 900 900 - err = cgw_register_filter(gwj); 901 + err = cgw_register_filter(net, gwj); 901 902 if (!err) 902 - hlist_add_head_rcu(&gwj->list, &cgw_list); 903 + hlist_add_head_rcu(&gwj->list, &net->can.cgw_list); 903 904 out: 904 905 if (err) 905 906 kmem_cache_free(cgw_cache, gwj); ··· 907 908 return err; 908 909 } 909 910 910 - static void cgw_remove_all_jobs(void) 911 + static void cgw_remove_all_jobs(struct net *net) 911 912 { 912 913 struct cgw_job *gwj = NULL; 913 914 struct hlist_node *nx; 914 915 915 916 ASSERT_RTNL(); 916 917 917 - hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) { 918 + hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) { 918 919 hlist_del(&gwj->list); 919 - cgw_unregister_filter(gwj); 920 + cgw_unregister_filter(net, gwj); 920 921 kmem_cache_free(cgw_cache, gwj); 921 922 } 922 923 } ··· 924 925 static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, 925 926 struct netlink_ext_ack *extack) 926 927 { 928 + struct net *net = sock_net(skb->sk); 927 929 struct cgw_job *gwj = NULL; 928 930 struct hlist_node *nx; 929 931 struct rtcanmsg *r; ··· 953 953 954 954 /* two interface indices both set to 0 => remove all entries */ 955 955 if (!ccgw.src_idx && !ccgw.dst_idx) { 956 - cgw_remove_all_jobs(); 956 + cgw_remove_all_jobs(net); 957 957 return 0; 958 958 } 959 959 ··· 962 962 ASSERT_RTNL(); 963 963 964 964 /* 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) { 966 966 967 967 if (gwj->flags != r->flags) 968 968 continue; ··· 985 985 continue; 986 986 987 987 hlist_del(&gwj->list); 988 - cgw_unregister_filter(gwj); 988 + cgw_unregister_filter(net, gwj); 989 989 kmem_cache_free(cgw_cache, gwj); 990 990 err = 0; 991 991 break; ··· 993 993 994 994 return err; 995 995 } 996 + 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 + }; 996 1014 997 1015 static __init int cgw_module_init(void) 998 1016 { ··· 1020 1002 pr_info("can: netlink gateway (rev " CAN_GW_VERSION ") max_hops=%d\n", 1021 1003 max_hops); 1022 1004 1005 + register_pernet_subsys(&cangw_pernet_ops); 1023 1006 cgw_cache = kmem_cache_create("can_gw", sizeof(struct cgw_job), 1024 1007 0, 0, NULL); 1025 1008 ··· 1050 1031 1051 1032 unregister_netdevice_notifier(&notifier); 1052 1033 1053 - rtnl_lock(); 1054 - cgw_remove_all_jobs(); 1055 - rtnl_unlock(); 1056 - 1034 + unregister_pernet_subsys(&cangw_pernet_ops); 1057 1035 rcu_barrier(); /* Wait for completion of call_rcu()'s */ 1058 1036 1059 1037 kmem_cache_destroy(cgw_cache);