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 /net/ipv4 | |
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>
Diffstat (limited to 'net/ipv4')
-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 25d9e98e31fa..640203a153c6 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) { |