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

Generated by: LCOV version 1.14