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

_______________________________________________
discuss mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-discuss

Reply via email to