mirror of
https://github.com/xdp-project/bpf-examples.git
synced 2024-05-06 15:54:53 +00:00
Merge pull request #55 from simosund/pping-skip-syn
PPing: Add option to ignore SYN-packets
This commit is contained in:
@@ -102,6 +102,7 @@ static const struct option long_options[] = {
|
|||||||
{ "tcp", no_argument, NULL, 'T' }, // Calculate and report RTTs for TCP traffic (with TCP timestamps)
|
{ "tcp", no_argument, NULL, 'T' }, // Calculate and report RTTs for TCP traffic (with TCP timestamps)
|
||||||
{ "icmp", no_argument, NULL, 'C' }, // Calculate and report RTTs for ICMP echo-reply traffic
|
{ "icmp", no_argument, NULL, 'C' }, // Calculate and report RTTs for ICMP echo-reply traffic
|
||||||
{ "include-local", no_argument, NULL, 'l' }, // Also report "internal" RTTs
|
{ "include-local", no_argument, NULL, 'l' }, // Also report "internal" RTTs
|
||||||
|
{ "include-SYN", no_argument, NULL, 's' }, // Include SYN-packets in tracking (may fill up flow state with half-open connections)
|
||||||
{ 0, 0, NULL, 0 }
|
{ 0, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -170,8 +171,9 @@ static int parse_arguments(int argc, char *argv[], struct pping_config *config)
|
|||||||
config->force = false;
|
config->force = false;
|
||||||
config->bpf_config.track_tcp = false;
|
config->bpf_config.track_tcp = false;
|
||||||
config->bpf_config.track_icmp = false;
|
config->bpf_config.track_icmp = false;
|
||||||
|
config->bpf_config.skip_syn = true;
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, "hflTCi:r:R:t:c:F:I:",
|
while ((opt = getopt_long(argc, argv, "hflTCsi:r:R:t:c:F:I:",
|
||||||
long_options, NULL)) != -1) {
|
long_options, NULL)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'i':
|
case 'i':
|
||||||
@@ -266,6 +268,9 @@ static int parse_arguments(int argc, char *argv[], struct pping_config *config)
|
|||||||
case 'C':
|
case 'C':
|
||||||
config->bpf_config.track_icmp = true;
|
config->bpf_config.track_icmp = true;
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
config->bpf_config.skip_syn = false;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
printf("HELP:\n");
|
printf("HELP:\n");
|
||||||
print_usage(argv);
|
print_usage(argv);
|
||||||
|
@@ -64,7 +64,8 @@ struct bpf_config {
|
|||||||
bool track_tcp;
|
bool track_tcp;
|
||||||
bool track_icmp;
|
bool track_icmp;
|
||||||
bool localfilt;
|
bool localfilt;
|
||||||
__u32 reserved;
|
bool skip_syn;
|
||||||
|
__u8 reserved[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -105,7 +106,8 @@ struct flow_state {
|
|||||||
__u32 outstanding_timestamps;
|
__u32 outstanding_timestamps;
|
||||||
enum connection_state conn_state;
|
enum connection_state conn_state;
|
||||||
enum flow_event_reason opening_reason;
|
enum flow_event_reason opening_reason;
|
||||||
__u8 reserved[6];
|
bool has_been_timestamped;
|
||||||
|
__u8 reserved[5];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -104,6 +104,7 @@ struct packet_info {
|
|||||||
bool reply_pid_valid; // reply_identifier can be used to match packet
|
bool reply_pid_valid; // reply_identifier can be used to match packet
|
||||||
enum flow_event_type event_type; // flow event triggered by packet
|
enum flow_event_type event_type; // flow event triggered by packet
|
||||||
enum flow_event_reason event_reason; // reason for triggering flow event
|
enum flow_event_reason event_reason; // reason for triggering flow event
|
||||||
|
bool wait_first_edge; // Do we need to wait for the first identifier change before timestamping?
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -116,6 +117,7 @@ struct protocol_info {
|
|||||||
bool reply_pid_valid;
|
bool reply_pid_valid;
|
||||||
enum flow_event_type event_type;
|
enum flow_event_type event_type;
|
||||||
enum flow_event_reason event_reason;
|
enum flow_event_reason event_reason;
|
||||||
|
bool wait_first_edge;
|
||||||
};
|
};
|
||||||
|
|
||||||
char _license[] SEC("license") = "GPL";
|
char _license[] SEC("license") = "GPL";
|
||||||
@@ -339,6 +341,9 @@ static int parse_tcp_identifier(struct parsing_context *pctx,
|
|||||||
if (parse_tcphdr(&pctx->nh, pctx->data_end, &hdr) < 0)
|
if (parse_tcphdr(&pctx->nh, pctx->data_end, &hdr) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (config.skip_syn && hdr->syn)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (parse_tcp_ts(hdr, pctx->data_end, &proto_info->pid,
|
if (parse_tcp_ts(hdr, pctx->data_end, &proto_info->pid,
|
||||||
&proto_info->reply_pid) < 0)
|
&proto_info->reply_pid) < 0)
|
||||||
return -1; //Possible TODO, fall back on seq/ack instead
|
return -1; //Possible TODO, fall back on seq/ack instead
|
||||||
@@ -361,9 +366,11 @@ static int parse_tcp_identifier(struct parsing_context *pctx,
|
|||||||
proto_info->event_type = FLOW_EVENT_OPENING;
|
proto_info->event_type = FLOW_EVENT_OPENING;
|
||||||
proto_info->event_reason =
|
proto_info->event_reason =
|
||||||
hdr->ack ? EVENT_REASON_SYN_ACK : EVENT_REASON_SYN;
|
hdr->ack ? EVENT_REASON_SYN_ACK : EVENT_REASON_SYN;
|
||||||
|
proto_info->wait_first_edge = false;
|
||||||
} else {
|
} else {
|
||||||
proto_info->event_type = FLOW_EVENT_NONE;
|
proto_info->event_type = FLOW_EVENT_NONE;
|
||||||
proto_info->event_reason = EVENT_REASON_NONE;
|
proto_info->event_reason = EVENT_REASON_NONE;
|
||||||
|
proto_info->wait_first_edge = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*sport = hdr->source;
|
*sport = hdr->source;
|
||||||
@@ -416,6 +423,7 @@ static int parse_icmp6_identifier(struct parsing_context *pctx,
|
|||||||
|
|
||||||
proto_info->event_type = FLOW_EVENT_NONE;
|
proto_info->event_type = FLOW_EVENT_NONE;
|
||||||
proto_info->event_reason = EVENT_REASON_NONE;
|
proto_info->event_reason = EVENT_REASON_NONE;
|
||||||
|
proto_info->wait_first_edge = false;
|
||||||
*sport = hdr->icmp6_identifier;
|
*sport = hdr->icmp6_identifier;
|
||||||
*dport = hdr->icmp6_identifier;
|
*dport = hdr->icmp6_identifier;
|
||||||
*icmp6h = hdr;
|
*icmp6h = hdr;
|
||||||
@@ -453,6 +461,7 @@ static int parse_icmp_identifier(struct parsing_context *pctx,
|
|||||||
|
|
||||||
proto_info->event_type = FLOW_EVENT_NONE;
|
proto_info->event_type = FLOW_EVENT_NONE;
|
||||||
proto_info->event_reason = EVENT_REASON_NONE;
|
proto_info->event_reason = EVENT_REASON_NONE;
|
||||||
|
proto_info->wait_first_edge = false;
|
||||||
*sport = hdr->un.echo.id;
|
*sport = hdr->un.echo.id;
|
||||||
*dport = hdr->un.echo.id;
|
*dport = hdr->un.echo.id;
|
||||||
*icmph = hdr;
|
*icmph = hdr;
|
||||||
@@ -531,6 +540,7 @@ static int parse_packet_identifier(struct parsing_context *pctx,
|
|||||||
p_info->reply_pid_valid = proto_info.reply_pid_valid;
|
p_info->reply_pid_valid = proto_info.reply_pid_valid;
|
||||||
p_info->event_type = proto_info.event_type;
|
p_info->event_type = proto_info.event_type;
|
||||||
p_info->event_reason = proto_info.event_reason;
|
p_info->event_reason = proto_info.event_reason;
|
||||||
|
p_info->wait_first_edge = proto_info.wait_first_edge;
|
||||||
|
|
||||||
if (p_info->pid.flow.ipv == AF_INET) {
|
if (p_info->pid.flow.ipv == AF_INET) {
|
||||||
map_ipv4_to_ipv6(&p_info->pid.flow.saddr.ip,
|
map_ipv4_to_ipv6(&p_info->pid.flow.saddr.ip,
|
||||||
@@ -705,14 +715,19 @@ static void init_flowstate(struct flow_state *f_state,
|
|||||||
{
|
{
|
||||||
f_state->conn_state = CONNECTION_STATE_WAITOPEN;
|
f_state->conn_state = CONNECTION_STATE_WAITOPEN;
|
||||||
f_state->last_timestamp = p_info->time;
|
f_state->last_timestamp = p_info->time;
|
||||||
|
/* We should only ever create new flows for packet with valid pid,
|
||||||
|
so assume pid is valid*/
|
||||||
|
f_state->last_id = p_info->pid.identifier;
|
||||||
f_state->opening_reason = p_info->event_type == FLOW_EVENT_OPENING ?
|
f_state->opening_reason = p_info->event_type == FLOW_EVENT_OPENING ?
|
||||||
p_info->event_reason :
|
p_info->event_reason :
|
||||||
EVENT_REASON_FIRST_OBS_PCKT;
|
EVENT_REASON_FIRST_OBS_PCKT;
|
||||||
|
f_state->has_been_timestamped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_empty_flowstate(struct flow_state *f_state)
|
static void init_empty_flowstate(struct flow_state *f_state)
|
||||||
{
|
{
|
||||||
f_state->conn_state = CONNECTION_STATE_EMPTY;
|
f_state->conn_state = CONNECTION_STATE_EMPTY;
|
||||||
|
f_state->has_been_timestamped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -732,18 +747,15 @@ static void init_dualflow_state(struct dual_flow_state *df_state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct dual_flow_state *
|
static struct dual_flow_state *
|
||||||
create_dualflow_state(void *ctx, struct packet_info *p_info, bool *new_flow)
|
create_dualflow_state(void *ctx, struct packet_info *p_info)
|
||||||
{
|
{
|
||||||
struct network_tuple *key = get_dualflow_key_from_packet(p_info);
|
struct network_tuple *key = get_dualflow_key_from_packet(p_info);
|
||||||
struct dual_flow_state new_state = { 0 };
|
struct dual_flow_state new_state = { 0 };
|
||||||
|
|
||||||
init_dualflow_state(&new_state, p_info);
|
init_dualflow_state(&new_state, p_info);
|
||||||
|
|
||||||
if (bpf_map_update_elem(&flow_state, key, &new_state, BPF_NOEXIST) ==
|
if (bpf_map_update_elem(&flow_state, key, &new_state, BPF_NOEXIST) !=
|
||||||
0) {
|
0) {
|
||||||
if (new_flow)
|
|
||||||
*new_flow = true;
|
|
||||||
} else {
|
|
||||||
send_map_full_event(ctx, p_info, PPING_MAP_FLOWSTATE);
|
send_map_full_event(ctx, p_info, PPING_MAP_FLOWSTATE);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -752,8 +764,7 @@ create_dualflow_state(void *ctx, struct packet_info *p_info, bool *new_flow)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct dual_flow_state *
|
static struct dual_flow_state *
|
||||||
lookup_or_create_dualflow_state(void *ctx, struct packet_info *p_info,
|
lookup_or_create_dualflow_state(void *ctx, struct packet_info *p_info)
|
||||||
bool *new_flow)
|
|
||||||
{
|
{
|
||||||
struct dual_flow_state *df_state;
|
struct dual_flow_state *df_state;
|
||||||
|
|
||||||
@@ -768,7 +779,7 @@ lookup_or_create_dualflow_state(void *ctx, struct packet_info *p_info,
|
|||||||
p_info->event_type == FLOW_EVENT_CLOSING_BOTH)
|
p_info->event_type == FLOW_EVENT_CLOSING_BOTH)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return create_dualflow_state(ctx, p_info, new_flow);
|
return create_dualflow_state(ctx, p_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_flowstate_active(struct flow_state *f_state)
|
static bool is_flowstate_active(struct flow_state *f_state)
|
||||||
@@ -778,15 +789,11 @@ static bool is_flowstate_active(struct flow_state *f_state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void update_forward_flowstate(struct packet_info *p_info,
|
static void update_forward_flowstate(struct packet_info *p_info,
|
||||||
struct flow_state *f_state, bool *new_flow)
|
struct flow_state *f_state)
|
||||||
{
|
{
|
||||||
// "Create" flowstate if it's empty
|
// "Create" flowstate if it's empty
|
||||||
if (f_state->conn_state == CONNECTION_STATE_EMPTY &&
|
if (f_state->conn_state == CONNECTION_STATE_EMPTY && p_info->pid_valid)
|
||||||
p_info->pid_valid) {
|
|
||||||
init_flowstate(f_state, p_info);
|
init_flowstate(f_state, p_info);
|
||||||
if (new_flow)
|
|
||||||
*new_flow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_flowstate_active(f_state)) {
|
if (is_flowstate_active(f_state)) {
|
||||||
f_state->sent_pkts++;
|
f_state->sent_pkts++;
|
||||||
@@ -902,7 +909,7 @@ static bool is_new_identifier(struct packet_id *pid, struct flow_state *f_state)
|
|||||||
* Attempt to create a timestamp-entry for packet p_info for flow in f_state
|
* Attempt to create a timestamp-entry for packet p_info for flow in f_state
|
||||||
*/
|
*/
|
||||||
static void pping_timestamp_packet(struct flow_state *f_state, void *ctx,
|
static void pping_timestamp_packet(struct flow_state *f_state, void *ctx,
|
||||||
struct packet_info *p_info, bool new_flow)
|
struct packet_info *p_info)
|
||||||
{
|
{
|
||||||
if (!is_flowstate_active(f_state) || !p_info->pid_valid)
|
if (!is_flowstate_active(f_state) || !p_info->pid_valid)
|
||||||
return;
|
return;
|
||||||
@@ -912,12 +919,13 @@ static void pping_timestamp_packet(struct flow_state *f_state, void *ctx,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Check if identfier is new
|
// Check if identfier is new
|
||||||
if (!new_flow && !is_new_identifier(&p_info->pid, f_state))
|
if ((f_state->has_been_timestamped || p_info->wait_first_edge) &&
|
||||||
|
!is_new_identifier(&p_info->pid, f_state))
|
||||||
return;
|
return;
|
||||||
f_state->last_id = p_info->pid.identifier;
|
f_state->last_id = p_info->pid.identifier;
|
||||||
|
|
||||||
// Check rate-limit
|
// Check rate-limit
|
||||||
if (!new_flow &&
|
if (f_state->has_been_timestamped &&
|
||||||
is_rate_limited(p_info->time, f_state->last_timestamp,
|
is_rate_limited(p_info->time, f_state->last_timestamp,
|
||||||
config.use_srtt ? f_state->srtt : f_state->min_rtt))
|
config.use_srtt ? f_state->srtt : f_state->min_rtt))
|
||||||
return;
|
return;
|
||||||
@@ -928,6 +936,7 @@ static void pping_timestamp_packet(struct flow_state *f_state, void *ctx,
|
|||||||
* the next available map slot somewhat fairer between heavy and sparse
|
* the next available map slot somewhat fairer between heavy and sparse
|
||||||
* flows.
|
* flows.
|
||||||
*/
|
*/
|
||||||
|
f_state->has_been_timestamped = true;
|
||||||
f_state->last_timestamp = p_info->time;
|
f_state->last_timestamp = p_info->time;
|
||||||
|
|
||||||
if (bpf_map_update_elem(&packet_ts, &p_info->pid, &p_info->time,
|
if (bpf_map_update_elem(&packet_ts, &p_info->pid, &p_info->time,
|
||||||
@@ -993,15 +1002,14 @@ static void pping_parsed_packet(void *ctx, struct packet_info *p_info)
|
|||||||
{
|
{
|
||||||
struct dual_flow_state *df_state;
|
struct dual_flow_state *df_state;
|
||||||
struct flow_state *fw_flow, *rev_flow;
|
struct flow_state *fw_flow, *rev_flow;
|
||||||
bool new_flow = false;
|
|
||||||
|
|
||||||
df_state = lookup_or_create_dualflow_state(ctx, p_info, &new_flow);
|
df_state = lookup_or_create_dualflow_state(ctx, p_info);
|
||||||
if (!df_state)
|
if (!df_state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fw_flow = get_flowstate_from_packet(df_state, p_info);
|
fw_flow = get_flowstate_from_packet(df_state, p_info);
|
||||||
update_forward_flowstate(p_info, fw_flow, &new_flow);
|
update_forward_flowstate(p_info, fw_flow);
|
||||||
pping_timestamp_packet(fw_flow, ctx, p_info, new_flow);
|
pping_timestamp_packet(fw_flow, ctx, p_info);
|
||||||
|
|
||||||
rev_flow = get_reverse_flowstate_from_packet(df_state, p_info);
|
rev_flow = get_reverse_flowstate_from_packet(df_state, p_info);
|
||||||
update_reverse_flowstate(ctx, p_info, rev_flow);
|
update_reverse_flowstate(ctx, p_info, rev_flow);
|
||||||
|
Reference in New Issue
Block a user