refactor: IP reassembly and rename stat name
This commit is contained in:
@@ -78,7 +78,7 @@ struct ip_frag_hdr
|
||||
uint8_t next_proto;
|
||||
};
|
||||
|
||||
struct ip_frag_pkt
|
||||
struct ip_frag
|
||||
{
|
||||
void *data; // need be freed
|
||||
uint16_t len;
|
||||
@@ -86,7 +86,7 @@ struct ip_frag_pkt
|
||||
uint16_t offset;
|
||||
};
|
||||
|
||||
struct ip_flow_key
|
||||
struct ip_frag_key
|
||||
{
|
||||
uint64_t src_dst_addr[4]; // src and dst address (only first 8 bytes used for IPv4)
|
||||
uint32_t src_dst_len;
|
||||
@@ -94,20 +94,20 @@ struct ip_flow_key
|
||||
uint8_t proto;
|
||||
};
|
||||
|
||||
struct ip_flow
|
||||
struct ip_frag_pkt
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct ip_flow *tqe_next;
|
||||
struct ip_flow **tqe_prev;
|
||||
struct ip_frag_pkt *tqe_next;
|
||||
struct ip_frag_pkt **tqe_prev;
|
||||
} lru;
|
||||
struct ip_flow_key key;
|
||||
struct ip_frag_key key;
|
||||
struct ip_frag_hdr hdr;
|
||||
uint64_t create_time;
|
||||
uint32_t expected_total_size;
|
||||
uint32_t received_frag_size;
|
||||
uint32_t next_fill_idx;
|
||||
struct ip_frag_pkt frags[IP_MAX_FRAG_NUM]; // first two entries in the frags[] array are for the last and first fragments.
|
||||
struct ip_frag frags[IP_MAX_FRAG_NUM]; // first two entries in the frags[] array are for the last and first fragments.
|
||||
};
|
||||
|
||||
struct ip_reassembly
|
||||
@@ -128,26 +128,26 @@ struct ip_reassembly
|
||||
// hash table
|
||||
struct
|
||||
{
|
||||
struct ip_flow *tqh_first;
|
||||
struct ip_flow **tqh_last;
|
||||
struct ip_frag_pkt *tqh_first;
|
||||
struct ip_frag_pkt **tqh_last;
|
||||
} lru;
|
||||
struct ip_flow *last;
|
||||
struct ip_flow *table; // array of ip_flow
|
||||
struct ip_frag_pkt *last;
|
||||
struct ip_frag_pkt *table; // array of ip_frag_pkt
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* utils
|
||||
******************************************************************************/
|
||||
|
||||
#define ip_reassembly_stat_inc(assy, filed, key) \
|
||||
#define IP_REASSEMBLY_STAT_INC(stat, filed, key) \
|
||||
{ \
|
||||
if ((key)->src_dst_len == IPV4_KEYLEN) \
|
||||
{ \
|
||||
(assy)->stat.ip4_flow_##filed++; \
|
||||
(stat)->ip4_##filed++; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
(assy)->stat.ip6_flow_##filed++; \
|
||||
(stat)->ip6_##filed++; \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -223,10 +223,10 @@ static int check_options(const struct ip_reassembly_options *opts)
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ip flow key
|
||||
* ip frag key
|
||||
******************************************************************************/
|
||||
|
||||
static inline void ipv4_flow_key_hash(const struct ip_flow_key *key, uint32_t *value1, uint32_t *value2)
|
||||
static inline void ipv4_frag_key_hash(const struct ip_frag_key *key, uint32_t *value1, uint32_t *value2)
|
||||
{
|
||||
uint32_t v = 0;
|
||||
const uint32_t *p = (const uint32_t *)&key->src_dst_addr;
|
||||
@@ -239,7 +239,7 @@ static inline void ipv4_flow_key_hash(const struct ip_flow_key *key, uint32_t *v
|
||||
*value2 = (v << 7) + (v >> 14);
|
||||
}
|
||||
|
||||
static inline void ipv6_flow_key_hash(const struct ip_flow_key *key, uint32_t *value1, uint32_t *value2)
|
||||
static inline void ipv6_frag_key_hash(const struct ip_frag_key *key, uint32_t *value1, uint32_t *value2)
|
||||
{
|
||||
uint32_t v = 0;
|
||||
const uint32_t *p = (const uint32_t *)&key->src_dst_addr;
|
||||
@@ -258,7 +258,7 @@ static inline void ipv6_flow_key_hash(const struct ip_flow_key *key, uint32_t *v
|
||||
*value2 = (v << 7) + (v >> 14);
|
||||
}
|
||||
|
||||
static inline uint64_t ip_flow_key_cmp(const struct ip_flow_key *key1, const struct ip_flow_key *key2)
|
||||
static inline uint64_t ip_frag_key_cmp(const struct ip_frag_key *key1, const struct ip_frag_key *key2)
|
||||
{
|
||||
if (key1->ip_id != key2->ip_id)
|
||||
{
|
||||
@@ -281,12 +281,12 @@ static inline uint64_t ip_flow_key_cmp(const struct ip_flow_key *key1, const str
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ip_flow_key_is_empty(const struct ip_flow_key *key)
|
||||
static inline int ip_frag_key_is_empty(const struct ip_frag_key *key)
|
||||
{
|
||||
return (key->src_dst_len == 0);
|
||||
}
|
||||
|
||||
static inline void ip_flow_key_zero(struct ip_flow_key *key)
|
||||
static inline void ip_frag_key_zero(struct ip_frag_key *key)
|
||||
{
|
||||
key->src_dst_addr[0] = 0;
|
||||
key->src_dst_addr[1] = 0;
|
||||
@@ -339,78 +339,100 @@ static inline void ip_frag_hdr_free(struct ip_frag_hdr *hdr)
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ip frag pkt
|
||||
* ip frag
|
||||
******************************************************************************/
|
||||
|
||||
static inline void ip_frag_pkt_init(struct ip_frag_pkt *frag, void *data, uint16_t len, uint16_t offset)
|
||||
static inline void ip_frag_init(struct ip_frag *frag, void *data, uint16_t len, uint16_t offset)
|
||||
{
|
||||
frag->data = memdup(data, len);
|
||||
frag->len = len;
|
||||
frag->offset = offset;
|
||||
}
|
||||
|
||||
static inline void ip_frag_pkt_free(struct ip_frag_pkt *frag)
|
||||
static inline int ip_frag_free(struct ip_frag *frag)
|
||||
{
|
||||
int ret = -1;
|
||||
if (frag)
|
||||
{
|
||||
if (frag->data)
|
||||
{
|
||||
free(frag->data);
|
||||
frag->data = NULL;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
frag->len = 0;
|
||||
frag->offset = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ip flow
|
||||
* ip frag pkt
|
||||
******************************************************************************/
|
||||
|
||||
static inline void ip_flow_init(struct ip_flow *flow, const struct ip_flow_key *key, uint64_t now)
|
||||
static inline void ip_frag_pkt_init(struct ip_frag_pkt *frag_pkt, const struct ip_frag_key *key, uint64_t now)
|
||||
{
|
||||
static const struct ip_frag_pkt zero_frag = {
|
||||
static const struct ip_frag zero_frag = {
|
||||
.data = NULL,
|
||||
.len = 0,
|
||||
.offset = 0,
|
||||
};
|
||||
|
||||
flow->lru.tqe_next = NULL;
|
||||
flow->lru.tqe_prev = NULL;
|
||||
flow->key = *key;
|
||||
flow->create_time = now;
|
||||
flow->expected_total_size = UINT32_MAX;
|
||||
flow->received_frag_size = 0;
|
||||
flow->next_fill_idx = IP_MIN_FRAG_NUM;
|
||||
flow->frags[IP_LAST_FRAG_IDX] = zero_frag;
|
||||
flow->frags[IP_FIRST_FRAG_IDX] = zero_frag;
|
||||
frag_pkt->lru.tqe_next = NULL;
|
||||
frag_pkt->lru.tqe_prev = NULL;
|
||||
frag_pkt->key = *key;
|
||||
frag_pkt->create_time = now;
|
||||
frag_pkt->expected_total_size = UINT32_MAX;
|
||||
frag_pkt->received_frag_size = 0;
|
||||
|
||||
frag_pkt->next_fill_idx = IP_MIN_FRAG_NUM;
|
||||
frag_pkt->frags[IP_LAST_FRAG_IDX] = zero_frag;
|
||||
frag_pkt->frags[IP_FIRST_FRAG_IDX] = zero_frag;
|
||||
}
|
||||
|
||||
static inline void ip_flow_free(struct ip_flow *flow)
|
||||
static inline void ip_frag_pkt_clean(struct ip_reassembly_stat *stat, struct ip_frag_pkt *frag_pkt)
|
||||
{
|
||||
for (uint32_t i = 0; i < IP_MAX_FRAG_NUM; i++)
|
||||
{
|
||||
struct ip_frag_pkt *frag = &flow->frags[i];
|
||||
ip_frag_pkt_free(frag);
|
||||
struct ip_frag *frag = &frag_pkt->frags[i];
|
||||
if (ip_frag_free(frag) == 0)
|
||||
{
|
||||
IP_REASSEMBLY_STAT_INC(stat, frags_freed, &frag_pkt->key);
|
||||
}
|
||||
}
|
||||
ip_flow_key_zero(&flow->key);
|
||||
ip_frag_hdr_free(&flow->hdr);
|
||||
ip_frag_key_zero(&frag_pkt->key);
|
||||
ip_frag_hdr_free(&frag_pkt->hdr);
|
||||
}
|
||||
|
||||
static inline int ip_flow_is_ready(struct ip_flow *flow)
|
||||
static inline int ip_frag_pkt_is_ready(struct ip_frag_pkt *frag_pkt)
|
||||
{
|
||||
return (flow->received_frag_size == flow->expected_total_size && flow->frags[IP_FIRST_FRAG_IDX].data != NULL);
|
||||
return (frag_pkt->received_frag_size == frag_pkt->expected_total_size && frag_pkt->frags[IP_FIRST_FRAG_IDX].data != NULL);
|
||||
}
|
||||
|
||||
static inline void ip_reassembly_add_frag_pkt(struct ip_reassembly *assy, struct ip_frag_pkt *frag_pkt, const struct ip_frag_key *key, uint64_t now)
|
||||
{
|
||||
ip_frag_pkt_init(frag_pkt, key, now);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, defrags_expected, &frag_pkt->key);
|
||||
TAILQ_INSERT_TAIL(&assy->lru, frag_pkt, lru);
|
||||
assy->entry_used++;
|
||||
}
|
||||
|
||||
static inline void ip_reassembly_del_frag_pkt(struct ip_reassembly *assy, struct ip_frag_pkt *frag_pkt)
|
||||
{
|
||||
TAILQ_REMOVE(&assy->lru, frag_pkt, lru);
|
||||
assy->entry_used--;
|
||||
ip_frag_pkt_clean(&assy->stat, frag_pkt);
|
||||
}
|
||||
|
||||
// return 0 : success
|
||||
// return -1 : failed
|
||||
static inline int ip_flow_update(struct ip_reassembly *assy,
|
||||
struct ip_flow *flow, const struct packet *pkt,
|
||||
char *frag_data, uint16_t frag_len, uint16_t frag_offset, bool more_frags)
|
||||
static inline int ip_frag_pkt_update(struct ip_reassembly *assy,
|
||||
struct ip_frag_pkt *frag_pkt, const struct packet *pkt,
|
||||
char *frag_data, uint16_t frag_len, uint16_t frag_offset, bool more_frags)
|
||||
{
|
||||
uint32_t idx;
|
||||
struct ip_frag_pkt *frag_pkt;
|
||||
/*
|
||||
* Internet Protocol, Version 6 (IPv6) Specification
|
||||
*
|
||||
@@ -424,81 +446,55 @@ static inline int ip_flow_update(struct ip_reassembly *assy,
|
||||
*/
|
||||
if (frag_offset == 0)
|
||||
{
|
||||
if (flow->frags[IP_FIRST_FRAG_IDX].data != NULL)
|
||||
if (frag_pkt->frags[IP_FIRST_FRAG_IDX].data != NULL)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG1("duplicate first fragment bypass", &flow->key);
|
||||
ip_reassembly_stat_inc(assy, bypass_dup_fist_frag, &flow->key);
|
||||
IP_REASSEMBLE_DEBUG1("duplicate first fragment bypass", &frag_pkt->key);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, frags_bypass_dup_fist_frag, &frag_pkt->key);
|
||||
return 0;
|
||||
}
|
||||
idx = IP_FIRST_FRAG_IDX;
|
||||
ip_frag_hdr_init(&flow->hdr, pkt);
|
||||
ip_frag_hdr_init(&frag_pkt->hdr, pkt);
|
||||
}
|
||||
else if (more_frags == 0)
|
||||
{
|
||||
if (flow->frags[IP_LAST_FRAG_IDX].data != NULL)
|
||||
if (frag_pkt->frags[IP_LAST_FRAG_IDX].data != NULL)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG1("duplicate last fragment bypass", &flow->key);
|
||||
ip_reassembly_stat_inc(assy, bypass_dup_last_frag, &flow->key);
|
||||
IP_REASSEMBLE_DEBUG1("duplicate last fragment bypass", &frag_pkt->key);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, frags_bypass_dup_last_frag, &frag_pkt->key);
|
||||
return 0;
|
||||
}
|
||||
idx = IP_LAST_FRAG_IDX;
|
||||
flow->expected_total_size = frag_offset + frag_len;
|
||||
frag_pkt->expected_total_size = frag_offset + frag_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flow->next_fill_idx >= IP_MAX_FRAG_NUM)
|
||||
if (frag_pkt->next_fill_idx >= IP_MAX_FRAG_NUM)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR1("max number of fragment exceeded", &flow->key);
|
||||
ip_reassembly_stat_inc(assy, fail_many_frag, &flow->key);
|
||||
IP_REASSEMBLE_ERROR1("max number of fragment exceeded", &frag_pkt->key);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, defrags_failed_too_many_frag, &frag_pkt->key);
|
||||
ip_reassembly_del_frag_pkt(assy, frag_pkt);
|
||||
return -1;
|
||||
}
|
||||
idx = flow->next_fill_idx;
|
||||
flow->next_fill_idx++;
|
||||
idx = frag_pkt->next_fill_idx;
|
||||
frag_pkt->next_fill_idx++;
|
||||
}
|
||||
|
||||
flow->received_frag_size += frag_len;
|
||||
frag_pkt = &flow->frags[idx];
|
||||
ip_frag_pkt_init(frag_pkt, frag_data, frag_len, frag_offset);
|
||||
frag_pkt->received_frag_size += frag_len;
|
||||
struct ip_frag *frag = &frag_pkt->frags[idx];
|
||||
ip_frag_init(frag, frag_data, frag_len, frag_offset);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, frags_buffered, &frag_pkt->key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ip reassemble manager add/del/reuse/find/update flow
|
||||
******************************************************************************/
|
||||
|
||||
static inline void ip_reassembly_add_flow(struct ip_reassembly *assy, struct ip_flow *flow)
|
||||
{
|
||||
ip_reassembly_stat_inc(assy, add, &flow->key);
|
||||
TAILQ_INSERT_TAIL(&assy->lru, flow, lru);
|
||||
assy->entry_used++;
|
||||
}
|
||||
|
||||
static inline void ip_reassembly_del_flow(struct ip_reassembly *assy, struct ip_flow *flow)
|
||||
{
|
||||
ip_reassembly_stat_inc(assy, del, &flow->key);
|
||||
TAILQ_REMOVE(&assy->lru, flow, lru);
|
||||
assy->entry_used--;
|
||||
}
|
||||
|
||||
static inline void ip_reassembly_reuse_flow(struct ip_reassembly *assy, struct ip_flow *flow, const struct ip_flow_key *key, uint64_t now)
|
||||
{
|
||||
ip_reassembly_del_flow(assy, flow);
|
||||
ip_flow_free(flow);
|
||||
ip_flow_init(flow, key, now);
|
||||
ip_reassembly_add_flow(assy, flow);
|
||||
}
|
||||
|
||||
/*
|
||||
* if return NULL, then *free and *expired are valid
|
||||
* free : the first empty entry in the bucket
|
||||
* expired: the first timed-out entry in the bucket
|
||||
*/
|
||||
static struct ip_flow *ip_reassembly_find_flow(struct ip_reassembly *assy, const struct ip_flow_key *key, struct ip_flow **free, struct ip_flow **expired, uint64_t now)
|
||||
static struct ip_frag_pkt *ip_reassembly_find_frag_pkt(struct ip_reassembly *assy, const struct ip_frag_key *key, struct ip_frag_pkt **free, struct ip_frag_pkt **expired, uint64_t now)
|
||||
{
|
||||
ip_reassembly_stat_inc(assy, find, key);
|
||||
|
||||
if (assy->last != NULL && ip_flow_key_cmp(key, &assy->last->key) == 0)
|
||||
if (assy->last != NULL && ip_frag_key_cmp(key, &assy->last->key) == 0)
|
||||
{
|
||||
return assy->last;
|
||||
}
|
||||
@@ -507,31 +503,31 @@ static struct ip_flow *ip_reassembly_find_flow(struct ip_reassembly *assy, const
|
||||
uint32_t sig2 = 0;
|
||||
if (key->src_dst_len == IPV4_KEYLEN)
|
||||
{
|
||||
ipv4_flow_key_hash(key, &sig1, &sig2);
|
||||
ipv4_frag_key_hash(key, &sig1, &sig2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ipv6_flow_key_hash(key, &sig1, &sig2);
|
||||
ipv6_frag_key_hash(key, &sig1, &sig2);
|
||||
}
|
||||
|
||||
// get the bucket by hash
|
||||
struct ip_flow *p1 = IP_FRAG_TBL_POS(assy, sig1);
|
||||
struct ip_flow *p2 = IP_FRAG_TBL_POS(assy, sig2);
|
||||
struct ip_frag_pkt *p1 = IP_FRAG_TBL_POS(assy, sig1);
|
||||
struct ip_frag_pkt *p2 = IP_FRAG_TBL_POS(assy, sig2);
|
||||
|
||||
// search in the bucket
|
||||
struct ip_flow *old = NULL;
|
||||
struct ip_flow *empty = NULL;
|
||||
struct ip_frag_pkt *old = NULL;
|
||||
struct ip_frag_pkt *empty = NULL;
|
||||
uint64_t timeout = assy->timeout;
|
||||
uint32_t assoc = assy->bucket_entries;
|
||||
for (uint32_t i = 0; i != assoc; i++)
|
||||
{
|
||||
if (ip_flow_key_cmp(key, &p1[i].key) == 0)
|
||||
if (ip_frag_key_cmp(key, &p1[i].key) == 0)
|
||||
{
|
||||
*free = NULL;
|
||||
*expired = NULL;
|
||||
return p1 + i;
|
||||
}
|
||||
else if (ip_flow_key_is_empty(&p1[i].key))
|
||||
else if (ip_frag_key_is_empty(&p1[i].key))
|
||||
{
|
||||
empty = (empty == NULL) ? (p1 + i) : empty;
|
||||
}
|
||||
@@ -540,13 +536,13 @@ static struct ip_flow *ip_reassembly_find_flow(struct ip_reassembly *assy, const
|
||||
old = (old == NULL) ? (p1 + i) : old;
|
||||
}
|
||||
|
||||
if (ip_flow_key_cmp(key, &p2[i].key) == 0)
|
||||
if (ip_frag_key_cmp(key, &p2[i].key) == 0)
|
||||
{
|
||||
*free = NULL;
|
||||
*expired = NULL;
|
||||
return p2 + i;
|
||||
}
|
||||
else if (ip_flow_key_is_empty(&p2[i].key))
|
||||
else if (ip_frag_key_is_empty(&p2[i].key))
|
||||
{
|
||||
empty = (empty == NULL) ? (p2 + i) : empty;
|
||||
}
|
||||
@@ -561,20 +557,21 @@ static struct ip_flow *ip_reassembly_find_flow(struct ip_reassembly *assy, const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ip_flow *ip_reassembly_update_flow(struct ip_reassembly *assy, const struct ip_flow_key *key, uint64_t now)
|
||||
static struct ip_frag_pkt *ip_reassembly_update_frag_pkt(struct ip_reassembly *assy, const struct ip_frag_key *key, uint64_t now)
|
||||
{
|
||||
struct ip_flow *flow = NULL;
|
||||
struct ip_flow *free = NULL;
|
||||
struct ip_flow *expired = NULL;
|
||||
struct ip_frag_pkt *frag_pkt = NULL;
|
||||
struct ip_frag_pkt *free = NULL;
|
||||
struct ip_frag_pkt *expired = NULL;
|
||||
|
||||
flow = ip_reassembly_find_flow(assy, key, &free, &expired, now);
|
||||
if (flow == NULL)
|
||||
frag_pkt = ip_reassembly_find_frag_pkt(assy, key, &free, &expired, now);
|
||||
if (frag_pkt == NULL)
|
||||
{
|
||||
if (expired)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG1("add ip flow success: reuse expired entry", key);
|
||||
ip_reassembly_reuse_flow(assy, expired, key, now);
|
||||
ip_reassembly_stat_inc(assy, timeout, key);
|
||||
IP_REASSEMBLE_DEBUG1("add ip frag pkt success: reuse expired entry", key);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, defrags_failed_timeout, key);
|
||||
ip_reassembly_del_frag_pkt(assy, expired);
|
||||
ip_reassembly_add_frag_pkt(assy, expired, key, now);
|
||||
|
||||
assy->last = expired;
|
||||
return expired;
|
||||
@@ -582,38 +579,38 @@ static struct ip_flow *ip_reassembly_update_flow(struct ip_reassembly *assy, con
|
||||
|
||||
if (free)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG1("add ip flow success: use free entry", key);
|
||||
ip_flow_init(free, key, now);
|
||||
ip_reassembly_add_flow(assy, free);
|
||||
IP_REASSEMBLE_DEBUG1("add ip frag pkt success: use free entry", key);
|
||||
ip_reassembly_add_frag_pkt(assy, free, key, now);
|
||||
|
||||
assy->last = free;
|
||||
return free;
|
||||
}
|
||||
|
||||
// no space
|
||||
IP_REASSEMBLE_ERROR1("add ip flow failed: bucket full", key);
|
||||
ip_reassembly_stat_inc(assy, fail_no_space, key);
|
||||
IP_REASSEMBLE_ERROR1("add ip frag pkt failed: bucket full", key);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, frags_bypass_no_buffer, key);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// expired
|
||||
if (assy->timeout + flow->create_time <= now)
|
||||
if (assy->timeout + frag_pkt->create_time <= now)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG1("add ip flow success: reuse expired entry", key);
|
||||
ip_reassembly_reuse_flow(assy, flow, key, now);
|
||||
ip_reassembly_stat_inc(assy, timeout, key);
|
||||
IP_REASSEMBLE_DEBUG1("add ip frag pkt success: reuse expired entry", key);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, defrags_failed_timeout, key);
|
||||
ip_reassembly_del_frag_pkt(assy, frag_pkt);
|
||||
ip_reassembly_add_frag_pkt(assy, frag_pkt, key, now);
|
||||
|
||||
assy->last = flow;
|
||||
return flow;
|
||||
assy->last = frag_pkt;
|
||||
return frag_pkt;
|
||||
}
|
||||
// not expired
|
||||
else
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG1("find ip flow success: not expire", key);
|
||||
IP_REASSEMBLE_DEBUG1("find ip frag pkt success: not expire", key);
|
||||
|
||||
assy->last = flow;
|
||||
return flow;
|
||||
assy->last = frag_pkt;
|
||||
return frag_pkt;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -622,11 +619,11 @@ static struct ip_flow *ip_reassembly_update_flow(struct ip_reassembly *assy, con
|
||||
* frag reassemble
|
||||
******************************************************************************/
|
||||
|
||||
static struct packet *ip_frag_reassemble(struct ip_reassembly *assy, struct ip_flow *flow)
|
||||
static struct packet *ip_frag_reassemble(struct ip_reassembly *assy, struct ip_frag_pkt *frag_pkt)
|
||||
{
|
||||
struct ip_frag_pkt *first = &flow->frags[IP_FIRST_FRAG_IDX];
|
||||
struct ip_frag_pkt *last = &flow->frags[IP_LAST_FRAG_IDX];
|
||||
struct ip_frag_pkt *temp = NULL;
|
||||
struct ip_frag *first = &frag_pkt->frags[IP_FIRST_FRAG_IDX];
|
||||
struct ip_frag *last = &frag_pkt->frags[IP_LAST_FRAG_IDX];
|
||||
struct ip_frag *temp = NULL;
|
||||
|
||||
uint32_t loop = 0;
|
||||
uint16_t last_offset = last->offset;
|
||||
@@ -635,7 +632,7 @@ static struct packet *ip_frag_reassemble(struct ip_reassembly *assy, struct ip_f
|
||||
struct ip6_hdr *ip6_hdr = NULL;
|
||||
|
||||
// calculate the length of the reassembled packet
|
||||
uint32_t packet_len = flow->expected_total_size + flow->hdr.hdr_len;
|
||||
uint32_t packet_len = frag_pkt->expected_total_size + frag_pkt->hdr.hdr_len;
|
||||
struct packet *pkt = packet_new(packet_len);
|
||||
if (pkt == NULL)
|
||||
{
|
||||
@@ -649,7 +646,7 @@ static struct packet *ip_frag_reassemble(struct ip_reassembly *assy, struct ip_f
|
||||
// copy last frag
|
||||
if (last->len > end - ptr)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR1("last frag length not match expected reassembled length", &flow->key);
|
||||
IP_REASSEMBLE_ERROR1("last frag length not match expected reassembled length", &frag_pkt->key);
|
||||
goto error_out_invalid_length;
|
||||
}
|
||||
end -= last->len;
|
||||
@@ -665,14 +662,14 @@ static struct packet *ip_frag_reassemble(struct ip_reassembly *assy, struct ip_f
|
||||
* will use the more recently arrived copy in the data buffer and
|
||||
* datagram delivered.
|
||||
*/
|
||||
for (uint32_t i = flow->next_fill_idx - 1; i >= IP_MIN_FRAG_NUM; i--)
|
||||
for (uint32_t i = frag_pkt->next_fill_idx - 1; i >= IP_MIN_FRAG_NUM; i--)
|
||||
{
|
||||
temp = &flow->frags[i];
|
||||
temp = &frag_pkt->frags[i];
|
||||
if (temp->offset + temp->len == last_offset)
|
||||
{
|
||||
if (temp->len > end - ptr)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR1("middle frag length not match expected reassembled length", &flow->key);
|
||||
IP_REASSEMBLE_ERROR1("middle frag length not match expected reassembled length", &frag_pkt->key);
|
||||
goto error_out_invalid_length;
|
||||
}
|
||||
|
||||
@@ -683,9 +680,9 @@ static struct packet *ip_frag_reassemble(struct ip_reassembly *assy, struct ip_f
|
||||
}
|
||||
}
|
||||
|
||||
if (loop > flow->next_fill_idx - IP_MIN_FRAG_NUM)
|
||||
if (loop > frag_pkt->next_fill_idx - IP_MIN_FRAG_NUM)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR1("overlap appear during frag reassemble", &flow->key);
|
||||
IP_REASSEMBLE_ERROR1("overlap appear during frag reassemble", &frag_pkt->key);
|
||||
goto error_out_overlap;
|
||||
}
|
||||
|
||||
@@ -695,55 +692,64 @@ static struct packet *ip_frag_reassemble(struct ip_reassembly *assy, struct ip_f
|
||||
// copy fist fragment data
|
||||
if (first->len > end - ptr)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR1("first frag length not match expected reassembled length", &flow->key);
|
||||
IP_REASSEMBLE_ERROR1("first frag length not match expected reassembled length", &frag_pkt->key);
|
||||
goto error_out_invalid_length;
|
||||
}
|
||||
end -= first->len;
|
||||
memcpy(end, first->data, first->len);
|
||||
|
||||
// copy frag hdr
|
||||
if (flow->hdr.hdr_len > end - ptr)
|
||||
if (frag_pkt->hdr.hdr_len > end - ptr)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR1("packet header length not match expected reassembled length", &flow->key);
|
||||
IP_REASSEMBLE_ERROR1("packet header length not match expected reassembled length", &frag_pkt->key);
|
||||
goto error_out_invalid_length;
|
||||
}
|
||||
end -= flow->hdr.hdr_len;
|
||||
memcpy(end, flow->hdr.hdr_data, flow->hdr.hdr_len);
|
||||
end -= frag_pkt->hdr.hdr_len;
|
||||
memcpy(end, frag_pkt->hdr.hdr_data, frag_pkt->hdr.hdr_len);
|
||||
|
||||
// assert
|
||||
assert(ptr == end);
|
||||
|
||||
if (flow->key.src_dst_len == IPV4_KEYLEN)
|
||||
if (frag_pkt->key.src_dst_len == IPV4_KEYLEN)
|
||||
{
|
||||
// update ip total length & ip checksum
|
||||
ip4_hdr = (struct ip *)(ptr + flow->hdr.l3_offset);
|
||||
ip4_hdr_set_total_len(ip4_hdr, packet_len - flow->hdr.l3_offset); // update total length
|
||||
ip4_hdr_set_mf_flag(ip4_hdr, false); // update more fragment flag
|
||||
ip4_hdr_set_frag_offset(ip4_hdr, 0); // update fragment offset
|
||||
ip4_hdr->ip_sum = 0; // update checksum
|
||||
ip4_hdr->ip_sum = checksum((const void *)ip4_hdr, flow->hdr.l3_len);
|
||||
ip4_hdr = (struct ip *)(ptr + frag_pkt->hdr.l3_offset);
|
||||
ip4_hdr_set_total_len(ip4_hdr, packet_len - frag_pkt->hdr.l3_offset); // update total length
|
||||
ip4_hdr_set_mf_flag(ip4_hdr, false); // update more fragment flag
|
||||
ip4_hdr_set_frag_offset(ip4_hdr, 0); // update fragment offset
|
||||
ip4_hdr->ip_sum = 0; // update checksum
|
||||
ip4_hdr->ip_sum = checksum((const void *)ip4_hdr, frag_pkt->hdr.l3_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
// update ipv6 payload length & next header
|
||||
ip6_hdr = (struct ip6_hdr *)(ptr + flow->hdr.l3_offset);
|
||||
ip6_hdr_set_payload_len(ip6_hdr, flow->expected_total_size); // update payload length
|
||||
ip6_hdr_set_next_header(ip6_hdr, flow->hdr.next_proto); // update next header
|
||||
ip6_hdr = (struct ip6_hdr *)(ptr + frag_pkt->hdr.l3_offset);
|
||||
ip6_hdr_set_payload_len(ip6_hdr, frag_pkt->expected_total_size); // update payload length
|
||||
ip6_hdr_set_next_header(ip6_hdr, frag_pkt->hdr.next_proto); // update next header
|
||||
}
|
||||
|
||||
// create a new packet
|
||||
packet_parse(pkt, ptr, packet_len);
|
||||
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, defrags_succeed, &frag_pkt->key);
|
||||
ip_reassembly_del_frag_pkt(assy, frag_pkt);
|
||||
|
||||
return pkt;
|
||||
|
||||
error_out_invalid_length:
|
||||
ip_reassembly_stat_inc(assy, fail_invalid_length, &flow->key);
|
||||
packet_free(pkt);
|
||||
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, defrags_failed_invalid_length, &frag_pkt->key);
|
||||
ip_reassembly_del_frag_pkt(assy, frag_pkt);
|
||||
|
||||
return NULL;
|
||||
|
||||
error_out_overlap:
|
||||
ip_reassembly_stat_inc(assy, fail_overlap, &flow->key);
|
||||
packet_free(pkt);
|
||||
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, defrags_failed_overlap, &frag_pkt->key);
|
||||
ip_reassembly_del_frag_pkt(assy, frag_pkt);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -783,7 +789,7 @@ struct ip_reassembly *ip_reassembly_new(const struct ip_reassembly_options *opts
|
||||
|
||||
assy->entry_total = (uint32_t)entry_total;
|
||||
assy->entry_mask = (assy->entry_total - 1) & ~(assy->bucket_entries - 1);
|
||||
assy->table = (struct ip_flow *)calloc(assy->entry_total, sizeof(struct ip_flow));
|
||||
assy->table = (struct ip_frag_pkt *)calloc(assy->entry_total, sizeof(struct ip_frag_pkt));
|
||||
if (assy->table == NULL)
|
||||
{
|
||||
IP_REASSEMBLE_ERROR("unable to allocate memory");
|
||||
@@ -804,7 +810,7 @@ void ip_reassembly_free(struct ip_reassembly *assy)
|
||||
{
|
||||
for (uint32_t i = 0; i < assy->entry_total; i++)
|
||||
{
|
||||
ip_flow_free(assy->table + i);
|
||||
ip_frag_pkt_clean(&assy->stat, assy->table + i);
|
||||
}
|
||||
|
||||
free(assy->table);
|
||||
@@ -818,16 +824,15 @@ void ip_reassembly_free(struct ip_reassembly *assy)
|
||||
void ip_reassembly_expire(struct ip_reassembly *assy, uint64_t max_free, uint64_t now)
|
||||
{
|
||||
uint64_t count = 0;
|
||||
struct ip_flow *flow = NULL;
|
||||
struct ip_frag_pkt *frag_pkt = NULL;
|
||||
uint64_t timeout = assy->timeout;
|
||||
TAILQ_FOREACH(flow, &assy->lru, lru)
|
||||
TAILQ_FOREACH(frag_pkt, &assy->lru, lru)
|
||||
{
|
||||
if (timeout + flow->create_time <= now)
|
||||
if (timeout + frag_pkt->create_time <= now)
|
||||
{
|
||||
IP_REASSEMBLE_DEBUG1("expire ip flow: discarding old fragmented packets", &flow->key);
|
||||
ip_reassembly_del_flow(assy, flow);
|
||||
ip_reassembly_stat_inc(assy, timeout, &flow->key);
|
||||
ip_flow_free(flow);
|
||||
IP_REASSEMBLE_DEBUG1("expire ip frag pkt: discarding old fragmented packets", &frag_pkt->key);
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, defrags_failed_timeout, &frag_pkt->key);
|
||||
ip_reassembly_del_frag_pkt(assy, frag_pkt);
|
||||
count++;
|
||||
|
||||
if (count >= max_free)
|
||||
@@ -916,7 +921,7 @@ struct packet *ipv4_reassembly_packet(struct ip_reassembly *assy, const struct p
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ip_flow_key key = {};
|
||||
struct ip_frag_key key = {};
|
||||
uint64_t src_addr = hdr->ip_src.s_addr;
|
||||
uint64_t dst_addr = hdr->ip_dst.s_addr;
|
||||
key.src_dst_addr[0] = src_addr << 32 | dst_addr;
|
||||
@@ -924,8 +929,10 @@ struct packet *ipv4_reassembly_packet(struct ip_reassembly *assy, const struct p
|
||||
key.ip_id = ip4_hdr_get_ipid(hdr);
|
||||
key.proto = ip4_hdr_get_proto(hdr);
|
||||
|
||||
struct ip_flow *flow = ip_reassembly_update_flow(assy, &key, now);
|
||||
if (flow == NULL)
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, frags, &key);
|
||||
|
||||
struct ip_frag_pkt *frag_pkt = ip_reassembly_update_frag_pkt(assy, &key, now);
|
||||
if (frag_pkt == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@@ -933,23 +940,17 @@ struct packet *ipv4_reassembly_packet(struct ip_reassembly *assy, const struct p
|
||||
char *frag_data = (char *)layer->pld_ptr;
|
||||
bool more_frags = ip4_hdr_get_mf_flag(hdr);
|
||||
uint16_t frag_offset = ip4_hdr_get_frag_offset(hdr);
|
||||
if (ip_flow_update(assy, flow, pkt, frag_data, frag_len, frag_offset, more_frags) != 0)
|
||||
{
|
||||
ip_reassembly_del_flow(assy, flow);
|
||||
ip_flow_free(flow);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ip_flow_is_ready(flow))
|
||||
if (ip_frag_pkt_update(assy, frag_pkt, pkt, frag_data, frag_len, frag_offset, more_frags) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct packet *new_pkt = ip_frag_reassemble(assy, flow);
|
||||
ip_reassembly_del_flow(assy, flow);
|
||||
ip_flow_free(flow);
|
||||
if (!ip_frag_pkt_is_ready(frag_pkt))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new_pkt;
|
||||
return ip_frag_reassemble(assy, frag_pkt);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1009,36 +1010,32 @@ struct packet *ipv6_reassembly_packet(struct ip_reassembly *assy, const struct p
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ip_flow_key key = {};
|
||||
struct ip_frag_key key = {};
|
||||
memcpy(&key.src_dst_addr[0], hdr->ip6_src.s6_addr, 16);
|
||||
memcpy(&key.src_dst_addr[2], hdr->ip6_dst.s6_addr, 16);
|
||||
key.src_dst_len = IPV6_KEYLEN;
|
||||
key.ip_id = ipv6_frag_get_ident(frag_hdr);
|
||||
key.proto = 0; // only first fragment has the upper layer protocol
|
||||
|
||||
struct ip_flow *flow = ip_reassembly_update_flow(assy, &key, now);
|
||||
if (flow == NULL)
|
||||
IP_REASSEMBLY_STAT_INC(&assy->stat, frags, &key);
|
||||
|
||||
struct ip_frag_pkt *frag_pkt = ip_reassembly_update_frag_pkt(assy, &key, now);
|
||||
if (frag_pkt == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool more_frags = ipv6_frag_get_more(frag_hdr);
|
||||
uint16_t frag_offset = ipv6_frag_get_offset(frag_hdr);
|
||||
if (ip_flow_update(assy, flow, pkt, frag_data, frag_len, frag_offset, more_frags) != 0)
|
||||
{
|
||||
ip_reassembly_del_flow(assy, flow);
|
||||
ip_flow_free(flow);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ip_flow_is_ready(flow))
|
||||
if (ip_frag_pkt_update(assy, frag_pkt, pkt, frag_data, frag_len, frag_offset, more_frags) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct packet *new_pkt = ip_frag_reassemble(assy, flow);
|
||||
ip_reassembly_del_flow(assy, flow);
|
||||
ip_flow_free(flow);
|
||||
if (!ip_frag_pkt_is_ready(frag_pkt))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new_pkt;
|
||||
return ip_frag_reassemble(assy, frag_pkt);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user