when a session is closed, use the packet manager to create a pseudo packet,
set the session to be closed as packet Exdata, and schedule it to the packet forwarding stage.
when the pseudo packet free, the session will be free.
479 lines
18 KiB
C
479 lines
18 KiB
C
#include "stellar/exdata.h"
|
|
#include "session_internal.h"
|
|
#include "session_manager_stat.h"
|
|
|
|
void session_init(struct session *sess)
|
|
{
|
|
memset(sess, 0, sizeof(struct session));
|
|
}
|
|
|
|
void session_set_id(struct session *sess, uint64_t id)
|
|
{
|
|
sess->id = id;
|
|
}
|
|
|
|
uint64_t session_get_id(const struct session *sess)
|
|
{
|
|
return sess->id;
|
|
}
|
|
|
|
void session_set_tuple6(struct session *sess, const struct tuple6 *tuple)
|
|
{
|
|
memcpy(&sess->tuple, tuple, sizeof(struct tuple6));
|
|
}
|
|
|
|
const struct tuple6 *session_get_tuple6(const struct session *sess)
|
|
{
|
|
return &sess->tuple;
|
|
}
|
|
|
|
const char *session_get_readable_addr(const struct session *sess)
|
|
{
|
|
return sess->tuple_str;
|
|
}
|
|
|
|
void session_set_direction(struct session *sess, enum session_direction dir)
|
|
{
|
|
sess->sess_dir = dir;
|
|
}
|
|
|
|
enum session_direction session_get_direction(const struct session *sess)
|
|
{
|
|
return sess->sess_dir;
|
|
}
|
|
|
|
void session_set_flow_type(struct session *sess, enum flow_type type)
|
|
{
|
|
sess->flow_type = type;
|
|
}
|
|
|
|
enum flow_type session_get_flow_type(const struct session *sess)
|
|
{
|
|
return sess->flow_type;
|
|
}
|
|
|
|
void session_set_current_state(struct session *sess, enum session_state state)
|
|
{
|
|
sess->state = state;
|
|
}
|
|
|
|
enum session_state session_get_current_state(const struct session *sess)
|
|
{
|
|
return sess->state;
|
|
}
|
|
|
|
void session_set_type(struct session *sess, enum session_type type)
|
|
{
|
|
sess->sess_type = type;
|
|
}
|
|
|
|
enum session_type session_get_type(const struct session *sess)
|
|
{
|
|
return sess->sess_type;
|
|
}
|
|
|
|
void session_set_duplicate_traffic(struct session *sess)
|
|
{
|
|
sess->dup = 1;
|
|
}
|
|
|
|
int session_has_duplicate_traffic(const struct session *sess)
|
|
{
|
|
return sess->dup;
|
|
}
|
|
|
|
void session_set_closing_reason(struct session *sess, enum closing_reason reason)
|
|
{
|
|
sess->reason = reason;
|
|
}
|
|
|
|
enum closing_reason session_get_closing_reason(const struct session *sess)
|
|
{
|
|
return sess->reason;
|
|
}
|
|
|
|
void session_inc_stat(struct session *sess, enum flow_type type, enum session_stat stat, uint64_t val)
|
|
{
|
|
sess->stats[type][stat] += val;
|
|
}
|
|
|
|
uint64_t session_get_stat(const struct session *sess, enum flow_type type, enum session_stat stat)
|
|
{
|
|
return sess->stats[type][stat];
|
|
}
|
|
|
|
void session_set_timestamp(struct session *sess, enum session_timestamp type, uint64_t value)
|
|
{
|
|
sess->timestamps[type] = value;
|
|
}
|
|
|
|
uint64_t session_get_timestamp(const struct session *sess, enum session_timestamp type)
|
|
{
|
|
return sess->timestamps[type];
|
|
}
|
|
|
|
void session_clear_sids(struct session *sess, enum flow_type type)
|
|
{
|
|
memset(&sess->sids[type], 0, sizeof(struct sids));
|
|
}
|
|
|
|
void session_set_sids(struct session *sess, enum flow_type type, const struct sids *sids)
|
|
{
|
|
sess->sids[type] = *sids;
|
|
}
|
|
|
|
const struct sids *session_get_sids(const struct session *sess, enum flow_type type)
|
|
{
|
|
return &sess->sids[type];
|
|
}
|
|
|
|
void session_clear_route_ctx(struct session *sess, enum flow_type type)
|
|
{
|
|
memset(&sess->route_ctx[type], 0, sizeof(struct route_ctx));
|
|
}
|
|
|
|
void session_set_route_ctx(struct session *sess, enum flow_type type, const struct route_ctx *ctx)
|
|
{
|
|
sess->route_ctx[type] = *ctx;
|
|
}
|
|
|
|
const struct route_ctx *session_get_route_ctx(const struct session *sess, enum flow_type type)
|
|
{
|
|
return &sess->route_ctx[type];
|
|
}
|
|
|
|
void session_set_first_packet(struct session *sess, enum flow_type type, const struct packet *pkt)
|
|
{
|
|
sess->first_pkt[type] = pkt;
|
|
}
|
|
|
|
const struct packet *session_get_first_packet(const struct session *sess, enum flow_type type)
|
|
{
|
|
return sess->first_pkt[type];
|
|
}
|
|
|
|
void session_set_current_packet(struct session *sess, const struct packet *pkt)
|
|
{
|
|
sess->curr_pkt = pkt;
|
|
}
|
|
|
|
const struct packet *session_get_current_packet(const struct session *sess)
|
|
{
|
|
return sess->curr_pkt;
|
|
}
|
|
|
|
int session_is_symmetric(const struct session *sess, unsigned char *flag)
|
|
{
|
|
int is_symmetric = 0;
|
|
if (sess->first_pkt[FLOW_TYPE_C2S] && sess->first_pkt[FLOW_TYPE_S2C])
|
|
{
|
|
if (flag)
|
|
{
|
|
*flag = (SESSION_SEEN_C2S_FLOW | SESSION_SEEN_S2C_FLOW);
|
|
}
|
|
is_symmetric = 1;
|
|
}
|
|
else if (sess->first_pkt[FLOW_TYPE_C2S])
|
|
{
|
|
if (flag)
|
|
{
|
|
*flag = SESSION_SEEN_C2S_FLOW;
|
|
}
|
|
}
|
|
else if (sess->first_pkt[FLOW_TYPE_S2C])
|
|
{
|
|
if (flag)
|
|
{
|
|
*flag = SESSION_SEEN_S2C_FLOW;
|
|
}
|
|
}
|
|
return is_symmetric;
|
|
}
|
|
|
|
void session_set_user_data(struct session *sess, void *user_data)
|
|
{
|
|
sess->user_data = user_data;
|
|
}
|
|
|
|
void *session_get_user_data(const struct session *sess)
|
|
{
|
|
return sess->user_data;
|
|
}
|
|
|
|
struct tcp_segment *session_get_tcp_segment(struct session *sess)
|
|
{
|
|
enum flow_type type = session_get_flow_type(sess);
|
|
struct tcp_half *half = &sess->tcp_halfs[type];
|
|
|
|
if (half->inorder_seg.data != NULL && half->inorder_seg.len > 0 && !half->inorder_seg_consumed)
|
|
{
|
|
sess->sess_mgr_stat->tcp_segs_consumed++;
|
|
half->inorder_seg_consumed = 1;
|
|
return &half->inorder_seg;
|
|
}
|
|
else
|
|
{
|
|
struct tcp_segment *seg = tcp_reassembly_pop(half->tcp_reass);
|
|
if (seg)
|
|
{
|
|
session_inc_stat(sess, type, STAT_TCP_SEGMENTS_REORDERED, 1);
|
|
session_inc_stat(sess, type, STAT_TCP_PAYLOADS_REORDERED, seg->len);
|
|
|
|
// TODO
|
|
sess->sess_mgr_stat->tcp_segs_consumed++;
|
|
sess->sess_mgr_stat->tcp_segs_reordered++;
|
|
}
|
|
return seg;
|
|
}
|
|
}
|
|
|
|
void session_free_tcp_segment(struct session *sess, struct tcp_segment *seg)
|
|
{
|
|
if (seg == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
enum flow_type type = session_get_flow_type(sess);
|
|
struct tcp_half *half = &sess->tcp_halfs[type];
|
|
|
|
// in order segment
|
|
if (seg == &half->inorder_seg)
|
|
{
|
|
half->inorder_seg.data = NULL;
|
|
half->inorder_seg.len = 0;
|
|
return;
|
|
}
|
|
// tcp reassembly segment
|
|
else
|
|
{
|
|
session_inc_stat(sess, type, STAT_TCP_SEGMENTS_RELEASED, 1);
|
|
session_inc_stat(sess, type, STAT_TCP_PAYLOADS_RELEASED, seg->len);
|
|
sess->sess_mgr_stat->tcp_segs_freed++;
|
|
|
|
tcp_segment_free(seg);
|
|
}
|
|
}
|
|
|
|
const char *closing_reason_to_str(enum closing_reason reason)
|
|
{
|
|
switch (reason)
|
|
{
|
|
case CLOSING_BY_TIMEOUT:
|
|
return "closing by timeout";
|
|
case CLOSING_BY_LRU_EVICTED:
|
|
return "closing by lru evicted";
|
|
case CLOSING_BY_PORT_REUSE_EVICTED:
|
|
return "closing by port reuse evicted";
|
|
case CLOSING_BY_CLIENT_FIN:
|
|
return "closing by client FIN";
|
|
case CLOSING_BY_CLIENT_RST:
|
|
return "closing by client RST";
|
|
case CLOSING_BY_SERVER_FIN:
|
|
return "closing by server FIN";
|
|
case CLOSING_BY_SERVER_RST:
|
|
return "closing by server RST";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
const char *session_state_to_str(enum session_state state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case SESSION_STATE_INIT:
|
|
return "init";
|
|
case SESSION_STATE_OPENING:
|
|
return "opening";
|
|
case SESSION_STATE_ACTIVE:
|
|
return "active";
|
|
case SESSION_STATE_CLOSING:
|
|
return "closing";
|
|
case SESSION_STATE_DISCARD:
|
|
return "discard";
|
|
case SESSION_STATE_CLOSED:
|
|
return "closed";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
const char *session_type_to_str(enum session_type type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case SESSION_TYPE_TCP:
|
|
return "TCP";
|
|
case SESSION_TYPE_UDP:
|
|
return "UDP";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
const char *flow_direction_to_str(enum flow_type type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case FLOW_TYPE_C2S:
|
|
return "C2S";
|
|
case FLOW_TYPE_S2C:
|
|
return "S2C";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
static void tcp_flags_to_str(uint8_t flags, char *buffer, size_t len)
|
|
{
|
|
int used = 0;
|
|
|
|
if (flags & TH_SYN)
|
|
{
|
|
used += snprintf(buffer + used, len - used, "SYN ");
|
|
}
|
|
if (flags & TH_ACK)
|
|
{
|
|
used += snprintf(buffer + used, len - used, "ACK ");
|
|
}
|
|
if (flags & TH_FIN)
|
|
{
|
|
used += snprintf(buffer + used, len - used, "FIN ");
|
|
}
|
|
if (flags & TH_RST)
|
|
{
|
|
used += snprintf(buffer + used, len - used, "RST ");
|
|
}
|
|
}
|
|
|
|
int session_to_str(const struct session *sess, int bref, char *buff, int size)
|
|
{
|
|
memset(buff, 0, size);
|
|
char flags[64] = {0};
|
|
int used = 0;
|
|
|
|
if (bref)
|
|
{
|
|
used += snprintf(buff + used, size - used, "session id: %lu, addr: %s, type: %s, state: %s, dir: %s, c2s_rx_pkts: %lu, s2c_rx_pkts: %lu",
|
|
session_get_id(sess),
|
|
session_get_readable_addr(sess),
|
|
session_type_to_str(session_get_type(sess)),
|
|
session_state_to_str(session_get_current_state(sess)),
|
|
flow_direction_to_str(session_get_flow_type(sess)),
|
|
session_get_stat(sess, FLOW_TYPE_C2S, STAT_RAW_PACKETS_RECEIVED),
|
|
session_get_stat(sess, FLOW_TYPE_S2C, STAT_RAW_PACKETS_RECEIVED));
|
|
}
|
|
else
|
|
{
|
|
used += snprintf(buff + used, size - used, "{");
|
|
used += snprintf(buff + used, size - used, "\"id\":%" PRIu64 ",", session_get_id(sess));
|
|
used += snprintf(buff + used, size - used, "\"start_timestamp_ms\":%" PRIu64 ",", session_get_timestamp(sess, SESSION_TIMESTAMP_START));
|
|
used += snprintf(buff + used, size - used, "\"last_timestamp_ms\":%" PRIu64 ",", session_get_timestamp(sess, SESSION_TIMESTAMP_LAST));
|
|
used += snprintf(buff + used, size - used, "\"tuple\":\"%s\",", session_get_readable_addr(sess));
|
|
used += snprintf(buff + used, size - used, "\"type\":\"%s\",", session_type_to_str(session_get_type(sess)));
|
|
used += snprintf(buff + used, size - used, "\"state\":\"%s\",", session_state_to_str(session_get_current_state(sess)));
|
|
used += snprintf(buff + used, size - used, "\"closing_reason\":\"%s\",", closing_reason_to_str(session_get_closing_reason(sess)));
|
|
used += snprintf(buff + used, size - used, "\"duplicate_traffic\":%d,", session_has_duplicate_traffic(sess));
|
|
used += snprintf(buff + used, size - used, "\"current_packet\":\"%p\",", session_get_current_packet(sess));
|
|
|
|
const char *str[] = {"c2s", "s2c"};
|
|
enum flow_type type[] = {FLOW_TYPE_C2S, FLOW_TYPE_S2C};
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
// raw packets
|
|
used += snprintf(buff + used, size - used, "\"%s_raw_packets_received\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_PACKETS_RECEIVED));
|
|
used += snprintf(buff + used, size - used, "\"%s_raw_bytes_received\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_BYTES_RECEIVED));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_raw_packets_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_PACKETS_TRANSMITTED));
|
|
used += snprintf(buff + used, size - used, "\"%s_raw_bytes_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_BYTES_TRANSMITTED));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_raw_packets_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_PACKETS_DROPPED));
|
|
used += snprintf(buff + used, size - used, "\"%s_raw_bytes_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_RAW_BYTES_DROPPED));
|
|
|
|
// duplicate packets
|
|
used += snprintf(buff + used, size - used, "\"%s_duplicate_packets_bypass\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_DUPLICATE_PACKETS_BYPASS));
|
|
used += snprintf(buff + used, size - used, "\"%s_duplicate_bytes_bypass\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_DUPLICATE_BYTES_BYPASS));
|
|
|
|
// injected packets
|
|
used += snprintf(buff + used, size - used, "\"%s_injected_packets_failed\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_INJECTED_PACKETS_FAILED));
|
|
used += snprintf(buff + used, size - used, "\"%s_injected_packets_success\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_INJECTED_PACKETS_SUCCESS));
|
|
used += snprintf(buff + used, size - used, "\"%s_injected_bytes_success\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_INJECTED_BYTES_SUCCESS));
|
|
|
|
// control packets
|
|
used += snprintf(buff + used, size - used, "\"%s_pseudo_packets_received\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_PSEUDO_PACKETS_RECEIVED));
|
|
used += snprintf(buff + used, size - used, "\"%s_pseudo_bytes_received\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_PSEUDO_BYTES_RECEIVED));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_pseudo_packets_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_PSEUDO_PACKETS_TRANSMITTED));
|
|
used += snprintf(buff + used, size - used, "\"%s_pseudo_bytes_transmitted\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_PSEUDO_BYTES_TRANSMITTED));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_pseudo_packets_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_PSEUDO_PACKETS_DROPPED));
|
|
used += snprintf(buff + used, size - used, "\"%s_pseudo_bytes_dropped\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_PSEUDO_BYTES_DROPPED));
|
|
|
|
if (session_get_type(sess) == SESSION_TYPE_TCP)
|
|
{
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_last_seq\":%u,", str[i], sess->tcp_halfs[type[i]].seq);
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_last_ack\":%u,", str[i], sess->tcp_halfs[type[i]].ack);
|
|
memset(flags, 0, sizeof(flags));
|
|
tcp_flags_to_str(sess->tcp_halfs[type[i]].flags, flags, sizeof(flags));
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_flags\":\"%s\",", str[i], flags);
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_segments_received\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_RECEIVED));
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_received\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_RECEIVED));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_segments_expired\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_EXPIRED));
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_expired\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_EXPIRED));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_segments_retransmit\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_RETRANSMIT));
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_retransmit\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_RETRANSMIT));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_segments_overlap\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_OVERLAP));
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_overlap\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_OVERLAP));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_segments_nospace\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_NOSPACE));
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_nospace\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_NOSPACE));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_segments_inorder\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_INORDER));
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_inorder\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_INORDER));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_segments_reordered\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_REORDERED));
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_reordered\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_REORDERED));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_segments_buffered\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_BUFFERED));
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_buffered\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_BUFFERED));
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_segments_released\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_SEGMENTS_RELEASED));
|
|
used += snprintf(buff + used, size - used, "\"%s_tcp_payloads_released\":%" PRIu64 ",", str[i], session_get_stat(sess, type[i], STAT_TCP_PAYLOADS_RELEASED));
|
|
}
|
|
|
|
used += snprintf(buff + used, size - used, "\"%s_first_packet\":\"%p\"", str[i], session_get_first_packet(sess, type[i]));
|
|
if (i == 0)
|
|
{
|
|
used += snprintf(buff + used, size - used, ",");
|
|
}
|
|
}
|
|
used += snprintf(buff + used, size - used, "}");
|
|
}
|
|
|
|
return used;
|
|
}
|
|
|
|
void session_print(const struct session *sess)
|
|
{
|
|
char buff[4096];
|
|
session_to_str(sess, 0, buff, sizeof(buff));
|
|
printf("%s\n", buff);
|
|
}
|
|
|
|
void session_set_exdata(struct session *sess, int idx, void *ex_ptr)
|
|
{
|
|
struct exdata_runtime *rte = (struct exdata_runtime *)session_get_user_data(sess);
|
|
exdata_set(rte, idx, ex_ptr);
|
|
}
|
|
|
|
void *session_get_exdata(const struct session *sess, int idx)
|
|
{
|
|
struct exdata_runtime *rte = (struct exdata_runtime *)session_get_user_data(sess);
|
|
return exdata_get(rte, idx);
|
|
}
|