Commit 426b5303 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by David S. Miller

[NETNS]: Modify the neighbour table code so it handles multiple network namespaces

I'm actually surprised at how much was involved.  At first glance it
appears that the neighbour table data structures are already split by
network device so all that should be needed is to modify the user
interface commands to filter the set of neighbours by the network
namespace of their devices.

However a couple things turned up while I was reading through the
code.  The proxy neighbour table allows entries with no network
device, and the neighbour parms are per network device (except for the
defaults) so they now need a per network namespace default.

So I updated the two structures (which surprised me) with their very
own network namespace parameter.  Updated the relevant lookup and
destroy routines with a network namespace parameter and modified the
code that interacts with users to filter out neighbour table entries
for devices of other namespaces.

I'm a little concerned that we can modify and display the global table
configuration and from all network namespaces.  But this appears good
enough for now.

I keep thinking modifying the neighbour table to have per network
namespace instances of each table type would should be cleaner.  The
hash table is already dynamically sized so there are it is not a
limiter.  The default parameter would be straight forward to take care
of.  However when I look at the how the network table is built and
used I still find some assumptions that there is only a single
neighbour table for each type of table in the kernel.  The netlink
operations, neigh_seq_start, the non-core network users that call
neigh_lookup.  So while it might be doable it would require more
refactoring than my current approach of just doing a little extra
filtering in the code.
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
Signed-off-by: default avatarDaniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e1af9f27
......@@ -34,6 +34,7 @@ struct neighbour;
struct neigh_parms
{
struct net *net;
struct net_device *dev;
struct neigh_parms *next;
int (*neigh_setup)(struct neighbour *);
......@@ -126,7 +127,8 @@ struct neigh_ops
struct pneigh_entry
{
struct pneigh_entry *next;
struct net_device *dev;
struct net *net;
struct net_device *dev;
u8 flags;
u8 key[0];
};
......@@ -187,6 +189,7 @@ extern struct neighbour * neigh_lookup(struct neigh_table *tbl,
const void *pkey,
struct net_device *dev);
extern struct neighbour * neigh_lookup_nodev(struct neigh_table *tbl,
struct net *net,
const void *pkey);
extern struct neighbour * neigh_create(struct neigh_table *tbl,
const void *pkey,
......@@ -211,8 +214,8 @@ extern unsigned long neigh_rand_reach_time(unsigned long base);
extern void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
struct sk_buff *skb);
extern struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, const void *key, struct net_device *dev, int creat);
extern int pneigh_delete(struct neigh_table *tbl, const void *key, struct net_device *dev);
extern struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net, const void *key, struct net_device *dev, int creat);
extern int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key, struct net_device *dev);
extern void neigh_app_ns(struct neighbour *n);
extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie);
......@@ -220,6 +223,7 @@ extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct n
extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *));
struct neigh_seq_state {
struct net *net;
struct neigh_table *tbl;
void *(*neigh_sub_iter)(struct neigh_seq_state *state,
struct neighbour *n, loff_t *pos);
......
......@@ -949,6 +949,11 @@ static int arp_seq_open(struct inode *inode, struct file *file)
seq = file->private_data;
seq->private = state;
state->ns.net = get_proc_net(inode);
if (!state->ns.net) {
seq_release_private(inode, file);
rc = -ENXIO;
}
out:
return rc;
......@@ -957,11 +962,19 @@ static int arp_seq_open(struct inode *inode, struct file *file)
goto out;
}
static int arp_seq_release(struct inode *inode, struct file *file)
{
struct seq_file *seq = file->private_data;
struct clip_seq_state *state = seq->private;
put_net(state->ns.net);
return seq_release_private(inode, file);
}
static const struct file_operations arp_seq_fops = {
.open = arp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
.release = arp_seq_release,
.owner = THIS_MODULE
};
#endif
......
This diff is collapsed.
......@@ -580,8 +580,8 @@ static const struct seq_operations dn_neigh_seq_ops = {
static int dn_neigh_seq_open(struct inode *inode, struct file *file)
{
return seq_open_private(file, &dn_neigh_seq_ops,
sizeof(struct neigh_seq_state));
return seq_open_net(inode, file, &dn_neigh_seq_ops,
sizeof(struct neigh_seq_state));
}
static const struct file_operations dn_neigh_seq_fops = {
......@@ -589,7 +589,7 @@ static const struct file_operations dn_neigh_seq_fops = {
.open = dn_neigh_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
.release = seq_release_net,
};
#endif
......
......@@ -984,7 +984,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
* here
*/
if (!try_hard) {
neigh = neigh_lookup_nodev(&dn_neigh_table, &fl.fld_dst);
neigh = neigh_lookup_nodev(&dn_neigh_table, &init_net, &fl.fld_dst);
if (neigh) {
if ((oldflp->oif &&
(neigh->dev->ifindex != oldflp->oif)) ||
......
......@@ -837,7 +837,7 @@ static int arp_process(struct sk_buff *skb)
} else if (IN_DEV_FORWARD(in_dev)) {
if ((rt->rt_flags&RTCF_DNAT) ||
(addr_type == RTN_UNICAST && rt->u.dst.dev != dev &&
(arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
(arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &init_net, &tip, dev, 0)))) {
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
if (n)
neigh_release(n);
......@@ -980,7 +980,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
return -ENODEV;
}
if (mask) {
if (pneigh_lookup(&arp_tbl, &ip, dev, 1) == NULL)
if (pneigh_lookup(&arp_tbl, &init_net, &ip, dev, 1) == NULL)
return -ENOBUFS;
return 0;
}
......@@ -1089,7 +1089,7 @@ static int arp_req_delete_public(struct net *net, struct arpreq *r,
__be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
if (mask == htonl(0xFFFFFFFF))
return pneigh_delete(&arp_tbl, &ip, dev);
return pneigh_delete(&arp_tbl, &init_net, &ip, dev);
if (mask)
return -EINVAL;
......@@ -1375,8 +1375,8 @@ static const struct seq_operations arp_seq_ops = {
static int arp_seq_open(struct inode *inode, struct file *file)
{
return seq_open_private(file, &arp_seq_ops,
sizeof(struct neigh_seq_state));
return seq_open_net(inode, file, &arp_seq_ops,
sizeof(struct neigh_seq_state));
}
static const struct file_operations arp_seq_fops = {
......@@ -1384,7 +1384,7 @@ static const struct file_operations arp_seq_fops = {
.open = arp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
.release = seq_release_net,
};
static int __init arp_proc_init(void)
......
......@@ -449,7 +449,7 @@ int ip6_forward(struct sk_buff *skb)
/* XXX: idev->cnf.proxy_ndp? */
if (ipv6_devconf.proxy_ndp &&
pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
pneigh_lookup(&nd_tbl, &init_net, &hdr->daddr, skb->dev, 0)) {
int proxied = ip6_forward_proxy_check(skb);
if (proxied > 0)
return ip6_input(skb);
......
......@@ -789,7 +789,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
if (ipv6_chk_acast_addr(dev, &msg->target) ||
(idev->cnf.forwarding &&
(ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) &&
(pneigh = pneigh_lookup(&nd_tbl,
(pneigh = pneigh_lookup(&nd_tbl, &init_net,
&msg->target, dev, 0)) != NULL)) {
if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
skb->pkt_type != PACKET_HOST &&
......@@ -930,7 +930,7 @@ static void ndisc_recv_na(struct sk_buff *skb)
*/
if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp &&
pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
pneigh_lookup(&nd_tbl, &init_net, &msg->target, dev, 0)) {
/* XXX: idev->cnf.prixy_ndp */
goto out;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment