diff options
| author | Vince Busam <vbusam@google.com> | 2008-09-02 09:55:52 -0400 |
|---|---|---|
| committer | Simon Horman <horms@verge.net.au> | 2008-09-04 21:17:12 -0400 |
| commit | 09571c7ae30865adfa79dccd12a822a65d2c4b5a (patch) | |
| tree | 4a6b129d70b8dab77bb8f80fff98d9827a5a06ef | |
| parent | a0eb662f9ec8962928d937a185ad128db12c4637 (diff) | |
IPVS: Add function to determine if IPv6 address is local
Add __ip_vs_addr_is_local_v6() to find out if an IPv6 address belongs to a
local interface. Use this function to decide whether to set the
IP_VS_CONN_F_LOCALNODE flag for IPv6 destinations.
Signed-off-by: Vince Busam <vbusam@google.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
| -rw-r--r-- | net/ipv4/ipvs/ip_vs_ctl.c | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index 25d9e98e31f..640203a153c 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c | |||
| @@ -35,6 +35,10 @@ | |||
| 35 | 35 | ||
| 36 | #include <net/net_namespace.h> | 36 | #include <net/net_namespace.h> |
| 37 | #include <net/ip.h> | 37 | #include <net/ip.h> |
| 38 | #ifdef CONFIG_IP_VS_IPV6 | ||
| 39 | #include <net/ipv6.h> | ||
| 40 | #include <net/ip6_route.h> | ||
| 41 | #endif | ||
| 38 | #include <net/route.h> | 42 | #include <net/route.h> |
| 39 | #include <net/sock.h> | 43 | #include <net/sock.h> |
| 40 | #include <net/genetlink.h> | 44 | #include <net/genetlink.h> |
| @@ -91,6 +95,26 @@ int ip_vs_get_debug_level(void) | |||
| 91 | } | 95 | } |
| 92 | #endif | 96 | #endif |
| 93 | 97 | ||
| 98 | #ifdef CONFIG_IP_VS_IPV6 | ||
| 99 | /* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */ | ||
| 100 | static int __ip_vs_addr_is_local_v6(const struct in6_addr *addr) | ||
| 101 | { | ||
| 102 | struct rt6_info *rt; | ||
| 103 | struct flowi fl = { | ||
| 104 | .oif = 0, | ||
| 105 | .nl_u = { | ||
| 106 | .ip6_u = { | ||
| 107 | .daddr = *addr, | ||
| 108 | .saddr = { .s6_addr32 = {0, 0, 0, 0} }, } }, | ||
| 109 | }; | ||
| 110 | |||
| 111 | rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl); | ||
| 112 | if (rt && rt->rt6i_dev && (rt->rt6i_dev->flags & IFF_LOOPBACK)) | ||
| 113 | return 1; | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | #endif | ||
| 94 | /* | 118 | /* |
| 95 | * update_defense_level is called from keventd and from sysctl, | 119 | * update_defense_level is called from keventd and from sysctl, |
| 96 | * so it needs to protect itself from softirqs | 120 | * so it needs to protect itself from softirqs |
| @@ -751,10 +775,18 @@ __ip_vs_update_dest(struct ip_vs_service *svc, | |||
| 751 | conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE; | 775 | conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE; |
| 752 | 776 | ||
| 753 | /* check if local node and update the flags */ | 777 | /* check if local node and update the flags */ |
| 754 | if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) { | 778 | #ifdef CONFIG_IP_VS_IPV6 |
| 755 | conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK) | 779 | if (svc->af == AF_INET6) { |
| 756 | | IP_VS_CONN_F_LOCALNODE; | 780 | if (__ip_vs_addr_is_local_v6(&udest->addr.in6)) { |
| 757 | } | 781 | conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK) |
| 782 | | IP_VS_CONN_F_LOCALNODE; | ||
| 783 | } | ||
| 784 | } else | ||
| 785 | #endif | ||
| 786 | if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) { | ||
| 787 | conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK) | ||
| 788 | | IP_VS_CONN_F_LOCALNODE; | ||
| 789 | } | ||
| 758 | 790 | ||
| 759 | /* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */ | 791 | /* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */ |
| 760 | if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) { | 792 | if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) { |
| @@ -803,9 +835,19 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest, | |||
| 803 | 835 | ||
| 804 | EnterFunction(2); | 836 | EnterFunction(2); |
| 805 | 837 | ||
| 806 | atype = inet_addr_type(&init_net, udest->addr.ip); | 838 | #ifdef CONFIG_IP_VS_IPV6 |
| 807 | if (atype != RTN_LOCAL && atype != RTN_UNICAST) | 839 | if (svc->af == AF_INET6) { |
| 808 | return -EINVAL; | 840 | atype = ipv6_addr_type(&udest->addr.in6); |
| 841 | if (!(atype & IPV6_ADDR_UNICAST) && | ||
| 842 | !__ip_vs_addr_is_local_v6(&udest->addr.in6)) | ||
| 843 | return -EINVAL; | ||
| 844 | } else | ||
| 845 | #endif | ||
| 846 | { | ||
| 847 | atype = inet_addr_type(&init_net, udest->addr.ip); | ||
| 848 | if (atype != RTN_LOCAL && atype != RTN_UNICAST) | ||
| 849 | return -EINVAL; | ||
| 850 | } | ||
| 809 | 851 | ||
| 810 | dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC); | 852 | dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC); |
| 811 | if (dest == NULL) { | 853 | if (dest == NULL) { |
