dect
/
linux-2.6
Archived
13
0
Fork 0

IPVS: Add 'af' args to protocol handler functions

Add 'af' arguments to conn_schedule(), conn_in_get(), conn_out_get() and
csum_check() function pointers in struct ip_vs_protocol. Extend the
respective functions for TCP, UDP, AH and ESP and adjust the callers.

The changes in the callers need to be somewhat extensive, since they now
need to pass a filled out struct ip_vs_iphdr * to the modified functions
instead of a struct iphdr *.

Signed-off-by: Julius Volz <juliusv@google.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
This commit is contained in:
Julius Volz 2008-09-02 15:55:40 +02:00 committed by Simon Horman
parent b14198f6c1
commit 51ef348b14
5 changed files with 171 additions and 124 deletions

View File

@ -296,21 +296,23 @@ struct ip_vs_protocol {
void (*exit)(struct ip_vs_protocol *pp); 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, struct ip_vs_protocol *pp,
int *verdict, struct ip_vs_conn **cpp); int *verdict, struct ip_vs_conn **cpp);
struct ip_vs_conn * 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, struct ip_vs_protocol *pp,
const struct iphdr *iph, const struct ip_vs_iphdr *iph,
unsigned int proto_off, unsigned int proto_off,
int inverse); int inverse);
struct ip_vs_conn * 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, struct ip_vs_protocol *pp,
const struct iphdr *iph, const struct ip_vs_iphdr *iph,
unsigned int proto_off, unsigned int proto_off,
int inverse); int inverse);
@ -320,7 +322,8 @@ struct ip_vs_protocol {
int (*dnat_handler)(struct sk_buff *skb, int (*dnat_handler)(struct sk_buff *skb,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp); 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); const char *(*state_name)(int state);

View File

@ -572,6 +572,7 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
struct iphdr *iph; struct iphdr *iph;
struct icmphdr _icmph, *ic; struct icmphdr _icmph, *ic;
struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */ struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
struct ip_vs_iphdr ciph;
struct ip_vs_conn *cp; struct ip_vs_conn *cp;
struct ip_vs_protocol *pp; struct ip_vs_protocol *pp;
unsigned int offset, ihl, verdict; unsigned int offset, ihl, verdict;
@ -627,8 +628,9 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
offset += cih->ihl * 4; offset += cih->ihl * 4;
ip_vs_fill_iphdr(AF_INET, cih, &ciph);
/* The embedded headers contain source and dest in reverse order */ /* The embedded headers contain source and dest in reverse order */
cp = pp->conn_out_get(skb, pp, cih, offset, 1); cp = pp->conn_out_get(AF_INET, skb, pp, &ciph, offset, 1);
if (!cp) if (!cp)
return NF_ACCEPT; return NF_ACCEPT;
@ -686,43 +688,41 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out, const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *))
{ {
struct iphdr *iph; struct ip_vs_iphdr iph;
struct ip_vs_protocol *pp; struct ip_vs_protocol *pp;
struct ip_vs_conn *cp; struct ip_vs_conn *cp;
int ihl;
EnterFunction(11); EnterFunction(11);
if (skb->ipvs_property) if (skb->ipvs_property)
return NF_ACCEPT; return NF_ACCEPT;
iph = ip_hdr(skb); ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
if (unlikely(iph->protocol == IPPROTO_ICMP)) { if (unlikely(iph.protocol == IPPROTO_ICMP)) {
int related, verdict = ip_vs_out_icmp(skb, &related); int related, verdict = ip_vs_out_icmp(skb, &related);
if (related) if (related)
return verdict; return verdict;
iph = ip_hdr(skb); ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
} }
pp = ip_vs_proto_get(iph->protocol); pp = ip_vs_proto_get(iph.protocol);
if (unlikely(!pp)) if (unlikely(!pp))
return NF_ACCEPT; return NF_ACCEPT;
/* reassemble IP fragments */ /* reassemble IP fragments */
if (unlikely(iph->frag_off & htons(IP_MF|IP_OFFSET) && if (unlikely(ip_hdr(skb)->frag_off & htons(IP_MF|IP_OFFSET) &&
!pp->dont_defrag)) { !pp->dont_defrag)) {
if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT)) if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
return NF_STOLEN; return NF_STOLEN;
iph = ip_hdr(skb);
}
ihl = iph->ihl << 2; ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
}
/* /*
* Check if the packet belongs to an existing entry * Check if the packet belongs to an existing entry
*/ */
cp = pp->conn_out_get(skb, pp, iph, ihl, 0); cp = pp->conn_out_get(AF_INET, skb, pp, &iph, iph.len, 0);
if (unlikely(!cp)) { if (unlikely(!cp)) {
if (sysctl_ip_vs_nat_icmp_send && if (sysctl_ip_vs_nat_icmp_send &&
@ -730,18 +730,18 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
pp->protocol == IPPROTO_UDP)) { pp->protocol == IPPROTO_UDP)) {
__be16 _ports[2], *pptr; __be16 _ports[2], *pptr;
pptr = skb_header_pointer(skb, ihl, pptr = skb_header_pointer(skb, iph.len,
sizeof(_ports), _ports); sizeof(_ports), _ports);
if (pptr == NULL) if (pptr == NULL)
return NF_ACCEPT; /* Not for me */ return NF_ACCEPT; /* Not for me */
if (ip_vs_lookup_real_service(iph->protocol, if (ip_vs_lookup_real_service(iph.protocol,
iph->saddr, pptr[0])) { iph.saddr.ip, pptr[0])) {
/* /*
* Notify the real server: there is no * Notify the real server: there is no
* existing entry if it is not RST * existing entry if it is not RST
* packet or not TCP packet. * packet or not TCP packet.
*/ */
if (iph->protocol != IPPROTO_TCP if (iph.protocol != IPPROTO_TCP
|| !is_tcp_reset(skb)) { || !is_tcp_reset(skb)) {
icmp_send(skb,ICMP_DEST_UNREACH, icmp_send(skb,ICMP_DEST_UNREACH,
ICMP_PORT_UNREACH, 0); ICMP_PORT_UNREACH, 0);
@ -756,7 +756,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet"); IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet");
if (!skb_make_writable(skb, ihl)) if (!skb_make_writable(skb, iph.len))
goto drop; goto drop;
/* mangle the packet */ /* mangle the packet */
@ -804,6 +804,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
struct iphdr *iph; struct iphdr *iph;
struct icmphdr _icmph, *ic; struct icmphdr _icmph, *ic;
struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */ struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
struct ip_vs_iphdr ciph;
struct ip_vs_conn *cp; struct ip_vs_conn *cp;
struct ip_vs_protocol *pp; struct ip_vs_protocol *pp;
unsigned int offset, ihl, verdict; unsigned int offset, ihl, verdict;
@ -860,8 +861,9 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
offset += cih->ihl * 4; offset += cih->ihl * 4;
ip_vs_fill_iphdr(AF_INET, cih, &ciph);
/* The embedded headers contain source and dest in reverse order */ /* The embedded headers contain source and dest in reverse order */
cp = pp->conn_in_get(skb, pp, cih, offset, 1); cp = pp->conn_in_get(AF_INET, skb, pp, &ciph, offset, 1);
if (!cp) if (!cp)
return NF_ACCEPT; return NF_ACCEPT;
@ -897,11 +899,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out, const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *))
{ {
struct iphdr *iph; struct ip_vs_iphdr iph;
struct ip_vs_protocol *pp; struct ip_vs_protocol *pp;
struct ip_vs_conn *cp; struct ip_vs_conn *cp;
int ret, restart; int ret, restart;
int ihl;
ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
/* /*
* Big tappo: only PACKET_HOST (neither loopback nor mcasts) * Big tappo: only PACKET_HOST (neither loopback nor mcasts)
@ -909,38 +912,35 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
*/ */
if (unlikely(skb->pkt_type != PACKET_HOST if (unlikely(skb->pkt_type != PACKET_HOST
|| skb->dev->flags & IFF_LOOPBACK || skb->sk)) { || skb->dev->flags & IFF_LOOPBACK || skb->sk)) {
IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n", IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
skb->pkt_type, skb->pkt_type,
ip_hdr(skb)->protocol, iph.protocol,
NIPQUAD(ip_hdr(skb)->daddr)); IP_VS_DBG_ADDR(AF_INET, &iph.daddr));
return NF_ACCEPT; return NF_ACCEPT;
} }
iph = ip_hdr(skb); if (unlikely(iph.protocol == IPPROTO_ICMP)) {
if (unlikely(iph->protocol == IPPROTO_ICMP)) {
int related, verdict = ip_vs_in_icmp(skb, &related, hooknum); int related, verdict = ip_vs_in_icmp(skb, &related, hooknum);
if (related) if (related)
return verdict; return verdict;
iph = ip_hdr(skb); ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
} }
/* Protocol supported? */ /* Protocol supported? */
pp = ip_vs_proto_get(iph->protocol); pp = ip_vs_proto_get(iph.protocol);
if (unlikely(!pp)) if (unlikely(!pp))
return NF_ACCEPT; return NF_ACCEPT;
ihl = iph->ihl << 2;
/* /*
* Check if the packet belongs to an existing connection entry * Check if the packet belongs to an existing connection entry
*/ */
cp = pp->conn_in_get(skb, pp, iph, ihl, 0); cp = pp->conn_in_get(AF_INET, skb, pp, &iph, iph.len, 0);
if (unlikely(!cp)) { if (unlikely(!cp)) {
int v; int v;
if (!pp->conn_schedule(skb, pp, &v, &cp)) if (!pp->conn_schedule(AF_INET, skb, pp, &v, &cp))
return v; return v;
} }

View File

@ -39,25 +39,23 @@ struct isakmp_hdr {
static struct ip_vs_conn * static struct ip_vs_conn *
ah_esp_conn_in_get(const struct sk_buff *skb, ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_protocol *pp, const struct ip_vs_iphdr *iph, unsigned int proto_off,
const struct iphdr *iph,
unsigned int proto_off,
int inverse) int inverse)
{ {
struct ip_vs_conn *cp; struct ip_vs_conn *cp;
if (likely(!inverse)) { if (likely(!inverse)) {
cp = ip_vs_conn_in_get(IPPROTO_UDP, cp = ip_vs_conn_in_get(IPPROTO_UDP,
iph->saddr, iph->saddr.ip,
htons(PORT_ISAKMP), htons(PORT_ISAKMP),
iph->daddr, iph->daddr.ip,
htons(PORT_ISAKMP)); htons(PORT_ISAKMP));
} else { } else {
cp = ip_vs_conn_in_get(IPPROTO_UDP, cp = ip_vs_conn_in_get(IPPROTO_UDP,
iph->daddr, iph->daddr.ip,
htons(PORT_ISAKMP), htons(PORT_ISAKMP),
iph->saddr, iph->saddr.ip,
htons(PORT_ISAKMP)); htons(PORT_ISAKMP));
} }
@ -66,12 +64,12 @@ ah_esp_conn_in_get(const struct sk_buff *skb,
* We are not sure if the packet is from our * We are not sure if the packet is from our
* service, so our conn_schedule hook should return NF_ACCEPT * service, so our conn_schedule hook should return NF_ACCEPT
*/ */
IP_VS_DBG(12, "Unknown ISAKMP entry for outin packet " IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for outin packet "
"%s%s %u.%u.%u.%u->%u.%u.%u.%u\n", "%s%s %s->%s\n",
inverse ? "ICMP+" : "", inverse ? "ICMP+" : "",
pp->name, pp->name,
NIPQUAD(iph->saddr), IP_VS_DBG_ADDR(af, &iph->saddr),
NIPQUAD(iph->daddr)); IP_VS_DBG_ADDR(af, &iph->daddr));
} }
return cp; return cp;
@ -79,32 +77,35 @@ ah_esp_conn_in_get(const struct sk_buff *skb,
static struct ip_vs_conn * static struct ip_vs_conn *
ah_esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, ah_esp_conn_out_get(int af, const struct sk_buff *skb,
const struct iphdr *iph, unsigned int proto_off, int inverse) struct ip_vs_protocol *pp,
const struct ip_vs_iphdr *iph,
unsigned int proto_off,
int inverse)
{ {
struct ip_vs_conn *cp; struct ip_vs_conn *cp;
if (likely(!inverse)) { if (likely(!inverse)) {
cp = ip_vs_conn_out_get(IPPROTO_UDP, cp = ip_vs_conn_out_get(IPPROTO_UDP,
iph->saddr, iph->saddr.ip,
htons(PORT_ISAKMP), htons(PORT_ISAKMP),
iph->daddr, iph->daddr.ip,
htons(PORT_ISAKMP)); htons(PORT_ISAKMP));
} else { } else {
cp = ip_vs_conn_out_get(IPPROTO_UDP, cp = ip_vs_conn_out_get(IPPROTO_UDP,
iph->daddr, iph->daddr.ip,
htons(PORT_ISAKMP), htons(PORT_ISAKMP),
iph->saddr, iph->saddr.ip,
htons(PORT_ISAKMP)); htons(PORT_ISAKMP));
} }
if (!cp) { if (!cp) {
IP_VS_DBG(12, "Unknown ISAKMP entry for inout packet " IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
"%s%s %u.%u.%u.%u->%u.%u.%u.%u\n", "%s%s %s->%s\n",
inverse ? "ICMP+" : "", inverse ? "ICMP+" : "",
pp->name, pp->name,
NIPQUAD(iph->saddr), IP_VS_DBG_ADDR(af, &iph->saddr),
NIPQUAD(iph->daddr)); IP_VS_DBG_ADDR(af, &iph->daddr));
} }
return cp; return cp;
@ -112,8 +113,7 @@ ah_esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
static int static int
ah_esp_conn_schedule(struct sk_buff *skb, ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_protocol *pp,
int *verdict, struct ip_vs_conn **cpp) int *verdict, struct ip_vs_conn **cpp)
{ {
/* /*

View File

@ -25,8 +25,9 @@
static struct ip_vs_conn * static struct ip_vs_conn *
tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, tcp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse) const struct ip_vs_iphdr *iph, unsigned int proto_off,
int inverse)
{ {
__be16 _ports[2], *pptr; __be16 _ports[2], *pptr;
@ -36,18 +37,19 @@ tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
if (likely(!inverse)) { if (likely(!inverse)) {
return ip_vs_conn_in_get(iph->protocol, return ip_vs_conn_in_get(iph->protocol,
iph->saddr, pptr[0], iph->saddr.ip, pptr[0],
iph->daddr, pptr[1]); iph->daddr.ip, pptr[1]);
} else { } else {
return ip_vs_conn_in_get(iph->protocol, return ip_vs_conn_in_get(iph->protocol,
iph->daddr, pptr[1], iph->daddr.ip, pptr[1],
iph->saddr, pptr[0]); iph->saddr.ip, pptr[0]);
} }
} }
static struct ip_vs_conn * static struct ip_vs_conn *
tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, tcp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse) const struct ip_vs_iphdr *iph, unsigned int proto_off,
int inverse)
{ {
__be16 _ports[2], *pptr; __be16 _ports[2], *pptr;
@ -57,26 +59,25 @@ tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
if (likely(!inverse)) { if (likely(!inverse)) {
return ip_vs_conn_out_get(iph->protocol, return ip_vs_conn_out_get(iph->protocol,
iph->saddr, pptr[0], iph->saddr.ip, pptr[0],
iph->daddr, pptr[1]); iph->daddr.ip, pptr[1]);
} else { } else {
return ip_vs_conn_out_get(iph->protocol, return ip_vs_conn_out_get(iph->protocol,
iph->daddr, pptr[1], iph->daddr.ip, pptr[1],
iph->saddr, pptr[0]); iph->saddr.ip, pptr[0]);
} }
} }
static int static int
tcp_conn_schedule(struct sk_buff *skb, tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_protocol *pp,
int *verdict, struct ip_vs_conn **cpp) int *verdict, struct ip_vs_conn **cpp)
{ {
struct ip_vs_service *svc; struct ip_vs_service *svc;
struct tcphdr _tcph, *th; struct tcphdr _tcph, *th;
struct ip_vs_iphdr iph; struct ip_vs_iphdr iph;
ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph); ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
th = skb_header_pointer(skb, iph.len, sizeof(_tcph), &_tcph); th = skb_header_pointer(skb, iph.len, sizeof(_tcph), &_tcph);
if (th == NULL) { if (th == NULL) {
@ -85,8 +86,8 @@ tcp_conn_schedule(struct sk_buff *skb,
} }
if (th->syn && if (th->syn &&
(svc = ip_vs_service_get(AF_INET, skb->mark, iph.protocol, (svc = ip_vs_service_get(af, skb->mark, iph.protocol, &iph.daddr,
&iph.daddr, th->dest))) { th->dest))) {
if (ip_vs_todrop()) { if (ip_vs_todrop()) {
/* /*
* It seems that we are very loaded. * It seems that we are very loaded.
@ -136,7 +137,7 @@ tcp_snat_handler(struct sk_buff *skb,
if (unlikely(cp->app != NULL)) { if (unlikely(cp->app != NULL)) {
/* Some checks before mangling */ /* Some checks before mangling */
if (pp->csum_check && !pp->csum_check(skb, pp)) if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
return 0; return 0;
/* Call application helper if needed */ /* Call application helper if needed */
@ -182,7 +183,7 @@ tcp_dnat_handler(struct sk_buff *skb,
if (unlikely(cp->app != NULL)) { if (unlikely(cp->app != NULL)) {
/* Some checks before mangling */ /* Some checks before mangling */
if (pp->csum_check && !pp->csum_check(skb, pp)) if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
return 0; return 0;
/* /*
@ -219,21 +220,43 @@ tcp_dnat_handler(struct sk_buff *skb,
static int static int
tcp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
{ {
const unsigned int tcphoff = ip_hdrlen(skb); unsigned int tcphoff;
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6)
tcphoff = sizeof(struct ipv6hdr);
else
#endif
tcphoff = ip_hdrlen(skb);
switch (skb->ip_summed) { switch (skb->ip_summed) {
case CHECKSUM_NONE: case CHECKSUM_NONE:
skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0); skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
case CHECKSUM_COMPLETE: case CHECKSUM_COMPLETE:
if (csum_tcpudp_magic(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, #ifdef CONFIG_IP_VS_IPV6
skb->len - tcphoff, if (af == AF_INET6) {
ip_hdr(skb)->protocol, skb->csum)) { if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
IP_VS_DBG_RL_PKT(0, pp, skb, 0, &ipv6_hdr(skb)->daddr,
"Failed checksum for"); skb->len - tcphoff,
return 0; ipv6_hdr(skb)->nexthdr,
} skb->csum)) {
IP_VS_DBG_RL_PKT(0, pp, skb, 0,
"Failed checksum for");
return 0;
}
} else
#endif
if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
ip_hdr(skb)->daddr,
skb->len - tcphoff,
ip_hdr(skb)->protocol,
skb->csum)) {
IP_VS_DBG_RL_PKT(0, pp, skb, 0,
"Failed checksum for");
return 0;
}
break; break;
default: default:
/* No need to checksum. */ /* No need to checksum. */

View File

@ -24,8 +24,9 @@
#include <net/ip.h> #include <net/ip.h>
static struct ip_vs_conn * static struct ip_vs_conn *
udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, udp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse) const struct ip_vs_iphdr *iph, unsigned int proto_off,
int inverse)
{ {
struct ip_vs_conn *cp; struct ip_vs_conn *cp;
__be16 _ports[2], *pptr; __be16 _ports[2], *pptr;
@ -36,12 +37,12 @@ udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
if (likely(!inverse)) { if (likely(!inverse)) {
cp = ip_vs_conn_in_get(iph->protocol, cp = ip_vs_conn_in_get(iph->protocol,
iph->saddr, pptr[0], iph->saddr.ip, pptr[0],
iph->daddr, pptr[1]); iph->daddr.ip, pptr[1]);
} else { } else {
cp = ip_vs_conn_in_get(iph->protocol, cp = ip_vs_conn_in_get(iph->protocol,
iph->daddr, pptr[1], iph->daddr.ip, pptr[1],
iph->saddr, pptr[0]); iph->saddr.ip, pptr[0]);
} }
return cp; return cp;
@ -49,25 +50,25 @@ udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
static struct ip_vs_conn * static struct ip_vs_conn *
udp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp, udp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse) const struct ip_vs_iphdr *iph, unsigned int proto_off,
int inverse)
{ {
struct ip_vs_conn *cp; struct ip_vs_conn *cp;
__be16 _ports[2], *pptr; __be16 _ports[2], *pptr;
pptr = skb_header_pointer(skb, ip_hdrlen(skb), pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
sizeof(_ports), _ports);
if (pptr == NULL) if (pptr == NULL)
return NULL; return NULL;
if (likely(!inverse)) { if (likely(!inverse)) {
cp = ip_vs_conn_out_get(iph->protocol, cp = ip_vs_conn_out_get(iph->protocol,
iph->saddr, pptr[0], iph->saddr.ip, pptr[0],
iph->daddr, pptr[1]); iph->daddr.ip, pptr[1]);
} else { } else {
cp = ip_vs_conn_out_get(iph->protocol, cp = ip_vs_conn_out_get(iph->protocol,
iph->daddr, pptr[1], iph->daddr.ip, pptr[1],
iph->saddr, pptr[0]); iph->saddr.ip, pptr[0]);
} }
return cp; return cp;
@ -75,14 +76,14 @@ udp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
static int static int
udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp, udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
int *verdict, struct ip_vs_conn **cpp) int *verdict, struct ip_vs_conn **cpp)
{ {
struct ip_vs_service *svc; struct ip_vs_service *svc;
struct udphdr _udph, *uh; struct udphdr _udph, *uh;
struct ip_vs_iphdr iph; struct ip_vs_iphdr iph;
ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph); ip_vs_fill_iphdr(af, skb_network_header(skb), &iph);
uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph); uh = skb_header_pointer(skb, iph.len, sizeof(_udph), &_udph);
if (uh == NULL) { if (uh == NULL) {
@ -90,7 +91,7 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
return 0; return 0;
} }
svc = ip_vs_service_get(AF_INET, skb->mark, iph.protocol, svc = ip_vs_service_get(af, skb->mark, iph.protocol,
&iph.daddr, uh->dest); &iph.daddr, uh->dest);
if (svc) { if (svc) {
if (ip_vs_todrop()) { if (ip_vs_todrop()) {
@ -143,7 +144,7 @@ udp_snat_handler(struct sk_buff *skb,
if (unlikely(cp->app != NULL)) { if (unlikely(cp->app != NULL)) {
/* Some checks before mangling */ /* Some checks before mangling */
if (pp->csum_check && !pp->csum_check(skb, pp)) if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
return 0; return 0;
/* /*
@ -195,7 +196,7 @@ udp_dnat_handler(struct sk_buff *skb,
if (unlikely(cp->app != NULL)) { if (unlikely(cp->app != NULL)) {
/* Some checks before mangling */ /* Some checks before mangling */
if (pp->csum_check && !pp->csum_check(skb, pp)) if (pp->csum_check && !pp->csum_check(AF_INET, skb, pp))
return 0; return 0;
/* /*
@ -234,10 +235,17 @@ udp_dnat_handler(struct sk_buff *skb,
static int static int
udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
{ {
struct udphdr _udph, *uh; struct udphdr _udph, *uh;
const unsigned int udphoff = ip_hdrlen(skb); unsigned int udphoff;
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6)
udphoff = sizeof(struct ipv6hdr);
else
#endif
udphoff = ip_hdrlen(skb);
uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph); uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
if (uh == NULL) if (uh == NULL)
@ -249,15 +257,28 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
skb->csum = skb_checksum(skb, udphoff, skb->csum = skb_checksum(skb, udphoff,
skb->len - udphoff, 0); skb->len - udphoff, 0);
case CHECKSUM_COMPLETE: case CHECKSUM_COMPLETE:
if (csum_tcpudp_magic(ip_hdr(skb)->saddr, #ifdef CONFIG_IP_VS_IPV6
ip_hdr(skb)->daddr, if (af == AF_INET6) {
skb->len - udphoff, if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
ip_hdr(skb)->protocol, &ipv6_hdr(skb)->daddr,
skb->csum)) { skb->len - udphoff,
IP_VS_DBG_RL_PKT(0, pp, skb, 0, ipv6_hdr(skb)->nexthdr,
"Failed checksum for"); skb->csum)) {
return 0; IP_VS_DBG_RL_PKT(0, pp, skb, 0,
} "Failed checksum for");
return 0;
}
} else
#endif
if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
ip_hdr(skb)->daddr,
skb->len - udphoff,
ip_hdr(skb)->protocol,
skb->csum)) {
IP_VS_DBG_RL_PKT(0, pp, skb, 0,
"Failed checksum for");
return 0;
}
break; break;
default: default:
/* No need to checksum. */ /* No need to checksum. */