diff options
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r-- | net/core/neighbour.c | 116 |
1 files changed, 72 insertions, 44 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 9a283fcde9a6..bd899d557737 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -375,7 +375,8 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, | |||
375 | return n; | 375 | return n; |
376 | } | 376 | } |
377 | 377 | ||
378 | struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, const void *pkey) | 378 | struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, |
379 | const void *pkey) | ||
379 | { | 380 | { |
380 | struct neighbour *n; | 381 | struct neighbour *n; |
381 | int key_len = tbl->key_len; | 382 | int key_len = tbl->key_len; |
@@ -385,7 +386,8 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, const void *pkey) | |||
385 | 386 | ||
386 | read_lock_bh(&tbl->lock); | 387 | read_lock_bh(&tbl->lock); |
387 | for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { | 388 | for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { |
388 | if (!memcmp(n->primary_key, pkey, key_len)) { | 389 | if (!memcmp(n->primary_key, pkey, key_len) && |
390 | (net == n->dev->nd_net)) { | ||
389 | neigh_hold(n); | 391 | neigh_hold(n); |
390 | NEIGH_CACHE_STAT_INC(tbl, hits); | 392 | NEIGH_CACHE_STAT_INC(tbl, hits); |
391 | break; | 393 | break; |
@@ -463,7 +465,8 @@ out_neigh_release: | |||
463 | goto out; | 465 | goto out; |
464 | } | 466 | } |
465 | 467 | ||
466 | struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, const void *pkey, | 468 | struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, |
469 | struct net *net, const void *pkey, | ||
467 | struct net_device *dev, int creat) | 470 | struct net_device *dev, int creat) |
468 | { | 471 | { |
469 | struct pneigh_entry *n; | 472 | struct pneigh_entry *n; |
@@ -479,6 +482,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, const void *pkey, | |||
479 | 482 | ||
480 | for (n = tbl->phash_buckets[hash_val]; n; n = n->next) { | 483 | for (n = tbl->phash_buckets[hash_val]; n; n = n->next) { |
481 | if (!memcmp(n->key, pkey, key_len) && | 484 | if (!memcmp(n->key, pkey, key_len) && |
485 | (n->net == net) && | ||
482 | (n->dev == dev || !n->dev)) { | 486 | (n->dev == dev || !n->dev)) { |
483 | read_unlock_bh(&tbl->lock); | 487 | read_unlock_bh(&tbl->lock); |
484 | goto out; | 488 | goto out; |
@@ -495,6 +499,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, const void *pkey, | |||
495 | if (!n) | 499 | if (!n) |
496 | goto out; | 500 | goto out; |
497 | 501 | ||
502 | n->net = hold_net(net); | ||
498 | memcpy(n->key, pkey, key_len); | 503 | memcpy(n->key, pkey, key_len); |
499 | n->dev = dev; | 504 | n->dev = dev; |
500 | if (dev) | 505 | if (dev) |
@@ -517,7 +522,7 @@ out: | |||
517 | } | 522 | } |
518 | 523 | ||
519 | 524 | ||
520 | int pneigh_delete(struct neigh_table *tbl, const void *pkey, | 525 | int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, |
521 | struct net_device *dev) | 526 | struct net_device *dev) |
522 | { | 527 | { |
523 | struct pneigh_entry *n, **np; | 528 | struct pneigh_entry *n, **np; |
@@ -532,13 +537,15 @@ int pneigh_delete(struct neigh_table *tbl, const void *pkey, | |||
532 | write_lock_bh(&tbl->lock); | 537 | write_lock_bh(&tbl->lock); |
533 | for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL; | 538 | for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL; |
534 | np = &n->next) { | 539 | np = &n->next) { |
535 | if (!memcmp(n->key, pkey, key_len) && n->dev == dev) { | 540 | if (!memcmp(n->key, pkey, key_len) && n->dev == dev && |
541 | (n->net == net)) { | ||
536 | *np = n->next; | 542 | *np = n->next; |
537 | write_unlock_bh(&tbl->lock); | 543 | write_unlock_bh(&tbl->lock); |
538 | if (tbl->pdestructor) | 544 | if (tbl->pdestructor) |
539 | tbl->pdestructor(n); | 545 | tbl->pdestructor(n); |
540 | if (n->dev) | 546 | if (n->dev) |
541 | dev_put(n->dev); | 547 | dev_put(n->dev); |
548 | release_net(n->net); | ||
542 | kfree(n); | 549 | kfree(n); |
543 | return 0; | 550 | return 0; |
544 | } | 551 | } |
@@ -561,6 +568,7 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev) | |||
561 | tbl->pdestructor(n); | 568 | tbl->pdestructor(n); |
562 | if (n->dev) | 569 | if (n->dev) |
563 | dev_put(n->dev); | 570 | dev_put(n->dev); |
571 | release_net(n->net); | ||
564 | kfree(n); | 572 | kfree(n); |
565 | continue; | 573 | continue; |
566 | } | 574 | } |
@@ -1261,12 +1269,37 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, | |||
1261 | spin_unlock(&tbl->proxy_queue.lock); | 1269 | spin_unlock(&tbl->proxy_queue.lock); |
1262 | } | 1270 | } |
1263 | 1271 | ||
1272 | static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, | ||
1273 | struct net *net, int ifindex) | ||
1274 | { | ||
1275 | struct neigh_parms *p; | ||
1276 | |||
1277 | for (p = &tbl->parms; p; p = p->next) { | ||
1278 | if (p->net != net) | ||
1279 | continue; | ||
1280 | if ((p->dev && p->dev->ifindex == ifindex) || | ||
1281 | (!p->dev && !ifindex)) | ||
1282 | return p; | ||
1283 | } | ||
1284 | |||
1285 | return NULL; | ||
1286 | } | ||
1264 | 1287 | ||
1265 | struct neigh_parms *neigh_parms_alloc(struct net_device *dev, | 1288 | struct neigh_parms *neigh_parms_alloc(struct net_device *dev, |
1266 | struct neigh_table *tbl) | 1289 | struct neigh_table *tbl) |
1267 | { | 1290 | { |
1268 | struct neigh_parms *p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL); | 1291 | struct neigh_parms *p, *ref; |
1292 | struct net *net; | ||
1293 | |||
1294 | net = &init_net; | ||
1295 | if (dev) | ||
1296 | net = dev->nd_net; | ||
1297 | |||
1298 | ref = lookup_neigh_params(tbl, net, 0); | ||
1299 | if (!ref) | ||
1300 | return NULL; | ||
1269 | 1301 | ||
1302 | p = kmemdup(ref, sizeof(*p), GFP_KERNEL); | ||
1270 | if (p) { | 1303 | if (p) { |
1271 | p->tbl = tbl; | 1304 | p->tbl = tbl; |
1272 | atomic_set(&p->refcnt, 1); | 1305 | atomic_set(&p->refcnt, 1); |
@@ -1282,6 +1315,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, | |||
1282 | dev_hold(dev); | 1315 | dev_hold(dev); |
1283 | p->dev = dev; | 1316 | p->dev = dev; |
1284 | } | 1317 | } |
1318 | p->net = hold_net(net); | ||
1285 | p->sysctl_table = NULL; | 1319 | p->sysctl_table = NULL; |
1286 | write_lock_bh(&tbl->lock); | 1320 | write_lock_bh(&tbl->lock); |
1287 | p->next = tbl->parms.next; | 1321 | p->next = tbl->parms.next; |
@@ -1323,6 +1357,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) | |||
1323 | 1357 | ||
1324 | void neigh_parms_destroy(struct neigh_parms *parms) | 1358 | void neigh_parms_destroy(struct neigh_parms *parms) |
1325 | { | 1359 | { |
1360 | release_net(parms->net); | ||
1326 | kfree(parms); | 1361 | kfree(parms); |
1327 | } | 1362 | } |
1328 | 1363 | ||
@@ -1333,6 +1368,7 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) | |||
1333 | unsigned long now = jiffies; | 1368 | unsigned long now = jiffies; |
1334 | unsigned long phsize; | 1369 | unsigned long phsize; |
1335 | 1370 | ||
1371 | tbl->parms.net = &init_net; | ||
1336 | atomic_set(&tbl->parms.refcnt, 1); | 1372 | atomic_set(&tbl->parms.refcnt, 1); |
1337 | INIT_RCU_HEAD(&tbl->parms.rcu_head); | 1373 | INIT_RCU_HEAD(&tbl->parms.rcu_head); |
1338 | tbl->parms.reachable_time = | 1374 | tbl->parms.reachable_time = |
@@ -1446,9 +1482,6 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1446 | struct net_device *dev = NULL; | 1482 | struct net_device *dev = NULL; |
1447 | int err = -EINVAL; | 1483 | int err = -EINVAL; |
1448 | 1484 | ||
1449 | if (net != &init_net) | ||
1450 | return -EINVAL; | ||
1451 | |||
1452 | if (nlmsg_len(nlh) < sizeof(*ndm)) | 1485 | if (nlmsg_len(nlh) < sizeof(*ndm)) |
1453 | goto out; | 1486 | goto out; |
1454 | 1487 | ||
@@ -1477,7 +1510,7 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1477 | goto out_dev_put; | 1510 | goto out_dev_put; |
1478 | 1511 | ||
1479 | if (ndm->ndm_flags & NTF_PROXY) { | 1512 | if (ndm->ndm_flags & NTF_PROXY) { |
1480 | err = pneigh_delete(tbl, nla_data(dst_attr), dev); | 1513 | err = pneigh_delete(tbl, net, nla_data(dst_attr), dev); |
1481 | goto out_dev_put; | 1514 | goto out_dev_put; |
1482 | } | 1515 | } |
1483 | 1516 | ||
@@ -1515,9 +1548,6 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1515 | struct net_device *dev = NULL; | 1548 | struct net_device *dev = NULL; |
1516 | int err; | 1549 | int err; |
1517 | 1550 | ||
1518 | if (net != &init_net) | ||
1519 | return -EINVAL; | ||
1520 | |||
1521 | err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); | 1551 | err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); |
1522 | if (err < 0) | 1552 | if (err < 0) |
1523 | goto out; | 1553 | goto out; |
@@ -1557,7 +1587,7 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1557 | struct pneigh_entry *pn; | 1587 | struct pneigh_entry *pn; |
1558 | 1588 | ||
1559 | err = -ENOBUFS; | 1589 | err = -ENOBUFS; |
1560 | pn = pneigh_lookup(tbl, dst, dev, 1); | 1590 | pn = pneigh_lookup(tbl, net, dst, dev, 1); |
1561 | if (pn) { | 1591 | if (pn) { |
1562 | pn->flags = ndm->ndm_flags; | 1592 | pn->flags = ndm->ndm_flags; |
1563 | err = 0; | 1593 | err = 0; |
@@ -1752,19 +1782,6 @@ errout: | |||
1752 | return -EMSGSIZE; | 1782 | return -EMSGSIZE; |
1753 | } | 1783 | } |
1754 | 1784 | ||
1755 | static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, | ||
1756 | int ifindex) | ||
1757 | { | ||
1758 | struct neigh_parms *p; | ||
1759 | |||
1760 | for (p = &tbl->parms; p; p = p->next) | ||
1761 | if ((p->dev && p->dev->ifindex == ifindex) || | ||
1762 | (!p->dev && !ifindex)) | ||
1763 | return p; | ||
1764 | |||
1765 | return NULL; | ||
1766 | } | ||
1767 | |||
1768 | static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = { | 1785 | static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = { |
1769 | [NDTA_NAME] = { .type = NLA_STRING }, | 1786 | [NDTA_NAME] = { .type = NLA_STRING }, |
1770 | [NDTA_THRESH1] = { .type = NLA_U32 }, | 1787 | [NDTA_THRESH1] = { .type = NLA_U32 }, |
@@ -1798,9 +1815,6 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1798 | struct nlattr *tb[NDTA_MAX+1]; | 1815 | struct nlattr *tb[NDTA_MAX+1]; |
1799 | int err; | 1816 | int err; |
1800 | 1817 | ||
1801 | if (net != &init_net) | ||
1802 | return -EINVAL; | ||
1803 | |||
1804 | err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX, | 1818 | err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX, |
1805 | nl_neightbl_policy); | 1819 | nl_neightbl_policy); |
1806 | if (err < 0) | 1820 | if (err < 0) |
@@ -1845,7 +1859,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1845 | if (tbp[NDTPA_IFINDEX]) | 1859 | if (tbp[NDTPA_IFINDEX]) |
1846 | ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]); | 1860 | ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]); |
1847 | 1861 | ||
1848 | p = lookup_neigh_params(tbl, ifindex); | 1862 | p = lookup_neigh_params(tbl, net, ifindex); |
1849 | if (p == NULL) { | 1863 | if (p == NULL) { |
1850 | err = -ENOENT; | 1864 | err = -ENOENT; |
1851 | goto errout_tbl_lock; | 1865 | goto errout_tbl_lock; |
@@ -1926,9 +1940,6 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | |||
1926 | int neigh_skip = cb->args[1]; | 1940 | int neigh_skip = cb->args[1]; |
1927 | struct neigh_table *tbl; | 1941 | struct neigh_table *tbl; |
1928 | 1942 | ||
1929 | if (net != &init_net) | ||
1930 | return 0; | ||
1931 | |||
1932 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; | 1943 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; |
1933 | 1944 | ||
1934 | read_lock(&neigh_tbl_lock); | 1945 | read_lock(&neigh_tbl_lock); |
@@ -1943,8 +1954,11 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | |||
1943 | NLM_F_MULTI) <= 0) | 1954 | NLM_F_MULTI) <= 0) |
1944 | break; | 1955 | break; |
1945 | 1956 | ||
1946 | for (nidx = 0, p = tbl->parms.next; p; p = p->next, nidx++) { | 1957 | for (nidx = 0, p = tbl->parms.next; p; p = p->next) { |
1947 | if (nidx < neigh_skip) | 1958 | if (net != p->net) |
1959 | continue; | ||
1960 | |||
1961 | if (nidx++ < neigh_skip) | ||
1948 | continue; | 1962 | continue; |
1949 | 1963 | ||
1950 | if (neightbl_fill_param_info(skb, tbl, p, | 1964 | if (neightbl_fill_param_info(skb, tbl, p, |
@@ -2020,6 +2034,7 @@ static void neigh_update_notify(struct neighbour *neigh) | |||
2020 | static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, | 2034 | static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, |
2021 | struct netlink_callback *cb) | 2035 | struct netlink_callback *cb) |
2022 | { | 2036 | { |
2037 | struct net * net = skb->sk->sk_net; | ||
2023 | struct neighbour *n; | 2038 | struct neighbour *n; |
2024 | int rc, h, s_h = cb->args[1]; | 2039 | int rc, h, s_h = cb->args[1]; |
2025 | int idx, s_idx = idx = cb->args[2]; | 2040 | int idx, s_idx = idx = cb->args[2]; |
@@ -2030,8 +2045,12 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, | |||
2030 | continue; | 2045 | continue; |
2031 | if (h > s_h) | 2046 | if (h > s_h) |
2032 | s_idx = 0; | 2047 | s_idx = 0; |
2033 | for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) { | 2048 | for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) { |
2034 | if (idx < s_idx) | 2049 | int lidx; |
2050 | if (n->dev->nd_net != net) | ||
2051 | continue; | ||
2052 | lidx = idx++; | ||
2053 | if (lidx < s_idx) | ||
2035 | continue; | 2054 | continue; |
2036 | if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid, | 2055 | if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid, |
2037 | cb->nlh->nlmsg_seq, | 2056 | cb->nlh->nlmsg_seq, |
@@ -2053,13 +2072,9 @@ out: | |||
2053 | 2072 | ||
2054 | static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | 2073 | static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) |
2055 | { | 2074 | { |
2056 | struct net *net = skb->sk->sk_net; | ||
2057 | struct neigh_table *tbl; | 2075 | struct neigh_table *tbl; |
2058 | int t, family, s_t; | 2076 | int t, family, s_t; |
2059 | 2077 | ||
2060 | if (net != &init_net) | ||
2061 | return 0; | ||
2062 | |||
2063 | read_lock(&neigh_tbl_lock); | 2078 | read_lock(&neigh_tbl_lock); |
2064 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; | 2079 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; |
2065 | s_t = cb->args[0]; | 2080 | s_t = cb->args[0]; |
@@ -2127,6 +2142,7 @@ EXPORT_SYMBOL(__neigh_for_each_release); | |||
2127 | static struct neighbour *neigh_get_first(struct seq_file *seq) | 2142 | static struct neighbour *neigh_get_first(struct seq_file *seq) |
2128 | { | 2143 | { |
2129 | struct neigh_seq_state *state = seq->private; | 2144 | struct neigh_seq_state *state = seq->private; |
2145 | struct net *net = state->net; | ||
2130 | struct neigh_table *tbl = state->tbl; | 2146 | struct neigh_table *tbl = state->tbl; |
2131 | struct neighbour *n = NULL; | 2147 | struct neighbour *n = NULL; |
2132 | int bucket = state->bucket; | 2148 | int bucket = state->bucket; |
@@ -2136,6 +2152,8 @@ static struct neighbour *neigh_get_first(struct seq_file *seq) | |||
2136 | n = tbl->hash_buckets[bucket]; | 2152 | n = tbl->hash_buckets[bucket]; |
2137 | 2153 | ||
2138 | while (n) { | 2154 | while (n) { |
2155 | if (n->dev->nd_net != net) | ||
2156 | goto next; | ||
2139 | if (state->neigh_sub_iter) { | 2157 | if (state->neigh_sub_iter) { |
2140 | loff_t fakep = 0; | 2158 | loff_t fakep = 0; |
2141 | void *v; | 2159 | void *v; |
@@ -2165,6 +2183,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq, | |||
2165 | loff_t *pos) | 2183 | loff_t *pos) |
2166 | { | 2184 | { |
2167 | struct neigh_seq_state *state = seq->private; | 2185 | struct neigh_seq_state *state = seq->private; |
2186 | struct net *net = state->net; | ||
2168 | struct neigh_table *tbl = state->tbl; | 2187 | struct neigh_table *tbl = state->tbl; |
2169 | 2188 | ||
2170 | if (state->neigh_sub_iter) { | 2189 | if (state->neigh_sub_iter) { |
@@ -2176,6 +2195,8 @@ static struct neighbour *neigh_get_next(struct seq_file *seq, | |||
2176 | 2195 | ||
2177 | while (1) { | 2196 | while (1) { |
2178 | while (n) { | 2197 | while (n) { |
2198 | if (n->dev->nd_net != net) | ||
2199 | goto next; | ||
2179 | if (state->neigh_sub_iter) { | 2200 | if (state->neigh_sub_iter) { |
2180 | void *v = state->neigh_sub_iter(state, n, pos); | 2201 | void *v = state->neigh_sub_iter(state, n, pos); |
2181 | if (v) | 2202 | if (v) |
@@ -2222,6 +2243,7 @@ static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos) | |||
2222 | static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) | 2243 | static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) |
2223 | { | 2244 | { |
2224 | struct neigh_seq_state *state = seq->private; | 2245 | struct neigh_seq_state *state = seq->private; |
2246 | struct net * net = state->net; | ||
2225 | struct neigh_table *tbl = state->tbl; | 2247 | struct neigh_table *tbl = state->tbl; |
2226 | struct pneigh_entry *pn = NULL; | 2248 | struct pneigh_entry *pn = NULL; |
2227 | int bucket = state->bucket; | 2249 | int bucket = state->bucket; |
@@ -2229,6 +2251,8 @@ static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) | |||
2229 | state->flags |= NEIGH_SEQ_IS_PNEIGH; | 2251 | state->flags |= NEIGH_SEQ_IS_PNEIGH; |
2230 | for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) { | 2252 | for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) { |
2231 | pn = tbl->phash_buckets[bucket]; | 2253 | pn = tbl->phash_buckets[bucket]; |
2254 | while (pn && (pn->net != net)) | ||
2255 | pn = pn->next; | ||
2232 | if (pn) | 2256 | if (pn) |
2233 | break; | 2257 | break; |
2234 | } | 2258 | } |
@@ -2242,6 +2266,7 @@ static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, | |||
2242 | loff_t *pos) | 2266 | loff_t *pos) |
2243 | { | 2267 | { |
2244 | struct neigh_seq_state *state = seq->private; | 2268 | struct neigh_seq_state *state = seq->private; |
2269 | struct net * net = state->net; | ||
2245 | struct neigh_table *tbl = state->tbl; | 2270 | struct neigh_table *tbl = state->tbl; |
2246 | 2271 | ||
2247 | pn = pn->next; | 2272 | pn = pn->next; |
@@ -2249,6 +2274,8 @@ static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, | |||
2249 | if (++state->bucket > PNEIGH_HASHMASK) | 2274 | if (++state->bucket > PNEIGH_HASHMASK) |
2250 | break; | 2275 | break; |
2251 | pn = tbl->phash_buckets[state->bucket]; | 2276 | pn = tbl->phash_buckets[state->bucket]; |
2277 | while (pn && (pn->net != net)) | ||
2278 | pn = pn->next; | ||
2252 | if (pn) | 2279 | if (pn) |
2253 | break; | 2280 | break; |
2254 | } | 2281 | } |
@@ -2450,6 +2477,7 @@ static inline size_t neigh_nlmsg_size(void) | |||
2450 | 2477 | ||
2451 | static void __neigh_notify(struct neighbour *n, int type, int flags) | 2478 | static void __neigh_notify(struct neighbour *n, int type, int flags) |
2452 | { | 2479 | { |
2480 | struct net *net = n->dev->nd_net; | ||
2453 | struct sk_buff *skb; | 2481 | struct sk_buff *skb; |
2454 | int err = -ENOBUFS; | 2482 | int err = -ENOBUFS; |
2455 | 2483 | ||
@@ -2464,10 +2492,10 @@ static void __neigh_notify(struct neighbour *n, int type, int flags) | |||
2464 | kfree_skb(skb); | 2492 | kfree_skb(skb); |
2465 | goto errout; | 2493 | goto errout; |
2466 | } | 2494 | } |
2467 | err = rtnl_notify(skb, &init_net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); | 2495 | err = rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); |
2468 | errout: | 2496 | errout: |
2469 | if (err < 0) | 2497 | if (err < 0) |
2470 | rtnl_set_sk_err(&init_net, RTNLGRP_NEIGH, err); | 2498 | rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); |
2471 | } | 2499 | } |
2472 | 2500 | ||
2473 | #ifdef CONFIG_ARPD | 2501 | #ifdef CONFIG_ARPD |