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 <rte_ether.h>
18 #include <rte_prefetch.h>
19 #include <rte_cycles.h>
20 #include <rte_malloc.h>
21 #include <rte_memcpy.h>
22 #include <rte_timer.h>
23 #include <rte_spinlock.h>
24 #include "rte_cnxn_tracking.h"
25 #include "rte_ct_tcp.h"
27 #define CNXN_TRX_DEBUG 0
28 #define TESTING_TIMERS 0
29 #define RTE_CT_TIMER_EXPIRED_DUMP 0
31 #define META_DATA_OFFSET 128
32 #define ETHERNET_START (META_DATA_OFFSET + RTE_PKTMBUF_HEADROOM)
33 #define ETH_HDR_SIZE 14
34 #define IP_START (ETHERNET_START + ETH_HDR_SIZE)
35 #define PROTOCOL_START (IP_START + 9)
36 #define SRC_ADDR_START (IP_START + 12)
37 #define TCP_START (IP_START + 20)
40 #define PROTOCOL_START_IPV6 (IP_START + 6)
41 #define SRC_ADDR_START_IPV6 (IP_START + 8)
42 #define TCP_START_IPV6 (IP_START + 40)
44 #define TCP_PROTOCOL 6
45 #define UDP_PROTOCOL 17
46 #define TCP_FW_IPV4_KEY_SIZE 16
48 #define TCP_FW_IPV6_KEY_SIZE 40
50 #define IPv4_HEADER_SIZE 20
51 #define IPv6_HEADER_SIZE 40
53 #define IP_VERSION_4 4
54 #define IP_VERSION_6 6
57 rte_ct_cnxn_tracker_batch_lookup_basic_type(
58 struct rte_ct_cnxn_tracker *ct,
59 struct rte_mbuf **pkts,
61 uint64_t no_new_cnxn_mask,
62 uint64_t *reply_pkt_mask,
63 uint64_t *hijack_mask,
64 uint8_t ip_hdr_size_bytes);
67 * Check if the packet is valid for the given connection. "original_direction"
68 * is false if the address order need to be "flipped".See create_cnxn_hashkey().
69 * True otherwise. Return 0 if the packet is valid, or a negative otherwise.
72 /* IP/TCP header print for debugging */
74 rte_ct_cnxn_print_pkt(struct rte_mbuf *pkt, uint8_t type)
77 uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, IP_START);
80 printf("IP and TCP/UDP headers:\n");
82 if (type == IP_VERSION_4) {
83 for (i = 0; i < 40; i++) {
84 printf("%02x ", rd[i]);
91 if (type == IP_VERSION_6) {
92 for (i = 0; i < 60; i++) {
93 printf("%02x ", rd[i]);
103 rte_cnxn_ip_type(uint8_t *type, struct rte_mbuf *pkt)
106 int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(pkt);
108 if (ip_hdr_size_bytes == IPv4_HEADER_SIZE)
109 *type = IP_VERSION_4;
111 if (ip_hdr_size_bytes == IPv6_HEADER_SIZE)
112 *type = IP_VERSION_6;
116 rte_ct_print_hashkey(uint32_t *key)
118 printf("Key: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x \\\n",
119 key[0], key[1], key[2], key[3],
120 key[4], key[5], key[6], key[7], key[8], key[9]);
124 * Create a hash key consisting of the source address/port, the destination
125 * address/ports, and the tcp protocol number. The address/port combos are
126 * treated as two 48 bit numbers and sorted. Thus the key is always the
127 * same regardless of the direction of the packet. Remembering if the numbers
128 * were "flipped" from the order in the packet, and comparing that to whether
129 * the original hash key was flipped, tells if this packet is from the same
130 * direction as the original sender or the response direction. Returns 1 (true)
131 * if the key was left in the original direction.
134 rte_ct_create_cnxn_hashkey(
143 uint8_t hash_order_original_direction = 1;
147 if (type == IP_VERSION_4) {
148 uint32_t source = *src_addr;
149 uint32_t dest = *dst_addr;
151 key[3] = key[4] = key[5] = key[6] = key[7] = key[8] = 0;
154 || ((source == dest) && (src_port < dst_port))) {
157 key[2] = (src_port << 16) | dst_port;
161 key[2] = (dst_port << 16) | src_port;
162 hash_order_original_direction = 0;
166 if (type == IP_VERSION_6) {
167 int ip_cmp = memcmp(src_addr, dst_addr, 16);
171 if ((ip_cmp < 0) || ((ip_cmp == 0) && (src_port < dst_port))) {
174 key[8] = (src_port << 16) | dst_port;
178 key[8] = (dst_port << 16) | src_port;
179 hash_order_original_direction = 0;
192 rte_ct_print_hashkey(key);
194 return hash_order_original_direction;
199 rte_ct_get_IP_hdr_size(struct rte_mbuf *pkt)
201 /* NOTE: Only supporting IP headers with no options at this time, so
202 * header is fixed size
204 /* TODO: Need to find defined contstants for start of Ether and
207 uint8_t hdr_chk = RTE_MBUF_METADATA_UINT8(pkt, IP_START);
209 hdr_chk = hdr_chk >> 4;
211 if (hdr_chk == IP_VERSION_4)
212 return IPv4_HEADER_SIZE;
214 else if (hdr_chk == IP_VERSION_6)
215 return IPv6_HEADER_SIZE;
217 else /* Not IPv4 header with no options, return negative. */
220 * int ip_hdr_size_bytes = (ihdr->version_ihl & IPV4_HDR_IHL_MASK) *
221 * IPV4_IHL_MULTIPLIER;
222 * return ip_hdr_size_bytes;
227 rte_ct_set_timer_for_new_cnxn(
228 struct rte_ct_cnxn_tracker *ct,
229 struct rte_ct_cnxn_data *cd)
231 cd->state_used_for_timer = RTE_CT_TCP_NONE;
232 rte_ct_set_cnxn_timer_for_tcp(ct, cd, RTE_CT_TCP_SYN_SENT);
236 * The connection data is stored in a hash table which makes use of the bulk
237 * lookup optimization provided in DPDK. All of the packets seen in one call
238 * to rte_ct_cnxn_tracker_batch_lookup are done in one hash table lookup. The
239 * number of packets is the number being processed by the pipeline (default
240 * max 32, absolute max 64). For any TCP or UDP packet that does not have
241 * an existing (pseudo-)connection in the table (i.e. was a miss on the hash
242 * lookup), a new connection must be added.
244 * It is possible, for UDP, that the first packet for a (pseudo-)connection and
245 * a subsequent packet are in the same batch. This means that when looking for
246 * new connections in a batch the first one must add the connection, the
247 * second and subsequent (in that batch) that are part of the same connection
248 * must use that newly created one, not create another table entry.
250 * Any newly created entries are "remembered" in linear table, which is search
251 * when processing hash tables misses. All the entries in that table are
252 * "forgotten" at the start of a new batch.
254 * A linear table may seem slow, but consider:
255 * - out of millions of packets/second, this involves at most 64.
256 * - this affects only UDP. TCP connections are set up using an acknowledgement
257 * protocl, so would not have multiple packets for new connection in
259 * - the number of new connections in a batch would usually be zero, or a low
261 * - all the data to search through should still be in cache
265 rte_ct_remember_new_connection(
266 struct rte_ct_cnxn_tracker *ct,
267 struct rte_ct_cnxn_data *entry)
269 ct->latest_connection++;
270 ct->new_connections[ct->latest_connection] = entry;
273 static struct rte_ct_cnxn_data *
274 rte_ct_search_new_connections(struct rte_ct_cnxn_tracker *ct, uint32_t *key)
278 for (i = 0; i <= ct->latest_connection; i++) {
279 uint32_t *cnxn_key = ct->new_connections[i]->key;
280 int key_cmp = memcmp(cnxn_key, key,
281 sizeof(ct->new_connections[i]->key));
284 return ct->new_connections[i];
289 static inline void rte_ct_forget_new_connections(struct rte_ct_cnxn_tracker *ct)
291 ct->latest_connection = -1;
297 static enum rte_ct_packet_action
298 rte_ct_handle_tcp_lookup(
299 struct rte_ct_cnxn_tracker *ct,
300 struct rte_mbuf *packet,
302 uint8_t key_is_client_order,
304 int hash_table_entry,
306 uint8_t ip_hdr_size_bytes)
308 struct rte_ct_cnxn_data new_cnxn_data;
310 memset(&new_cnxn_data, 0, sizeof(struct rte_ct_cnxn_data));
311 enum rte_ct_packet_action packet_action;
314 int32_t position = hash_table_entry;
315 ct->positions[pkt_num] = position;
318 /* rte_ct_cnxn_print_pkt(packet); */
319 if (hash_table_entry >= 0) {
321 * connection found for this packet.
322 * Check that this is a valid packet for connection
325 struct rte_ct_cnxn_data *entry =
326 &ct->hash_table_entries[hash_table_entry];
328 packet_action = rte_ct_verify_tcp_packet(ct, entry, packet,
329 key_is_client_order, ip_hdr_size_bytes);
331 switch (packet_action) {
333 case RTE_CT_FORWARD_PACKET:
334 entry->counters.packets_forwarded++;
337 case RTE_CT_DROP_PACKET:
338 entry->counters.packets_dropped++;
339 return RTE_CT_DROP_PACKET;
341 case RTE_CT_REOPEN_CNXN_AND_FORWARD_PACKET:
342 /* Entry already in hash table, just re-initialize */
344 /* Don't use syproxy on re-init, since it
345 * is a valid connection
348 if (rte_ct_tcp_new_connection(ct, &new_cnxn_data,
349 packet, 0, ip_hdr_size_bytes) !=
350 RTE_CT_DROP_PACKET) {
351 rte_memcpy(&entry->ct_protocol.tcp_ct_data,
352 &new_cnxn_data.ct_protocol.tcp_ct_data,
353 sizeof(new_cnxn_data.ct_protocol.tcp_ct_data));
354 rte_ct_set_timer_for_new_cnxn(ct, entry);
355 if (ct->counters->sessions_reactivated > 0)
356 ct->counters->sessions_reactivated--;
361 case RTE_CT_SEND_SERVER_SYN:
362 ct->counters->pkts_forwarded++;
363 /* packet modified, send back to original source */
364 return RTE_CT_SEND_SERVER_SYN;
366 case RTE_CT_SEND_SERVER_ACK:
367 ct->counters->pkts_forwarded++;
368 /* packet modified, send back to original source */
369 return RTE_CT_SEND_SERVER_ACK;
372 ct->counters->pkts_forwarded++;
373 /* packet saved with connection, notify VNF
376 return RTE_CT_HIJACK;
378 case RTE_CT_DESTROY_CNXN_AND_FORWARD_PACKET:
381 * Forward the packet because it is "legal", but destroy
382 * the connection by removing it from the hash table and
383 * cancelling any timer. There is a remote possibility
384 * (perhaps impossible?) that a later packet in the same
385 * batch is for this connection. Due to the batch
386 * lookup, which has already happened, the later packet
387 * thinks that the connection is valid. This might cause
388 * a timer to be set. Eventually, it would time out so
389 * the only bug case occurs if the hash table also, in
390 * the same batch, allocates this entry for a new
391 * connection before the above packet is received. The
392 * chances of this happening seem impossibly small but
393 * this case should perhaps be investigated further.
396 if (rte_hash_del_key(ct->rhash, entry->key) >= 0) {
398 * if rte_hash_del_key >= 0, then the connection
399 * was found in the hash table and removed.
400 * Counters must be updated, and the timer
401 * cancelled. If the result was < 0, then the
402 * connection must have already been deleted,
403 * and it must have been deleted in this batch
404 * of packets processed. Do nothing.
407 ct->counters->sessions_closed++;
408 if (ct->counters->current_active_sessions > 0)
409 ct->counters->current_active_sessions--;
410 rte_ct_cancel_cnxn_timer(entry);
412 entry->counters.packets_forwarded++;
419 /* try to add new connection */
420 struct rte_ct_cnxn_data *new_hash_entry;
423 ct->counters->pkts_drop_invalid_conn++;
424 return RTE_CT_DROP_PACKET;
427 packet_action = rte_ct_tcp_new_connection(ct, &new_cnxn_data,
428 packet, ct->misc_options.synproxy_enabled,
431 if (unlikely(packet_action == RTE_CT_DROP_PACKET)) {
432 ct->counters->pkts_drop_invalid_conn++;
433 return RTE_CT_DROP_PACKET;
436 /* This packet creates a connection . */
437 int32_t position = rte_hash_add_key(ct->rhash, key);
440 ("Failed to add new connection to hash table %d, pkt_num:%d\n",
442 return RTE_CT_DROP_PACKET;
445 ct->positions[pkt_num] = position;
447 new_hash_entry = &ct->hash_table_entries[position];
449 /* update fields in new_cnxn_data not set by new_connection */
451 memcpy(new_cnxn_data.key, key, sizeof(new_cnxn_data.key));
452 new_cnxn_data.key_is_client_order = key_is_client_order;
453 new_cnxn_data.protocol = TCP_PROTOCOL;
454 rte_cnxn_ip_type(&new_cnxn_data.type, packet);
455 rte_memcpy(new_hash_entry, &new_cnxn_data,
456 sizeof(struct rte_ct_cnxn_data));
457 new_hash_entry->counters.packets_forwarded = 1;
458 new_hash_entry->counters.packets_dropped = 0;
459 ct->counters->current_active_sessions++;
460 ct->counters->sessions_activated++;
462 if (packet_action == RTE_CT_SEND_CLIENT_SYNACK) {
463 /* this is a synproxied connecton */
464 /* must remember mss, window scaling etc. from client */
466 rte_sp_parse_options(packet, new_hash_entry);
469 * update packet to a SYN/ACK directed to the client,
470 * including default header options
473 rte_sp_cvt_to_spoofed_client_synack(new_hash_entry,
477 * run updated packet through connection tracking so
478 * cnxn data updated appropriately and timer set for syn
479 * received state, not syn sent.
481 packet_action = rte_ct_verify_tcp_packet(ct,
482 new_hash_entry, packet,
483 !key_is_client_order,
486 if (unlikely(packet_action != RTE_CT_FORWARD_PACKET)) {
487 /* should never get here */
488 printf("Serious error in synproxy generating ");
490 return RTE_CT_DROP_PACKET;
492 ct->counters->pkts_forwarded++;
493 /* spoofed packet good to go */
494 return RTE_CT_SEND_CLIENT_SYNACK;
496 rte_ct_set_timer_for_new_cnxn(ct, new_hash_entry);
500 /* TODO: is it possible that earlier packet in this batch caused new
501 * entry to be added for the connection? Seems unlikely, since it
502 * would require multiple packets from the same side of the connection
503 * one after another immediately, and the TCP connection OPEN requires
504 * acknowledgement before further packets. What about simultaneous
505 * OPEN? Only if both sides are on same input port. Is that possible?
507 /* if made it here, packet will be forwarded */
508 ct->counters->pkts_forwarded++;
509 return RTE_CT_FORWARD_PACKET;
513 rte_ct_cnxn_tracker_batch_lookup_basic(
514 struct rte_ct_cnxn_tracker *ct,
515 struct rte_mbuf **pkts,
517 uint64_t no_new_cnxn_mask,
518 uint64_t *reply_pkt_mask,
519 uint64_t *hijack_mask)
521 /* bitmap of packets left to process */
522 uint64_t pkts_to_process = pkts_mask;
523 /* bitmap of valid packets to return */
524 uint64_t valid_packets = pkts_mask;
525 uint8_t compacting_map[RTE_HASH_LOOKUP_BULK_MAX];
526 /* for pkt, key in originators direction? */
527 uint8_t key_orig_dir[RTE_HASH_LOOKUP_BULK_MAX];
528 uint32_t packets_for_lookup = 0;
529 int32_t positions[RTE_HASH_LOOKUP_BULK_MAX];
531 struct rte_ct_cnxn_data new_cnxn_data;
533 if (CNXN_TRX_DEBUG > 1) {
534 printf("Enter cnxn tracker %p", ct);
535 printf(" synproxy batch lookup with packet mask %p\n",
539 rte_ct_forget_new_connections(ct);
544 * Use bulk lookup into hash table for performance reasons. Cannot have
545 * "empty slots" in the bulk lookup,so need to create a compacted table.
548 for (; pkts_to_process;) {
549 uint8_t pos = (uint8_t) __builtin_ctzll(pkts_to_process);
550 /* bitmask representing only this packet */
551 uint64_t pkt_mask = 1LLU << pos;
552 /* remove this packet from remaining list */
553 pkts_to_process &= ~pkt_mask;
555 struct rte_mbuf *pkt = pkts[pos];
557 int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(pkt);
559 if (unlikely(ip_hdr_size_bytes < 0)) {
560 /* Not IPv4, ignore. */
564 void *ip_hdr = RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
566 /* TCP and UDP ports at same offset, just use TCP for
569 struct tcp_hdr *thdr =
570 (struct tcp_hdr *)RTE_MBUF_METADATA_UINT32_PTR(pkt,
571 (IP_START + ip_hdr_size_bytes));
572 uint16_t src_port = rte_bswap16(thdr->src_port);
573 uint16_t dst_port = rte_bswap16(thdr->dst_port);
575 if (ip_hdr_size_bytes == IPv4_HEADER_SIZE) {
576 struct ipv4_hdr *ihdr = (struct ipv4_hdr *)ip_hdr;
577 uint8_t proto = ihdr->next_proto_id;
579 if (!(proto == TCP_PROTOCOL || proto == UDP_PROTOCOL)) {
580 /* only tracking TCP and UDP at this time */
585 * Load the addresses and ports, and convert from Intel
586 * to network byte order. Strictly speaking, it is not
587 * necessary to do this conversion, as this data is only
588 * used to create a hash key.
590 uint32_t src_addr = rte_bswap32(ihdr->src_addr);
591 uint32_t dst_addr = rte_bswap32(ihdr->dst_addr);
593 if (CNXN_TRX_DEBUG > 2) {
594 if (CNXN_TRX_DEBUG > 4)
595 rte_ct_cnxn_print_pkt(pkt,
598 /* need to create compacted table of pointers to pass
602 compacting_map[packets_for_lookup] = pos;
603 key_orig_dir[packets_for_lookup] =
604 rte_ct_create_cnxn_hashkey(&src_addr, &dst_addr,
608 [packets_for_lookup][0],
610 packets_for_lookup++;
613 if (ip_hdr_size_bytes == IPv6_HEADER_SIZE) {
614 struct ipv6_hdr *ihdr = (struct ipv6_hdr *)ip_hdr;
615 uint8_t proto = ihdr->proto;
617 if (!(proto == TCP_PROTOCOL || proto == UDP_PROTOCOL)) {
618 /* only tracking TCP and UDP at this time */
622 if (CNXN_TRX_DEBUG > 2) {
623 if (CNXN_TRX_DEBUG > 4)
624 rte_ct_cnxn_print_pkt(pkt,
628 /* need to create compacted table of pointers to pass
632 compacting_map[packets_for_lookup] = pos;
633 key_orig_dir[packets_for_lookup] =
634 rte_ct_create_cnxn_hashkey(
635 (uint32_t *) ihdr->src_addr,
636 (uint32_t *) ihdr->dst_addr,
640 [packets_for_lookup][0],
642 packets_for_lookup++;
647 if (unlikely(packets_for_lookup == 0))
648 return valid_packets; /* no suitable packet for lookup */
650 /* Clear all the data to make sure no stack garbage is in it */
651 memset(&new_cnxn_data, 0, sizeof(struct rte_ct_cnxn_data));
653 /* lookup all tcp & udp packets in the connection table */
656 rte_hash_lookup_bulk(ct->rhash, (const void **)&ct->hash_key_ptrs,
657 packets_for_lookup, &positions[0]);
659 if (unlikely(lookup_result < 0)) {
660 /* TODO: change a log */
661 printf("Unexpected hash table problem, discarding all packets");
662 return 0; /* unknown error, just discard all packets */
665 for (i = 0; i < packets_for_lookup; i++) {
666 if (positions[i] >= 0)
667 printf("@CT positions[i]= %d, compacting_map[i]= %d\n",
668 positions[i], compacting_map[i]);
671 for (i = 0; i < packets_for_lookup; i++) {
672 /* index into hash table entries */
673 int hash_table_entry = positions[i];
674 /* index into packet table of this packet */
675 uint8_t pkt_index = compacting_map[i];
676 /* bitmask representing only this packet */
677 uint64_t pkt_mask = 1LLU << pkt_index;
678 uint8_t key_is_client_order = key_orig_dir[i];
679 uint32_t *key = ct->hash_key_ptrs[pkt_index];
680 uint8_t protocol = *(key + 9);
681 struct rte_mbuf *packet = pkts[pkt_index];
682 int no_new_cnxn = (pkt_mask & no_new_cnxn_mask) != 0;
684 /* rte_ct_print_hashkey(key); */
686 if (protocol == TCP_PROTOCOL) {
687 enum rte_ct_packet_action tcp_pkt_action;
689 int ip_hdr_size_bytes = rte_ct_get_IP_hdr_size(packet);
690 tcp_pkt_action = rte_ct_handle_tcp_lookup(ct, packet,
691 pkt_index, key_is_client_order,
692 key, hash_table_entry, no_new_cnxn,
695 switch (tcp_pkt_action) {
697 case RTE_CT_SEND_CLIENT_SYNACK:
698 case RTE_CT_SEND_SERVER_ACK:
699 /* altered packet or copy must be returned
702 *reply_pkt_mask |= pkt_mask;
705 case RTE_CT_SEND_SERVER_SYN:
706 case RTE_CT_FORWARD_PACKET:
710 *hijack_mask |= pkt_mask;
714 /* bad packet, clear mask to drop */
715 valid_packets ^= pkt_mask;
716 ct->counters->pkts_drop++;
720 /* rte_ct_cnxn_print_pkt(pkts[pkt_index]); */
721 } else { /* UDP entry */
723 if (hash_table_entry >= 0) {
725 * connection found for this packet. Check that
726 * this is a valid packet for connection
729 struct rte_ct_cnxn_data *entry =
730 &ct->hash_table_entries[hash_table_entry];
732 if (rte_ct_udp_packet
733 (ct, entry, pkts[pkt_index],
734 key_is_client_order)) {
735 entry->counters.packets_forwarded++;
736 ct->counters->pkts_forwarded++;
740 * connection not found in bulk hash lookup,
741 * but might have been added in this batch
744 struct rte_ct_cnxn_data *recent_entry =
745 rte_ct_search_new_connections(ct, key);
747 if (recent_entry != NULL) {
748 if (rte_ct_udp_packet(ct, recent_entry,
750 key_is_client_order)) {
751 recent_entry->counters.
753 ct->counters->pkts_forwarded++;
756 /* no existing connection, try to add
761 /* new cnxn not allowed, clear
764 valid_packets ^= pkt_mask;
765 ct->counters->pkts_drop++;
767 pkts_drop_invalid_conn++;
771 if (rte_ct_udp_new_connection(ct,
774 /* This packet creates a
784 struct rte_ct_cnxn_data
785 *new_hash_entry = &ct->
786 hash_table_entries[position];
789 *update fields in new_cnxn_data
790 * not set by "new_connection"
793 memcpy(new_cnxn_data.key, key,
794 sizeof(new_cnxn_data.key));
798 = key_is_client_order;
799 new_cnxn_data.protocol =
804 rte_memcpy(new_hash_entry,
809 new_hash_entry->counters.
810 packets_forwarded = 1;
811 ct->counters->pkts_forwarded++;
812 new_hash_entry->counters.
814 ct->counters->pkts_drop = 0;
816 current_active_sessions++;
818 sessions_activated++;
823 rte_ct_set_cnxn_timer_for_udp(
826 RTE_CT_UDP_UNREPLIED);
828 rte_ct_remember_new_connection(
837 } /* packets_for_lookup */
839 if (CNXN_TRX_DEBUG > 1) {
840 printf("Exit cnxn tracker synproxy batch lookup with");
841 printf(" packet mask %p\n", (void *)valid_packets);
844 return valid_packets;
848 rte_ct_cnxn_tracker_batch_lookup_with_synproxy(
849 struct rte_ct_cnxn_tracker *ct,
850 struct rte_mbuf **pkts,
852 struct rte_synproxy_helper *sp_helper)
854 return rte_ct_cnxn_tracker_batch_lookup_basic(ct, pkts, pkts_mask, 0,
855 &sp_helper->reply_pkt_mask, &sp_helper->hijack_mask);
858 uint64_t cgnapt_ct_process(
859 struct rte_ct_cnxn_tracker *ct,
860 struct rte_mbuf **pkts,
862 struct rte_CT_helper *ct_helper)
864 /* to disable SynProxy for CGNAT */
865 rte_ct_disable_synproxy(ct);
866 return rte_ct_cnxn_tracker_batch_lookup_basic(ct, pkts, pkts_mask,
867 ct_helper->no_new_cnxn_mask,
868 &ct_helper->reply_pkt_mask,
869 &ct_helper->hijack_mask);
873 rte_ct_cnxn_tracker_batch_lookup(
874 struct rte_ct_cnxn_tracker *ct,
875 struct rte_mbuf **pkts,
877 struct rte_CT_helper *ct_helper)
880 return rte_ct_cnxn_tracker_batch_lookup_basic(ct, pkts, pkts_mask,
881 ct_helper->no_new_cnxn_mask,
882 &ct_helper->reply_pkt_mask, &ct_helper->hijack_mask);
886 void rte_ct_cnxn_tracker_batch_lookup_type(
887 struct rte_ct_cnxn_tracker *ct,
888 struct rte_mbuf **pkts,
890 struct rte_CT_helper *ct_helper,
891 uint8_t ip_hdr_size_bytes)
894 rte_ct_cnxn_tracker_batch_lookup_basic_type(ct, pkts, pkts_mask,
895 ct_helper->no_new_cnxn_mask,
896 &ct_helper->reply_pkt_mask, &ct_helper->hijack_mask,
903 rte_ct_cnxn_tracker_batch_lookup_with_new_cnxn_control(
904 struct rte_ct_cnxn_tracker *ct,
905 struct rte_mbuf **pkts,
907 uint64_t no_new_cnxn_mask)
911 return rte_ct_cnxn_tracker_batch_lookup_basic(ct, pkts, pkts_mask,
913 &dont_care, &dont_care);
918 rte_ct_initialize_default_timeouts(struct rte_ct_cnxn_tracker *new_cnxn_tracker)
921 /* timer system init */
923 uint64_t hertz = rte_get_tsc_hz();
925 new_cnxn_tracker->hertz = hertz;
926 new_cnxn_tracker->timing_cycles_per_timing_step = hertz / 10;
927 new_cnxn_tracker->timing_100ms_steps_previous = 0;
928 new_cnxn_tracker->timing_100ms_steps = 0;
929 new_cnxn_tracker->timing_last_time = rte_get_tsc_cycles();
931 /* timeouts in seconds */
932 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
933 [RTE_CT_TCP_SYN_SENT] = 120 * hertz;
934 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
935 [RTE_CT_TCP_SYN_RECV] = 60 * hertz;
937 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
938 [RTE_CT_TCP_ESTABLISHED] = 60 * 60 * 24 * 5 * hertz;
940 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
941 [RTE_CT_TCP_FIN_WAIT] = 120 * hertz;
942 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
943 [RTE_CT_TCP_CLOSE_WAIT] = 60 * hertz;
944 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
945 [RTE_CT_TCP_LAST_ACK] = 30 * hertz;
946 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
947 [RTE_CT_TCP_TIME_WAIT] = 120 * hertz;
948 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
949 [RTE_CT_TCP_CLOSE] = 10 * hertz;
950 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
951 [RTE_CT_TCP_SYN_SENT_2] = 120 * hertz;
952 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
953 [RTE_CT_TCP_RETRANS] = 300 * hertz;
954 new_cnxn_tracker->ct_timeout.tcptimeout.tcp_timeouts
955 [RTE_CT_TCP_UNACK] = 300 * hertz;
957 new_cnxn_tracker->ct_timeout.udptimeout.udp_timeouts
958 [RTE_CT_UDP_UNREPLIED] = 30 * hertz;
959 new_cnxn_tracker->ct_timeout.udptimeout.udp_timeouts
960 [RTE_CT_UDP_REPLIED] = 180 * hertz;
961 /* miscellaneous init */
962 new_cnxn_tracker->misc_options.tcp_max_retrans =
963 RTE_CT_TCP_MAX_RETRANS;
964 new_cnxn_tracker->misc_options.tcp_loose = 0;
965 new_cnxn_tracker->misc_options.tcp_be_liberal = 0;
968 for (i=0; i < RTE_HASH_LOOKUP_BULK_MAX ;i ++ )
969 new_cnxn_tracker->positions[i] = -1;
975 struct rte_CT_counter_block rte_CT_counter_table[MAX_CT_INSTANCES]
977 int rte_CT_hi_counter_block_in_use = -1;
980 rte_ct_initialize_cnxn_tracker_with_synproxy(
981 struct rte_ct_cnxn_tracker *new_cnxn_tracker,
982 uint32_t max_connection_count,
984 uint16_t pointer_offset)
988 struct rte_CT_counter_block *counter_ptr;
990 * TODO: Should number of entries be something like
991 * max_connection_count * 1.1 to allow for unused space
992 * and thus increased performance of hash table, at a cost of memory???
995 new_cnxn_tracker->pointer_offset = pointer_offset;
997 memset(new_cnxn_tracker->name, '\0', sizeof(new_cnxn_tracker->name));
998 strncpy(new_cnxn_tracker->name, name, strlen(new_cnxn_tracker->name));
999 //strcpy(new_cnxn_tracker->name, name);
1000 /* + (max_connection_count >> 3); */
1001 uint32_t number_of_entries = max_connection_count;
1003 size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct rte_ct_cnxn_data) *
1005 new_cnxn_tracker->hash_table_entries =
1006 rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
1007 if (new_cnxn_tracker->hash_table_entries == NULL) {
1008 printf(" Not enough memory, or invalid arguments\n");
1011 new_cnxn_tracker->num_cnxn_entries = number_of_entries;
1013 /* initialize all timers */
1015 for (i = 0; i < number_of_entries; i++)
1016 rte_timer_init(&new_cnxn_tracker->hash_table_entries[i].timer);
1018 /* pointers for temp storage used during bulk hash */
1019 for (i = 0; i < RTE_HASH_LOOKUP_BULK_MAX; i++)
1020 new_cnxn_tracker->hash_key_ptrs[i] =
1021 &new_cnxn_tracker->hash_keys[i][0];
1024 * Now allocate a counter block entry.It appears that the initialization
1025 * of these threads is serialized on core 0 so no lock is necessary
1028 if (rte_CT_hi_counter_block_in_use == MAX_CT_INSTANCES)
1031 rte_CT_hi_counter_block_in_use++;
1032 counter_ptr = &rte_CT_counter_table[rte_CT_hi_counter_block_in_use];
1034 new_cnxn_tracker->counters = counter_ptr;
1036 /* set up hash table parameters, then create hash table */
1037 struct rte_hash_parameters rhash_parms = {
1039 .entries = number_of_entries,
1040 .hash_func = NULL, /* use default hash */
1042 .hash_func_init_val = 0,
1043 .socket_id = rte_socket_id(),
1044 .extra_flag = 1 /*This is needed for TSX memory*/
1047 new_cnxn_tracker->rhash = rte_hash_create(&rhash_parms);
1053 rte_ct_initialize_cnxn_tracker(
1054 struct rte_ct_cnxn_tracker *new_cnxn_tracker,
1055 uint32_t max_connection_count,
1058 return rte_ct_initialize_cnxn_tracker_with_synproxy(new_cnxn_tracker,
1059 max_connection_count, name, 0);
1063 rte_ct_free_cnxn_tracker_resources(struct rte_ct_cnxn_tracker *old_cnxn_tracker)
1065 rte_free(old_cnxn_tracker->hash_table_entries);
1066 rte_hash_free(old_cnxn_tracker->rhash);
1071 rte_ct_get_cnxn_tracker_size(void)
1073 return sizeof(struct rte_ct_cnxn_tracker);
1077 rte_ct_cnxn_timer_expired(struct rte_timer *rt, void *arg);
1080 rte_ct_set_cnxn_timer(
1081 struct rte_ct_cnxn_tracker *ct,
1082 struct rte_ct_cnxn_data *cd,
1083 uint64_t ticks_until_timeout)
1086 * pointer to cnxn_data will be stored in timer system as pointer to
1087 * rte_timer for later cast back to cnxn_data during timeout handling
1090 struct rte_timer *rt = (struct rte_timer *)cd;
1092 /* execute timeout on timer core */
1093 uint32_t core_id = get_timer_core_id();
1095 /* execute timeout on current core */
1096 uint32_t core_id = rte_lcore_id();
1098 /* safe to reset since timeouts handled synchronously
1099 * by rte_timer_manage
1101 int success = rte_timer_reset(rt, ticks_until_timeout, SINGLE, core_id,
1102 rte_ct_cnxn_timer_expired, ct);
1105 /* TODO: Change to log, perhaps something else?
1106 * This should not happen
1108 printf("CNXN_TRACKER: Failed to set connection timer.\n");
1113 * For the given connection, set a timeout based on the given state. If the
1114 * timer is already set, this call will reset the timer with a new value.
1118 rte_ct_set_cnxn_timer_for_tcp(
1119 struct rte_ct_cnxn_tracker *ct,
1120 struct rte_ct_cnxn_data *cd,
1124 cd->expected_timeout =
1125 (ct->timing_100ms_steps * ct->timing_cycles_per_timing_step) +
1126 ct->ct_timeout.tcptimeout.tcp_timeouts[tcp_state];
1128 if (tcp_state == cd->state_used_for_timer) {
1130 * Don't reset timer, too expensive. Instead, determine time
1131 * elapsed since start of timer. When this timer expires, the
1132 * timer will be reset to the elapsed timer. So if in a state
1133 * with a 5 minute timer last sees a packet 4 minutes into the
1134 * timer, the timer when expires will be reset to 4 minutes.
1135 * This means the timer will then expire 5 minutes after
1142 printf("Set Timer for connection %p and state %s\n", cd,
1143 rte_ct_tcp_names[tcp_state]);
1145 rte_ct_set_cnxn_timer(ct, cd,
1147 tcptimeout.tcp_timeouts[tcp_state]);
1148 cd->state_used_for_timer = tcp_state;
1152 * For the given connection, set a timeout based on the given state.
1153 * If the timer is already set,
1154 * this call will reset the timer with a new value.
1158 rte_ct_set_cnxn_timer_for_udp(
1159 struct rte_ct_cnxn_tracker *ct,
1160 struct rte_ct_cnxn_data *cd,
1164 cd->expected_timeout = (ct->timing_cycles_per_timing_step) +
1165 ct->ct_timeout.udptimeout.udp_timeouts[udp_state];
1167 if (udp_state == cd->state_used_for_timer) {
1169 * Don't reset timer, too expensive. Instead, determine time
1170 * elapsed since start of timer. When this timer expires, the
1171 * timer will be reset to the elapsed timer. So if in a state
1172 * with a 5 minute timer last sees a packet 4 minutes into the
1173 * timer, the timer when expires will be reset to 4 minutes.
1174 * This means the timer will then
1175 * expire 5 minutes after the last packet.
1181 printf("Set Timer for connection %p and state %s\n", cd,
1182 rte_ct_udp_names[udp_state]);
1183 rte_ct_set_cnxn_timer(ct, cd,
1185 udptimeout.udp_timeouts[udp_state]);
1186 cd->state_used_for_timer = udp_state;
1189 /* Cancel the timer associated with the connection.
1190 * Safe to call if no timer set.
1193 rte_ct_cancel_cnxn_timer(struct rte_ct_cnxn_data *cd)
1196 printf("Cancel Timer\n");
1198 rte_timer_stop(&cd->timer);
1202 rte_ct_handle_expired_timers(struct rte_ct_cnxn_tracker *ct)
1205 * If current time (in 100 ms increments) is different from the
1206 * time it was last viewed, then check for and process expired timers.
1209 uint64_t new_time = rte_get_tsc_cycles();
1210 uint64_t time_diff = new_time - ct->timing_last_time;
1212 if (time_diff >= ct->timing_cycles_per_timing_step) {
1213 ct->timing_last_time = new_time;
1214 ct->timing_100ms_steps++;
1217 if (ct->timing_100ms_steps != ct->timing_100ms_steps_previous) {
1219 ct->timing_100ms_steps_previous = ct->timing_100ms_steps;
1223 /* timer has expired. Need to delete connection entry */
1226 rte_ct_cnxn_timer_expired(struct rte_timer *rt, void *arg)
1228 /* the pointer to the rte_timer was actually a pointer
1231 struct rte_ct_cnxn_data *cd = (struct rte_ct_cnxn_data *)rt;
1232 struct rte_ct_cnxn_tracker *ct = (struct rte_ct_cnxn_tracker *)arg;
1236 * Check to see if the timer has "really" expired. If traffic occured
1237 * since the timer was set, the timer needs be extended, so that timer
1238 * expires the appropriate amount after that last packet.
1241 uint64_t current_time = ct->timing_100ms_steps *
1242 ct->timing_cycles_per_timing_step;
1244 if (cd->expected_timeout >= current_time) {
1245 uint64_t time_diff = cd->expected_timeout - current_time;
1247 rte_ct_set_cnxn_timer(ct, cd, time_diff);
1251 if (cd->protocol == TCP_PROTOCOL) {
1252 if (cd->state_used_for_timer == RTE_CT_TCP_TIME_WAIT ||
1253 cd->state_used_for_timer == RTE_CT_TCP_CLOSE)
1254 ct->counters->sessions_closed++;
1256 ct->counters->sessions_timedout++;
1257 /* if synproxied connection, free list of buffered
1261 if (cd->ct_protocol.synproxy_data.synproxied)
1262 rte_ct_release_buffered_packets(ct, cd);
1264 } else if (cd->protocol == UDP_PROTOCOL)
1265 ct->counters->sessions_closed++;
1266 if (ct->counters->current_active_sessions > 0)
1267 ct->counters->current_active_sessions--;
1269 if (RTE_CT_TIMER_EXPIRED_DUMP) {
1270 uint64_t percent = (cd->counters.packets_dropped * 10000) /
1271 (cd->counters.packets_forwarded +
1272 cd->counters.packets_dropped);
1274 if (cd->protocol == TCP_PROTOCOL) {
1275 printf("CnxnTrkr %s, timed-out TCP Connection: %p,",
1277 printf(" %s, pkts forwarded %"
1278 PRIu64 ", pkts dropped %" PRIu64
1280 rte_ct_tcp_names[cd->state_used_for_timer],
1281 cd->counters.packets_forwarded,
1282 cd->counters.packets_dropped,
1283 (uint32_t) (percent / 100),
1284 (uint32_t) (percent % 100));
1285 } else if (cd->protocol == UDP_PROTOCOL) {
1286 printf("CnxnTrkr %s, Timed-out UDP Connection: %p,",
1288 printf(" %s, pkts forwarded %" PRIu64
1289 ", pkts dropped %" PRIu64 ", drop%% %u.%u\n",
1290 rte_ct_udp_names[cd->state_used_for_timer],
1291 cd->counters.packets_forwarded,
1292 cd->counters.packets_dropped,
1293 (uint32_t) (percent / 100),
1294 (uint32_t) (percent % 100));
1298 success = rte_hash_del_key(ct->rhash, &cd->key);
1301 /* TODO: change to a log */
1302 rte_ct_print_hashkey(cd->key);
1307 struct rte_CT_counter_block *
1308 rte_ct_get_counter_address(struct rte_ct_cnxn_tracker *ct)
1310 return ct->counters;
1314 rte_ct_set_configuration_options(struct rte_ct_cnxn_tracker *ct,
1315 char *name, char *value)
1317 /* check non-time values first */
1318 int ival = atoi(value);
1321 if (strcmp(name, "tcp_loose") == 0) {
1322 ct->misc_options.tcp_loose = ival;
1326 /* tcp_be_liberal */
1327 if (strcmp(name, "tcp_be_liberal") == 0) {
1328 ct->misc_options.tcp_be_liberal = ival;
1332 /* tcp_max_retrans */
1333 if (strcmp(name, "tcp_max_retrans") == 0) {
1334 ct->misc_options.tcp_max_retrans = ival;
1338 uint64_t time_value = ival * ct->hertz;
1341 /* configuration of timer values */
1344 if (strcmp(name, "tcp_syn_sent") == 0) {
1345 if (time_value == 0)
1347 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_SYN_SENT] =
1353 if (strcmp(name, "tcp_syn_recv") == 0) {
1354 if (time_value == 0)
1356 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_SYN_RECV] =
1361 /* tcp_established */
1362 if (strcmp(name, "tcp_established") == 0) {
1363 if (time_value == 0)
1365 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_ESTABLISHED] =
1371 if (strcmp(name, "tcp_fin_wait") == 0) {
1372 if (time_value == 0)
1374 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_FIN_WAIT] =
1379 /* tcp_close_wait */
1380 if (strcmp(name, "tcp_close_wait") == 0) {
1381 if (time_value == 0)
1383 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_CLOSE_WAIT] =
1389 if (strcmp(name, "tcp_last_ack") == 0) {
1390 if (time_value == 0)
1392 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_LAST_ACK] =
1398 if (strcmp(name, "tcp_time_wait") == 0) {
1399 if (time_value == 0)
1401 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_TIME_WAIT] =
1407 if (strcmp(name, "tcp_close") == 0) {
1408 if (time_value == 0)
1410 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_CLOSE] =
1415 /* tcp_syn_sent_2 */
1416 if (strcmp(name, "tcp_syn_sent_2") == 0) {
1417 if (time_value == 0)
1419 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_SYN_SENT_2] =
1425 if (strcmp(name, "tcp_retrans") == 0) {
1426 if (time_value == 0)
1428 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_RETRANS] =
1434 if (strcmp(name, "tcp_unack") == 0) {
1435 if (time_value == 0)
1437 ct->ct_timeout.tcptimeout.tcp_timeouts[RTE_CT_TCP_UNACK] =
1443 if (strcmp(name, "udp_unreplied") == 0) {
1444 if (time_value == 0)
1446 ct->ct_timeout.udptimeout.udp_timeouts[RTE_CT_UDP_UNREPLIED] =
1452 if (strcmp(name, "udp_replied") == 0) {
1453 if (time_value == 0)
1455 ct->ct_timeout.udptimeout.udp_timeouts[RTE_CT_UDP_REPLIED] =
1463 rte_ct_cnxn_tracker_batch_lookup_basic_type(
1464 struct rte_ct_cnxn_tracker *ct,
1465 struct rte_mbuf **pkts,
1466 uint64_t *pkts_mask,
1467 uint64_t no_new_cnxn_mask,
1468 uint64_t *reply_pkt_mask,
1469 uint64_t *hijack_mask,
1470 uint8_t ip_hdr_size_bytes)
1472 /* bitmap of packets left to process */
1473 uint64_t pkts_to_process = *pkts_mask;
1474 /* bitmap of valid packets to return */
1475 uint8_t compacting_map[RTE_HASH_LOOKUP_BULK_MAX];
1476 /* for pkt, key in originators direction? */
1477 uint8_t key_orig_dir[RTE_HASH_LOOKUP_BULK_MAX];
1478 uint32_t packets_for_lookup = 0;
1479 int32_t positions[RTE_HASH_LOOKUP_BULK_MAX];
1481 struct rte_ct_cnxn_data new_cnxn_data;
1483 if (CNXN_TRX_DEBUG > 1) {
1484 printf("Enter cnxn tracker %p", ct);
1485 printf(" synproxy batch lookup with packet mask %p\n",
1486 (void *)*pkts_mask);
1489 rte_ct_forget_new_connections(ct);
1490 *reply_pkt_mask = 0;
1494 * Use bulk lookup into hash table for performance reasons. Cannot have
1495 * "empty slots" in the bulk lookup,so need to create a compacted table.
1498 switch (ip_hdr_size_bytes) {
1499 case IPv4_HEADER_SIZE:
1500 for (; pkts_to_process;) {
1501 uint8_t pos = (uint8_t) __builtin_ctzll(
1503 /* bitmask representing only this packet */
1504 uint64_t pkt_mask = 1LLU << pos;
1505 /* remove this packet from remaining list */
1506 pkts_to_process &= ~pkt_mask;
1508 struct rte_mbuf *pkt = pkts[pos];
1511 /* TCP and UDP ports at same offset, just use TCP for
1512 * offset calculation
1514 struct tcp_hdr *thdr = (struct tcp_hdr *)
1515 RTE_MBUF_METADATA_UINT32_PTR(pkt,
1516 (IP_START + ip_hdr_size_bytes));
1517 uint16_t src_port = rte_bswap16(thdr->src_port);
1518 uint16_t dst_port = rte_bswap16(thdr->dst_port);
1520 struct ipv4_hdr *ihdr = (struct ipv4_hdr *)
1521 RTE_MBUF_METADATA_UINT32_PTR(pkt, IP_START);
1522 uint8_t proto = ihdr->next_proto_id;
1524 if (!(proto == TCP_PROTOCOL || proto == UDP_PROTOCOL)) {
1525 /* only tracking TCP and UDP at this time */
1530 * Load the addresses and ports, and convert from Intel
1531 * to network byte order. Strictly speaking, it is not
1532 * necessary to do this conversion, as this data is only
1533 * used to create a hash key.
1535 uint32_t src_addr = rte_bswap32(ihdr->src_addr);
1536 uint32_t dst_addr = rte_bswap32(ihdr->dst_addr);
1538 if (CNXN_TRX_DEBUG > 2) {
1539 if (CNXN_TRX_DEBUG > 4)
1540 rte_ct_cnxn_print_pkt(pkt,
1543 /* need to create compacted table of pointers to pass
1547 compacting_map[packets_for_lookup] = pos;
1548 key_orig_dir[packets_for_lookup] =
1549 rte_ct_create_cnxn_hashkey(&src_addr, &dst_addr,
1553 [packets_for_lookup][0],
1555 packets_for_lookup++;
1558 case IPv6_HEADER_SIZE:
1559 for (; pkts_to_process;) {
1560 uint8_t pos = (uint8_t) __builtin_ctzll(
1562 /* bitmask representing only this packet */
1563 uint64_t pkt_mask = 1LLU << pos;
1564 /* remove this packet from remaining list */
1565 pkts_to_process &= ~pkt_mask;
1567 struct rte_mbuf *pkt = pkts[pos];
1570 void *ip_hdr = RTE_MBUF_METADATA_UINT32_PTR(pkt,
1573 /* TCP and UDP ports at same offset, just use TCP for
1574 * offset calculation
1576 struct tcp_hdr *thdr = (struct tcp_hdr *)
1577 RTE_MBUF_METADATA_UINT32_PTR(pkt,
1578 (IP_START + ip_hdr_size_bytes));
1579 uint16_t src_port = rte_bswap16(thdr->src_port);
1580 uint16_t dst_port = rte_bswap16(thdr->dst_port);
1582 struct ipv6_hdr *ihdr = (struct ipv6_hdr *)ip_hdr;
1583 uint8_t proto = ihdr->proto;
1585 if (!(proto == TCP_PROTOCOL || proto == UDP_PROTOCOL)) {
1586 /* only tracking TCP and UDP at this time */
1590 if (CNXN_TRX_DEBUG > 2) {
1591 if (CNXN_TRX_DEBUG > 4)
1592 rte_ct_cnxn_print_pkt(pkt,
1596 /* need to create compacted table of pointers to pass
1600 compacting_map[packets_for_lookup] = pos;
1601 key_orig_dir[packets_for_lookup] =
1602 rte_ct_create_cnxn_hashkey(
1603 (uint32_t *) ihdr->src_addr,
1604 (uint32_t *) ihdr->dst_addr,
1608 [packets_for_lookup][0],
1610 packets_for_lookup++;
1616 if (unlikely(packets_for_lookup == 0))
1617 return; /* no suitable packet for lookup */
1619 /* Clear all the data to make sure no stack garbage is in it */
1620 memset(&new_cnxn_data, 0, sizeof(struct rte_ct_cnxn_data));
1622 /* lookup all tcp & udp packets in the connection table */
1624 int lookup_result = rte_hash_lookup_bulk(ct->rhash,
1625 (const void **)&ct->hash_key_ptrs,
1626 packets_for_lookup, &positions[0]);
1628 if (unlikely(lookup_result < 0)) {
1629 /* TODO: change a log */
1630 printf("Unexpected hash table problem, discarding all packets");
1632 return; /* unknown error, just discard all packets */
1634 for (i = 0; i < packets_for_lookup; i++) {
1635 /* index into hash table entries */
1636 int hash_table_entry = positions[i];
1637 /* index into packet table of this packet */
1638 uint8_t pkt_index = compacting_map[i];
1639 /* bitmask representing only this packet */
1640 uint64_t pkt_mask = 1LLU << pkt_index;
1641 uint8_t key_is_client_order = key_orig_dir[i];
1642 uint32_t *key = ct->hash_key_ptrs[pkt_index];
1643 uint8_t protocol = *(key + 9);
1644 struct rte_mbuf *packet = pkts[pkt_index];
1645 int no_new_cnxn = (pkt_mask & no_new_cnxn_mask) != 0;
1647 /* rte_ct_print_hashkey(key); */
1649 if (protocol == TCP_PROTOCOL) {
1650 enum rte_ct_packet_action tcp_pkt_action;
1652 tcp_pkt_action = rte_ct_handle_tcp_lookup(ct, packet,
1653 pkt_index, key_is_client_order,
1654 key, hash_table_entry, no_new_cnxn,
1657 switch (tcp_pkt_action) {
1659 case RTE_CT_SEND_CLIENT_SYNACK:
1660 case RTE_CT_SEND_SERVER_ACK:
1661 /* altered packet or copy must be returned
1664 *reply_pkt_mask |= pkt_mask;
1667 case RTE_CT_SEND_SERVER_SYN:
1668 case RTE_CT_FORWARD_PACKET:
1672 *hijack_mask |= pkt_mask;
1676 /* bad packet, clear mask to drop */
1677 *pkts_mask ^= pkt_mask;
1678 ct->counters->pkts_drop++;
1681 /* rte_ct_cnxn_print_pkt(pkts[pkt_index]); */
1683 } else { /* UDP entry */
1685 if (hash_table_entry >= 0) {
1687 * connection found for this packet. Check that
1688 * this is a valid packet for connection
1691 struct rte_ct_cnxn_data *entry =
1692 &ct->hash_table_entries[hash_table_entry];
1694 if (rte_ct_udp_packet
1695 (ct, entry, pkts[pkt_index],
1696 key_is_client_order)) {
1697 entry->counters.packets_forwarded++;
1698 ct->counters->pkts_forwarded++;
1702 * connection not found in bulk hash lookup,
1703 * but might have been added in this batch
1706 struct rte_ct_cnxn_data *recent_entry =
1707 rte_ct_search_new_connections(ct, key);
1709 if (recent_entry != NULL) {
1710 if (rte_ct_udp_packet(ct, recent_entry,
1712 key_is_client_order)) {
1713 recent_entry->counters.
1714 packets_forwarded++;
1715 ct->counters->pkts_forwarded++;
1718 /* no existing connection, try to add
1723 /* new cnxn not allowed, clear
1726 *pkts_mask ^= pkt_mask;
1727 ct->counters->pkts_drop++;
1729 pkts_drop_invalid_conn++;
1733 if (rte_ct_udp_new_connection(ct,
1734 &new_cnxn_data, pkts[pkt_index])) {
1735 /* This packet creates a
1739 rte_hash_add_key(ct->
1745 struct rte_ct_cnxn_data
1746 *new_hash_entry = &ct->
1747 hash_table_entries[position];
1750 *update fields in new_cnxn_data
1751 * not set by "new_connection"
1754 memcpy(new_cnxn_data.key, key,
1755 sizeof(new_cnxn_data.key));
1759 = key_is_client_order;
1760 new_cnxn_data.protocol =
1763 &new_cnxn_data.type,
1765 rte_memcpy(new_hash_entry,
1770 new_hash_entry->counters.
1771 packets_forwarded = 1;
1772 ct->counters->pkts_forwarded++;
1773 new_hash_entry->counters.
1774 packets_dropped = 0;
1775 ct->counters->pkts_drop = 0;
1777 current_active_sessions++;
1779 sessions_activated++;
1782 state_used_for_timer
1784 rte_ct_set_cnxn_timer_for_udp(
1787 RTE_CT_UDP_UNREPLIED);
1789 rte_ct_remember_new_connection(
1798 } /* packets_for_lookup */
1800 if (CNXN_TRX_DEBUG > 1) {
1801 printf("Exit cnxn tracker synproxy batch lookup with");
1802 printf(" packet mask %p\n", (void *)*pkts_mask);