diff options
author | Cong Wang <amwang@redhat.com> | 2013-01-28 14:55:53 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-29 15:17:46 -0500 |
commit | 4e58a0275015e5c8988bda9cd0635e2ef405c985 (patch) | |
tree | 743245c3e8b10fb83577b590579c3e593aa693c7 /net/core/pktgen.c | |
parent | dc975382d2ef36be7e78fac3717927de1a5abcd8 (diff) |
pktgen: support net namespace
v3: make pktgen_threads list per-namespace
v2: remove a useless check
This patch add net namespace to pktgen, so that
we can use pktgen in different namespaces.
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/pktgen.c')
-rw-r--r-- | net/core/pktgen.c | 196 |
1 files changed, 117 insertions, 79 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b29dacf900f9..797769551b91 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -164,6 +164,7 @@ | |||
164 | #ifdef CONFIG_XFRM | 164 | #ifdef CONFIG_XFRM |
165 | #include <net/xfrm.h> | 165 | #include <net/xfrm.h> |
166 | #endif | 166 | #endif |
167 | #include <net/netns/generic.h> | ||
167 | #include <asm/byteorder.h> | 168 | #include <asm/byteorder.h> |
168 | #include <linux/rcupdate.h> | 169 | #include <linux/rcupdate.h> |
169 | #include <linux/bitops.h> | 170 | #include <linux/bitops.h> |
@@ -212,7 +213,6 @@ | |||
212 | #define PKTGEN_MAGIC 0xbe9be955 | 213 | #define PKTGEN_MAGIC 0xbe9be955 |
213 | #define PG_PROC_DIR "pktgen" | 214 | #define PG_PROC_DIR "pktgen" |
214 | #define PGCTRL "pgctrl" | 215 | #define PGCTRL "pgctrl" |
215 | static struct proc_dir_entry *pg_proc_dir; | ||
216 | 216 | ||
217 | #define MAX_CFLOWS 65536 | 217 | #define MAX_CFLOWS 65536 |
218 | 218 | ||
@@ -397,7 +397,15 @@ struct pktgen_hdr { | |||
397 | __be32 tv_usec; | 397 | __be32 tv_usec; |
398 | }; | 398 | }; |
399 | 399 | ||
400 | static bool pktgen_exiting __read_mostly; | 400 | |
401 | static int pg_net_id __read_mostly; | ||
402 | |||
403 | struct pktgen_net { | ||
404 | struct net *net; | ||
405 | struct proc_dir_entry *proc_dir; | ||
406 | struct list_head pktgen_threads; | ||
407 | bool pktgen_exiting; | ||
408 | }; | ||
401 | 409 | ||
402 | struct pktgen_thread { | 410 | struct pktgen_thread { |
403 | spinlock_t if_lock; /* for list of devices */ | 411 | spinlock_t if_lock; /* for list of devices */ |
@@ -414,6 +422,7 @@ struct pktgen_thread { | |||
414 | 422 | ||
415 | wait_queue_head_t queue; | 423 | wait_queue_head_t queue; |
416 | struct completion start_done; | 424 | struct completion start_done; |
425 | struct pktgen_net *net; | ||
417 | }; | 426 | }; |
418 | 427 | ||
419 | #define REMOVE 1 | 428 | #define REMOVE 1 |
@@ -428,9 +437,9 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); | |||
428 | static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, | 437 | static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, |
429 | const char *ifname, bool exact); | 438 | const char *ifname, bool exact); |
430 | static int pktgen_device_event(struct notifier_block *, unsigned long, void *); | 439 | static int pktgen_device_event(struct notifier_block *, unsigned long, void *); |
431 | static void pktgen_run_all_threads(void); | 440 | static void pktgen_run_all_threads(struct pktgen_net *pn); |
432 | static void pktgen_reset_all_threads(void); | 441 | static void pktgen_reset_all_threads(struct pktgen_net *pn); |
433 | static void pktgen_stop_all_threads_ifs(void); | 442 | static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn); |
434 | 443 | ||
435 | static void pktgen_stop(struct pktgen_thread *t); | 444 | static void pktgen_stop(struct pktgen_thread *t); |
436 | static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); | 445 | static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); |
@@ -442,7 +451,6 @@ static int pg_clone_skb_d __read_mostly; | |||
442 | static int debug __read_mostly; | 451 | static int debug __read_mostly; |
443 | 452 | ||
444 | static DEFINE_MUTEX(pktgen_thread_lock); | 453 | static DEFINE_MUTEX(pktgen_thread_lock); |
445 | static LIST_HEAD(pktgen_threads); | ||
446 | 454 | ||
447 | static struct notifier_block pktgen_notifier_block = { | 455 | static struct notifier_block pktgen_notifier_block = { |
448 | .notifier_call = pktgen_device_event, | 456 | .notifier_call = pktgen_device_event, |
@@ -464,6 +472,7 @@ static ssize_t pgctrl_write(struct file *file, const char __user *buf, | |||
464 | { | 472 | { |
465 | int err = 0; | 473 | int err = 0; |
466 | char data[128]; | 474 | char data[128]; |
475 | struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id); | ||
467 | 476 | ||
468 | if (!capable(CAP_NET_ADMIN)) { | 477 | if (!capable(CAP_NET_ADMIN)) { |
469 | err = -EPERM; | 478 | err = -EPERM; |
@@ -480,13 +489,13 @@ static ssize_t pgctrl_write(struct file *file, const char __user *buf, | |||
480 | data[count - 1] = 0; /* Make string */ | 489 | data[count - 1] = 0; /* Make string */ |
481 | 490 | ||
482 | if (!strcmp(data, "stop")) | 491 | if (!strcmp(data, "stop")) |
483 | pktgen_stop_all_threads_ifs(); | 492 | pktgen_stop_all_threads_ifs(pn); |
484 | 493 | ||
485 | else if (!strcmp(data, "start")) | 494 | else if (!strcmp(data, "start")) |
486 | pktgen_run_all_threads(); | 495 | pktgen_run_all_threads(pn); |
487 | 496 | ||
488 | else if (!strcmp(data, "reset")) | 497 | else if (!strcmp(data, "reset")) |
489 | pktgen_reset_all_threads(); | 498 | pktgen_reset_all_threads(pn); |
490 | 499 | ||
491 | else | 500 | else |
492 | pr_warning("Unknown command: %s\n", data); | 501 | pr_warning("Unknown command: %s\n", data); |
@@ -1824,13 +1833,14 @@ static const struct file_operations pktgen_thread_fops = { | |||
1824 | }; | 1833 | }; |
1825 | 1834 | ||
1826 | /* Think find or remove for NN */ | 1835 | /* Think find or remove for NN */ |
1827 | static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove) | 1836 | static struct pktgen_dev *__pktgen_NN_threads(const struct pktgen_net *pn, |
1837 | const char *ifname, int remove) | ||
1828 | { | 1838 | { |
1829 | struct pktgen_thread *t; | 1839 | struct pktgen_thread *t; |
1830 | struct pktgen_dev *pkt_dev = NULL; | 1840 | struct pktgen_dev *pkt_dev = NULL; |
1831 | bool exact = (remove == FIND); | 1841 | bool exact = (remove == FIND); |
1832 | 1842 | ||
1833 | list_for_each_entry(t, &pktgen_threads, th_list) { | 1843 | list_for_each_entry(t, &pn->pktgen_threads, th_list) { |
1834 | pkt_dev = pktgen_find_dev(t, ifname, exact); | 1844 | pkt_dev = pktgen_find_dev(t, ifname, exact); |
1835 | if (pkt_dev) { | 1845 | if (pkt_dev) { |
1836 | if (remove) { | 1846 | if (remove) { |
@@ -1848,7 +1858,7 @@ static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove) | |||
1848 | /* | 1858 | /* |
1849 | * mark a device for removal | 1859 | * mark a device for removal |
1850 | */ | 1860 | */ |
1851 | static void pktgen_mark_device(const char *ifname) | 1861 | static void pktgen_mark_device(const struct pktgen_net *pn, const char *ifname) |
1852 | { | 1862 | { |
1853 | struct pktgen_dev *pkt_dev = NULL; | 1863 | struct pktgen_dev *pkt_dev = NULL; |
1854 | const int max_tries = 10, msec_per_try = 125; | 1864 | const int max_tries = 10, msec_per_try = 125; |
@@ -1859,7 +1869,7 @@ static void pktgen_mark_device(const char *ifname) | |||
1859 | 1869 | ||
1860 | while (1) { | 1870 | while (1) { |
1861 | 1871 | ||
1862 | pkt_dev = __pktgen_NN_threads(ifname, REMOVE); | 1872 | pkt_dev = __pktgen_NN_threads(pn, ifname, REMOVE); |
1863 | if (pkt_dev == NULL) | 1873 | if (pkt_dev == NULL) |
1864 | break; /* success */ | 1874 | break; /* success */ |
1865 | 1875 | ||
@@ -1880,21 +1890,21 @@ static void pktgen_mark_device(const char *ifname) | |||
1880 | mutex_unlock(&pktgen_thread_lock); | 1890 | mutex_unlock(&pktgen_thread_lock); |
1881 | } | 1891 | } |
1882 | 1892 | ||
1883 | static void pktgen_change_name(struct net_device *dev) | 1893 | static void pktgen_change_name(const struct pktgen_net *pn, struct net_device *dev) |
1884 | { | 1894 | { |
1885 | struct pktgen_thread *t; | 1895 | struct pktgen_thread *t; |
1886 | 1896 | ||
1887 | list_for_each_entry(t, &pktgen_threads, th_list) { | 1897 | list_for_each_entry(t, &pn->pktgen_threads, th_list) { |
1888 | struct pktgen_dev *pkt_dev; | 1898 | struct pktgen_dev *pkt_dev; |
1889 | 1899 | ||
1890 | list_for_each_entry(pkt_dev, &t->if_list, list) { | 1900 | list_for_each_entry(pkt_dev, &t->if_list, list) { |
1891 | if (pkt_dev->odev != dev) | 1901 | if (pkt_dev->odev != dev) |
1892 | continue; | 1902 | continue; |
1893 | 1903 | ||
1894 | remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); | 1904 | remove_proc_entry(pkt_dev->entry->name, pn->proc_dir); |
1895 | 1905 | ||
1896 | pkt_dev->entry = proc_create_data(dev->name, 0600, | 1906 | pkt_dev->entry = proc_create_data(dev->name, 0600, |
1897 | pg_proc_dir, | 1907 | pn->proc_dir, |
1898 | &pktgen_if_fops, | 1908 | &pktgen_if_fops, |
1899 | pkt_dev); | 1909 | pkt_dev); |
1900 | if (!pkt_dev->entry) | 1910 | if (!pkt_dev->entry) |
@@ -1909,8 +1919,9 @@ static int pktgen_device_event(struct notifier_block *unused, | |||
1909 | unsigned long event, void *ptr) | 1919 | unsigned long event, void *ptr) |
1910 | { | 1920 | { |
1911 | struct net_device *dev = ptr; | 1921 | struct net_device *dev = ptr; |
1922 | struct pktgen_net *pn = net_generic(dev_net(dev), pg_net_id); | ||
1912 | 1923 | ||
1913 | if (!net_eq(dev_net(dev), &init_net) || pktgen_exiting) | 1924 | if (pn->pktgen_exiting) |
1914 | return NOTIFY_DONE; | 1925 | return NOTIFY_DONE; |
1915 | 1926 | ||
1916 | /* It is OK that we do not hold the group lock right now, | 1927 | /* It is OK that we do not hold the group lock right now, |
@@ -1919,18 +1930,19 @@ static int pktgen_device_event(struct notifier_block *unused, | |||
1919 | 1930 | ||
1920 | switch (event) { | 1931 | switch (event) { |
1921 | case NETDEV_CHANGENAME: | 1932 | case NETDEV_CHANGENAME: |
1922 | pktgen_change_name(dev); | 1933 | pktgen_change_name(pn, dev); |
1923 | break; | 1934 | break; |
1924 | 1935 | ||
1925 | case NETDEV_UNREGISTER: | 1936 | case NETDEV_UNREGISTER: |
1926 | pktgen_mark_device(dev->name); | 1937 | pktgen_mark_device(pn, dev->name); |
1927 | break; | 1938 | break; |
1928 | } | 1939 | } |
1929 | 1940 | ||
1930 | return NOTIFY_DONE; | 1941 | return NOTIFY_DONE; |
1931 | } | 1942 | } |
1932 | 1943 | ||
1933 | static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, | 1944 | static struct net_device *pktgen_dev_get_by_name(const struct pktgen_net *pn, |
1945 | struct pktgen_dev *pkt_dev, | ||
1934 | const char *ifname) | 1946 | const char *ifname) |
1935 | { | 1947 | { |
1936 | char b[IFNAMSIZ+5]; | 1948 | char b[IFNAMSIZ+5]; |
@@ -1944,13 +1956,14 @@ static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, | |||
1944 | } | 1956 | } |
1945 | b[i] = 0; | 1957 | b[i] = 0; |
1946 | 1958 | ||
1947 | return dev_get_by_name(&init_net, b); | 1959 | return dev_get_by_name(pn->net, b); |
1948 | } | 1960 | } |
1949 | 1961 | ||
1950 | 1962 | ||
1951 | /* Associate pktgen_dev with a device. */ | 1963 | /* Associate pktgen_dev with a device. */ |
1952 | 1964 | ||
1953 | static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname) | 1965 | static int pktgen_setup_dev(const struct pktgen_net *pn, |
1966 | struct pktgen_dev *pkt_dev, const char *ifname) | ||
1954 | { | 1967 | { |
1955 | struct net_device *odev; | 1968 | struct net_device *odev; |
1956 | int err; | 1969 | int err; |
@@ -1961,7 +1974,7 @@ static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname) | |||
1961 | pkt_dev->odev = NULL; | 1974 | pkt_dev->odev = NULL; |
1962 | } | 1975 | } |
1963 | 1976 | ||
1964 | odev = pktgen_dev_get_by_name(pkt_dev, ifname); | 1977 | odev = pktgen_dev_get_by_name(pn, pkt_dev, ifname); |
1965 | if (!odev) { | 1978 | if (!odev) { |
1966 | pr_err("no such netdevice: \"%s\"\n", ifname); | 1979 | pr_err("no such netdevice: \"%s\"\n", ifname); |
1967 | return -ENODEV; | 1980 | return -ENODEV; |
@@ -2203,9 +2216,10 @@ static inline int f_pick(struct pktgen_dev *pkt_dev) | |||
2203 | static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) | 2216 | static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) |
2204 | { | 2217 | { |
2205 | struct xfrm_state *x = pkt_dev->flows[flow].x; | 2218 | struct xfrm_state *x = pkt_dev->flows[flow].x; |
2219 | struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id); | ||
2206 | if (!x) { | 2220 | if (!x) { |
2207 | /*slow path: we dont already have xfrm_state*/ | 2221 | /*slow path: we dont already have xfrm_state*/ |
2208 | x = xfrm_stateonly_find(&init_net, DUMMY_MARK, | 2222 | x = xfrm_stateonly_find(pn->net, DUMMY_MARK, |
2209 | (xfrm_address_t *)&pkt_dev->cur_daddr, | 2223 | (xfrm_address_t *)&pkt_dev->cur_daddr, |
2210 | (xfrm_address_t *)&pkt_dev->cur_saddr, | 2224 | (xfrm_address_t *)&pkt_dev->cur_saddr, |
2211 | AF_INET, | 2225 | AF_INET, |
@@ -2912,7 +2926,7 @@ static void pktgen_run(struct pktgen_thread *t) | |||
2912 | t->control &= ~(T_STOP); | 2926 | t->control &= ~(T_STOP); |
2913 | } | 2927 | } |
2914 | 2928 | ||
2915 | static void pktgen_stop_all_threads_ifs(void) | 2929 | static void pktgen_stop_all_threads_ifs(struct pktgen_net *pn) |
2916 | { | 2930 | { |
2917 | struct pktgen_thread *t; | 2931 | struct pktgen_thread *t; |
2918 | 2932 | ||
@@ -2920,7 +2934,7 @@ static void pktgen_stop_all_threads_ifs(void) | |||
2920 | 2934 | ||
2921 | mutex_lock(&pktgen_thread_lock); | 2935 | mutex_lock(&pktgen_thread_lock); |
2922 | 2936 | ||
2923 | list_for_each_entry(t, &pktgen_threads, th_list) | 2937 | list_for_each_entry(t, &pn->pktgen_threads, th_list) |
2924 | t->control |= T_STOP; | 2938 | t->control |= T_STOP; |
2925 | 2939 | ||
2926 | mutex_unlock(&pktgen_thread_lock); | 2940 | mutex_unlock(&pktgen_thread_lock); |
@@ -2956,28 +2970,28 @@ signal: | |||
2956 | return 0; | 2970 | return 0; |
2957 | } | 2971 | } |
2958 | 2972 | ||
2959 | static int pktgen_wait_all_threads_run(void) | 2973 | static int pktgen_wait_all_threads_run(struct pktgen_net *pn) |
2960 | { | 2974 | { |
2961 | struct pktgen_thread *t; | 2975 | struct pktgen_thread *t; |
2962 | int sig = 1; | 2976 | int sig = 1; |
2963 | 2977 | ||
2964 | mutex_lock(&pktgen_thread_lock); | 2978 | mutex_lock(&pktgen_thread_lock); |
2965 | 2979 | ||
2966 | list_for_each_entry(t, &pktgen_threads, th_list) { | 2980 | list_for_each_entry(t, &pn->pktgen_threads, th_list) { |
2967 | sig = pktgen_wait_thread_run(t); | 2981 | sig = pktgen_wait_thread_run(t); |
2968 | if (sig == 0) | 2982 | if (sig == 0) |
2969 | break; | 2983 | break; |
2970 | } | 2984 | } |
2971 | 2985 | ||
2972 | if (sig == 0) | 2986 | if (sig == 0) |
2973 | list_for_each_entry(t, &pktgen_threads, th_list) | 2987 | list_for_each_entry(t, &pn->pktgen_threads, th_list) |
2974 | t->control |= (T_STOP); | 2988 | t->control |= (T_STOP); |
2975 | 2989 | ||
2976 | mutex_unlock(&pktgen_thread_lock); | 2990 | mutex_unlock(&pktgen_thread_lock); |
2977 | return sig; | 2991 | return sig; |
2978 | } | 2992 | } |
2979 | 2993 | ||
2980 | static void pktgen_run_all_threads(void) | 2994 | static void pktgen_run_all_threads(struct pktgen_net *pn) |
2981 | { | 2995 | { |
2982 | struct pktgen_thread *t; | 2996 | struct pktgen_thread *t; |
2983 | 2997 | ||
@@ -2985,7 +2999,7 @@ static void pktgen_run_all_threads(void) | |||
2985 | 2999 | ||
2986 | mutex_lock(&pktgen_thread_lock); | 3000 | mutex_lock(&pktgen_thread_lock); |
2987 | 3001 | ||
2988 | list_for_each_entry(t, &pktgen_threads, th_list) | 3002 | list_for_each_entry(t, &pn->pktgen_threads, th_list) |
2989 | t->control |= (T_RUN); | 3003 | t->control |= (T_RUN); |
2990 | 3004 | ||
2991 | mutex_unlock(&pktgen_thread_lock); | 3005 | mutex_unlock(&pktgen_thread_lock); |
@@ -2993,10 +3007,10 @@ static void pktgen_run_all_threads(void) | |||
2993 | /* Propagate thread->control */ | 3007 | /* Propagate thread->control */ |
2994 | schedule_timeout_interruptible(msecs_to_jiffies(125)); | 3008 | schedule_timeout_interruptible(msecs_to_jiffies(125)); |
2995 | 3009 | ||
2996 | pktgen_wait_all_threads_run(); | 3010 | pktgen_wait_all_threads_run(pn); |
2997 | } | 3011 | } |
2998 | 3012 | ||
2999 | static void pktgen_reset_all_threads(void) | 3013 | static void pktgen_reset_all_threads(struct pktgen_net *pn) |
3000 | { | 3014 | { |
3001 | struct pktgen_thread *t; | 3015 | struct pktgen_thread *t; |
3002 | 3016 | ||
@@ -3004,7 +3018,7 @@ static void pktgen_reset_all_threads(void) | |||
3004 | 3018 | ||
3005 | mutex_lock(&pktgen_thread_lock); | 3019 | mutex_lock(&pktgen_thread_lock); |
3006 | 3020 | ||
3007 | list_for_each_entry(t, &pktgen_threads, th_list) | 3021 | list_for_each_entry(t, &pn->pktgen_threads, th_list) |
3008 | t->control |= (T_REMDEVALL); | 3022 | t->control |= (T_REMDEVALL); |
3009 | 3023 | ||
3010 | mutex_unlock(&pktgen_thread_lock); | 3024 | mutex_unlock(&pktgen_thread_lock); |
@@ -3012,7 +3026,7 @@ static void pktgen_reset_all_threads(void) | |||
3012 | /* Propagate thread->control */ | 3026 | /* Propagate thread->control */ |
3013 | schedule_timeout_interruptible(msecs_to_jiffies(125)); | 3027 | schedule_timeout_interruptible(msecs_to_jiffies(125)); |
3014 | 3028 | ||
3015 | pktgen_wait_all_threads_run(); | 3029 | pktgen_wait_all_threads_run(pn); |
3016 | } | 3030 | } |
3017 | 3031 | ||
3018 | static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) | 3032 | static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) |
@@ -3154,9 +3168,7 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t) | |||
3154 | static void pktgen_rem_thread(struct pktgen_thread *t) | 3168 | static void pktgen_rem_thread(struct pktgen_thread *t) |
3155 | { | 3169 | { |
3156 | /* Remove from the thread list */ | 3170 | /* Remove from the thread list */ |
3157 | 3171 | remove_proc_entry(t->tsk->comm, t->net->proc_dir); | |
3158 | remove_proc_entry(t->tsk->comm, pg_proc_dir); | ||
3159 | |||
3160 | } | 3172 | } |
3161 | 3173 | ||
3162 | static void pktgen_resched(struct pktgen_dev *pkt_dev) | 3174 | static void pktgen_resched(struct pktgen_dev *pkt_dev) |
@@ -3302,7 +3314,7 @@ static int pktgen_thread_worker(void *arg) | |||
3302 | pkt_dev = next_to_run(t); | 3314 | pkt_dev = next_to_run(t); |
3303 | 3315 | ||
3304 | if (unlikely(!pkt_dev && t->control == 0)) { | 3316 | if (unlikely(!pkt_dev && t->control == 0)) { |
3305 | if (pktgen_exiting) | 3317 | if (t->net->pktgen_exiting) |
3306 | break; | 3318 | break; |
3307 | wait_event_interruptible_timeout(t->queue, | 3319 | wait_event_interruptible_timeout(t->queue, |
3308 | t->control != 0, | 3320 | t->control != 0, |
@@ -3424,7 +3436,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) | |||
3424 | 3436 | ||
3425 | /* We don't allow a device to be on several threads */ | 3437 | /* We don't allow a device to be on several threads */ |
3426 | 3438 | ||
3427 | pkt_dev = __pktgen_NN_threads(ifname, FIND); | 3439 | pkt_dev = __pktgen_NN_threads(t->net, ifname, FIND); |
3428 | if (pkt_dev) { | 3440 | if (pkt_dev) { |
3429 | pr_err("ERROR: interface already used\n"); | 3441 | pr_err("ERROR: interface already used\n"); |
3430 | return -EBUSY; | 3442 | return -EBUSY; |
@@ -3459,13 +3471,13 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) | |||
3459 | pkt_dev->svlan_id = 0xffff; | 3471 | pkt_dev->svlan_id = 0xffff; |
3460 | pkt_dev->node = -1; | 3472 | pkt_dev->node = -1; |
3461 | 3473 | ||
3462 | err = pktgen_setup_dev(pkt_dev, ifname); | 3474 | err = pktgen_setup_dev(t->net, pkt_dev, ifname); |
3463 | if (err) | 3475 | if (err) |
3464 | goto out1; | 3476 | goto out1; |
3465 | if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING) | 3477 | if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING) |
3466 | pkt_dev->clone_skb = pg_clone_skb_d; | 3478 | pkt_dev->clone_skb = pg_clone_skb_d; |
3467 | 3479 | ||
3468 | pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir, | 3480 | pkt_dev->entry = proc_create_data(ifname, 0600, t->net->proc_dir, |
3469 | &pktgen_if_fops, pkt_dev); | 3481 | &pktgen_if_fops, pkt_dev); |
3470 | if (!pkt_dev->entry) { | 3482 | if (!pkt_dev->entry) { |
3471 | pr_err("cannot create %s/%s procfs entry\n", | 3483 | pr_err("cannot create %s/%s procfs entry\n", |
@@ -3490,7 +3502,7 @@ out1: | |||
3490 | return err; | 3502 | return err; |
3491 | } | 3503 | } |
3492 | 3504 | ||
3493 | static int __init pktgen_create_thread(int cpu) | 3505 | static int __net_init pktgen_create_thread(int cpu, struct pktgen_net *pn) |
3494 | { | 3506 | { |
3495 | struct pktgen_thread *t; | 3507 | struct pktgen_thread *t; |
3496 | struct proc_dir_entry *pe; | 3508 | struct proc_dir_entry *pe; |
@@ -3508,7 +3520,7 @@ static int __init pktgen_create_thread(int cpu) | |||
3508 | 3520 | ||
3509 | INIT_LIST_HEAD(&t->if_list); | 3521 | INIT_LIST_HEAD(&t->if_list); |
3510 | 3522 | ||
3511 | list_add_tail(&t->th_list, &pktgen_threads); | 3523 | list_add_tail(&t->th_list, &pn->pktgen_threads); |
3512 | init_completion(&t->start_done); | 3524 | init_completion(&t->start_done); |
3513 | 3525 | ||
3514 | p = kthread_create_on_node(pktgen_thread_worker, | 3526 | p = kthread_create_on_node(pktgen_thread_worker, |
@@ -3524,7 +3536,7 @@ static int __init pktgen_create_thread(int cpu) | |||
3524 | kthread_bind(p, cpu); | 3536 | kthread_bind(p, cpu); |
3525 | t->tsk = p; | 3537 | t->tsk = p; |
3526 | 3538 | ||
3527 | pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir, | 3539 | pe = proc_create_data(t->tsk->comm, 0600, pn->proc_dir, |
3528 | &pktgen_thread_fops, t); | 3540 | &pktgen_thread_fops, t); |
3529 | if (!pe) { | 3541 | if (!pe) { |
3530 | pr_err("cannot create %s/%s procfs entry\n", | 3542 | pr_err("cannot create %s/%s procfs entry\n", |
@@ -3535,6 +3547,7 @@ static int __init pktgen_create_thread(int cpu) | |||
3535 | return -EINVAL; | 3547 | return -EINVAL; |
3536 | } | 3548 | } |
3537 | 3549 | ||
3550 | t->net = pn; | ||
3538 | wake_up_process(p); | 3551 | wake_up_process(p); |
3539 | wait_for_completion(&t->start_done); | 3552 | wait_for_completion(&t->start_done); |
3540 | 3553 | ||
@@ -3560,6 +3573,7 @@ static void _rem_dev_from_if_list(struct pktgen_thread *t, | |||
3560 | static int pktgen_remove_device(struct pktgen_thread *t, | 3573 | static int pktgen_remove_device(struct pktgen_thread *t, |
3561 | struct pktgen_dev *pkt_dev) | 3574 | struct pktgen_dev *pkt_dev) |
3562 | { | 3575 | { |
3576 | struct pktgen_net *pn = t->net; | ||
3563 | 3577 | ||
3564 | pr_debug("remove_device pkt_dev=%p\n", pkt_dev); | 3578 | pr_debug("remove_device pkt_dev=%p\n", pkt_dev); |
3565 | 3579 | ||
@@ -3580,7 +3594,7 @@ static int pktgen_remove_device(struct pktgen_thread *t, | |||
3580 | _rem_dev_from_if_list(t, pkt_dev); | 3594 | _rem_dev_from_if_list(t, pkt_dev); |
3581 | 3595 | ||
3582 | if (pkt_dev->entry) | 3596 | if (pkt_dev->entry) |
3583 | remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); | 3597 | remove_proc_entry(pkt_dev->entry->name, pn->proc_dir); |
3584 | 3598 | ||
3585 | #ifdef CONFIG_XFRM | 3599 | #ifdef CONFIG_XFRM |
3586 | free_SAs(pkt_dev); | 3600 | free_SAs(pkt_dev); |
@@ -3592,63 +3606,63 @@ static int pktgen_remove_device(struct pktgen_thread *t, | |||
3592 | return 0; | 3606 | return 0; |
3593 | } | 3607 | } |
3594 | 3608 | ||
3595 | static int __init pg_init(void) | 3609 | static int __net_init pg_net_init(struct net *net) |
3596 | { | 3610 | { |
3597 | int cpu; | 3611 | struct pktgen_net *pn = net_generic(net, pg_net_id); |
3598 | struct proc_dir_entry *pe; | 3612 | struct proc_dir_entry *pe; |
3599 | int ret = 0; | 3613 | int cpu, ret = 0; |
3600 | 3614 | ||
3601 | pr_info("%s", version); | 3615 | pn->net = net; |
3602 | 3616 | INIT_LIST_HEAD(&pn->pktgen_threads); | |
3603 | pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net); | 3617 | pn->pktgen_exiting = false; |
3604 | if (!pg_proc_dir) | 3618 | pn->proc_dir = proc_mkdir(PG_PROC_DIR, pn->net->proc_net); |
3619 | if (!pn->proc_dir) { | ||
3620 | pr_warn("cannot create /proc/net/%s\n", PG_PROC_DIR); | ||
3605 | return -ENODEV; | 3621 | return -ENODEV; |
3606 | 3622 | } | |
3607 | pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops); | 3623 | pe = proc_create(PGCTRL, 0600, pn->proc_dir, &pktgen_fops); |
3608 | if (pe == NULL) { | 3624 | if (pe == NULL) { |
3609 | pr_err("ERROR: cannot create %s procfs entry\n", PGCTRL); | 3625 | pr_err("cannot create %s procfs entry\n", PGCTRL); |
3610 | ret = -EINVAL; | 3626 | ret = -EINVAL; |
3611 | goto remove_dir; | 3627 | goto remove; |
3612 | } | 3628 | } |
3613 | 3629 | ||
3614 | register_netdevice_notifier(&pktgen_notifier_block); | ||
3615 | |||
3616 | for_each_online_cpu(cpu) { | 3630 | for_each_online_cpu(cpu) { |
3617 | int err; | 3631 | int err; |
3618 | 3632 | ||
3619 | err = pktgen_create_thread(cpu); | 3633 | err = pktgen_create_thread(cpu, pn); |
3620 | if (err) | 3634 | if (err) |
3621 | pr_warning("WARNING: Cannot create thread for cpu %d (%d)\n", | 3635 | pr_warn("Cannot create thread for cpu %d (%d)\n", |
3622 | cpu, err); | 3636 | cpu, err); |
3623 | } | 3637 | } |
3624 | 3638 | ||
3625 | if (list_empty(&pktgen_threads)) { | 3639 | if (list_empty(&pn->pktgen_threads)) { |
3626 | pr_err("ERROR: Initialization failed for all threads\n"); | 3640 | pr_err("Initialization failed for all threads\n"); |
3627 | ret = -ENODEV; | 3641 | ret = -ENODEV; |
3628 | goto unregister; | 3642 | goto remove_entry; |
3629 | } | 3643 | } |
3630 | 3644 | ||
3631 | return 0; | 3645 | return 0; |
3632 | 3646 | ||
3633 | unregister: | 3647 | remove_entry: |
3634 | unregister_netdevice_notifier(&pktgen_notifier_block); | 3648 | remove_proc_entry(PGCTRL, pn->proc_dir); |
3635 | remove_proc_entry(PGCTRL, pg_proc_dir); | 3649 | remove: |
3636 | remove_dir: | 3650 | proc_net_remove(pn->net, PG_PROC_DIR); |
3637 | proc_net_remove(&init_net, PG_PROC_DIR); | ||
3638 | return ret; | 3651 | return ret; |
3639 | } | 3652 | } |
3640 | 3653 | ||
3641 | static void __exit pg_cleanup(void) | 3654 | static void __net_exit pg_net_exit(struct net *net) |
3642 | { | 3655 | { |
3656 | struct pktgen_net *pn = net_generic(net, pg_net_id); | ||
3643 | struct pktgen_thread *t; | 3657 | struct pktgen_thread *t; |
3644 | struct list_head *q, *n; | 3658 | struct list_head *q, *n; |
3645 | LIST_HEAD(list); | 3659 | LIST_HEAD(list); |
3646 | 3660 | ||
3647 | /* Stop all interfaces & threads */ | 3661 | /* Stop all interfaces & threads */ |
3648 | pktgen_exiting = true; | 3662 | pn->pktgen_exiting = true; |
3649 | 3663 | ||
3650 | mutex_lock(&pktgen_thread_lock); | 3664 | mutex_lock(&pktgen_thread_lock); |
3651 | list_splice_init(&pktgen_threads, &list); | 3665 | list_splice_init(&pn->pktgen_threads, &list); |
3652 | mutex_unlock(&pktgen_thread_lock); | 3666 | mutex_unlock(&pktgen_thread_lock); |
3653 | 3667 | ||
3654 | list_for_each_safe(q, n, &list) { | 3668 | list_for_each_safe(q, n, &list) { |
@@ -3658,12 +3672,36 @@ static void __exit pg_cleanup(void) | |||
3658 | kfree(t); | 3672 | kfree(t); |
3659 | } | 3673 | } |
3660 | 3674 | ||
3661 | /* Un-register us from receiving netdevice events */ | 3675 | remove_proc_entry(PGCTRL, pn->proc_dir); |
3662 | unregister_netdevice_notifier(&pktgen_notifier_block); | 3676 | proc_net_remove(pn->net, PG_PROC_DIR); |
3677 | } | ||
3678 | |||
3679 | static struct pernet_operations pg_net_ops = { | ||
3680 | .init = pg_net_init, | ||
3681 | .exit = pg_net_exit, | ||
3682 | .id = &pg_net_id, | ||
3683 | .size = sizeof(struct pktgen_net), | ||
3684 | }; | ||
3685 | |||
3686 | static int __init pg_init(void) | ||
3687 | { | ||
3688 | int ret = 0; | ||
3663 | 3689 | ||
3664 | /* Clean up proc file system */ | 3690 | pr_info("%s", version); |
3665 | remove_proc_entry(PGCTRL, pg_proc_dir); | 3691 | ret = register_pernet_subsys(&pg_net_ops); |
3666 | proc_net_remove(&init_net, PG_PROC_DIR); | 3692 | if (ret) |
3693 | return ret; | ||
3694 | ret = register_netdevice_notifier(&pktgen_notifier_block); | ||
3695 | if (ret) | ||
3696 | unregister_pernet_subsys(&pg_net_ops); | ||
3697 | |||
3698 | return ret; | ||
3699 | } | ||
3700 | |||
3701 | static void __exit pg_cleanup(void) | ||
3702 | { | ||
3703 | unregister_netdevice_notifier(&pktgen_notifier_block); | ||
3704 | unregister_pernet_subsys(&pg_net_ops); | ||
3667 | } | 3705 | } |
3668 | 3706 | ||
3669 | module_init(pg_init); | 3707 | module_init(pg_init); |