diff options
author | Jesper Dangaard Brouer <hawk@comx.dk> | 2010-01-05 00:50:47 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-01-07 03:59:09 -0500 |
commit | 65324144b50bc7022cc9b6ca8f4a536a957019e3 (patch) | |
tree | 1e910817f6d4f1ecd821bfd8ce493f81fe4aae60 /net/ipv4 | |
parent | ca8d9ea30bc79b2965a1d169dcb2f48f02af4d2d (diff) |
net: RFC3069, private VLAN proxy arp support
This is to be used together with switch technologies, like RFC3069,
that where the individual ports are not allowed to communicate with
each other, but they are allowed to talk to the upstream router. As
described in RFC 3069, it is possible to allow these hosts to
communicate through the upstream router by proxy_arp'ing.
This patch basically allow proxy arp replies back to the same
interface (from which the ARP request/solicitation was received).
Tunable per device via proc "proxy_arp_pvlan":
/proc/sys/net/ipv4/conf/*/proxy_arp_pvlan
This switch technology is known by different vendor names:
- In RFC 3069 it is called VLAN Aggregation.
- Cisco and Allied Telesyn call it Private VLAN.
- Hewlett-Packard call it Source-Port filtering or port-isolation.
- Ericsson call it MAC-Forced Forwarding (RFC Draft).
Signed-off-by: Jesper Dangaard Brouer <hawk@comx.dk>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/arp.c | 52 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 1 | ||||
-rw-r--r-- | net/ipv4/route.c | 7 |
3 files changed, 55 insertions, 5 deletions
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index c95cd93acf29..078709233bc4 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> |
@@ -524,12 +525,15 @@ int arp_bind_neighbour(struct dst_entry *dst) | |||
524 | /* | 525 | /* |
525 | * Check if we can use proxy ARP for this path | 526 | * Check if we can use proxy ARP for this path |
526 | */ | 527 | */ |
527 | 528 | 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) | 529 | struct net_device *dev, struct rtable *rt) |
529 | { | 530 | { |
530 | struct in_device *out_dev; | 531 | struct in_device *out_dev; |
531 | int imi, omi = -1; | 532 | int imi, omi = -1; |
532 | 533 | ||
534 | if (rt->u.dst.dev == dev) | ||
535 | return 0; | ||
536 | |||
533 | if (!IN_DEV_PROXY_ARP(in_dev)) | 537 | if (!IN_DEV_PROXY_ARP(in_dev)) |
534 | return 0; | 538 | return 0; |
535 | 539 | ||
@@ -548,6 +552,43 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt) | |||
548 | } | 552 | } |
549 | 553 | ||
550 | /* | 554 | /* |
555 | * Check for RFC3069 proxy arp private VLAN (allow to send back to same dev) | ||
556 | * | ||
557 | * RFC3069 supports proxy arp replies back to the same interface. This | ||
558 | * is done to support (ethernet) switch features, like RFC 3069, where | ||
559 | * the individual ports are not allowed to communicate with each | ||
560 | * other, BUT they are allowed to talk to the upstream router. As | ||
561 | * described in RFC 3069, it is possible to allow these hosts to | ||
562 | * communicate through the upstream router, by proxy_arp'ing. | ||
563 | * | ||
564 | * RFC 3069: "VLAN Aggregation for Efficient IP Address Allocation" | ||
565 | * | ||
566 | * This technology is known by different names: | ||
567 | * In RFC 3069 it is called VLAN Aggregation. | ||
568 | * Cisco and Allied Telesyn call it Private VLAN. | ||
569 | * Hewlett-Packard call it Source-Port filtering or port-isolation. | ||
570 | * Ericsson call it MAC-Forced Forwarding (RFC Draft). | ||
571 | * | ||
572 | */ | ||
573 | static inline int arp_fwd_pvlan(struct in_device *in_dev, | ||
574 | struct net_device *dev, struct rtable *rt, | ||
575 | __be32 sip, __be32 tip) | ||
576 | { | ||
577 | /* Private VLAN is only concerned about the same ethernet segment */ | ||
578 | if (rt->u.dst.dev != dev) | ||
579 | return 0; | ||
580 | |||
581 | /* Don't reply on self probes (often done by windowz boxes)*/ | ||
582 | if (sip == tip) | ||
583 | return 0; | ||
584 | |||
585 | if (IN_DEV_PROXY_ARP_PVLAN(in_dev)) | ||
586 | return 1; | ||
587 | else | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | /* | ||
551 | * Interface to link layer: send routine and receive handler. | 592 | * Interface to link layer: send routine and receive handler. |
552 | */ | 593 | */ |
553 | 594 | ||
@@ -833,8 +874,11 @@ static int arp_process(struct sk_buff *skb) | |||
833 | } | 874 | } |
834 | goto out; | 875 | goto out; |
835 | } else if (IN_DEV_FORWARD(in_dev)) { | 876 | } else if (IN_DEV_FORWARD(in_dev)) { |
836 | if (addr_type == RTN_UNICAST && rt->u.dst.dev != dev && | 877 | if (addr_type == RTN_UNICAST && |
837 | (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) { | 878 | (arp_fwd_proxy(in_dev, dev, rt) || |
879 | arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || | ||
880 | pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) | ||
881 | { | ||
838 | n = neigh_event_ns(&arp_tbl, sha, &sip, dev); | 882 | n = neigh_event_ns(&arp_tbl, sha, &sip, dev); |
839 | if (n) | 883 | if (n) |
840 | neigh_release(n); | 884 | neigh_release(n); |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 5cdbc102a418..0715f4cac391 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -1407,6 +1407,7 @@ static struct devinet_sysctl_table { | |||
1407 | DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"), | 1407 | DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"), |
1408 | DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"), | 1408 | DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"), |
1409 | DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"), | 1409 | DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"), |
1410 | DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"), | ||
1410 | 1411 | ||
1411 | DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"), | 1412 | DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"), |
1412 | DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"), | 1413 | DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"), |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index e446496f564f..1cc339441e7d 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1988,8 +1988,13 @@ static int __mkroute_input(struct sk_buff *skb, | |||
1988 | if (skb->protocol != htons(ETH_P_IP)) { | 1988 | if (skb->protocol != htons(ETH_P_IP)) { |
1989 | /* Not IP (i.e. ARP). Do not create route, if it is | 1989 | /* Not IP (i.e. ARP). Do not create route, if it is |
1990 | * invalid for proxy arp. DNAT routes are always valid. | 1990 | * invalid for proxy arp. DNAT routes are always valid. |
1991 | * | ||
1992 | * Proxy arp feature have been extended to allow, ARP | ||
1993 | * replies back to the same interface, to support | ||
1994 | * Private VLAN switch technologies. See arp.c. | ||
1991 | */ | 1995 | */ |
1992 | if (out_dev == in_dev) { | 1996 | if (out_dev == in_dev && |
1997 | IN_DEV_PROXY_ARP_PVLAN(in_dev) == 0) { | ||
1993 | err = -EINVAL; | 1998 | err = -EINVAL; |
1994 | goto cleanup; | 1999 | goto cleanup; |
1995 | } | 2000 | } |