[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