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