2 // Copyright (c) 2017 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "vnf_common.h"
19 #define ACL_LIB_DEBUG 0
20 static struct rte_acl_field_def field_format_ipv4[] = {
23 .type = RTE_ACL_FIELD_TYPE_BITMASK,
24 .size = sizeof(uint8_t),
27 .offset = sizeof(struct ether_hdr) +
28 offsetof(struct ipv4_hdr, next_proto_id),
31 /* Source IP address (IPv4) */
33 .type = RTE_ACL_FIELD_TYPE_MASK,
34 .size = sizeof(uint32_t),
37 .offset = sizeof(struct ether_hdr) +
38 offsetof(struct ipv4_hdr, src_addr),
41 /* Destination IP address (IPv4) */
43 .type = RTE_ACL_FIELD_TYPE_MASK,
44 .size = sizeof(uint32_t),
47 .offset = sizeof(struct ether_hdr) +
48 offsetof(struct ipv4_hdr, dst_addr),
53 .type = RTE_ACL_FIELD_TYPE_RANGE,
54 .size = sizeof(uint16_t),
57 .offset = sizeof(struct ether_hdr) +
58 sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, src_port),
61 /* Destination Port */
63 .type = RTE_ACL_FIELD_TYPE_RANGE,
64 .size = sizeof(uint16_t),
67 .offset = sizeof(struct ether_hdr) +
68 sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, dst_port),
72 #define SIZEOF_VLAN_HDR 4
74 static struct rte_acl_field_def field_format_vlan_ipv4[] = {
77 .type = RTE_ACL_FIELD_TYPE_BITMASK,
78 .size = sizeof(uint8_t),
81 .offset = sizeof(struct ether_hdr) +
82 SIZEOF_VLAN_HDR + offsetof(struct ipv4_hdr, next_proto_id),
85 /* Source IP address (IPv4) */
87 .type = RTE_ACL_FIELD_TYPE_MASK,
88 .size = sizeof(uint32_t),
91 .offset = sizeof(struct ether_hdr) +
92 SIZEOF_VLAN_HDR + offsetof(struct ipv4_hdr, src_addr),
95 /* Destination IP address (IPv4) */
97 .type = RTE_ACL_FIELD_TYPE_MASK,
98 .size = sizeof(uint32_t),
101 .offset = sizeof(struct ether_hdr) +
102 SIZEOF_VLAN_HDR + offsetof(struct ipv4_hdr, dst_addr),
107 .type = RTE_ACL_FIELD_TYPE_RANGE,
108 .size = sizeof(uint16_t),
111 .offset = sizeof(struct ether_hdr) +
113 sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, src_port),
116 /* Destination Port */
118 .type = RTE_ACL_FIELD_TYPE_RANGE,
119 .size = sizeof(uint16_t),
122 .offset = sizeof(struct ether_hdr) +
124 sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, dst_port),
128 #define SIZEOF_QINQ_HEADER 8
130 static struct rte_acl_field_def field_format_qinq_ipv4[] = {
133 .type = RTE_ACL_FIELD_TYPE_BITMASK,
134 .size = sizeof(uint8_t),
137 .offset = sizeof(struct ether_hdr) +
138 SIZEOF_QINQ_HEADER + offsetof(struct ipv4_hdr, next_proto_id),
141 /* Source IP address (IPv4) */
143 .type = RTE_ACL_FIELD_TYPE_MASK,
144 .size = sizeof(uint32_t),
147 .offset = sizeof(struct ether_hdr) +
148 SIZEOF_QINQ_HEADER + offsetof(struct ipv4_hdr, src_addr),
151 /* Destination IP address (IPv4) */
153 .type = RTE_ACL_FIELD_TYPE_MASK,
154 .size = sizeof(uint32_t),
157 .offset = sizeof(struct ether_hdr) +
158 SIZEOF_QINQ_HEADER + offsetof(struct ipv4_hdr, dst_addr),
163 .type = RTE_ACL_FIELD_TYPE_RANGE,
164 .size = sizeof(uint16_t),
167 .offset = sizeof(struct ether_hdr) +
169 sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, src_port),
172 /* Destination Port */
174 .type = RTE_ACL_FIELD_TYPE_RANGE,
175 .size = sizeof(uint16_t),
178 .offset = sizeof(struct ether_hdr) +
180 sizeof(struct ipv4_hdr) + offsetof(struct tcp_hdr, dst_port),
184 static struct rte_acl_field_def field_format_ipv6[] = {
187 .type = RTE_ACL_FIELD_TYPE_BITMASK,
188 .size = sizeof(uint8_t),
191 .offset = sizeof(struct ether_hdr) +
192 offsetof(struct ipv6_hdr, proto),
195 /* Source IP address (IPv6) */
197 .type = RTE_ACL_FIELD_TYPE_MASK,
198 .size = sizeof(uint32_t),
201 .offset = sizeof(struct ether_hdr) +
202 offsetof(struct ipv6_hdr, src_addr),
206 .type = RTE_ACL_FIELD_TYPE_MASK,
207 .size = sizeof(uint32_t),
210 .offset = sizeof(struct ether_hdr) +
211 offsetof(struct ipv6_hdr, src_addr) + sizeof(uint32_t),
215 .type = RTE_ACL_FIELD_TYPE_MASK,
216 .size = sizeof(uint32_t),
219 .offset = sizeof(struct ether_hdr) +
220 offsetof(struct ipv6_hdr, src_addr) + 2 * sizeof(uint32_t),
224 .type = RTE_ACL_FIELD_TYPE_MASK,
225 .size = sizeof(uint32_t),
228 .offset = sizeof(struct ether_hdr) +
229 offsetof(struct ipv6_hdr, src_addr) + 3 * sizeof(uint32_t),
232 /* Destination IP address (IPv6) */
234 .type = RTE_ACL_FIELD_TYPE_MASK,
235 .size = sizeof(uint32_t),
238 .offset = sizeof(struct ether_hdr) +
239 offsetof(struct ipv6_hdr, dst_addr),
243 .type = RTE_ACL_FIELD_TYPE_MASK,
244 .size = sizeof(uint32_t),
247 .offset = sizeof(struct ether_hdr) +
248 offsetof(struct ipv6_hdr, dst_addr) + sizeof(uint32_t),
252 .type = RTE_ACL_FIELD_TYPE_MASK,
253 .size = sizeof(uint32_t),
256 .offset = sizeof(struct ether_hdr) +
257 offsetof(struct ipv6_hdr, dst_addr) + 2 * sizeof(uint32_t),
261 .type = RTE_ACL_FIELD_TYPE_MASK,
262 .size = sizeof(uint32_t),
265 .offset = sizeof(struct ether_hdr) +
266 offsetof(struct ipv6_hdr, dst_addr) + 3 * sizeof(uint32_t),
271 .type = RTE_ACL_FIELD_TYPE_RANGE,
272 .size = sizeof(uint16_t),
275 .offset = sizeof(struct ether_hdr) +
276 sizeof(struct ipv6_hdr) + offsetof(struct tcp_hdr, src_port),
279 /* Destination Port */
281 .type = RTE_ACL_FIELD_TYPE_RANGE,
282 .size = sizeof(uint16_t),
285 .offset = sizeof(struct ether_hdr) +
286 sizeof(struct ipv6_hdr) + offsetof(struct tcp_hdr, dst_port),
290 void *lib_acl_create_active_standby_table_ipv4(uint8_t table_num,
291 uint32_t *libacl_n_rules)
293 printf("Create LIBACL active IPV4 Tables rte_socket_id(): %i\n",
296 /* Create IPV4 LIBACL Rule Tables */
297 struct rte_table_acl_params common_ipv4_table_libacl_params = {
298 .name = "LIBACLIPV4A",
299 .n_rules = *libacl_n_rules,
300 .n_rule_fields = RTE_DIM(field_format_ipv4),
303 memcpy(common_ipv4_table_libacl_params.field_format,
304 field_format_ipv4, sizeof(field_format_ipv4));
306 uint32_t ipv4_entry_size = sizeof(struct lib_acl_table_entry);
307 /* Create second IPV4 Table */
309 common_ipv4_table_libacl_params.name = "LIBACLIPV4B";
310 return rte_table_acl_ops.f_create(&common_ipv4_table_libacl_params,
317 void *lib_acl_create_active_standby_table_ipv6(uint8_t table_num,
318 uint32_t *libacl_n_rules)
320 printf("Create LIBACL active IPV6 Tables rte_socket_id(): %i\n",
322 /* Create IPV6 LIBACL Rule Tables */
323 struct rte_table_acl_params common_ipv6_table_libacl_params = {
324 .name = "LIBACLIPV6A",
325 .n_rules = *libacl_n_rules,
326 .n_rule_fields = RTE_DIM(field_format_ipv6),
329 memcpy(common_ipv6_table_libacl_params.field_format,
330 field_format_ipv6, sizeof(field_format_ipv6));
332 uint32_t ipv6_entry_size = sizeof(struct lib_acl_table_entry);
333 /* Create second IPV6 table */
335 common_ipv6_table_libacl_params.name = "LIBACLIPV6B";
336 return rte_table_acl_ops.f_create(&common_ipv6_table_libacl_params,
342 int lib_acl_parse_config(struct lib_acl *plib_acl,
343 char *arg_name, char *arg_value,
344 uint32_t *libacl_n_rules)
346 uint32_t n_rules_present = 0;
347 uint32_t pkt_type_present = 0;
349 plib_acl->n_rules = DEFULT_NUM_RULE;
350 *libacl_n_rules = DEFULT_NUM_RULE;
351 plib_acl->n_rule_fields = RTE_DIM(field_format_ipv4);
352 plib_acl->field_format = field_format_ipv4;
353 plib_acl->field_format_size = sizeof(field_format_ipv4);
354 if (strcmp(arg_name, "n_rules") == 0) {
355 if (n_rules_present) {
356 printf("n_rules_present");
361 plib_acl->n_rules = atoi(arg_value);
362 *libacl_n_rules = atoi(arg_value);
365 if (strcmp(arg_name, "pkt_type") == 0) {
366 if (pkt_type_present) {
370 pkt_type_present = 1;
373 if (strcmp(arg_value, "ipv4") == 0) {
374 plib_acl->n_rule_fields =
375 RTE_DIM(field_format_ipv4);
376 plib_acl->field_format = field_format_ipv4;
377 plib_acl->field_format_size =
378 sizeof(field_format_ipv4);
383 if (strcmp(arg_value, "vlan_ipv4") == 0) {
384 plib_acl->n_rule_fields =
385 RTE_DIM(field_format_vlan_ipv4);
386 plib_acl->field_format =
387 field_format_vlan_ipv4;
388 plib_acl->field_format_size =
389 sizeof(field_format_vlan_ipv4);
394 if (strcmp(arg_value, "qinq_ipv4") == 0) {
395 plib_acl->n_rule_fields =
396 RTE_DIM(field_format_qinq_ipv4);
397 plib_acl->field_format =
398 field_format_qinq_ipv4;
399 plib_acl->field_format_size =
400 sizeof(field_format_qinq_ipv4);
405 if (strcmp(arg_value, "ipv6") == 0) {
406 plib_acl->n_rule_fields =
407 RTE_DIM(field_format_ipv6);
408 plib_acl->field_format = field_format_ipv6;
409 plib_acl->field_format_size =
410 sizeof(field_format_ipv6);
417 /* Parameter not processed in this parse function */
423 * Main packet processing function.
424 * 64 packet bit mask are used to identify which packets to forward.
425 * Performs the following:
426 * - Burst lookup packets in the IPv4 ACL Rule Table.
427 * - Lookup Action Table, perform actions.
428 * - Burst lookup Connection Tracking, if enabled.
429 * - Lookup MAC address.
431 * - Packets with bit mask set are forwarded
434 * A pointer to the pipeline.
436 * A pointer to a burst of packets.
438 * Number of packets to process.
440 * A pointer to pipeline specific data.
443 * 0 on success, negative on error.
446 lib_acl_ipv4_pkt_work_key(struct lib_acl *plib_acl,
447 struct rte_mbuf **pkts, uint64_t pkts_mask,
448 uint64_t *pkts_drop_without_rule,
449 void *plib_acl_rule_table_ipv4_active,
450 struct pipeline_action_key *action_array_active,
451 struct action_counter_block (*p_action_counter_table)[action_array_max],
452 uint64_t *conntrack_mask,
453 uint64_t *connexist_mask)
456 uint64_t lookup_hit_mask_ipv4 = 0;
457 uint64_t lookup_miss_mask_ipv4 = 0;
461 printf("ACL IPV4 Lookup Mask Before = 0x%"PRIx64"\n",
463 status = rte_table_acl_ops.f_lookup(
464 plib_acl_rule_table_ipv4_active,
465 pkts, pkts_mask, &lookup_hit_mask_ipv4,
466 (void **) plib_acl->plib_acl_entries_ipv4);
468 printf("Lookup Failed\n");
470 printf("ACL IPV4 Lookup Mask After = 0x%"PRIx64"\n",
471 lookup_hit_mask_ipv4);
473 printf("ACL Lookup Mask After = 0x%"PRIx64"\n",
474 lookup_hit_mask_ipv4);
476 lookup_miss_mask_ipv4 = pkts_mask & (~lookup_hit_mask_ipv4);
477 pkts_mask = lookup_hit_mask_ipv4;
478 *pkts_drop_without_rule += __builtin_popcountll(lookup_miss_mask_ipv4);
480 printf("pkt_work_acl_key pkts_drop: %" PRIu64 " n_pkts: %u\n",
481 *pkts_drop_without_rule,
482 __builtin_popcountll(lookup_miss_mask_ipv4));
483 /* bitmap of packets left to process for ARP */
484 uint64_t pkts_to_process = lookup_hit_mask_ipv4;
486 for (; pkts_to_process;) {
487 uint8_t pos = (uint8_t)__builtin_ctzll(pkts_to_process);
488 /* bitmask representing only this packet */
489 uint64_t pkt_mask = 1LLU << pos;
490 /* remove this packet from remaining list */
491 pkts_to_process &= ~pkt_mask;
492 struct rte_mbuf *pkt = pkts[pos];
496 struct lib_acl_table_entry *entry =
497 (struct lib_acl_table_entry *)
498 plib_acl->plib_acl_entries_ipv4[pos];
499 uint16_t phy_port = entry->head.port_id;
500 uint32_t action_id = entry->action_id;
503 printf("action_id = %u\n", action_id);
505 uint32_t dscp_offset = IP_START + IP_HDR_DSCP_OFST;
507 if (action_array_active[action_id].action_bitmap &
508 lib_acl_action_count) {
509 p_action_counter_table
510 [plib_acl->action_counter_index]
511 [action_id].packetCount++;
512 p_action_counter_table
513 [plib_acl->action_counter_index]
514 [action_id].byteCount +=
515 rte_pktmbuf_pkt_len(pkt);
517 printf("Action Count Packet Count: %"
518 PRIu64 " Byte Count: %"
520 , p_action_counter_table
521 [plib_acl->action_counter_index]
522 [action_id].packetCount,
523 p_action_counter_table
524 [plib_acl->action_counter_index]
525 [action_id].byteCount);
528 if (action_array_active[action_id].action_bitmap &
529 lib_acl_action_packet_drop) {
531 /* Drop packet by changing the mask */
533 printf("ACL before drop pkt_mask %"
534 PRIx64", pkt_num %d\n",
536 pkts_mask &= ~(1LLU << pos);
537 (*pkts_drop_without_rule)++;
539 printf("ACL after drop pkt_mask %" PRIx64
540 ", pkt_num %d, action_packet_drop %"
541 PRIu64 "\n", pkts_mask, pos,
542 *pkts_drop_without_rule);
545 if (action_array_active[action_id].action_bitmap &
546 lib_acl_action_fwd) {
547 phy_port = action_array_active[action_id].
549 entry->head.port_id = phy_port;
551 printf("Action FWD Port ID: %"
552 PRIu16"\n", phy_port);
555 if (action_array_active[action_id].action_bitmap &
556 lib_acl_action_nat) {
557 phy_port = action_array_active[action_id].
559 entry->head.port_id = phy_port;
561 printf("Action NAT Port ID: %"
562 PRIu16"\n", phy_port);
565 if (action_array_active[action_id].action_bitmap &
566 lib_acl_action_dscp) {
568 /* Set DSCP priority */
569 uint8_t *dscp = RTE_MBUF_METADATA_UINT8_PTR(pkt,
571 *dscp = action_array_active[action_id].
574 printf("Action DSCP DSCP Priority: %"
578 if (action_array_active[action_id].action_bitmap &
579 lib_acl_action_packet_accept) {
581 printf("Action Accept\n");
583 if (action_array_active[action_id].action_bitmap
584 & lib_acl_action_conntrack) {
586 /* Set conntrack bit for this pkt */
587 *conntrack_mask |= pkt_mask;
589 printf("ACL CT enabled: 0x%"
590 PRIx64" pkt_mask: 0x%"
596 if (action_array_active[action_id].action_bitmap
597 & lib_acl_action_connexist) {
599 /* Set conntrack bit for this pkt */
600 *conntrack_mask |= pkt_mask;
602 /* Set connexist bit for this pkt for
603 * public -> private */
604 /* Private -> public packet will open
606 if (action_array_active[action_id].
608 lib_acl_public_private)
609 *connexist_mask |= pkt_mask;
612 printf("ACL Connexist ENB CT:0x%"
613 PRIx64" connexist: 0x%"
614 PRIx64" pkt_mask: 0x%"
626 * Main packet processing function.
627 * 64 packet bit mask are used to identify which packets to forward.
628 * Performs the following:
629 * - Burst lookup packets in the IPv6 ACL Rule Table.
630 * - Lookup Action Table, perform actions.
631 * - Burst lookup Connection Tracking, if enabled.
632 * - Lookup MAC address.
634 * - Packets with bit mask set are forwarded
637 * A pointer to the pipeline.
639 * A pointer to a burst of packets.
641 * Number of packets to process.
643 * A pointer to pipeline specific data.
646 * 0 on success, negative on error.
649 lib_acl_ipv6_pkt_work_key(struct lib_acl *plib_acl,
650 struct rte_mbuf **pkts, uint64_t pkts_mask,
651 uint64_t *pkts_drop_without_rule,
652 void *plib_acl_rule_table_ipv6_active,
653 struct pipeline_action_key *action_array_active,
654 struct action_counter_block (*p_action_counter_table)[action_array_max],
655 uint64_t *conntrack_mask,
656 uint64_t *connexist_mask)
659 uint64_t lookup_hit_mask_ipv6 = 0;
660 uint64_t lookup_miss_mask_ipv6 = 0;
665 printf("ACL IPV6 Lookup Mask Before = 0x%"PRIx64"\n",
667 status = rte_table_acl_ops.f_lookup(
668 plib_acl_rule_table_ipv6_active,
669 pkts, pkts_mask, &lookup_hit_mask_ipv6,
670 (void **) plib_acl->plib_acl_entries_ipv6);
672 printf("Lookup Failed\n");
674 printf("ACL IPV6 Lookup Mask After = 0x%"PRIx64"\n",
675 lookup_hit_mask_ipv6);
678 printf("ACL Lookup Mask After = 0x%"PRIx64"\n",
679 lookup_hit_mask_ipv6);
681 lookup_miss_mask_ipv6 = pkts_mask & (~lookup_hit_mask_ipv6);
682 pkts_mask = lookup_hit_mask_ipv6;
683 *pkts_drop_without_rule += __builtin_popcountll(lookup_miss_mask_ipv6);
685 printf("pkt_work_acl_key pkts_drop: %" PRIu64 " n_pkts: %u\n",
686 *pkts_drop_without_rule,
687 __builtin_popcountll(lookup_miss_mask_ipv6));
688 /* bitmap of packets left to process for ARP */
689 uint64_t pkts_to_process = lookup_hit_mask_ipv6;
691 for (; pkts_to_process;) {
692 uint8_t pos = (uint8_t)__builtin_ctzll(pkts_to_process);
693 /* bitmask representing only this packet */
694 uint64_t pkt_mask = 1LLU << pos;
695 /* remove this packet from remaining list */
696 pkts_to_process &= ~pkt_mask;
697 struct rte_mbuf *pkt = pkts[pos];
700 struct lib_acl_table_entry *entry =
701 (struct lib_acl_table_entry *)
702 plib_acl->plib_acl_entries_ipv6[pos];
703 uint16_t phy_port = entry->head.port_id;
704 uint32_t action_id = entry->action_id;
707 printf("action_id = %u\n", action_id);
709 if (action_array_active[action_id].action_bitmap &
710 lib_acl_action_count) {
711 p_action_counter_table
712 [plib_acl->action_counter_index]
713 [action_id].packetCount++;
714 p_action_counter_table
715 [plib_acl->action_counter_index]
716 [action_id].byteCount +=
717 rte_pktmbuf_pkt_len(pkt);
719 printf("Action Count Packet Count: %"
720 PRIu64 " Byte Count: %"
722 p_action_counter_table
723 [plib_acl->action_counter_index]
724 [action_id].packetCount,
725 p_action_counter_table
726 [plib_acl->action_counter_index]
727 [action_id].byteCount);
730 if (action_array_active[action_id].action_bitmap &
731 lib_acl_action_packet_drop) {
732 /* Drop packet by changing the mask */
734 printf("ACL before drop pkt_mask %"
735 PRIx64", pkt_num %d\n",
737 pkts_mask &= ~(1LLU << pos);
738 (*pkts_drop_without_rule)++;
740 printf("ACL after drop pkt_mask %" PRIx64
741 ", pkt_num %d, action_packet_drop %"
742 PRIu64 "\n", pkts_mask, pos,
743 *pkts_drop_without_rule);
747 if (action_array_active[action_id].action_bitmap &
748 lib_acl_action_fwd) {
749 phy_port = action_array_active[action_id].
751 entry->head.port_id = phy_port;
753 printf("Action FWD Port ID: %"
754 PRIu16"\n", phy_port);
757 if (action_array_active[action_id].action_bitmap &
758 lib_acl_action_nat) {
759 phy_port = action_array_active[action_id].
761 entry->head.port_id = phy_port;
763 printf("Action NAT Port ID: %"
764 PRIu16"\n", phy_port);
767 if (action_array_active[action_id].action_bitmap &
768 lib_acl_action_dscp) {
770 /* Set DSCP priority */
771 uint32_t dscp_offset = IP_START +
772 IP_HDR_DSCP_OFST_IPV6;
773 uint16_t *dscp = RTE_MBUF_METADATA_UINT16_PTR(
775 uint16_t temp = *dscp;
776 uint16_t dscp_value = (rte_bswap16(temp) &
780 [action_id].dscp_priority << 2;
781 uint16_t dscp_temp = dscp_store;
783 dscp_temp = dscp_temp << 4;
784 *dscp = rte_bswap16(dscp_temp | dscp_value);
786 printf("Action DSCP DSCP Priority: %"
790 if (action_array_active[action_id].action_bitmap
791 & lib_acl_action_packet_accept) {
793 printf("Action Accept\n");
795 if (action_array_active[action_id].action_bitmap
796 & lib_acl_action_conntrack) {
798 /* Set conntrack bit for this pkt */
799 *conntrack_mask |= pkt_mask;
801 printf("ACL CT enabled: 0x%"
802 PRIx64" pkt_mask: 0x%"
808 if (action_array_active[action_id].action_bitmap
809 & lib_acl_action_connexist) {
811 /* Set conntrack bit for this pkt */
812 *conntrack_mask |= pkt_mask;
814 /* Set connexist bit for this pkt for
815 * public -> private */
816 /* Private -> public packet will open
818 if (action_array_active[action_id].
820 lib_acl_public_private)
821 *connexist_mask |= pkt_mask;
824 printf("ACL Connexist ENB CT:0x%"
825 PRIx64" connexist: 0x%"
826 PRIx64" pkt_mask: 0x%"