diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 94 |
1 files changed, 66 insertions, 28 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index aa13ef105110..33137307d52a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -108,6 +108,7 @@ | |||
108 | #ifdef CONFIG_SYSCTL | 108 | #ifdef CONFIG_SYSCTL |
109 | #include <linux/sysctl.h> | 109 | #include <linux/sysctl.h> |
110 | #endif | 110 | #endif |
111 | #include <net/atmclip.h> | ||
111 | 112 | ||
112 | #define RT_FL_TOS(oldflp4) \ | 113 | #define RT_FL_TOS(oldflp4) \ |
113 | ((u32)(oldflp4->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))) | 114 | ((u32)(oldflp4->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))) |
@@ -184,6 +185,8 @@ static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old) | |||
184 | return p; | 185 | return p; |
185 | } | 186 | } |
186 | 187 | ||
188 | static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, const void *daddr); | ||
189 | |||
187 | static struct dst_ops ipv4_dst_ops = { | 190 | static struct dst_ops ipv4_dst_ops = { |
188 | .family = AF_INET, | 191 | .family = AF_INET, |
189 | .protocol = cpu_to_be16(ETH_P_IP), | 192 | .protocol = cpu_to_be16(ETH_P_IP), |
@@ -198,6 +201,7 @@ static struct dst_ops ipv4_dst_ops = { | |||
198 | .link_failure = ipv4_link_failure, | 201 | .link_failure = ipv4_link_failure, |
199 | .update_pmtu = ip_rt_update_pmtu, | 202 | .update_pmtu = ip_rt_update_pmtu, |
200 | .local_out = __ip_local_out, | 203 | .local_out = __ip_local_out, |
204 | .neigh_lookup = ipv4_neigh_lookup, | ||
201 | }; | 205 | }; |
202 | 206 | ||
203 | #define ECN_OR_COST(class) TC_PRIO_##class | 207 | #define ECN_OR_COST(class) TC_PRIO_##class |
@@ -411,8 +415,10 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) | |||
411 | "HHUptod\tSpecDst"); | 415 | "HHUptod\tSpecDst"); |
412 | else { | 416 | else { |
413 | struct rtable *r = v; | 417 | struct rtable *r = v; |
418 | struct neighbour *n; | ||
414 | int len; | 419 | int len; |
415 | 420 | ||
421 | n = dst_get_neighbour(&r->dst); | ||
416 | seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t" | 422 | seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t" |
417 | "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n", | 423 | "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n", |
418 | r->dst.dev ? r->dst.dev->name : "*", | 424 | r->dst.dev ? r->dst.dev->name : "*", |
@@ -425,9 +431,8 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) | |||
425 | (int)((dst_metric(&r->dst, RTAX_RTT) >> 3) + | 431 | (int)((dst_metric(&r->dst, RTAX_RTT) >> 3) + |
426 | dst_metric(&r->dst, RTAX_RTTVAR)), | 432 | dst_metric(&r->dst, RTAX_RTTVAR)), |
427 | r->rt_key_tos, | 433 | r->rt_key_tos, |
428 | r->dst.hh ? atomic_read(&r->dst.hh->hh_refcnt) : -1, | 434 | -1, |
429 | r->dst.hh ? (r->dst.hh->hh_output == | 435 | (n && (n->nud_state & NUD_CONNECTED)) ? 1 : 0, |
430 | dev_queue_xmit) : 0, | ||
431 | r->rt_spec_dst, &len); | 436 | r->rt_spec_dst, &len); |
432 | 437 | ||
433 | seq_printf(seq, "%*s\n", 127 - len, ""); | 438 | seq_printf(seq, "%*s\n", 127 - len, ""); |
@@ -1006,6 +1011,37 @@ static int slow_chain_length(const struct rtable *head) | |||
1006 | return length >> FRACT_BITS; | 1011 | return length >> FRACT_BITS; |
1007 | } | 1012 | } |
1008 | 1013 | ||
1014 | static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, const void *daddr) | ||
1015 | { | ||
1016 | struct neigh_table *tbl = &arp_tbl; | ||
1017 | static const __be32 inaddr_any = 0; | ||
1018 | struct net_device *dev = dst->dev; | ||
1019 | const __be32 *pkey = daddr; | ||
1020 | struct neighbour *n; | ||
1021 | |||
1022 | #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) | ||
1023 | if (dev->type == ARPHRD_ATM) | ||
1024 | tbl = clip_tbl_hook; | ||
1025 | #endif | ||
1026 | if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) | ||
1027 | pkey = &inaddr_any; | ||
1028 | |||
1029 | n = __ipv4_neigh_lookup(tbl, dev, *(__force u32 *)pkey); | ||
1030 | if (n) | ||
1031 | return n; | ||
1032 | return neigh_create(tbl, pkey, dev); | ||
1033 | } | ||
1034 | |||
1035 | static int rt_bind_neighbour(struct rtable *rt) | ||
1036 | { | ||
1037 | struct neighbour *n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway); | ||
1038 | if (IS_ERR(n)) | ||
1039 | return PTR_ERR(n); | ||
1040 | dst_set_neighbour(&rt->dst, n); | ||
1041 | |||
1042 | return 0; | ||
1043 | } | ||
1044 | |||
1009 | static struct rtable *rt_intern_hash(unsigned hash, struct rtable *rt, | 1045 | static struct rtable *rt_intern_hash(unsigned hash, struct rtable *rt, |
1010 | struct sk_buff *skb, int ifindex) | 1046 | struct sk_buff *skb, int ifindex) |
1011 | { | 1047 | { |
@@ -1042,7 +1078,7 @@ restart: | |||
1042 | 1078 | ||
1043 | rt->dst.flags |= DST_NOCACHE; | 1079 | rt->dst.flags |= DST_NOCACHE; |
1044 | if (rt->rt_type == RTN_UNICAST || rt_is_output_route(rt)) { | 1080 | if (rt->rt_type == RTN_UNICAST || rt_is_output_route(rt)) { |
1045 | int err = arp_bind_neighbour(&rt->dst); | 1081 | int err = rt_bind_neighbour(rt); |
1046 | if (err) { | 1082 | if (err) { |
1047 | if (net_ratelimit()) | 1083 | if (net_ratelimit()) |
1048 | printk(KERN_WARNING | 1084 | printk(KERN_WARNING |
@@ -1138,7 +1174,7 @@ restart: | |||
1138 | route or unicast forwarding path. | 1174 | route or unicast forwarding path. |
1139 | */ | 1175 | */ |
1140 | if (rt->rt_type == RTN_UNICAST || rt_is_output_route(rt)) { | 1176 | if (rt->rt_type == RTN_UNICAST || rt_is_output_route(rt)) { |
1141 | int err = arp_bind_neighbour(&rt->dst); | 1177 | int err = rt_bind_neighbour(rt); |
1142 | if (err) { | 1178 | if (err) { |
1143 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1179 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1144 | 1180 | ||
@@ -1439,20 +1475,20 @@ static int ip_error(struct sk_buff *skb) | |||
1439 | int code; | 1475 | int code; |
1440 | 1476 | ||
1441 | switch (rt->dst.error) { | 1477 | switch (rt->dst.error) { |
1442 | case EINVAL: | 1478 | case EINVAL: |
1443 | default: | 1479 | default: |
1444 | goto out; | 1480 | goto out; |
1445 | case EHOSTUNREACH: | 1481 | case EHOSTUNREACH: |
1446 | code = ICMP_HOST_UNREACH; | 1482 | code = ICMP_HOST_UNREACH; |
1447 | break; | 1483 | break; |
1448 | case ENETUNREACH: | 1484 | case ENETUNREACH: |
1449 | code = ICMP_NET_UNREACH; | 1485 | code = ICMP_NET_UNREACH; |
1450 | IP_INC_STATS_BH(dev_net(rt->dst.dev), | 1486 | IP_INC_STATS_BH(dev_net(rt->dst.dev), |
1451 | IPSTATS_MIB_INNOROUTES); | 1487 | IPSTATS_MIB_INNOROUTES); |
1452 | break; | 1488 | break; |
1453 | case EACCES: | 1489 | case EACCES: |
1454 | code = ICMP_PKT_FILTERED; | 1490 | code = ICMP_PKT_FILTERED; |
1455 | break; | 1491 | break; |
1456 | } | 1492 | } |
1457 | 1493 | ||
1458 | if (!rt->peer) | 1494 | if (!rt->peer) |
@@ -1592,23 +1628,24 @@ static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) | |||
1592 | { | 1628 | { |
1593 | struct rtable *rt = (struct rtable *) dst; | 1629 | struct rtable *rt = (struct rtable *) dst; |
1594 | __be32 orig_gw = rt->rt_gateway; | 1630 | __be32 orig_gw = rt->rt_gateway; |
1631 | struct neighbour *n; | ||
1595 | 1632 | ||
1596 | dst_confirm(&rt->dst); | 1633 | dst_confirm(&rt->dst); |
1597 | 1634 | ||
1598 | neigh_release(rt->dst.neighbour); | 1635 | neigh_release(dst_get_neighbour(&rt->dst)); |
1599 | rt->dst.neighbour = NULL; | 1636 | dst_set_neighbour(&rt->dst, NULL); |
1600 | 1637 | ||
1601 | rt->rt_gateway = peer->redirect_learned.a4; | 1638 | rt->rt_gateway = peer->redirect_learned.a4; |
1602 | if (arp_bind_neighbour(&rt->dst) || | 1639 | rt_bind_neighbour(rt); |
1603 | !(rt->dst.neighbour->nud_state & NUD_VALID)) { | 1640 | n = dst_get_neighbour(&rt->dst); |
1604 | if (rt->dst.neighbour) | 1641 | if (!n || !(n->nud_state & NUD_VALID)) { |
1605 | neigh_event_send(rt->dst.neighbour, NULL); | 1642 | if (n) |
1643 | neigh_event_send(n, NULL); | ||
1606 | rt->rt_gateway = orig_gw; | 1644 | rt->rt_gateway = orig_gw; |
1607 | return -EAGAIN; | 1645 | return -EAGAIN; |
1608 | } else { | 1646 | } else { |
1609 | rt->rt_flags |= RTCF_REDIRECTED; | 1647 | rt->rt_flags |= RTCF_REDIRECTED; |
1610 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, | 1648 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); |
1611 | rt->dst.neighbour); | ||
1612 | } | 1649 | } |
1613 | return 0; | 1650 | return 0; |
1614 | } | 1651 | } |
@@ -2708,6 +2745,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { | |||
2708 | .default_advmss = ipv4_default_advmss, | 2745 | .default_advmss = ipv4_default_advmss, |
2709 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, | 2746 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, |
2710 | .cow_metrics = ipv4_rt_blackhole_cow_metrics, | 2747 | .cow_metrics = ipv4_rt_blackhole_cow_metrics, |
2748 | .neigh_lookup = ipv4_neigh_lookup, | ||
2711 | }; | 2749 | }; |
2712 | 2750 | ||
2713 | struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig) | 2751 | struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig) |
@@ -3303,7 +3341,7 @@ int __init ip_rt_init(void) | |||
3303 | xfrm_init(); | 3341 | xfrm_init(); |
3304 | xfrm4_init(ip_rt_max_size); | 3342 | xfrm4_init(ip_rt_max_size); |
3305 | #endif | 3343 | #endif |
3306 | rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL); | 3344 | rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL, NULL); |
3307 | 3345 | ||
3308 | #ifdef CONFIG_SYSCTL | 3346 | #ifdef CONFIG_SYSCTL |
3309 | register_pernet_subsys(&sysctl_route_ops); | 3347 | register_pernet_subsys(&sysctl_route_ops); |