Skip to content

Commit

Permalink
Merge "Identify IPv6 diagnostic packets"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and opencontrail-ci-admin committed Oct 12, 2016
2 parents 1d376ff + 010fc0d commit 3b137fe
Showing 1 changed file with 102 additions and 62 deletions.
164 changes: 102 additions & 62 deletions linux/vrouter_mod.c
Expand Up @@ -943,9 +943,19 @@ lh_csum_verify_fast(struct vr_ip *iph, void *transport_hdr, unsigned
char proto, unsigned int size)
{
__wsum csum;
struct ipv6hdr *ip6;

if (vr_ip_is_ip4(iph)) {
csum = csum_tcpudp_nofold(iph->ip_saddr, iph->ip_daddr,
size, proto, 0);
} else if (vr_ip_is_ip6(iph)) {
ip6 = (struct ipv6hdr *)iph;
csum = ~csum_unfold(csum_ipv6_magic(&ip6->saddr, &ip6->daddr,
size, proto, 0));
} else {
return -1;
}

csum = csum_tcpudp_nofold(iph->ip_saddr, iph->ip_daddr,
size, proto, 0);
if (csum_fold(csum_partial(transport_hdr, size, csum))) {
return -1;
}
Expand All @@ -960,9 +970,25 @@ lh_csum_verify_fast(struct vr_ip *iph, void *transport_hdr, unsigned
static int
lh_csum_verify(struct sk_buff *skb, struct vr_ip *iph)
{
skb->csum = csum_tcpudp_nofold(iph->ip_saddr, iph->ip_daddr,
ntohs(iph->ip_len) - (iph->ip_hl * 4),
iph->ip_proto, 0);
uint8_t proto;
uint32_t size;
struct ipv6hdr *ip6;

if (vr_ip_is_ip4(iph)) {
proto = iph->ip_proto;
size = ntohs(iph->ip_len) - (iph->ip_hl * 4);
skb->csum = csum_tcpudp_nofold(iph->ip_saddr, iph->ip_daddr, size,
proto, 0);
} else if (vr_ip_is_ip6(iph)) {
ip6 = (struct ipv6hdr *)iph;
proto = ip6->nexthdr;
size = ntohs(ip6->payload_len);
skb->csum = ~csum_unfold(csum_ipv6_magic(&ip6->saddr, &ip6->daddr,
size, proto, 0));
} else {
return -1;
}

if (__skb_checksum_complete(skb)) {
return -1;
}
Expand Down Expand Up @@ -1057,20 +1083,20 @@ lh_pull_inner_headers_fast_udp(struct vr_packet *pkt, int
int, unsigned short *), int *ret,
int *encap_type)
{
struct sk_buff *skb = vp_os_packet(pkt);
unsigned short pkt_headlen;
uint8_t proto;
int pkt_type = 0, helper_ret, parse_ret;
unsigned int frag_size, hdr_len, transport_size;
unsigned int pull_len, skb_pull_len, th_pull_len = 0, hlen = 0;
unsigned short th_csum = 0, pkt_headlen;

void *th = NULL;
unsigned char *va = NULL;
skb_frag_t *frag;
unsigned int frag_size, pull_len, hdr_len, skb_pull_len, tcp_size;
unsigned int th_pull_len = 0, hlen = 0;
struct sk_buff *skb = vp_os_packet(pkt);
struct vr_ip *iph = NULL;
struct vr_ip6 *ip6h = NULL;
struct vr_udp *udph;
int pkt_type = 0;
struct vr_ip *outer_iph = NULL;
unsigned short th_csum = 0;
void *th = NULL;
int helper_ret, parse_ret;
skb_frag_t *frag;

pkt_headlen = pkt_head_len(pkt);
hdr_len = sizeof(struct udphdr);
Expand Down Expand Up @@ -1161,33 +1187,37 @@ lh_pull_inner_headers_fast_udp(struct vr_packet *pkt, int
*/
skb_push(skb, skb_pull_len);
}
} else {
} else if (iph) {
/*
* We require checksum to be validated for TCP for GRO purpose
* and in case of UDP for DIAG purpose. Rest all packets can
* have the checksum validated in VM
*/
if (!ip6h && iph && (!vr_ip_fragment(iph))) {
if (((iph->ip_proto == VR_IP_PROTO_UDP) && th_csum == VR_DIAG_CSUM)
|| (iph->ip_proto == VR_IP_PROTO_TCP)) {
if (ip6h) {
proto = ip6h->ip6_nxt;
transport_size = ntohs(ip6h->ip6_plen);
} else {
proto = iph->ip_proto;
transport_size = ntohs(iph->ip_len) - hlen;
}

if ((!vr_ip_fragment(iph))) {
if (((proto == VR_IP_PROTO_UDP) && th_csum == VR_DIAG_CSUM) ||
(proto == VR_IP_PROTO_TCP)) {
lh_handle_checksum_complete_skb(skb);

if (skb_shinfo(skb)->nr_frags == 1) {
tcp_size = ntohs(iph->ip_len) - hlen;
if (lh_csum_verify_fast(iph, th, iph->ip_proto, tcp_size)) {
if (lh_csum_verify_fast(iph, th,
proto, transport_size)) {
if (th_csum == VR_DIAG_CSUM) {
vr_pkt_set_diag(pkt);
} else {
goto cksum_err;
}
}
} else {
/*
* Pull to the start of the transport header
*/
/* Pull to the start of the transport header */
skb_pull_len = (pkt_data(pkt) - skb->data) +
pkt_headlen + th_pull_len;
pkt_headlen + th_pull_len;

skb_pull(skb, skb_pull_len);
if (lh_csum_verify(skb, iph)) {
Expand Down Expand Up @@ -1261,18 +1291,19 @@ lh_pull_inner_headers_fast_gre(struct vr_packet *pkt, int
(*tunnel_type_cb)(unsigned int, unsigned int, unsigned short *),
int *ret, int *encap_type)
{
struct sk_buff *skb = vp_os_packet(pkt);
unsigned short pkt_headlen, *gre_hdr = NULL, gre_proto,
hdr_len = VR_GRE_BASIC_HDR_LEN;
uint8_t proto;
int pkt_type = 0, helper_ret, parse_ret;
unsigned short pkt_headlen, *gre_hdr = NULL, gre_proto;
unsigned short hdr_len = VR_GRE_BASIC_HDR_LEN, th_csum = 0;
unsigned int frag_size, hlen = 0, transport_size;
unsigned int pull_len, skb_pull_len, th_pull_len;

void *th = NULL;
unsigned char *va = NULL;
skb_frag_t *frag;
unsigned int frag_size, pull_len, hlen = 0, tcp_size, skb_pull_len,
th_pull_len = 0;
unsigned short th_csum = 0;
struct sk_buff *skb = vp_os_packet(pkt);
struct vr_ip *iph = NULL;
struct vr_ip6 *ip6h = NULL;
void *th = NULL;
int pkt_type = 0, helper_ret, parse_ret;
skb_frag_t *frag;

pkt_headlen = pkt_head_len(pkt);
if (pkt_headlen) {
Expand Down Expand Up @@ -1410,16 +1441,21 @@ lh_pull_inner_headers_fast_gre(struct vr_packet *pkt, int
* of the outer packet and this covers the inner packet too.
*/

if (!skb_csum_unnecessary(skb)) {
if (!ip6h && iph && !vr_ip_fragment(iph)) {
if ((th_csum == VR_DIAG_CSUM && (iph->ip_proto == VR_IP_PROTO_UDP))
|| (iph->ip_proto == VR_IP_PROTO_TCP)) {
if (!skb_csum_unnecessary(skb) && iph) {
if (ip6h) {
proto = ip6h->ip6_nxt;
transport_size = ntohs(ip6h->ip6_plen);
} else {
proto = iph->ip_proto;
transport_size = ntohs(iph->ip_len) - hlen;
}

if (!vr_ip_fragment(iph)) {
if ((th_csum == VR_DIAG_CSUM && (proto == VR_IP_PROTO_UDP)) ||
(proto == VR_IP_PROTO_TCP)) {
lh_handle_checksum_complete_skb(skb);

if (skb_shinfo(skb)->nr_frags == 1) {
tcp_size = ntohs(iph->ip_len) - hlen;
if (lh_csum_verify_fast(iph, th, iph->ip_proto, tcp_size)) {
if (lh_csum_verify_fast(iph, th, proto, transport_size)) {
if (th_csum == VR_DIAG_CSUM) {
vr_pkt_set_diag(pkt);
} else {
Expand Down Expand Up @@ -1559,20 +1595,20 @@ lh_pull_inner_headers(struct vr_packet *pkt,
unsigned short *))
{
int pull_len, hlen, hoff, ret = 0;
uint32_t label, control_data;
unsigned short hdr_len, vrouter_overlay_len, eth_proto, l4_proto;
unsigned short udph_cksum = 0, th_csum = 0;
unsigned short icmp_pl_ip_proto;
unsigned int toff, skb_pull_len;
bool thdr_valid = false, mpls_pkt = true, outer_cksum_validate;

struct sk_buff *skb = vp_os_packet(pkt);
struct vr_ip *iph = NULL, *icmp_pl_iph = NULL;
struct vr_ip *iph = NULL, *icmp_pl_iph = NULL, *outer_iph = NULL;
struct vr_ip6 *ip6h = NULL, *icmp_pl_ip6h = NULL;
unsigned short icmp_pl_ip_proto;
struct tcphdr *tcph = NULL;
struct vr_icmp *icmph = NULL;
unsigned int toff, skb_pull_len;
bool thdr_valid = false, mpls_pkt = true, outer_cksum_validate;
uint32_t label, control_data;
struct vr_eth *eth = NULL;
unsigned short hdr_len, vrouter_overlay_len, eth_proto, l4_proto, udph_cksum = 0;
unsigned short th_csum = 0;
struct udphdr *udph;
struct vr_ip *outer_iph = NULL;

*reason = VP_DROP_PULL;
pull_len = 0;
Expand Down Expand Up @@ -1725,11 +1761,11 @@ lh_pull_inner_headers(struct vr_packet *pkt,
l4_proto = ip6h->ip6_nxt;
hlen = sizeof(struct vr_ip6);
thdr_valid = true;
} else if (iph) {
} else {
l4_proto = iph->ip_proto;
thdr_valid = vr_ip_transport_header_valid(iph);
hlen = iph->ip_hl * 4;
if (thdr_valid) {
hlen = iph->ip_hl * 4;
pull_len += (hlen - sizeof(struct vr_ip));
}
}
Expand All @@ -1753,8 +1789,7 @@ lh_pull_inner_headers(struct vr_packet *pkt,
*/
iph = (struct vr_ip *) (skb->head + hoff);
if (ip6h)
ip6h = (struct vr_ip6 *) iph;

ip6h = (struct vr_ip6 *)iph;

/*
* Account for TCP options, if present
Expand Down Expand Up @@ -1903,7 +1938,7 @@ lh_pull_inner_headers(struct vr_packet *pkt,
}

ip6h = (struct vr_ip6 *) (skb->head + hoff);
iph = (struct vr_ip*) ip6h;
iph = (struct vr_ip*)ip6h;
}
}
lh_reset_skb_fields(pkt);
Expand Down Expand Up @@ -1943,15 +1978,19 @@ lh_pull_inner_headers(struct vr_packet *pkt,
*/
skb_push(skb, skb_pull_len);
if (tcph && vr_to_vm_mss_adj) {
lh_adjust_tcp_mss(tcph, skb, vrouter_overlay_len, sizeof(struct vr_ip));
lh_adjust_tcp_mss(tcph, skb, vrouter_overlay_len, hlen);
}
} else {
if (!ip6h && !vr_ip_fragment(iph)) {
if (((th_csum == VR_DIAG_CSUM) && iph->ip_proto == VR_IP_PROTO_UDP)
|| (iph->ip_proto == VR_IP_PROTO_TCP)) {
lh_handle_checksum_complete_skb(skb);
toff = (char *)((char *)iph + (iph->ip_hl * 4)) - (char *) skb->data;
if (ip6h) {
toff = (char *)((char *)ip6h + sizeof(*ip6h)) - (char *)skb->data;
} else {
toff = (char *)((char *)iph + (iph->ip_hl * 4)) - (char *)skb->data;
}

if (thdr_valid) {
if (((th_csum == VR_DIAG_CSUM) && l4_proto == VR_IP_PROTO_UDP)
|| (l4_proto == VR_IP_PROTO_TCP)) {
lh_handle_checksum_complete_skb(skb);
skb_pull(skb, toff);
if (lh_csum_verify(skb, iph)) {
if (th_csum == VR_DIAG_CSUM) {
Expand All @@ -1965,8 +2004,9 @@ lh_pull_inner_headers(struct vr_packet *pkt,

skb_push(skb, toff);
}
if ((iph->ip_proto == VR_IP_PROTO_TCP) && vr_to_vm_mss_adj) {
lh_adjust_tcp_mss(tcph, skb, vrouter_overlay_len, sizeof(struct vr_ip));

if (tcph && vr_to_vm_mss_adj) {
lh_adjust_tcp_mss(tcph, skb, vrouter_overlay_len, hlen);
}
}
}
Expand Down

0 comments on commit 3b137fe

Please sign in to comment.