/* // Copyright (c) 2010-2017 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ #ifndef _GENL4_STREAM_H_ #define _GENL4_STREAM_H_ #include "prox_lua_types.h" #include "pkt_parser.h" #include "token_time.h" #include "quit.h" enum tcp_state { CLOSED, LISTEN, SYN_SENT, SYN_RECEIVED, ESTABLISHED, CLOSE_WAIT, LAST_ACK, FIN_WAIT, TIME_WAIT }; static const char *tcp_state_to_str(const enum tcp_state s) { switch(s) { case CLOSED: return "CLOSED"; case LISTEN: return "LISTEN"; case SYN_SENT: return "SYN_SENT"; case SYN_RECEIVED: return "SYN_RECEIVED"; case ESTABLISHED: return "ESTABLISHED"; case CLOSE_WAIT: return "CLOSE_WAIT"; case LAST_ACK: return "LAST_ACK"; case FIN_WAIT: return "FIN_WAIT"; case TIME_WAIT: return "TIME_WAIT"; default: return "INVALID_STATE"; } } #define STREAM_CTX_F_EXPIRED 0x01 #define STREAM_CTX_F_NEW_DATA 0x02 /* Set on recv to track first ACK of data */ #define STREAM_CTX_F_TCP_ENDED 0x04 #define STREAM_CTX_F_TCP_GOT_SYN 0x08 /* Set only once when syn has been received */ #define STREAM_CTX_F_TCP_GOT_FIN 0x10 /* Set only once when fin has been received */ #define STREAM_CTX_F_MORE_DATA 0x20 #define STREAM_CTX_F_LAST_RX_PKT_MADE_PROGRESS 0x40 /* Run-time structure to management state information associated with current stream_cfg. */ struct stream_ctx { enum l4gen_peer peer; uint32_t cur_action; uint32_t cur_pos[2]; enum tcp_state tcp_state; struct token_time token_time; struct token_time token_time_other; uint16_t flags; uint16_t same_state; uint32_t next_seq; uint32_t ackd_seq; uint32_t recv_seq; uint32_t ackable_data_seq; uint32_t seq_first_byte; /* seq number - seq_first_byte gives offset within content. */ uint32_t other_seq_first_byte; /* seq number - seq_first_byte gives offset within content. */ uint32_t other_mss; uint64_t sched_tsc; uint32_t retransmits; const struct stream_cfg *stream_cfg; /* Current active steam_cfg */ struct pkt_tuple *tuple; }; struct host_set { uint32_t ip; uint32_t ip_mask; uint16_t port; uint16_t port_mask; }; struct stream_cfg { struct peer_data data[2]; struct host_set servers; // Current implementation only allows mask == 0. (i.e. single server) struct token_time_cfg tt_cfg[2]; // bytes per period rate uint16_t proto; uint64_t tsc_timeout; uint64_t tsc_timeout_time_wait; uint32_t n_actions; uint32_t n_pkts; uint32_t n_bytes; int (*proc)(struct stream_ctx *meta, struct rte_mbuf *mbuf, struct l4_meta *l4_meta, uint64_t *next_tsc); int (*is_ended)(struct stream_ctx *meta); struct peer_action actions[0]; }; static void scale_for_jitter(uint64_t *to_scale) { (*to_scale) *= 2; } static void reset_token_times(struct stream_ctx *ctx) { const uint64_t now = rte_rdtsc(); const struct stream_cfg *cfg = ctx->stream_cfg; enum l4gen_peer peer = ctx->peer; token_time_init(&ctx->token_time, &cfg->tt_cfg[peer]); token_time_reset_full(&ctx->token_time, now); token_time_init(&ctx->token_time_other, &cfg->tt_cfg[!peer]); scale_for_jitter(&ctx->token_time_other.cfg.bytes_max); token_time_reset_full(&ctx->token_time_other, now); } static void stream_ctx_init(struct stream_ctx *ctx, enum l4gen_peer peer, struct stream_cfg *cfg, struct pkt_tuple *tuple) { ctx->stream_cfg = cfg; ctx->peer = peer; ctx->tuple = tuple; /* Server's initial state is different from client for TCP. For now, don't use a specific init function for TCP/UDP since there is not a lot of difference and to avoid an additional function pointer. */ ctx->tcp_state = PEER_CLIENT == peer? CLOSED : LISTEN; ctx->other_mss = 536; /* default 536 as per RFC 879 */ reset_token_times(ctx); } static void stream_ctx_reset_move(struct stream_ctx *ctx, struct stream_cfg *cfg) { enum l4gen_peer peer = ctx->peer; struct pkt_tuple *tuple = ctx->tuple; memset(ctx, 0, sizeof(*ctx)); stream_ctx_init(ctx, peer, cfg, tuple); } static int stream_cfg_calc_max_payload_len(struct stream_cfg *cfg, enum l4gen_peer peer) { const uint32_t l4_hdr_len = cfg->proto == IPPROTO_UDP? sizeof(struct udp_hdr) : sizeof(struct tcp_hdr); return ETHER_MAX_LEN - ETHER_CRC_LEN - cfg->data[peer].hdr_len - l4_hdr_len; } static int stream_cfg_max_n_segments(struct stream_cfg *cfg) { if (cfg->proto == IPPROTO_UDP) return 1; uint32_t ret = 1; uint32_t cur; const uint32_t mss = stream_cfg_calc_max_payload_len(cfg, PEER_CLIENT); for (uint32_t i = 0; i < cfg->n_actions; ++i) { cur = (cfg->actions[i].len + (mss - 1)) / mss; ret = ret > cur? ret: cur; } return ret; } static int stream_cfg_verify_action(struct stream_cfg *cfg, struct peer_action *action) { if (cfg->proto == IPPROTO_TCP) return 0; uint16_t max_payload_len = stream_cfg_calc_max_payload_len(cfg, action->peer); PROX_PANIC(action->len > max_payload_len, "Action %zu has length %u while for the maximum action length for UDP connections is limited to %u\n", action - cfg->actions, action->len, max_payload_len); return 0; } #endif /* _GENL4_STREAM_H_ */