Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7937df15 authored by Julius Volz's avatar Julius Volz Committed by Simon Horman
Browse files

IPVS: Convert real server lookup functions



Convert functions for looking up destinations (real servers) to support
IPv6 services/dests.

Signed-off-by: default avatarJulius Volz <juliusv@google.com>
Signed-off-by: default avatarSimon Horman <horms@verge.net.au>
parent 2a3b791e
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -804,14 +804,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);


+3 −2
Original line number Diff line number Diff line
@@ -491,8 +491,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.ip, cp->dport,
				       cp->vaddr.ip, 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
+2 −2
Original line number Diff line number Diff line
@@ -957,8 +957,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
						  sizeof(_ports), _ports);
			if (pptr == NULL)
				return NF_ACCEPT;	/* Not for me */
			if (ip_vs_lookup_real_service(iph.protocol,
						      iph.saddr.ip,
			if (ip_vs_lookup_real_service(af, iph.protocol,
						      &iph.saddr,
						      pptr[0])) {
				/*
				 * Notify the real server: there is no
+52 −28
Original line number Diff line number Diff line
@@ -492,11 +492,20 @@ __ip_vs_unbind_svc(struct ip_vs_dest *dest)
/*
 *	Returns hash value for real service
 */
static __inline__ unsigned ip_vs_rs_hashkey(__be32 addr, __be16 port)
static inline unsigned ip_vs_rs_hashkey(int af,
					    const union nf_inet_addr *addr,
					    __be16 port)
{
	register unsigned porth = ntohs(port);
	__be32 addr_fold = addr->ip;

	return (ntohl(addr)^(porth>>IP_VS_RTAB_BITS)^porth)
#ifdef CONFIG_IP_VS_IPV6
	if (af == AF_INET6)
		addr_fold = addr->ip6[0]^addr->ip6[1]^
			    addr->ip6[2]^addr->ip6[3];
#endif

	return (ntohl(addr_fold)^(porth>>IP_VS_RTAB_BITS)^porth)
		& IP_VS_RTAB_MASK;
}

@@ -516,7 +525,8 @@ static int ip_vs_rs_hash(struct ip_vs_dest *dest)
	 *	Hash by proto,addr,port,
	 *	which are the parameters of the real service.
	 */
	hash = ip_vs_rs_hashkey(dest->addr.ip, dest->port);
	hash = ip_vs_rs_hashkey(dest->af, &dest->addr, dest->port);

	list_add(&dest->d_list, &ip_vs_rtable[hash]);

	return 1;
@@ -543,7 +553,9 @@ static int ip_vs_rs_unhash(struct ip_vs_dest *dest)
 *	Lookup real service by <proto,addr,port> in the real service table.
 */
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)
{
	unsigned hash;
	struct ip_vs_dest *dest;
@@ -552,11 +564,12 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
	 *	Check for "full" addressed entries
	 *	Return the first found entry
	 */
	hash = ip_vs_rs_hashkey(daddr, dport);
	hash = ip_vs_rs_hashkey(af, daddr, dport);

	read_lock(&__ip_vs_rs_lock);
	list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) {
		if ((dest->addr.ip == daddr)
		if ((dest->af == af)
		    && ip_vs_addr_equal(af, &dest->addr, daddr)
		    && (dest->port == dport)
		    && ((dest->protocol == protocol) ||
			dest->vfwmark)) {
@@ -574,7 +587,8 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
 *	Lookup destination by {addr,port} in the given service
 */
static struct ip_vs_dest *
ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
		  __be16 dport)
{
	struct ip_vs_dest *dest;

@@ -582,7 +596,9 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
	 * Find the destination for the given service
	 */
	list_for_each_entry(dest, &svc->destinations, n_list) {
		if ((dest->addr.ip == daddr) && (dest->port == dport)) {
		if ((dest->af == svc->af)
		    && ip_vs_addr_equal(svc->af, &dest->addr, daddr)
		    && (dest->port == dport)) {
			/* HIT */
			return dest;
		}
@@ -601,14 +617,15 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
 * ip_vs_lookup_real_service() looked promissing, but
 * seems not working as expected.
 */
struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
				    __be32 vaddr, __be16 vport, __u16 protocol)
struct ip_vs_dest *ip_vs_find_dest(int af, const union nf_inet_addr *daddr,
				   __be16 dport,
				   const union nf_inet_addr *vaddr,
				   __be16 vport, __u16 protocol)
{
	struct ip_vs_dest *dest;
	struct ip_vs_service *svc;
	union nf_inet_addr _vaddr = { .ip = vaddr };

	svc = ip_vs_service_get(AF_INET, 0, protocol, &_vaddr, vport);
	svc = ip_vs_service_get(af, 0, protocol, vaddr, vport);
	if (!svc)
		return NULL;
	dest = ip_vs_lookup_dest(svc, daddr, dport);
@@ -629,7 +646,8 @@ struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
 *  scheduling.
 */
static struct ip_vs_dest *
ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
		     __be16 dport)
{
	struct ip_vs_dest *dest, *nxt;

@@ -637,17 +655,19 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
	 * Find the destination in trash
	 */
	list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) {
		IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, "
		IP_VS_DBG_BUF(3, "Destination %u/%s:%u still in trash, "
			      "dest->refcnt=%d\n",
			      dest->vfwmark,
			  NIPQUAD(dest->addr.ip), ntohs(dest->port),
			      IP_VS_DBG_ADDR(svc->af, &dest->addr),
			      ntohs(dest->port),
			      atomic_read(&dest->refcnt));
		if (dest->addr.ip == daddr &&
		if (dest->af == svc->af &&
		    ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
		    dest->port == dport &&
		    dest->vfwmark == svc->fwmark &&
		    dest->protocol == svc->protocol &&
		    (svc->fwmark ||
		     (dest->vaddr.ip == svc->addr.ip &&
		     (ip_vs_addr_equal(svc->af, &dest->vaddr, &svc->addr) &&
		      dest->vport == svc->port))) {
			/* HIT */
			return dest;
@@ -657,10 +677,11 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
		 * Try to purge the destination from trash if not referenced
		 */
		if (atomic_read(&dest->refcnt) == 1) {
			IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u "
			IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u "
				      "from trash\n",
				      dest->vfwmark,
				  NIPQUAD(dest->addr.ip), ntohs(dest->port));
				      IP_VS_DBG_ADDR(svc->af, &dest->addr),
				      ntohs(dest->port));
			list_del(&dest->n_list);
			ip_vs_dst_reset(dest);
			__ip_vs_unbind_svc(dest);
@@ -847,7 +868,8 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
	/*
	 * Check if the dest already exists in the list
	 */
	dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
	dest = ip_vs_lookup_dest(svc, &daddr, dport);

	if (dest != NULL) {
		IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
		return -EEXIST;
@@ -857,7 +879,8 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
	 * Check if the dest already exists in the trash and
	 * is from the same service
	 */
	dest = ip_vs_trash_get_dest(svc, daddr.ip, dport);
	dest = ip_vs_trash_get_dest(svc, &daddr, dport);

	if (dest != NULL) {
		IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, "
			  "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
@@ -956,7 +979,8 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
	/*
	 *  Lookup the destination list
	 */
	dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
	dest = ip_vs_lookup_dest(svc, &daddr, dport);

	if (dest == NULL) {
		IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
		return -ENOENT;
@@ -1054,7 +1078,7 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)

	EnterFunction(2);

	dest = ip_vs_lookup_dest(svc, udest->addr.ip, dport);
	dest = ip_vs_lookup_dest(svc, &udest->addr, dport);

	if (dest == NULL) {
		IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");
+5 −2
Original line number Diff line number Diff line
@@ -383,8 +383,11 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
			 * If it is not found the connection will remain unbound
			 * but still handled.
			 */
			dest = ip_vs_find_dest(s->daddr, s->dport,
					       s->vaddr, s->vport,
			dest = ip_vs_find_dest(AF_INET,
					       (union nf_inet_addr *)&s->daddr,
					       s->dport,
					       (union nf_inet_addr *)&s->vaddr,
					       s->vport,
					       s->protocol);
			/*  Set the approprite ativity flag */
			if (s->protocol == IPPROTO_TCP) {