diff options
author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-03-04 19:11:51 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:23:31 -0400 |
commit | 39df232f1a9ba48d41c68ee7d4046756e709cf91 (patch) | |
tree | 8778c69e9b70f55d9c3161674887f3de217a0d6a | |
parent | d5f1ce9a5e80fb315c86b036a89b1237fdf11938 (diff) |
[PKTGEN]: fix device name handling
Since devices can change name and other wierdness, don't hold onto
a copy of device name, instead use pointer to output device.
Fix a couple of leaks in error handling path as well.
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/core/pktgen.c | 137 |
1 files changed, 70 insertions, 67 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index edf46fbb27d1..895739fdfac3 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -211,15 +211,11 @@ struct flow_state { | |||
211 | }; | 211 | }; |
212 | 212 | ||
213 | struct pktgen_dev { | 213 | struct pktgen_dev { |
214 | |||
215 | /* | 214 | /* |
216 | * Try to keep frequent/infrequent used vars. separated. | 215 | * Try to keep frequent/infrequent used vars. separated. |
217 | */ | 216 | */ |
218 | 217 | struct proc_dir_entry *entry; /* proc file */ | |
219 | char ifname[IFNAMSIZ]; | 218 | struct pktgen_thread *pg_thread;/* the owner */ |
220 | char result[512]; | ||
221 | |||
222 | struct pktgen_thread *pg_thread; /* the owner */ | ||
223 | struct list_head list; /* Used for chaining in the thread's run-queue */ | 219 | struct list_head list; /* Used for chaining in the thread's run-queue */ |
224 | 220 | ||
225 | int running; /* if this changes to false, the test will stop */ | 221 | int running; /* if this changes to false, the test will stop */ |
@@ -346,6 +342,8 @@ struct pktgen_dev { | |||
346 | unsigned cflows; /* Concurrent flows (config) */ | 342 | unsigned cflows; /* Concurrent flows (config) */ |
347 | unsigned lflow; /* Flow length (config) */ | 343 | unsigned lflow; /* Flow length (config) */ |
348 | unsigned nflows; /* accumulated flows (stats) */ | 344 | unsigned nflows; /* accumulated flows (stats) */ |
345 | |||
346 | char result[512]; | ||
349 | }; | 347 | }; |
350 | 348 | ||
351 | struct pktgen_hdr { | 349 | struct pktgen_hdr { |
@@ -498,7 +496,7 @@ static void pktgen_stop_all_threads_ifs(void); | |||
498 | static int pktgen_stop_device(struct pktgen_dev *pkt_dev); | 496 | static int pktgen_stop_device(struct pktgen_dev *pkt_dev); |
499 | static void pktgen_stop(struct pktgen_thread *t); | 497 | static void pktgen_stop(struct pktgen_thread *t); |
500 | static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); | 498 | static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); |
501 | static int pktgen_mark_device(const char *ifname); | 499 | |
502 | static unsigned int scan_ip6(const char *s, char ip[16]); | 500 | static unsigned int scan_ip6(const char *s, char ip[16]); |
503 | static unsigned int fmt_ip6(char *s, const char ip[16]); | 501 | static unsigned int fmt_ip6(char *s, const char ip[16]); |
504 | 502 | ||
@@ -592,7 +590,7 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
592 | " frags: %d delay: %u clone_skb: %d ifname: %s\n", | 590 | " frags: %d delay: %u clone_skb: %d ifname: %s\n", |
593 | pkt_dev->nfrags, | 591 | pkt_dev->nfrags, |
594 | 1000 * pkt_dev->delay_us + pkt_dev->delay_ns, | 592 | 1000 * pkt_dev->delay_us + pkt_dev->delay_ns, |
595 | pkt_dev->clone_skb, pkt_dev->ifname); | 593 | pkt_dev->clone_skb, pkt_dev->odev->name); |
596 | 594 | ||
597 | seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, | 595 | seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, |
598 | pkt_dev->lflow); | 596 | pkt_dev->lflow); |
@@ -1683,13 +1681,13 @@ static int pktgen_thread_show(struct seq_file *seq, void *v) | |||
1683 | if_lock(t); | 1681 | if_lock(t); |
1684 | list_for_each_entry(pkt_dev, &t->if_list, list) | 1682 | list_for_each_entry(pkt_dev, &t->if_list, list) |
1685 | if (pkt_dev->running) | 1683 | if (pkt_dev->running) |
1686 | seq_printf(seq, "%s ", pkt_dev->ifname); | 1684 | seq_printf(seq, "%s ", pkt_dev->odev->name); |
1687 | 1685 | ||
1688 | seq_printf(seq, "\nStopped: "); | 1686 | seq_printf(seq, "\nStopped: "); |
1689 | 1687 | ||
1690 | list_for_each_entry(pkt_dev, &t->if_list, list) | 1688 | list_for_each_entry(pkt_dev, &t->if_list, list) |
1691 | if (!pkt_dev->running) | 1689 | if (!pkt_dev->running) |
1692 | seq_printf(seq, "%s ", pkt_dev->ifname); | 1690 | seq_printf(seq, "%s ", pkt_dev->odev->name); |
1693 | 1691 | ||
1694 | if (t->result[0]) | 1692 | if (t->result[0]) |
1695 | seq_printf(seq, "\nResult: %s\n", t->result); | 1693 | seq_printf(seq, "\nResult: %s\n", t->result); |
@@ -1835,12 +1833,11 @@ static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove) | |||
1835 | /* | 1833 | /* |
1836 | * mark a device for removal | 1834 | * mark a device for removal |
1837 | */ | 1835 | */ |
1838 | static int pktgen_mark_device(const char *ifname) | 1836 | static void pktgen_mark_device(const char *ifname) |
1839 | { | 1837 | { |
1840 | struct pktgen_dev *pkt_dev = NULL; | 1838 | struct pktgen_dev *pkt_dev = NULL; |
1841 | const int max_tries = 10, msec_per_try = 125; | 1839 | const int max_tries = 10, msec_per_try = 125; |
1842 | int i = 0; | 1840 | int i = 0; |
1843 | int ret = 0; | ||
1844 | 1841 | ||
1845 | mutex_lock(&pktgen_thread_lock); | 1842 | mutex_lock(&pktgen_thread_lock); |
1846 | pr_debug("pktgen: pktgen_mark_device marking %s for removal\n", ifname); | 1843 | pr_debug("pktgen: pktgen_mark_device marking %s for removal\n", ifname); |
@@ -1861,32 +1858,49 @@ static int pktgen_mark_device(const char *ifname) | |||
1861 | printk("pktgen_mark_device: timed out after waiting " | 1858 | printk("pktgen_mark_device: timed out after waiting " |
1862 | "%d msec for device %s to be removed\n", | 1859 | "%d msec for device %s to be removed\n", |
1863 | msec_per_try * i, ifname); | 1860 | msec_per_try * i, ifname); |
1864 | ret = 1; | ||
1865 | break; | 1861 | break; |
1866 | } | 1862 | } |
1867 | 1863 | ||
1868 | } | 1864 | } |
1869 | 1865 | ||
1870 | mutex_unlock(&pktgen_thread_lock); | 1866 | mutex_unlock(&pktgen_thread_lock); |
1867 | } | ||
1871 | 1868 | ||
1872 | return ret; | 1869 | static void pktgen_change_name(struct net_device *dev) |
1870 | { | ||
1871 | struct pktgen_thread *t; | ||
1872 | |||
1873 | list_for_each_entry(t, &pktgen_threads, th_list) { | ||
1874 | struct pktgen_dev *pkt_dev; | ||
1875 | |||
1876 | list_for_each_entry(pkt_dev, &t->if_list, list) { | ||
1877 | if (pkt_dev->odev != dev) | ||
1878 | continue; | ||
1879 | |||
1880 | remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); | ||
1881 | |||
1882 | pkt_dev->entry = create_proc_entry(dev->name, 0600, | ||
1883 | pg_proc_dir); | ||
1884 | if (!pkt_dev->entry) | ||
1885 | printk(KERN_ERR "pktgen: can't move proc " | ||
1886 | " entry for '%s'\n", dev->name); | ||
1887 | break; | ||
1888 | } | ||
1889 | } | ||
1873 | } | 1890 | } |
1874 | 1891 | ||
1875 | static int pktgen_device_event(struct notifier_block *unused, | 1892 | static int pktgen_device_event(struct notifier_block *unused, |
1876 | unsigned long event, void *ptr) | 1893 | unsigned long event, void *ptr) |
1877 | { | 1894 | { |
1878 | struct net_device *dev = (struct net_device *)(ptr); | 1895 | struct net_device *dev = ptr; |
1879 | 1896 | ||
1880 | /* It is OK that we do not hold the group lock right now, | 1897 | /* It is OK that we do not hold the group lock right now, |
1881 | * as we run under the RTNL lock. | 1898 | * as we run under the RTNL lock. |
1882 | */ | 1899 | */ |
1883 | 1900 | ||
1884 | switch (event) { | 1901 | switch (event) { |
1885 | case NETDEV_CHANGEADDR: | 1902 | case NETDEV_CHANGENAME: |
1886 | case NETDEV_GOING_DOWN: | 1903 | pktgen_change_name(dev); |
1887 | case NETDEV_DOWN: | ||
1888 | case NETDEV_UP: | ||
1889 | /* Ignore for now */ | ||
1890 | break; | 1904 | break; |
1891 | 1905 | ||
1892 | case NETDEV_UNREGISTER: | 1906 | case NETDEV_UNREGISTER: |
@@ -1899,41 +1913,36 @@ static int pktgen_device_event(struct notifier_block *unused, | |||
1899 | 1913 | ||
1900 | /* Associate pktgen_dev with a device. */ | 1914 | /* Associate pktgen_dev with a device. */ |
1901 | 1915 | ||
1902 | static struct net_device *pktgen_setup_dev(struct pktgen_dev *pkt_dev) | 1916 | static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname) |
1903 | { | 1917 | { |
1904 | struct net_device *odev; | 1918 | struct net_device *odev; |
1919 | int err; | ||
1905 | 1920 | ||
1906 | /* Clean old setups */ | 1921 | /* Clean old setups */ |
1907 | |||
1908 | if (pkt_dev->odev) { | 1922 | if (pkt_dev->odev) { |
1909 | dev_put(pkt_dev->odev); | 1923 | dev_put(pkt_dev->odev); |
1910 | pkt_dev->odev = NULL; | 1924 | pkt_dev->odev = NULL; |
1911 | } | 1925 | } |
1912 | 1926 | ||
1913 | odev = dev_get_by_name(pkt_dev->ifname); | 1927 | odev = dev_get_by_name(ifname); |
1914 | |||
1915 | if (!odev) { | 1928 | if (!odev) { |
1916 | printk("pktgen: no such netdevice: \"%s\"\n", pkt_dev->ifname); | 1929 | printk("pktgen: no such netdevice: \"%s\"\n", ifname); |
1917 | goto out; | 1930 | return -ENODEV; |
1918 | } | 1931 | } |
1932 | |||
1919 | if (odev->type != ARPHRD_ETHER) { | 1933 | if (odev->type != ARPHRD_ETHER) { |
1920 | printk("pktgen: not an ethernet device: \"%s\"\n", | 1934 | printk("pktgen: not an ethernet device: \"%s\"\n", ifname); |
1921 | pkt_dev->ifname); | 1935 | err = -EINVAL; |
1922 | goto out_put; | 1936 | } else if (!netif_running(odev)) { |
1923 | } | 1937 | printk("pktgen: device is down: \"%s\"\n", ifname); |
1924 | if (!netif_running(odev)) { | 1938 | err = -ENETDOWN; |
1925 | printk("pktgen: device is down: \"%s\"\n", pkt_dev->ifname); | 1939 | } else { |
1926 | goto out_put; | 1940 | pkt_dev->odev = odev; |
1941 | return 0; | ||
1927 | } | 1942 | } |
1928 | pkt_dev->odev = odev; | ||
1929 | 1943 | ||
1930 | return pkt_dev->odev; | ||
1931 | |||
1932 | out_put: | ||
1933 | dev_put(odev); | 1944 | dev_put(odev); |
1934 | out: | 1945 | return err; |
1935 | return NULL; | ||
1936 | |||
1937 | } | 1946 | } |
1938 | 1947 | ||
1939 | /* Read pkt_dev from the interface and set up internal pktgen_dev | 1948 | /* Read pkt_dev from the interface and set up internal pktgen_dev |
@@ -1941,10 +1950,6 @@ out: | |||
1941 | */ | 1950 | */ |
1942 | static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | 1951 | static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) |
1943 | { | 1952 | { |
1944 | /* Try once more, just in case it works now. */ | ||
1945 | if (!pkt_dev->odev) | ||
1946 | pktgen_setup_dev(pkt_dev); | ||
1947 | |||
1948 | if (!pkt_dev->odev) { | 1953 | if (!pkt_dev->odev) { |
1949 | printk("pktgen: ERROR: pkt_dev->odev == NULL in setup_inject.\n"); | 1954 | printk("pktgen: ERROR: pkt_dev->odev == NULL in setup_inject.\n"); |
1950 | sprintf(pkt_dev->result, | 1955 | sprintf(pkt_dev->result, |
@@ -2988,7 +2993,7 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev) | |||
2988 | 2993 | ||
2989 | if (!pkt_dev->running) { | 2994 | if (!pkt_dev->running) { |
2990 | printk("pktgen: interface: %s is already stopped\n", | 2995 | printk("pktgen: interface: %s is already stopped\n", |
2991 | pkt_dev->ifname); | 2996 | pkt_dev->odev->name); |
2992 | return -EINVAL; | 2997 | return -EINVAL; |
2993 | } | 2998 | } |
2994 | 2999 | ||
@@ -3340,7 +3345,7 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, | |||
3340 | if_lock(t); | 3345 | if_lock(t); |
3341 | 3346 | ||
3342 | list_for_each_entry(p, &t->if_list, list) | 3347 | list_for_each_entry(p, &t->if_list, list) |
3343 | if (strncmp(p->ifname, ifname, IFNAMSIZ) == 0) { | 3348 | if (strncmp(p->odev->name, ifname, IFNAMSIZ) == 0) { |
3344 | pkt_dev = p; | 3349 | pkt_dev = p; |
3345 | break; | 3350 | break; |
3346 | } | 3351 | } |
@@ -3381,7 +3386,7 @@ out: | |||
3381 | static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) | 3386 | static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) |
3382 | { | 3387 | { |
3383 | struct pktgen_dev *pkt_dev; | 3388 | struct pktgen_dev *pkt_dev; |
3384 | struct proc_dir_entry *pe; | 3389 | int err; |
3385 | 3390 | ||
3386 | /* We don't allow a device to be on several threads */ | 3391 | /* We don't allow a device to be on several threads */ |
3387 | 3392 | ||
@@ -3423,29 +3428,28 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) | |||
3423 | pkt_dev->svlan_cfi = 0; | 3428 | pkt_dev->svlan_cfi = 0; |
3424 | pkt_dev->svlan_id = 0xffff; | 3429 | pkt_dev->svlan_id = 0xffff; |
3425 | 3430 | ||
3426 | strncpy(pkt_dev->ifname, ifname, IFNAMSIZ); | 3431 | err = pktgen_setup_dev(pkt_dev, ifname); |
3427 | 3432 | if (err) | |
3428 | if (!pktgen_setup_dev(pkt_dev)) { | 3433 | goto out1; |
3429 | printk("pktgen: ERROR: pktgen_setup_dev failed.\n"); | ||
3430 | if (pkt_dev->flows) | ||
3431 | vfree(pkt_dev->flows); | ||
3432 | kfree(pkt_dev); | ||
3433 | return -ENODEV; | ||
3434 | } | ||
3435 | 3434 | ||
3436 | pe = create_proc_entry(ifname, 0600, pg_proc_dir); | 3435 | pkt_dev->entry = create_proc_entry(ifname, 0600, pg_proc_dir); |
3437 | if (!pe) { | 3436 | if (!pkt_dev->entry) { |
3438 | printk("pktgen: cannot create %s/%s procfs entry.\n", | 3437 | printk("pktgen: cannot create %s/%s procfs entry.\n", |
3439 | PG_PROC_DIR, ifname); | 3438 | PG_PROC_DIR, ifname); |
3440 | if (pkt_dev->flows) | 3439 | err = -EINVAL; |
3441 | vfree(pkt_dev->flows); | 3440 | goto out2; |
3442 | kfree(pkt_dev); | ||
3443 | return -EINVAL; | ||
3444 | } | 3441 | } |
3445 | pe->proc_fops = &pktgen_if_fops; | 3442 | pkt_dev->entry->proc_fops = &pktgen_if_fops; |
3446 | pe->data = pkt_dev; | 3443 | pkt_dev->entry->data = pkt_dev; |
3447 | 3444 | ||
3448 | return add_dev_to_thread(t, pkt_dev); | 3445 | return add_dev_to_thread(t, pkt_dev); |
3446 | out2: | ||
3447 | dev_put(pkt_dev->odev); | ||
3448 | out1: | ||
3449 | if (pkt_dev->flows) | ||
3450 | vfree(pkt_dev->flows); | ||
3451 | kfree(pkt_dev); | ||
3452 | return err; | ||
3449 | } | 3453 | } |
3450 | 3454 | ||
3451 | static int __init pktgen_create_thread(int cpu) | 3455 | static int __init pktgen_create_thread(int cpu) |
@@ -3533,9 +3537,8 @@ static int pktgen_remove_device(struct pktgen_thread *t, | |||
3533 | 3537 | ||
3534 | _rem_dev_from_if_list(t, pkt_dev); | 3538 | _rem_dev_from_if_list(t, pkt_dev); |
3535 | 3539 | ||
3536 | /* Clean up proc file system */ | 3540 | if (pkt_dev->entry) |
3537 | 3541 | remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); | |
3538 | remove_proc_entry(pkt_dev->ifname, pg_proc_dir); | ||
3539 | 3542 | ||
3540 | if (pkt_dev->flows) | 3543 | if (pkt_dev->flows) |
3541 | vfree(pkt_dev->flows); | 3544 | vfree(pkt_dev->flows); |