Skip to content

Commit

Permalink
IPVS: Add 'af' args to protocol handler functions
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Julius Volz authored and Simon Horman committed Sep 5, 2008
1 parent b14198f commit 51ef348
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 124 deletions.
15 changes: 9 additions & 6 deletions include/net/ip_vs.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,21 +296,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);

Expand All @@ -320,7 +322,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);

Expand Down
64 changes: 32 additions & 32 deletions net/ipv4/ipvs/ip_vs_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)
struct iphdr *iph;
struct icmphdr _icmph, *ic;
struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
struct ip_vs_iphdr ciph;
struct ip_vs_conn *cp;
struct ip_vs_protocol *pp;
unsigned int offset, ihl, verdict;
Expand Down Expand Up @@ -627,8 +628,9 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related)

offset += cih->ihl * 4;

ip_vs_fill_iphdr(AF_INET, cih, &ciph);
/* 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)
return NF_ACCEPT;

Expand Down Expand Up @@ -686,62 +688,60 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph;
struct ip_vs_iphdr iph;
struct ip_vs_protocol *pp;
struct ip_vs_conn *cp;
int ihl;

EnterFunction(11);

if (skb->ipvs_property)
return NF_ACCEPT;

iph = ip_hdr(skb);
if (unlikely(iph->protocol == IPPROTO_ICMP)) {
ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
if (unlikely(iph.protocol == IPPROTO_ICMP)) {
int related, verdict = ip_vs_out_icmp(skb, &related);

if (related)
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))
return NF_ACCEPT;

/* 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)) {
if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT))
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
*/
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 (sysctl_ip_vs_nat_icmp_send &&
(pp->protocol == IPPROTO_TCP ||
pp->protocol == IPPROTO_UDP)) {
__be16 _ports[2], *pptr;

pptr = skb_header_pointer(skb, ihl,
pptr = skb_header_pointer(skb, iph.len,
sizeof(_ports), _ports);
if (pptr == NULL)
return NF_ACCEPT; /* Not for me */
if (ip_vs_lookup_real_service(iph->protocol,
iph->saddr, pptr[0])) {
if (ip_vs_lookup_real_service(iph.protocol,
iph.saddr.ip, pptr[0])) {
/*
* Notify the real server: there is no
* existing entry if it is not RST
* packet or not TCP packet.
*/
if (iph->protocol != IPPROTO_TCP
if (iph.protocol != IPPROTO_TCP
|| !is_tcp_reset(skb)) {
icmp_send(skb,ICMP_DEST_UNREACH,
ICMP_PORT_UNREACH, 0);
Expand All @@ -756,7 +756,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb,

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;

/* mangle the packet */
Expand Down Expand Up @@ -804,6 +804,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
struct iphdr *iph;
struct icmphdr _icmph, *ic;
struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
struct ip_vs_iphdr ciph;
struct ip_vs_conn *cp;
struct ip_vs_protocol *pp;
unsigned int offset, ihl, verdict;
Expand Down Expand Up @@ -860,8 +861,9 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)

offset += cih->ihl * 4;

ip_vs_fill_iphdr(AF_INET, cih, &ciph);
/* 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)
return NF_ACCEPT;

Expand Down Expand Up @@ -897,50 +899,48 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph;
struct ip_vs_iphdr iph;
struct ip_vs_protocol *pp;
struct ip_vs_conn *cp;
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)
* ... don't know why 1st test DOES NOT include 2nd (?)
*/
if (unlikely(skb->pkt_type != PACKET_HOST
|| skb->dev->flags & IFF_LOOPBACK || skb->sk)) {
IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n",
skb->pkt_type,
ip_hdr(skb)->protocol,
NIPQUAD(ip_hdr(skb)->daddr));
IP_VS_DBG_BUF(12, "packet type=%d proto=%d daddr=%s ignored\n",
skb->pkt_type,
iph.protocol,
IP_VS_DBG_ADDR(AF_INET, &iph.daddr));
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);

if (related)
return verdict;
iph = ip_hdr(skb);
ip_vs_fill_iphdr(AF_INET, skb_network_header(skb), &iph);
}

/* Protocol supported? */
pp = ip_vs_proto_get(iph->protocol);
pp = ip_vs_proto_get(iph.protocol);
if (unlikely(!pp))
return NF_ACCEPT;

ihl = iph->ihl << 2;

/*
* 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)) {
int v;

if (!pp->conn_schedule(skb, pp, &v, &cp))
if (!pp->conn_schedule(AF_INET, skb, pp, &v, &cp))
return v;
}

Expand Down
56 changes: 28 additions & 28 deletions net/ipv4/ipvs/ip_vs_proto_ah_esp.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,23 @@ struct isakmp_hdr {


static struct ip_vs_conn *
ah_esp_conn_in_get(const struct sk_buff *skb,
struct ip_vs_protocol *pp,
const struct iphdr *iph,
unsigned int proto_off,
ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct ip_vs_iphdr *iph, unsigned int proto_off,
int inverse)
{
struct ip_vs_conn *cp;

if (likely(!inverse)) {
cp = ip_vs_conn_in_get(IPPROTO_UDP,
iph->saddr,
iph->saddr.ip,
htons(PORT_ISAKMP),
iph->daddr,
iph->daddr.ip,
htons(PORT_ISAKMP));
} else {
cp = ip_vs_conn_in_get(IPPROTO_UDP,
iph->daddr,
iph->daddr.ip,
htons(PORT_ISAKMP),
iph->saddr,
iph->saddr.ip,
htons(PORT_ISAKMP));
}

Expand All @@ -66,54 +64,56 @@ ah_esp_conn_in_get(const struct sk_buff *skb,
* We are not sure if the packet is from our
* service, so our conn_schedule hook should return NF_ACCEPT
*/
IP_VS_DBG(12, "Unknown ISAKMP entry for outin packet "
"%s%s %u.%u.%u.%u->%u.%u.%u.%u\n",
inverse ? "ICMP+" : "",
pp->name,
NIPQUAD(iph->saddr),
NIPQUAD(iph->daddr));
IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for outin packet "
"%s%s %s->%s\n",
inverse ? "ICMP+" : "",
pp->name,
IP_VS_DBG_ADDR(af, &iph->saddr),
IP_VS_DBG_ADDR(af, &iph->daddr));
}

return cp;
}


