[RFC PATCH] IPVS: Backup, Adding IPv6 address packing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add pack/unpack of IPv6 address in sync message
in binary form similar to the ASCII ::

A packed IPv6 address constists of -
first byte
  high nibble first segment leng in bytes
  low nibble  possition of last segment.
then
  First segemnt i.e. left side of ::
  Last segment right side of ::

Examle  FC00::2
unpacked FC00 0000 0000 0000 0000 0000 0000 0002
packed   1F FC02
Example 2 2003::2:100
unpacked 2003 0000 0000 0000 0000 0000 0002 0100
packed   2D 20 03 02 01 00

Signed-off-by: Hans Schillstrom <hans.schillstrom@xxxxxxxxxxxx>
---
 net/netfilter/ipvs/ip_vs_sync.c |  128 +++++++++++++++++++++++++++++++++++---
 1 files changed, 117 insertions(+), 11 deletions(-)

diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 00f0fd3..6b4976c 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -363,6 +363,65 @@ get_curr_sync_buff(unsigned long time)
 	return sb;
 }
 
+/*
+ * Try to pack an IPv6 address
+ * Note that buffer must be at least 17 bytes
+ *
+ * Packing adds a byte before packed address
+ * m.s.nibble first segment size in bytes
+ * l.s.nibble last segment start offset in bytes (size = 16 - lastSeg)
+ *
+ * Return packed size, 0=no reduction
+ *        buffer contains first/lastSegemnt + (un)packed address
+ *
+ */
+static int ipv6addr_pack(struct in6_addr *in6, char *buffer)
+{
+	int i, pos=0, score=0;
+	int lmatch=0, firstSeg=0,lastSeg=0;
+	char *addr = in6->s6_addr;
+	char *buff = buffer;
+
+	/* Check for more than 3 bytes of zeroes */
+	for( i=0; i<16; i++) {
+		if ( *(addr++) ) {
+			score = 0;
+			continue;
+		}
+		if ( !score )
+			pos = i;
+		score++;
+		if (score > lmatch) {
+			lmatch = score;
+			firstSeg = pos;	/* Start of longest match */
+		}
+	}
+	lastSeg = firstSeg + lmatch;
+	addr = in6->s6_addr;
+	/* Store length of first seg then size of last seg */
+	*(buff++) = (firstSeg<<4 & 0xf0) | (lastSeg & 0xf);
+	memcpy(buff, addr, firstSeg);	/* Copy first segment */
+	buff += firstSeg;
+	memcpy(buff, addr+lastSeg, 16-lastSeg);
+	return 16 - lmatch;
+}
+/*
+ * unpack IPv6 address packed by above func.
+ */
+static int ipv6addr_unpack(char *buff, struct in6_addr *addr)
+{
+	int firstSeg, lastSeg;
+
+	firstSeg = (*buff >> 4) & 0xf;
+	lastSeg = *(buff++) & 0xf;
+	addr->s6_addr32[0] = 0;
+	addr->s6_addr32[1] = 0;
+	addr->s6_addr32[2] = 0;
+	addr->s6_addr32[3] = 0;
+	memcpy(addr->s6_addr, buff, firstSeg);
+	memcpy(addr->s6_addr+lastSeg, buff+firstSeg, 16-lastSeg);
+	return 0;
+}
 
 /*
  *      Add an ip_vs_conn information into the current sync_buff.
@@ -406,8 +465,8 @@ void ip_vs_sync_conn(struct ip_vs_conn *cp)
 		len += pe_name_len + 2;
 	len = (len+3) & 0xffc;		/* Final 32 bit alignment */
 
