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