diff --git a/share/man/man4/siftr.4 b/share/man/man4/siftr.4 --- a/share/man/man4/siftr.4 +++ b/share/man/man4/siftr.4 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 26, 2023 +.Dd April 27, 2023 .Dt SIFTR 4 .Os .Sh NAME @@ -345,7 +345,7 @@ num_outbound_skipped_pkts_malloc=0 num_inbound_skipped_pkts_tcb=0 \\ num_outbound_skipped_pkts_tcb=0 num_inbound_skipped_pkts_icb=0 \\ num_outbound_skipped_pkts_icb=0 total_skipped_tcp_pkts=0 \\ -flow_list=172.16.7.28;22-172.16.2.5;55931, +flowid_list=3645937075, .Ed .Pp Field descriptions are as follows: @@ -412,12 +412,11 @@ The summation of all skipped packet counters. .El .Bl -tag -offset indent -width Va -.It Va flow_list -A CSV list of TCP flows that triggered data log messages to be generated since +.It Va flowid_list +A CSV list of TCP flow ids that triggered data log messages to be generated since the module was loaded. -Each flow entry in the CSV list is -formatted as -.Qq local_ip;local_port-foreign_ip;foreign_port . +Each flow entry in the CSV list is a 32bit hash value, for example +.Qq 3645937075 . If there are no entries in the list (i.e., no data log messages were generated), the value will be blank. If there is at least one entry in the list, a trailing comma will always be diff --git a/sys/netinet/siftr.c b/sys/netinet/siftr.c --- a/sys/netinet/siftr.c +++ b/sys/netinet/siftr.c @@ -87,9 +87,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -100,6 +102,7 @@ #ifdef SIFTR_IPV6 #include #include +#include #include #endif /* SIFTR_IPV6 */ @@ -136,17 +139,6 @@ /* XXX: Make this a sysctl tunable. */ #define SIFTR_ALQ_BUFLEN (1000*MAX_LOG_MSG_LEN) -/* - * 1 byte for IP version - * IPv4: src/dst IP (4+4) + src/dst port (2+2) = 12 bytes - * IPv6: src/dst IP (16+16) + src/dst port (2+2) = 36 bytes - */ -#ifdef SIFTR_IPV6 -#define FLOW_KEY_LEN 37 -#else -#define FLOW_KEY_LEN 13 -#endif - #ifdef SIFTR_IPV6 #define SIFTR_IPMODE 6 #else @@ -240,7 +232,7 @@ struct flow_hash_node { uint16_t counter; - uint8_t key[FLOW_KEY_LEN]; + uint32_t key; LIST_ENTRY(flow_hash_node) nodes; }; @@ -319,42 +311,10 @@ /* Begin functions. */ -static void -siftr_process_pkt(struct pkt_node * pkt_node) +static inline struct flow_hash_node * +siftr_find_flow(struct listhead *counter_list, uint32_t id) { struct flow_hash_node *hash_node; - struct listhead *counter_list; - struct siftr_stats *ss; - struct ale *log_buf; - uint8_t key[FLOW_KEY_LEN]; - uint8_t found_match, key_offset; - - hash_node = NULL; - ss = DPCPU_PTR(ss); - found_match = 0; - key_offset = 1; - - /* - * Create the key that will be used to create a hash index - * into our hash table. Our key consists of: - * ipversion, localip, localport, foreignip, foreignport - */ - key[0] = pkt_node->ipver; - memcpy(key + key_offset, &pkt_node->ip_laddr, - sizeof(pkt_node->ip_laddr)); - key_offset += sizeof(pkt_node->ip_laddr); - memcpy(key + key_offset, &pkt_node->tcp_localport, - sizeof(pkt_node->tcp_localport)); - key_offset += sizeof(pkt_node->tcp_localport); - memcpy(key + key_offset, &pkt_node->ip_faddr, - sizeof(pkt_node->ip_faddr)); - key_offset += sizeof(pkt_node->ip_faddr); - memcpy(key + key_offset, &pkt_node->tcp_foreignport, - sizeof(pkt_node->tcp_foreignport)); - - counter_list = counter_hash + - (hash32_buf(key, sizeof(key), 0) & siftr_hashmask); - /* * If the list is not empty i.e. the hash index has * been used by another flow previously. @@ -362,9 +322,7 @@ if (LIST_FIRST(counter_list) != NULL) { /* * Loop through the hash nodes in the list. - * There should normally only be 1 hash node in the list, - * except if there have been collisions at the hash index - * computed by hash32_buf(). + * There should normally only be 1 hash node in the list. */ LIST_FOREACH(hash_node, counter_list, nodes) { /* @@ -375,15 +333,34 @@ * hash node that stores the counter for the flow * the pkt belongs to. */ - if (memcmp(hash_node->key, key, sizeof(key)) == 0) { - found_match = 1; - break; + if (hash_node->key == id) { + return hash_node; } } } + return NULL; +} + +static void +siftr_process_pkt(struct pkt_node * pkt_node) +{ + struct flow_hash_node *hash_node; + struct listhead *counter_list; + struct siftr_stats *ss; + struct ale *log_buf; + + ss = DPCPU_PTR(ss); + + if (pkt_node->flowid == 0) { + panic("%s: flowid not available", __func__); + } + + counter_list = counter_hash + (pkt_node->flowid & siftr_hashmask); + hash_node = siftr_find_flow(counter_list, pkt_node->flowid); + /* If this flow hash hasn't been seen before or we have a collision. */ - if (hash_node == NULL || !found_match) { + if (hash_node == NULL) { /* Create a new hash node to store the flow's counter. */ hash_node = malloc(sizeof(struct flow_hash_node), M_SIFTR_HASHNODE, M_WAITOK); @@ -391,7 +368,7 @@ if (hash_node != NULL) { /* Initialise our new hash node list entry. */ hash_node->counter = 0; - memcpy(hash_node->key, key, sizeof(key)); + hash_node->key = pkt_node->flowid; LIST_INSERT_HEAD(counter_list, hash_node, nodes); } else { /* Malloc failed. */ @@ -708,6 +685,34 @@ return (inp); } +static inline uint32_t +siftr_get_flowid(struct inpcb *inp, int ipver, uint32_t *phashtype) +{ + if (inp->inp_flowid == 0) { +#ifdef SIFTR_IPV6 + if (ipver == INP_IPV6) { + return fib6_calc_packet_hash(&inp->in6p_laddr, + &inp->in6p_faddr, + inp->inp_lport, + inp->inp_fport, + IPPROTO_TCP, + phashtype); + } else +#endif + { + return fib4_calc_packet_hash(inp->inp_laddr, + inp->inp_faddr, + inp->inp_lport, + inp->inp_fport, + IPPROTO_TCP, + phashtype); + } + } else { + *phashtype = inp->inp_flowtype; + return inp->inp_flowid; + } +} + static inline void siftr_siftdata(struct pkt_node *pn, struct inpcb *inp, struct tcpcb *tp, int ipver, int dir, int inp_locally_locked) @@ -753,8 +758,6 @@ pn->rcv_buf_cc = sbused(&inp->inp_socket->so_rcv); pn->sent_inflight_bytes = tp->snd_max - tp->snd_una; pn->t_segqlen = tp->t_segqlen; - pn->flowid = inp->inp_flowid; - pn->flowtype = inp->inp_flowtype; /* We've finished accessing the tcb so release the lock. */ if (inp_locally_locked) @@ -770,7 +773,6 @@ */ microtime(&pn->tval); TCP_PROBE1(siftr, &pn); - } /* @@ -792,6 +794,7 @@ struct siftr_stats *ss; unsigned int ip_hl; int inp_locally_locked, dir; + uint32_t hash_id, hash_type; inp_locally_locked = 0; dir = PFIL_DIR(flags); @@ -872,6 +875,7 @@ goto inp_unlock; } + hash_id = siftr_get_flowid(inp, INP_IPV4, &hash_type); pn = malloc(sizeof(struct pkt_node), M_SIFTR_PKTNODE, M_NOWAIT|M_ZERO); @@ -884,6 +888,9 @@ goto inp_unlock; } + pn->flowid = hash_id; + pn->flowtype = hash_type; + siftr_siftdata(pn, inp, tp, INP_IPV4, dir, inp_locally_locked); mtx_lock(&siftr_pkt_queue_mtx); @@ -911,6 +918,7 @@ struct siftr_stats *ss; unsigned int ip6_hl; int inp_locally_locked, dir; + uint32_t hash_id, hash_type; inp_locally_locked = 0; dir = PFIL_DIR(flags); @@ -993,6 +1001,7 @@ goto inp_unlock6; } + hash_id = siftr_get_flowid(inp, INP_IPV6, &hash_type); pn = malloc(sizeof(struct pkt_node), M_SIFTR_PKTNODE, M_NOWAIT|M_ZERO); @@ -1005,6 +1014,9 @@ goto inp_unlock6; } + pn->flowid = hash_id; + pn->flowtype = hash_type; + siftr_siftdata(pn, inp, tp, INP_IPV6, dir, inp_locally_locked); /* XXX: Figure out how to generate hashes for IPv6 packets. */ @@ -1122,18 +1134,8 @@ struct timeval tval; struct flow_hash_node *counter, *tmp_counter; struct sbuf *s; - int i, key_index, error; + int i, error; uint32_t bytes_to_write, total_skipped_pkts; - uint16_t lport, fport; - uint8_t *key, ipver __unused; - -#ifdef SIFTR_IPV6 - uint32_t laddr[4]; - uint32_t faddr[4]; -#else - uint8_t laddr[4]; - uint8_t faddr[4]; -#endif error = 0; total_skipped_pkts = 0; @@ -1227,7 +1229,7 @@ "num_outbound_skipped_pkts_tcpcb=%u\t" "num_inbound_skipped_pkts_inpcb=%u\t" "num_outbound_skipped_pkts_inpcb=%u\t" - "total_skipped_tcp_pkts=%u\tflow_list=", + "total_skipped_tcp_pkts=%u\tflowid_list=", (intmax_t)tval.tv_sec, tval.tv_usec, (uintmax_t)totalss.n_in, @@ -1243,84 +1245,13 @@ /* * Iterate over the flow hash, printing a summary of each - * flow seen and freeing any malloc'd memory. + * flowid seen and freeing any malloc'd memory. * The hash consists of an array of LISTs (man 3 queue). */ for (i = 0; i <= siftr_hashmask; i++) { LIST_FOREACH_SAFE(counter, counter_hash + i, nodes, tmp_counter) { - key = counter->key; - key_index = 1; - - ipver = key[0]; - - memcpy(laddr, key + key_index, sizeof(laddr)); - key_index += sizeof(laddr); - memcpy(&lport, key + key_index, sizeof(lport)); - key_index += sizeof(lport); - memcpy(faddr, key + key_index, sizeof(faddr)); - key_index += sizeof(faddr); - memcpy(&fport, key + key_index, sizeof(fport)); - -#ifdef SIFTR_IPV6 - laddr[3] = ntohl(laddr[3]); - faddr[3] = ntohl(faddr[3]); - - if (ipver == INP_IPV6) { - laddr[0] = ntohl(laddr[0]); - laddr[1] = ntohl(laddr[1]); - laddr[2] = ntohl(laddr[2]); - faddr[0] = ntohl(faddr[0]); - faddr[1] = ntohl(faddr[1]); - faddr[2] = ntohl(faddr[2]); - - sbuf_printf(s, - "%x:%x:%x:%x:%x:%x:%x:%x;%u-" - "%x:%x:%x:%x:%x:%x:%x:%x;%u,", - UPPER_SHORT(laddr[0]), - LOWER_SHORT(laddr[0]), - UPPER_SHORT(laddr[1]), - LOWER_SHORT(laddr[1]), - UPPER_SHORT(laddr[2]), - LOWER_SHORT(laddr[2]), - UPPER_SHORT(laddr[3]), - LOWER_SHORT(laddr[3]), - ntohs(lport), - UPPER_SHORT(faddr[0]), - LOWER_SHORT(faddr[0]), - UPPER_SHORT(faddr[1]), - LOWER_SHORT(faddr[1]), - UPPER_SHORT(faddr[2]), - LOWER_SHORT(faddr[2]), - UPPER_SHORT(faddr[3]), - LOWER_SHORT(faddr[3]), - ntohs(fport)); - } else { - laddr[0] = FIRST_OCTET(laddr[3]); - laddr[1] = SECOND_OCTET(laddr[3]); - laddr[2] = THIRD_OCTET(laddr[3]); - laddr[3] = FOURTH_OCTET(laddr[3]); - faddr[0] = FIRST_OCTET(faddr[3]); - faddr[1] = SECOND_OCTET(faddr[3]); - faddr[2] = THIRD_OCTET(faddr[3]); - faddr[3] = FOURTH_OCTET(faddr[3]); -#endif - sbuf_printf(s, - "%u.%u.%u.%u;%u-%u.%u.%u.%u;%u,", - laddr[0], - laddr[1], - laddr[2], - laddr[3], - ntohs(lport), - faddr[0], - faddr[1], - faddr[2], - faddr[3], - ntohs(fport)); -#ifdef SIFTR_IPV6 - } -#endif - + sbuf_printf(s, "%u,", counter->key); free(counter, M_SIFTR_HASHNODE); }