-	/* check if there is a space for this one */
-	if (curr_sb && (curr_sb->head+len > curr_sb->end) ) {
+	/* check if there is a space for this one and offest for ipv6 pack*/
+	if (curr_sb && (curr_sb->head+len+4 > curr_sb->end) ) {
 		sb_queue_tail(curr_sb);
 		curr_sb = NULL;
 	}
@@ -441,10 +500,26 @@ void ip_vs_sync_conn(struct ip_vs_conn *cp)
 
 #ifdef CONFIG_IP_VS_IPV6
 	if (cp->af == AF_INET6 ) {
-		p += sizeof(struct ip_vs_sync_v6);
-		ipv6_addr_copy(&s->v6.caddr, &cp->caddr.in6);
-		ipv6_addr_copy(&s->v6.vaddr, &cp->vaddr.in6);
-		ipv6_addr_copy(&s->v6.daddr, &cp->daddr.in6);
+		int psz;
+		p = (char *)&s->v6.caddr;
+		psz = ipv6addr_pack(&cp->caddr.in6, p);
+		psz += ipv6addr_pack(&cp->vaddr.in6, p+psz+1);
+		psz += ipv6addr_pack(&cp->vaddr.in6, p+psz+2);
+		if( psz >= 6 ) {
+			psz += 3;
+			p += psz;
+			s->v6.type |= STYPE_INET6_PACK;
+			len -= ((sizeof(struct in6_addr) * 3) - psz);
+			psz = sizeof(struct ip_vs_sync_v6)
+			      - (sizeof(struct in6_addr) * 3) + psz;
+			s->v6.ver_size = htons(psz & SVER_MASK);
+		}
+		else {
+			p += sizeof(struct ip_vs_sync_v6);
+			ipv6_addr_copy(&s->v6.caddr, &cp->caddr.in6);
+			ipv6_addr_copy(&s->v6.vaddr, &cp->vaddr.in6);
+			ipv6_addr_copy(&s->v6.daddr, &cp->daddr.in6);
+		}
 	} else
 #endif
 	{
@@ -508,13 +583,14 @@ ip_vs_conn_fill_param_sync(int af, union ip_vs_sync_conn *sc,
 			   int pe_data_len, char *pe_name, int pe_name_len )
 {
 #ifdef CONFIG_IP_VS_IPV6
-	if ( af == AF_INET6 )
-		ip_vs_conn_fill_param(af, sc->v6.protocol,
+	if ( af == AF_INET6 ) {
+		if (!(sc->v6.type & STYPE_INET6_PACK))
+			ip_vs_conn_fill_param(af, sc->v6.protocol,
 				   (const union nf_inet_addr *)&sc->v6.caddr,
 				   sc->v6.cport,
 				   (const union nf_inet_addr *)&sc->v6.vaddr,
 				   sc->v6.vport, p);
-	else
+	} else
 #endif
 		ip_vs_conn_fill_param(af, sc->v4.protocol,
 				   (const union nf_inet_addr *)&sc->v4.caddr,
@@ -780,7 +856,16 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
 		if (s->v6.type & STYPE_INET6  ) {
 #ifdef CONFIG_IP_VS_IPV6
 			af = AF_INET6;
-			p += sizeof(struct ip_vs_sync_v6);
+			if (s->v6.type & STYPE_INET6_PACK  ) {
+				p = (char*) &s->v6.caddr;
+				p += 1 + ((*p >> 4) & 0xf) /* len + First seg */
+				   + (16 - (*p & 0xf ));   /* + Last seg */
+				p += 1 + ((*p >> 4) & 0xf) /* len + First seg */
+				   + (16 - (*p & 0xf ));   /* + Last seg */
+				p += 1 + ((*p >> 4) & 0xf) /* len + First seg */
+				   + (16 - (*p & 0xf ));   /* + Last seg */
+			} else
+				p += sizeof(struct ip_vs_sync_v6);
 #else
 			IP_VS_DBG(2,"IPv6 sync message received, and IPVS is not compiled for IPv6\n");
 			p = (char *)s + size;		
@@ -891,7 +976,27 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
 				         ? &opt : NULL),
 				        pp);
 #ifdef CONFIG_IP_VS_IPV6
-		else
+		else {
+			/* Check if packed IPv6 */
+			if (s->v6.type & STYPE_INET6_PACK  ) {
+				union nf_inet_addr vaddr, daddr, caddr;
+				int ret;
+				p = (char*) &s->v6.caddr;
+				ret = ipv6addr_unpack(p, &caddr.in6);
+				p += 1 + ((*p >> 4) & 0xf) + (16 - (*p & 0xf ));
+				ret |= ipv6addr_unpack(p, &vaddr.in6);
+				p += 1 + ((*p >> 4) & 0xf) + (16 - (*p & 0xf ));
+				ret |= ipv6addr_unpack(p, &daddr.in6);
+				if (ret) {
+					IP_VS_ERR_RL("Invalid packed IPv6 add in sync msg\n");
+					return;
+				}
+				ip_vs_conn_fill_param(af, s->v6.protocol,
+						      &caddr, s->v6.cport,
+						      &vaddr, s->v6.vport,
+						      &param);
+
+			}
 			ip_vs_proc_conn(&param, flags, state, s->v6.protocol,
 					af,
 					(union nf_inet_addr *)&s->v6.daddr,
@@ -900,6 +1005,7 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
 				        (opt_flags & IPVS_OPT_F_SEQ_DATA
 				          ? &opt : NULL),
 				        pp);
+		}
 #endif
 		p = (char *)s + size;
 	} /* End of for(...) */
-- 
1.7.0.1

--
To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Devel]     [Linux NFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]     [X.Org]

  Powered by Linux