LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dp-core - vr_packet.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 46 374 12.3 %
Date: 2026-11-09 02:10:49 Functions: 2 9 22.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * vr_packet.c -- packet handling helpers
       3             :  *
       4             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       5             :  * Copyright Contributors to the OpenSDN project
       6             :  */
       7             : #include <vr_os.h>
       8             : #include <vr_packet.h>
       9             : 
      10             : struct vr_packet *
      11           0 : pkt_copy(struct vr_packet *pkt, unsigned short off, unsigned short len)
      12             : {
      13             :     struct vr_packet *pkt_c;
      14             :     unsigned short head_space;
      15             : 
      16             :     /*
      17             :      * one eth header for agent, and one more for packets from
      18             :      * tun interfaces
      19             :      */
      20           0 :     head_space = (2 * sizeof(struct vr_eth)) + sizeof(struct agent_hdr);
      21           0 :     pkt_c = vr_palloc(head_space + len);
      22           0 :     if (!pkt_c)
      23           0 :         return pkt_c;
      24             : 
      25           0 :     pkt_c->vp_data += head_space;
      26           0 :     pkt_c->vp_tail += head_space;
      27           0 :     if (vr_pcopy(pkt_data(pkt_c), pkt, off, len) < 0) {
      28           0 :         PKT_LOG(VP_DROP_MISC, pkt, 0, VR_PACKET_C, __LINE__);
      29           0 :         vr_pfree(pkt_c, VP_DROP_MISC);
      30           0 :         return NULL;
      31             :     }
      32           0 :     pkt_pull_tail(pkt_c, len);
      33             : 
      34           0 :     pkt_c->vp_if = pkt->vp_if;
      35           0 :     pkt_c->vp_flags = pkt->vp_flags;
      36           0 :     pkt_c->vp_cpu = pkt->vp_cpu;
      37           0 :     pkt_c->vp_network_h = 0;
      38             : 
      39           0 :     return pkt_c;
      40             : }
      41             : 
      42             : struct vr_packet *
      43           2 : pkt_cow(struct vr_packet *pkt, unsigned short head_room)
      44             : {
      45             :     struct vr_packet *clone_pkt;
      46             : 
      47             :     /* Clone the packet */
      48           2 :     clone_pkt = vr_pclone(pkt);
      49           2 :     if (!clone_pkt) {
      50           0 :         return NULL;
      51             :     }
      52             : 
      53             :     /* Increase the head space by the head_room */
      54           2 :     if (vr_pcow(&clone_pkt, head_room)) {
      55           0 :         PKT_LOG(VP_DROP_PCOW_FAIL, pkt, 0, VR_PACKET_C, __LINE__);
      56           0 :         vr_pfree(clone_pkt, VP_DROP_PCOW_FAIL);
      57           0 :         return NULL;
      58             :     }
      59             : 
      60             :     /* Copy the ttl from old packet */
      61           2 :     clone_pkt->vp_ttl = pkt->vp_ttl;
      62             : 
      63           2 :     return clone_pkt;
      64             : }
      65             : 
      66             : bool
      67           0 : vr_ip_proto_pull(struct vr_ip *iph)
      68             : {
      69           0 :     unsigned char proto = iph->ip_proto;
      70             : 
      71           0 :     if ((proto == VR_IP_PROTO_TCP) || (proto == VR_IP_PROTO_UDP) ||
      72           0 :         (proto == VR_IP_PROTO_ICMP) || (proto == VR_IP_PROTO_SCTP)) {
      73           0 :         return true;
      74             :     }
      75             : 
      76           0 :     return false;
      77             : }
      78             : 
      79             : bool
      80           0 : vr_ip6_proto_pull(struct vr_ip6 *ip6h)
      81             : {
      82           0 :     unsigned char proto = ip6h->ip6_nxt;
      83             : 
      84           0 :    if ((proto == VR_IP_PROTO_TCP) || (proto == VR_IP_PROTO_UDP) ||
      85           0 :        (proto == VR_IP_PROTO_ICMP6) || (proto == VR_IP_PROTO_SCTP) ||
      86             :        (proto == VR_IP6_PROTO_FRAG)) {
      87           0 :         return true;
      88             :     }
      89             : 
      90           0 :     return false;
      91             : }
      92             : 
      93             : /**
      94             :  * vr_ip_transport_parse - parse IP packet to reach the L4 header
      95             :  */
      96             : int
      97           0 : vr_ip_transport_parse(struct vr_ip *iph, struct vr_ip6 *ip6h,
      98             :                       void **thp, unsigned int frag_size,
      99             :                       void (do_tcp_mss_adj)(struct tcphdr *, unsigned short,
     100             :                                           unsigned char),
     101             :                       unsigned int *hlenp,
     102             :                       unsigned short *th_csump,
     103             :                       unsigned int *tcph_pull_lenp,
     104             :                       unsigned int *pull_lenp)
     105             : {
     106             :     unsigned char *thdr;
     107             :     unsigned short ip_proto;
     108           0 :     bool thdr_valid = false, icmp_pl_frag_hdr = false;
     109           0 :     unsigned int hlen = 0, tcph_pull_len = 0;
     110           0 :     unsigned int pull_len = *pull_lenp;
     111           0 :     struct vr_tcp *tcph = NULL;
     112           0 :     unsigned short th_csum = 0;
     113           0 :     struct vr_icmp *icmph = NULL;
     114           0 :     struct vr_ip *icmp_pl_iph = NULL;
     115           0 :     struct vr_ip6 *icmp_pl_ip6h = NULL;
     116             :     struct vr_ip6_frag *v6_frag;
     117             : 
     118             : 
     119             :     /* Note: iph is set for both ipv4 and ipv6 cases */
     120           0 :     if (iph) {
     121           0 :         if (vr_ip_is_ip6(iph)) {
     122           0 :             if (ip6h) {
     123           0 :                 ip_proto = ip6h->ip6_nxt;
     124           0 :                 hlen = sizeof(struct vr_ip6);
     125           0 :                 if (ip_proto == VR_IP6_PROTO_FRAG) {
     126           0 :                     pull_len += sizeof(struct vr_ip6_frag);
     127           0 :                     if (frag_size < pull_len) {
     128           0 :                         return PKT_RET_SLOW_PATH;
     129             :                     }
     130             : 
     131           0 :                     v6_frag = (struct vr_ip6_frag *)((char *)ip6h + hlen);
     132           0 :                     ip_proto = v6_frag->ip6_frag_nxt;
     133           0 :                     hlen += sizeof(struct vr_ip6_frag);
     134             :                 }
     135           0 :                 thdr_valid = vr_ip6_transport_header_valid(ip6h);
     136             :             } else {
     137           0 :                 return PKT_RET_UNHANDLED;
     138             :             }
     139           0 :         } else if (vr_ip_is_ip4(iph)) {
     140           0 :             ip_proto = iph->ip_proto;
     141             :             /*
     142             :              * Account for IP options
     143             :              */
     144           0 :             thdr_valid = vr_ip_transport_header_valid(iph);
     145           0 :             if (thdr_valid) {
     146           0 :                 hlen = iph->ip_hl * 4;
     147           0 :                 pull_len += (hlen - sizeof(struct vr_ip));
     148             :             }
     149             :         } else {
     150           0 :             return PKT_RET_UNHANDLED;
     151             :         }
     152             : 
     153           0 :         if (thdr_valid) {
     154           0 :             tcph_pull_len = pull_len;
     155           0 :             if (thp)
     156           0 :                 *thp = (char *)iph + hlen;
     157             : 
     158           0 :             if (ip_proto == VR_IP_PROTO_TCP) {
     159           0 :                 pull_len += sizeof(struct vr_tcp);
     160           0 :             } else if (ip_proto == VR_IP_PROTO_UDP) {
     161           0 :                 pull_len += sizeof(struct vr_udp);
     162           0 :             } else if ((ip_proto == VR_IP_PROTO_ICMP) ||
     163             :                        (ip_proto == VR_IP_PROTO_ICMP6)) {
     164           0 :                 pull_len += sizeof(struct vr_icmp);
     165           0 :             } else if (ip_proto == VR_IP_PROTO_SCTP) {
     166           0 :                pull_len += sizeof(struct vr_sctp);
     167             :             }
     168             : 
     169           0 :             if (frag_size < pull_len) {
     170           0 :                 return PKT_RET_SLOW_PATH;
     171             :             }
     172             : 
     173             : 
     174           0 :             if (ip_proto == VR_IP_PROTO_TCP) {
     175             :                 /*
     176             :                  * Account for TCP options
     177             :                  */
     178           0 :                 tcph = (struct vr_tcp *)((char *)iph + hlen);
     179             : 
     180             :                 /*
     181             :                  * If SYN, do TCP MSS adjust using passed callback, or send it
     182             :                  * to the slow path.
     183             :                  */
     184           0 :                 if ((ntohs(tcph->tcp_offset_r_flags) & VR_TCP_FLAG_SYN) &&
     185             :                         vr_to_vm_mss_adj) {
     186           0 :                     if (do_tcp_mss_adj) {
     187             :                         /* Kernel will never get here, it will return slow path */
     188           0 :                         do_tcp_mss_adj((struct tcphdr *)tcph,
     189             :                                             VROUTER_L2_OVERLAY_LEN, hlen);
     190             :                     } else {
     191           0 :                         return PKT_RET_SLOW_PATH;
     192             :                     }
     193             :                 }
     194             : 
     195           0 :                 if ((VR_TCP_OFFSET(tcph->tcp_offset_r_flags) * 4) >
     196             :                         (sizeof(struct vr_tcp))) {
     197           0 :                     pull_len += ((VR_TCP_OFFSET(tcph->tcp_offset_r_flags) * 4) -
     198             :                                     (sizeof(struct vr_tcp)));
     199             : 
     200           0 :                     if (frag_size < pull_len) {
     201           0 :                         return PKT_RET_SLOW_PATH;
     202             :                     }
     203             :                 }
     204           0 :                 th_csum = tcph->tcp_csum;
     205           0 :             } else if (ip_proto == VR_IP_PROTO_ICMP) {
     206           0 :                 icmph = (struct vr_icmp *)((unsigned char *)iph + hlen);
     207           0 :                 th_csum = icmph->icmp_csum;
     208           0 :                 if (vr_icmp_error(icmph)) {
     209           0 :                     pull_len += sizeof(struct vr_ip);
     210           0 :                     if (frag_size < pull_len)
     211           0 :                         return PKT_RET_SLOW_PATH;
     212           0 :                     icmp_pl_iph = (struct vr_ip *)(icmph + 1);
     213           0 :                     pull_len += (icmp_pl_iph->ip_hl * 4) - sizeof(struct vr_ip);
     214           0 :                     if (frag_size < pull_len)
     215           0 :                         return PKT_RET_SLOW_PATH;
     216           0 :                     if (vr_ip_proto_pull(icmp_pl_iph)) {
     217           0 :                         if (icmp_pl_iph->ip_proto == VR_IP_PROTO_TCP)
     218           0 :                             pull_len += sizeof(struct vr_tcp);
     219           0 :                         else if (icmp_pl_iph->ip_proto == VR_IP_PROTO_UDP)
     220           0 :                             pull_len += sizeof(struct vr_udp);
     221           0 :                         else if (icmp_pl_iph->ip_proto == VR_IP_PROTO_SCTP)
     222           0 :                             pull_len += sizeof(struct vr_sctp);
     223             :                         else
     224           0 :                             pull_len += sizeof(struct vr_icmp);
     225             : 
     226           0 :                         if (frag_size < pull_len)
     227           0 :                             return PKT_RET_SLOW_PATH;
     228             : 
     229           0 :                         if (icmp_pl_iph->ip_proto == VR_IP_PROTO_TCP) {
     230           0 :                             th_csum = ((struct vr_tcp *)
     231             :                                         ((unsigned char *)icmp_pl_iph +
     232           0 :                                         icmp_pl_iph->ip_hl * 4))->tcp_csum;
     233           0 :                         } else if (icmp_pl_iph->ip_proto == VR_IP_PROTO_UDP) {
     234           0 :                             th_csum = ((struct vr_udp *)
     235             :                                         ((unsigned char *)icmp_pl_iph +
     236           0 :                                         icmp_pl_iph->ip_hl * 4))->udp_csum;
     237           0 :                         } else if (icmp_pl_iph->ip_proto == VR_IP_PROTO_ICMP) {
     238           0 :                             th_csum = ((struct vr_icmp *)
     239             :                                         ((unsigned char *)icmp_pl_iph +
     240           0 :                                         icmp_pl_iph->ip_hl * 4))->icmp_csum;
     241             :                         }
     242             :                     }
     243             :                 }
     244           0 :             } else if (iph->ip_proto == VR_IP_PROTO_UDP) {
     245           0 :                 th_csum = ((struct vr_udp *)
     246             :                             ((unsigned char *)iph + hlen))->udp_csum;
     247           0 :             } else if ((ip_proto == VR_IP_PROTO_ICMP6) && ip6h) {
     248           0 :                 icmph = (struct vr_icmp *)((unsigned char *)ip6h + hlen);
     249           0 :                 if (icmph->icmp_type == VR_ICMP6_TYPE_NEIGH_SOL) {
     250             :                     /*
     251             :                      * We do not know if neighbour option of length
     252             :                      * VR_ETHER_ALEN is not at all there or not in this
     253             :                      * frag. So we will calculate the length to
     254             :                      * be inclusive of both Target address and neighbour
     255             :                      * option. If option is not preset, slow path would
     256             :                      * take care of it
     257             :                      */
     258           0 :                     pull_len += sizeof(struct vr_neighbor_option) +
     259             :                                 VR_IP6_ADDRESS_LEN + VR_ETHER_ALEN;
     260           0 :                 } else if (icmph->icmp_type == VR_ICMP6_TYPE_ROUTER_SOL) {
     261           0 :                     pull_len += 8;
     262           0 :                 } else if (vr_icmp6_error(icmph)) {
     263           0 :                     pull_len += sizeof(struct vr_ip6);
     264           0 :                     if (frag_size < pull_len)
     265           0 :                         return PKT_RET_SLOW_PATH;
     266           0 :                     icmp_pl_ip6h = (struct vr_ip6 *)(icmph + 1);
     267           0 :                     ip_proto = icmp_pl_ip6h->ip6_nxt;
     268           0 :                     if (vr_ip6_proto_pull(icmp_pl_ip6h)) {
     269           0 :                         if (icmp_pl_ip6h->ip6_nxt == VR_IP_PROTO_TCP)
     270           0 :                             pull_len += sizeof(struct vr_tcp);
     271           0 :                         else if (icmp_pl_ip6h->ip6_nxt == VR_IP_PROTO_UDP)
     272           0 :                             pull_len += sizeof(struct vr_udp);
     273           0 :                         else if (icmp_pl_ip6h->ip6_nxt == VR_IP_PROTO_SCTP)
     274           0 :                             pull_len += sizeof(struct vr_sctp);
     275           0 :                         else if (icmp_pl_ip6h->ip6_nxt == VR_IP6_PROTO_FRAG) {
     276           0 :                             pull_len += sizeof(struct vr_ip6_frag);
     277           0 :                             icmp_pl_frag_hdr = true;
     278             :                         } else
     279           0 :                             pull_len += sizeof(struct vr_icmp);
     280             : 
     281           0 :                         if (frag_size < pull_len)
     282           0 :                             return PKT_RET_SLOW_PATH;
     283             : 
     284           0 :                         if (icmp_pl_frag_hdr) {
     285           0 :                             v6_frag = (struct vr_ip6_frag *)
     286             :                                 ((unsigned char *)icmp_pl_ip6h +
     287             :                                  sizeof(struct vr_ip6));
     288           0 :                             ip_proto = v6_frag->ip6_frag_nxt;
     289           0 :                             thdr = (unsigned char *)v6_frag +
     290             :                                         sizeof(struct vr_ip6_frag);
     291             :                         } else {
     292           0 :                             thdr = (unsigned char *)icmp_pl_ip6h +
     293             :                                 sizeof(struct vr_ip6);
     294             :                         }
     295             : 
     296           0 :                         if (ip_proto == VR_IP_PROTO_TCP) {
     297           0 :                             th_csum = ((struct vr_tcp *)thdr)->tcp_csum;
     298           0 :                             if (icmp_pl_frag_hdr)
     299           0 :                                 pull_len += sizeof(struct vr_tcp);
     300           0 :                         } else if (ip_proto == VR_IP_PROTO_UDP) {
     301           0 :                             th_csum = ((struct vr_udp *)thdr)->udp_csum;
     302           0 :                             if (icmp_pl_frag_hdr)
     303           0 :                                 pull_len += sizeof(struct vr_udp);
     304           0 :                         } else if (ip_proto == VR_IP_PROTO_ICMP6) {
     305           0 :                             th_csum = ((struct vr_icmp *)thdr)->icmp_csum;
     306           0 :                             if (icmp_pl_frag_hdr)
     307           0 :                                 pull_len += sizeof(struct vr_icmp);
     308           0 :                         } else if (ip_proto == VR_IP_PROTO_SCTP) {
     309           0 :                             if (icmp_pl_frag_hdr)
     310           0 :                                 pull_len += sizeof(struct vr_sctp);
     311             :                         }
     312             :                     }
     313             :                 }
     314             : 
     315           0 :                 if (frag_size < pull_len)
     316           0 :                     return PKT_RET_SLOW_PATH;
     317             :             }
     318             :         }
     319             :     }
     320             : 
     321           0 :     if (hlenp)
     322           0 :         *hlenp = hlen;
     323           0 :     if (th_csump)
     324           0 :         *th_csump = th_csum;
     325           0 :     if (tcph_pull_lenp)
     326           0 :         *tcph_pull_lenp = tcph_pull_len;
     327           0 :     *pull_lenp = pull_len;
     328             : 
     329           0 :     return 0;
     330             : }
     331             : 
     332             : /**
     333             :  * vr_inner_pkt_parse - parse inner packet transported in MPLS-o-UDP, MPLS-o-GRE
     334             :  * or VXLAN tunnel.
     335             :  */
     336             : 
     337             : int
     338           0 : vr_inner_pkt_parse(unsigned char *va, int (*tunnel_type_cb)(unsigned int,
     339             :                 unsigned int, unsigned short *), int *encap_type,
     340             :                 int *pkt_typep, unsigned int *pull_lenp,
     341             :                 unsigned int frag_size, struct vr_ip **iphp,
     342             :                 struct vr_ip6 **ip6hp, unsigned short gre_udp_encap,
     343             :                 unsigned char ip_proto)
     344             : {
     345             :     unsigned short eth_proto;
     346           0 :     unsigned int pull_len = *pull_lenp;
     347             :     unsigned int label, control_data;
     348           0 :     int pkt_type = 0;
     349           0 :     struct vr_ip6 *ip6h = NULL;
     350           0 :     struct vr_ip *iph = NULL;
     351           0 :     struct vr_eth *eth = NULL;
     352           0 :     unsigned int mpls_label_len = VR_MPLS_HDR_LEN;
     353             : 
     354           0 :     if ((ip_proto == VR_IP_PROTO_GRE && gre_udp_encap == VR_GRE_PROTO_MPLS_NO) ||
     355           0 :         (ip_proto == VR_IP_PROTO_UDP && vr_mpls_udp_port(ntohs(gre_udp_encap)))) {
     356             : 
     357           0 :         *encap_type = PKT_ENCAP_MPLS;
     358             :         /* Take into consideration, the MPLS header and 4 bytes of
     359             :          * control information that might exist for L2 packet */
     360           0 :         if (frag_size < (pull_len + VR_MPLS_HDR_LEN +
     361             :                                 VR_L2_CTRL_DATA_LEN)) {
     362           0 :             return PKT_RET_SLOW_PATH;
     363             :         }
     364             : 
     365           0 :         label = ntohl(*(uint32_t *)(va + pull_len));
     366           0 :         if (!(label & VR_MPLS_LABEL_STACK_BIT_MASK)
     367           0 :               && ((label >> VR_MPLS_LABEL_SHIFT) == VR_MPLS_LABEL_MASK)) {
     368             :             // ignore outer label
     369           0 :             label = ntohl(*(uint32_t *)(va + pull_len + VR_MPLS_HDR_LEN));
     370           0 :             mpls_label_len = 2*VR_MPLS_HDR_LEN;
     371             :         }
     372             : 
     373           0 :         control_data = *(uint32_t *)(va + pull_len + mpls_label_len);
     374             : 
     375             :         /* Identify whether the packet is L2 or not using the label and
     376             :          * control data */
     377           0 :         pkt_type = tunnel_type_cb(label, control_data, NULL);
     378           0 :         if (pkt_type <= 0)
     379           0 :             return PKT_RET_UNHANDLED;
     380             : 
     381           0 :         if (pkt_type == PKT_MPLS_TUNNEL_L3) {
     382             :             /* L3 packet */
     383           0 :             iph = (struct vr_ip *) (va + pull_len + mpls_label_len);
     384           0 :             if (vr_ip_is_ip6(iph)) {
     385           0 :                 ip6h = (struct vr_ip6 *)iph;
     386           0 :                 pull_len += mpls_label_len + sizeof(struct vr_ip6);
     387           0 :             } else if (vr_ip_is_ip4(iph)) {
     388           0 :                 pull_len += mpls_label_len + sizeof(struct vr_ip);
     389             :             } else {
     390           0 :                 return PKT_RET_UNHANDLED;
     391             :             }
     392           0 :         } else if (pkt_type == PKT_MPLS_TUNNEL_L2_MCAST) {
     393             :             /* L2 Multicast packet with control information and
     394             :              * Vxlan header. Vxlan header contains IP + UDP + Vxlan */
     395           0 :             eth = (struct vr_eth *)(va + pull_len + mpls_label_len +
     396           0 :                     VR_L2_CTRL_DATA_LEN + VR_VXLAN_HDR_LEN);
     397           0 :             pull_len += mpls_label_len + VR_L2_CTRL_DATA_LEN +
     398             :                             VR_VXLAN_HDR_LEN + sizeof(struct vr_eth);
     399           0 :         } else if (pkt_type == PKT_MPLS_TUNNEL_L2_CONTROL_DATA) {
     400             :             /* L2 packet with control information */
     401           0 :             eth = (struct vr_eth *)(va + pull_len + mpls_label_len +
     402             :                     VR_L2_CTRL_DATA_LEN);
     403           0 :             pull_len += mpls_label_len + VR_L2_CTRL_DATA_LEN +
     404             :                                             sizeof(struct vr_eth);
     405           0 :         } else if (pkt_type == PKT_MPLS_TUNNEL_L2_UCAST) {
     406             :             /* L2 packet with no control information */
     407           0 :             eth = (struct vr_eth *)(va + pull_len + mpls_label_len);
     408           0 :             pull_len += mpls_label_len + sizeof(struct vr_eth);
     409             :         } else {
     410           0 :             return PKT_RET_UNHANDLED;
     411             :         }
     412             : 
     413           0 :         if (frag_size < pull_len)
     414           0 :             return PKT_RET_SLOW_PATH;
     415             : 
     416           0 :     } else if (ip_proto == VR_IP_PROTO_UDP &&
     417           0 :                 ntohs(gre_udp_encap) == VR_VXLAN_UDP_DST_PORT) {
     418           0 :         *encap_type = PKT_ENCAP_VXLAN;
     419           0 :         pull_len += sizeof(struct vr_vxlan);
     420             : 
     421             :         /* Take into consideration, the VXLAN header ethernet header */
     422           0 :         if (frag_size < pull_len + VR_ETHER_HLEN)
     423           0 :             return PKT_RET_SLOW_PATH;
     424             : 
     425           0 :         eth = (struct vr_eth *)(va + pull_len);
     426             : 
     427           0 :         pull_len += VR_ETHER_HLEN;
     428             :     } else {
     429           0 :         return PKT_RET_UNHANDLED;
     430             :     }
     431             : 
     432           0 :     if (eth) {
     433             : 
     434           0 :         eth_proto = eth->eth_proto;
     435           0 :         if (ntohs(eth_proto) == VR_ETH_PROTO_PBB) {
     436           0 :             pull_len += sizeof(struct vr_pbb_itag);
     437           0 :             if (frag_size < pull_len)
     438           0 :                 return PKT_RET_SLOW_PATH;
     439             : 
     440           0 :             eth = (struct vr_eth *)(va + pull_len);
     441           0 :             pull_len += VR_ETHER_HLEN;
     442           0 :             if (frag_size < pull_len)
     443           0 :                 return PKT_RET_SLOW_PATH;
     444           0 :             eth_proto = eth->eth_proto;
     445             :         }
     446             : 
     447           0 :         while (ntohs(eth_proto) == VR_ETH_PROTO_VLAN) {
     448           0 :             eth_proto = ((struct vr_vlan_hdr *)(va + pull_len))->vlan_proto;
     449           0 :             pull_len += sizeof(struct vr_vlan_hdr);
     450           0 :             if (frag_size < pull_len)
     451           0 :                 return PKT_RET_SLOW_PATH;
     452             :         }
     453             : 
     454           0 :         if (ntohs(eth_proto) == VR_ETH_PROTO_IP) {
     455           0 :             iph = (struct vr_ip *)(va + pull_len);
     456           0 :             pull_len += sizeof(struct vr_ip);
     457           0 :             if (frag_size < pull_len)
     458           0 :                 return PKT_RET_SLOW_PATH;
     459           0 :         } else if (ntohs(eth_proto) == VR_ETH_PROTO_IP6) {
     460           0 :             ip6h = (struct vr_ip6 *)(va + pull_len);
     461           0 :             iph = (struct vr_ip *)ip6h;
     462           0 :             pull_len += sizeof(struct vr_ip6);
     463           0 :             if (frag_size < pull_len)
     464           0 :                 return PKT_RET_SLOW_PATH;
     465           0 :         } else if (ntohs(eth_proto) == VR_ETH_PROTO_ARP) {
     466           0 :             pull_len += sizeof(struct vr_arp);
     467           0 :             if (frag_size < pull_len)
     468           0 :                 return PKT_RET_SLOW_PATH;
     469             :         }
     470             :     }
     471             : 
     472           0 :     *pull_lenp = pull_len;
     473           0 :     *iphp = iph;
     474           0 :     *ip6hp = ip6h;
     475           0 :     if (pkt_typep)
     476           0 :         *pkt_typep = pkt_type;
     477             : 
     478           0 :     return 0;
     479             : }
     480             : 
     481             : bool
     482           0 : __vr_adjust_tcp_mss(struct vr_tcp *tcph, uint16_t len_overhead, uint16_t eth_mtu, uint16_t *old_mss, uint16_t *new_mss)
     483             : {
     484           0 :     int opt_off = sizeof(struct vr_tcp);
     485           0 :     uint8_t *opt_ptr = (uint8_t *) tcph;
     486             :     uint16_t pkt_mss, max_mss;
     487             : 
     488           0 :     if ((tcph == NULL) || (!tcph->tcp_flag_syn)) {
     489           0 :         return false;
     490             :     }
     491             : 
     492           0 :     while (opt_off < (tcph->tcp_doff*4)) {
     493           0 :         switch (opt_ptr[opt_off]) {
     494           0 :             case VR_TCP_OPT_EOL:
     495           0 :                 return false;
     496             : 
     497           0 :             case VR_TCP_OPT_NOP:
     498           0 :                 opt_off++;
     499           0 :                 continue;
     500             : 
     501           0 :             case VR_TCP_OPT_MSS:
     502           0 :                 if ((opt_off + VR_TCP_OLEN_MSS) > (tcph->tcp_doff*4)) {
     503           0 :                     return false;
     504             :                 }
     505             : 
     506           0 :                 if (opt_ptr[opt_off+1] != VR_TCP_OLEN_MSS) {
     507           0 :                     return false;
     508             :                 }
     509             : 
     510           0 :                 pkt_mss = (opt_ptr[opt_off+2] << 8) | opt_ptr[opt_off+3];
     511           0 :                 max_mss = eth_mtu - (len_overhead + sizeof(struct vr_tcp));
     512             : 
     513           0 :                 if (pkt_mss > max_mss) {
     514           0 :                     *old_mss = pkt_mss;
     515           0 :                     *new_mss = max_mss;
     516           0 :                     opt_ptr[opt_off+2] = (max_mss & 0xff00) >> 8;
     517           0 :                     opt_ptr[opt_off+3] = max_mss & 0xff;
     518             : 
     519           0 :                     return true;
     520             :                 }
     521             : 
     522           0 :                 return false;
     523             : 
     524           0 :             default:
     525             : 
     526           0 :                 if ((opt_off + 1) == (tcph->tcp_doff*4)) {
     527           0 :                     return false;
     528             :                 }
     529             : 
     530           0 :                 if (opt_ptr[opt_off+1]) {
     531           0 :                     opt_off += opt_ptr[opt_off+1];
     532             :                 } else {
     533           0 :                     opt_off++;
     534             :                 }
     535             : 
     536           0 :                 continue;
     537             :         }
     538             :     }
     539             : 
     540           0 :     return false;
     541             : }
     542             : 
     543             : 
     544             : /*
     545             :  * vr_adjust_tcp_mss - adjust the TCP MSS in the given packet based on
     546             :  * vrouter physical interface MTU. If MSS was changed return true and sets
     547             :  * old_mss and new_mss args, returns false otherwise.
     548             :  */
     549             : bool
     550           0 : vr_adjust_tcp_mss(struct vr_tcp *tcph, uint16_t len_overhead, uint16_t *old_mss, uint16_t *new_mss)
     551             : {
     552           0 :     uint16_t eth_mtu = VR_INVALID_MTU;
     553           0 :     struct vrouter *router = vrouter_get(0);
     554             :     int i;
     555             : 
     556           0 :     if (router == NULL) {
     557           0 :         return false;
     558             :     }
     559             : 
     560           0 :     for (i = 0; i < VR_MAX_PHY_INF; i++) {
     561           0 :         if (router->vr_eth_if[i]) {
     562           0 :             uint16_t mtu = vif_get_mtu(router->vr_eth_if[i]);
     563           0 :             if (mtu < eth_mtu)
     564           0 :                 eth_mtu = mtu;
     565             :         }
     566             :     }
     567           0 :     if (eth_mtu == VR_INVALID_MTU)
     568           0 :         return false;
     569             : 
     570           0 :     return __vr_adjust_tcp_mss(tcph, len_overhead, eth_mtu, old_mss, new_mss);
     571             : }
     572             : 
     573             : /*
     574             :  * calculate a 5 tuple hash for ipv4 and ipv6 packets
     575             :  * and smac, dmac and proto based hash for other packets
     576             :  */
     577           7 : unsigned int vr_get_pkt_hash(struct vr_packet * pkt)
     578             : {
     579             :     struct vr_tcp *tcp;
     580             :     struct vr_udp *udp;
     581             :     unsigned short sport, dport;
     582           7 :     int proto, flag = 0;
     583           7 :     struct vr_eth *eth = NULL;
     584           7 :     struct vr_ip *ip = NULL;
     585           7 :     struct vr_ip6 *ip6 = NULL;
     586           7 :     char *hdr = NULL;
     587             :     char key[38];
     588             :     uint32_t hash;
     589             : 
     590           7 :     if (!pkt)
     591           0 :         return 0;
     592             : 
     593           7 :     if (pkt->vp_type == VP_TYPE_IP6) {
     594           1 :         ip6 = (struct vr_ip6 *) pkt_network_header(pkt);
     595           1 :         hdr = (char *) ip6;
     596           1 :         if (vr_ip6_fragment(ip6)) {
     597           0 :             flag = 1;
     598           0 :             sport = dport = 0;
     599           0 :             proto = 0;
     600             :         } else
     601           1 :             proto = ip6->ip6_nxt;
     602           6 :     } else if(pkt->vp_type == VP_TYPE_IP) {
     603           6 :         ip = (struct vr_ip *) pkt_network_header(pkt);
     604           6 :         hdr = (char *) ip;
     605           6 :         if (vr_ip_fragment(ip)) {
     606           0 :             flag = 1;
     607           0 :             sport = dport = 0;
     608             :         }
     609           6 :         proto = ip->ip_proto;
     610             :     } else {
     611           0 :         eth = (struct vr_eth *) pkt_data(pkt);
     612           0 :         proto = -1;
     613             :     }
     614             : 
     615           7 :     if (flag == 0) {
     616           7 :         if (proto == VR_IP_PROTO_TCP) {
     617           0 :             if (pkt->vp_type == VP_TYPE_IP6)
     618           0 :                 tcp = (struct vr_tcp *) (hdr + sizeof(*ip6));
     619             :             else
     620           0 :                 tcp = (struct vr_tcp *) (hdr + ip->ip_hl*4);
     621           0 :             sport = ntohs(tcp->tcp_sport);
     622           0 :             dport = ntohs(tcp->tcp_dport);
     623           7 :         } else if (proto == VR_IP_PROTO_UDP) {
     624           6 :             if (pkt->vp_type == VP_TYPE_IP6)
     625           0 :                 udp = (struct vr_udp *) (hdr + sizeof(*ip6));
     626             :             else
     627           6 :                 udp = (struct vr_udp *) (hdr + ip->ip_hl*4);
     628           6 :             sport = ntohs(udp->udp_sport);
     629           6 :             dport = ntohs(udp->udp_dport);
     630             :         } else {
     631           1 :             sport = dport = 0;
     632             :         }
     633             :     }
     634             : 
     635           7 :     if (pkt->vp_type == VP_TYPE_IP6) {
     636           1 :         memcpy(key, &ip6->ip6_src, 16);
     637           1 :         memcpy(key+16, &ip6->ip6_dst, 16);
     638           1 :         memcpy(key+32, &proto, 1);
     639           1 :         memcpy(key+33, &sport, 2);
     640           1 :         memcpy(key+35, &dport, 2);
     641           1 :         hash = vr_hash(key, 37, 0);
     642           6 :     } else if (pkt->vp_type == VP_TYPE_IP) {
     643           6 :         memcpy(key, &ip->ip_saddr, 4);
     644           6 :         memcpy(key+4, &ip->ip_daddr, 4);
     645           6 :         memcpy(key+8, &proto, 1);
     646           6 :         memcpy(key+9, &sport, 2);
     647           6 :         memcpy(key+11, &dport, 2);
     648           6 :         hash = vr_hash(key, 13, 0);
     649             :     } else {
     650           0 :         memcpy(key, &eth->eth_smac, 6);
     651           0 :         memcpy(key+6, &eth->eth_dmac, 6);
     652           0 :         memcpy(key+12, &eth->eth_proto, 1);
     653           0 :         hash = vr_hash(key, 13, 0);
     654             :     }
     655             : 
     656           7 :     return hash;
     657             : }

Generated by: LCOV version 1.14