static struct ip_vs_conn *
ah_esp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse)
ah_esp_conn_out_get(int af, const struct sk_buff *skb,
struct ip_vs_protocol *pp,
const struct ip_vs_iphdr *iph,
unsigned int proto_off,
int inverse)
{
struct ip_vs_conn *cp;

if (likely(!inverse)) {
cp = ip_vs_conn_out_get(IPPROTO_UDP,
iph->saddr,
iph->saddr.ip,
htons(PORT_ISAKMP),
iph->daddr,
iph->daddr.ip,
htons(PORT_ISAKMP));
} else {
cp = ip_vs_conn_out_get(IPPROTO_UDP,
iph->daddr,
iph->daddr.ip,
htons(PORT_ISAKMP),
iph->saddr,
iph->saddr.ip,
htons(PORT_ISAKMP));
}

if (!cp) {
IP_VS_DBG(12, "Unknown ISAKMP entry for inout packet "
"%s%s %u.%u.%u.%u->%u.%u.%u.%u\n",
inverse ? "ICMP+" : "",
pp->name,
NIPQUAD(iph->saddr),
NIPQUAD(iph->daddr));
IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
"%s%s %s->%s\n",
inverse ? "ICMP+" : "",
pp->name,
IP_VS_DBG_ADDR(af, &iph->saddr),
IP_VS_DBG_ADDR(af, &iph->daddr));
}

return cp;
}


static int
ah_esp_conn_schedule(struct sk_buff *skb,
struct ip_vs_protocol *pp,
ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
int *verdict, struct ip_vs_conn **cpp)
{
/*
Expand Down
Loading

0 comments on commit 51ef348

Please sign in to comment.