Hi, Ok, it might be the time to post these experimental IPv6 patches for IPVS again to get some comments and help. Since the last time, I've worked on reducing a lot of unnecessary code duplication, but some is still there where it was harder to get rid of. Also, we've implemented a genetlink interface (the first two patches in this series are exactly the v4 version of that) and updated ipvsadm to work with it, so we do not have to break the existing sockopt userspace interface. Of course, there are also many other small fixes and changes since the last version. - Full kernel patch in one file against davem's net-2.6: http://www-user.tu-chemnitz.de/~volz/ipvs_ipv6/ipvs_ipv6.patch While not all IPv6 features are working or tested, existing IPv4 features should still work as before. However, to use any of the new features, you will need a new ipvsadm with support for genetlink and IPv6: http://sixpak.org/vince/google/ipvsadm/ (by Vince Busam) To enable IPv6 support in IPVS, set CONFIG_IP_VS_IPV6=y. Short overview: What works with IPv6: - forwarding mechanisms: NAT, DR, maybe Tunnel (not fully tested yet) - protocols: TCP, UDP, ESP, AH (last two not tested) - manipulation and inspection of both IPv4 and IPv6 entries with ipvsadm - 6 out of 10 schedulers What is not supported with IPv6: - handling fragmentation or other extension headers - FTP application helper (can be loaded, but only operates on v4) - sync daemon (can be started, but only operates on v4) - probably some incorrect handling of ICMPv6 or other corner cases Since fragmentation and extension headers should not occur very often, things should "mostly" work. I tested HTTP and DNS over NAT and DR with various supported schedulers without encountering any problems. But we didn't test any exotic situations. Also, there are some TODOs in the code for things that haven't been tested or implemented yet. Thanks for any comments! Julius --
Add the implementation of the new Generic Netlink interface to IPVS and
keep the old set/getsockopt interface for userspace backwards
compatibility.
Signed-off-by: Julius Volz <juliusv@google.com>
1 files changed, 875 insertions(+), 0 deletions(-)
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 6379705..d1dbd8b 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -37,6 +37,7 @@
#include <net/ip.h>
#include <net/route.h>
#include <net/sock.h>
+#include <net/genetlink.h>
#include <asm/uaccess.h>
@@ -2320,6 +2321,872 @@ static struct nf_sockopt_ops ip_vs_sockopts = {
.owner = THIS_MODULE,
};
+/*
+ * Generic Netlink interface
+ */
+
+/* IPVS genetlink family */
+static struct genl_family ip_vs_genl_family = {
+ .id = GENL_ID_GENERATE,
+ .hdrsize = 0,
+ .name = IPVS_GENL_NAME,
+ .version = IPVS_GENL_VERSION,
+ .maxattr = IPVS_CMD_MAX,
+};
+
+/* Policy used for first-level command attributes */
+static const struct nla_policy ip_vs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] = {
+ [IPVS_CMD_ATTR_SERVICE] = { .type = NLA_NESTED },
+ [IPVS_CMD_ATTR_DEST] = { .type = NLA_NESTED },
+ [IPVS_CMD_ATTR_DAEMON] = { .type = NLA_NESTED },
+ [IPVS_CMD_ATTR_TIMEOUT_TCP] = { .type = NLA_U32 },
+ [IPVS_CMD_ATTR_TIMEOUT_TCP_FIN] = { .type = NLA_U32 },
+ [IPVS_CMD_ATTR_TIMEOUT_UDP] = { .type = NLA_U32 },
+};
+
+/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DAEMON */
+static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = {
+ [IPVS_DAEMON_ATTR_STATE] = { .type = NLA_U32 },
+ [IPVS_DAEMON_ATTR_MCAST_IFN] = { .type = NLA_NUL_STRING,
+ .len = IP_VS_IFNAME_MAXLEN },
+ [IPVS_DAEMON_ATTR_SYNC_ID] = { .type = NLA_U32 },
+};
+
+/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_SERVICE */
+static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = {
+ [IPVS_SVC_ATTR_AF] = { .type = NLA_U16 },
+ [IPVS_SVC_ATTR_PROTOCOL] = { .type = NLA_U16 ...Allow adding IPv6 services in genetlink interface.
Signed-off-by: Julius Volz <juliusv@google.com>
1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 73150ce..f2caf56 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -2565,7 +2565,7 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
if (!nl_service)
return -EMSGSIZE;
- NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, AF_INET);
+ NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, svc->af);
if (svc->fwmark) {
NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark);
@@ -2671,8 +2671,12 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc,
if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr))))
return -EINVAL;
- /* For now, only support IPv4 */
- if (nla_get_u16(nla_af) != AF_INET)
+ usvc->af = nla_get_u16(nla_af);
+#ifdef CONFIG_IP_VS_IPV6
+ if (usvc->af != AF_INET && usvc->af != AF_INET6)
+#else
+ if (usvc->af != AF_INET)
+#endif
return -EAFNOSUPPORT;
if (nla_fwmark) {
--
1.5.4.5
--
Introduce new 'af' fields into IPVS data structures for specifying an
entry's address family. Convert IP addresses to be of type union
nf_inet_addr. Add extended internal versions of ip_vs_service_user and
struct ip_vs_dest_user (the originals can't be modified as they are part
of the old sockopt interface).
Signed-off-by: Julius Volz <juliusv@google.com>
1 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 7312c3d..e41a164 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -21,6 +21,9 @@
#include <linux/timer.h>
#include <net/checksum.h>
+#include <linux/netfilter.h> /* for union nf_inet_addr */
+#include <linux/ipv6.h> /* for struct ipv6hdr */
+#include <net/ipv6.h> /* for ipv6_addr_copy */
#ifdef CONFIG_IP_VS_DEBUG
#include <linux/net.h>
@@ -259,9 +262,10 @@ struct ip_vs_conn {
struct list_head c_list; /* hashed list heads */
/* Protocol, addresses and port numbers */
- __be32 caddr; /* client address */
- __be32 vaddr; /* virtual address */
- __be32 daddr; /* destination address */
+ u_int16_t af; /* address family */
+ union nf_inet_addr caddr; /* client address */
+ union nf_inet_addr vaddr; /* virtual address */
+ union nf_inet_addr daddr; /* destination address */
__be16 cport;
__be16 vport;
__be16 dport;
@@ -305,6 +309,45 @@ struct ip_vs_conn {
/*
+ * Extended internal versions of struct ip_vs_service_user and
+ * ip_vs_dest_user for IPv6 support.
+ *
+ * We need these to conveniently pass around service and destination
+ * options, but unfortunately, we also need to keep the old definitions to
+ * maintain userspace backwards compatibility for the setsockopt interface.
+ */
+struct ip_vs_service_user_kern {
+ /* virtual service addresses ...Add IPv6 support to ip_vs_conn_hashkey() by adding an 'af' argument and
update callers.
Signed-off-by: Julius Volz <juliusv@google.com>
1 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 1a6b9d8..5e013c9 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -114,13 +114,21 @@ static inline void ct_write_unlock_bh(unsigned key)
/*
* Returns hash value for IPVS connection entry
*/
-static unsigned int ip_vs_conn_hashkey(unsigned proto, __be32 addr, __be16 port)
+static unsigned int ip_vs_conn_hashkey(int af, unsigned proto,
+ const union nf_inet_addr *addr,
+ __be16 port)
{
- return jhash_3words((__force u32)addr, (__force u32)port, proto, ip_vs_conn_rnd)
+#ifdef CONFIG_IP_VS_IPV6
+ if (af == AF_INET6)
+ return jhash_3words(jhash(addr, 16, ip_vs_conn_rnd),
+ (__force u32)port, proto, ip_vs_conn_rnd)
+ & IP_VS_CONN_TAB_MASK;
+#endif
+ return jhash_3words((__force u32)addr->ip, (__force u32)port, proto,
+ ip_vs_conn_rnd)
& IP_VS_CONN_TAB_MASK;
}
-
/*
* Hashes ip_vs_conn in ip_vs_conn_tab by proto,addr,port.
* returns bool success.
@@ -131,7 +139,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
int ret;
/* Hash by protocol, client address and port */
- hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
+ hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
ct_write_lock(hash);
@@ -162,7 +170,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
int ret;
/* unhash it and decrease its reference counter */
- hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
+ hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
ct_write_lock(hash);
--
1.5.4.5
--
Immediately return from FTP application helper and do nothing when dealing with IPv6 packets. IPv6 is not supported by this helper yet. Signed-off-by: Julius Volz <juliusv@google.com> 1 files changed, 16 insertions(+), 0 deletions(-) diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c index c1c758e..b4c7491 100644 --- a/net/ipv4/ipvs/ip_vs_ftp.c +++ b/net/ipv4/ipvs/ip_vs_ftp.c @@ -147,6 +147,14 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, unsigned buf_len; int ret; +#ifdef CONFIG_IP_VS_IPV6 + /* This application helper doesn't work with IPv6 yet, + * so turn this into a no-op for IPv6 packets + */ + if (cp->af == AF_INET6) + return 1; +#endif + *diff = 0; /* Only useful for established sessions */ @@ -247,6 +255,14 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, __be16 port; struct ip_vs_conn *n_cp; +#ifdef CONFIG_IP_VS_IPV6 + /* This application helper doesn't work with IPv6 yet, + * so turn this into a no-op for IPv6 packets + */ + if (cp->af == AF_INET6) + return 1; +#endif + /* no diff required for incoming packets */ *diff = 0; -- 1.5.4.5 --
Add notes about the IPv6 changes to header comments in relevant files. Signed-off-by: Julius Volz <juliusv@google.com> 5 files changed, 5 insertions(+), 0 deletions(-) diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c index 011d455..aa6f43b 100644 --- a/net/ipv4/ipvs/ip_vs_conn.c +++ b/net/ipv4/ipvs/ip_vs_conn.c @@ -19,6 +19,7 @@ * and others. Many code here is taken from IP MASQ code of kernel 2.2. * * Changes: + * Julius Volz add first IPv6 support * */ diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 0f9a0a2..5bb53c0 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -21,6 +21,7 @@ * Changes: * Paul `Rusty' Russell properly handle non-linear skbs * Harald Welte don't use nfcache + * Julius Volz add first IPv6 support * */ diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index ba4d7c2..ec5e855 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c @@ -15,6 +15,7 @@ * 2 of the License, or (at your option) any later version. * * Changes: + * Julius Volz, Vince Busam add first IPv6 support * */ diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c index 301b779..5c4b8f9 100644 --- a/net/ipv4/ipvs/ip_vs_proto.c +++ b/net/ipv4/ipvs/ip_vs_proto.c @@ -10,6 +10,7 @@ * 2 of the License, or (at your option) any later version. * * Changes: + * Julius Volz add first IPv6 support * */ diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c index 15c59aa..e1a3fde 100644 --- a/net/ipv4/ipvs/ip_vs_xmit.c +++ b/net/ipv4/ipvs/ip_vs_xmit.c @@ -10,6 +10,7 @@ * 2 of the License, or (at your option) any later version. * * Changes: + * Julius Volz add first IPv6 support * */ -- 1.5.4.5 --
Add a struct ip_vs_iphdr for easier handling of common v4 and v6 header
fields in the same code path. ip_vs_fill_iphdr() helps to fill this struct
from an IPv4 or IPv6 header. Add further helper functions for copying and
comparing addresses.
Signed-off-by: Julius Volz <juliusv@google.com>
1 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index e41a164..016af19 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -25,6 +25,56 @@
#include <linux/ipv6.h> /* for struct ipv6hdr */
#include <net/ipv6.h> /* for ipv6_addr_copy */
+struct ip_vs_iphdr {
+ int len;
+ __u8 protocol;
+ union nf_inet_addr saddr;
+ union nf_inet_addr daddr;
+};
+
+static inline void
+ip_vs_fill_iphdr(int af, const void *nh, struct ip_vs_iphdr *iphdr)
+{
+#ifdef CONFIG_IP_VS_IPV6
+ if (af == AF_INET6) {
+ const struct ipv6hdr *iph = nh;
+ iphdr->len = sizeof(struct ipv6hdr);
+ iphdr->protocol = iph->nexthdr;
+ ipv6_addr_copy(&iphdr->saddr.in6, &iph->saddr);
+ ipv6_addr_copy(&iphdr->daddr.in6, &iph->daddr);
+ } else
+#endif
+ {
+ const struct iphdr *iph = nh;
+ iphdr->len = iph->ihl * 4;
+ iphdr->protocol = iph->protocol;
+ iphdr->saddr.ip = iph->saddr;
+ iphdr->daddr.ip = iph->daddr;
+ }
+}
+
+static inline void ip_vs_addr_copy(int af, union nf_inet_addr *dst,
+ const union nf_inet_addr *src)
+{
+#ifdef CONFIG_IP_VS_IPV6
+ if (af == AF_INET6)
+ ipv6_addr_copy(&dst->in6, &src->in6);
+ else
+#endif
+ dst->ip = src->ip;
+}
+
+static inline int ip_vs_addr_equal(int af, const union nf_inet_addr *a,
+ const union nf_inet_addr *b)
+{
+#ifdef CONFIG_IP_VS_IPV6
+ return (af == AF_INET) ? (a->ip == b->ip)
+ : ipv6_addr_equal(&a->in6, &b->in6);
+#else
+ return a->ip == b->ip;
+#endif
+}
+
#ifdef CONFIG_IP_VS_DEBUG
#include <linux/net.h>
--
1.5.4.5
--
Where this has not already been covered by other patches, fix up the code
to work with the new data structures and 'af' parameters.
Signed-off-by: Julius Volz <juliusv@google.com>
4 files changed, 158 insertions(+), 97 deletions(-)
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index f0b848d..011d455 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -489,8 +489,9 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
struct ip_vs_dest *dest;
if ((cp) && (!cp->dest)) {
- dest = ip_vs_find_dest(cp->daddr, cp->dport,
- cp->vaddr, cp->vport, cp->protocol);
+ dest = ip_vs_find_dest(cp->af, &cp->daddr, cp->dport,
+ &cp->vaddr, cp->vport,
+ cp->protocol);
ip_vs_bind_dest(cp, dest);
return dest;
} else
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index f2caf56..ba4d7c2 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -759,7 +759,7 @@ ip_vs_zero_stats(struct ip_vs_stats *stats)
*/
static void
__ip_vs_update_dest(struct ip_vs_service *svc,
- struct ip_vs_dest *dest, struct ip_vs_dest_user *udest)
+ struct ip_vs_dest *dest, struct ip_vs_dest_user_kern *udest)
{
int conn_flags;
@@ -820,7 +820,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
* Create a destination for the given service
*/
static int
-ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
+ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
struct ip_vs_dest **dest_p)
{
struct ip_vs_dest *dest;
@@ -848,11 +848,12 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest,
return -ENOMEM;
}
+ dest->af = svc->af;
dest->protocol = svc->protocol;
dest->vaddr = svc->addr;
dest->vport = svc->port;
dest->vfwmark = svc->fwmark;
- dest->addr = udest->addr;
+ ip_vs_addr_copy(svc->af, &dest->addr, &udest->addr);
dest->port = udest->port;
...Add support for IPv6 entry output to ip_vs_conn_seq_show() and
ip_vs_conn_sync_seq_show() proc/net file handlers.
Signed-off-by: Vince Busam <vbusam@google.com>
1 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 5e013c9..f0b848d 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -815,14 +815,26 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
else {
const struct ip_vs_conn *cp = v;
- seq_printf(seq,
- "%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n",
+ if (cp->af == AF_INET)
+ seq_printf(seq,
+ "%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n",
ip_vs_proto_name(cp->protocol),
- ntohl(cp->caddr), ntohs(cp->cport),
- ntohl(cp->vaddr), ntohs(cp->vport),
- ntohl(cp->daddr), ntohs(cp->dport),
+ ntohl(cp->caddr.ip), ntohs(cp->cport),
+ ntohl(cp->vaddr.ip), ntohs(cp->vport),
+ ntohl(cp->daddr.ip), ntohs(cp->dport),
ip_vs_state_name(cp->protocol, cp->state),
(cp->timer.expires-jiffies)/HZ);
+#ifdef CONFIG_IP_VS_IPV6
+ else
+ seq_printf(seq,
+ "%-3s " NIP6_FMT " %04X " NIP6_FMT " %04X " NIP6_FMT " %04X %-11s %7lu\n",
+ ip_vs_proto_name(cp->protocol),
+ NIP6(cp->caddr.in6), ntohs(cp->cport),
+ NIP6(cp->vaddr.in6), ntohs(cp->vport),
+ NIP6(cp->daddr.in6), ntohs(cp->dport),
+ ip_vs_state_name(cp->protocol, cp->state),
+ (cp->timer.expires-jiffies)/HZ);
+#endif
}
return 0;
}
@@ -864,15 +876,28 @@ static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v)
else {
const struct ip_vs_conn *cp = v;
- seq_printf(seq,
- "%-3s %08X %04X %08X %04X %08X %04X %-11s %-6s %7lu\n",
+ if (cp->af == AF_INET)
+ seq_printf(seq,
+ "%-3s %08X %04X %08X %04X %08X %04X %-11s %-6s %7lu\n",
ip_vs_proto_name(cp->protocol),
- ntohl(cp->caddr), ntohs(cp->cport),
- ntohl(cp->vaddr), ntohs(cp->vport),
- ntohl(cp->daddr), ...Add __ip_vs_addr_is_local_v6() to find out if an IPv6 address belongs to a
local interface. This function is used to decide whether to set the
IP_VS_CONN_F_LOCALNODE flag for IPv6 destinations.
Signed-off-by: Vince Busam <vbusam@google.com>
1 files changed, 46 insertions(+), 7 deletions(-)
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index e793d82..f9db095 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -35,6 +35,10 @@
#include <net/net_namespace.h>
#include <net/ip.h>
+#ifdef CONFIG_IP_VS_IPV6
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#endif
#include <net/route.h>
#include <net/sock.h>
#include <net/genetlink.h>
@@ -91,6 +95,23 @@ int ip_vs_get_debug_level(void)
}
#endif
+#ifdef CONFIG_IP_VS_IPV6
+/* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */
+static int __ip_vs_addr_is_local_v6(const struct in6_addr *addr) {
+ struct rt6_info *rt;
+ struct flowi fl = {
+ .oif = 0,
+ .nl_u = {
+ .ip6_u = {
+ .daddr = *addr,
+ .saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
+ };
+ if ((rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl)))
+ if (rt->rt6i_dev && (rt->rt6i_dev->flags & IFF_LOOPBACK))
+ return 1;
+ return 0;
+}
+#endif
/*
* update_defense_level is called from keventd and from sysctl,
* so it needs to protect itself from softirqs
@@ -718,10 +739,18 @@ __ip_vs_update_dest(struct ip_vs_service *svc,
conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE;
/* check if local node and update the flags */
- if (inet_addr_type(&init_net, udest->addr) == RTN_LOCAL) {
- conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
- | IP_VS_CONN_F_LOCALNODE;
- }
+#ifdef CONFIG_IP_VS_IPV6
+ if (svc->af == AF_INET6) {
+ if (__ip_vs_addr_is_local_v6(&udest->addr.in6)) {
+ conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK)
+ | IP_VS_CONN_F_LOCALNODE;
+ }
+ } else
+#endif
+ if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) ...Convert existing debugging outputs to use the newly introduced debugging
macros where appropriate.
Signed-off-by: Julius Volz <juliusv@google.com>
13 files changed, 213 insertions(+), 180 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 82037b7..fbf57c2 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -670,24 +670,32 @@ static inline void ip_vs_control_del(struct ip_vs_conn *cp)
{
struct ip_vs_conn *ctl_cp = cp->control;
if (!ctl_cp) {
- IP_VS_ERR("request control DEL for uncontrolled: "
- "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
- NIPQUAD(cp->caddr),ntohs(cp->cport),
- NIPQUAD(cp->vaddr),ntohs(cp->vport));
+ IP_VS_ERR_BUF("request control DEL for uncontrolled: "
+ "%s:%d to %s:%d\n",
+ IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+ ntohs(cp->cport),
+ IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+ ntohs(cp->vport));
+
return;
}
- IP_VS_DBG(7, "DELeting control for: "
- "cp.dst=%d.%d.%d.%d:%d ctl_cp.dst=%d.%d.%d.%d:%d\n",
- NIPQUAD(cp->caddr),ntohs(cp->cport),
- NIPQUAD(ctl_cp->caddr),ntohs(ctl_cp->cport));
+ IP_VS_DBG_BUF(7, "DELeting control for: "
+ "cp.dst=%s:%d ctl_cp.dst=%s:%d\n",
+ IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+ ntohs(cp->cport),
+ IP_VS_DBG_ADDR(cp->af, &ctl_cp->caddr),
+ ntohs(ctl_cp->cport));
cp->control = NULL;
if (atomic_read(&ctl_cp->n_control) == 0) {
- IP_VS_ERR("BUG control DEL with n=0 : "
- "%d.%d.%d.%d:%d to %d.%d.%d.%d:%d\n",
- NIPQUAD(cp->caddr),ntohs(cp->cport),
- NIPQUAD(cp->vaddr),ntohs(cp->vport));
+ IP_VS_ERR_BUF("BUG control DEL with n=0 : "
+ "%s:%d to %s:%d\n",
+ IP_VS_DBG_ADDR(cp->af, &cp->caddr),
+ ntohs(cp->cport),
+ IP_VS_DBG_ADDR(cp->af, &cp->vaddr),
+ ntohs(cp->vport));
+
return;
}
atomic_dec(&ctl_cp->n_control);
@@ -697,23 +705,27 @@ static inline void
ip_vs_control_add(struct ip_vs_conn *cp, struct ip_vs_conn ...Check to see if the specified scheduler is supported with IPv6 and whether
the supplied prefix length is valid.
Signed-off-by: Julius Volz <juliusv@google.com>
1 files changed, 26 insertions(+), 0 deletions(-)
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 6127a97..39ab7dc 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -1160,6 +1160,19 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
goto out_mod_dec;
}
+#ifdef CONFIG_IP_VS_IPV6
+ if (u->af == AF_INET6) {
+ if (!sched->supports_ipv6) {
+ ret = -EAFNOSUPPORT;
+ goto out_err;
+ }
+ if ((u->netmask < 1) || (u->netmask > 128)) {
+ ret = -EINVAL;
+ goto out_err;
+ }
+ }
+#endif
+
svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC);
if (svc == NULL) {
IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n");
@@ -1247,6 +1260,19 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user *u)
}
old_sched = sched;
+#ifdef CONFIG_IP_VS_IPV6
+ if (u->af == AF_INET6) {
+ if (!sched->supports_ipv6) {
+ ret = EAFNOSUPPORT;
+ goto out;
+ }
+ if ((u->netmask < 1) || (u->netmask > 128)) {
+ ret = EINVAL;
+ goto out;
+ }
+ }
+#endif
+
write_lock_bh(&__ip_vs_svc_lock);
/*
--
1.5.4.5
--
Add IPVS Generic Netlink interface definitions to include/linux/ip_vs.h.
Signed-off-by: Julius Volz <juliusv@google.com>
1 files changed, 160 insertions(+), 0 deletions(-)
diff --git a/include/linux/ip_vs.h b/include/linux/ip_vs.h
index ec6eb49..0f434a2 100644
--- a/include/linux/ip_vs.h
+++ b/include/linux/ip_vs.h
@@ -242,4 +242,164 @@ struct ip_vs_daemon_user {
int syncid;
};
+/*
+ *
+ * IPVS Generic Netlink interface definitions
+ *
+ */
+
+/* Generic Netlink family info */
+
+#define IPVS_GENL_NAME "IPVS"
+#define IPVS_GENL_VERSION 0x1
+
+struct ip_vs_flags {
+ __be32 flags;
+ __be32 mask;
+};
+
+/* Generic Netlink command attributes */
+enum {
+ IPVS_CMD_UNSPEC = 0,
+
+ IPVS_CMD_NEW_SERVICE, /* add service */
+ IPVS_CMD_SET_SERVICE, /* modify service */
+ IPVS_CMD_DEL_SERVICE, /* delete service */
+ IPVS_CMD_GET_SERVICE, /* get service info */
+
+ IPVS_CMD_NEW_DEST, /* add destination */
+ IPVS_CMD_SET_DEST, /* modify destination */
+ IPVS_CMD_DEL_DEST, /* delete destination */
+ IPVS_CMD_GET_DEST, /* get destination info */
+
+ IPVS_CMD_NEW_DAEMON, /* start sync daemon */
+ IPVS_CMD_DEL_DAEMON, /* stop sync daemon */
+ IPVS_CMD_GET_DAEMON, /* get sync daemon status */
+
+ IPVS_CMD_SET_CONFIG, /* set config settings */
+ IPVS_CMD_GET_CONFIG, /* get config settings */
+
+ IPVS_CMD_SET_INFO, /* only used in GET_INFO reply */
+ IPVS_CMD_GET_INFO, /* get general IPVS info */
+
+ IPVS_CMD_ZERO, /* zero all counters and stats */
+ IPVS_CMD_FLUSH, /* flush services and dests */
+
+ __IPVS_CMD_MAX,
+};
+
+#define IPVS_CMD_MAX (__IPVS_CMD_MAX - 1)
+
+/* Attributes used in the first level of commands */
+enum {
+ IPVS_CMD_ATTR_UNSPEC = 0,
+ IPVS_CMD_ATTR_SERVICE, /* nested service attribute */
+ IPVS_CMD_ATTR_DEST, /* nested destination attribute */
+ IPVS_CMD_ATTR_DAEMON, /* nested sync daemon attribute */
+ IPVS_CMD_ATTR_TIMEOUT_TCP, /* TCP connection timeout */
+ IPVS_CMD_ATTR_TIMEOUT_TCP_FIN, /* TCP FIN wait ...Add 'supports_ipv6' flag to struct ip_vs_scheduler to indicate whether a
scheduler supports IPv6. Set the flag to 1 in schedulers that work with
IPv6, 0 otherwise. This flag is checked in a later patch while trying to
add a service with a specific scheduler.
Signed-off-by: Julius Volz <juliusv@google.com>
11 files changed, 33 insertions(+), 0 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 28880e4..144bcd5 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -521,6 +521,9 @@ struct ip_vs_scheduler {
char *name; /* scheduler name */
atomic_t refcnt; /* reference counter */
struct module *module; /* THIS_MODULE/NULL */
+#ifdef CONFIG_IP_VS_IPV6
+ int supports_ipv6; /* scheduler has IPv6 support */
+#endif
/* scheduler initializing service */
int (*init_service)(struct ip_vs_service *svc);
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
index fa66824..bb0d426 100644
--- a/net/ipv4/ipvs/ip_vs_dh.c
+++ b/net/ipv4/ipvs/ip_vs_dh.c
@@ -234,6 +234,9 @@ static struct ip_vs_scheduler ip_vs_dh_scheduler =
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
.n_list = LIST_HEAD_INIT(ip_vs_dh_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+ .supports_ipv6 = 0,
+#endif
.init_service = ip_vs_dh_init_svc,
.done_service = ip_vs_dh_done_svc,
.update_service = ip_vs_dh_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
index 7a6a319..5c37b73 100644
--- a/net/ipv4/ipvs/ip_vs_lblc.c
+++ b/net/ipv4/ipvs/ip_vs_lblc.c
@@ -540,6 +540,9 @@ static struct ip_vs_scheduler ip_vs_lblc_scheduler =
.refcnt = ATOMIC_INIT(0),
.module = THIS_MODULE,
.n_list = LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list),
+#ifdef CONFIG_IP_VS_IPV6
+ .supports_ipv6 = 0,
+#endif
.init_service = ip_vs_lblc_init_svc,
.done_service = ip_vs_lblc_done_svc,
.update_service = ip_vs_lblc_update_svc,
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
index c234e73..5ee5588 ...I wonder if there are some spare bits inside the flags
member of ip_vs_scheduler that could be used for this purpose?
Otherwise, I'm fine with this, we can juggle things around
later to use the other bits in supports_ipv6 for other things
if and when the need arises.
Here is a version that applies against lvs-2.6
From: Julius Volz <juliusv@google.com>
IPVS: Add IPv6 support flag to schedulers
Add 'supports_ipv6' flag to struct ip_vs_scheduler to indicate whether a
scheduler supports IPv6. Set the flag to 1 in schedulers that work with
IPv6, 0 otherwise. This flag is checked in a later patch while trying to
add a service with a specific scheduler.
Signed-off-by: Julius Volz <juliusv@google.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
---
include/net/ip_vs.h | 3 +++
net/ipv4/ipvs/ip_vs_dh.c | 3 +++
net/ipv4/ipvs/ip_vs_lblc.c | 3 +++
net/ipv4/ipvs/ip_vs_lblcr.c | 3 +++
net/ipv4/ipvs/ip_vs_lc.c | 3 +++
net/ipv4/ipvs/ip_vs_nq.c | 3 +++
net/ipv4/ipvs/ip_vs_rr.c | 3 +++
net/ipv4/ipvs/ip_vs_sed.c | 3 +++
net/ipv4/ipvs/ip_vs_sh.c | 3 +++
net/ipv4/ipvs/ip_vs_wlc.c | 3 +++
net/ipv4/ipvs/ip_vs_wrr.c | 3 +++
11 files changed, 33 insertions(+)
b8c297df2a43ab6a2143f6ec5ccfb4943231e1c5
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index f591d7d..66ca986 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -475,6 +475,9 @@ struct ip_vs_scheduler {
char *name; /* scheduler name */
atomic_t refcnt; /* reference counter */
struct module *module; /* THIS_MODULE/NULL */
+#ifdef CONFIG_IP_VS_IPV6
+ int supports_ipv6; /* scheduler has IPv6 support */
+#endif
/* scheduler initializing service */
int (*init_service)(struct ip_vs_service *svc);
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
index fa66824..bb0d426 100644
--- a/net/ipv4/ipvs/ip_vs_dh.c
+++ b/net/ipv4/ipvs/ip_vs_dh.c
@@ -234,6 +234,9 @@ static struct ip_vs_scheduler ...Thanks, I guess I should start basing all of my IPVS patches on this tree rather than net-2.6? Julius -- Google Switzerland GmbH --
That would make things slightly more convenient for me. But I'm not the only fish in the sea :-) --
Add boolean config option CONFIG_IP_VS_IPV6 for enabling experimental IPv6 support in IPVS. Only visible if IPv6 support is set to 'y' or both IPv6 and IPVS are modules. Signed-off-by: Julius Volz <juliusv@google.com> 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/net/ipv4/ipvs/Kconfig b/net/ipv4/ipvs/Kconfig index 09d0c3f..fd24182 100644 --- a/net/ipv4/ipvs/Kconfig +++ b/net/ipv4/ipvs/Kconfig @@ -24,6 +24,14 @@ menuconfig IP_VS if IP_VS +config IP_VS_IPV6 + bool "IPv6 support for IPVS (DANGEROUS)" + depends on EXPERIMENTAL && (IPV6 = y || IP_VS = IPV6) + ---help--- + Add IPv6 support to IPVS. This is incomplete and might be dangerous. + + Say N if unsure. + config IP_VS_DEBUG bool "IP virtual server debugging" ---help--- -- 1.5.4.5 --
Add support for procfs output of IPv6 service and connection entries.
Signed-off-by: Vince Busam <vbusam@google.com>
1 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index efa34fb..e793d82 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -1611,6 +1611,7 @@ static struct ctl_table vs_vars[] = {
const struct ctl_path net_vs_ctl_path[] = {
{ .procname = "net", .ctl_name = CTL_NET, },
+ /* TODO IPv6: possible to move / duplicate this? */
{ .procname = "ipv4", .ctl_name = NET_IPV4, },
{ .procname = "vs", },
{ }
@@ -1751,15 +1752,26 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
const struct ip_vs_iter *iter = seq->private;
const struct ip_vs_dest *dest;
- if (iter->table == ip_vs_svc_table)
- seq_printf(seq, "%s %08X:%04X %s ",
- ip_vs_proto_name(svc->protocol),
- ntohl(svc->addr),
- ntohs(svc->port),
- svc->scheduler->name);
- else
+ if (iter->table == ip_vs_svc_table) {
+ if (svc->af == AF_INET) {
+ seq_printf(seq, "%s %08X:%04X %s ",
+ ip_vs_proto_name(svc->protocol),
+ ntohl(svc->addr.ip),
+ ntohs(svc->port),
+ svc->scheduler->name);
+ } else if (svc->af == AF_INET6) {
+#ifdef CONFIG_IP_VS_IPV6
+ seq_printf(seq, "%s [" NIP6_FMT "]:%04X %s ",
+ ip_vs_proto_name(svc->protocol),
+ NIP6(svc->addr.in6),
+ ntohs(svc->port),
+ svc->scheduler->name);
+#endif
+ }
+ } else {
seq_printf(seq, "FWM %08X %s ",
svc->fwmark, svc->scheduler->name);
+ }
if (svc->flags & IP_VS_SVC_F_PERSISTENT)
seq_printf(seq, "persistent %d %08X\n",
@@ -1769,13 +1781,24 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
seq_putc(seq, '\n');
list_for_each_entry(dest, &svc->destinations, n_list) {
- seq_printf(seq,
- " -> %08X:%04X %-7s %-6d %-10d %-10d\n",
- ntohl(dest->addr), ...Do not expose v6 services via the old sockopt interface and only count v6
services in ip_vs_num_services (which is only used to report the count to
userspace in the old interface).
Signed-off-by: Julius Volz <juliusv@google.com>
1 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 39ab7dc..73150ce 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -1209,7 +1209,10 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p)
atomic_inc(&ip_vs_nullsvc_counter);
ip_vs_new_estimator(&svc->stats);
- ip_vs_num_services++;
+
+ /* Count only IPv4 services for old get/setsockopt interface */
+ if (svc->af == AF_INET)
+ ip_vs_num_services++;
/* Hash the service into the service table */
write_lock_bh(&__ip_vs_svc_lock);
@@ -1337,7 +1340,10 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
struct ip_vs_dest *dest, *nxt;
struct ip_vs_scheduler *old_sched;
- ip_vs_num_services--;
+ /* Count only IPv4 services for old get/setsockopt interface */
+ if (svc->af == AF_INET)
+ ip_vs_num_services--;
+
ip_vs_kill_estimator(&svc->stats);
/* Unbind scheduler */
@@ -2182,8 +2188,13 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
+ /* Only expose IPv4 entries to old interface */
+ if (svc->af != AF_INET)
+ continue;
+
if (count >= get->num_services)
goto out;
+
memset(&entry, 0, sizeof(entry));
ip_vs_copy_service(&entry, svc);
if (copy_to_user(&uptr->entrytable[count],
@@ -2197,8 +2208,12 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
+ if (svc->af != AF_INET)
+ continue;
+
if (count >= get->num_services)
goto ...Convert ip_vs_schedule() and ip_vs_sched_persist() to support scheduling
IPv6 connections.
Signed-off-by: Julius Volz <juliusv@google.com>
1 files changed, 58 insertions(+), 43 deletions(-)
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 99e8938..0f9a0a2 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -183,14 +183,21 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
__be16 ports[2])
{
struct ip_vs_conn *cp = NULL;
- struct iphdr *iph = ip_hdr(skb);
+ struct ip_vs_iphdr iph;
struct ip_vs_dest *dest;
struct ip_vs_conn *ct;
- __be16 dport; /* destination port to forward */
- __be32 snet; /* source network of the client, after masking */
+ __be16 dport; /* destination port to forward */
+ union nf_inet_addr snet; /* source network of the client, after masking */
+
+ ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
/* Mask saddr with the netmask to adjust template granularity */
- snet = iph->saddr & svc->netmask;
+#ifdef CONFIG_IP_VS_IPV6
+ if (svc->af == AF_INET6)
+ ipv6_addr_prefix(&snet.in6, &iph.saddr.in6, svc->netmask);
+ else
+#endif
+ snet.ip = iph.saddr.ip & svc->netmask;
IP_VS_DBG_BUF(6, "p-schedule: src %s:%u dest %s:%u "
"mnet %s\n",
@@ -214,11 +221,11 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
if (ports[1] == svc->port) {
/* Check if a template already exists */
if (svc->port != FTPPORT)
- ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
- iph->daddr, ports[1]);
+ ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
+ &iph.daddr, ports[1]);
else
- ct = ip_vs_ct_in_get(iph->protocol, snet, 0,
- iph->daddr, 0);
+ ct = ip_vs_ct_in_get(svc->af, iph.protocol, &snet, 0,
+ &iph.daddr, 0);
if (!ct || !ip_vs_check_template(ct)) {
/*
@@ -238,18 +245,18 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
* for ftp service.
*/
if (svc->port != FTPPORT)
- ct = ...Can you break the line above so that it is <= 80 columns wide? union nf_inet_addr snet; /* source network of the client, --
Sure! Same for all the other cases. Julius -- Julius Volz - Corporate Operations - SysOps Google Switzerland GmbH - Identification No.: CH-020.4.028.116-1 --
Extend functions for getting/creating connections and connection
templates with IPv6 support.
Signed-off-by: Julius Volz <juliusv@google.com>
2 files changed, 52 insertions(+), 28 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 565121e..c80eaec 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -641,11 +641,16 @@ enum {
};
extern struct ip_vs_conn *ip_vs_conn_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port);
+
extern struct ip_vs_conn *ip_vs_ct_in_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port);
+
extern struct ip_vs_conn *ip_vs_conn_out_get
-(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
+(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
+ const union nf_inet_addr *d_addr, __be16 d_port);
/* put back the conn without restarting its timer */
static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
@@ -656,9 +661,11 @@ extern void ip_vs_conn_put(struct ip_vs_conn *cp);
extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
extern struct ip_vs_conn *
-ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
- __be32 daddr, __be16 dport, unsigned flags,
+ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
+ const union nf_inet_addr *vaddr, __be16 vport,
+ const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
struct ip_vs_dest *dest);
+
extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
extern const char * ip_vs_state_name(__u16 proto, int state);
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index ...Add some debugging macros that allow conditional output of either v4 or v6
addresses, depending on an 'af' parameter. This is done by creating a
temporary string buffer in an outer debug macro and writing addresses'
string representations into it from another macro which can only be used
when inside the outer one.
Signed-off-by: Julius Volz <juliusv@google.com>
1 files changed, 43 insertions(+), 0 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 016af19..82037b7 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -79,6 +79,47 @@ static inline int ip_vs_addr_equal(int af, const union nf_inet_addr *a,
#include <linux/net.h>
extern int ip_vs_get_debug_level(void);
+
+static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
+ const union nf_inet_addr *addr,
+ int *idx)
+{
+ int len;
+#ifdef CONFIG_IP_VS_IPV6
+ if (af == AF_INET)
+#endif
+ len = snprintf(&buf[*idx], buf_len - *idx, NIPQUAD_FMT,
+ NIPQUAD(addr->ip)) + 1;
+#ifdef CONFIG_IP_VS_IPV6
+ else
+ len = snprintf(&buf[*idx], buf_len - *idx, "[" NIP6_FMT "]",
+ NIP6(addr->in6)) + 1;
+#endif
+
+ *idx += len;
+ return &buf[*idx - len];
+}
+
+#define IP_VS_DBG_BUF(level, msg...) \
+ do { \
+ char ip_vs_dbg_buf[160]; \
+ int ip_vs_dbg_idx = 0; \
+ if (level <= ip_vs_get_debug_level()) \
+ printk(KERN_DEBUG "IPVS: " msg); \
+ } while (0)
+#define IP_VS_ERR_BUF(msg...) \
+ do { \
+ char ip_vs_dbg_buf[160]; \
+ int ip_vs_dbg_idx = 0; \
+ printk(KERN_ERR "IPVS: " msg); \
+ } while (0)
+
+/* Only use from within IP_VS_DBG_BUF() macro */
+#define IP_VS_DBG_ADDR(af, addr) \
+ ip_vs_dbg_addr(af, ip_vs_dbg_buf, \
+ sizeof(ip_vs_dbg_buf), addr, \
+ &ip_vs_dbg_idx)
+
#define IP_VS_DBG(level, msg...) \
do { \
if (level <= ip_vs_get_debug_level()) \
@@ -101,6 +142,8 @@ extern int ip_vs_get_debug_level(void);
...Add xmit functions for IPv6 and a function ip_vs_bind_xmit_v6() for
binding them to a connection. Also add support for v6 to IP_VS_XMIT() and
the routing cache functions.
Much duplication here, since the new functions are copied from the old ones
and then modified for IPv6. Hard to efficiently factor out the common parts
though?
Signed-off-by: Julius Volz <juliusv@google.com>
3 files changed, 476 insertions(+), 13 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 352807b..565121e 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -857,6 +857,18 @@ extern int ip_vs_icmp_xmit
(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset);
extern void ip_vs_dst_reset(struct ip_vs_dest *dest);
+#ifdef CONFIG_IP_VS_IPV6
+extern int ip_vs_bypass_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_nat_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_tunnel_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_dr_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_icmp_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset);
+#endif
/*
* This is a simple mechanism to ignore packets when
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index ea921dc..4eae6bf 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -369,6 +369,33 @@ static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp)
}
}
+#ifdef CONFIG_IP_VS_IPV6
+static inline void ip_vs_bind_xmit_v6(struct ip_vs_conn *cp)
+{
+ switch (IP_VS_FWD_METHOD(cp)) {
+ case IP_VS_CONN_F_MASQ:
+ cp->packet_xmit = ip_vs_nat_xmit_v6;
+ break;
+
+ case IP_VS_CONN_F_TUNNEL:
+ cp->packet_xmit = ip_vs_tunnel_xmit_v6;
+ break;
+
+ case IP_VS_CONN_F_DROUTE:
+ cp->packet_xmit = ...Convert the low-level dest and service lookup/hashing functions to deal
with IPv6 entries.
Signed-off-by: Julius Volz <juliusv@google.com>
2 files changed, 63 insertions(+), 31 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index c80eaec..28880e4 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -807,7 +807,8 @@ extern struct ip_vs_stats ip_vs_stats;
extern const struct ctl_path net_vs_ctl_path[];
extern struct ip_vs_service *
-ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport);
+ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
+ const union nf_inet_addr *vaddr, __be16 vport);
static inline void ip_vs_service_put(struct ip_vs_service *svc)
{
@@ -815,14 +816,16 @@ static inline void ip_vs_service_put(struct ip_vs_service *svc)
}
extern struct ip_vs_dest *
-ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport);
+ip_vs_lookup_real_service(int af, __u16 protocol,
+ const union nf_inet_addr *daddr, __be16 dport);
+
extern int ip_vs_use_count_inc(void);
extern void ip_vs_use_count_dec(void);
extern int ip_vs_control_init(void);
extern void ip_vs_control_cleanup(void);
extern struct ip_vs_dest *
-ip_vs_find_dest(__be32 daddr, __be16 dport,
- __be32 vaddr, __be16 vport, __u16 protocol);
+ip_vs_find_dest(int af, const union nf_inet_addr *daddr, __be16 dport,
+ const union nf_inet_addr *vaddr, __be16 vport, __u16 protocol);
extern struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp);
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index f9db095..6127a97 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -303,11 +303,19 @@ static atomic_t ip_vs_nullsvc_counter = ATOMIC_INIT(0);
* Returns hash value for virtual service
*/
static __inline__ unsigned
-ip_vs_svc_hashkey(unsigned proto, __be32 addr, __be16 port)
+ip_vs_svc_hashkey(int af, unsigned proto, const union nf_inet_addr *addr,
+ __be16 port)
...Add Netfilter hook entries for IPv6 and either extend the existing hook
functions to handle both v4 and v6, or where it seems easier, add new ones
for v6. Also adapt/add some helper functions for v6.
Signed-off-by: Julius Volz <juliusv@google.com>
2 files changed, 437 insertions(+), 61 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 9ba9ee7..352807b 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -901,7 +901,12 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)
}
extern void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
- struct ip_vs_conn *cp, int dir);
+ struct ip_vs_conn *cp, int dir);
+
+#ifdef CONFIG_IP_VS_IPV6
+extern void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
+ struct ip_vs_conn *cp, int dir);
+#endif
extern __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset);
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 63c08c4..99e8938 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -39,6 +39,11 @@
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
+#ifdef CONFIG_IP_VS_IPV6
+#include <net/ipv6.h>
+#include <linux/netfilter_ipv6.h>
+#endif
+
#include <net/ip_vs.h>
@@ -60,6 +65,7 @@ EXPORT_SYMBOL(ip_vs_get_debug_level);
/* ID used in ICMP lookups */
#define icmp_id(icmph) (((icmph)->un).echo.id)
+#define icmpv6_id(icmph) (icmph->icmp6_dataun.u_echo.identifier)
const char *ip_vs_proto_name(unsigned proto)
{
@@ -74,6 +80,10 @@ const char *ip_vs_proto_name(unsigned proto)
return "TCP";
case IPPROTO_ICMP:
return "ICMP";
+#ifdef CONFIG_IP_VS_IPV6
+ case IPPROTO_ICMPV6:
+ return "ICMPv6";
+#endif
default:
sprintf(buf, "IP_%d", proto);
return buf;
@@ -408,20 +418,27 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
struct ip_vs_protocol *pp)
{
__be16 _ports[2], *pptr;
- struct iphdr *iph = ...Add 'af' argument to protocol handler functions and make them handle both
IPv4 and IPv6 in the same function. Change the protocol debugging functions
to detect the AF from the skb and generate the appropriate output. Probably
still too much duplication here.
Signed-off-by: Julius Volz <juliusv@google.com>
6 files changed, 430 insertions(+), 160 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index fbf57c2..9ba9ee7 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -298,21 +298,23 @@ struct ip_vs_protocol {
void (*exit)(struct ip_vs_protocol *pp);
- int (*conn_schedule)(struct sk_buff *skb,
+ int (*conn_schedule)(int af, struct sk_buff *skb,
struct ip_vs_protocol *pp,
int *verdict, struct ip_vs_conn **cpp);
struct ip_vs_conn *
- (*conn_in_get)(const struct sk_buff *skb,
+ (*conn_in_get)(int af,
+ const struct sk_buff *skb,
struct ip_vs_protocol *pp,
- const struct iphdr *iph,
+ const struct ip_vs_iphdr *iph,
unsigned int proto_off,
int inverse);
struct ip_vs_conn *
- (*conn_out_get)(const struct sk_buff *skb,
+ (*conn_out_get)(int af,
+ const struct sk_buff *skb,
struct ip_vs_protocol *pp,
- const struct iphdr *iph,
+ const struct ip_vs_iphdr *iph,
unsigned int proto_off,
int inverse);
@@ -322,7 +324,8 @@ struct ip_vs_protocol {
int (*dnat_handler)(struct sk_buff *skb,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp);
- int (*csum_check)(struct sk_buff *skb, struct ip_vs_protocol *pp);
+ int (*csum_check)(int af, struct sk_buff *skb,
+ struct ip_vs_protocol *pp);
const char *(*state_name)(int state);
@@ -909,6 +912,17 @@ static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum)
return csum_partial((char *) diff, sizeof(diff), oldsum);
}
+#ifdef CONFIG_IP_VS_IPV6
+static inline __wsum ip_vs_check_diff16(const __be32 *old, const __be32 *new,
+ __wsum ...I don't think you need the __constant_htons() here, just htons() - htons() I think there's more in one of the other patches too. So why can't you just create one ip_vs_debug_packet_v6() instead of these ah and esp ones which are identical? -Brian --
Hi, Thanks! I guessed from the name and other uses that __constant_htons() is just a version of htons() optimized for values that are constant at compile If you look at the original files, the whole ip_vs_proto_ah.c and ip_vs_proto_esp.c are 100% identical except for the protocol names / constants :-/ So I stuck with this pattern for now. Maybe it would make sense to join those two files in a change separate from the v6 functionality? There's already a lot of duplication in the existing IPVS that could be removed... Julius -- Google Switzerland GmbH --
I think the __constant one is for initializations. All I know is that someone (Stephen Hemminger?) always points this out in other patchsets, I didn't look too closely, there's a lot of patches! :) Doing it in a separate patch is probably a good idea though. -Brian --
He :) Still, I think my original interpretation was correct? It's always used with constant values and there are many usages similar to this: skb->protocol = __constant_htons(ETH_P_802_3); Yep, it's too big, I know :) And reworking the complete patch into a sane series didn't really work out that well because everything is so interdependent. Sometimes it might even be easier to look at the Yeah, should be easy. I'll look at it (if there is any interest). Julius -- Google Switzerland GmbH --
I know it's a minor point, but look at tcp_ipv6.c:
if (skb->protocol == htons(ETH_P_IP))
return tcp_v4_conn_request(sk, skb);
That's different from the code you quoted that's doing an assignment.
__constant_htons() isn't used anywhere in an if() statement, although I
did find a couple in the bonding driver that should be fixed.
-Brian
--
Ok, maybe the problem with this is more what it says before the definition of __constant_htons() in include/linux/byteorder.h? ---- /* * These helpers could be phased out over time as the base version * handles constant folding. */ --- Which is probably the reason why it shouldn't be used anymore? So although it's probably doing the right thing already, I'll just change it to htons() and everyone should be happy... Julius -- Google Switzerland GmbH --
Other than the packet format of the sync deamon, are there any fundamental restrictions here? If we extended the sync daemon, could it work? If so, perhaps we could rev the sync deamon protocol and fix a few other kinks, like the handling of timeouts and the Unfortunately (or fortunately depending on how you look at it), I'm going to be away skiing for the next couple of days. Apologies for the slow responses that will lead to. --
There shouldn't be any fundamental restrictions, it's just a piece of the puzzle that I could easily leave out of the picture for now. I haven't studied the sync daemon closely yet, but one thing I was briefly wondering about was whether we should just blow up the addresses in struct ip_vs_sync_conn to be of type union nf_inet_addr (probably not acceptable, wasting too much bandwidth for v4 entries) or how to send differently sized entries based on the IP version in a clean way. But it sounds like you'd want to redesign a lot of that anyways? I'm glad to help with anything, I just don't know this code as well as you or Sven, but I'll study it more. Maybe you can share Have fun! And be careful, we need you to come back healthy :) Julius -- Google Switzerland GmbH --
Thanks.
Here are a few thoughts I have had in my breif overview of the code so far
- mainly just simple style things. If any of my comments are obviously
stupid, please just say so as I haven't got to the end of the series yet
and I'm sure some of my questions are answered in the code.
[PATCH RFC 01/24] IPVS: Add genetlink interface definitions to ip_vs.h
[PATCH RFC 02/24] IPVS: Add genetlink interface implementation
* Already in lvs-2.6. Are there any changes?
[PATCH RFC 02/24] IPVS: Add genetlink interface implementation
* What is IP_VS = IPV6 ?
[PATCH RFC 04/24] IPVS: Change IPVS data structures to support IPv6 addresses
* Indentation of af in struct ip_vs_conn seems inconsistent with other
elements.
[PATCH RFC 05/24] IPVS: Add general v4/v6 helper functions / data structures
* Use of p ? a : b construct in ip_vs_addr_equal() seems a bit aquard.
How about
static inline int ip_vs_addr_equal(int af, const union nf_inet_addr *a,
const union nf_inet_addr *b)
{
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET)
return ipv6_addr_equal(&a->in6, &b->in6);
#endif
return a->ip == b->ip;
}
--
Thanks for looking at this, no problem. I know it's a bit much to digest, but I think there is no smaller part that I could post that is No, those are just exactly what I sent you before. I included them because I was basing it on net-2.6. Btw., David just announced that he opened net-next-2.6, so perhaps he (IPV6 = y || IP_VS = IPV6) means that this option will only be visible if either CONFIG_IPV6 is set to Y or if both CONFIG_IPV6 and CONFIG_IP_VS are modules (if both are off, the whole submenu will be hidden). So CONFIG_IPV6 has to be set at least as high as CONFIG_IP_VS Yeah, it's broken like this in the original and I kept it like that so that things would still line up (because I didn't want to add noise by touching the neighboring lines just for whitespace fixes). I could Right, that is nicer! With AF_INET6 in that if-condition, of course. Julius -- Google Switzerland GmbH --
Sorry, I forgot to finish this sentance :-( What I was thinking was that any change would introduce a protocol incompatibility. However I think that there is some room for small changes to be added using currently unsued bits in ip_vs_sync_conn.flags. This could also be used to allow syncryonising of timeouts (which is unrelated to IPv6). So while my general feeling that the synchronisation protocol is not as extendable as it should be stands. We can probably work with the current protocol for now. --
There's also a '__u8 reserved' field at the beginning of that struct which could be used. But in general, is it reasonable to expect both nodes to use the same kernel version, which gets rid of the extensibility problems? It's not really an ABI that can't be broken, Yes, without jumping through hoops, we have to probably break the current protocol anyways for new features? Even if we designated unused fields for new information, an old kernel will not look at them / fill them out, which limits the possibilities... Julius -- Google Switzerland GmbH --
I think from an operational (ie. end user) perspective, ABI breakage is something to try to avoid but _not_ at all costs. If it's possible to extend the sync daemon protocol by reusing the existing code and ABI, all well and good; however if a fundamental change is made which breaks the old sync daemon ABI then as long as it's documented and we make sure that users know to have the same (or higher) I guess that as and when this change is made and gets into mainline releases, Joe and I will have to have a mantra of "ensure your directors are using the same kernel version" in response to queries on lvs-users :) Graeme --
Yeah, and it's not an ABI, it's a very specialized protocol between two kernels, so the rules are less clear. However, I totally agree He :) Imagine an old kernel on the backup receiving new messages and not understanding them. How could we at least handle that situation gracefully (without totally confusing the older kernel)? We'd need to do it in a way that old features are still communicated in the same way. E.g., v4-only connection syncs still use the same message format, but once you use v6 entries, an unused flag or the 'reserved' field in ip_vs_sync_conn is used. A v6 message would still confuse an older kernel then, but a user would already notice that ipvsadm can't configure the v6 services on the older kernel, so that's not too bad. Anyways, these are just some thoughts. I'm unsure if we really need to worry about this extension right now or if we could postpone it? At least for me, it makes more sense to clean up the minimal set of IPv6 features first and then think about the more advanced/optional ones, like the sync daemon. Julius -- Google Switzerland GmbH --
If that's a problem, we can easily change the communication port and even completely redesign the protocol this way, without having old kernels getting confused about the data they get. We might lose the ability to sync between different versions, but in the end this is just the connection synchronziation and both systems should be running the same version. We could also keep the old communication port for some time, if that's really needed. Sven --
Yes, starting from scratch on another port sounds like a good idea. Losing sync ability totally isn't as bad as confusing an older kernel with new messages, so I hope it's not necessary to keep the old baggage around? Is there enough motivation for doing this though before having a cleaned-up minimal v6 version without the sync daemon? This is where I'm currently a bit stuck with... any help is appreciated :) Julius -- Google Switzerland GmbH --
I agree - having a new sync daemon which can deal with v6 entries aswell as v4 entries would be a good way to work; the legacy code can then be Well, as someone else mentioned on lvs-users recently "I couldn't code my way out of a wet paper bag in C" so I'm not much help on that front, however I feel that getting the minimal working feature set going first and then adding the sync code later is probably a good way to proceed. This also gives us a development timeline that we can offer to interested parties, along the lines of: 2008-10 Minimal IPv6 functionality 2008-?? Full IPv6 functionality matching IPv4 features, no IPv6 sync 2009-?? Restructured sync daemon with full IPv4 and IPv6 support Horms, Joe - do you agree that this is a good idea? Graeme --
we aren't a commercial shop. This is all being done by volunteers. In which case features arrive in the time and order that the coder(s) do it. Joe -- Joseph Mack NA3T EME(B,D), FM05lw North Carolina jmack (at) wm7d (dot) net - azimuthal equidistant map generator at http://www.wm7d.net/azproj.shtml Homepage http://www.austintek.com/ It's GNU/Linux! --
Well, it was just a suggestion. It'd be nice, I reckon, to be able to say to people on lvs-users who ask us that "yes, this is currently being worked on" at the very least. It might stop people bleating, as they currently do (albeit rarely). Graeme --
If you say that then people will expect that it will eventually be released and will work, and be documented and we'll be able to help people get it working when it arrives. A lot of stuff has been "worked on", but not tested or released. Horms has piles of stuff. Jason Stubbs has working code for lvs hooked into PREROUTING, a great step forward in my estimate, but has disappeared off the mailing list. If you tell people all this code is out there somewhere, being worked on, are you then prepared to tell them that you don't have the code, or that no-one's tested it, and there's no documentation and you haven't a clue how to set it up, and then try to help them install it and get it going? I'm quite prepared to believe that you can get Horms version of lvs hooked into FORWARD working and help people with it, but I can't. There's been more code written for LVS that's never seen the light of day, than has ever been released. I wouldn't want the LVS mailing list to become famous as a list of promises that are not kept. Even code that's been tested by the author and released doesn't get used. The -SH scheduler sat untouched for years, because no-one knew how to use it. Someone spelunking the code, figured out how to configure it. I still have no clue what LBLC does and it's been out for No-one, who is running LVS as part of his business, and who monitors the mailing list daily for at least a year, never helping anyone, waiting for a mention of the -SH scheduler, so that he remind everyone that the clueless LVS developers have not fixed his -SH problem (and that he has no intention of fixing it himself, or getting anyone under his command to fix it either) and if we don't do something pronto, he'll go to a commercial loadbalancer, is entitled to bleat. Joe -- Joseph Mack NA3T EME(B,D), FM05lw North Carolina jmack (at) wm7d (dot) net - azimuthal equidistant map generator at http://www.wm7d.net/azproj.shtml Homepage http://www.austintek.com/ ...
Right, we can only do our best, and even then we can't make This is what we have as an experimental version right now. Meaning, 'works for us without problems, but not well tested or reviewed - any For fragmentation and other extension headers support, we would probably need people with more knowledge of the rest of the IPv6 stack to contribute. However, both features aren't common (especially fragmentation with IPv6) in this situation, so missing them is not likely to hurt a lot of people. The other missing features are the 4 missing schedulers (DH, SH, LBLC, This seems pretty doable once a protocol is decided upon and should be done before the previous step, IMO. Julius -- Julius Volz Corporate Operations - SysOps Google Switzerland GmbH Identification No.: CH-020.4.028.116-1 --
If it helps, the ipv4 ftp helper causes a lot of problems. People can't get it to work, because they can't follow the instructions. ftp is hard to secure and I think it should be done on a separate single machine. But if you have reasons to write an ipv6 ftp helper, don't let me stop you. I personally don't know important it is to have load balanced ftp. How does ftp.gnu.org and ftp.kernel.org handle their load? Since it's read-only, wouldn't failover handle it? Now that I think if it. ibiblio.org, just up the street from me, runs on LVS. So maybe load balanced ftp is useful. Joe -- Joseph Mack NA3T EME(B,D), FM05lw North Carolina jmack (at) wm7d (dot) net - azimuthal equidistant map generator at http://www.wm7d.net/azproj.shtml Homepage http://www.austintek.com/ It's GNU/Linux! --
That does sound like a nice idea. I think that is important that we don't confuse older kernels. I guess the only time that ineroperability would be important is when upgrading kernels, where you might want to take the IPv6 without sync is fine by me. Its certainly much better than no IPv6. Lets tackle sync a bit later. --
Ok, going for cleaning up and reworking more of the current IPv6 code then... -- Julius Volz Corporate Operations - SysOps Google Switzerland GmbH Identification No.: CH-020.4.028.116-1 --
I'd like to keep compatibility if possible. But I think there is --
Here is a second round of thoughts after having gone through the whole series.
[PATCH RFC 06/24] IPVS: Add debug macros for v4 and v6 address output
* The #defines in ip_vs_dbg_addr seem a bit aquard.
Could it be rearanged liks this?
static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
const union nf_inet_addr *addr,
int *idx)
{
int len;
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6)
len = snprintf(&buf[*idx], buf_len - *idx, "[" NIP6_FMT "]",
NIP6(addr->in6)) + 1;
else
#endif
len = snprintf(&buf[*idx], buf_len - *idx, NIPQUAD_FMT,
NIPQUAD(addr->ip)) + 1;
*idx += len;
return &buf[*idx - len];
}
* The comment "/* Only use from within IP_VS_DBG_BUF() macro */"
should also mention usage inside IP_VS_ERR_BUF()
* If IP_VS_DBG_ADDR() is used more than once inside a single
IP_VS_DBG_BUF() or IP_VS_ERR_BUF() call, won't ip_vs_dbg_buf
be set to the value one of the calls to IP_VS_DBG_ADDR,
thus overwriting other calls and producing incorrect debugging
output?
[PATCH RFC 15/24] IPVS: Add support for IPv6 entry output in procfs files
* The netlink-aware ipvsadm code also seems to allow for dotted-quad
representation of ipv4 addresses in proc. Is that representation used
or planned to be used?
[PATCH RFC 17/24] IPVS: Make proc/net files output IPv6 entries
* It might be cleaner to do:
#ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6)
seq_printf ...
else
#endif
seq_printf ...
General
* You need to reorder and or merge patches such that after each
patch is applied the code will build and run. It is ok for
a patch to add code which isn't used until a later patch is applied.
* Where possible please make lines <= 80 columns wide
--
No, the buffer can receive several strings (but it's limited in size, so you have to be careful). An index to the current position in the buffer is maintained in the 'idx' variable between multiple IP_VS_DBG_ADDR calls used in the same outer macro. In general, I'm a bit unsure if this kind of macro magic is acceptable style, but it was the best way I could come up with to merge Good catch! No, I wasn't even aware of that feature in the new ipvsadm (but now I see it). I think it should be removed because it is effectively dead code (the existing v4 proc format shouldn't be Yes, I have found no nice way to achieve this yet :( At least not when reworking the complete end result (one big patch) into smaller patches, because there is so much interdependency and several logical changes within the same hunks (or even lines). I might have to manually do a step-by-step adding of the logical code features to get Yes, I will check for that more strictly now (unless it really looks nicer otherwise), thanks! Julius -- Julius Volz Corporate Operations - SysOps Google Switzerland GmbH Identification No.: CH-020.4.028.116-1 --
Thanks, I knew I was missing something obvious. From a style point of view, I'm not sure either, but it seems like a reasonable start. Perhaps a slight enhancement would be to add a BUG_ON() to ip_vs_dbg_addr() which will I only noticed it from fixing up the atio() problem in ipvsadm that I posted a patch for the other day. Its not a big deal. But This is less critical, but thankfully easy :-) --
| Greg KH | Og dreams of kernels |
| Jens Axboe | [PATCH 31/33] Fusion: sg chaining support |
| Arnd Bergmann | Re: finding your own dead "CONFIG_" variables |
| Mark Brown |
