69#include <sys/eventhandler.h>
71#include <sys/kernel.h>
72#include <sys/kthread.h>
75#include <sys/module.h>
82#include <sys/socket.h>
83#include <sys/socketvar.h>
84#include <sys/sysctl.h>
85#include <sys/unistd.h>
88#include <net/if_var.h>
102#include <netinet6/ip6_var.h>
103#include <netinet6/in6_pcb.h>
106#include <machine/in_cksum.h>
116#define V_BACKCOMPAT 4
117#define MODVERSION __CONCAT(V_MAJOR, __CONCAT(V_BACKBREAK, V_BACKCOMPAT))
118#define MODVERSION_STR __XSTRING(V_MAJOR) "." __XSTRING(V_BACKBREAK) "." \
119 __XSTRING(V_BACKCOMPAT)
123#define SIFTR_EXPECTED_MAX_TCP_FLOWS 65536
124#define SYS_NAME "FreeBSD"
125#define PACKET_TAG_SIFTR 100
126#define PACKET_COOKIE_SIFTR 21749576
127#define SIFTR_LOG_FILE_MODE 0644
128#define SIFTR_DISABLE 0
129#define SIFTR_ENABLE 1
135#define MAX_LOG_MSG_LEN 200
137#define SIFTR_ALQ_BUFLEN (1000*MAX_LOG_MSG_LEN)
145#define FLOW_KEY_LEN 37
147#define FLOW_KEY_LEN 13
151#define SIFTR_IPMODE 6
153#define SIFTR_IPMODE 4
157#define UPPER_SHORT(X) (((X) & 0xFFFF0000) >> 16)
158#define LOWER_SHORT(X) ((X) & 0x0000FFFF)
160#define FIRST_OCTET(X) (((X) & 0xFF000000) >> 24)
161#define SECOND_OCTET(X) (((X) & 0x00FF0000) >> 16)
162#define THIRD_OCTET(X) (((X) & 0x0000FF00) >> 8)
163#define FOURTH_OCTET(X) ((X) & 0x000000FF)
167 "SIFTR pkt_node struct");
169 "SIFTR flow_hash_node struct");
287static int wait_for_pkt;
288static struct alq *siftr_alq = NULL;
289static struct mtx siftr_pkt_queue_mtx;
290static struct mtx siftr_pkt_mgr_mtx;
291static struct thread *siftr_pkt_manager_thr = NULL;
292static char direction[2] = {
'i',
'o'};
302SYSCTL_NODE(_net_inet, OID_AUTO, siftr, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
303 "siftr related settings");
306 CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
308 "switch siftr module operations on/off");
313 "file to save siftr log messages to");
317 "number of packets between generating a log message");
321 "enable packet hash generation");
323SYSCTL_U16(_net_inet_siftr, OID_AUTO, port_filter, CTLFLAG_RW,
325 "enable packet filter on a TCP port");
339 struct listhead *counter_list;
343 uint8_t found_match, key_offset;
368 counter_list = counter_hash +
375 if (LIST_FIRST(counter_list) != NULL) {
382 LIST_FOREACH(hash_node, counter_list, nodes) {
391 if (memcmp(hash_node->
key, key,
sizeof(key)) == 0) {
399 if (hash_node == NULL || !found_match) {
402 M_SIFTR_HASHNODE, M_WAITOK);
404 if (hash_node != NULL) {
407 memcpy(hash_node->
key, key,
sizeof(key));
408 LIST_INSERT_HEAD(counter_list, hash_node, nodes);
455 log_buf->ae_bytesused = snprintf(log_buf->ae_data,
457 "%c,0x%08x,%zd.%06ld,%x:%x:%x:%x:%x:%x:%x:%x,%u,%x:%x:%x:"
458 "%x:%x:%x:%x:%x,%u,%ld,%ld,%ld,%ld,%ld,%u,%u,%u,%u,%u,%u,"
459 "%u,%d,%u,%u,%u,%u,%u,%u,%u,%u\n",
515 log_buf->ae_bytesused = snprintf(log_buf->ae_data,
517 "%c,0x%08x,%jd.%06ld,%u.%u.%u.%u,%u,%u.%u.%u.%u,%u,%ld,%ld,"
518 "%ld,%ld,%ld,%u,%u,%u,%u,%u,%u,%u,%d,%u,%u,%u,%u,%u,%u,%u,%u\n",
558 alq_post_flags(siftr_alq, log_buf, 0);
565 STAILQ_HEAD_INITIALIZER(tmp_pkt_queue);
571 mtx_lock(&siftr_pkt_mgr_mtx);
579 mtx_sleep(&wait_for_pkt, &siftr_pkt_mgr_mtx, PWAIT,
"pktwait",
583 mtx_lock(&siftr_pkt_queue_mtx);
589 STAILQ_CONCAT(&tmp_pkt_queue, &pkt_queue);
595 mtx_unlock(&siftr_pkt_queue_mtx);
601 mtx_unlock(&siftr_pkt_mgr_mtx);
604 STAILQ_FOREACH_SAFE(
pkt_node, &tmp_pkt_queue, nodes,
607 STAILQ_REMOVE_HEAD(&tmp_pkt_queue, nodes);
611 KASSERT(STAILQ_EMPTY(&tmp_pkt_queue),
612 (
"SIFTR tmp_pkt_queue not empty after flush"));
614 mtx_lock(&siftr_pkt_mgr_mtx);
632 mtx_unlock(&siftr_pkt_mgr_mtx);
645 while (m != NULL && offset > m->m_len) {
657 if ((m->m_len - offset) > 0)
658 hash = hash32_buf(m->m_data + offset,
659 m->m_len - offset,
hash);
696 m_tag_prepend(m, tag);
706static inline struct inpcb *
758 int ipver,
int dir,
int inp_locally_locked)
762 pn->
ip_laddr[3] = inp->inp_laddr.s_addr;
763 pn->
ip_faddr[3] = inp->inp_faddr.s_addr;
770 pn->
ip_laddr[0] = inp->in6p_laddr.s6_addr32[0];
771 pn->
ip_laddr[1] = inp->in6p_laddr.s6_addr32[1];
772 pn->
ip_laddr[2] = inp->in6p_laddr.s6_addr32[2];
773 pn->
ip_laddr[3] = inp->in6p_laddr.s6_addr32[3];
774 pn->
ip_faddr[0] = inp->in6p_faddr.s6_addr32[0];
775 pn->
ip_faddr[1] = inp->in6p_faddr.s6_addr32[1];
776 pn->
ip_faddr[2] = inp->in6p_faddr.s6_addr32[2];
777 pn->
ip_faddr[3] = inp->in6p_faddr.s6_addr32[3];
805 if (inp_locally_locked)
809 pn->
direction = (dir == PFIL_IN ? DIR_IN : DIR_OUT);
816 microtime(&pn->
tval);
831 void *ruleset __unused,
struct inpcb *inp)
839 int inp_locally_locked, dir;
841 inp_locally_locked = 0;
842 dir = PFIL_DIR(flags);
850 ip = mtod(*m,
struct ip *);
875 th = (
struct tcphdr *)((caddr_t)
ip +
ip_hl);
884 th->th_dport, dir, ss);
889 inp_locally_locked = 1;
921 pn = malloc(
sizeof(
struct pkt_node), M_SIFTR_PKTNODE, M_NOWAIT|M_ZERO);
935 if ((*m)->m_pkthdr.csum_flags & CSUM_TCP) {
946 (*m)->m_pkthdr.csum_flags &= ~CSUM_TCP;
996 mtx_lock(&siftr_pkt_queue_mtx);
997 STAILQ_INSERT_TAIL(&pkt_queue, pn, nodes);
998 mtx_unlock(&siftr_pkt_queue_mtx);
1002 if (inp_locally_locked)
1011siftr_chkpkt6(
struct mbuf **m,
struct ifnet *ifp,
int flags,
1012 void *ruleset __unused,
struct inpcb *inp)
1019 unsigned int ip6_hl;
1020 int inp_locally_locked, dir;
1022 inp_locally_locked = 0;
1023 dir = PFIL_DIR(flags);
1031 ip6 = mtod(*m,
struct ip6_hdr *);
1055 ip6_hl =
sizeof(
struct ip6_hdr);
1062 th = (
struct tcphdr *)((caddr_t)ip6 + ip6_hl);
1071 th->th_sport, th->th_dport, dir, ss);
1076 inp_locally_locked = 1;
1106 pn = malloc(
sizeof(
struct pkt_node), M_SIFTR_PKTNODE, M_NOWAIT|M_ZERO);
1121 mtx_lock(&siftr_pkt_queue_mtx);
1122 STAILQ_INSERT_TAIL(&pkt_queue, pn, nodes);
1123 mtx_unlock(&siftr_pkt_queue_mtx);
1127 if (inp_locally_locked)
1137#define V_siftr_inet_hook VNET(siftr_inet_hook)
1140#define V_siftr_inet6_hook VNET(siftr_inet6_hook)
1145 struct pfil_hook_args pha;
1146 struct pfil_link_args pla;
1148 pha.pa_version = PFIL_VERSION;
1149 pha.pa_flags = PFIL_IN | PFIL_OUT;
1150 pha.pa_modname =
"siftr";
1151 pha.pa_ruleset = NULL;
1152 pha.pa_rulname =
"default";
1154 pla.pa_version = PFIL_VERSION;
1155 pla.pa_flags = PFIL_IN | PFIL_OUT |
1156 PFIL_HEADPTR | PFIL_HOOKPTR;
1158 VNET_ITERATOR_DECL(vnet_iter);
1161 VNET_FOREACH(vnet_iter) {
1162 CURVNET_SET(vnet_iter);
1164 if (action ==
HOOK) {
1166 pha.pa_type = PFIL_TYPE_IP4;
1170 (void)pfil_link(&pla);
1172 pha.pa_func = siftr_chkpkt6;
1173 pha.pa_type = PFIL_TYPE_IP6;
1174 V_siftr_inet6_hook = pfil_add_hook(&pha);
1175 pla.pa_hook = V_siftr_inet6_hook;
1176 pla.pa_head = V_inet6_pfil_head;
1177 (void)pfil_link(&pla);
1179 }
else if (action ==
UNHOOK) {
1182 pfil_remove_hook(V_siftr_inet6_hook);
1187 VNET_LIST_RUNLOCK();
1195 struct alq *new_alq;
1198 error = sysctl_handle_string(oidp, arg1, arg2, req);
1201 if (error != 0 || req->newptr == NULL ||
1206 error = alq_open(&new_alq, arg1, curthread->td_ucred,
1217 if (siftr_alq == NULL) {
1220 alq_close(siftr_alq);
1221 siftr_alq = new_alq;
1234 struct timeval tval;
1237 int i, key_index, error;
1238 uint32_t bytes_to_write, total_skipped_pkts;
1251 total_skipped_pkts = 0;
1254 if ((s = sbuf_new(NULL, NULL, 200, SBUF_AUTOEXTEND)) == NULL)
1257 if (action ==
SIFTR_ENABLE && siftr_pkt_manager_thr == NULL) {
1265 STAILQ_INIT(&pkt_queue);
1272 &siftr_pkt_manager_thr, RFNOWAIT, 0,
1273 "siftr_pkt_manager_thr");
1280 "enable_time_secs=%jd\tenable_time_usecs=%06ld\t"
1281 "siftrver=%s\thz=%u\ttcp_rtt_scale=%u\tsysname=%s\t"
1282 "sysver=%u\tipmode=%u\n",
1287 alq_writen(siftr_alq, sbuf_data(s), sbuf_len(s), ALQ_WAITOK);
1289 }
else if (action ==
SIFTR_DISABLE && siftr_pkt_manager_thr != NULL) {
1298 mtx_lock(&siftr_pkt_mgr_mtx);
1309 wakeup(&wait_for_pkt);
1312 mtx_sleep(siftr_pkt_manager_thr, &siftr_pkt_mgr_mtx, PWAIT,
1315 siftr_pkt_manager_thr = NULL;
1316 mtx_unlock(&siftr_pkt_mgr_mtx);
1318 totalss.
n_in = DPCPU_VARSUM(ss, n_in);
1319 totalss.
n_out = DPCPU_VARSUM(ss, n_out);
1338 "disable_time_secs=%jd\tdisable_time_usecs=%06ld\t"
1339 "num_inbound_tcp_pkts=%ju\tnum_outbound_tcp_pkts=%ju\t"
1340 "total_tcp_pkts=%ju\tnum_inbound_skipped_pkts_malloc=%u\t"
1341 "num_outbound_skipped_pkts_malloc=%u\t"
1342 "num_inbound_skipped_pkts_mtx=%u\t"
1343 "num_outbound_skipped_pkts_mtx=%u\t"
1344 "num_inbound_skipped_pkts_tcpcb=%u\t"
1345 "num_outbound_skipped_pkts_tcpcb=%u\t"
1346 "num_inbound_skipped_pkts_inpcb=%u\t"
1347 "num_outbound_skipped_pkts_inpcb=%u\t"
1348 "total_skipped_tcp_pkts=%u\tflow_list=",
1349 (intmax_t)tval.tv_sec,
1351 (uintmax_t)totalss.
n_in,
1352 (uintmax_t)totalss.
n_out,
1353 (uintmax_t)(totalss.
n_in + totalss.
n_out),
1362 total_skipped_pkts);
1370 LIST_FOREACH_SAFE(counter, counter_hash + i, nodes,
1377 memcpy(laddr, key + key_index,
sizeof(laddr));
1378 key_index +=
sizeof(laddr);
1379 memcpy(&lport, key + key_index,
sizeof(lport));
1380 key_index +=
sizeof(lport);
1381 memcpy(faddr, key + key_index,
sizeof(faddr));
1382 key_index +=
sizeof(faddr);
1383 memcpy(&fport, key + key_index,
sizeof(fport));
1386 laddr[3] = ntohl(laddr[3]);
1387 faddr[3] = ntohl(faddr[3]);
1390 laddr[0] = ntohl(laddr[0]);
1391 laddr[1] = ntohl(laddr[1]);
1392 laddr[2] = ntohl(laddr[2]);
1393 faddr[0] = ntohl(faddr[0]);
1394 faddr[1] = ntohl(faddr[1]);
1395 faddr[2] = ntohl(faddr[2]);
1398 "%x:%x:%x:%x:%x:%x:%x:%x;%u-"
1399 "%x:%x:%x:%x:%x:%x:%x:%x;%u,",
1429 "%u.%u.%u.%u;%u-%u.%u.%u.%u;%u,",
1444 free(counter, M_SIFTR_HASHNODE);
1447 LIST_INIT(counter_hash + i);
1450 sbuf_printf(s,
"\n");
1456 alq_writen(siftr_alq, sbuf_data(s)+i, bytes_to_write, ALQ_WAITOK);
1457 i += bytes_to_write;
1458 }
while (i < sbuf_len(s));
1460 alq_close(siftr_alq);
1482 error = sysctl_handle_int(oidp, &
new, 0, req);
1483 if (error == 0 && req->newptr != NULL) {
1515 mtx_destroy(&siftr_pkt_queue_mtx);
1516 mtx_destroy(&siftr_pkt_mgr_mtx);
1528 SHUTDOWN_PRI_FIRST);
1534 mtx_init(&siftr_pkt_queue_mtx,
"siftr_pkt_queue_mtx", NULL, MTX_DEF);
1535 mtx_init(&siftr_pkt_mgr_mtx,
"siftr_pkt_mgr_mtx", NULL, MTX_DEF);
1538 uprintf(
"\nStatistical Information For TCP Research (SIFTR) %s\n"
1539 " http://caia.swin.edu.au/urp/newtcp\n\n",
u_short in_cksum_skip(struct mbuf *m, int len, int skip)
#define TCP_PROBE1(probe, arg0)
static void inp_unlock(struct inpcb *inp, const inp_lookup_t lock)
#define INP_LOCK_ASSERT(inp)
struct inpcb * in_pcblookup(struct inpcbinfo *, struct in_addr, u_int, struct in_addr, u_int, int, struct ifnet *)
#define INP_INFO_WUNLOCK_ASSERT(ipi)
static LIST_HEAD(carp_softc)
static u_long siftr_hashmask
static int siftr_sysctl_enabled_handler(SYSCTL_HANDLER_ARGS)
DPCPU_DEFINE_STATIC(struct siftr_stats, ss)
#define PACKET_COOKIE_SIFTR
static int init_siftr(void)
SYSCTL_U16(_net_inet_siftr, OID_AUTO, port_filter, CTLFLAG_RW, &siftr_port_filter, 0, "enable packet filter on a TCP port")
static int siftr_pfil(int action)
static volatile unsigned int siftr_exit_pkt_manager_thread
static struct inpcb * siftr_findinpcb(int ipver, struct ip *ip, struct mbuf *m, uint16_t sport, uint16_t dport, int dir, struct siftr_stats *ss)
#define SIFTR_LOG_FILE_MODE
static void siftr_pkt_manager_thread(void *arg)
SYSCTL_UINT(_net_inet_siftr, OID_AUTO, ppl, CTLFLAG_RW, &siftr_pkts_per_log, 1, "number of packets between generating a log message")
SYSCTL_NODE(_net_inet, OID_AUTO, siftr, CTLFLAG_RW|CTLFLAG_MPSAFE, NULL, "siftr related settings")
static uint32_t hash_pkt(struct mbuf *m, uint32_t offset)
static unsigned int siftr_generate_hashes
static int deinit_siftr(void)
static void siftr_process_pkt(struct pkt_node *pkt_node)
#define SIFTR_EXPECTED_MAX_TCP_FLOWS
STAILQ_HEAD(pkthead, pkt_node)
static unsigned int siftr_pkts_per_log
static moduledata_t siftr_mod
MODULE_VERSION(siftr, MODVERSION)
static unsigned int siftr_enabled
MODULE_DEPEND(siftr, alq, 1, 1, 1)
DECLARE_MODULE(siftr, siftr_mod, SI_SUB_LAST, SI_ORDER_ANY)
#define V_siftr_inet_hook
static int siftr_sysctl_logfile_name_handler(SYSCTL_HANDLER_ARGS)
static int siftr_chkreinject(struct mbuf *m, int dir, struct siftr_stats *ss)
VNET_DEFINE_STATIC(pfil_hook_t, siftr_inet_hook)
static int siftr_load_handler(module_t mod, int what, void *arg)
static MALLOC_DEFINE(M_SIFTR, "siftr", "dynamic memory used by SIFTR")
static char siftr_logfile_shadow[PATH_MAX]
SYSCTL_PROC(_net_inet_siftr, OID_AUTO, enabled, CTLTYPE_UINT|CTLFLAG_RW|CTLFLAG_NEEDGIANT, &siftr_enabled, 0, &siftr_sysctl_enabled_handler, "IU", "switch siftr module operations on/off")
SYSCTL_DECL(_net_inet_siftr)
static void siftr_siftdata(struct pkt_node *pn, struct inpcb *inp, struct tcpcb *tp, int ipver, int dir, int inp_locally_locked)
static uint16_t siftr_port_filter
static pfil_return_t siftr_chkpkt(struct mbuf **m, struct ifnet *ifp, int flags, void *ruleset __unused, struct inpcb *inp)
static int siftr_manage_ops(uint8_t action)
static void siftr_shutdown_handler(void *arg)
static char siftr_logfile[PATH_MAX]
uint8_t key[FLOW_KEY_LEN]
struct socket * inp_socket
struct in_addr ip_src ip_dst
u_int sent_inflight_bytes
enum pkt_node::@38 direction
uint32_t nskip_out_malloc
uint32_t nskip_out_dejavu