Commit bcc58c4d authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs-next

Pull updates from Jesper Dangaard Brouer for IPVS mostly targeted
to improve IPv6 support (7 commits):

 ipvs: Trivial changes, use compressed IPv6 address in output
 ipvs: IPv6 extend ICMPv6 handling for future types
 ipvs: Use config macro IS_ENABLED()
 ipvs: Fix faulty IPv6 extension header handling in IPVS
 ipvs: Complete IPv6 fragment handling for IPVS
 ipvs: API change to avoid rescan of IPv6 exthdr
 ipvs: SIP fragment handling
parents 7fe0b14b 92eec78d
This diff is collapsed.
...@@ -28,12 +28,11 @@ if IP_VS ...@@ -28,12 +28,11 @@ if IP_VS
config IP_VS_IPV6 config IP_VS_IPV6
bool "IPv6 support for IPVS" bool "IPv6 support for IPVS"
depends on IPV6 = y || IP_VS = IPV6 depends on IPV6 = y || IP_VS = IPV6
select IP6_NF_IPTABLES
---help--- ---help---
Add IPv6 support to IPVS. This is incomplete and might be dangerous. Add IPv6 support to IPVS.
See http://www.mindbasket.com/ipvs for more information. Say Y if unsure.
Say N if unsure.
config IP_VS_DEBUG config IP_VS_DEBUG
bool "IP virtual server debugging" bool "IP virtual server debugging"
......
...@@ -308,13 +308,12 @@ struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p) ...@@ -308,13 +308,12 @@ struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
static int static int
ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb, ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb,
const struct ip_vs_iphdr *iph, const struct ip_vs_iphdr *iph,
unsigned int proto_off, int inverse, int inverse, struct ip_vs_conn_param *p)
struct ip_vs_conn_param *p)
{ {
__be16 _ports[2], *pptr; __be16 _ports[2], *pptr;
struct net *net = skb_net(skb); struct net *net = skb_net(skb);
pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports); pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph);
if (pptr == NULL) if (pptr == NULL)
return 1; return 1;
...@@ -329,12 +328,11 @@ ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb, ...@@ -329,12 +328,11 @@ ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb,
struct ip_vs_conn * struct ip_vs_conn *
ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb, ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
const struct ip_vs_iphdr *iph, const struct ip_vs_iphdr *iph, int inverse)
unsigned int proto_off, int inverse)
{ {
struct ip_vs_conn_param p; struct ip_vs_conn_param p;
if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p)) if (ip_vs_conn_fill_param_proto(af, skb, iph, inverse, &p))
return NULL; return NULL;
return ip_vs_conn_in_get(&p); return ip_vs_conn_in_get(&p);
...@@ -432,12 +430,11 @@ struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p) ...@@ -432,12 +430,11 @@ struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p)
struct ip_vs_conn * struct ip_vs_conn *
ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb, ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
const struct ip_vs_iphdr *iph, const struct ip_vs_iphdr *iph, int inverse)
unsigned int proto_off, int inverse)
{ {
struct ip_vs_conn_param p; struct ip_vs_conn_param p;
if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p)) if (ip_vs_conn_fill_param_proto(af, skb, iph, inverse, &p))
return NULL; return NULL;
return ip_vs_conn_out_get(&p); return ip_vs_conn_out_get(&p);
......
This diff is collapsed.
...@@ -215,7 +215,7 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) ...@@ -215,7 +215,7 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
struct ip_vs_dh_bucket *tbl; struct ip_vs_dh_bucket *tbl;
struct ip_vs_iphdr iph; struct ip_vs_iphdr iph;
ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); ip_vs_fill_iph_addr_only(svc->af, skb, &iph);
IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
......
...@@ -479,7 +479,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) ...@@ -479,7 +479,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
struct ip_vs_dest *dest = NULL; struct ip_vs_dest *dest = NULL;
struct ip_vs_lblc_entry *en; struct ip_vs_lblc_entry *en;
ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); ip_vs_fill_iph_addr_only(svc->af, skb, &iph);
IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
......
...@@ -649,7 +649,7 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) ...@@ -649,7 +649,7 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
struct ip_vs_dest *dest = NULL; struct ip_vs_dest *dest = NULL;
struct ip_vs_lblcr_entry *en; struct ip_vs_lblcr_entry *en;
ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); ip_vs_fill_iph_addr_only(svc->af, skb, &iph);
IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
......
...@@ -68,23 +68,31 @@ static int get_callid(const char *dptr, unsigned int dataoff, ...@@ -68,23 +68,31 @@ static int get_callid(const char *dptr, unsigned int dataoff,
static int static int
ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb) ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
{ {
struct sk_buff *reasm = skb_nfct_reasm(skb);
struct ip_vs_iphdr iph; struct ip_vs_iphdr iph;
unsigned int dataoff, datalen, matchoff, matchlen; unsigned int dataoff, datalen, matchoff, matchlen;
const char *dptr; const char *dptr;
int retc; int retc;
ip_vs_fill_iphdr(p->af, skb_network_header(skb), &iph); ip_vs_fill_iph_skb(p->af, skb, &iph);
/* Only useful with UDP */ /* Only useful with UDP */
if (iph.protocol != IPPROTO_UDP) if (iph.protocol != IPPROTO_UDP)
return -EINVAL; return -EINVAL;
/* todo: IPv6 fragments:
/* No Data ? */ * I think this only should be done for the first fragment. /HS
*/
if (reasm) {
skb = reasm;
dataoff = iph.thoff_reasm + sizeof(struct udphdr);
} else
dataoff = iph.len + sizeof(struct udphdr); dataoff = iph.len + sizeof(struct udphdr);
if (dataoff >= skb->len) if (dataoff >= skb->len)
return -EINVAL; return -EINVAL;
/* todo: Check if this will mess-up the reasm skb !!! /HS */
if ((retc=skb_linearize(skb)) < 0) retc = skb_linearize(skb);
if (retc < 0)
return retc; return retc;
dptr = skb->data + dataoff; dptr = skb->data + dataoff;
datalen = skb->len - dataoff; datalen = skb->len - dataoff;
......
...@@ -280,17 +280,17 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp, ...@@ -280,17 +280,17 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,
if (ih == NULL) if (ih == NULL)
sprintf(buf, "TRUNCATED"); sprintf(buf, "TRUNCATED");
else if (ih->nexthdr == IPPROTO_FRAGMENT) else if (ih->nexthdr == IPPROTO_FRAGMENT)
sprintf(buf, "%pI6->%pI6 frag", &ih->saddr, &ih->daddr); sprintf(buf, "%pI6c->%pI6c frag", &ih->saddr, &ih->daddr);
else { else {
__be16 _ports[2], *pptr; __be16 _ports[2], *pptr;
pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr), pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr),
sizeof(_ports), _ports); sizeof(_ports), _ports);
if (pptr == NULL) if (pptr == NULL)
sprintf(buf, "TRUNCATED %pI6->%pI6", sprintf(buf, "TRUNCATED %pI6c->%pI6c",
&ih->saddr, &ih->daddr); &ih->saddr, &ih->daddr);
else else
sprintf(buf, "%pI6:%u->%pI6:%u", sprintf(buf, "%pI6c:%u->%pI6c:%u",
&ih->saddr, ntohs(pptr[0]), &ih->saddr, ntohs(pptr[0]),
&ih->daddr, ntohs(pptr[1])); &ih->daddr, ntohs(pptr[1]));
} }
......
...@@ -57,7 +57,7 @@ ah_esp_conn_fill_param_proto(struct net *net, int af, ...@@ -57,7 +57,7 @@ ah_esp_conn_fill_param_proto(struct net *net, int af,
static struct ip_vs_conn * static struct ip_vs_conn *
ah_esp_conn_in_get(int af, const struct sk_buff *skb, ah_esp_conn_in_get(int af, const struct sk_buff *skb,
const struct ip_vs_iphdr *iph, unsigned int proto_off, const struct ip_vs_iphdr *iph,
int inverse) int inverse)
{ {
struct ip_vs_conn *cp; struct ip_vs_conn *cp;
...@@ -85,9 +85,7 @@ ah_esp_conn_in_get(int af, const struct sk_buff *skb, ...@@ -85,9 +85,7 @@ ah_esp_conn_in_get(int af, const struct sk_buff *skb,
static struct ip_vs_conn * static struct ip_vs_conn *
ah_esp_conn_out_get(int af, const struct sk_buff *skb, ah_esp_conn_out_get(int af, const struct sk_buff *skb,
const struct ip_vs_iphdr *iph, const struct ip_vs_iphdr *iph, int inverse)
unsigned int proto_off,
int inverse)
{ {
struct ip_vs_conn *cp; struct ip_vs_conn *cp;
struct ip_vs_conn_param p; struct ip_vs_conn_param p;
...@@ -110,7 +108,8 @@ ah_esp_conn_out_get(int af, const struct sk_buff *skb, ...@@ -110,7 +108,8 @@ ah_esp_conn_out_get(int af, const struct sk_buff *skb,
static int static int
ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
int *verdict, struct ip_vs_conn **cpp) int *verdict, struct ip_vs_conn **cpp,
struct ip_vs_iphdr *iph)
{ {
/* /*
* AH/ESP is only related traffic. Pass the packet to IP stack. * AH/ESP is only related traffic. Pass the packet to IP stack.
......
...@@ -10,28 +10,26 @@ ...@@ -10,28 +10,26 @@
static int static int
sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
int *verdict, struct ip_vs_conn **cpp) int *verdict, struct ip_vs_conn **cpp,
struct ip_vs_iphdr *iph)
{ {
struct net *net; struct net *net;
struct ip_vs_service *svc; struct ip_vs_service *svc;
sctp_chunkhdr_t _schunkh, *sch; sctp_chunkhdr_t _schunkh, *sch;
sctp_sctphdr_t *sh, _sctph; sctp_sctphdr_t *sh, _sctph;
struct ip_vs_iphdr iph;
ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); sh = skb_header_pointer(skb, iph->len, sizeof(_sctph), &_sctph);
sh = skb_header_pointer(skb, iph.len, sizeof(_sctph), &_sctph);
if (sh == NULL) if (sh == NULL)
return 0; return 0;
sch = skb_header_pointer(skb, iph.len + sizeof(sctp_sctphdr_t), sch = skb_header_pointer(skb, iph->len + sizeof(sctp_sctphdr_t),
sizeof(_schunkh), &_schunkh); sizeof(_schunkh), &_schunkh);
if (sch == NULL) if (sch == NULL)
return 0; return 0;
net = skb_net(skb); net = skb_net(skb);
if ((sch->type == SCTP_CID_INIT) && if ((sch->type == SCTP_CID_INIT) &&
(svc = ip_vs_service_get(net, af, skb->mark, iph.protocol, (svc = ip_vs_service_get(net, af, skb->mark, iph->protocol,
&iph.daddr, sh->dest))) { &iph->daddr, sh->dest))) {
int ignored; int ignored;
if (ip_vs_todrop(net_ipvs(net))) { if (ip_vs_todrop(net_ipvs(net))) {
...@@ -47,10 +45,10 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, ...@@ -47,10 +45,10 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
* Let the virtual server select a real server for the * Let the virtual server select a real server for the
* incoming connection, and create a connection entry. * incoming connection, and create a connection entry.
*/ */
*cpp = ip_vs_schedule(svc, skb, pd, &ignored); *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph);
if (!*cpp && ignored <= 0) { if (!*cpp && ignored <= 0) {
if (!ignored) if (!ignored)
*verdict = ip_vs_leave(svc, skb, pd); *verdict = ip_vs_leave(svc, skb, pd, iph);
else { else {
ip_vs_service_put(svc); ip_vs_service_put(svc);
*verdict = NF_DROP; *verdict = NF_DROP;
...@@ -64,20 +62,18 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, ...@@ -64,20 +62,18 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
} }
static int static int
sctp_snat_handler(struct sk_buff *skb, sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp) struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
{ {
sctp_sctphdr_t *sctph; sctp_sctphdr_t *sctph;
unsigned int sctphoff; unsigned int sctphoff = iph->len;
struct sk_buff *iter; struct sk_buff *iter;
__be32 crc32; __be32 crc32;
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6) if (cp->af == AF_INET6 && iph->fragoffs)
sctphoff = sizeof(struct ipv6hdr); return 1;
else
#endif #endif
sctphoff = ip_hdrlen(skb);
/* csum_check requires unshared skb */ /* csum_check requires unshared skb */
if (!skb_make_writable(skb, sctphoff + sizeof(*sctph))) if (!skb_make_writable(skb, sctphoff + sizeof(*sctph)))
...@@ -108,20 +104,18 @@ sctp_snat_handler(struct sk_buff *skb, ...@@ -108,20 +104,18 @@ sctp_snat_handler(struct sk_buff *skb,
} }
static int static int
sctp_dnat_handler(struct sk_buff *skb, sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp) struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
{ {
sctp_sctphdr_t *sctph; sctp_sctphdr_t *sctph;
unsigned int sctphoff; unsigned int sctphoff = iph->len;
struct sk_buff *iter; struct sk_buff *iter;
__be32 crc32; __be32 crc32;
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6) if (cp->af == AF_INET6 && iph->fragoffs)
sctphoff = sizeof(struct ipv6hdr); return 1;
else
#endif #endif
sctphoff = ip_hdrlen(skb);
/* csum_check requires unshared skb */ /* csum_check requires unshared skb */
if (!skb_make_writable(skb, sctphoff + sizeof(*sctph))) if (!skb_make_writable(skb, sctphoff + sizeof(*sctph)))
......
...@@ -33,16 +33,14 @@ ...@@ -33,16 +33,14 @@
static int static int
tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
int *verdict, struct ip_vs_conn **cpp) int *verdict, struct ip_vs_conn **cpp,
struct ip_vs_iphdr *iph)
{ {
struct net *net; struct net *net;
struct ip_vs_service *svc; struct ip_vs_service *svc;
struct tcphdr _tcph, *th; struct tcphdr _tcph, *th;
struct ip_vs_iphdr 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) {
*verdict = NF_DROP; *verdict = NF_DROP;
return 0; return 0;
...@@ -50,8 +48,8 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, ...@@ -50,8 +48,8 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
net = skb_net(skb); net = skb_net(skb);
/* No !th->ack check to allow scheduling on SYN+ACK for Active FTP */ /* No !th->ack check to allow scheduling on SYN+ACK for Active FTP */
if (th->syn && if (th->syn &&
(svc = ip_vs_service_get(net, af, skb->mark, iph.protocol, (svc = ip_vs_service_get(net, af, skb->mark, iph->protocol,
&iph.daddr, th->dest))) { &iph->daddr, th->dest))) {
int ignored; int ignored;
if (ip_vs_todrop(net_ipvs(net))) { if (ip_vs_todrop(net_ipvs(net))) {
...@@ -68,10 +66,10 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, ...@@ -68,10 +66,10 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
* Let the virtual server select a real server for the * Let the virtual server select a real server for the
* incoming connection, and create a connection entry. * incoming connection, and create a connection entry.
*/ */
*cpp = ip_vs_schedule(svc, skb, pd, &ignored); *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph);
if (!*cpp && ignored <= 0) { if (!*cpp && ignored <= 0) {
if (!ignored) if (!ignored)
*verdict = ip_vs_leave(svc, skb, pd); *verdict = ip_vs_leave(svc, skb, pd, iph);
else { else {
ip_vs_service_put(svc); ip_vs_service_put(svc);
*verdict = NF_DROP; *verdict = NF_DROP;
...@@ -128,20 +126,18 @@ tcp_partial_csum_update(int af, struct tcphdr *tcph, ...@@ -128,20 +126,18 @@ tcp_partial_csum_update(int af, struct tcphdr *tcph,
static int static int
tcp_snat_handler(struct sk_buff *skb, tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp) struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
{ {
struct tcphdr *tcph; struct tcphdr *tcph;
unsigned int tcphoff; unsigned int tcphoff = iph->len;
int oldlen; int oldlen;
int payload_csum = 0; int payload_csum = 0;
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6) if (cp->af == AF_INET6 && iph->fragoffs)
tcphoff = sizeof(struct ipv6hdr); return 1;
else
#endif #endif
tcphoff = ip_hdrlen(skb);
oldlen = skb->len - tcphoff; oldlen = skb->len - tcphoff;
/* csum_check requires unshared skb */ /* csum_check requires unshared skb */
...@@ -208,20 +204,18 @@ tcp_snat_handler(struct sk_buff *skb, ...@@ -208,20 +204,18 @@ tcp_snat_handler(struct sk_buff *skb,
static int static int
tcp_dnat_handler(struct sk_buff *skb, tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp) struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
{ {
struct tcphdr *tcph; struct tcphdr *tcph;
unsigned int tcphoff; unsigned int tcphoff = iph->len;
int oldlen; int oldlen;
int payload_csum = 0; int payload_csum = 0;
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6) if (cp->af == AF_INET6 && iph->fragoffs)
tcphoff = sizeof(struct ipv6hdr); return 1;
else
#endif #endif
tcphoff = ip_hdrlen(skb);
oldlen = skb->len - tcphoff; oldlen = skb->len - tcphoff;
/* csum_check requires unshared skb */ /* csum_check requires unshared skb */
......
...@@ -30,23 +30,22 @@ ...@@ -30,23 +30,22 @@
static int static int
udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
int *verdict, struct ip_vs_conn **cpp) int *verdict, struct ip_vs_conn **cpp,
struct ip_vs_iphdr *iph)
{ {
struct net *net; struct net *net;
struct ip_vs_service *svc; struct ip_vs_service *svc;
struct udphdr _udph, *uh; struct udphdr _udph, *uh;
struct ip_vs_iphdr iph;
ip_vs_fill_iphdr(af, skb_network_header(skb), &iph); /* IPv6 fragments, only first fragment will hit this */
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) {
*verdict = NF_DROP; *verdict = NF_DROP;
return 0; return 0;
} }
net = skb_net(skb); net = skb_net(skb);
svc = ip_vs_service_get(net, af, skb->mark, iph.protocol, svc = ip_vs_service_get(net, af, skb->mark, iph->protocol,
&iph.daddr, uh->dest); &iph->daddr, uh->dest);
if (svc) { if (svc) {
int ignored; int ignored;
...@@ -64,10 +63,10 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, ...@@ -64,10 +63,10 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
* Let the virtual server select a real server for the * Let the virtual server select a real server for the
* incoming connection, and create a connection entry. * incoming connection, and create a connection entry.
*/ */
*cpp = ip_vs_schedule(svc, skb, pd, &ignored); *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph);
if (!*cpp && ignored <= 0) { if (!*cpp && ignored <= 0) {
if (!ignored) if (!ignored)
*verdict = ip_vs_leave(svc, skb, pd); *verdict = ip_vs_leave(svc, skb, pd, iph);
else { else {
ip_vs_service_put(svc); ip_vs_service_put(svc);
*verdict = NF_DROP; *verdict = NF_DROP;
...@@ -125,20 +124,18 @@ udp_partial_csum_update(int af, struct udphdr *uhdr, ...@@ -125,20 +124,18 @@ udp_partial_csum_update(int af, struct udphdr *uhdr,
static int static int
udp_snat_handler(struct sk_buff *skb, udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp) struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
{ {
struct udphdr *udph; struct udphdr *udph;
unsigned int udphoff; unsigned int udphoff = iph->len;
int oldlen; int oldlen;
int payload_csum = 0; int payload_csum = 0;
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6) if (cp->af == AF_INET6 && iph->fragoffs)
udphoff = sizeof(struct ipv6hdr); return 1;
else
#endif #endif
udphoff = ip_hdrlen(skb);
oldlen = skb->len - udphoff; oldlen = skb->len - udphoff;
/* csum_check requires unshared skb */ /* csum_check requires unshared skb */
...@@ -210,20 +207,18 @@ udp_snat_handler(struct sk_buff *skb, ...@@ -210,20 +207,18 @@ udp_snat_handler(struct sk_buff *skb,
static int static int
udp_dnat_handler(struct sk_buff *skb, udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_protocol *pp, struct ip_vs_conn *cp) struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
{ {
struct udphdr *udph; struct udphdr *udph;
unsigned int udphoff; unsigned int udphoff = iph->len;
int oldlen; int oldlen;
int payload_csum = 0; int payload_csum = 0;
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6) if (cp->af == AF_INET6 && iph->fragoffs)
udphoff = sizeof(struct ipv6hdr); return 1;
else
#endif #endif
udphoff = ip_hdrlen(skb);
oldlen = skb->len - udphoff; oldlen = skb->len - udphoff;
/* csum_check requires unshared skb */ /* csum_check requires unshared skb */
......
...@@ -159,7 +159,7 @@ void ip_vs_scheduler_err(struct ip_vs_service *svc, const char *msg) ...@@ -159,7 +159,7 @@ void ip_vs_scheduler_err(struct ip_vs_service *svc, const char *msg)
svc->fwmark, msg); svc->fwmark, msg);
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
} else if (svc->af == AF_INET6) { } else if (svc->af == AF_INET6) {
IP_VS_ERR_RL("%s: %s [%pI6]:%d - %s\n", IP_VS_ERR_RL("%s: %s [%pI6c]:%d - %s\n",
svc->scheduler->name, svc->scheduler->name,
ip_vs_proto_name(svc->protocol), ip_vs_proto_name(svc->protocol),
&svc->addr.in6, ntohs(svc->port), msg); &svc->addr.in6, ntohs(svc->port), msg);
......
...@@ -228,7 +228,7 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) ...@@ -228,7 +228,7 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
struct ip_vs_sh_bucket *tbl; struct ip_vs_sh_bucket *tbl;
struct ip_vs_iphdr iph; struct ip_vs_iphdr iph;
ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); ip_vs_fill_iph_addr_only(svc->af, skb, &iph);
IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n"); IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n");
......
...@@ -335,7 +335,7 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, ...@@ -335,7 +335,7 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
local = __ip_vs_is_local_route6(rt); local = __ip_vs_is_local_route6(rt);
if (!((local ? IP_VS_RT_MODE_LOCAL : IP_VS_RT_MODE_NON_LOCAL) & if (!((local ? IP_VS_RT_MODE_LOCAL : IP_VS_RT_MODE_NON_LOCAL) &
rt_mode)) { rt_mode)) {
IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6\n", IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6c\n",
local ? "local":"non-local", daddr); local ? "local":"non-local", daddr);
dst_release(&rt->dst); dst_release(&rt->dst);
return NULL; return NULL;
...@@ -343,8 +343,8 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, ...@@ -343,8 +343,8 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
if (local && !(rt_mode & IP_VS_RT_MODE_RDR) && if (local && !(rt_mode & IP_VS_RT_MODE_RDR) &&
!((ort = (struct rt6_info *) skb_dst(skb)) && !((ort = (struct rt6_info *) skb_dst(skb)) &&
__ip_vs_is_local_route6(ort))) { __ip_vs_is_local_route6(ort))) {
IP_VS_DBG_RL("Redirect from non-local address %pI6 to local " IP_VS_DBG_RL("Redirect from non-local address %pI6c to local "
"requires NAT method, dest: %pI6\n", "requires NAT method, dest: %pI6c\n",
&ipv6_hdr(skb)->daddr, daddr); &ipv6_hdr(skb)->daddr, daddr);
dst_release(&rt->dst); dst_release(&rt->dst);
return NULL; return NULL;
...@@ -352,8 +352,8 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, ...@@ -352,8 +352,8 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
if (unlikely(!local && (!skb->dev || skb->dev->flags & IFF_LOOPBACK) && if (unlikely(!local && (!skb->dev || skb->dev->flags & IFF_LOOPBACK) &&
ipv6_addr_type(&ipv6_hdr(skb)->saddr) & ipv6_addr_type(&ipv6_hdr(skb)->saddr) &
IPV6_ADDR_LOOPBACK)) { IPV6_ADDR_LOOPBACK)) {
IP_VS_DBG_RL("Stopping traffic from loopback address %pI6 " IP_VS_DBG_RL("Stopping traffic from loopback address %pI6c "
"to non-local address, dest: %pI6\n", "to non-local address, dest: %pI6c\n",
&ipv6_hdr(skb)->saddr, daddr); &ipv6_hdr(skb)->saddr, daddr);
dst_release(&rt->dst); dst_release(&rt->dst);
return NULL; return NULL;
...@@ -424,7 +424,7 @@ do { \ ...@@ -424,7 +424,7 @@ do { \
*/ */
int int
ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp) struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{ {
/* we do not touch skb and do not need pskb ptr */ /* we do not touch skb and do not need pskb ptr */
IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1); IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1);
...@@ -438,7 +438,7 @@ ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -438,7 +438,7 @@ ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
*/ */
int int
ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp) struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{ {
struct rtable *rt; /* Route to the other host */ struct rtable *rt; /* Route to the other host */
struct iphdr *iph = ip_hdr(skb); struct iphdr *iph = ip_hdr(skb);
...@@ -493,16 +493,16 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -493,16 +493,16 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
int int
ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp) struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph)
{ {
struct rt6_info *rt; /* Route to the other host */ struct rt6_info *rt; /* Route to the other host */
struct ipv6hdr *iph = ipv6_hdr(skb);
int mtu; int mtu;
EnterFunction(10); EnterFunction(10);
if (!(rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph->daddr, NULL, 0, rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph->daddr.in6, NULL, 0,
IP_VS_RT_MODE_NON_LOCAL))) IP_VS_RT_MODE_NON_LOCAL);
if (!rt)
goto tx_error_icmp; goto tx_error_icmp;
/* MTU checking */ /* MTU checking */
...@@ -513,6 +513,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -513,6 +513,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dev = net->loopback_dev; skb->dev = net->loopback_dev;
} }
/* only send ICMP too big on first fragment */
if (!iph->fragoffs)
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
dst_release(&rt->dst); dst_release(&rt->dst);
IP_VS_DBG_RL("%s(): frag needed\n", __func__); IP_VS_DBG_RL("%s(): frag needed\n", __func__);
...@@ -556,7 +558,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -556,7 +558,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
*/ */
int int
ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp) struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{ {
struct rtable *rt; /* Route to the other host */ struct rtable *rt; /* Route to the other host */
int mtu; int mtu;
...@@ -626,7 +628,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -626,7 +628,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
goto tx_error_put; goto tx_error_put;
/* mangle the packet */ /* mangle the packet */
if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp, ipvsh))
goto tx_error_put; goto tx_error_put;
ip_hdr(skb)->daddr = cp->daddr.ip; ip_hdr(skb)->daddr = cp->daddr.ip;
ip_send_check(ip_hdr(skb)); ip_send_check(ip_hdr(skb));
...@@ -674,7 +676,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -674,7 +676,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
int int
ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp) struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph)
{ {
struct rt6_info *rt; /* Route to the other host */ struct rt6_info *rt; /* Route to the other host */
int mtu; int mtu;
...@@ -683,10 +685,9 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -683,10 +685,9 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
EnterFunction(10); EnterFunction(10);
/* check if it is a connection of no-client-port */ /* check if it is a connection of no-client-port */
if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) { if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT && !iph->fragoffs)) {
__be16 _pt, *p; __be16 _pt, *p;
p = skb_header_pointer(skb, sizeof(struct ipv6hdr), p = skb_header_pointer(skb, iph->len, sizeof(_pt), &_pt);
sizeof(_pt), &_pt);
if (p == NULL) if (p == NULL)
goto tx_error; goto tx_error;
ip_vs_conn_fill_cport(cp, *p); ip_vs_conn_fill_cport(cp, *p);
...@@ -734,6 +735,8 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -734,6 +735,8 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dev = net->loopback_dev; skb->dev = net->loopback_dev;
} }
/* only send ICMP too big on first fragment */
if (!iph->fragoffs)
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0, IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0,
"ip_vs_nat_xmit_v6(): frag needed for"); "ip_vs_nat_xmit_v6(): frag needed for");
...@@ -748,7 +751,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -748,7 +751,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
goto tx_error_put; goto tx_error_put;
/* mangle the packet */ /* mangle the packet */
if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp, iph))
goto tx_error; goto tx_error;
ipv6_hdr(skb)->daddr = cp->daddr.in6; ipv6_hdr(skb)->daddr = cp->daddr.in6;
...@@ -809,7 +812,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -809,7 +812,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
*/ */
int int
ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp) struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{ {
struct netns_ipvs *ipvs = net_ipvs(skb_net(skb)); struct netns_ipvs *ipvs = net_ipvs(skb_net(skb));
struct rtable *rt; /* Route to the other host */ struct rtable *rt; /* Route to the other host */
...@@ -929,7 +932,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -929,7 +932,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
int int
ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp) struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{ {
struct rt6_info *rt; /* Route to the other host */ struct rt6_info *rt; /* Route to the other host */
struct in6_addr saddr; /* Source for tunnel */ struct in6_addr saddr; /* Source for tunnel */
...@@ -969,6 +972,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -969,6 +972,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dev = net->loopback_dev; skb->dev = net->loopback_dev;
} }
/* only send ICMP too big on first fragment */
if (!ipvsh->fragoffs)
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP_VS_DBG_RL("%s(): frag needed\n", __func__); IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error_put; goto tx_error_put;
...@@ -1050,7 +1055,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -1050,7 +1055,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
*/ */
int int
ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp) struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{ {
struct rtable *rt; /* Route to the other host */ struct rtable *rt; /* Route to the other host */
struct iphdr *iph = ip_hdr(skb); struct iphdr *iph = ip_hdr(skb);
...@@ -1111,7 +1116,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -1111,7 +1116,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
int int
ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp) struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph)
{ {
struct rt6_info *rt; /* Route to the other host */ struct rt6_info *rt; /* Route to the other host */
int mtu; int mtu;
...@@ -1135,6 +1140,8 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -1135,6 +1140,8 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dev = net->loopback_dev; skb->dev = net->loopback_dev;
} }
/* only send ICMP too big on first fragment */
if (!iph->fragoffs)
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
dst_release(&rt->dst); dst_release(&rt->dst);
IP_VS_DBG_RL("%s(): frag needed\n", __func__); IP_VS_DBG_RL("%s(): frag needed\n", __func__);
...@@ -1179,7 +1186,8 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -1179,7 +1186,8 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
*/ */
int int
ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp, int offset, unsigned int hooknum) struct ip_vs_protocol *pp, int offset, unsigned int hooknum,
struct ip_vs_iphdr *iph)
{ {
struct rtable *rt; /* Route to the other host */ struct rtable *rt; /* Route to the other host */
int mtu; int mtu;
...@@ -1194,7 +1202,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -1194,7 +1202,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
translate address/port back */ translate address/port back */
if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
if (cp->packet_xmit) if (cp->packet_xmit)
rc = cp->packet_xmit(skb, cp, pp); rc = cp->packet_xmit(skb, cp, pp, iph);
else else
rc = NF_ACCEPT; rc = NF_ACCEPT;
/* do not touch skb anymore */ /* do not touch skb anymore */
...@@ -1300,7 +1308,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -1300,7 +1308,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
#ifdef CONFIG_IP_VS_IPV6 #ifdef CONFIG_IP_VS_IPV6
int int
ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp, int offset, unsigned int hooknum) struct ip_vs_protocol *pp, int offset, unsigned int hooknum,
struct ip_vs_iphdr *iph)
{ {
struct rt6_info *rt; /* Route to the other host */ struct rt6_info *rt; /* Route to the other host */
int mtu; int mtu;
...@@ -1315,7 +1324,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -1315,7 +1324,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
translate address/port back */ translate address/port back */
if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
if (cp->packet_xmit) if (cp->packet_xmit)
rc = cp->packet_xmit(skb, cp, pp); rc = cp->packet_xmit(skb, cp, pp, iph);
else else
rc = NF_ACCEPT; rc = NF_ACCEPT;
/* do not touch skb anymore */ /* do not touch skb anymore */
...@@ -1371,6 +1380,8 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -1371,6 +1380,8 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dev = net->loopback_dev; skb->dev = net->loopback_dev;
} }
/* only send ICMP too big on first fragment */
if (!iph->fragoffs)
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP_VS_DBG_RL("%s(): frag needed\n", __func__); IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error_put; goto tx_error_put;
......
...@@ -67,7 +67,7 @@ ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -67,7 +67,7 @@ ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par)
goto out; goto out;
} }
ip_vs_fill_iphdr(family, skb_network_header(skb), &iph); ip_vs_fill_iph_skb(family, skb, &iph);
if (data->bitmask & XT_IPVS_PROTO) if (data->bitmask & XT_IPVS_PROTO)
if ((iph.protocol == data->l4proto) ^ if ((iph.protocol == data->l4proto) ^
...@@ -85,7 +85,7 @@ ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -85,7 +85,7 @@ ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par)
/* /*
* Check if the packet belongs to an existing entry * Check if the packet belongs to an existing entry
*/ */
cp = pp->conn_out_get(family, skb, &iph, iph.len, 1 /* inverse */); cp = pp->conn_out_get(family, skb, &iph, 1 /* inverse */);
if (unlikely(cp == NULL)) { if (unlikely(cp == NULL)) {
match = false; match = false;
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment