summaryrefslogtreecommitdiff
path: root/net/ipv4/arp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/arp.c')
-rw-r--r--net/ipv4/arp.c131
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);
}