diff options
Diffstat (limited to 'net/ipv4/arp.c')
| -rw-r--r-- | net/ipv4/arp.c | 131 |
1 files changed, 88 insertions, 43 deletions
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 60009d92e071..95f3359d0f92 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -149,7 +149,7 @@ static const struct neigh_ops arp_direct_ops = { .connected_output = neigh_direct_output, }; -struct neigh_table arp_tbl = { +static struct neigh_table arp_tbl = { .family = AF_INET, .key_len = 4, .protocol = cpu_to_be16(ETH_P_IP), @@ -182,7 +182,6 @@ struct neigh_table arp_tbl = { .gc_thresh2 = 512, .gc_thresh3 = 1024, }; -EXPORT_SYMBOL(arp_tbl); int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) { @@ -222,14 +221,18 @@ static bool arp_key_eq(const struct neighbour *neigh, const void *pkey) static int arp_constructor(struct neighbour *neigh) { - __be32 addr; struct net_device *dev = neigh->dev; - struct in_device *in_dev; - struct neigh_parms *parms; + struct net *net = dev_net(dev); u32 inaddr_any = INADDR_ANY; + struct neigh_parms *parms; + struct in_device *in_dev; + struct neigh_table *tbl; + __be32 addr; + + tbl = arp_table(net); if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) - memcpy(neigh->primary_key, &inaddr_any, arp_tbl.key_len); + memcpy(neigh->primary_key, &inaddr_any, tbl->key_len); addr = *(__be32 *)neigh->primary_key; rcu_read_lock(); @@ -239,7 +242,7 @@ static int arp_constructor(struct neighbour *neigh) return -EINVAL; } - neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr); + neigh->type = inet_addr_type_dev_table(net, dev, addr); parms = in_dev->arp_parms; __neigh_parms_put(neigh->parms); @@ -701,24 +704,24 @@ static bool arp_is_garp(struct net *net, struct net_device *dev, static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) { + struct neigh_table *tbl = arp_table(net); + struct dst_entry *reply_dst = NULL; struct net_device *dev = skb->dev; - struct in_device *in_dev = __in_dev_get_rcu(dev); - struct arphdr *arp; + unsigned char *sha, *tha = NULL; + struct in_device *in_dev; + u16 dev_type = dev->type; unsigned char *arp_ptr; + bool is_garp = false; + struct neighbour *n; + struct arphdr *arp; struct rtable *rt; - unsigned char *sha; - unsigned char *tha = NULL; __be32 sip, tip; - u16 dev_type = dev->type; int addr_type; - struct neighbour *n; - struct dst_entry *reply_dst = NULL; - bool is_garp = false; /* arp_rcv below verifies the ARP header and verifies the device * is ARP'able. */ - + in_dev = __in_dev_get_rcu(dev); if (!in_dev) goto out_free_skb; @@ -850,7 +853,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) if (!dont_send && IN_DEV_ARPFILTER(in_dev)) dont_send = arp_filter(sip, tip, dev); if (!dont_send) { - n = neigh_event_ns(&arp_tbl, sha, &sip, dev); + n = neigh_event_ns(tbl, sha, &sip, dev); if (n) { arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, @@ -865,8 +868,8 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) (arp_fwd_proxy(in_dev, dev, rt) || arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || (rt->dst.dev != dev && - pneigh_lookup(&arp_tbl, net, &tip, dev)))) { - n = neigh_event_ns(&arp_tbl, sha, &sip, dev); + pneigh_lookup(tbl, &tip, dev)))) { + n = neigh_event_ns(tbl, sha, &sip, dev); if (n) neigh_release(n); @@ -878,7 +881,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) dev->dev_addr, sha, reply_dst); } else { - pneigh_enqueue(&arp_tbl, + pneigh_enqueue(tbl, in_dev->arp_parms, skb); goto out_free_dst; } @@ -889,7 +892,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) /* Update our ARP tables */ - n = __neigh_lookup(&arp_tbl, &sip, dev, 0); + n = __neigh_lookup(tbl, &sip, dev, 0); addr_type = -1; if (n || arp_accept(in_dev, sip)) { @@ -910,7 +913,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) /* postpone calculation to as late as possible */ inet_addr_type_dev_table(net, dev, sip) == RTN_UNICAST))))) - n = __neigh_lookup(&arp_tbl, &sip, dev, 1); + n = __neigh_lookup(tbl, &sip, dev, 1); } if (n) { @@ -1077,9 +1080,10 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on) } static int arp_req_set_public(struct net *net, struct arpreq *r, - struct net_device *dev) + struct net_device *dev) { __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; + struct neigh_table *tbl = arp_table(net); if (!dev && (r->arp_flags & ATF_COM)) { dev = dev_getbyhwaddr(net, r->arp_ha.sa_family, @@ -1090,7 +1094,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r, if (mask) { __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; - return pneigh_create(&arp_tbl, net, &ip, dev, 0, 0, false); + return pneigh_create(tbl, &ip, dev, 0, 0, false); } return arp_req_set_proxy(net, dev, 1); @@ -1098,6 +1102,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r, static int arp_req_set(struct net *net, struct arpreq *r) { + struct neigh_table *tbl = arp_table(net); struct neighbour *neigh; struct net_device *dev; __be32 ip; @@ -1133,7 +1138,7 @@ static int arp_req_set(struct net *net, struct arpreq *r) ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; - neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev); + neigh = __neigh_lookup_errno(tbl, &ip, dev); err = PTR_ERR(neigh); if (!IS_ERR(neigh)) { unsigned int state = NUD_STALE; @@ -1169,6 +1174,7 @@ static unsigned int arp_state_to_flags(struct neighbour *neigh) static int arp_req_get(struct net *net, struct arpreq *r) { __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; + struct neigh_table *tbl = arp_table(net); struct neighbour *neigh; struct net_device *dev; @@ -1179,7 +1185,7 @@ static int arp_req_get(struct net *net, struct arpreq *r) if (IS_ERR(dev)) return PTR_ERR(dev); - neigh = neigh_lookup(&arp_tbl, &ip, dev); + neigh = neigh_lookup(tbl, &ip, dev); if (!neigh) return -ENXIO; @@ -1204,10 +1210,11 @@ static int arp_req_get(struct net *net, struct arpreq *r) int arp_invalidate(struct net_device *dev, __be32 ip, bool force) { - struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); + struct neigh_table *tbl = arp_table(dev_net(dev)); + struct neighbour *neigh; int err = -ENXIO; - struct neigh_table *tbl = &arp_tbl; + neigh = neigh_lookup(tbl, &ip, dev); if (neigh) { if ((READ_ONCE(neigh->nud_state) & NUD_VALID) && !force) { neigh_release(neigh); @@ -1228,14 +1235,15 @@ int arp_invalidate(struct net_device *dev, __be32 ip, bool force) } static int arp_req_delete_public(struct net *net, struct arpreq *r, - struct net_device *dev) + struct net_device *dev) { __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; + struct neigh_table *tbl = arp_table(net); if (mask) { __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; - return pneigh_delete(&arp_tbl, net, &ip, dev); + return pneigh_delete(tbl, &ip, dev); } return arp_req_set_proxy(net, dev, 0); @@ -1326,18 +1334,22 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct netdev_notifier_change_info *change_info; + struct net *net = dev_net(dev); struct in_device *in_dev; + struct neigh_table *tbl; bool evict_nocarrier; + tbl = arp_table(net); + switch (event) { case NETDEV_CHANGEADDR: - neigh_changeaddr(&arp_tbl, dev); - rt_cache_flush(dev_net(dev)); + neigh_changeaddr(tbl, dev); + rt_cache_flush(net); break; case NETDEV_CHANGE: change_info = ptr; if (change_info->flags_changed & IFF_NOARP) - neigh_changeaddr(&arp_tbl, dev); + neigh_changeaddr(tbl, dev); in_dev = __in_dev_get_rtnl(dev); if (!in_dev) @@ -1346,7 +1358,7 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, evict_nocarrier = IN_DEV_ARP_EVICT_NOCARRIER(in_dev); if (evict_nocarrier && !netif_carrier_ok(dev)) - neigh_carrier_down(&arp_tbl, dev); + neigh_carrier_down(tbl, dev); break; default: break; @@ -1365,7 +1377,9 @@ static struct notifier_block arp_netdev_notifier = { */ void arp_ifdown(struct net_device *dev) { - neigh_ifdown(&arp_tbl, dev); + struct neigh_table *tbl = arp_table(dev_net(dev)); + + neigh_ifdown(tbl, dev); } @@ -1480,10 +1494,12 @@ static int arp_seq_show(struct seq_file *seq, void *v) static void *arp_seq_start(struct seq_file *seq, loff_t *pos) { + struct neigh_table *tbl = arp_table(seq_file_net(seq)); + /* Don't want to confuse "arp -a" w/ magic entries, * so we tell the generic iterator to skip NUD_NOARP. */ - return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_SKIP_NOARP); + return neigh_seq_start(seq, pos, tbl, NEIGH_SEQ_SKIP_NOARP); } static const struct seq_operations arp_seq_ops = { @@ -1496,15 +1512,47 @@ static const struct seq_operations arp_seq_ops = { static int __net_init arp_net_init(struct net *net) { + int err; + + err = neigh_table_register(net, &arp_tbl, NEIGH_ARP_TABLE); + if (err) + goto err; + +#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SYSCTL + err = neigh_sysctl_register(NULL, &arp_table(net)->parms, NULL); + if (err) + goto err_sysctl; +#endif + if (!proc_create_net("arp", 0444, net->proc_net, &arp_seq_ops, - sizeof(struct neigh_seq_state))) - return -ENOMEM; + sizeof(struct neigh_seq_state))) { + err = -ENOMEM; + goto err_proc_create; + } +#endif + return 0; + +#ifdef CONFIG_PROC_FS +err_proc_create: +#ifdef CONFIG_SYSCTL + neigh_sysctl_unregister(&arp_table(net)->parms); +err_sysctl: +#endif + neigh_table_unregister(net, NEIGH_ARP_TABLE); +#endif +err: + return err; } static void __net_exit arp_net_exit(struct net *net) { remove_proc_entry("arp", net->proc_net); +#ifdef CONFIG_SYSCTL + neigh_sysctl_unregister(&arp_table(net)->parms); +#endif + neigh_table_unregister(net, NEIGH_ARP_TABLE); } static struct pernet_operations arp_net_ops = { @@ -1514,12 +1562,9 @@ static struct pernet_operations arp_net_ops = { void __init arp_init(void) { - neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl); + if (register_pernet_subsys(&arp_net_ops)) + panic("Cannot allocate arp table\n"); dev_add_pack(&arp_packet_type); - register_pernet_subsys(&arp_net_ops); -#ifdef CONFIG_SYSCTL - neigh_sysctl_register(NULL, &arp_tbl.parms, NULL); -#endif register_netdevice_notifier(&arp_netdev_notifier); } |
