diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 5293d504b09b0faae8e436b58a821b8ab47648f3..7cdc6de6cadcecea1f49e26f47377ae4ec9d4a66 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -229,7 +229,9 @@ struct tcp_sock { u8 compressed_ack; u8 dup_ack_counter:2, tlp_retrans:1, /* TLP is a retransmission */ - unused:5; + no_comp_tx:1, /* tcp comp tx status */ + no_comp_rx:1, /* tcp comp rx status */ + unused:3; u32 chrono_start; /* Start time in jiffies of a TCP chrono */ u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ u8 chrono_type:2, /* current chronograph type */ diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index 62db78b9c1a0a21963c8cdd61212c0c09ce8a58e..c87ae6a09f4f3de73b14338bee6c876ad53eda1d 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -128,7 +128,8 @@ enum { #define TCP_CM_INQ TCP_INQ #define TCP_TX_DELAY 37 /* delay outgoing packets by XX usec */ - +#define TCP_NO_COMP_TX 38 /* controls whether tcp compression tx is enabled */ +#define TCP_NO_COMP_RX 39 /* controls whether tcp compression rx is enabled */ #define TCP_REPAIR_ON 1 #define TCP_REPAIR_OFF 0 diff --git a/net/core/filter.c b/net/core/filter.c index 51514e41025eada7824efd38121552e2df278742..653dba4893e598ff9674b7d391cdca8f25ed71b8 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4903,6 +4903,20 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname, tp->notsent_lowat = val; sk->sk_write_space(sk); break; +#if IS_ENABLED(CONFIG_TCP_COMP) + case TCP_NO_COMP_TX: + if (val > 1 || val < 0) + ret = -EINVAL; + else + tp->no_comp_tx = val; + break; + case TCP_NO_COMP_RX: + if (val > 1 || val < 0) + ret = -EINVAL; + else + tp->no_comp_rx = val; + break; +#endif default: ret = -EINVAL; } diff --git a/net/ipv4/tcp_comp.c b/net/ipv4/tcp_comp.c index ffddbd6d3a6bc38f346bfc4acd529cdcb9cc016d..f93a27047dba0bd5b198fbf7cb17c1dc327be1df 100644 --- a/net/ipv4/tcp_comp.c +++ b/net/ipv4/tcp_comp.c @@ -24,6 +24,8 @@ unsigned long *sysctl_tcp_compression_ports = tcp_compression_ports; int sysctl_tcp_compression_local __read_mostly; static struct proto tcp_prot_override; +static struct proto tcp_prot_override_send; +static struct proto tcp_prot_override_recv; struct tcp_comp_context_tx { ZSTD_CStream *cstream; @@ -824,13 +826,22 @@ void tcp_init_compression(struct sock *sk) ctx->sk_write_space = sk->sk_write_space; ctx->sk_proto = sk->sk_prot; - WRITE_ONCE(sk->sk_prot, &tcp_prot_override); - sk->sk_write_space = tcp_comp_write_space; + + if (!tp->no_comp_tx && !tp->no_comp_rx) + WRITE_ONCE(sk->sk_prot, &tcp_prot_override); + else if (!tp->no_comp_tx) + WRITE_ONCE(sk->sk_prot, &tcp_prot_override_send); + else if (!tp->no_comp_rx) + WRITE_ONCE(sk->sk_prot, &tcp_prot_override_recv); + + if (!tp->no_comp_tx) + sk->sk_write_space = tcp_comp_write_space; rcu_assign_pointer(icsk->icsk_ulp_data, ctx); sock_set_flag(sk, SOCK_COMP); - comp_setup_strp(sk, ctx); + if (!tp->no_comp_rx) + comp_setup_strp(sk, ctx); } static void tcp_comp_context_tx_free(struct tcp_comp_context *ctx) @@ -896,5 +907,12 @@ int tcp_comp_init(void) tcp_prot_override.recvmsg = tcp_comp_recvmsg; tcp_prot_override.stream_memory_read = comp_stream_read; + tcp_prot_override_send = tcp_prot; + tcp_prot_override_send.sendmsg = tcp_comp_sendmsg; + + tcp_prot_override_recv = tcp_prot; + tcp_prot_override_recv.recvmsg = tcp_comp_recvmsg; + tcp_prot_override_recv.stream_memory_read = comp_stream_read; + return 0; } diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index aeebf5d12f32c09f7782e5f406fa715104ef7ac9..1e325dc1fd81c12557939a74896ace654079fb0f 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -153,6 +153,7 @@ always-y += tcp_bufs_kern.o always-y += tcp_cong_kern.o always-y += tcp_iw_kern.o always-y += tcp_clamp_kern.o +always-y += tcp_comp_option_kern.o always-y += tcp_basertt_kern.o always-y += tcp_tos_reflect_kern.o always-y += tcp_dumpstats_kern.o diff --git a/samples/bpf/tcp_comp_option.h b/samples/bpf/tcp_comp_option.h new file mode 100644 index 0000000000000000000000000000000000000000..f7ebd1b22afabe607a336f97e142a3e38b4d563d --- /dev/null +++ b/samples/bpf/tcp_comp_option.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2022 sunshouxun */ + +#ifndef _BPF_TCP_COMP_H +#define _BPF_TCP_COMP_H + +struct bpf_comp_option { + __u8 flags; + __u8 no_comp_tx; + __u8 no_comp_rx; +} __attribute__((packed)); + +enum { + OPTION_RESEND, + OPTION_NO_COMP_TX, + OPTION_NO_COMP_RX, + __NR_OPTION_FLAGS, +}; + +#define OPTION_F_RESEND (1 << OPTION_RESEND) +#define OPTION_F_NO_COMP_TX (1 << OPTION_NO_COMP_TX) +#define OPTION_F_NO_COMP_RX (1 << OPTION_NO_COMP_RX) +#define OPTION_MASK ((1 << __NR_OPTION_FLAGS) - 1) + +#define TEST_OPTION_FLAGS(flags, option) (1 & ((flags) >> (option))) +#define SET_OPTION_FLAGS(flags, option) ((flags) |= (1 << (option))) + +/* Store in bpf_sk_storage */ +struct hdr_stg { + bool active; + bool resend_syn; /* active side only */ + bool syncookie; /* passive side only */ + bool fastopen; /* passive side only */ +}; + +struct linum_err { + unsigned int linum; + int err; +}; + +#define TCPHDR_FIN 0x01 +#define TCPHDR_SYN 0x02 +#define TCPHDR_RST 0x04 +#define TCPHDR_PSH 0x08 +#define TCPHDR_ACK 0x10 +#define TCPHDR_URG 0x20 +#define TCPHDR_ECE 0x40 +#define TCPHDR_CWR 0x80 +#define TCPHDR_SYNACK (TCPHDR_SYN | TCPHDR_ACK) + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_WINDOW 3 +#define TCPOPT_EXP 254 + +#define TCP_BPF_EXPOPT_BASE_LEN 4 +#define MAX_TCP_HDR_LEN 60 +#define MAX_TCP_OPTION_SPACE 40 + +#ifdef BPF_PROG_TCP_COMP + +#define CG_OK 1 +#define CG_ERR 0 + +#ifndef SOL_TCP +#define SOL_TCP 6 +#endif + +struct tcp_exprm_opt { + __u8 kind; + __u8 len; + __u16 magic; + union { + __u8 data[4]; + __u32 data32; + }; +} __attribute__((packed)); + +struct tcp_opt { + __u8 kind; + __u8 len; + union { + __u8 data[4]; + __u32 data32; + }; +} __attribute__((packed)); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 2); + __type(key, int); + __type(value, struct linum_err); +} lport_linum_map SEC(".maps"); + +static inline unsigned int tcp_hdrlen(const struct tcphdr *th) +{ + return th->doff << 2; +} + +static inline __u8 skops_tcp_flags(const struct bpf_sock_ops *skops) +{ + return skops->skb_tcp_flags; +} + +static inline void clear_hdr_cb_flags(struct bpf_sock_ops *skops) +{ + bpf_sock_ops_cb_flags_set(skops, + skops->bpf_sock_ops_cb_flags & + ~(BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG | + BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG)); +} + +static inline void set_hdr_cb_flags(struct bpf_sock_ops *skops, __u32 extra) +{ + bpf_sock_ops_cb_flags_set(skops, + skops->bpf_sock_ops_cb_flags | + BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG | + BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG | + extra); +} +static inline void +clear_parse_all_hdr_cb_flags(struct bpf_sock_ops *skops) +{ + bpf_sock_ops_cb_flags_set(skops, + skops->bpf_sock_ops_cb_flags & + ~BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG); +} + +static inline void +set_parse_all_hdr_cb_flags(struct bpf_sock_ops *skops) +{ + bpf_sock_ops_cb_flags_set(skops, + skops->bpf_sock_ops_cb_flags | + BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG); +} + +#define RET_CG_ERR(__err) ({ \ + struct linum_err __linum_err; \ + int __lport; \ + \ + __linum_err.linum = __LINE__; \ + __linum_err.err = __err; \ + __lport = skops->local_port; \ + bpf_map_update_elem(&lport_linum_map, &__lport, &__linum_err, BPF_NOEXIST); \ + clear_hdr_cb_flags(skops); \ + clear_parse_all_hdr_cb_flags(skops); \ + return CG_ERR; \ +}) + +#endif /* BPF_PROG_TCP_COMP */ + +#endif /* _BPF_TCP_COMP_H */ \ No newline at end of file diff --git a/samples/bpf/tcp_comp_option_kern.c b/samples/bpf/tcp_comp_option_kern.c new file mode 100644 index 0000000000000000000000000000000000000000..c30adcd42a8fdf59ba8c90f5f7289ca9f5135f7f --- /dev/null +++ b/samples/bpf/tcp_comp_option_kern.c @@ -0,0 +1,534 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2022 sunshouxun */ + +#include +#include +#include +#include +#include +#define BPF_PROG_TCP_COMP +#include "tcp_comp_option.h" + +#ifndef sizeof_field +#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) +#endif + +__u8 option_kind = TCPOPT_EXP; +__u16 option_magic = 0xeB9F; + +int port = 1234; + +static struct bpf_comp_option passive_synack_out = { + .flags = 6, + .no_comp_tx = 1, + .no_comp_rx = 1, +}; + +static struct bpf_comp_option active_syn_out = { + .flags = 6, + .no_comp_tx = 1, + .no_comp_rx = 1, +}; + +struct { + __uint(type, BPF_MAP_TYPE_SK_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, int); + __type(value, struct hdr_stg); +} hdr_stg_map SEC(".maps"); + +static bool skops_want_cookie(const struct bpf_sock_ops *skops) +{ + return skops->args[0] == BPF_WRITE_HDR_TCP_SYNACK_COOKIE; +} + +static __u8 option_total_len(__u8 flags) +{ + __u8 i, len = 1; /* +1 for flags */ + + if (!flags) + return 0; + + /* RESEND bit does not use a byte */ + for (i = OPTION_RESEND + 1; i < __NR_OPTION_FLAGS; i++) + len += !!TEST_OPTION_FLAGS(flags, i); + + if (option_kind == TCPOPT_EXP) + return len + TCP_BPF_EXPOPT_BASE_LEN; + else + return len + 2; /* +1 kind, +1 kind-len */ +} + +static void write_comp_option(const struct bpf_comp_option *comp_opt, + __u8 *data) +{ + __u8 offset = 0; + + data[offset++] = comp_opt->flags; + if (TEST_OPTION_FLAGS(comp_opt->flags, OPTION_NO_COMP_TX)){ + data[offset++] = comp_opt->no_comp_tx; + } + + if (TEST_OPTION_FLAGS(comp_opt->flags, OPTION_NO_COMP_RX)){ + data[offset++] = comp_opt->no_comp_rx; + } +} + +static int store_option(struct bpf_sock_ops *skops, + const struct bpf_comp_option *comp_opt) +{ + union { + struct tcp_exprm_opt exprm; + struct tcp_opt regular; + } write_opt; + int err; + + if (option_kind == TCPOPT_EXP) { + write_opt.exprm.kind = TCPOPT_EXP; + write_opt.exprm.len = option_total_len(comp_opt->flags); + write_opt.exprm.magic = __bpf_htons(option_magic); + write_opt.exprm.data32 = 0; + write_comp_option(comp_opt, write_opt.exprm.data); + err = bpf_store_hdr_opt(skops, &write_opt.exprm, + sizeof(write_opt.exprm), 0); + } else { + write_opt.regular.kind = option_kind; + write_opt.regular.len = option_total_len(comp_opt->flags); + write_opt.regular.data32 = 0; + write_comp_option(comp_opt, write_opt.regular.data); + err = bpf_store_hdr_opt(skops, &write_opt.regular, + sizeof(write_opt.regular), 0); + } + + if (err) + RET_CG_ERR(err); + + return CG_OK; +} + +static int parse_comp_option(struct bpf_comp_option *opt, const __u8 *start) +{ + opt->flags = *start++; + + + if (TEST_OPTION_FLAGS(opt->flags, OPTION_NO_COMP_TX)) + opt->no_comp_tx = *start++; + + if (TEST_OPTION_FLAGS(opt->flags, OPTION_NO_COMP_RX)) + opt->no_comp_rx = *start++; + + return 0; +} + +static int load_option(struct bpf_sock_ops *skops, + struct bpf_comp_option *comp_opt, bool from_syn) +{ + union { + struct tcp_exprm_opt exprm; + struct tcp_opt regular; + } search_opt; + int ret, load_flags = from_syn ? BPF_LOAD_HDR_OPT_TCP_SYN : 0; + + if (option_kind == TCPOPT_EXP) { + search_opt.exprm.kind = TCPOPT_EXP; + search_opt.exprm.len = 4; + search_opt.exprm.magic = __bpf_htons(option_magic); + search_opt.exprm.data32 = 0; + ret = bpf_load_hdr_opt(skops, &search_opt.exprm, + sizeof(search_opt.exprm), load_flags); + if (ret < 0) + return ret; + return parse_comp_option(comp_opt, search_opt.exprm.data); + } else { + search_opt.regular.kind = option_kind; + search_opt.regular.len = 0; + search_opt.regular.data32 = 0; + ret = bpf_load_hdr_opt(skops, &search_opt.regular, + sizeof(search_opt.regular), load_flags); + if (ret < 0) + return ret; + return parse_comp_option(comp_opt, search_opt.regular.data); + } +} + +static int synack_opt_len(struct bpf_sock_ops *skops) +{ + struct bpf_comp_option comp_opt = {}; + __u8 optlen; + int err; + + if (!passive_synack_out.flags) + return CG_OK; + + err = load_option(skops, &comp_opt, true); + + /* bpf_comp_option is not found */ + if (err) + RET_CG_ERR(err); + + optlen = option_total_len(passive_synack_out.flags); + if (optlen) { + err = bpf_reserve_hdr_opt(skops, optlen, 0); + if (err) + RET_CG_ERR(err); + } + + return CG_OK; +} + +static int write_synack_opt(struct bpf_sock_ops *skops) +{ + struct bpf_comp_option opt; + + if (!passive_synack_out.flags) + /* We should not even be called since no header + * space has been reserved. + */ + RET_CG_ERR(0); + + opt = passive_synack_out; + if (skops_want_cookie(skops)) + SET_OPTION_FLAGS(opt.flags, OPTION_RESEND); + + return store_option(skops, &opt); +} + +static int syn_opt_len(struct bpf_sock_ops *skops) +{ + __u8 optlen; + int err; + + if (!active_syn_out.flags) + return CG_OK; + + optlen = option_total_len(active_syn_out.flags); + if (optlen) { + err = bpf_reserve_hdr_opt(skops, optlen, 0); + if (err) + RET_CG_ERR(err); + } + + return CG_OK; +} + +static int write_syn_opt(struct bpf_sock_ops *skops) +{ + if (!active_syn_out.flags) + RET_CG_ERR(0); + + return store_option(skops, &active_syn_out); +} + +static int resend_in_ack(struct bpf_sock_ops *skops) +{ + struct hdr_stg *hdr_stg; + + if (!skops->sk) + return -1; + + hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0); + if (!hdr_stg) + return -1; + + return !!hdr_stg->resend_syn; +} + +static int nodata_opt_len(struct bpf_sock_ops *skops) +{ + int resend; + + resend = resend_in_ack(skops); + if (resend < 0) + RET_CG_ERR(0); + + if (resend) + return syn_opt_len(skops); + + return CG_OK; +} + +static int write_nodata_opt(struct bpf_sock_ops *skops) +{ + int resend; + + resend = resend_in_ack(skops); + if (resend < 0) + RET_CG_ERR(0); + + if (resend) + return write_syn_opt(skops); + + return CG_OK; +} + +static int data_opt_len(struct bpf_sock_ops *skops) +{ + /* Same as the nodata version. Mostly to show + * an example usage on skops->skb_len. + */ + return nodata_opt_len(skops); +} + +static int write_data_opt(struct bpf_sock_ops *skops) +{ + return write_nodata_opt(skops); +} + +static int handle_hdr_opt_len(struct bpf_sock_ops *skops) +{ + __u8 tcp_flags = skops_tcp_flags(skops); + + if ((tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK) + return synack_opt_len(skops); + + if (tcp_flags & TCPHDR_SYN) + return syn_opt_len(skops); + + if (skops->skb_len) + return data_opt_len(skops); + + return nodata_opt_len(skops); +} + +static int handle_write_hdr_opt(struct bpf_sock_ops *skops) +{ + __u8 tcp_flags = skops_tcp_flags(skops); + struct tcphdr *th; + + if ((tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK) + return write_synack_opt(skops); + + if (tcp_flags & TCPHDR_SYN) + return write_syn_opt(skops); + + th = skops->skb_data; + if (th + 1 > skops->skb_data_end) + RET_CG_ERR(0); + + if (skops->skb_len > tcp_hdrlen(th)) + return write_data_opt(skops); + + return write_nodata_opt(skops); +} + +static int set_no_comp_tx(struct bpf_sock_ops *skops, __u32 no_comp_tx) +{ + return bpf_setsockopt(skops, SOL_TCP, TCP_NO_COMP_TX, + &no_comp_tx, sizeof(no_comp_tx)); +} + + +static int set_no_comp_rx(struct bpf_sock_ops *skops, __u32 no_comp_rx) +{ + return bpf_setsockopt(skops, SOL_TCP, TCP_NO_COMP_RX, + &no_comp_rx, sizeof(no_comp_rx)); +} + +// client side +static int handle_active_estab(struct bpf_sock_ops *skops) +{ + struct hdr_stg init_stg = { + .active = true, + }; + + struct bpf_comp_option active_estab_in = {}; + int err; + + err = load_option(skops, &active_estab_in, false); + if (err) + RET_CG_ERR(err); + + init_stg.resend_syn = TEST_OPTION_FLAGS(active_estab_in.flags, + OPTION_RESEND); + if (!skops->sk || !bpf_sk_storage_get(&hdr_stg_map, skops->sk, + &init_stg, + BPF_SK_STORAGE_GET_F_CREATE)) + RET_CG_ERR(0); + + if (init_stg.resend_syn) + /* Don't clear the write_hdr cb now because + * the ACK may get lost and retransmit may + * be needed. + * + * PARSE_ALL_HDR cb flag is set to learn if this + * resend_syn option has received by the peer. + * + * The header option will be resent until a valid + * packet is received at handle_parse_hdr() + * and all hdr cb flags will be cleared in + * handle_parse_hdr(). + */ + set_parse_all_hdr_cb_flags(skops); + else + /* No options will be written from now */ + clear_hdr_cb_flags(skops); + + // use map data + if (active_syn_out.no_comp_tx == 1 && active_estab_in.no_comp_rx == 1) { + err = set_no_comp_tx(skops, active_syn_out.no_comp_tx); + if (err) + RET_CG_ERR(err); + } + + if (active_syn_out.no_comp_rx == 1 && active_estab_in.no_comp_tx == 1) { + err = set_no_comp_rx(skops, active_syn_out.no_comp_rx); + if (err) + RET_CG_ERR(err); + } + + return CG_OK; +} + +// server side +static int handle_passive_estab(struct bpf_sock_ops *skops) +{ + struct hdr_stg init_stg = {}; + struct bpf_comp_option passive_estab_in = {}; + struct tcphdr *th; + + int err; + + err = load_option(skops, &passive_estab_in, true); + + if (err == -2) { + /* -2 is No such file or directory + * saved_syn is not found. It was in syncookie mode. + * We have asked the active side to resend the options + * in ACK, so try to find the bpf_comp_option from ACK now. + */ + err = load_option(skops, &passive_estab_in, false); + init_stg.syncookie = true; + } + + /* ENOMSG: The bpf_comp_option is not found which is fine. + * Bail out now for all other errors. + */ + if (err) + RET_CG_ERR(err); + + th = skops->skb_data; + if (th + 1 > skops->skb_data_end) + RET_CG_ERR(0); + + if (th->syn) { + /* Fastopen */ + + /* Cannot clear cb_flags to stop write_hdr cb. + * synack is not sent yet for fast open. + * Even it was, the synack may need to be retransmitted. + * + * PARSE_ALL_HDR cb flag is set to learn + * if synack has reached the peer. + * All cb_flags will be cleared in handle_parse_hdr(). + */ + set_parse_all_hdr_cb_flags(skops); + init_stg.fastopen = true; + } else { + /* No options will be written from now */ + clear_hdr_cb_flags(skops); + } + + if (!skops->sk || + !bpf_sk_storage_get(&hdr_stg_map, skops->sk, &init_stg, + BPF_SK_STORAGE_GET_F_CREATE)) + RET_CG_ERR(0); + + + if (passive_synack_out.no_comp_tx == 1 && passive_estab_in.no_comp_rx == 1) { + err = set_no_comp_tx(skops, passive_synack_out.no_comp_tx); + if (err) + RET_CG_ERR(err); + } + + if (passive_synack_out.no_comp_rx == 1 && passive_estab_in.no_comp_tx == 1) { + err = set_no_comp_rx(skops, passive_synack_out.no_comp_rx); + if (err) + RET_CG_ERR(err); + } + + return CG_OK; +} + +static int handle_parse_hdr(struct bpf_sock_ops *skops) +{ + struct hdr_stg *hdr_stg; + struct tcphdr *th; + + if (!skops->sk) + RET_CG_ERR(0); + + th = skops->skb_data; + if (th + 1 > skops->skb_data_end) + RET_CG_ERR(0); + + hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0); + if (!hdr_stg) + RET_CG_ERR(0); + + if (hdr_stg->resend_syn || hdr_stg->fastopen) { + /* The PARSE_ALL_HDR cb flag was turned on + * to ensure that the previously written + * options have reached the peer. + * Those previously written option includes: + * - Active side: resend_syn in ACK during syncookie + * or + * - Passive side: SYNACK during fastopen + * + * A valid packet has been received here after + * the 3WHS, so the PARSE_ALL_HDR cb flag + * can be cleared now. + */ + clear_parse_all_hdr_cb_flags(skops); + + /* Active side resent the syn option in ACK + * because the server was in syncookie mode. + * A valid packet has been received, so + * the SYNACK has reached the peer. + * Clear header cb flags if there is no more + * option to send. + * + * or + * + * Passive side was in fastopen. + * A valid packet has been received, so + * clear header cb flags if there is no + * more option to send. + */ + clear_hdr_cb_flags(skops); + } + + return CG_OK; +} + +SEC("sockops") +int bpf_tcp_comp_option(struct bpf_sock_ops *skops) +{ + int true_val = 1; + if(port != bpf_ntohl(skops->remote_port) && port != skops->local_port) { + return 0; + } + switch (skops->op) { + case BPF_SOCK_OPS_TCP_LISTEN_CB: + bpf_setsockopt(skops, SOL_TCP, TCP_SAVE_SYN, + &true_val, sizeof(true_val)); + set_hdr_cb_flags(skops, BPF_SOCK_OPS_STATE_CB_FLAG); + break; + case BPF_SOCK_OPS_TCP_CONNECT_CB: + set_hdr_cb_flags(skops, 0); + break; + case BPF_SOCK_OPS_PARSE_HDR_OPT_CB: + return handle_parse_hdr(skops); + case BPF_SOCK_OPS_HDR_OPT_LEN_CB: + return handle_hdr_opt_len(skops); + case BPF_SOCK_OPS_WRITE_HDR_OPT_CB: + return handle_write_hdr_opt(skops); + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: + return handle_passive_estab(skops); + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: + return handle_active_estab(skops); + } + + return CG_OK; +} + +char _license[] SEC("license") = "GPL"; \ No newline at end of file