mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
siftr: three changes that improve performance
Summary: (1) use inp_flowid or a new packet hash for a flow identification (2) cache constant connection info into struct flow_hash_node (3) use compressed notation for IPv6 address representation Reviewers: rscheff, tuexen Approved by: tuexen (mentor) Subscribers: imp, melifaro, glebius Differential Revision: https://reviews.freebsd.org/D40302
This commit is contained in:
parent
eb98f77910
commit
aa61cff424
2 changed files with 200 additions and 343 deletions
|
|
@ -29,7 +29,7 @@
|
||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd April 26, 2023
|
.Dd May 27, 2023
|
||||||
.Dt SIFTR 4
|
.Dt SIFTR 4
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
|
@ -83,10 +83,7 @@ In the IPv4-only (default) mode, standard dotted decimal notation (e.g.
|
||||||
"136.186.229.95") is used to format IPv4 addresses for logging.
|
"136.186.229.95") is used to format IPv4 addresses for logging.
|
||||||
In IPv6 mode, standard dotted decimal notation is used to format IPv4 addresses,
|
In IPv6 mode, standard dotted decimal notation is used to format IPv4 addresses,
|
||||||
and standard colon-separated hex notation (see RFC 4291) is used to format IPv6
|
and standard colon-separated hex notation (see RFC 4291) is used to format IPv6
|
||||||
addresses for logging.
|
addresses (e.g. "fd00::2") for logging.
|
||||||
Note that SIFTR uses uncompressed notation to format IPv6 addresses.
|
|
||||||
For example, the address "fe80::20f:feff:fea2:531b" would be logged as
|
|
||||||
"fe80:0:0:0:20f:feff:fea2:531b".
|
|
||||||
.Ss Run-time Configuration
|
.Ss Run-time Configuration
|
||||||
.Nm
|
.Nm
|
||||||
utilises the
|
utilises the
|
||||||
|
|
@ -746,7 +743,4 @@ value logged by
|
||||||
does not take into account bytes that have been
|
does not take into account bytes that have been
|
||||||
.No SACK Ap ed
|
.No SACK Ap ed
|
||||||
by the receiving host.
|
by the receiving host.
|
||||||
.It
|
|
||||||
Compressed notation is not used for IPv6 address representation.
|
|
||||||
This consumes more bytes than is necessary in log output.
|
|
||||||
.El
|
.El
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,11 @@ __FBSDID("$FreeBSD$");
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <net/if_var.h>
|
#include <net/if_var.h>
|
||||||
#include <net/pfil.h>
|
#include <net/pfil.h>
|
||||||
|
#include <net/route.h>
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/in_kdtrace.h>
|
#include <netinet/in_kdtrace.h>
|
||||||
|
#include <netinet/in_fib.h>
|
||||||
#include <netinet/in_pcb.h>
|
#include <netinet/in_pcb.h>
|
||||||
#include <netinet/in_systm.h>
|
#include <netinet/in_systm.h>
|
||||||
#include <netinet/in_var.h>
|
#include <netinet/in_var.h>
|
||||||
|
|
@ -100,6 +102,7 @@ __FBSDID("$FreeBSD$");
|
||||||
#ifdef SIFTR_IPV6
|
#ifdef SIFTR_IPV6
|
||||||
#include <netinet/ip6.h>
|
#include <netinet/ip6.h>
|
||||||
#include <netinet6/ip6_var.h>
|
#include <netinet6/ip6_var.h>
|
||||||
|
#include <netinet6/in6_fib.h>
|
||||||
#include <netinet6/in6_pcb.h>
|
#include <netinet6/in6_pcb.h>
|
||||||
#endif /* SIFTR_IPV6 */
|
#endif /* SIFTR_IPV6 */
|
||||||
|
|
||||||
|
|
@ -136,32 +139,12 @@ __FBSDID("$FreeBSD$");
|
||||||
/* XXX: Make this a sysctl tunable. */
|
/* XXX: Make this a sysctl tunable. */
|
||||||
#define SIFTR_ALQ_BUFLEN (1000*MAX_LOG_MSG_LEN)
|
#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
|
#ifdef SIFTR_IPV6
|
||||||
#define SIFTR_IPMODE 6
|
#define SIFTR_IPMODE 6
|
||||||
#else
|
#else
|
||||||
#define SIFTR_IPMODE 4
|
#define SIFTR_IPMODE 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* useful macros */
|
|
||||||
#define UPPER_SHORT(X) (((X) & 0xFFFF0000) >> 16)
|
|
||||||
#define LOWER_SHORT(X) ((X) & 0x0000FFFF)
|
|
||||||
|
|
||||||
#define FIRST_OCTET(X) (((X) & 0xFF000000) >> 24)
|
|
||||||
#define SECOND_OCTET(X) (((X) & 0x00FF0000) >> 16)
|
|
||||||
#define THIRD_OCTET(X) (((X) & 0x0000FF00) >> 8)
|
|
||||||
#define FOURTH_OCTET(X) ((X) & 0x000000FF)
|
|
||||||
|
|
||||||
static MALLOC_DEFINE(M_SIFTR, "siftr", "dynamic memory used by SIFTR");
|
static MALLOC_DEFINE(M_SIFTR, "siftr", "dynamic memory used by SIFTR");
|
||||||
static MALLOC_DEFINE(M_SIFTR_PKTNODE, "siftr_pktnode",
|
static MALLOC_DEFINE(M_SIFTR_PKTNODE, "siftr_pktnode",
|
||||||
"SIFTR pkt_node struct");
|
"SIFTR pkt_node struct");
|
||||||
|
|
@ -177,20 +160,6 @@ struct pkt_node {
|
||||||
DIR_IN = 0,
|
DIR_IN = 0,
|
||||||
DIR_OUT = 1,
|
DIR_OUT = 1,
|
||||||
} direction;
|
} direction;
|
||||||
/* IP version pkt_node relates to; either INP_IPV4 or INP_IPV6. */
|
|
||||||
uint8_t ipver;
|
|
||||||
/* Local/foreign IP address. */
|
|
||||||
#ifdef SIFTR_IPV6
|
|
||||||
uint32_t ip_laddr[4];
|
|
||||||
uint32_t ip_faddr[4];
|
|
||||||
#else
|
|
||||||
uint8_t ip_laddr[4];
|
|
||||||
uint8_t ip_faddr[4];
|
|
||||||
#endif
|
|
||||||
/* Local TCP port. */
|
|
||||||
uint16_t tcp_localport;
|
|
||||||
/* Foreign TCP port. */
|
|
||||||
uint16_t tcp_foreignport;
|
|
||||||
/* Congestion Window (bytes). */
|
/* Congestion Window (bytes). */
|
||||||
uint32_t snd_cwnd;
|
uint32_t snd_cwnd;
|
||||||
/* Sending Window (bytes). */
|
/* Sending Window (bytes). */
|
||||||
|
|
@ -237,10 +206,25 @@ struct pkt_node {
|
||||||
STAILQ_ENTRY(pkt_node) nodes;
|
STAILQ_ENTRY(pkt_node) nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct flow_info
|
||||||
|
{
|
||||||
|
#ifdef SIFTR_IPV6
|
||||||
|
char laddr[INET6_ADDRSTRLEN]; /* local IP address */
|
||||||
|
char faddr[INET6_ADDRSTRLEN]; /* foreign IP address */
|
||||||
|
#else
|
||||||
|
char laddr[INET_ADDRSTRLEN]; /* local IP address */
|
||||||
|
char faddr[INET_ADDRSTRLEN]; /* foreign IP address */
|
||||||
|
#endif
|
||||||
|
uint16_t lport; /* local TCP port */
|
||||||
|
uint16_t fport; /* foreign TCP port */
|
||||||
|
uint8_t ipver; /* IP version */
|
||||||
|
uint32_t key; /* flowid of the connection */
|
||||||
|
};
|
||||||
|
|
||||||
struct flow_hash_node
|
struct flow_hash_node
|
||||||
{
|
{
|
||||||
uint16_t counter;
|
uint16_t counter;
|
||||||
uint8_t key[FLOW_KEY_LEN];
|
struct flow_info const_info; /* constant connection info */
|
||||||
LIST_ENTRY(flow_hash_node) nodes;
|
LIST_ENTRY(flow_hash_node) nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -319,42 +303,10 @@ SYSCTL_UINT(_net_inet_siftr, OID_AUTO, binary, CTLFLAG_RW,
|
||||||
|
|
||||||
/* Begin functions. */
|
/* Begin functions. */
|
||||||
|
|
||||||
static void
|
static inline struct flow_hash_node *
|
||||||
siftr_process_pkt(struct pkt_node * pkt_node)
|
siftr_find_flow(struct listhead *counter_list, uint32_t id)
|
||||||
{
|
{
|
||||||
struct flow_hash_node *hash_node;
|
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
|
* If the list is not empty i.e. the hash index has
|
||||||
* been used by another flow previously.
|
* been used by another flow previously.
|
||||||
|
|
@ -362,9 +314,7 @@ siftr_process_pkt(struct pkt_node * pkt_node)
|
||||||
if (LIST_FIRST(counter_list) != NULL) {
|
if (LIST_FIRST(counter_list) != NULL) {
|
||||||
/*
|
/*
|
||||||
* Loop through the hash nodes in the list.
|
* Loop through the hash nodes in the list.
|
||||||
* There should normally only be 1 hash node 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().
|
|
||||||
*/
|
*/
|
||||||
LIST_FOREACH(hash_node, counter_list, nodes) {
|
LIST_FOREACH(hash_node, counter_list, nodes) {
|
||||||
/*
|
/*
|
||||||
|
|
@ -375,50 +325,60 @@ siftr_process_pkt(struct pkt_node * pkt_node)
|
||||||
* hash node that stores the counter for the flow
|
* hash node that stores the counter for the flow
|
||||||
* the pkt belongs to.
|
* the pkt belongs to.
|
||||||
*/
|
*/
|
||||||
if (memcmp(hash_node->key, key, sizeof(key)) == 0) {
|
if (hash_node->const_info.key == id) {
|
||||||
found_match = 1;
|
return hash_node;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this flow hash hasn't been seen before or we have a collision. */
|
return NULL;
|
||||||
if (hash_node == NULL || !found_match) {
|
}
|
||||||
/* Create a new hash node to store the flow's counter. */
|
|
||||||
hash_node = malloc(sizeof(struct flow_hash_node),
|
|
||||||
M_SIFTR_HASHNODE, M_WAITOK);
|
|
||||||
|
|
||||||
if (hash_node != NULL) {
|
static inline struct flow_hash_node *
|
||||||
/* Initialise our new hash node list entry. */
|
siftr_new_hash_node(struct flow_info info, int dir,
|
||||||
hash_node->counter = 0;
|
struct siftr_stats *ss)
|
||||||
memcpy(hash_node->key, key, sizeof(key));
|
{
|
||||||
LIST_INSERT_HEAD(counter_list, hash_node, nodes);
|
struct flow_hash_node *hash_node;
|
||||||
} else {
|
struct listhead *counter_list;
|
||||||
/* Malloc failed. */
|
|
||||||
if (pkt_node->direction == DIR_IN)
|
|
||||||
ss->nskip_in_malloc++;
|
|
||||||
else
|
|
||||||
ss->nskip_out_malloc++;
|
|
||||||
|
|
||||||
return;
|
counter_list = counter_hash + (info.key & siftr_hashmask);
|
||||||
}
|
/* Create a new hash node to store the flow's constant info. */
|
||||||
} else if (siftr_pkts_per_log > 1) {
|
hash_node = malloc(sizeof(struct flow_hash_node), M_SIFTR_HASHNODE,
|
||||||
/*
|
M_NOWAIT|M_ZERO);
|
||||||
* Taking the remainder of the counter divided
|
|
||||||
* by the current value of siftr_pkts_per_log
|
|
||||||
* and storing that in counter provides a neat
|
|
||||||
* way to modulate the frequency of log
|
|
||||||
* messages being written to the log file.
|
|
||||||
*/
|
|
||||||
hash_node->counter = (hash_node->counter + 1) %
|
|
||||||
siftr_pkts_per_log;
|
|
||||||
|
|
||||||
/*
|
if (hash_node != NULL) {
|
||||||
* If we have not seen enough packets since the last time
|
/* Initialise our new hash node list entry. */
|
||||||
* we wrote a log message for this connection, return.
|
hash_node->counter = 0;
|
||||||
*/
|
hash_node->const_info = info;
|
||||||
if (hash_node->counter > 0)
|
LIST_INSERT_HEAD(counter_list, hash_node, nodes);
|
||||||
return;
|
return hash_node;
|
||||||
|
} else {
|
||||||
|
/* malloc failed */
|
||||||
|
if (dir == DIR_IN)
|
||||||
|
ss->nskip_in_malloc++;
|
||||||
|
else
|
||||||
|
ss->nskip_out_malloc++;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
siftr_process_pkt(struct pkt_node * pkt_node)
|
||||||
|
{
|
||||||
|
struct flow_hash_node *hash_node;
|
||||||
|
struct listhead *counter_list;
|
||||||
|
struct ale *log_buf;
|
||||||
|
|
||||||
|
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 (hash_node == NULL) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_buf = alq_getn(siftr_alq, MAX_LOG_MSG_LEN, ALQ_WAITOK);
|
log_buf = alq_getn(siftr_alq, MAX_LOG_MSG_LEN, ALQ_WAITOK);
|
||||||
|
|
@ -426,119 +386,38 @@ siftr_process_pkt(struct pkt_node * pkt_node)
|
||||||
if (log_buf == NULL)
|
if (log_buf == NULL)
|
||||||
return; /* Should only happen if the ALQ is shutting down. */
|
return; /* Should only happen if the ALQ is shutting down. */
|
||||||
|
|
||||||
#ifdef SIFTR_IPV6
|
/* Construct a log message. */
|
||||||
pkt_node->ip_laddr[3] = ntohl(pkt_node->ip_laddr[3]);
|
log_buf->ae_bytesused = snprintf(log_buf->ae_data, MAX_LOG_MSG_LEN,
|
||||||
pkt_node->ip_faddr[3] = ntohl(pkt_node->ip_faddr[3]);
|
"%c,%zd.%06ld,%s,%hu,%s,%hu,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,"
|
||||||
|
"%u,%u,%u,%u,%u,%u,%u,%u\n",
|
||||||
if (pkt_node->ipver == INP_IPV6) { /* IPv6 packet */
|
direction[pkt_node->direction],
|
||||||
pkt_node->ip_laddr[0] = ntohl(pkt_node->ip_laddr[0]);
|
pkt_node->tval.tv_sec,
|
||||||
pkt_node->ip_laddr[1] = ntohl(pkt_node->ip_laddr[1]);
|
pkt_node->tval.tv_usec,
|
||||||
pkt_node->ip_laddr[2] = ntohl(pkt_node->ip_laddr[2]);
|
hash_node->const_info.laddr,
|
||||||
pkt_node->ip_faddr[0] = ntohl(pkt_node->ip_faddr[0]);
|
hash_node->const_info.lport,
|
||||||
pkt_node->ip_faddr[1] = ntohl(pkt_node->ip_faddr[1]);
|
hash_node->const_info.faddr,
|
||||||
pkt_node->ip_faddr[2] = ntohl(pkt_node->ip_faddr[2]);
|
hash_node->const_info.fport,
|
||||||
|
pkt_node->snd_ssthresh,
|
||||||
/* Construct an IPv6 log message. */
|
pkt_node->snd_cwnd,
|
||||||
log_buf->ae_bytesused = snprintf(log_buf->ae_data,
|
pkt_node->t_flags2,
|
||||||
MAX_LOG_MSG_LEN,
|
pkt_node->snd_wnd,
|
||||||
"%c,%zd.%06ld,%x:%x:%x:%x:%x:%x:%x:%x,%u,%x:%x:%x:"
|
pkt_node->rcv_wnd,
|
||||||
"%x:%x:%x:%x:%x,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,"
|
pkt_node->snd_scale,
|
||||||
"%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n",
|
pkt_node->rcv_scale,
|
||||||
direction[pkt_node->direction],
|
pkt_node->conn_state,
|
||||||
pkt_node->tval.tv_sec,
|
pkt_node->max_seg_size,
|
||||||
pkt_node->tval.tv_usec,
|
pkt_node->srtt,
|
||||||
UPPER_SHORT(pkt_node->ip_laddr[0]),
|
pkt_node->sack_enabled,
|
||||||
LOWER_SHORT(pkt_node->ip_laddr[0]),
|
pkt_node->flags,
|
||||||
UPPER_SHORT(pkt_node->ip_laddr[1]),
|
pkt_node->rto,
|
||||||
LOWER_SHORT(pkt_node->ip_laddr[1]),
|
pkt_node->snd_buf_hiwater,
|
||||||
UPPER_SHORT(pkt_node->ip_laddr[2]),
|
pkt_node->snd_buf_cc,
|
||||||
LOWER_SHORT(pkt_node->ip_laddr[2]),
|
pkt_node->rcv_buf_hiwater,
|
||||||
UPPER_SHORT(pkt_node->ip_laddr[3]),
|
pkt_node->rcv_buf_cc,
|
||||||
LOWER_SHORT(pkt_node->ip_laddr[3]),
|
pkt_node->sent_inflight_bytes,
|
||||||
ntohs(pkt_node->tcp_localport),
|
pkt_node->t_segqlen,
|
||||||
UPPER_SHORT(pkt_node->ip_faddr[0]),
|
pkt_node->flowid,
|
||||||
LOWER_SHORT(pkt_node->ip_faddr[0]),
|
pkt_node->flowtype);
|
||||||
UPPER_SHORT(pkt_node->ip_faddr[1]),
|
|
||||||
LOWER_SHORT(pkt_node->ip_faddr[1]),
|
|
||||||
UPPER_SHORT(pkt_node->ip_faddr[2]),
|
|
||||||
LOWER_SHORT(pkt_node->ip_faddr[2]),
|
|
||||||
UPPER_SHORT(pkt_node->ip_faddr[3]),
|
|
||||||
LOWER_SHORT(pkt_node->ip_faddr[3]),
|
|
||||||
ntohs(pkt_node->tcp_foreignport),
|
|
||||||
pkt_node->snd_ssthresh,
|
|
||||||
pkt_node->snd_cwnd,
|
|
||||||
pkt_node->t_flags2,
|
|
||||||
pkt_node->snd_wnd,
|
|
||||||
pkt_node->rcv_wnd,
|
|
||||||
pkt_node->snd_scale,
|
|
||||||
pkt_node->rcv_scale,
|
|
||||||
pkt_node->conn_state,
|
|
||||||
pkt_node->max_seg_size,
|
|
||||||
pkt_node->srtt,
|
|
||||||
pkt_node->sack_enabled,
|
|
||||||
pkt_node->flags,
|
|
||||||
pkt_node->rto,
|
|
||||||
pkt_node->snd_buf_hiwater,
|
|
||||||
pkt_node->snd_buf_cc,
|
|
||||||
pkt_node->rcv_buf_hiwater,
|
|
||||||
pkt_node->rcv_buf_cc,
|
|
||||||
pkt_node->sent_inflight_bytes,
|
|
||||||
pkt_node->t_segqlen,
|
|
||||||
pkt_node->flowid,
|
|
||||||
pkt_node->flowtype);
|
|
||||||
} else { /* IPv4 packet */
|
|
||||||
pkt_node->ip_laddr[0] = FIRST_OCTET(pkt_node->ip_laddr[3]);
|
|
||||||
pkt_node->ip_laddr[1] = SECOND_OCTET(pkt_node->ip_laddr[3]);
|
|
||||||
pkt_node->ip_laddr[2] = THIRD_OCTET(pkt_node->ip_laddr[3]);
|
|
||||||
pkt_node->ip_laddr[3] = FOURTH_OCTET(pkt_node->ip_laddr[3]);
|
|
||||||
pkt_node->ip_faddr[0] = FIRST_OCTET(pkt_node->ip_faddr[3]);
|
|
||||||
pkt_node->ip_faddr[1] = SECOND_OCTET(pkt_node->ip_faddr[3]);
|
|
||||||
pkt_node->ip_faddr[2] = THIRD_OCTET(pkt_node->ip_faddr[3]);
|
|
||||||
pkt_node->ip_faddr[3] = FOURTH_OCTET(pkt_node->ip_faddr[3]);
|
|
||||||
#endif /* SIFTR_IPV6 */
|
|
||||||
|
|
||||||
/* Construct an IPv4 log message. */
|
|
||||||
log_buf->ae_bytesused = snprintf(log_buf->ae_data,
|
|
||||||
MAX_LOG_MSG_LEN,
|
|
||||||
"%c,%jd.%06ld,%u.%u.%u.%u,%u,%u.%u.%u.%u,%u,%u,%u,"
|
|
||||||
"%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n",
|
|
||||||
direction[pkt_node->direction],
|
|
||||||
(intmax_t)pkt_node->tval.tv_sec,
|
|
||||||
pkt_node->tval.tv_usec,
|
|
||||||
pkt_node->ip_laddr[0],
|
|
||||||
pkt_node->ip_laddr[1],
|
|
||||||
pkt_node->ip_laddr[2],
|
|
||||||
pkt_node->ip_laddr[3],
|
|
||||||
ntohs(pkt_node->tcp_localport),
|
|
||||||
pkt_node->ip_faddr[0],
|
|
||||||
pkt_node->ip_faddr[1],
|
|
||||||
pkt_node->ip_faddr[2],
|
|
||||||
pkt_node->ip_faddr[3],
|
|
||||||
ntohs(pkt_node->tcp_foreignport),
|
|
||||||
pkt_node->snd_ssthresh,
|
|
||||||
pkt_node->snd_cwnd,
|
|
||||||
pkt_node->t_flags2,
|
|
||||||
pkt_node->snd_wnd,
|
|
||||||
pkt_node->rcv_wnd,
|
|
||||||
pkt_node->snd_scale,
|
|
||||||
pkt_node->rcv_scale,
|
|
||||||
pkt_node->conn_state,
|
|
||||||
pkt_node->max_seg_size,
|
|
||||||
pkt_node->srtt,
|
|
||||||
pkt_node->sack_enabled,
|
|
||||||
pkt_node->flags,
|
|
||||||
pkt_node->rto,
|
|
||||||
pkt_node->snd_buf_hiwater,
|
|
||||||
pkt_node->snd_buf_cc,
|
|
||||||
pkt_node->rcv_buf_hiwater,
|
|
||||||
pkt_node->rcv_buf_cc,
|
|
||||||
pkt_node->sent_inflight_bytes,
|
|
||||||
pkt_node->t_segqlen,
|
|
||||||
pkt_node->flowid,
|
|
||||||
pkt_node->flowtype);
|
|
||||||
#ifdef SIFTR_IPV6
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
alq_post_flags(siftr_alq, log_buf, 0);
|
alq_post_flags(siftr_alq, log_buf, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -708,32 +587,38 @@ siftr_findinpcb(int ipver, struct ip *ip, struct mbuf *m, uint16_t sport,
|
||||||
return (inp);
|
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
|
static inline void
|
||||||
siftr_siftdata(struct pkt_node *pn, struct inpcb *inp, struct tcpcb *tp,
|
siftr_siftdata(struct pkt_node *pn, struct inpcb *inp, struct tcpcb *tp,
|
||||||
int ipver, int dir, int inp_locally_locked)
|
int ipver, int dir, int inp_locally_locked)
|
||||||
{
|
{
|
||||||
#ifdef SIFTR_IPV6
|
|
||||||
if (ipver == INP_IPV4) {
|
|
||||||
pn->ip_laddr[3] = inp->inp_laddr.s_addr;
|
|
||||||
pn->ip_faddr[3] = inp->inp_faddr.s_addr;
|
|
||||||
#else
|
|
||||||
*((uint32_t *)pn->ip_laddr) = inp->inp_laddr.s_addr;
|
|
||||||
*((uint32_t *)pn->ip_faddr) = inp->inp_faddr.s_addr;
|
|
||||||
#endif
|
|
||||||
#ifdef SIFTR_IPV6
|
|
||||||
} else {
|
|
||||||
pn->ip_laddr[0] = inp->in6p_laddr.s6_addr32[0];
|
|
||||||
pn->ip_laddr[1] = inp->in6p_laddr.s6_addr32[1];
|
|
||||||
pn->ip_laddr[2] = inp->in6p_laddr.s6_addr32[2];
|
|
||||||
pn->ip_laddr[3] = inp->in6p_laddr.s6_addr32[3];
|
|
||||||
pn->ip_faddr[0] = inp->in6p_faddr.s6_addr32[0];
|
|
||||||
pn->ip_faddr[1] = inp->in6p_faddr.s6_addr32[1];
|
|
||||||
pn->ip_faddr[2] = inp->in6p_faddr.s6_addr32[2];
|
|
||||||
pn->ip_faddr[3] = inp->in6p_faddr.s6_addr32[3];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
pn->tcp_localport = inp->inp_lport;
|
|
||||||
pn->tcp_foreignport = inp->inp_fport;
|
|
||||||
pn->snd_cwnd = tp->snd_cwnd;
|
pn->snd_cwnd = tp->snd_cwnd;
|
||||||
pn->snd_wnd = tp->snd_wnd;
|
pn->snd_wnd = tp->snd_wnd;
|
||||||
pn->rcv_wnd = tp->rcv_wnd;
|
pn->rcv_wnd = tp->rcv_wnd;
|
||||||
|
|
@ -743,7 +628,7 @@ siftr_siftdata(struct pkt_node *pn, struct inpcb *inp, struct tcpcb *tp,
|
||||||
pn->rcv_scale = tp->rcv_scale;
|
pn->rcv_scale = tp->rcv_scale;
|
||||||
pn->conn_state = tp->t_state;
|
pn->conn_state = tp->t_state;
|
||||||
pn->max_seg_size = tp->t_maxseg;
|
pn->max_seg_size = tp->t_maxseg;
|
||||||
pn->srtt = ((u_int64_t)tp->t_srtt * tick) >> TCP_RTT_SHIFT;
|
pn->srtt = ((uint64_t)tp->t_srtt * tick) >> TCP_RTT_SHIFT;
|
||||||
pn->sack_enabled = (tp->t_flags & TF_SACK_PERMIT) != 0;
|
pn->sack_enabled = (tp->t_flags & TF_SACK_PERMIT) != 0;
|
||||||
pn->flags = tp->t_flags;
|
pn->flags = tp->t_flags;
|
||||||
pn->rto = tp->t_rxtcur * tick;
|
pn->rto = tp->t_rxtcur * tick;
|
||||||
|
|
@ -753,14 +638,11 @@ siftr_siftdata(struct pkt_node *pn, struct inpcb *inp, struct tcpcb *tp,
|
||||||
pn->rcv_buf_cc = sbused(&inp->inp_socket->so_rcv);
|
pn->rcv_buf_cc = sbused(&inp->inp_socket->so_rcv);
|
||||||
pn->sent_inflight_bytes = tp->snd_max - tp->snd_una;
|
pn->sent_inflight_bytes = tp->snd_max - tp->snd_una;
|
||||||
pn->t_segqlen = tp->t_segqlen;
|
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. */
|
/* We've finished accessing the tcb so release the lock. */
|
||||||
if (inp_locally_locked)
|
if (inp_locally_locked)
|
||||||
INP_RUNLOCK(inp);
|
INP_RUNLOCK(inp);
|
||||||
|
|
||||||
pn->ipver = ipver;
|
|
||||||
pn->direction = (dir == PFIL_IN ? DIR_IN : DIR_OUT);
|
pn->direction = (dir == PFIL_IN ? DIR_IN : DIR_OUT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -770,7 +652,6 @@ siftr_siftdata(struct pkt_node *pn, struct inpcb *inp, struct tcpcb *tp,
|
||||||
*/
|
*/
|
||||||
microtime(&pn->tval);
|
microtime(&pn->tval);
|
||||||
TCP_PROBE1(siftr, &pn);
|
TCP_PROBE1(siftr, &pn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -792,6 +673,9 @@ siftr_chkpkt(struct mbuf **m, struct ifnet *ifp, int flags,
|
||||||
struct siftr_stats *ss;
|
struct siftr_stats *ss;
|
||||||
unsigned int ip_hl;
|
unsigned int ip_hl;
|
||||||
int inp_locally_locked, dir;
|
int inp_locally_locked, dir;
|
||||||
|
uint32_t hash_id, hash_type;
|
||||||
|
struct listhead *counter_list;
|
||||||
|
struct flow_hash_node *hash_node;
|
||||||
|
|
||||||
inp_locally_locked = 0;
|
inp_locally_locked = 0;
|
||||||
dir = PFIL_DIR(flags);
|
dir = PFIL_DIR(flags);
|
||||||
|
|
@ -861,9 +745,11 @@ siftr_chkpkt(struct mbuf **m, struct ifnet *ifp, int flags,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we can't find the TCP control block (happens occasionaly for a
|
* If we can't find the TCP control block (happens occasionaly for a
|
||||||
* packet sent during the shutdown phase of a TCP connection), bail
|
* packet sent during the shutdown phase of a TCP connection), or the
|
||||||
|
* TCP control block has not initialized (happens during TCPS_SYN_SENT),
|
||||||
|
* bail.
|
||||||
*/
|
*/
|
||||||
if (tp == NULL) {
|
if (tp == NULL || tp->t_state < TCPS_ESTABLISHED) {
|
||||||
if (dir == PFIL_IN)
|
if (dir == PFIL_IN)
|
||||||
ss->nskip_in_tcpcb++;
|
ss->nskip_in_tcpcb++;
|
||||||
else
|
else
|
||||||
|
|
@ -872,6 +758,27 @@ siftr_chkpkt(struct mbuf **m, struct ifnet *ifp, int flags,
|
||||||
goto inp_unlock;
|
goto inp_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hash_id = siftr_get_flowid(inp, INP_IPV4, &hash_type);
|
||||||
|
counter_list = counter_hash + (hash_id & siftr_hashmask);
|
||||||
|
hash_node = siftr_find_flow(counter_list, hash_id);
|
||||||
|
|
||||||
|
/* If this flow hasn't been seen before, we create a new entry. */
|
||||||
|
if (hash_node == NULL) {
|
||||||
|
struct flow_info info;
|
||||||
|
|
||||||
|
inet_ntoa_r(inp->inp_laddr, info.laddr);
|
||||||
|
inet_ntoa_r(inp->inp_faddr, info.faddr);
|
||||||
|
info.lport = ntohs(inp->inp_lport);
|
||||||
|
info.fport = ntohs(inp->inp_fport);
|
||||||
|
info.key = hash_id;
|
||||||
|
info.ipver = INP_IPV4;
|
||||||
|
|
||||||
|
hash_node = siftr_new_hash_node(info, dir, ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hash_node == NULL) {
|
||||||
|
goto inp_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
pn = malloc(sizeof(struct pkt_node), M_SIFTR_PKTNODE, M_NOWAIT|M_ZERO);
|
pn = malloc(sizeof(struct pkt_node), M_SIFTR_PKTNODE, M_NOWAIT|M_ZERO);
|
||||||
|
|
||||||
|
|
@ -884,6 +791,9 @@ siftr_chkpkt(struct mbuf **m, struct ifnet *ifp, int flags,
|
||||||
goto inp_unlock;
|
goto inp_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pn->flowid = hash_id;
|
||||||
|
pn->flowtype = hash_type;
|
||||||
|
|
||||||
siftr_siftdata(pn, inp, tp, INP_IPV4, dir, inp_locally_locked);
|
siftr_siftdata(pn, inp, tp, INP_IPV4, dir, inp_locally_locked);
|
||||||
|
|
||||||
mtx_lock(&siftr_pkt_queue_mtx);
|
mtx_lock(&siftr_pkt_queue_mtx);
|
||||||
|
|
@ -911,6 +821,9 @@ siftr_chkpkt6(struct mbuf **m, struct ifnet *ifp, int flags,
|
||||||
struct siftr_stats *ss;
|
struct siftr_stats *ss;
|
||||||
unsigned int ip6_hl;
|
unsigned int ip6_hl;
|
||||||
int inp_locally_locked, dir;
|
int inp_locally_locked, dir;
|
||||||
|
uint32_t hash_id, hash_type;
|
||||||
|
struct listhead *counter_list;
|
||||||
|
struct flow_hash_node *hash_node;
|
||||||
|
|
||||||
inp_locally_locked = 0;
|
inp_locally_locked = 0;
|
||||||
dir = PFIL_DIR(flags);
|
dir = PFIL_DIR(flags);
|
||||||
|
|
@ -982,9 +895,11 @@ siftr_chkpkt6(struct mbuf **m, struct ifnet *ifp, int flags,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we can't find the TCP control block (happens occasionaly for a
|
* If we can't find the TCP control block (happens occasionaly for a
|
||||||
* packet sent during the shutdown phase of a TCP connection), bail
|
* packet sent during the shutdown phase of a TCP connection), or the
|
||||||
|
* TCP control block has not initialized (happens during TCPS_SYN_SENT),
|
||||||
|
* bail.
|
||||||
*/
|
*/
|
||||||
if (tp == NULL) {
|
if (tp == NULL || tp->t_state < TCPS_ESTABLISHED) {
|
||||||
if (dir == PFIL_IN)
|
if (dir == PFIL_IN)
|
||||||
ss->nskip_in_tcpcb++;
|
ss->nskip_in_tcpcb++;
|
||||||
else
|
else
|
||||||
|
|
@ -993,6 +908,27 @@ siftr_chkpkt6(struct mbuf **m, struct ifnet *ifp, int flags,
|
||||||
goto inp_unlock6;
|
goto inp_unlock6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hash_id = siftr_get_flowid(inp, INP_IPV6, &hash_type);
|
||||||
|
counter_list = counter_hash + (hash_id & siftr_hashmask);
|
||||||
|
hash_node = siftr_find_flow(counter_list, hash_id);
|
||||||
|
|
||||||
|
/* If this flow hasn't been seen before, we create a new entry. */
|
||||||
|
if (!hash_node) {
|
||||||
|
struct flow_info info;
|
||||||
|
|
||||||
|
ip6_sprintf(info.laddr, &inp->in6p_laddr);
|
||||||
|
ip6_sprintf(info.faddr, &inp->in6p_faddr);
|
||||||
|
info.lport = ntohs(inp->inp_lport);
|
||||||
|
info.fport = ntohs(inp->inp_fport);
|
||||||
|
info.key = hash_id;
|
||||||
|
info.ipver = INP_IPV6;
|
||||||
|
|
||||||
|
hash_node = siftr_new_hash_node(info, dir, ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hash_node) {
|
||||||
|
goto inp_unlock6;
|
||||||
|
}
|
||||||
|
|
||||||
pn = malloc(sizeof(struct pkt_node), M_SIFTR_PKTNODE, M_NOWAIT|M_ZERO);
|
pn = malloc(sizeof(struct pkt_node), M_SIFTR_PKTNODE, M_NOWAIT|M_ZERO);
|
||||||
|
|
||||||
|
|
@ -1005,6 +941,9 @@ siftr_chkpkt6(struct mbuf **m, struct ifnet *ifp, int flags,
|
||||||
goto inp_unlock6;
|
goto inp_unlock6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pn->flowid = hash_id;
|
||||||
|
pn->flowtype = hash_type;
|
||||||
|
|
||||||
siftr_siftdata(pn, inp, tp, INP_IPV6, dir, inp_locally_locked);
|
siftr_siftdata(pn, inp, tp, INP_IPV6, dir, inp_locally_locked);
|
||||||
|
|
||||||
/* XXX: Figure out how to generate hashes for IPv6 packets. */
|
/* XXX: Figure out how to generate hashes for IPv6 packets. */
|
||||||
|
|
@ -1122,18 +1061,8 @@ siftr_manage_ops(uint8_t action)
|
||||||
struct timeval tval;
|
struct timeval tval;
|
||||||
struct flow_hash_node *counter, *tmp_counter;
|
struct flow_hash_node *counter, *tmp_counter;
|
||||||
struct sbuf *s;
|
struct sbuf *s;
|
||||||
int i, key_index, error;
|
int i, error;
|
||||||
uint32_t bytes_to_write, total_skipped_pkts;
|
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;
|
error = 0;
|
||||||
total_skipped_pkts = 0;
|
total_skipped_pkts = 0;
|
||||||
|
|
@ -1249,77 +1178,11 @@ siftr_manage_ops(uint8_t action)
|
||||||
for (i = 0; i <= siftr_hashmask; i++) {
|
for (i = 0; i <= siftr_hashmask; i++) {
|
||||||
LIST_FOREACH_SAFE(counter, counter_hash + i, nodes,
|
LIST_FOREACH_SAFE(counter, counter_hash + i, nodes,
|
||||||
tmp_counter) {
|
tmp_counter) {
|
||||||
key = counter->key;
|
sbuf_printf(s, "%s;%hu-%s;%hu,",
|
||||||
key_index = 1;
|
counter->const_info.laddr,
|
||||||
|
counter->const_info.lport,
|
||||||
ipver = key[0];
|
counter->const_info.faddr,
|
||||||
|
counter->const_info.fport);
|
||||||
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
|
|
||||||
|
|
||||||
free(counter, M_SIFTR_HASHNODE);
|
free(counter, M_SIFTR_HASHNODE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue