[ovs-discuss] UDP Checksum Computation

Ranjith Kumar D Ranjith.Kumar at radisys.com
Thu Oct 5 07:28:53 UTC 2017


Hello All,

I have added below highlighted code to compute UDP checksum in OVS data path(actions.c), but UDP checksum is failing at wireshark.   I am using csum_tcpudp_magic function to calculate UDP checksum. Is anything wrong in the way I am suing  csum_tcpudp_magic function.

static int push_gtpv1(struct sk_buff *skb, struct sw_flow_key *key, const struct ovs_action_push_gtpv1 *gtpv1)
{
                // length in bytes comprising all the gtp tunnel related headers
                const size_t gtp_tun_len = ETH_HLEN + IPV4_HLEN_PLAIN + UDP_HLEN + GTPU_HLEN_PLAIN;
                struct iphdr *outer_iphdr;                           // tunnel IPv4 header
                struct udphdr *outer_udphdr;   // tunnel UDP header
                struct gtpv1hdr *gtphdr;                              // GTPv1 header
                __be16 inner_ip_totlen;                                               // in network byte order

                if (ip_hdr(skb)->version != 4)                       // encapsulate only IPv4 traffic
                {
                                return -EINVAL;
                }
                if (check_extract_gtp(skb, NULL) == 0)    // before encapsulating, check if the packet is already GTPv1 tunneled
                {
                                return -EINVAL;
                }

                /* we will need it later, as this IPv4 packet gets encapsulated */
                inner_ip_totlen = ip_hdr(skb)->tot_len;

                /* reserve a maximum amount of headroom for containing the GTP tunnel headers */
                if (skb_cow(skb, LL_MAX_HEADER + gtp_tun_len) < 0)
                                return -ENOMEM;

                /* Update the 'data' ptr in such a way that the old ethernet header gets perfectly overwrited,
                * zeroing out the space required by the gtp tunnel headers (including the "old" ethernet header).
                */
                memset(__skb_push(skb, gtp_tun_len - ETH_HLEN), 0, gtp_tun_len);

                /* update header offsets as the original packet has been expanded */
                skb_reset_mac_header(skb);
                skb_set_network_header(skb, ETH_HLEN);          // the new network header becomes the tunnel's ip header
                skb_set_transport_header(skb, skb_network_offset(skb) + IPV4_HLEN_PLAIN);  // the new transport header becomes the tunnel's udp header

                /* Get ptrs to all the gtp tunnel headers inside the expanded 'skb'. */
                outer_iphdr = ip_hdr(skb);
                outer_udphdr = udp_hdr(skb);
                gtphdr = GTPv1_HDR(skb);

                /* fill the tunnel's IP header */
                outer_iphdr->ihl = 5;                                       // 5 words (20 bytes) header
                outer_iphdr->version = 4;                             // IPv4
                outer_iphdr->tos = 0;
                outer_iphdr->tot_len = htons(IPV4_HLEN_PLAIN + UDP_HLEN + GTPU_HLEN_PLAIN + ntohs(inner_ip_totlen));
                outer_iphdr->id = 0;
                outer_iphdr->frag_off = 0;
                outer_iphdr->ttl = 255;                                  // maximum TTL
                outer_iphdr->protocol = IPPROTO_UDP;                                // follows UDP tunnel header
                outer_iphdr->saddr = htonl(gtpv1->ipv4.src);      // tunnel's src address
                outer_iphdr->daddr = htonl(gtpv1->ipv4.dst);     // tunnel's dst address

                /* fill the tunnel's UDP header */
                outer_udphdr->source = htons(GTPv1_PORT);
                outer_udphdr->dest = htons(GTPv1_PORT);
                outer_udphdr->len = htons(UDP_HLEN + GTPU_HLEN_PLAIN + ntohs(inner_ip_totlen));
                outer_udphdr->check = 0;
                outer_udphdr->check = csum_tcpudp_magic(ntohl(outer_iphdr->saddr),ntohl(outer_iphdr->daddr),ntohs(outer_udphdr->len),
                                                IPPROTO_UDP,csum_partial((unsigned char *)outer_udphdr,ntohs(outer_udphdr->len),0));
                if(outer_udphdr->check == 0)
               {
                        outer_udphdr->check = 0xffff;
                }

                /* fill the GTPv1 header */
                gtphdr->version = 1;                                                                       // GTPv1
                gtphdr->ptype = 1;                                                                                          // protocol type is GTP (0 for GTP')
                gtphdr->reserved = 0;
                gtphdr->ehf = 0;
                gtphdr->snf = 0;
                gtphdr->pnf = 0;
                gtphdr->type = GTP_MSG_TYPE_GPDU;                 // G-PDU msg type
                gtphdr->tot_len = inner_ip_totlen;                          // IPv4's 'tot_len' header field is already in network byte order
                gtphdr->teid = 0x0100008; /*htonl(gtpv1->teid);*/                          // Tunnel ID

                ip_send_check(ip_hdr(skb));                                                       // compute the tunnel's ip checksum

                /* update 'key' corresponding to this 'gtpv1' encapsulation */
                key->gtp_u.ipv4_dst = htonl(gtpv1->ipv4.dst);
                key->gtp_u.teid = htonl(gtpv1->teid);

                return 0;
}

Regards,
Ranjith

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openvswitch.org/pipermail/ovs-discuss/attachments/20171005/37e97742/attachment-0001.html>


More information about the discuss mailing list