diff options
Diffstat (limited to 'net/ipv4/arp.c')
| -rw-r--r-- | net/ipv4/arp.c | 59 |
1 files changed, 52 insertions, 7 deletions
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index c95cd93acf29..6e747065c202 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c | |||
| @@ -70,6 +70,7 @@ | |||
| 70 | * bonding can change the skb before | 70 | * bonding can change the skb before |
| 71 | * sending (e.g. insert 8021q tag). | 71 | * sending (e.g. insert 8021q tag). |
| 72 | * Harald Welte : convert to make use of jenkins hash | 72 | * Harald Welte : convert to make use of jenkins hash |
| 73 | * Jesper D. Brouer: Proxy ARP PVLAN RFC 3069 support. | ||
| 73 | */ | 74 | */ |
| 74 | 75 | ||
| 75 | #include <linux/module.h> | 76 | #include <linux/module.h> |
| @@ -97,6 +98,7 @@ | |||
| 97 | #include <linux/net.h> | 98 | #include <linux/net.h> |
| 98 | #include <linux/rcupdate.h> | 99 | #include <linux/rcupdate.h> |
| 99 | #include <linux/jhash.h> | 100 | #include <linux/jhash.h> |
| 101 | #include <linux/slab.h> | ||
| 100 | #ifdef CONFIG_SYSCTL | 102 | #ifdef CONFIG_SYSCTL |
| 101 | #include <linux/sysctl.h> | 103 | #include <linux/sysctl.h> |
| 102 | #endif | 104 | #endif |
| @@ -524,12 +526,15 @@ int arp_bind_neighbour(struct dst_entry *dst) | |||
| 524 | /* | 526 | /* |
| 525 | * Check if we can use proxy ARP for this path | 527 | * Check if we can use proxy ARP for this path |
| 526 | */ | 528 | */ |
| 527 | 529 | static inline int arp_fwd_proxy(struct in_device *in_dev, | |
| 528 | static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt) | 530 | struct net_device *dev, struct rtable *rt) |
| 529 | { | 531 | { |
| 530 | struct in_device *out_dev; | 532 | struct in_device *out_dev; |
| 531 | int imi, omi = -1; | 533 | int imi, omi = -1; |
| 532 | 534 | ||
| 535 | if (rt->u.dst.dev == dev) | ||
| 536 | return 0; | ||
| 537 | |||
| 533 | if (!IN_DEV_PROXY_ARP(in_dev)) | 538 | if (!IN_DEV_PROXY_ARP(in_dev)) |
| 534 | return 0; | 539 | return 0; |
| 535 | 540 | ||
| @@ -548,6 +553,43 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt) | |||
| 548 | } | 553 | } |
| 549 | 554 | ||
| 550 | /* | 555 | /* |
| 556 | * Check for RFC3069 proxy arp private VLAN (allow to send back to same dev) | ||
| 557 | * | ||
| 558 | * RFC3069 supports proxy arp replies back to the same interface. This | ||
| 559 | * is done to support (ethernet) switch features, like RFC 3069, where | ||
| 560 | * the individual ports are not allowed to communicate with each | ||
| 561 | * other, BUT they are allowed to talk to the upstream router. As | ||
| 562 | * described in RFC 3069, it is possible to allow these hosts to | ||
| 563 | * communicate through the upstream router, by proxy_arp'ing. | ||
| 564 | * | ||
| 565 | * RFC 3069: "VLAN Aggregation for Efficient IP Address Allocation" | ||
| 566 | * | ||
| 567 | * This technology is known by different names: | ||
| 568 | * In RFC 3069 it is called VLAN Aggregation. | ||
| 569 | * Cisco and Allied Telesyn call it Private VLAN. | ||
| 570 | * Hewlett-Packard call it Source-Port filtering or port-isolation. | ||
| 571 | * Ericsson call it MAC-Forced Forwarding (RFC Draft). | ||
| 572 | * | ||
| 573 | */ | ||
| 574 | static inline int arp_fwd_pvlan(struct in_device *in_dev, | ||
| 575 | struct net_device *dev, struct rtable *rt, | ||
| 576 | __be32 sip, __be32 tip) | ||
| 577 | { | ||
| 578 | /* Private VLAN is only concerned about the same ethernet segment */ | ||
| 579 | if (rt->u.dst.dev != dev) | ||
| 580 | return 0; | ||
| 581 | |||
| 582 | /* Don't reply on self probes (often done by windowz boxes)*/ | ||
| 583 | if (sip == tip) | ||
| 584 | return 0; | ||
| 585 | |||
| 586 | if (IN_DEV_PROXY_ARP_PVLAN(in_dev)) | ||
| 587 | return 1; | ||
| 588 | else | ||
| 589 | return 0; | ||
| 590 | } | ||
| 591 | |||
| 592 | /* | ||
| 551 | * Interface to link layer: send routine and receive handler. | 593 | * Interface to link layer: send routine and receive handler. |
| 552 | */ | 594 | */ |
| 553 | 595 | ||
| @@ -833,8 +875,11 @@ static int arp_process(struct sk_buff *skb) | |||
| 833 | } | 875 | } |
| 834 | goto out; | 876 | goto out; |
| 835 | } else if (IN_DEV_FORWARD(in_dev)) { | 877 | } else if (IN_DEV_FORWARD(in_dev)) { |
| 836 | if (addr_type == RTN_UNICAST && rt->u.dst.dev != dev && | 878 | if (addr_type == RTN_UNICAST && |
| 837 | (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) { | 879 | (arp_fwd_proxy(in_dev, dev, rt) || |
| 880 | arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || | ||
| 881 | pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) | ||
| 882 | { | ||
| 838 | n = neigh_event_ns(&arp_tbl, sha, &sip, dev); | 883 | n = neigh_event_ns(&arp_tbl, sha, &sip, dev); |
| 839 | if (n) | 884 | if (n) |
| 840 | neigh_release(n); | 885 | neigh_release(n); |
| @@ -863,7 +908,8 @@ static int arp_process(struct sk_buff *skb) | |||
| 863 | devices (strip is candidate) | 908 | devices (strip is candidate) |
| 864 | */ | 909 | */ |
| 865 | if (n == NULL && | 910 | if (n == NULL && |
| 866 | arp->ar_op == htons(ARPOP_REPLY) && | 911 | (arp->ar_op == htons(ARPOP_REPLY) || |
| 912 | (arp->ar_op == htons(ARPOP_REQUEST) && tip == sip)) && | ||
| 867 | inet_addr_type(net, sip) == RTN_UNICAST) | 913 | inet_addr_type(net, sip) == RTN_UNICAST) |
| 868 | n = __neigh_lookup(&arp_tbl, &sip, dev, 1); | 914 | n = __neigh_lookup(&arp_tbl, &sip, dev, 1); |
| 869 | } | 915 | } |
| @@ -1239,8 +1285,7 @@ void __init arp_init(void) | |||
| 1239 | dev_add_pack(&arp_packet_type); | 1285 | dev_add_pack(&arp_packet_type); |
| 1240 | arp_proc_init(); | 1286 | arp_proc_init(); |
| 1241 | #ifdef CONFIG_SYSCTL | 1287 | #ifdef CONFIG_SYSCTL |
| 1242 | neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, | 1288 | neigh_sysctl_register(NULL, &arp_tbl.parms, "ipv4", NULL); |
| 1243 | NET_IPV4_NEIGH, "ipv4", NULL); | ||
| 1244 | #endif | 1289 | #endif |
| 1245 | register_netdevice_notifier(&arp_netdev_notifier); | 1290 | register_netdevice_notifier(&arp_netdev_notifier); |
| 1246 | } | 1291 | } |
