Merge "[l2l3 stack] implements new arp state machine & arp buffering"
[samplevnf.git] / VNFs / vFW / pipeline / pipeline_vfw_be.c
1 /*
2 // Copyright (c) 2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 /**
18  * @file
19  * Pipeline VFW BE Implementation.
20  *
21  * Implementation of Pipeline VFW Back End (BE).
22  * Responsible for packet processing.
23  *
24  */
25
26 #define EN_SWP_ACL 1
27 #define EN_SWP_ARP 1
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <stddef.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 #include <rte_common.h>
37 #include <rte_malloc.h>
38 #include <rte_ether.h>
39 #include <rte_ethdev.h>
40 #include <rte_ip.h>
41 #include <rte_udp.h>
42 #include <rte_icmp.h>
43 #include <rte_byteorder.h>
44
45 #include <rte_table_lpm.h>
46 #include <rte_table_hash.h>
47 #include <rte_table_array.h>
48 #include <rte_table_acl.h>
49 #include <rte_table_stub.h>
50 #include <rte_timer.h>
51 #include <rte_cycles.h>
52 #include <rte_pipeline.h>
53 #include <rte_spinlock.h>
54 #include <rte_prefetch.h>
55 #include "pipeline_actions_common.h"
56 #include "hash_func.h"
57 #include "pipeline_vfw.h"
58 #include "pipeline_vfw_be.h"
59 #include "rte_cnxn_tracking.h"
60 #include "pipeline_arpicmp_be.h"
61 #include "vnf_common.h"
62 #include "vnf_define.h"
63
64 #include "lib_arp.h"
65 #include "lib_icmpv6.h"
66 #include "pipeline_common_fe.h"
67
68 uint32_t timer_lcore;
69
70 uint8_t firewall_flag = 1;
71 uint8_t VFW_DEBUG;
72 uint8_t cnxn_tracking_is_active = 1;
73 /**
74  * A structure defining the VFW pipeline input port per thread data.
75  */
76 struct vfw_ports_in_args {
77        struct pipeline *pipe;
78        struct rte_ct_cnxn_tracker *cnxn_tracker;
79 } __rte_cache_aligned;
80 /**
81  * A structure defining the VFW pipeline per thread data.
82  */
83 struct pipeline_vfw {
84        struct pipeline pipe;
85        pipeline_msg_req_handler custom_handlers[PIPELINE_VFW_MSG_REQS];
86
87        struct rte_ct_cnxn_tracker *cnxn_tracker;
88        struct rte_VFW_counter_block *counters;
89        struct rte_mbuf *pkt_buffer[PKT_BUFFER_SIZE];
90        struct lib_acl *plib_acl;
91        /* timestamp retrieved during in-port computations */
92        uint32_t n_flows;
93        uint8_t pipeline_num;
94        uint8_t traffic_type;
95        uint8_t links_map[PIPELINE_MAX_PORT_IN];
96        uint8_t outport_id[PIPELINE_MAX_PORT_IN];
97        /* Local ARP & ND Tables */
98        struct lib_arp_route_table_entry
99               local_lib_arp_route_table[MAX_ARP_RT_ENTRY];
100        uint8_t local_lib_arp_route_ent_cnt;
101        struct lib_nd_route_table_entry
102               local_lib_nd_route_table[MAX_ND_RT_ENTRY];
103        uint8_t local_lib_nd_route_ent_cnt;
104
105 } __rte_cache_aligned;
106 /**
107  * A structure defining the mbuf meta data for VFW.
108  */
109 struct mbuf_tcp_meta_data {
110 /* output port stored for RTE_PIPELINE_ACTION_PORT_META */
111        uint32_t output_port;
112        struct rte_mbuf *next;       /* next pointer for chained buffers */
113 } __rte_cache_aligned;
114
115 #define DONT_CARE_TCP_PACKET 0
116 #define IS_NOT_TCP_PACKET 0
117 #define IS_TCP_PACKET 1
118
119 #define META_DATA_OFFSET 128
120
121 #define RTE_PKTMBUF_HEADROOM 128       /* where is this defined ? */
122 #define ETHERNET_START (META_DATA_OFFSET + RTE_PKTMBUF_HEADROOM)
123 #define ETH_HDR_SIZE 14
124 #define PROTOCOL_START (IP_START + 9)
125
126 #define TCP_START (IP_START + 20)
127 #define RTE_LB_PORT_OFFSET 204       /* TODO: Need definition in LB header */
128 #define TCP_START_IPV6 (IP_START + 40)
129 #define PROTOCOL_START_IPV6 (IP_START + 6)
130 #define IP_HDR_DSCP_OFST 1
131
132 #define TCP_PROTOCOL 6
133 #define UDP_PROTOCOL 17
134
135 #define DELETE_BUFFERED_PACKETS 0
136 #define FORWARD_BUFFERED_PACKETS 1
137 #define DO_ARP 1
138 #define NO_ARP 0
139
140 #define IPv4_HEADER_SIZE 20
141 #define IPv6_HEADER_SIZE 40
142
143 #define IP_VERSION_4 4
144 #define IP_VERSION_6 6
145
146 /* IPv6 */
147 #define IP_HDR_SIZE_IPV6  40
148 #define IP_HDR_DSCP_OFST_IPV6 0
149 #define IP_HDR_LENGTH_OFST_IPV6 4
150 #define IP_HDR_PROTOCOL_OFST_IPV6 6
151 #define IP_HDR_DST_ADR_OFST_IPV6 24
152 #define MAX_NUM_LOCAL_MAC_ADDRESS 16
153 /** The counter table for VFW pipeline per thread data.*/
154 struct rte_VFW_counter_block rte_vfw_counter_table[MAX_VFW_INSTANCES]
155 __rte_cache_aligned;
156 int rte_VFW_hi_counter_block_in_use = -1;
157
158 /* a spin lock used during vfw initialization only */
159 rte_spinlock_t rte_VFW_init_lock = RTE_SPINLOCK_INITIALIZER;
160
161 /* Action Array */
162 struct pipeline_action_key *action_array_a;
163 struct pipeline_action_key *action_array_b;
164 struct pipeline_action_key *action_array_active;
165 struct pipeline_action_key *action_array_standby;
166 uint32_t action_array_size;
167 struct action_counter_block
168 action_counter_table[MAX_VFW_INSTANCES][action_array_max]
169 __rte_cache_aligned;
170 /*
171   * Pipeline table strategy for firewall. Unfortunately, there does not seem to
172   * be any use for the built-in table lookup of ip_pipeline for the firewall.
173   * The main table requirement of the firewall is the hash table to maintain
174   * connection info, but that is implemented seperately in the connection
175   * tracking library. So a "dummy" table lookup will be performed.
176   * TODO: look into "stub" table and see if that can be used
177   * to avoid useless table lookup
178   */
179 /***** ARP local cache *****/
180 #if 0
181 uint8_t link_hw_laddr_valid[MAX_NUM_LOCAL_MAC_ADDRESS] = {
182        0, 0, 0, 0, 0, 0, 0, 0,
183        0, 0, 0, 0, 0, 0, 0, 0
184 };
185
186 static struct ether_addr link_hw_laddr[MAX_NUM_LOCAL_MAC_ADDRESS] = {
187        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
188        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
189        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
190        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
191        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
192        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
193        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
194        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
195        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
196        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
197        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
198        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
199        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
200        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
201        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
202        {.addr_bytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }
203 };
204 #endif
205 uint64_t arp_pkts_mask;
206
207 /* Start TSC measurement */
208 /* Prefetch counters and pipe before this function */
209 static inline void start_tsc_measure(struct pipeline_vfw *vfw_pipe) {
210        vfw_pipe->counters->entry_timestamp = rte_get_tsc_cycles();
211        if (likely(vfw_pipe->counters->exit_timestamp))
212               vfw_pipe->counters->external_time_sum +=
213                      vfw_pipe->counters->entry_timestamp -
214                      vfw_pipe->counters->exit_timestamp;
215 }
216
217 /* End TSC measurement */
218 static inline void end_tsc_measure(
219        struct pipeline_vfw *vfw_pipe,
220        uint8_t n_pkts)
221 {
222        if (likely(n_pkts > 1)) {
223               vfw_pipe->counters->exit_timestamp = rte_get_tsc_cycles();
224               vfw_pipe->counters->internal_time_sum +=
225                      vfw_pipe->counters->exit_timestamp -
226                      vfw_pipe->counters->entry_timestamp;
227               vfw_pipe->counters->time_measurements++;
228        } else {
229               /* small counts skew results, ignore */
230               vfw_pipe->counters->exit_timestamp = 0;
231        }
232 }
233
234 //static struct ether_addr *get_local_link_hw_addr(uint8_t out_port)
235 //{
236 //       return &link_hw_laddr[out_port];
237 //}
238 #if 0
239 static uint8_t local_dest_mac_present(uint8_t out_port)
240 {
241        return link_hw_laddr_valid[out_port];
242 }
243
244 static uint32_t local_get_nh_ipv4(
245        uint32_t ip,
246        uint32_t *port,
247        uint32_t *nhip,
248        struct pipeline_vfw *vfw_pipe)
249 {
250        int i;
251
252        for (i = 0; i < vfw_pipe->local_lib_arp_route_ent_cnt; i++) {
253               if (((vfw_pipe->local_lib_arp_route_table[i].ip &
254               vfw_pipe->local_lib_arp_route_table[i].mask) ==
255               (ip & vfw_pipe->local_lib_arp_route_table[i].mask))) {
256                      *port = vfw_pipe->local_lib_arp_route_table[i].port;
257
258                      *nhip = vfw_pipe->local_lib_arp_route_table[i].nh;
259                      return 1;
260               }
261        }
262        return 0;
263 }
264
265 static void do_local_nh_ipv4_cache(uint32_t dest_if,
266               struct pipeline_vfw *vfw_pipe)
267 {
268
269        /* Search for the entry and do local copy */
270        int i;
271
272        for (i = 0; i < MAX_ARP_RT_ENTRY; i++) {
273               if (lib_arp_route_table[i].port == dest_if) {
274
275                      struct lib_arp_route_table_entry *lentry =
276                             &vfw_pipe->
277                             local_lib_arp_route_table[vfw_pipe->
278                             local_lib_arp_route_ent_cnt];
279
280                      lentry->ip   = lib_arp_route_table[i].ip;
281                      lentry->mask = lib_arp_route_table[i].mask;
282                      lentry->port = lib_arp_route_table[i].port;
283                      lentry->nh   = lib_arp_route_table[i].nh;
284
285                      vfw_pipe->local_lib_arp_route_ent_cnt++;
286                      break;
287               }
288        }
289 }
290 #endif
291 static uint32_t local_get_nh_ipv6(
292        uint8_t *ip,
293        uint32_t *port,
294        uint8_t nhip[],
295         struct pipeline_vfw *vfw_pipe)
296 {
297        uint8_t netmask_ipv6[IPV6_ADD_SIZE], netip_nd[IPV6_ADD_SIZE],
298               netip_in[IPV6_ADD_SIZE];
299        uint8_t i = 0, j = 0, k = 0, l = 0, depthflags = 0, depthflags1 = 0;
300        memset(netmask_ipv6, 0, sizeof(netmask_ipv6));
301        memset(netip_nd, 0, sizeof(netip_nd));
302        memset(netip_in, 0, sizeof(netip_in));
303
304        for (i = 0; i < vfw_pipe->local_lib_nd_route_ent_cnt; i++) {
305
306               convert_prefixlen_to_netmask_ipv6(
307                      vfw_pipe->local_lib_nd_route_table[i].depth,
308                      netmask_ipv6);
309
310               for (k = 0; k < IPV6_ADD_SIZE; k++)
311                      if (vfw_pipe->local_lib_nd_route_table[i].ipv6[k] &
312                                    netmask_ipv6[k]) {
313                             depthflags++;
314                             netip_nd[k] = vfw_pipe->
315                                    local_lib_nd_route_table[i].ipv6[k];
316                      }
317
318               for (l = 0; l < IPV6_ADD_SIZE; l++)
319                      if (ip[l] & netmask_ipv6[l]) {
320                             depthflags1++;
321                             netip_in[l] = ip[l];
322                      }
323
324
325               if ((depthflags == depthflags1) && (memcmp(netip_nd, netip_in,
326                                           sizeof(netip_nd)) == 0)) {
327
328                      *port = vfw_pipe->local_lib_nd_route_table[i].port;
329
330                      for (j = 0; j < IPV6_ADD_SIZE; j++)
331                             nhip[j] = vfw_pipe->
332                                    local_lib_nd_route_table[i].nhipv6[j];
333                      return 1;
334               }
335
336               depthflags = 0;
337               depthflags1 = 0;
338                      }
339                      return 0;
340 }
341
342 static void do_local_nh_ipv6_cache(uint32_t dest_if,
343               struct pipeline_vfw *vfw_pipe)
344 {
345               /* Search for the entry and do local copy */
346        int i, l;
347
348        for (i = 0; i < MAX_ND_RT_ENTRY; i++) {
349
350               if (lib_nd_route_table[i].port == dest_if) {
351
352                      struct lib_nd_route_table_entry *lentry = &vfw_pipe->
353                             local_lib_nd_route_table[vfw_pipe->
354                             local_lib_nd_route_ent_cnt];
355
356                      for (l = 0; l < IPV6_ADD_SIZE; l++) {
357                             lentry->ipv6[l]   =
358                                    lib_nd_route_table[i].ipv6[l];
359                             lentry->nhipv6[l] =
360                                    lib_nd_route_table[i].nhipv6[l];
361                      }
362                      lentry->depth = lib_nd_route_table[i].depth;
363                      lentry->port  = lib_nd_route_table[i].port;
364
365                      vfw_pipe->local_lib_nd_route_ent_cnt++;
366                      break;
367                      } /* if */
368               } /* for */
369 }
370 /**
371  * Print packet for debugging.
372  *
373  * @param pkt
374  *  A pointer to the packet.
375  *
376  */
377 static __rte_unused  void print_pkt(struct rte_mbuf *pkt)
378 {
379        int i;
380        int size = (int)sizeof(struct mbuf_tcp_meta_data);
381        uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, META_DATA_OFFSET);
382
383        printf("Meta-data:\n");
384        for (i = 0; i < size; i++) {
385               printf("%02x ", rd[i]);
386               if ((i & TWO_BYTE_PRINT) == TWO_BYTE_PRINT)
387                      printf("\n");
388        }
389        printf("\n");
390        printf("IP and TCP/UDP headers:\n");
391        rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, IP_START);
392        for (i = 0; i < IP_HDR_SIZE_IPV6; i++) {
393               printf("%02x ", rd[i]);
394               if ((i & TWO_BYTE_PRINT) == TWO_BYTE_PRINT)
395                      printf("\n");
396        }
397        printf("\n");
398 }
399
400 /* TODO: are the protocol numbers defined somewhere with meaningful names? */
401 #define IP_ICMP_PROTOCOL 1
402 #define IP_TCP_PROTOCOL 6
403 #define IP_UDP_PROTOCOL 17
404 #define IPv6_FRAGMENT_HEADER 44
405
406 /**
407  * Return ethernet header structure form packet.
408  *
409  * @param pkt
410  *  A pointer to the packet.
411  *
412  */
413 static inline struct ether_hdr *rte_vfw_get_ether_addr(struct rte_mbuf *pkt)
414 {
415        return (struct ether_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt,
416                                                         ETHERNET_START);
417 }
418
419 /**
420  * Return IPV4 header structure form packet.
421  *
422  * @param pkt
423  *  A pointer to the packet.
424  *
425  */
426
427 static inline struct ipv4_hdr *rte_vfw_get_IPv4_hdr_addr(
428               struct rte_mbuf *pkt)
429 {
430        return (struct ipv4_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
431 }
432
433 static inline int rte_vfw_is_IPv4(struct rte_mbuf *pkt)
434 {
435        /* NOTE: Only supporting IP headers with no options,
436         * so header is fixed size */
437        uint8_t ip_type = RTE_MBUF_METADATA_UINT8(pkt, IP_START)
438               >> VERSION_NO_BYTE;
439
440        return ip_type == IPv4_HDR_VERSION;
441 }
442
443 static inline int rte_vfw_is_IPv6(struct rte_mbuf *pkt)
444 {
445        /* NOTE: Only supporting IP headers with no options,
446         * so header is fixed size */
447        uint8_t ip_type = RTE_MBUF_METADATA_UINT8(pkt, IP_START)
448               >> VERSION_NO_BYTE;
449
450        return ip_type == IPv6_HDR_VERSION;
451 }
452
453 static inline void rte_vfw_incr_drop_ctr(uint64_t *counter)
454 {
455        if (likely(firewall_flag))
456               (*counter)++;
457 }
458
459 static uint8_t check_arp_icmp(
460               struct rte_mbuf *pkt,
461               struct pipeline_vfw *vfw_pipe)
462 {
463        struct ether_hdr *ehdr;
464        struct app_link_params *link;
465         uint8_t solicited_node_multicast_addr[IPV6_ADD_SIZE] = {
466                 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467                 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00};
468
469         /* ARP outport number */
470        uint16_t out_port = vfw_pipe->pipe.n_ports_out - 1;
471        struct ipv4_hdr *ipv4_h;
472        struct ipv6_hdr *ipv6_h;
473        link = &myApp->link_params[pkt->port];
474
475        ehdr = rte_vfw_get_ether_addr(pkt);
476        switch (rte_be_to_cpu_16(ehdr->ether_type)) {
477
478        case ETH_TYPE_ARP:
479               rte_pipeline_port_out_packet_insert(
480                             vfw_pipe->pipe.p,
481                             out_port,
482                             pkt);
483
484               vfw_pipe->counters->arpicmpPktCount++;
485
486               return 0;
487        case ETH_TYPE_IPV4:
488               ipv4_h = (struct ipv4_hdr *)
489                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
490               if ((ipv4_h->next_proto_id == IP_PROTOCOL_ICMP) &&
491                             link->ip ==
492                             rte_be_to_cpu_32(ipv4_h->dst_addr)) {
493                      if (is_phy_port_privte(pkt->port)) {
494                             rte_pipeline_port_out_packet_insert(
495                                           vfw_pipe->pipe.p,
496                                           out_port,
497                                           pkt);
498
499                      vfw_pipe->counters->arpicmpPktCount++;
500                             return 0;
501                      }
502               }
503               break;
504 #ifdef IPV6
505         case ETH_TYPE_IPV6:
506                 ipv6_h = (struct ipv6_hdr *)
507                         RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
508
509                 if (ipv6_h->proto == ICMPV6_PROTOCOL_ID) {
510                         if (!memcmp(ipv6_h->dst_addr, link->ipv6, IPV6_ADD_SIZE)
511                                         || !memcmp(ipv6_h->dst_addr,
512                                                 solicited_node_multicast_addr,
513                                                 IPV6_ADD_CMP_MULTI)) {
514
515                                 rte_pipeline_port_out_packet_insert(
516                                                 vfw_pipe->pipe.p,
517                                                 out_port,
518                                                 pkt);
519
520                                 vfw_pipe->counters->arpicmpPktCount++;
521
522                         } else
523                                 vfw_pipe->counters->
524                                         pkts_drop_unsupported_type++;
525
526                         return 0;
527                 }
528                 break;
529 #endif
530        default:
531               break;
532 }
533        return 1;
534 }
535
536 /**
537  * Performs basic VFW ipv4 packet filtering.
538  * @param pkts
539  *  A pointer to the packets.
540  * @param pkts_mask
541  *  packet mask.
542  * @param vfw_pipe
543  *  A pointer to VFW pipeline.
544  */
545
546 static uint64_t
547 rte_vfw_ipv4_packet_filter_and_process(struct rte_mbuf **pkts,
548                                  uint64_t pkts_mask,
549                                  struct pipeline_vfw *vfw_pipe)
550 {
551
552        /*
553         * Make use of cache prefetch. At beginning of loop, want to prefetch
554         * mbuf data for next iteration (not current one).
555         * Note that ethernet header (14 bytes) is cache aligned. IPv4 header
556         * is 20 bytes (extensions not supported), while the IPv6 header is 40
557         * bytes. TCP header is 20 bytes, UDP is 8. One cache line prefetch
558         * will cover IPv4 and TCP or UDP, but to get IPv6 and TCP,
559         * need two pre-fetches.
560         */
561
562        uint8_t pos, next_pos = 0;
563        uint64_t pkt_mask;       /* bitmask representing a single packet */
564        struct rte_mbuf *pkt;
565        struct rte_mbuf *next_pkt = NULL;
566        struct ipv4_hdr *ihdr4;
567        void *next_iphdr = NULL;
568
569        if (unlikely(pkts_mask == 0))
570               return pkts_mask;
571        pos = (uint8_t) __builtin_ctzll(pkts_mask);
572        pkt_mask = 1LLU << pos;       /* bitmask representing only this packet */
573        pkt = pkts[pos];
574
575        uint64_t bytes_processed = 0;
576        /* bitmap of packets left to process */
577        uint64_t pkts_to_process = pkts_mask;
578        /* bitmap of valid packets to return */
579        uint64_t valid_packets = pkts_mask;
580
581        rte_prefetch0(pkt);
582        /* prefetch counters, updated below. Most likely counters to update
583         * at beginnning */
584        rte_prefetch0(&vfw_pipe->counters);
585
586        do {                     /* always execute at least once */
587
588               /* remove this packet from remaining list */
589               uint64_t next_pkts_to_process = pkts_to_process &= ~pkt_mask;
590
591               if (likely(next_pkts_to_process)) {
592                      /* another packet to process after this, prefetch it */
593
594                      next_pos =
595                             (uint8_t) __builtin_ctzll(next_pkts_to_process);
596                      next_pkt = pkts[next_pos];
597                      next_iphdr = RTE_MBUF_METADATA_UINT32_PTR(next_pkt,
598                                    IP_START);
599                      rte_prefetch0(next_iphdr);
600               }
601
602               int discard = 0;
603               /* remove this packet from remaining list */
604               pkts_to_process &= ~pkt_mask;
605
606               if (enable_hwlb) {
607                       if (!check_arp_icmp(pkt, vfw_pipe)) {
608                               /* make next packet data the current */
609                               pkts_to_process = next_pkts_to_process;
610                               pos = next_pos;
611                               pkt = next_pkt;
612                               ihdr4 = next_iphdr;
613                               pkt_mask = 1LLU << pos;
614                               valid_packets &= ~pkt_mask;
615                               continue;
616                      }
617               }
618
619               uint32_t packet_length = rte_pktmbuf_pkt_len(pkt);
620
621               bytes_processed += packet_length;
622
623               ihdr4 = (struct ipv4_hdr *)
624                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
625
626               /* verify that packet size according to mbuf is at least
627                * as large as the size according to the IP header.
628                */
629
630               uint32_t ip_length = rte_bswap16(ihdr4->total_length);
631
632               if (unlikely
633                             (ip_length > (packet_length - ETH_HDR_SIZE))) {
634                      discard = 1;
635                      vfw_pipe->counters->pkts_drop_bad_size++;
636               }
637
638               /*
639                * IPv4 fragmented if: MF (more fragments) or Fragment
640                * Offset are non-zero. Header in Intel order, so flip
641                * constant to compensate. Note that IPv6 uses a header
642                * extension for identifying fragments.
643                */
644
645               int fragmented = (ihdr4->fragment_offset & 0xff3f) != 0;
646               uint8_t ttl = ihdr4->time_to_live;
647
648               if (unlikely(fragmented)) {
649                      discard = 1;
650                      vfw_pipe->counters->pkts_drop_fragmented++;
651               }
652
653               if (unlikely(ttl <= 1)) {
654                      /*
655                       * about to decrement to zero (or is somehow
656                       * already zero), so discard
657                       */
658                      discard = 1;
659                      vfw_pipe->counters->pkts_drop_ttl++;
660               }
661
662               /*
663                * Dropping the packets other than TCP AND UDP.
664                */
665
666               uint8_t proto = ihdr4->next_proto_id;
667
668               if (unlikely(!(proto == IP_TCP_PROTOCOL ||
669                                           proto == IP_UDP_PROTOCOL ||
670                                           proto == IP_ICMP_PROTOCOL))) {
671                      discard = 1;
672                      vfw_pipe->counters->
673                             pkts_drop_unsupported_type++;
674               }
675
676               if (unlikely(discard)) {
677                      valid_packets &= ~pkt_mask;
678               }
679
680               /* make next packet data the current */
681               pkts_to_process = next_pkts_to_process;
682               pos = next_pos;
683               pkt = next_pkt;
684               ihdr4 = next_iphdr;
685               pkt_mask = 1LLU << pos;
686
687        } while (pkts_to_process);
688
689        /* finalize counters, etc. */
690        vfw_pipe->counters->bytes_processed += bytes_processed;
691
692        if (likely(firewall_flag))
693               return valid_packets;
694        else
695               return pkts_mask;
696 }
697 /**
698  * Performs basic VFW IPV6 packet filtering.
699  * @param pkts
700  *  A pointer to the packets.
701  * @param pkts_mask
702  *  packet mask.
703  * @param vfw_pipe
704  *  A pointer to VFW pipeline.
705  */
706        static uint64_t
707 rte_vfw_ipv6_packet_filter_and_process(struct rte_mbuf **pkts,
708               uint64_t pkts_mask,
709               struct pipeline_vfw *vfw_pipe)
710 {
711
712        /*
713         * Make use of cache prefetch. At beginning of loop, want to prefetch
714         * mbuf data for next iteration (not current one).
715         * Note that ethernet header (14 bytes) is cache aligned. IPv4 header
716         * is 20 bytes (extensions not supported), while the IPv6 header is 40
717         * bytes. TCP header is 20 bytes, UDP is 8. One cache line prefetch
718         * will cover IPv4 and TCP or UDP, but to get IPv6 and TCP,
719         * need two pre-fetches.
720         */
721
722        uint8_t pos, next_pos = 0;
723        uint64_t pkt_mask;       /* bitmask representing a single packet */
724        struct rte_mbuf *pkt;
725        struct rte_mbuf *next_pkt = NULL;
726        struct ipv6_hdr *ihdr6;
727        void *next_iphdr = NULL;
728
729        if (unlikely(pkts_mask == 0))
730               return pkts_mask;
731        pos = (uint8_t) __builtin_ctzll(pkts_mask);
732        pkt_mask = 1LLU << pos;       /* bitmask representing only this packet */
733        pkt = pkts[pos];
734
735        uint64_t bytes_processed = 0;
736        /* bitmap of packets left to process */
737        uint64_t pkts_to_process = pkts_mask;
738        /* bitmap of valid packets to return */
739        uint64_t valid_packets = pkts_mask;
740
741        /* prefetch counters, updated below. Most likely counters to update
742         * at beginnning */
743        rte_prefetch0(&vfw_pipe->counters);
744
745        do {                     /* always execute at least once */
746
747               /* remove this packet from remaining list */
748               uint64_t next_pkts_to_process = pkts_to_process &= ~pkt_mask;
749
750               if (likely(next_pkts_to_process)) {
751                      /* another packet to process after this, prefetch it */
752
753                      next_pos =
754                          (uint8_t) __builtin_ctzll(next_pkts_to_process);
755                      next_pkt = pkts[next_pos];
756                      next_iphdr =
757                          RTE_MBUF_METADATA_UINT32_PTR(next_pkt, IP_START);
758                      rte_prefetch0(next_iphdr);
759               }
760
761               int discard = 0;
762               /* remove this packet from remaining list */
763               pkts_to_process &= ~pkt_mask;
764
765               if (enable_hwlb) {
766                      if (!check_arp_icmp(pkt, vfw_pipe)) {
767                              /* make next packet data the current */
768                              pkts_to_process = next_pkts_to_process;
769                              pos = next_pos;
770                              pkt = next_pkt;
771                              ihdr6 = next_iphdr;
772                              pkt_mask = 1LLU << pos;
773                              valid_packets &= ~pkt_mask;
774                              continue;
775                      }
776               }
777
778               uint32_t packet_length = rte_pktmbuf_pkt_len(pkt);
779
780               bytes_processed += packet_length;
781
782               ihdr6 = (struct ipv6_hdr *)
783                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
784
785               /*
786                * verify that packet size according to mbuf is at least
787                * as large as the size according to the IP header.
788                * For IPv6, note that size includes header extensions
789                * but not the base header size
790                */
791
792               uint32_t ip_length =
793                      rte_bswap16(ihdr6->payload_len) + IPv6_HEADER_SIZE;
794
795               if (unlikely
796                             (ip_length > (packet_length - ETH_HDR_SIZE))) {
797                      discard = 1;
798                      vfw_pipe->counters->pkts_drop_bad_size++;
799               }
800
801               /*
802                * Dropping the packets other than TCP AND UDP.
803                */
804
805               uint8_t proto = ihdr6->proto;
806
807               if (unlikely(!(proto == IP_TCP_PROTOCOL ||
808                                           proto == IP_UDP_PROTOCOL ||
809                                           proto == IP_ICMP_PROTOCOL))) {
810                      discard = 1;
811                      if (proto == IPv6_FRAGMENT_HEADER)
812                             vfw_pipe->counters->
813                                    pkts_drop_fragmented++;
814                      else
815                             vfw_pipe->counters->
816                                    pkts_drop_unsupported_type++;
817               }
818
819               /*
820                * Behave like a router, and decrement the TTL of an
821                * IP packet. If this causes the TTL to become zero,
822                * the packet will be discarded. Unlike a router,
823                * no ICMP code 11 (Time * Exceeded) message will be
824                * sent back to the packet originator.
825                */
826
827               if (unlikely(ihdr6->hop_limits <= 1)) {
828                      /*
829                       * about to decrement to zero (or is somehow
830                       * already zero), so discard
831                       */
832                      discard = 1;
833                      vfw_pipe->counters->pkts_drop_ttl++;
834               }
835
836               if (unlikely(discard))
837                      valid_packets &= ~pkt_mask;
838               else
839                      ihdr6->hop_limits--;
840
841               /* make next packet data the current */
842               pkts_to_process = next_pkts_to_process;
843               pos = next_pos;
844               pkt = next_pkt;
845               ihdr6 = next_iphdr;
846               pkt_mask = 1LLU << pos;
847
848        } while (pkts_to_process);
849
850        /* finalize counters, etc. */
851        vfw_pipe->counters->bytes_processed += bytes_processed;
852
853        if (likely(firewall_flag))
854               return valid_packets;
855        else
856               return pkts_mask;
857 }
858
859 /**
860  * exchange the mac address so source becomes destination and vice versa.
861  *
862  * @param ehdr
863  *  A pointer to the ethernet header.
864  *
865  */
866 static inline void rte_sp_exchange_mac_addresses(struct ether_hdr *ehdr)
867 {
868        struct ether_addr saved_copy;
869
870        ether_addr_copy(&ehdr->d_addr, &saved_copy);
871        ether_addr_copy(&ehdr->s_addr, &ehdr->d_addr);
872        ether_addr_copy(&saved_copy, &ehdr->s_addr);
873 }
874 #ifdef EN_SWP_ARP
875
876 /**
877  * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
878  * To support synproxy, some (altered) packets may need to be sent back where
879  * they came from. The ip header has already been adjusted, but the ethernet
880  * header has not, so this must be performed here.
881  * Return an updated pkts_mask, since arp may drop some packets
882  *
883  * @param pkts
884  *  A pointer to the packet array.
885  * @param pkt_num
886  *  Packet num to start processing
887  * @param pkts_mask
888  *  Packet mask
889  * @param synproxy_reply_mask
890  *  Reply Packet mask for Synproxy
891  * @param vfw_pipe
892  *  A pointer to VFW pipeline.
893  */
894 static void
895 pkt4_work_vfw_arp_ipv4_packets(struct rte_mbuf **pkts,
896               uint16_t pkt_num,
897               uint64_t *pkts_mask,
898               uint64_t synproxy_reply_mask,
899               struct pipeline_vfw *vfw_pipe)
900 {
901
902        uint8_t i;
903
904        struct mbuf_tcp_meta_data *meta_data_addr;
905        struct ether_hdr *ehdr;
906        struct rte_mbuf *pkt;
907
908        for (i = 0; i < 4; i++) {
909               uint32_t dest_if = INVALID_DESTIF;
910               /* bitmask representing only this packet */
911               uint64_t pkt_mask = 1LLU << (pkt_num + i);
912
913               pkt = pkts[i];
914
915               if(!(*pkts_mask & pkt_mask))
916                      continue;
917
918               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
919
920               meta_data_addr = (struct mbuf_tcp_meta_data *)
921                      RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
922               ehdr = rte_vfw_get_ether_addr(pkt);
923
924
925               struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
926                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
927               uint32_t nhip = 0;
928
929               uint32_t dest_address = rte_bswap32(ihdr->dst_addr);
930               if (must_reverse)
931                      rte_sp_exchange_mac_addresses(ehdr);
932 #if 0
933               ret = local_get_nh_ipv4(dest_address, &dest_if,
934                             &nhip, vfw_pipe);
935               if (must_reverse) {
936                      rte_sp_exchange_mac_addresses(ehdr);
937                      if (is_phy_port_privte(phy_port)) {
938                             if (!ret) {
939                                    dest_if = get_pub_to_prv_port(
940                                                  &dest_address,
941                                                  IP_VERSION_4);
942                                    if (dest_if == INVALID_DESTIF) {
943                                           *pkts_mask &= ~pkt_mask;
944                                           vfw_pipe->counters->
945                                           pkts_drop_without_arp_entry++;
946                                    }
947                                    do_local_nh_ipv4_cache(
948                                                  dest_if, vfw_pipe);
949                             }
950
951                      } else {
952                             if (!ret) {
953                                    dest_if = get_prv_to_pub_port(
954                                                  &dest_address,
955                                                  IP_VERSION_4);
956                                    if (dest_if == INVALID_DESTIF) {
957                                           *pkts_mask &= ~pkt_mask;
958                                           vfw_pipe->counters->
959                                           pkts_drop_without_arp_entry++;
960                                    }
961                                    do_local_nh_ipv4_cache(dest_if,
962                                                  vfw_pipe);
963                             }
964                      }
965               } else if (is_phy_port_privte(phy_port)) {
966                      if (!ret) {
967                             dest_if = get_prv_to_pub_port(&dest_address,
968                                           IP_VERSION_4);
969                             if (dest_if == INVALID_DESTIF) {
970                                    *pkts_mask &= ~pkt_mask;
971                                    vfw_pipe->counters->
972                                           pkts_drop_without_arp_entry++;
973                             }
974                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
975                      }
976
977               } else {
978                      if (!ret) {
979                             dest_if = get_pub_to_prv_port(&dest_address,
980                                           IP_VERSION_4);
981                             if (dest_if == INVALID_DESTIF) {
982                                    *pkts_mask &= ~pkt_mask;
983                                    vfw_pipe->counters->
984                                           pkts_drop_without_arp_entry++;
985                             }
986                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
987                      }
988
989               }
990               meta_data_addr->output_port =  vfw_pipe->outport_id[dest_if];
991               if (local_dest_mac_present(dest_if)) {
992                      ether_addr_copy(get_local_link_hw_addr(dest_if),
993                                    &ehdr->d_addr);
994                      ether_addr_copy(get_link_hw_addr(dest_if),
995                                    &ehdr->s_addr);
996               } else {
997 #endif
998         struct arp_entry_data *ret_arp_data = NULL;
999         ret_arp_data = get_dest_mac_addr_port(dest_address,
1000                        &dest_if, &ehdr->d_addr);
1001         meta_data_addr->output_port =  vfw_pipe->outport_id[dest_if];
1002
1003         if (arp_cache_dest_mac_present(dest_if)) {
1004
1005                 ether_addr_copy(get_link_hw_addr(dest_if), &ehdr->s_addr);
1006                 arp_data_ptr[dest_if]->n_last_update = time(NULL);
1007
1008                 if (unlikely(ret_arp_data && ret_arp_data->num_pkts)) {
1009
1010                         printf("sending buffered packets\n");
1011                         arp_send_buffered_pkts(ret_arp_data,
1012                                  &ehdr->d_addr, vfw_pipe->outport_id[dest_if]);
1013
1014                             }
1015
1016                      } else {
1017                 if (unlikely(ret_arp_data == NULL)) {
1018
1019                         printf("%s: NHIP Not Found, nhip:%x , "
1020                         "outport_id: %d\n", __func__, nhip,
1021                         vfw_pipe->outport_id[dest_if]);
1022
1023                         /* Drop the pkt */
1024                         vfw_pipe->counters->
1025                                  pkts_drop_without_arp_entry++;
1026                         continue;
1027                             }
1028                 if (ret_arp_data->status == INCOMPLETE ||
1029                            ret_arp_data->status == PROBE) {
1030                                 if (ret_arp_data->num_pkts >= NUM_DESC) {
1031                             /* ICMP req sent, drop packet by
1032                              * changing the mask */
1033                                 vfw_pipe->counters->
1034                                          pkts_drop_without_arp_entry++;
1035                                         continue;
1036                                 } else {
1037                                         arp_pkts_mask |= pkt_mask;
1038                                         arp_queue_unresolved_packet(ret_arp_data, pkt);
1039                                         continue;
1040                      }
1041               }
1042         }
1043        }
1044 }
1045
1046
1047 /**
1048  * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
1049  * To support synproxy, some (altered) packets may need to be sent back where
1050  * they came from. The ip header has already been adjusted, but the ethernet
1051  * header has not, so this must be performed here.
1052  * Return an updated pkts_mask, since arp may drop some packets
1053  *
1054  * @param pkts
1055  *  A pointer to the packet.
1056  * @param packet_num
1057  *  Packet number to process
1058  * @param pkts_mask
1059  *  Packet mask pointer
1060  * @param synproxy_reply_mask
1061  *  Reply Packet mask for Synproxy
1062  * @param vfw_pipe
1063  *  A pointer to VFW pipeline.
1064  */
1065 static void
1066 pkt_work_vfw_arp_ipv4_packets(struct rte_mbuf *pkts,
1067               uint16_t pkt_num,
1068               uint64_t *pkts_mask,
1069               uint64_t synproxy_reply_mask,
1070               struct pipeline_vfw *vfw_pipe)
1071 {
1072
1073        uint32_t dest_if = INVALID_DESTIF;
1074
1075        struct mbuf_tcp_meta_data *meta_data_addr;
1076        struct ether_hdr *ehdr;
1077        struct rte_mbuf *pkt;
1078        uint64_t pkt_mask = 1LLU << pkt_num;
1079
1080        pkt = pkts;
1081
1082        if(*pkts_mask & pkt_mask) {
1083
1084               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1085
1086               meta_data_addr = (struct mbuf_tcp_meta_data *)
1087                      RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1088               ehdr = rte_vfw_get_ether_addr(pkt);
1089
1090
1091               struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
1092                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1093               uint32_t nhip = 0;
1094
1095               uint32_t dest_address = rte_bswap32(ihdr->dst_addr);
1096               if (must_reverse)
1097                      rte_sp_exchange_mac_addresses(ehdr);
1098
1099 #if 0
1100               ret = local_get_nh_ipv4(dest_address, &dest_if,
1101                             &nhip, vfw_pipe);
1102               if (must_reverse) {
1103                      rte_sp_exchange_mac_addresses(ehdr);
1104                      if (is_phy_port_privte(phy_port)) {
1105                             if (!ret) {
1106                                    dest_if = get_pub_to_prv_port(
1107                                                  &dest_address,
1108                                                  IP_VERSION_4);
1109                                    if (dest_if == INVALID_DESTIF) {
1110                                           *pkts_mask &= ~pkt_mask;
1111                                           vfw_pipe->counters->
1112                                           pkts_drop_without_arp_entry++;
1113                                    }
1114                                    do_local_nh_ipv4_cache(
1115                                                  dest_if, vfw_pipe);
1116                             }
1117
1118                      } else {
1119                             if (!ret) {
1120                                    dest_if = get_prv_to_pub_port(
1121                                                  &dest_address,
1122                                                  IP_VERSION_4);
1123                                    if (dest_if == INVALID_DESTIF) {
1124                                           *pkts_mask &= ~pkt_mask;
1125                                           vfw_pipe->counters->
1126                                           pkts_drop_without_arp_entry++;
1127                                    }
1128                                    do_local_nh_ipv4_cache(dest_if,
1129                                                  vfw_pipe);
1130                             }
1131                      }
1132               } else if (is_phy_port_privte(phy_port)) {
1133                      if (!ret) {
1134                             dest_if = get_prv_to_pub_port(&dest_address,
1135                                           IP_VERSION_4);
1136                             if (dest_if == INVALID_DESTIF) {
1137                                    *pkts_mask &= ~pkt_mask;
1138                                    vfw_pipe->counters->
1139                                           pkts_drop_without_arp_entry++;
1140                             }
1141                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1142                      }
1143
1144               } else {
1145                      if (!ret) {
1146                             dest_if = get_pub_to_prv_port(&dest_address,
1147                                           IP_VERSION_4);
1148                             if (dest_if == INVALID_DESTIF) {
1149                                    *pkts_mask &= ~pkt_mask;
1150                                    vfw_pipe->counters->
1151                                           pkts_drop_without_arp_entry++;
1152                             }
1153                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1154                      }
1155
1156               }
1157               meta_data_addr->output_port =  vfw_pipe->outport_id[dest_if];
1158               if (local_dest_mac_present(dest_if)) {
1159                      ether_addr_copy(get_local_link_hw_addr(dest_if),
1160                                    &ehdr->d_addr);
1161                      ether_addr_copy(get_link_hw_addr(dest_if),
1162                                    &ehdr->s_addr);
1163               } else {
1164 #endif
1165         struct arp_entry_data *ret_arp_data = NULL;
1166                      ret_arp_data = get_dest_mac_addr_port(dest_address,
1167                                    &dest_if, &ehdr->d_addr);
1168                         meta_data_addr->output_port =  vfw_pipe->outport_id[dest_if];
1169         if (arp_cache_dest_mac_present(dest_if)) {
1170
1171                 ether_addr_copy(get_link_hw_addr(dest_if), &ehdr->s_addr);
1172                 arp_data_ptr[dest_if]->n_last_update = time(NULL);
1173
1174                 if (unlikely(ret_arp_data && ret_arp_data->num_pkts)) {
1175
1176                         printf("sending buffered packets\n");
1177                         arp_send_buffered_pkts(ret_arp_data,
1178                                  &ehdr->d_addr, vfw_pipe->outport_id[dest_if]);
1179
1180                             }
1181
1182                      } else {
1183                 if (unlikely(ret_arp_data == NULL)) {
1184
1185                         printf("%s: NHIP Not Found, nhip:%x , "
1186                         "outport_id: %d\n", __func__, nhip,
1187                         vfw_pipe->outport_id[dest_if]);
1188
1189                         vfw_pipe->counters->
1190                                 pkts_drop_without_arp_entry++;
1191                         return;
1192                             }
1193                 if (ret_arp_data->status == INCOMPLETE ||
1194                            ret_arp_data->status == PROBE) {
1195                                 if (ret_arp_data->num_pkts >= NUM_DESC) {
1196                             /* ICMP req sent, drop packet by
1197                              * changing the mask */
1198                                         vfw_pipe->counters->
1199                                                 pkts_drop_without_arp_entry++;
1200                                         return;
1201                                 } else {
1202                                         arp_pkts_mask |= pkt_mask;
1203                                         arp_queue_unresolved_packet(ret_arp_data, pkt);
1204                                         return;
1205                      }
1206               }
1207         }
1208
1209        }
1210 }
1211
1212
1213 /**
1214  * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
1215  * To support synproxy, some (altered) packets may need to be sent back where
1216  * they came from. The ip header has already been adjusted, but the ethernet
1217  * header has not, so this must be performed here.
1218  * Return an updated pkts_mask, since arp may drop some packets
1219  *
1220  * @param pkts
1221  *  A pointer to the packets array.
1222  * @param pkt_num
1223  *  Packet number to start processing.
1224  * @param pkts_mask
1225  *  Packet mask pointer
1226  * @param synproxy_reply_mask
1227  *  Reply Packet mask for Synproxy
1228  * @param vfw_pipe
1229  *  A pointer to VFW pipeline.
1230  */
1231
1232 static void
1233 pkt4_work_vfw_arp_ipv6_packets(struct rte_mbuf **pkts,
1234               uint16_t pkt_num,
1235               uint64_t *pkts_mask,
1236               uint64_t synproxy_reply_mask,
1237               struct pipeline_vfw *vfw_pipe)
1238 {
1239        uint8_t nh_ipv6[IPV6_ADD_SIZE];
1240        uint32_t ret;
1241        struct ether_addr hw_addr;
1242        struct mbuf_tcp_meta_data *meta_data_addr;
1243        struct ether_hdr *ehdr;
1244        struct rte_mbuf *pkt;
1245        uint16_t phy_port;
1246        uint8_t i;
1247
1248        for (i = 0; i < 4; i++) {
1249               uint32_t dest_if = INVALID_DESTIF;
1250               /* bitmask representing only this packet */
1251               uint64_t pkt_mask = 1LLU << (pkt_num + i);
1252
1253               pkt = pkts[i];
1254
1255               if(!(*pkts_mask & pkt_mask))
1256                      continue;
1257               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1258
1259               phy_port = pkt->port;
1260               meta_data_addr = (struct mbuf_tcp_meta_data *)
1261                      RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1262               ehdr = rte_vfw_get_ether_addr(pkt);
1263
1264               struct ipv6_hdr *ihdr = (struct ipv6_hdr *)
1265                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1266
1267               uint8_t nhip[IPV6_ADD_SIZE];
1268               uint8_t dest_address[IPV6_ADD_SIZE];
1269
1270               memset(nhip, 0, IPV6_ADD_SIZE);
1271
1272               rte_mov16(dest_address, ihdr->dst_addr);
1273               ret = local_get_nh_ipv6(&dest_address[0], &dest_if,
1274                             &nhip[0], vfw_pipe);
1275               if (must_reverse) {
1276                      rte_sp_exchange_mac_addresses(ehdr);
1277                      if (is_phy_port_privte(phy_port)) {
1278                             if (!ret) {
1279                                    dest_if = get_pub_to_prv_port(
1280                                                  (uint32_t *)
1281                                                  &dest_address[0],
1282                                                  IP_VERSION_6);
1283                                    if (dest_if == INVALID_DESTIF) {
1284                                           *pkts_mask &= ~pkt_mask;
1285                                           vfw_pipe->counters->
1286                                           pkts_drop_without_arp_entry++;
1287                                    }
1288                                    do_local_nh_ipv6_cache(dest_if,
1289                                                  vfw_pipe);
1290                             }
1291
1292                      } else {
1293                             if (!ret) {
1294                                    dest_if = get_prv_to_pub_port(
1295                                                  (uint32_t *)
1296                                                  &dest_address[0],
1297                                                  IP_VERSION_6);
1298                                    if (dest_if == INVALID_DESTIF) {
1299                                           *pkts_mask &= ~pkt_mask;
1300                                           vfw_pipe->counters->
1301                                           pkts_drop_without_arp_entry++;
1302                                    }
1303                                    do_local_nh_ipv6_cache(dest_if,
1304                                                  vfw_pipe);
1305                             }
1306                      }
1307
1308               } else if (is_phy_port_privte(phy_port)) {
1309                      if (!ret) {
1310                             dest_if = get_prv_to_pub_port((uint32_t *)
1311                                           &dest_address[0], IP_VERSION_6);
1312                             if (dest_if == INVALID_DESTIF) {
1313                                    *pkts_mask &= ~pkt_mask;
1314                                    vfw_pipe->counters->
1315                                           pkts_drop_without_arp_entry++;
1316                             }
1317                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1318                      }
1319
1320               } else {
1321                      if (!ret) {
1322                             dest_if = get_pub_to_prv_port((uint32_t *)
1323                                           &dest_address[0], IP_VERSION_6);
1324                             if (dest_if == INVALID_DESTIF) {
1325                                    *pkts_mask &= ~pkt_mask;
1326                                    vfw_pipe->counters->
1327                                           pkts_drop_without_arp_entry++;
1328
1329                             }
1330                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1331                      }
1332
1333               }
1334
1335               meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1336
1337               memset(nh_ipv6, 0, IPV6_ADD_SIZE);
1338               if (get_dest_mac_address_ipv6_port(
1339                                    &dest_address[0],
1340                                    &dest_if,
1341                                    &hw_addr,
1342                                    &nh_ipv6[0])) {
1343                      ether_addr_copy(&hw_addr, &ehdr->d_addr);
1344                      ether_addr_copy(get_link_hw_addr(dest_if),
1345                                    &ehdr->s_addr);
1346
1347                      if (vfw_debug >= DEBUG_LEVEL_4) {
1348                             char buf[HW_ADDR_SIZE];
1349
1350                             ether_format_addr(buf, sizeof(buf),
1351                                           &hw_addr);
1352                             printf("MAC found for  dest_if %d: %s, ",
1353                                           dest_if, buf);
1354                             ether_format_addr(buf, sizeof(buf),
1355                                           &ehdr->s_addr);
1356                             printf("new eth hdr src: %s, ", buf);
1357                             ether_format_addr(buf, sizeof(buf),
1358                                           &ehdr->d_addr);
1359                             printf("new eth hdr dst: %s\n", buf);
1360                      }
1361
1362               } else {
1363                      printf("deleting ipv6\n");
1364                      *pkts_mask &= ~pkt_mask;
1365                      /*Next Neighbor is not yet implemented
1366                       * for ipv6.*/
1367                      vfw_pipe->counters->
1368                             pkts_drop_without_arp_entry++;
1369               }
1370
1371        }
1372 }
1373
1374
1375 /**
1376  * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
1377  * To support synproxy, some (altered) packets may need to be sent back where
1378  * they came from. The ip header has already been adjusted, but the ethernet
1379  * header has not, so this must be performed here.
1380  * Return an updated pkts_mask, since arp may drop some packets
1381  *
1382  * @param pkts
1383  *  A pointer to the packets.
1384  * @param pkt_num
1385  *  Packet number to process.
1386  * @param pkts_mask
1387  *  Packet mask pointer
1388  * @param synproxy_reply_mask
1389  *  Reply Packet mask for Synproxy
1390  * @param vfw_pipe
1391  *  A pointer to VFW pipeline.
1392  */
1393
1394 static void
1395 pkt_work_vfw_arp_ipv6_packets(struct rte_mbuf *pkts,
1396               uint16_t pkt_num,
1397               uint64_t *pkts_mask,
1398               uint64_t synproxy_reply_mask,
1399               struct pipeline_vfw *vfw_pipe)
1400 {
1401        uint8_t nh_ipv6[IPV6_ADD_SIZE];
1402        uint32_t ret;
1403        struct ether_addr hw_addr;
1404        struct mbuf_tcp_meta_data *meta_data_addr;
1405        struct ether_hdr *ehdr;
1406        struct rte_mbuf *pkt;
1407        uint16_t phy_port;
1408
1409        uint32_t dest_if = INVALID_DESTIF;
1410        /* bitmask representing only this packet */
1411        uint64_t pkt_mask = 1LLU << pkt_num;
1412
1413        pkt = pkts;
1414
1415        if(*pkts_mask & pkt_mask) {
1416
1417               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1418
1419               phy_port = pkt->port;
1420               meta_data_addr = (struct mbuf_tcp_meta_data *)
1421                      RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1422               ehdr = rte_vfw_get_ether_addr(pkt);
1423
1424               struct ipv6_hdr *ihdr = (struct ipv6_hdr *)
1425                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1426
1427               uint8_t nhip[IPV6_ADD_SIZE];
1428               uint8_t dest_address[IPV6_ADD_SIZE];
1429
1430               memset(nhip, 0, IPV6_ADD_SIZE);
1431
1432               rte_mov16(dest_address, ihdr->dst_addr);
1433               ret = local_get_nh_ipv6(&dest_address[0], &dest_if,
1434                             &nhip[0], vfw_pipe);
1435               if (must_reverse) {
1436                      rte_sp_exchange_mac_addresses(ehdr);
1437                      if (is_phy_port_privte(phy_port)) {
1438                             if (!ret) {
1439                                    dest_if = get_pub_to_prv_port(
1440                                                  (uint32_t *)
1441                                                  &dest_address[0],
1442                                                  IP_VERSION_6);
1443                                    if (dest_if == INVALID_DESTIF) {
1444                                           *pkts_mask &= ~pkt_mask;
1445                                           vfw_pipe->counters->
1446                                           pkts_drop_without_arp_entry++;
1447                                    }
1448                                    do_local_nh_ipv6_cache(dest_if,
1449                                                  vfw_pipe);
1450                             }
1451
1452                      } else {
1453                             if (!ret) {
1454                                    dest_if = get_prv_to_pub_port(
1455                                                  (uint32_t *)
1456                                                  &dest_address[0],
1457                                                  IP_VERSION_6);
1458                                    if (dest_if == INVALID_DESTIF) {
1459                                           *pkts_mask &= ~pkt_mask;
1460                                           vfw_pipe->counters->
1461                                           pkts_drop_without_arp_entry++;
1462                                    }
1463                                    do_local_nh_ipv6_cache(dest_if,
1464                                                  vfw_pipe);
1465                             }
1466                      }
1467
1468               } else if (is_phy_port_privte(phy_port)) {
1469                      if (!ret) {
1470                             dest_if = get_prv_to_pub_port((uint32_t *)
1471                                           &dest_address[0], IP_VERSION_6);
1472                             if (dest_if == INVALID_DESTIF) {
1473                                    *pkts_mask &= ~pkt_mask;
1474                                    vfw_pipe->counters->
1475                                           pkts_drop_without_arp_entry++;
1476                             }
1477                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1478                      }
1479
1480               } else {
1481                      if (!ret) {
1482                             dest_if = get_pub_to_prv_port((uint32_t *)
1483                                           &dest_address[0], IP_VERSION_6);
1484                             if (dest_if == INVALID_DESTIF) {
1485                                    *pkts_mask &= ~pkt_mask;
1486                                    vfw_pipe->counters->
1487                                           pkts_drop_without_arp_entry++;
1488
1489                             }
1490                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1491                      }
1492
1493               }
1494
1495               meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1496
1497               memset(nh_ipv6, 0, IPV6_ADD_SIZE);
1498               if (get_dest_mac_address_ipv6_port(
1499                                    &dest_address[0],
1500                                    &dest_if,
1501                                    &hw_addr,
1502                                    &nh_ipv6[0])) {
1503                      ether_addr_copy(&hw_addr, &ehdr->d_addr);
1504                      ether_addr_copy(get_link_hw_addr(dest_if),
1505                                    &ehdr->s_addr);
1506
1507                      if (vfw_debug >= DEBUG_LEVEL_4) {
1508                             char buf[HW_ADDR_SIZE];
1509
1510                             ether_format_addr(buf, sizeof(buf),
1511                                           &hw_addr);
1512                             printf("MAC found for  dest_if %d: %s, ",
1513                                           dest_if, buf);
1514                             ether_format_addr(buf, sizeof(buf),
1515                                           &ehdr->s_addr);
1516                             printf("new eth hdr src: %s, ", buf);
1517                             ether_format_addr(buf, sizeof(buf),
1518                                           &ehdr->d_addr);
1519                             printf("new eth hdr dst: %s\n", buf);
1520                      }
1521
1522               } else {
1523                      printf("deleting ipv6\n");
1524                      *pkts_mask &= ~pkt_mask;
1525                      /*Next Neighbor is not yet implemented
1526                       * for ipv6.*/
1527                      vfw_pipe->counters->
1528                             pkts_drop_without_arp_entry++;
1529               }
1530
1531        }
1532
1533 }
1534
1535 #else
1536
1537 /**
1538  * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
1539  * To support synproxy, some (altered) packets may need to be sent back where
1540  * they came from. The ip header has already been adjusted, but the ethernet
1541  * header has not, so this must be performed here.
1542  * Return an updated pkts_mask, since arp may drop some packets
1543  *
1544  * @param pkts
1545  *  A pointer to the packet.
1546  * @param pkts_mask
1547  *  Packet mask
1548  * @param synproxy_reply_mask
1549  *  Reply Packet mask for Synproxy
1550  * @param vfw_pipe
1551  *  A pointer to VFW pipeline.
1552  */
1553 static uint64_t
1554 rte_vfw_arp_ipv4_packets(struct rte_mbuf **pkts,
1555               uint64_t pkts_mask,
1556               uint64_t synproxy_reply_mask,
1557               struct pipeline_vfw *vfw_pipe)
1558 {
1559        uint64_t pkts_to_arp = pkts_mask;
1560
1561        uint32_t ret;
1562        uint32_t dest_if = INVALID_DESTIF;
1563        for (; pkts_to_arp;) {
1564               struct ether_addr hw_addr;
1565               struct mbuf_tcp_meta_data *meta_data_addr;
1566               struct ether_hdr *ehdr;
1567               struct rte_mbuf *pkt;
1568               uint16_t phy_port;
1569
1570               uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_arp);
1571               /* bitmask representing only this packet */
1572               uint64_t pkt_mask = 1LLU << pos;
1573               /* remove this packet from remaining list */
1574               pkts_to_arp &= ~pkt_mask;
1575               pkt = pkts[pos];
1576               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1577
1578               phy_port = pkt->port;
1579               meta_data_addr = (struct mbuf_tcp_meta_data *)
1580                      RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1581               ehdr = rte_vfw_get_ether_addr(pkt);
1582
1583
1584               struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
1585                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1586               uint32_t nhip = 0;
1587
1588               uint32_t dest_address = rte_bswap32(ihdr->dst_addr);
1589               if (must_reverse)
1590                      rte_sp_exchange_mac_addresses(ehdr);
1591 #if 0
1592               ret = local_get_nh_ipv4(dest_address, &dest_if,
1593                             &nhip, vfw_pipe);
1594               if (must_reverse) {
1595                      rte_sp_exchange_mac_addresses(ehdr);
1596                      if (is_phy_port_privte(phy_port)) {
1597                             if (!ret) {
1598                                    dest_if = get_pub_to_prv_port(
1599                                                  &dest_address,
1600                                                  IP_VERSION_4);
1601                                    if (dest_if == INVALID_DESTIF) {
1602                                           pkts_mask &= ~pkt_mask;
1603                                           vfw_pipe->counters->
1604                                           pkts_drop_without_arp_entry++;
1605                                    }
1606                                    do_local_nh_ipv4_cache(
1607                                                  dest_if, vfw_pipe);
1608                             }
1609
1610                      } else {
1611                             if (!ret) {
1612                                    dest_if = get_prv_to_pub_port(
1613                                                  &dest_address,
1614                                                  IP_VERSION_4);
1615                                    if (dest_if == INVALID_DESTIF) {
1616                                           pkts_mask &= ~pkt_mask;
1617                                           vfw_pipe->counters->
1618                                           pkts_drop_without_arp_entry++;
1619                                    }
1620                                    do_local_nh_ipv4_cache(dest_if,
1621                                                  vfw_pipe);
1622                             }
1623                      }
1624               } else if (is_phy_port_privte(phy_port)) {
1625                      if (!ret) {
1626                             dest_if = get_prv_to_pub_port(&dest_address,
1627                                           IP_VERSION_4);
1628                             if (dest_if == INVALID_DESTIF) {
1629                                    pkts_mask &= ~pkt_mask;
1630                                    vfw_pipe->counters->
1631                                           pkts_drop_without_arp_entry++;
1632                             }
1633                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1634                      }
1635
1636               } else {
1637                      if (!ret) {
1638                             dest_if = get_pub_to_prv_port(&dest_address,
1639                                           IP_VERSION_4);
1640                             if (dest_if == INVALID_DESTIF) {
1641                                    pkts_mask &= ~pkt_mask;
1642                                    vfw_pipe->counters->
1643                                           pkts_drop_without_arp_entry++;
1644                             }
1645                             do_local_nh_ipv4_cache(dest_if, vfw_pipe);
1646                      }
1647
1648               }
1649               meta_data_addr->output_port =  vfw_pipe->outport_id[dest_if];
1650               if (local_dest_mac_present(dest_if)) {
1651                      ether_addr_copy(get_local_link_hw_addr(dest_if),
1652                                    &ehdr->d_addr);
1653                      ether_addr_copy(get_link_hw_addr(dest_if),
1654                                    &ehdr->s_addr);
1655               } else {
1656 #endif
1657                 struct arp_entry_data *ret_arp_data = NULL;
1658                      ret_arp_data = get_dest_mac_addr_port(dest_address,
1659                                    &dest_if, &ehdr->d_addr);
1660                 meta_data_addr->output_port =  vfw_pipe->outport_id[dest_if];
1661         if (arp_cache_dest_mac_present(dest_if)) {
1662
1663                 ether_addr_copy(get_link_hw_addr(dest_if), &ehdr->s_addr);
1664                 arp_data_ptr[dest_if]->n_last_update = time(NULL);
1665
1666                 if (unlikely(ret_arp_data && ret_arp_data->num_pkts)) {
1667
1668                         printf("sending buffered packets\n");
1669                         p_nat->naptedPktCount += ret_arp_data->num_pkts;
1670                         arp_send_buffered_pkts(ret_arp_data,
1671                                  &ehdr->d_addr, vfw_pipe->outport_id[dest_if]);
1672
1673                             }
1674
1675                      } else {
1676                 if (unlikely(ret_arp_data == NULL)) {
1677
1678                         printf("%s: NHIP Not Found, nhip:%x , "
1679                         "outport_id: %d\n", __func__, nhip,
1680                         vfw_pipe->outport_id[dest_if]);
1681
1682                         /* Drop the pkt */
1683                                    vfw_pipe->counters->
1684                                           pkts_drop_without_arp_entry++;
1685                         continue;
1686                      }
1687                 if (ret_arp_data->status == INCOMPLETE ||
1688                            ret_arp_data->status == PROBE) {
1689                                 if (ret_arp_data->num_pkts >= NUM_DESC) {
1690                      /* ICMP req sent, drop packet by
1691                       * changing the mask */
1692                                         vfw_pipe->counters->
1693                                           pkts_drop_without_arp_entry++;
1694                                         continue;
1695                                 } else {
1696                                         arp_pkts_mask |= pkt_mask;
1697                                         arp_queue_unresolved_packet(ret_arp_data, pkt);
1698                                         continue;
1699               }
1700 }
1701         }
1702
1703        }
1704
1705        return pkts_mask;
1706 }
1707 /**
1708  * walk every valid mbuf (denoted by pkts_mask) and apply arp to the packet.
1709  * To support synproxy, some (altered) packets may need to be sent back where
1710  * they came from. The ip header has already been adjusted, but the ethernet
1711  * header has not, so this must be performed here.
1712  * Return an updated pkts_mask, since arp may drop some packets
1713  *
1714  * @param pkts
1715  *  A pointer to the packet.
1716  * @param pkts_mask
1717  *  Packet mask
1718  * @param synproxy_reply_mask
1719  *  Reply Packet mask for Synproxy
1720  * @param vfw_pipe
1721  *  A pointer to VFW pipeline.
1722  */
1723
1724        static uint64_t
1725 rte_vfw_arp_ipv6_packets(struct rte_mbuf **pkts,
1726               uint64_t pkts_mask,
1727               uint64_t synproxy_reply_mask,
1728               struct pipeline_vfw *vfw_pipe)
1729 {
1730        uint64_t pkts_to_arp = pkts_mask;
1731        uint8_t nh_ipv6[IPV6_ADD_SIZE];
1732        uint32_t ret;
1733        uint32_t dest_if = INVALID_DESTIF;
1734
1735        for (; pkts_to_arp;) {
1736               struct ether_addr hw_addr;
1737               struct mbuf_tcp_meta_data *meta_data_addr;
1738               struct ether_hdr *ehdr;
1739               struct rte_mbuf *pkt;
1740               uint16_t phy_port;
1741
1742               uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_arp);
1743               /* bitmask representing only this packet */
1744               uint64_t pkt_mask = 1LLU << pos;
1745               /* remove this packet from remaining list */
1746               pkts_to_arp &= ~pkt_mask;
1747               pkt = pkts[pos];
1748               int must_reverse = ((synproxy_reply_mask & pkt_mask) != 0);
1749
1750               phy_port = pkt->port;
1751               meta_data_addr = (struct mbuf_tcp_meta_data *)
1752                      RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1753               ehdr = rte_vfw_get_ether_addr(pkt);
1754
1755               struct ipv6_hdr *ihdr = (struct ipv6_hdr *)
1756                      RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1757
1758               uint8_t nhip[IPV6_ADD_SIZE];
1759               uint8_t dest_address[IPV6_ADD_SIZE];
1760
1761               memset(nhip, 0, IPV6_ADD_SIZE);
1762
1763               rte_mov16(dest_address, ihdr->dst_addr);
1764               ret = local_get_nh_ipv6(&dest_address[0], &dest_if,
1765                             &nhip[0], vfw_pipe);
1766               if (must_reverse) {
1767                      rte_sp_exchange_mac_addresses(ehdr);
1768                      if (is_phy_port_privte(phy_port)) {
1769                             if (!ret) {
1770                                    dest_if = get_pub_to_prv_port(
1771                                                  (uint32_t *)
1772                                                  &dest_address[0],
1773                                                  IP_VERSION_6);
1774                                    if (dest_if == INVALID_DESTIF) {
1775                                           pkts_mask &= ~pkt_mask;
1776                                           vfw_pipe->counters->
1777                                           pkts_drop_without_arp_entry++;
1778                                    }
1779                                    do_local_nh_ipv6_cache(dest_if,
1780                                                  vfw_pipe);
1781                             }
1782
1783                      } else {
1784                             if (!ret) {
1785                                    dest_if = get_prv_to_pub_port(
1786                                                  (uint32_t *)
1787                                                  &dest_address[0],
1788                                                  IP_VERSION_6);
1789                                    if (dest_if == INVALID_DESTIF) {
1790                                           pkts_mask &= ~pkt_mask;
1791                                           vfw_pipe->counters->
1792                                           pkts_drop_without_arp_entry++;
1793                                    }
1794                                    do_local_nh_ipv6_cache(dest_if,
1795                                                  vfw_pipe);
1796                             }
1797                      }
1798
1799               } else if (is_phy_port_privte(phy_port)) {
1800                      if (!ret) {
1801                             dest_if = get_prv_to_pub_port((uint32_t *)
1802                                           &dest_address[0], IP_VERSION_6);
1803                             if (dest_if == INVALID_DESTIF) {
1804                                    pkts_mask &= ~pkt_mask;
1805                                    vfw_pipe->counters->
1806                                           pkts_drop_without_arp_entry++;
1807                             }
1808                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1809                      }
1810
1811               } else {
1812                      if (!ret) {
1813                             dest_if = get_pub_to_prv_port((uint32_t *)
1814                                           &dest_address[0], IP_VERSION_6);
1815                             if (dest_if == INVALID_DESTIF) {
1816                                    pkts_mask &= ~pkt_mask;
1817                                    vfw_pipe->counters->
1818                                           pkts_drop_without_arp_entry++;
1819
1820                             }
1821                             do_local_nh_ipv6_cache(dest_if, vfw_pipe);
1822                      }
1823
1824               }
1825
1826               meta_data_addr->output_port = vfw_pipe->outport_id[dest_if];
1827
1828               memset(nh_ipv6, 0, IPV6_ADD_SIZE);
1829               if (get_dest_mac_address_ipv6_port(
1830                                    &dest_address[0],
1831                                    &dest_if,
1832                                    &hw_addr,
1833                                    &nh_ipv6[0])) {
1834                      ether_addr_copy(&hw_addr, &ehdr->d_addr);
1835                      ether_addr_copy(get_link_hw_addr(dest_if),
1836                                    &ehdr->s_addr);
1837
1838                      if (vfw_debug >= DEBUG_LEVEL_4) {
1839                             char buf[HW_ADDR_SIZE];
1840
1841                             ether_format_addr(buf, sizeof(buf),
1842                                           &hw_addr);
1843                             printf("MAC found for  dest_if %d: %s, ",
1844                                           dest_if, buf);
1845                             ether_format_addr(buf, sizeof(buf),
1846                                           &ehdr->s_addr);
1847                             printf("new eth hdr src: %s, ", buf);
1848                             ether_format_addr(buf, sizeof(buf),
1849                                           &ehdr->d_addr);
1850                             printf("new eth hdr dst: %s\n", buf);
1851                      }
1852
1853               } else {
1854                      printf("deleting ipv6\n");
1855                      pkts_mask &= ~pkt_mask;
1856                      /*Next Neighbor is not yet implemented
1857                       * for ipv6.*/
1858                      vfw_pipe->counters->
1859                             pkts_drop_without_arp_entry++;
1860               }
1861
1862
1863        }
1864
1865        return pkts_mask;
1866 }
1867
1868 #endif
1869 /**
1870  * Packets processing for connection tracking.
1871  *
1872  * @param vfw_pipe
1873  *  A pointer to the pipeline.
1874  * @param ct
1875  *  A pointer to the connetion tracker .
1876  * @param pkts
1877  *  A pointer to a burst of packets.
1878  * @param packet_mask_in
1879  *  Input packets Mask.
1880  */
1881
1882        static  uint64_t
1883 vfw_process_buffered_pkts(__rte_unused struct pipeline_vfw *vfw_pipe,
1884               struct rte_ct_cnxn_tracker *ct,
1885                           struct rte_mbuf **pkts, uint64_t packet_mask_in)
1886 {
1887        uint64_t keep_mask = packet_mask_in;
1888        struct rte_synproxy_helper sp_helper;       /* for synproxy */
1889
1890        keep_mask =
1891            rte_ct_cnxn_tracker_batch_lookup_with_synproxy(ct, pkts, keep_mask,
1892                                                     &sp_helper);
1893
1894        if (unlikely(sp_helper.hijack_mask))
1895               printf("buffered hijack pkts severe error\n");
1896
1897        if (unlikely(sp_helper.reply_pkt_mask))
1898               printf("buffered reply pkts severe error\n");
1899
1900        return keep_mask;
1901 }
1902
1903 /**
1904  * Free Packets from mbuf.
1905  *
1906  * @param ct
1907  *  A pointer to the connection tracker to increment drop counter.
1908  *
1909  * @param pkt
1910  *  Packet to be free.
1911  */
1912 static inline void
1913 vfw_pktmbuf_free(struct rte_ct_cnxn_tracker *ct, struct rte_mbuf *pkt)
1914 {
1915        ct->counters->pkts_drop++;
1916        rte_pktmbuf_free(pkt);
1917 }
1918
1919 static void
1920 vfw_output_or_delete_buffered_packets(struct rte_ct_cnxn_tracker *ct,
1921                                     struct rte_pipeline *p,
1922                                     struct rte_mbuf **pkts,
1923                                     int num_pkts, uint64_t pkts_mask)
1924 {
1925        int i;
1926        struct mbuf_tcp_meta_data *meta_data_addr;
1927        uint64_t pkt_mask = 1;
1928
1929        /* any clear bits in low-order num_pkts bit of
1930         * pkt_mask must be discarded */
1931
1932        for (i = 0; i < num_pkts; i++) {
1933               struct rte_mbuf *pkt = pkts[i];
1934
1935               if (pkts_mask & pkt_mask) {
1936                      printf("vfw_output_or_delete_buffered_packets\n");
1937                      meta_data_addr = (struct mbuf_tcp_meta_data *)
1938                          RTE_MBUF_METADATA_UINT32_PTR(pkt, META_DATA_OFFSET);
1939                      rte_pipeline_port_out_packet_insert(
1940                                    p, meta_data_addr->output_port, pkt);
1941
1942               } else {
1943                      vfw_pktmbuf_free(ct, pkt);
1944               }
1945
1946               pkt_mask = pkt_mask << 1;
1947        }
1948 }
1949
1950 /**
1951  *Packet buffered for synproxy.
1952  *
1953  * @param p
1954  *  A pointer to the pipeline.
1955  * @param vfw_pipe
1956  *  A pointer to the vfw pipeline.
1957  * @param ct
1958  *  A pointer to the connection tracker.
1959  * @param forward_pkts
1960  *  Packet forwarded by synproxy.
1961  *
1962  */
1963 static void
1964 vfw_handle_buffered_packets(struct rte_pipeline *p,
1965                             struct pipeline_vfw *vfw_pipe,
1966                             struct rte_ct_cnxn_tracker *ct, int forward_pkts)
1967 {
1968        struct rte_mbuf *pkt_list = rte_ct_get_buffered_synproxy_packets(ct);
1969
1970        if (likely(pkt_list == NULL))       /* only during proxy setup is != NULL */
1971               return;
1972
1973        int pkt_count = 0;
1974        uint64_t keep_mask = 0;
1975        struct rte_mbuf **pkts = vfw_pipe->pkt_buffer;
1976        struct rte_mbuf *pkt;
1977
1978        while (pkt_list != NULL) {
1979               struct mbuf_tcp_meta_data *meta_data =
1980               (struct mbuf_tcp_meta_data *)
1981               RTE_MBUF_METADATA_UINT32_PTR(pkt_list, META_DATA_OFFSET);
1982
1983               /* detach head of list and advance list */
1984               pkt = pkt_list;
1985               pkt_list = meta_data->next;
1986
1987               if (forward_pkts) {
1988
1989                      pkts[pkt_count++] = pkt;
1990
1991                      if (pkt_count == PKT_BUFFER_SIZE) {
1992                             /* need to send out packets */
1993                             /* currently 0, set all bits */
1994                             keep_mask = ~keep_mask;
1995
1996                             keep_mask =
1997                                 vfw_process_buffered_pkts(vfw_pipe,
1998                                                          ct, pkts,
1999                                                          keep_mask);
2000                             vfw_output_or_delete_buffered_packets(
2001                                           ct, p,
2002                                           pkts,
2003                                           PKT_BUFFER_SIZE,
2004                                           keep_mask);
2005                             pkt_count = 0;
2006                             keep_mask = 0;
2007                      }
2008
2009               } else {
2010                      vfw_pktmbuf_free(ct, pkt);
2011               }
2012        }
2013
2014        if (pkt_count != 0) {
2015               /* need to send out packets */
2016               keep_mask = RTE_LEN2MASK(pkt_count, uint64_t);
2017
2018               keep_mask =
2019                      vfw_process_buffered_pkts(vfw_pipe, ct, pkts,
2020                                    keep_mask);
2021
2022               vfw_output_or_delete_buffered_packets(ct, p, pkts, pkt_count,
2023                             keep_mask);
2024
2025               pkt_count = 0;
2026               keep_mask = 0;
2027        }
2028 }
2029 /**
2030  * The pipeline port-in action is used to do all the firewall and
2031  * connection tracking work for IPV4 packets.
2032  *
2033  * @param p
2034  *  A pointer to the pipeline.
2035   * @param pkts
2036  *  A pointer to a burst of packets.
2037  * @param n_pkts
2038  *  Number of packets to process.
2039  * @param arg
2040  *  A pointer to pipeline specific data.
2041  *
2042  * @return
2043  *  0 on success, negative on error.
2044  */
2045
2046 static int
2047 vfw_port_in_action_ipv4(struct rte_pipeline *p,
2048               struct rte_mbuf **pkts,
2049               __rte_unused uint32_t n_pkts, __rte_unused void *arg)
2050 {
2051        struct vfw_ports_in_args *port_in_args =
2052               (struct vfw_ports_in_args *)arg;
2053        struct pipeline_vfw *vfw_pipe =
2054               (struct pipeline_vfw *)port_in_args->pipe;
2055        struct rte_ct_cnxn_tracker *ct = port_in_args->cnxn_tracker;
2056
2057        start_tsc_measure(vfw_pipe);
2058
2059        uint64_t packet_mask_in = RTE_LEN2MASK(n_pkts, uint64_t);
2060        uint64_t pkts_drop_mask;
2061        uint64_t hijack_mask = 0;
2062        arp_pkts_mask = 0;
2063        uint64_t synproxy_reply_mask = 0;       /* for synproxy */
2064        uint64_t keep_mask = packet_mask_in;
2065
2066        uint64_t conntrack_mask = 0, connexist_mask = 0;
2067        struct rte_CT_helper ct_helper;
2068        uint8_t j;
2069
2070        /*
2071         * This routine uses a bit mask to represent which packets in the
2072         * "pkts" table are considered valid. Any table entry which exists
2073         * and is considered valid has the corresponding bit in the mask set.
2074         * Otherwise, it is cleared. Note that the mask is 64 bits,
2075         * but the number of packets in the table may be considerably less.
2076         * Any mask bits which do correspond to actual packets are cleared.
2077         * Various routines are called which may determine that an existing
2078         * packet is somehow invalid. The routine will return an altered bit
2079         * mask, with the bit cleared. At the end of all the checks,
2080         * packets are dropped if their mask bit is a zero
2081         */
2082
2083        rte_prefetch0(& vfw_pipe->counters);
2084
2085 #ifdef EN_SWP_ACL
2086        /* Pre-fetch all rte_mbuf header */
2087        for(j = 0; j < n_pkts; j++)
2088               rte_prefetch0(pkts[j]);
2089 #endif
2090        memset(&ct_helper, 0, sizeof(struct rte_CT_helper));
2091 #ifdef EN_SWP_ACL
2092        rte_prefetch0(& vfw_pipe->counters->pkts_drop_ttl);
2093        rte_prefetch0(& vfw_pipe->counters->sum_latencies);
2094 #endif
2095
2096        if (unlikely(vfw_debug > 1))
2097               printf("Enter in-port action IPV4 with %p packet mask\n",
2098                             (void *)packet_mask_in);
2099        vfw_pipe->counters->pkts_received =
2100               vfw_pipe->counters->pkts_received + n_pkts;
2101
2102        if (unlikely(VFW_DEBUG))
2103               printf("vfw_port_in_action_ipv4 pkts_received: %" PRIu64
2104                             " n_pkts: %u\n",
2105                             vfw_pipe->counters->pkts_received, n_pkts);
2106
2107        /* first handle handle any previously buffered packets now released */
2108        vfw_handle_buffered_packets(p, vfw_pipe, ct,
2109                      FORWARD_BUFFERED_PACKETS);
2110
2111        /* now handle any new packets on input ports */
2112        if (likely(firewall_flag)) {
2113               keep_mask = rte_vfw_ipv4_packet_filter_and_process(pkts,
2114                             keep_mask, vfw_pipe);
2115               vfw_pipe->counters->pkts_fw_forwarded +=
2116                      __builtin_popcountll(keep_mask);
2117        }
2118 #ifdef ACL_ENABLE
2119 #ifdef EN_SWP_ACL
2120        rte_prefetch0((void*)vfw_pipe->plib_acl);
2121        rte_prefetch0((void*)vfw_rule_table_ipv4_active);
2122 #endif /* EN_SWP_ACL */
2123        keep_mask = lib_acl_ipv4_pkt_work_key(
2124                      vfw_pipe->plib_acl, pkts, keep_mask,
2125                      &vfw_pipe->counters->pkts_drop_without_rule,
2126                      vfw_rule_table_ipv4_active,
2127                      action_array_active,
2128                      action_counter_table,
2129                      &conntrack_mask, &connexist_mask);
2130        vfw_pipe->counters->pkts_acl_forwarded +=
2131               __builtin_popcountll(keep_mask);
2132        if (conntrack_mask > 0) {
2133               keep_mask = conntrack_mask;
2134               ct_helper.no_new_cnxn_mask = connexist_mask;
2135               cnxn_tracking_is_active = 1;
2136        } else
2137               cnxn_tracking_is_active = 0;
2138 #endif /* ACL_ENABLE */
2139
2140        if (likely(cnxn_tracking_is_active)) {
2141               rte_ct_cnxn_tracker_batch_lookup_type(ct, pkts,
2142                             &keep_mask, &ct_helper, IPv4_HEADER_SIZE);
2143               synproxy_reply_mask = ct_helper.reply_pkt_mask;
2144               hijack_mask = ct_helper.hijack_mask;
2145
2146        }
2147
2148 #ifdef EN_SWP_ARP
2149        for(j = 0; j < (n_pkts & 0x3LLU); j++) {
2150                rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2151                                    META_DATA_OFFSET));
2152                rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2153                                    ETHERNET_START));
2154        }
2155        rte_prefetch0((void*)in_port_dir_a);
2156        rte_prefetch0((void*)prv_to_pub_map);
2157
2158        uint8_t i;
2159        for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
2160               for (j = i+4; ((j < n_pkts) && (j < i+8)); j++) {
2161                      rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2162                                           META_DATA_OFFSET));
2163                      rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2164                                           ETHERNET_START));
2165               }
2166               pkt4_work_vfw_arp_ipv4_packets(&pkts[i], i, &keep_mask,
2167                             synproxy_reply_mask, vfw_pipe);
2168        }
2169        for (j = i; j < n_pkts; j++) {
2170               rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2171                                    META_DATA_OFFSET));
2172               rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2173                                    ETHERNET_START));
2174        }
2175        for (; i < n_pkts; i++) {
2176               pkt_work_vfw_arp_ipv4_packets(pkts[i], i, &keep_mask,
2177                             synproxy_reply_mask, vfw_pipe);
2178        }
2179 #else
2180        rte_prefetch0((void*)in_port_dir_a);
2181        rte_prefetch0((void*)prv_to_pub_map);
2182        rte_prefetch0((void*) & vfw_pipe->local_lib_arp_route_table);
2183        keep_mask = rte_vfw_arp_ipv4_packets(pkts, keep_mask,
2184                      synproxy_reply_mask, vfw_pipe);
2185 #endif
2186
2187        if (vfw_debug > 1) {
2188               printf("  Exit in-port action with %p packet mask\n",
2189                             (void *)keep_mask);
2190               if (keep_mask != packet_mask_in)
2191                      printf("dropped packets, %p in, %p out\n",
2192                                    (void *)packet_mask_in,
2193                                    (void *)keep_mask);
2194        }
2195
2196        /* Update mask before returning, so that bad packets are dropped */
2197         if (arp_pkts_mask) {
2198                 rte_pipeline_ah_packet_hijack(p, arp_pkts_mask);
2199         }
2200
2201        pkts_drop_mask = packet_mask_in & ~keep_mask;
2202
2203        if (unlikely(pkts_drop_mask != 0)) {
2204               /* printf("drop %p\n", (void *) pkts_drop_mask); */
2205               rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
2206        }
2207
2208        if (unlikely(hijack_mask != 0))
2209               rte_pipeline_ah_packet_hijack(p, hijack_mask);
2210
2211        vfw_pipe->counters->num_batch_pkts_sum += n_pkts;
2212        vfw_pipe->counters->num_pkts_measurements++;
2213
2214        end_tsc_measure(vfw_pipe, n_pkts);
2215
2216        return 0;
2217 }
2218 /**
2219  * The pipeline port-in action is used to do all the firewall and
2220  * connection tracking work for IPV6 packet.
2221  *
2222  * @param p
2223  *  A pointer to the pipeline.
2224   * @param pkts
2225  *  A pointer to a burst of packets.
2226  * @param n_pkts
2227  *  Number of packets to process.
2228  * @param arg
2229  *  A pointer to pipeline specific data.
2230  *
2231  * @return
2232  *  0 on success, negative on error.
2233  */
2234
2235 static int
2236 vfw_port_in_action_ipv6(struct rte_pipeline *p,
2237               struct rte_mbuf **pkts,
2238               __rte_unused uint32_t n_pkts, __rte_unused void *arg)
2239 {
2240        struct vfw_ports_in_args *port_in_args =
2241               (struct vfw_ports_in_args *)arg;
2242        struct pipeline_vfw *vfw_pipe =
2243               (struct pipeline_vfw *)port_in_args->pipe;
2244        struct rte_ct_cnxn_tracker *ct = port_in_args->cnxn_tracker;
2245
2246        start_tsc_measure(vfw_pipe);
2247
2248        uint64_t packet_mask_in = RTE_LEN2MASK(n_pkts, uint64_t);
2249        uint64_t pkts_drop_mask;
2250        uint64_t hijack_mask = 0;
2251        uint64_t synproxy_reply_mask = 0;       /* for synproxy */
2252        uint64_t keep_mask = packet_mask_in;
2253
2254        uint64_t conntrack_mask = 0, connexist_mask = 0;
2255        struct rte_CT_helper ct_helper;
2256        uint32_t j;
2257
2258        /*
2259         * This routine uses a bit mask to represent which packets in the
2260         * "pkts" table are considered valid. Any table entry which exists
2261         * and is considered valid has the corresponding bit in the mask set.
2262         * Otherwise, it is cleared. Note that the mask is 64 bits,
2263         * but the number of packets in the table may be considerably less.
2264         * Any mask bits which do correspond to actual packets are cleared.
2265         * Various routines are called which may determine that an existing
2266         * packet is somehow invalid. The routine will return an altered bit
2267         * mask, with the bit cleared. At the end of all the checks,
2268         * packets are dropped if their mask bit is a zero
2269         */
2270
2271        rte_prefetch0(& vfw_pipe->counters);
2272
2273        /* Pre-fetch all rte_mbuf header */
2274        for(j = 0; j < n_pkts; j++)
2275                rte_prefetch0(pkts[j]);
2276
2277        memset(&ct_helper, 0, sizeof(struct rte_CT_helper));
2278        rte_prefetch0(& vfw_pipe->counters->pkts_drop_ttl);
2279        rte_prefetch0(& vfw_pipe->counters->sum_latencies);
2280
2281        if (vfw_debug > 1)
2282               printf("Enter in-port action with %p packet mask\n",
2283                             (void *)packet_mask_in);
2284        vfw_pipe->counters->pkts_received =
2285               vfw_pipe->counters->pkts_received + n_pkts;
2286        if (VFW_DEBUG)
2287               printf("vfw_port_in_action pkts_received: %" PRIu64
2288                             " n_pkts: %u\n",
2289                             vfw_pipe->counters->pkts_received, n_pkts);
2290
2291        /* first handle handle any previously buffered packets now released */
2292        vfw_handle_buffered_packets(p, vfw_pipe, ct,
2293                      FORWARD_BUFFERED_PACKETS);
2294
2295        /* now handle any new packets on input ports */
2296        if (likely(firewall_flag)) {
2297               keep_mask = rte_vfw_ipv6_packet_filter_and_process(pkts,
2298                             keep_mask, vfw_pipe);
2299               vfw_pipe->counters->pkts_fw_forwarded +=
2300                      __builtin_popcountll(keep_mask);
2301        }
2302 #ifdef ACL_ENABLE
2303
2304 #ifdef EN_SWP_ACL
2305        rte_prefetch0((void*)vfw_pipe->plib_acl);
2306        rte_prefetch0((void*)vfw_rule_table_ipv6_active);
2307 #endif /* EN_SWP_ACL */
2308        keep_mask = lib_acl_ipv6_pkt_work_key(
2309                      vfw_pipe->plib_acl, pkts, keep_mask,
2310                      &vfw_pipe->counters->pkts_drop_without_rule,
2311                      vfw_rule_table_ipv6_active,
2312                      action_array_active,
2313                      action_counter_table,
2314                      &conntrack_mask, &connexist_mask);
2315        vfw_pipe->counters->pkts_acl_forwarded +=
2316               __builtin_popcountll(keep_mask);
2317        if (conntrack_mask > 0) {
2318               keep_mask = conntrack_mask;
2319               ct_helper.no_new_cnxn_mask = connexist_mask;
2320               cnxn_tracking_is_active = 1;
2321        } else
2322               cnxn_tracking_is_active = 0;
2323 #endif /* ACL_ENABLE */
2324        if (likely(cnxn_tracking_is_active)) {
2325               rte_ct_cnxn_tracker_batch_lookup_type(ct, pkts,
2326                             &keep_mask, &ct_helper, IPv6_HEADER_SIZE);
2327               synproxy_reply_mask = ct_helper.reply_pkt_mask;
2328               hijack_mask = ct_helper.hijack_mask;
2329
2330        }
2331
2332 #ifdef EN_SWP_ARP
2333        for(j = 0; j < (n_pkts & 0x3LLU); j++) {
2334                rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2335                                    META_DATA_OFFSET));
2336                rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2337                                    ETHERNET_START));
2338        }
2339        rte_prefetch0((void*)in_port_dir_a);
2340        rte_prefetch0(vfw_pipe->local_lib_nd_route_table);
2341        uint32_t i;
2342
2343        for (i = 0; i < (n_pkts & (~0x3LLU)); i += 4) {
2344               for (j = i+4; ((j < n_pkts) && (j < i+8)); j++) {
2345                      rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2346                                           META_DATA_OFFSET));
2347                      rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2348                                           ETHERNET_START));
2349               }
2350               pkt4_work_vfw_arp_ipv6_packets(&pkts[i], i, &keep_mask,
2351                             synproxy_reply_mask, vfw_pipe);
2352        }
2353        for (j = i; j < n_pkts; j++) {
2354               rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2355                                    META_DATA_OFFSET));
2356               rte_prefetch0(RTE_MBUF_METADATA_UINT32_PTR(pkts[j],
2357                                    ETHERNET_START));
2358        }
2359        for (; i < n_pkts; i++) {
2360               pkt_work_vfw_arp_ipv6_packets(pkts[i], i, &keep_mask,
2361                             synproxy_reply_mask, vfw_pipe);
2362        }
2363 #else
2364        rte_prefetch0((void*)in_port_dir_a);
2365        rte_prefetch0((void*) & vfw_pipe->local_lib_arp_route_table);
2366        keep_mask = rte_vfw_arp_ipv6_packets(pkts, keep_mask,
2367                      synproxy_reply_mask, vfw_pipe);
2368 #endif
2369
2370        if (vfw_debug > 1) {
2371               printf("  Exit in-port action with %p packet mask\n",
2372                             (void *)keep_mask);
2373               if (keep_mask != packet_mask_in)
2374                      printf("dropped packets, %p in, %p out\n",
2375                                    (void *)packet_mask_in,
2376                                    (void *)keep_mask);
2377        }
2378
2379        /* Update mask before returning, so that bad packets are dropped */
2380
2381        pkts_drop_mask = packet_mask_in & ~keep_mask;
2382
2383        if (unlikely(pkts_drop_mask != 0)) {
2384               /* printf("drop %p\n", (void *) pkts_drop_mask); */
2385               rte_pipeline_ah_packet_drop(p, pkts_drop_mask);
2386        }
2387
2388        if (unlikely(hijack_mask != 0))
2389               rte_pipeline_ah_packet_hijack(p, hijack_mask);
2390
2391        vfw_pipe->counters->num_batch_pkts_sum += n_pkts;
2392        vfw_pipe->counters->num_pkts_measurements++;
2393
2394        end_tsc_measure(vfw_pipe, n_pkts);
2395
2396        return 0;
2397 }
2398
2399
2400 /**
2401  * Parse arguments in config file.
2402  *
2403  * @param vfw_pipe
2404  *  A pointer to the pipeline.
2405  * @param params
2406  *  A pointer to pipeline specific parameters.
2407  *
2408  * @return
2409  *  0 on success, negative on error.
2410  */
2411 static int
2412 pipeline_vfw_parse_args(struct pipeline_vfw *vfw_pipe,
2413               struct pipeline_params *params)
2414 {
2415        uint32_t i;
2416        int status;
2417
2418        if (vfw_debug)
2419               printf("VFW pipeline_vfw_parse_args params->n_args: %d\n",
2420                             params->n_args);
2421
2422        for (i = 0; i < params->n_args; i++) {
2423               char *arg_name = params->args_name[i];
2424               char *arg_value = params->args_value[i];
2425
2426               printf("VFW args[%d]: %s %d, %s\n", i, arg_name,
2427                             atoi(arg_value), arg_value);
2428 #ifdef ACL_ENABLE
2429               status = lib_acl_parse_config(vfw_pipe->plib_acl,
2430                                    arg_name, arg_value, &vfw_n_rules);
2431               if (status < 0) {
2432                      printf("rte_ct_set_configuration_options =%s,%s",
2433                                    arg_name, arg_value);
2434                      return -1;
2435               } else if (status == 0)
2436                      continue;
2437
2438 #endif              /* traffic_type */
2439               if (strcmp(arg_name, "traffic_type") == 0) {
2440                      int traffic_type = atoi(arg_value);
2441
2442                      if (traffic_type == 0 ||
2443                                    !(traffic_type == IP_VERSION_4 ||
2444                                           traffic_type == IP_VERSION_6)) {
2445                             printf("not IPV4/IPV6");
2446                             return -1;
2447                      }
2448
2449                      vfw_pipe->traffic_type = traffic_type;
2450                      continue;
2451               }
2452
2453
2454               /* n_flows */
2455               if (strcmp(arg_name, "n_flows") == 0) {
2456                      int n_flows = atoi(arg_value);
2457
2458                      if (n_flows == 0)
2459                             return -1;
2460
2461                      /* must be power of 2, round up if not */
2462                      if (!rte_is_power_of_2(n_flows))
2463                             n_flows = rte_align32pow2(n_flows);
2464
2465                      vfw_pipe->n_flows = n_flows;
2466                      continue;
2467               }
2468
2469               /* not firewall option, process as cnxn tracking option */
2470               status = rte_ct_set_configuration_options(
2471                             vfw_pipe->cnxn_tracker,
2472                             arg_name, arg_value);
2473               if (status < 0) {
2474                      printf("rte_ct_set_configuration_options =%s,%s",
2475                                    arg_name, arg_value);
2476                      return -1;
2477               } else if (status == 0)
2478                      continue;
2479
2480        }
2481
2482        return 0;
2483 }
2484
2485 static void *pipeline_vfw_msg_req_custom_handler(struct pipeline *p,
2486                                               void *msg);
2487
2488 static pipeline_msg_req_handler handlers[] = {
2489        [PIPELINE_MSG_REQ_PING] = pipeline_msg_req_ping_handler,
2490        [PIPELINE_MSG_REQ_STATS_PORT_IN] =
2491            pipeline_msg_req_stats_port_in_handler,
2492        [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
2493            pipeline_msg_req_stats_port_out_handler,
2494        [PIPELINE_MSG_REQ_STATS_TABLE] = pipeline_msg_req_stats_table_handler,
2495        [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
2496            pipeline_msg_req_port_in_enable_handler,
2497        [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
2498            pipeline_msg_req_port_in_disable_handler,
2499        [PIPELINE_MSG_REQ_CUSTOM] = pipeline_vfw_msg_req_custom_handler,
2500 };
2501
2502 static void *pipeline_vfw_msg_req_synproxy_flag_handler(struct pipeline *p,
2503                                                     void *msg);
2504 static pipeline_msg_req_handler custom_handlers[] = {
2505
2506        [PIPELINE_VFW_MSG_REQ_SYNPROXY_FLAGS] =
2507            pipeline_vfw_msg_req_synproxy_flag_handler
2508 };
2509
2510 /**
2511  * Create and initialize Pipeline Back End (BE).
2512  *
2513  * @param params
2514  *  A pointer to the pipeline specific parameters..
2515  * @param arg
2516  *  A pointer to pipeline specific data.
2517  *
2518  * @return
2519  *  A pointer to the pipeline create, NULL on error.
2520  */
2521 static void
2522 *pipeline_vfw_init(struct pipeline_params *params, __rte_unused void *arg)
2523 {
2524        uint32_t size, i;
2525
2526        /* Check input arguments */
2527        if ((params == NULL) ||
2528                      (params->n_ports_in == 0) || (params->n_ports_out == 0))
2529               return NULL;
2530
2531        if (vfw_debug)
2532               printf("num ports in %d / num ports out %d\n",
2533                             params->n_ports_in, params->n_ports_out);
2534
2535        /* Create a single pipeline instance and initialize. */
2536        struct pipeline_vfw *pipe_vfw;
2537
2538        size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_vfw));
2539        pipe_vfw = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
2540
2541        if (pipe_vfw == NULL)
2542               return NULL;
2543
2544        struct pipeline *pipe;
2545
2546        pipe = &pipe_vfw->pipe;
2547
2548        strncpy(pipe->name, params->name, sizeof(pipe->name));
2549        pipe->log_level = params->log_level;
2550        pipe_vfw->n_flows = 4096;       /* small default value */
2551        pipe_vfw->traffic_type = IP_VERSION_4;
2552        pipe_vfw->pipeline_num = 0xff;
2553        for (i = 0; i < PIPELINE_MAX_PORT_IN; i++) {
2554               pipe_vfw->links_map[i] = 0xff;
2555               pipe_vfw->outport_id[i] = 0xff;
2556        }
2557        PLOG(pipe, HIGH, "VFW");
2558
2559        /* Create a firewall instance and initialize. */
2560        pipe_vfw->cnxn_tracker =
2561               rte_zmalloc(NULL, rte_ct_get_cnxn_tracker_size(),
2562                             RTE_CACHE_LINE_SIZE);
2563
2564        if (pipe_vfw->cnxn_tracker == NULL)
2565               return NULL;
2566 #ifdef ACL_ENABLE
2567        /* Create a acl instance and initialize. */
2568        pipe_vfw->plib_acl =
2569               rte_zmalloc(NULL, sizeof(struct lib_acl),
2570                             RTE_CACHE_LINE_SIZE);
2571
2572        if (pipe_vfw->plib_acl == NULL)
2573               return NULL;
2574 #endif
2575        timer_lcore = rte_lcore_id();
2576        /*
2577         * Now allocate a counter block entry. It appears that the
2578         * initialization of all instances is serialized on core 0,
2579         * so no lock is necessary.
2580         */
2581        struct rte_VFW_counter_block *counter_ptr;
2582
2583        if (rte_VFW_hi_counter_block_in_use == MAX_VFW_INSTANCES)
2584               /* error, exceeded table bounds */
2585               return NULL;
2586
2587        rte_VFW_hi_counter_block_in_use++;
2588        counter_ptr =
2589               &rte_vfw_counter_table[rte_VFW_hi_counter_block_in_use];
2590        strncpy(counter_ptr->name, params->name, sizeof(counter_ptr->name));
2591
2592        pipe_vfw->counters = counter_ptr;
2593
2594        rte_ct_initialize_default_timeouts(pipe_vfw->cnxn_tracker);
2595        /* Parse arguments */
2596        if (pipeline_vfw_parse_args(pipe_vfw, params))
2597               return NULL;
2598
2599        uint16_t pointers_offset =
2600               META_DATA_OFFSET + offsetof(struct mbuf_tcp_meta_data, next);
2601
2602        if (pipe_vfw->n_flows > 0)
2603               rte_ct_initialize_cnxn_tracker_with_synproxy(
2604                             pipe_vfw->cnxn_tracker,
2605                             pipe_vfw->n_flows,
2606                             params->name,
2607                             pointers_offset);
2608
2609        pipe_vfw->counters->ct_counters =
2610               rte_ct_get_counter_address(pipe_vfw->cnxn_tracker);
2611
2612        /* Pipeline */
2613        {
2614               struct rte_pipeline_params pipeline_params = {
2615                      .name = params->name,
2616                      .socket_id = params->socket_id,
2617                      .offset_port_id = META_DATA_OFFSET +
2618                             offsetof(struct mbuf_tcp_meta_data, output_port)
2619               };
2620
2621               pipe->p = rte_pipeline_create(&pipeline_params);
2622               if (pipe->p == NULL) {
2623                      rte_free(pipe_vfw);
2624                      return NULL;
2625               }
2626        }
2627
2628        /* Input ports */
2629
2630        /*
2631         * create a different "arg_ah" for each input port.
2632         * They differ only in the recorded port number. Unfortunately,
2633         * IP_PIPELINE does not pass port number in to input port handler
2634         */
2635
2636        uint32_t in_ports_arg_size =
2637               RTE_CACHE_LINE_ROUNDUP((sizeof(struct vfw_ports_in_args)) *
2638                             (params->n_ports_in));
2639        struct vfw_ports_in_args *port_in_args =
2640               (struct vfw_ports_in_args *)
2641               rte_zmalloc(NULL, in_ports_arg_size, RTE_CACHE_LINE_SIZE);
2642
2643        if (port_in_args == NULL)
2644               return NULL;
2645
2646        pipe->n_ports_in = params->n_ports_in;
2647        for (i = 0; i < pipe->n_ports_in; i++) {
2648
2649               /* initialize this instance of port_in_args as necessary */
2650               port_in_args[i].pipe = pipe;
2651               port_in_args[i].cnxn_tracker = pipe_vfw->cnxn_tracker;
2652
2653               struct rte_pipeline_port_in_params port_params = {
2654                      .ops =
2655                             pipeline_port_in_params_get_ops(&params->port_in
2656                                           [i]),
2657                      .arg_create =
2658                             pipeline_port_in_params_convert(&params->port_in
2659                                           [i]),
2660                      .f_action = vfw_port_in_action_ipv4,
2661                      .arg_ah = &(port_in_args[i]),
2662                      .burst_size = params->port_in[i].burst_size,
2663               };
2664                if (pipe_vfw->traffic_type == IP_VERSION_6)
2665                      port_params.f_action = vfw_port_in_action_ipv6;
2666               int status = rte_pipeline_port_in_create(pipe->p, &port_params,
2667                             &pipe->port_in_id[i]);
2668
2669               if (status) {
2670                      rte_pipeline_free(pipe->p);
2671                      rte_free(pipe_vfw);
2672                      return NULL;
2673               }
2674        }
2675
2676        /* Output ports */
2677        pipe->n_ports_out = params->n_ports_out;
2678        for (i = 0; i < pipe->n_ports_out; i++) {
2679               struct rte_pipeline_port_out_params port_params = {
2680                      .ops = pipeline_port_out_params_get_ops(
2681                                    &params->port_out[i]),
2682                      .arg_create = pipeline_port_out_params_convert(
2683                                    &params->port_out[i]),
2684                      .f_action = NULL,
2685                      .arg_ah = NULL,
2686               };
2687
2688               int status = rte_pipeline_port_out_create(pipe->p, &port_params,
2689                             &pipe->port_out_id[i]);
2690
2691               if (status) {
2692                      rte_pipeline_free(pipe->p);
2693                      rte_free(pipe_vfw);
2694                      return NULL;
2695               }
2696        }
2697
2698        int pipeline_num = 0;
2699        int dont_care = sscanf(params->name, "PIPELINE%d", &pipeline_num);
2700
2701        if (dont_care < 0)
2702               printf("sscanf unble to read pipeline id\n");
2703        pipe_vfw->pipeline_num = (uint8_t) pipeline_num;
2704        register_pipeline_Qs(pipe_vfw->pipeline_num, pipe);
2705        set_link_map(pipe_vfw->pipeline_num, pipe, pipe_vfw->links_map);
2706        set_outport_id(pipe_vfw->pipeline_num, pipe,
2707                      pipe_vfw->outport_id);
2708        printf("pipeline_num=%d\n", pipeline_num);
2709 #ifdef ACL_ENABLE
2710        /*If this is the first VFW thread, create common VFW Rule tables*/
2711        if (rte_VFW_hi_counter_block_in_use == 0) {
2712               vfw_rule_table_ipv4_active =
2713                      lib_acl_create_active_standby_table_ipv4(1,
2714                                    &vfw_n_rules);
2715               if (vfw_rule_table_ipv4_active == NULL) {
2716                      printf("Failed to create active table for IPV4\n");
2717                      rte_pipeline_free(pipe->p);
2718                      rte_free(pipe_vfw->cnxn_tracker);
2719                      rte_free(pipe_vfw->plib_acl);
2720                      rte_free(pipe_vfw);
2721                      return NULL;
2722               }
2723               vfw_rule_table_ipv4_standby =
2724                      lib_acl_create_active_standby_table_ipv4(2,
2725                                    &vfw_n_rules);
2726               if (vfw_rule_table_ipv4_standby == NULL) {
2727                      printf("Failed to create standby table for IPV4\n");
2728                      rte_pipeline_free(pipe->p);
2729                      rte_free(pipe_vfw->cnxn_tracker);
2730                      rte_free(pipe_vfw->plib_acl);
2731                      rte_free(pipe_vfw);
2732                      return NULL;
2733               }
2734
2735               vfw_rule_table_ipv6_active =
2736                      lib_acl_create_active_standby_table_ipv6(1,
2737                                    &vfw_n_rules);
2738
2739               if (vfw_rule_table_ipv6_active == NULL) {
2740                      printf("Failed to create active table for IPV6\n");
2741                      rte_pipeline_free(pipe->p);
2742                      rte_free(pipe_vfw->cnxn_tracker);
2743                      rte_free(pipe_vfw->plib_acl);
2744                      rte_free(pipe_vfw);
2745                      return NULL;
2746               }
2747               vfw_rule_table_ipv6_standby =
2748                      lib_acl_create_active_standby_table_ipv6(2,
2749                                    &vfw_n_rules);
2750               if (vfw_rule_table_ipv6_standby == NULL) {
2751                      printf("Failed to create standby table for IPV6\n");
2752                      rte_pipeline_free(pipe->p);
2753                      rte_free(pipe_vfw->cnxn_tracker);
2754                      rte_free(pipe_vfw->plib_acl);
2755                      rte_free(pipe_vfw);
2756                      return NULL;
2757               }
2758        }
2759
2760 #endif
2761
2762        /* Tables */
2763
2764        pipe->n_tables = 1;
2765
2766        struct rte_pipeline_table_params table_params = {
2767               .ops = &rte_table_stub_ops,
2768               .arg_create = NULL,
2769               .f_action_hit = NULL,
2770               .f_action_miss = NULL,
2771               .arg_ah = NULL,
2772               .action_data_size = 0,
2773        };
2774
2775        int status = rte_pipeline_table_create(pipe->p,
2776                      &table_params,
2777                      &pipe->table_id[0]);
2778
2779        if (status) {
2780               rte_pipeline_free(pipe->p);
2781               rte_free(pipe);
2782               return NULL;
2783        }
2784
2785        struct rte_pipeline_table_entry default_entry = {
2786               .action = RTE_PIPELINE_ACTION_PORT_META
2787        };
2788
2789        struct rte_pipeline_table_entry *default_entry_ptr;
2790
2791        status = rte_pipeline_table_default_entry_add(pipe->p,
2792                                                 pipe->table_id[0],
2793                                                 &default_entry,
2794                                                 &default_entry_ptr);
2795
2796        if (status) {
2797               rte_pipeline_free(pipe->p);
2798               rte_free(pipe);
2799               return NULL;
2800        }
2801        for (i = 0; i < pipe->n_ports_in; i++) {
2802               int status = rte_pipeline_port_in_connect_to_table(
2803                             pipe->p,
2804                             pipe->port_in_id[i],
2805                             pipe->table_id[0]);
2806
2807               if (status) {
2808                      rte_pipeline_free(pipe->p);
2809                      rte_free(pipe_vfw);
2810                      return NULL;
2811               }
2812        }
2813
2814        /* Enable input ports */
2815        for (i = 0; i < pipe->n_ports_in; i++) {
2816               int status =
2817                   rte_pipeline_port_in_enable(pipe->p, pipe->port_in_id[i]);
2818
2819               if (status) {
2820                      rte_pipeline_free(pipe->p);
2821                      rte_free(pipe_vfw);
2822                      return NULL;
2823               }
2824        }
2825
2826        /* Check pipeline consistency */
2827        if (rte_pipeline_check(pipe->p) < 0) {
2828               rte_pipeline_free(pipe->p);
2829               rte_free(pipe_vfw);
2830               return NULL;
2831        }
2832
2833        /* Message queues */
2834        pipe->n_msgq = params->n_msgq;
2835        for (i = 0; i < pipe->n_msgq; i++)
2836               pipe->msgq_in[i] = params->msgq_in[i];
2837
2838        for (i = 0; i < pipe->n_msgq; i++)
2839               pipe->msgq_out[i] = params->msgq_out[i];
2840
2841        /* Message handlers */
2842        memcpy(pipe->handlers, handlers, sizeof(pipe->handlers));
2843        memcpy(pipe_vfw->custom_handlers, custom_handlers,
2844               sizeof(pipe_vfw->custom_handlers));
2845
2846        return pipe_vfw;
2847 }
2848
2849 /**
2850  * Free resources and delete pipeline.
2851  *
2852  * @param pipeline
2853  *  A pointer to the pipeline.
2854  *
2855  * @return
2856  *  0 on success, negative on error.
2857  */
2858 static int pipeline_vfw_free(void *pipeline)
2859 {
2860        struct pipeline *p = (struct pipeline *)pipeline;
2861
2862        /* Check input arguments */
2863        if (p == NULL)
2864               return -1;
2865
2866        /* Free resources */
2867        rte_pipeline_free(p->p);
2868        rte_free(p);
2869        return 0;
2870 }
2871
2872 /**
2873  * Callback function to map input/output ports.
2874  *
2875  * @param pipeline
2876  *  A pointer to the pipeline.
2877  * @param port_in
2878  *  Input port ID
2879  * @param port_out
2880  *  A pointer to the Output port.
2881  *
2882  * @return
2883  *  0 on success, negative on error.
2884  */
2885 static int
2886 pipeline_vfw_track(void *pipeline, __rte_unused uint32_t port_in,
2887                     uint32_t *port_out)
2888 {
2889        struct pipeline *p = (struct pipeline *)pipeline;
2890
2891        /* Check input arguments */
2892        if ((p == NULL) || (port_in >= p->n_ports_in) || (port_out == NULL))
2893               return -1;
2894
2895        if (p->n_ports_in == 1) {
2896               *port_out = 0;
2897               return 0;
2898        }
2899
2900        return -1;
2901 }
2902
2903 /**
2904  * Callback function to process timers.
2905  *
2906  * @param pipeline
2907  *  A pointer to the pipeline.
2908  *
2909  * @return
2910  *  0 on success, negative on error.
2911  */
2912 static int pipeline_vfw_timer(void *pipeline)
2913 {
2914        struct pipeline_vfw *p = (struct pipeline_vfw *)pipeline;
2915
2916        /*
2917         * handle any good buffered packets released by synproxy before checking
2918         * for packets relased by synproxy due to timeout.
2919         * Don't want packets missed
2920         */
2921
2922        vfw_handle_buffered_packets(p->pipe.p, p, p->cnxn_tracker,
2923                                    FORWARD_BUFFERED_PACKETS);
2924
2925        pipeline_msg_req_handle(&p->pipe);
2926        rte_pipeline_flush(p->pipe.p);
2927
2928        rte_ct_handle_expired_timers(p->cnxn_tracker);
2929
2930        /* now handle packets released by synproxy due to timeout. */
2931        vfw_handle_buffered_packets(p->pipe.p, p, p->cnxn_tracker,
2932                                    DELETE_BUFFERED_PACKETS);
2933
2934        return 0;
2935 }
2936
2937 /**
2938  * Callback function to process CLI commands from FE.
2939  *
2940  * @param p
2941  *  A pointer to the pipeline.
2942  * @param msg
2943  *  A pointer to command specific data.
2944  *
2945  * @return
2946  *  A pointer to message handler on success,
2947  *  pipeline_msg_req_invalid_hander on error.
2948  */
2949 void *pipeline_vfw_msg_req_custom_handler(struct pipeline *p, void *msg)
2950 {
2951        struct pipeline_vfw *pipe_vfw = (struct pipeline_vfw *)p;
2952        struct pipeline_custom_msg_req *req = msg;
2953        pipeline_msg_req_handler f_handle;
2954
2955        f_handle = (req->subtype < PIPELINE_VFW_MSG_REQS) ?
2956            pipe_vfw->custom_handlers[req->subtype] :
2957            pipeline_msg_req_invalid_handler;
2958
2959        if (f_handle == NULL)
2960               f_handle = pipeline_msg_req_invalid_handler;
2961
2962        return f_handle(p, req);
2963 }
2964
2965 /**
2966  * Handler for synproxy ON/OFF CLI command.
2967  *
2968  * @param p
2969  *  A pointer to the pipeline.
2970  * @param msg
2971  *  A pointer to command specific data.
2972  *
2973  * @return
2974  *  Response message contains status.
2975  */
2976
2977 void *pipeline_vfw_msg_req_synproxy_flag_handler(struct pipeline *p,
2978                                               void *msg)
2979 {
2980        struct pipeline_vfw *pipe_vfw = (struct pipeline_vfw *)p;
2981        struct pipeline_vfw_synproxy_flag_msg_req *req = msg;
2982        struct pipeline_vfw_synproxy_flag_msg_rsp *rsp = msg;
2983
2984        if (req->synproxy_flag == 0) {
2985               rte_ct_disable_synproxy(pipe_vfw->cnxn_tracker);
2986               rsp->status = 0;
2987               printf("synproxy turned OFF for %s\n", p->name);
2988        } else if (req->synproxy_flag == 1) {
2989               rte_ct_enable_synproxy(pipe_vfw->cnxn_tracker);
2990               rsp->status = 0;
2991               printf("synproxy turned ON for %s\n", p->name);
2992        } else {
2993               printf("Invalid synproxy setting\n");
2994               rsp->status = -1;
2995        }
2996
2997        return rsp;
2998 }
2999
3000 struct pipeline_be_ops pipeline_vfw_be_ops = {
3001        .f_init = pipeline_vfw_init,
3002        .f_free = pipeline_vfw_free,
3003        .f_run = NULL,
3004        .f_timer = pipeline_vfw_timer,
3005        .f_track = pipeline_vfw_track,
3006 };