13 #include "odp_ipfragreass_reassemble.h"
14 #include "odp_ipfragreass_helpers.h"
16 #define ROT(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
26 static inline odp_bool_t equal_flow(
struct packet *current,
struct packet *frag)
31 return (memcmp(&curr_h->src_addr, &frag_h->src_addr,
32 sizeof(curr_h->src_addr) +
sizeof(curr_h->dst_addr))
34 curr_h->id == frag_h->id &&
35 curr_h->proto == frag_h->proto);
46 static inline odp_bool_t later_flow(
struct packet *current,
struct packet *frag)
51 return (memcmp(&curr_h->src_addr, &frag_h->src_addr,
52 sizeof(curr_h->src_addr) +
sizeof(curr_h->dst_addr))
54 curr_h->id > frag_h->id ||
55 curr_h->proto > frag_h->proto);
67 static inline struct flts earliest(struct flts a, struct flts b,
71 struct flts elapsed_a;
72 struct flts elapsed_b;
74 now.t += TS_NOW_TOLERANCE;
75 elapsed_a.t = now.t - a.t;
76 elapsed_b.t = now.t - b.t;
77 result.t = now.t - max(elapsed_a.t, elapsed_b.t);
88 static inline uint32_t hash(odph_ipv4hdr_t *hdr)
90 uint32_t a = hdr->src_addr;
91 uint32_t b = hdr->dst_addr;
92 uint32_t c = (uint32_t)hdr->id << 16 | hdr->proto;
125 static inline odp_bool_t later_fragment(
struct packet *a,
struct packet *b,
130 uint32_t offset_a = ipv4hdr_fragment_offset_oct(hdr_a);
131 uint32_t offset_b = ipv4hdr_fragment_offset_oct(hdr_b);
132 uint32_t payload_len_a = ipv4hdr_payload_len(hdr_a);
133 uint32_t payload_len_b = ipv4hdr_payload_len(hdr_b);
134 uint32_t endpoint_a = OCTS_TO_BYTES(offset_a) + payload_len_a;
135 uint32_t endpoint_b = OCTS_TO_BYTES(offset_b) + payload_len_b;
137 if (later_flow(a, b)) {
139 }
else if (equal_flow(a, b)) {
140 if (endpoint_a > endpoint_b) {
142 }
else if (endpoint_a == endpoint_b) {
143 if (offset_a < offset_b) {
145 }
else if (offset_a == offset_b) {
146 return b->arrival.t == earliest(a->arrival,
168 static struct packet *extract_complete_packet(
struct packet *tail,
169 struct packet **remaining_packets,
183 struct packet *current = tail;
184 odph_ipv4hdr_t tail_hdr;
185 uint16_t final_frag_offset;
188 final_frag_offset = ipv4hdr_fragment_offset_oct(tail_hdr);
190 odph_ipv4hdr_t curr_hdr;
191 uint16_t curr_offset_oct;
195 odph_ipv4hdr_t prev_hdr;
196 uint16_t prev_off_oct;
200 curr_hdr = *(odph_ipv4hdr_t *)tmp;
201 curr_offset_oct = ipv4hdr_fragment_offset_oct(curr_hdr);
202 final_fragment = (curr_offset_oct == final_frag_offset);
209 if (final_fragment && ipv4hdr_more_fragments(curr_hdr))
216 prev = prev_packet(*current);
217 if (prev == NULL || !equal_flow(current, prev)) {
225 if (remaining_packets)
226 *remaining_packets = prev;
227 set_prev_packet(current, NULL);
238 prev_hdr = *(odph_ipv4hdr_t *)tmp;
239 prev_off_oct = ipv4hdr_fragment_offset_oct(prev_hdr);
240 prev_oct = BYTES_TO_OCTS(ipv4hdr_payload_len(prev_hdr));
241 if (curr_offset_oct != prev_off_oct + prev_oct) {
242 if (prev_off_oct + prev_oct < curr_offset_oct) {
272 while (prev_packet(*current) &&
273 equal_flow(current, prev_packet(*current))) {
274 current = prev_packet(*current);
276 tail = prev_packet(*current);
277 remaining_packets = prev_packet_ptr(current);
292 static int send_packet(
struct packet *tail,
odp_queue_t out)
294 struct packet result = *tail;
295 struct packet *current = prev_packet(result);
296 odph_ipv4hdr_t *header;
303 while (current && equal_flow(current, &result)) {
304 struct packet new_result = *current;
305 int concat_success, trunc_success;
307 current = prev_packet(new_result);
311 if (trunc_success < 0) {
312 fprintf(stderr,
"ERROR: odp_packet_trunc_head\n");
318 if (concat_success < 0) {
319 fprintf(stderr,
"ERROR: odp_packet_concat\n");
328 assert(length >= IP_HDR_LEN_MIN || length <= UINT16_MAX);
330 ipv4hdr_set_more_fragments(header, 0);
331 ipv4hdr_set_fragment_offset_oct(header, 0);
333 odph_ipv4_csum_update(result.handle);
345 static void sort_fraglist(
union fraglist *fl,
struct flts now)
347 struct packet *to_insert = fl->tail;
351 struct packet *to_insert_next = prev_packet(*to_insert);
353 if (fl->tail == NULL ||
354 later_fragment(to_insert, fl->tail, now)) {
355 set_prev_packet(to_insert, fl->tail);
356 fl->tail = to_insert;
358 struct packet *current = fl->tail;
360 while (prev_packet(*current) &&
361 later_fragment(prev_packet(*current), to_insert,
363 current = prev_packet(*current);
365 set_prev_packet(to_insert, prev_packet(*current));
366 set_prev_packet(current, to_insert);
368 to_insert = to_insert_next;
385 struct packet *frags_head,
struct flts now,
397 union fraglist oldfl;
398 union fraglist newfl;
399 union fraglist nullfl;
400 struct flts oldfl_earliest;
401 struct flts frags_earliest;
409 if (oldfl.tail != NULL)
413 set_prev_packet(frags_head, oldfl.tail);
414 newfl.tail = frags.tail;
422 oldfl_earliest.t = oldfl.earliest;
423 frags_earliest.t = frags.earliest;
424 newfl.part_len = min(IP_OCTET_MAX, oldfl.part_len + frags.part_len);
425 newfl.whole_len = min(oldfl.whole_len, frags.whole_len);
426 newfl.earliest = (oldfl.tail == NULL ? frags.earliest
427 : earliest(oldfl_earliest,
435 if (newfl.part_len < newfl.whole_len || dont_assemble) {
438 set_prev_packet(frags_head, NULL);
454 init_fraglist(&nullfl);
457 set_prev_packet(frags_head, NULL);
467 struct packet *remaining_packets;
468 struct packet *complete_datagram;
469 int fraglist_changed = 0;
470 int call_changed_fraglist = 0;
471 union fraglist update;
473 sort_fraglist(&newfl, now);
474 remaining_packets = newfl.tail;
476 while ((complete_datagram =
477 extract_complete_packet(remaining_packets, &remaining_packets,
478 &call_changed_fraglist)) ||
479 call_changed_fraglist) {
480 fraglist_changed = 1;
481 if (complete_datagram) {
482 assert(!send_packet(complete_datagram, out));
486 call_changed_fraglist = 0;
490 if (!remaining_packets)
503 update.tail = remaining_packets;
504 update.part_len = newfl.part_len;
505 update.whole_len = newfl.whole_len;
506 update.earliest = newfl.earliest;
513 if (fraglist_changed) {
514 struct packet *current = remaining_packets;
516 update.earliest = now.t;
521 struct flts update_earliest;
523 update_earliest.t = update.earliest;
525 part_oct = ipv4hdr_payload_len_oct(*h);
526 whole_oct = ipv4hdr_reass_payload_len_oct(*h);
527 update.part_len = min(IP_OCTET_MAX,
528 update.part_len + part_oct);
529 update.whole_len = min(update.whole_len, whole_oct);
530 update.earliest = earliest(update_earliest,
531 current->arrival, now).t;
532 frags_head = current;
533 current = prev_packet(*current);
540 frags_head = frags.tail;
541 while (prev_packet(*frags_head))
542 frags_head = prev_packet(*frags_head);
559 uint16_t frag_payload_len,
560 uint16_t frag_reass_payload_len,
563 union fraglist frags;
566 frags.part_len = frag_payload_len;
567 frags.whole_len = frag_reass_payload_len;
568 frags.earliest = frag->arrival.t;
570 return add_fraglist_to_fraglist(fl, frags, frags.tail, frag->arrival,
588 union fraglist newfl = oldfl;
589 struct packet *current;
590 struct packet *current_tail;
591 struct packet *remaining_frags_head;
592 struct flts flow_earliest;
597 sort_fraglist(&newfl, timestamp_now);
600 current = newfl.tail;
601 current_tail = newfl.tail;
602 remaining_frags_head = NULL;
603 flow_earliest = current->arrival;
604 newfl.earliest = timestamp_now.t;
606 struct packet *prev = prev_packet(*current);
612 if (prev == NULL || !equal_flow(current, prev)) {
616 elapsed.t = timestamp_now.t - flow_earliest.t;
617 elapsed_ns = (elapsed.t * TS_RES_NS);
618 if ((elapsed_ns >= FLOW_TIMEOUT_NS &&
619 elapsed.t + TS_NOW_TOLERANCE >=
620 TS_NOW_TOLERANCE) || force) {
621 struct packet *to_free = current_tail;
623 while (to_free != prev) {
626 next = prev_packet(*to_free);
631 if (remaining_frags_head)
632 set_prev_packet(remaining_frags_head,
640 struct flts newfl_earliest;
642 newfl_earliest.t = newfl.earliest;
643 remaining_frags_head = current;
645 part_oct = ipv4hdr_payload_len_oct(*h);
646 whole_oct = ipv4hdr_reass_payload_len_oct(*h);
647 newfl.part_len = min(IP_OCTET_MAX,
648 newfl.part_len + part_oct);
649 newfl.whole_len = min(newfl.whole_len,
651 newfl.earliest = earliest(newfl_earliest,
657 flow_earliest.t = EARLIEST_MAX;
659 flow_earliest = earliest(flow_earliest,
671 if (remaining_frags_head)
672 add_fraglist_to_fraglist(fl, newfl, remaining_frags_head,
673 timestamp_now, out, 0);
687 struct flts timestamp_now;
690 union fraglist oldfl;
695 timestamp_now.t = time_now / TS_RES_NS;
699 elapsed.t = timestamp_now.t - oldfl.earliest;
701 if (oldfl.tail == NULL ||
702 elapsed.t + TS_NOW_TOLERANCE < TS_NOW_TOLERANCE)
705 elapsed_ns = (elapsed.t * TS_RES_NS);
706 assert(force || elapsed_ns <= 86400000000000);
707 if (elapsed_ns >= FLOW_TIMEOUT_NS || force) {
708 union fraglist nullfl;
710 init_fraglist(&nullfl);
714 remove_stale_flows(fl, oldfl, timestamp_now,
721 struct packet *fragments,
int num_fragments,
725 int packets_reassembled = 0;
727 for (i = 0; i < num_fragments; ++i) {
730 uint16_t frag_payload_len;
731 uint16_t frag_reass_payload_len;
738 frag_payload_len = ipv4hdr_payload_len_oct(*hdr);
739 frag_reass_payload_len = ipv4hdr_reass_payload_len_oct(*hdr);
747 fl = &fraglists[key % num_fraglists];
749 status = add_frag_to_fraglist(fl, &fragments[i],
751 frag_reass_payload_len, out);
754 "ERROR: failed to add fragment to fraglist\n");
757 packets_reassembled += status;
760 return packets_reassembled;
768 for (i = 0; i < num_fraglists; ++i)
769 garbage_collect_fraglist(&fraglists[i], out, destroy_all);
int odp_atomic_cas_acq_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, odp_u128_t new_val)
Compare and swap atomic odp_u128_t variable using ACQUIRE memory ordering.
int odp_atomic_cas_rel_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, odp_u128_t new_val)
Compare and swap atomic odp_u128_t variable using RELEASE memory ordering.
odp_u128_t odp_atomic_load_u128(odp_atomic_u128_t *atom)
Load value of atomic odp_u128_t variable.
odp_u16be_t odp_cpu_to_be_16(uint16_t cpu16)
Convert cpu native uint16_t to 16bit big endian.
odp_event_t odp_packet_to_event(odp_packet_t pkt)
Convert packet handle to event.
int odp_packet_concat(odp_packet_t *dst, odp_packet_t src)
Concatenate two packets.
void * odp_packet_data(odp_packet_t pkt)
Packet data pointer.
uint32_t odp_packet_len(odp_packet_t pkt)
Packet data length.
void odp_packet_free(odp_packet_t pkt)
Free packet.
int odp_packet_trunc_head(odp_packet_t *pkt, uint32_t len, void **data_ptr, uint32_t *seg_len)
Truncate packet head.
int odp_queue_enq(odp_queue_t queue, odp_event_t ev)
Enqueue an event to a queue.
bool odp_bool_t
Boolean type.
uint64_t odp_time_to_ns(odp_time_t time)
Convert time to nanoseconds.
odp_time_t odp_time_global(void)
Current global time.