Click
Loading...
Searching...
No Matches
packetbatch.hh
1// -*- related-file-name: "../../lib/packetbatch.cc" -*-
2#ifndef CLICK_PACKETBATCH_HH
3#define CLICK_PACKETBATCH_HH
4
5#include <click/packet.hh>
6CLICK_DECLS
7
12#define FOR_EACH_PACKET_LL(first,p) for(Packet* p = first;p != 0;p=p->next())
13
18#define FOR_EACH_PACKET(batch,p) FOR_EACH_PACKET_LL(batch->first(),p)
19
25#define FOR_EACH_PACKET_LL_SAFE(first,p) \
26 Packet* fep_next = ((first != 0)? first->next() : 0 );\
27 Packet* p = first;\
28 for (;p != 0;p=fep_next,fep_next=(p==0?0:p->next()))
29
30
31#define FOR_EACH_PACKET_SAFE(batch,p) FOR_EACH_PACKET_LL_SAFE(batch->first(),p)
32
38#define EXECUTE_FOR_EACH_PACKET(fnt,batch) \
39 Packet* efep_next = ((batch != 0)? batch->first()->next() : 0 );\
40 Packet* p = batch->first();\
41 Packet* last = 0;\
42 for (;p != 0;p=efep_next,efep_next=(p==0?0:p->next())) {\
43 Packet* q = fnt(p);\
44 if (q != p) {\
45 if (last) {\
46 last->set_next(q);\
47 } else {\
48 batch = reinterpret_cast<PacketBatch*>(q);\
49 }\
50 q->set_next(efep_next);\
51 }\
52 last = q;\
53 }
54
62#define EXECUTE_FOR_EACH_PACKET_UNTIL_DO(fnt,batch,on_stop) \
63 Packet* efep_next = ((batch != 0)? batch->first()->next() : 0 );\
64 Packet* p = batch->first();\
65 Packet* last = 0;\
66 int count = batch->count();\
67 for (;p != 0;p=efep_next,efep_next=(p==0?0:p->next())) {\
68 Packet* q = p;\
69 bool drop = !fnt(q);\
70 if (q != p) {\
71 if (last) {\
72 last->set_next(q);\
73 } else {\
74 batch = reinterpret_cast<PacketBatch*>(q);\
75 batch->set_count(count);\
76 }\
77 q->set_next(efep_next);\
78 }\
79 if (unlikely(drop)) {\
80 on_stop(batch, q, efep_next);\
81 break;\
82 }\
83 last = q;\
84 }
85
86//Variant that will drop the whole batch when fnt return false
87#define EXECUTE_FOR_EACH_PACKET_UNTIL(fnt,batch) \
88 EXECUTE_FOR_EACH_PACKET_UNTIL_DO(fnt, batch, [](PacketBatch*& batch, Packet*, Packet*){batch->kill();batch = 0;})
89
90/*
91 * Variant that will drop the remaining packets, but return the batch up to the drop (the packet for which fnt returned true is included.
92 * A usage example is a NAT, that translate all packets up to when the state is destroyed. But sometimes there could be unordered packets still coming after the last ACK, or duplicate FIN.
93 */
94#define EXECUTE_FOR_EACH_PACKET_UNTIL_DROP(fnt,batch) \
95 EXECUTE_FOR_EACH_PACKET_UNTIL_DO(fnt, batch, [](PacketBatch*& batch, Packet* dropped, Packet* next){ if (!next) return; PacketBatch* remain = PacketBatch::make_from_simple_list(next);batch->set_count(batch->count() - remain->count()); batch->set_tail(dropped); dropped->set_next(0); remain->kill(); })
96
113#define EXECUTE_FOR_EACH_PACKET_DROPPABLE(fnt,batch,on_drop) {\
114 Packet* efepd_next = ((batch != 0)? batch->first()->next() : 0 );\
115 Packet* p = batch->first();\
116 Packet* last = 0;\
117 int count = batch->count();\
118 for (;p != 0;p=efepd_next,efepd_next=(p==0?0:p->next())) {\
119 Packet* q = fnt(p);\
120 if (q == 0) {\
121 on_drop(p);\
122 if (last) {\
123 last->set_next(efepd_next);\
124 } else {\
125 batch = PacketBatch::start_head(efepd_next);\
126 }\
127 count--;\
128 continue;\
129 } else if (q != p) {\
130 if (last) {\
131 last->set_next(q);\
132 } else {\
133 batch = reinterpret_cast<PacketBatch*>(q);\
134 }\
135 q->set_next(efepd_next);\
136 }\
137 last = q;\
138 }\
139 if (batch) {\
140 batch->set_count(count);\
141 batch->set_tail(last);\
142 last->set_next(0);\
143 }\
144 }\
145
150#define EXECUTE_FOR_EACH_PACKET_DROP_LIST(fnt,batch,drop_list) \
151 PacketBatch* drop_list = 0;\
152 auto on_drop = [&drop_list](Packet* p) {\
153 if (drop_list == 0) {\
154 drop_list = PacketBatch::make_from_packet(p);\
155 } else {\
156 drop_list->append_packet(p);\
157 }\
158 };\
159 EXECUTE_FOR_EACH_PACKET_DROPPABLE(fnt,batch,on_drop);
160
161
172#define EXECUTE_FOR_EACH_PACKET_SPLITTABLE(fnt,batch,on_drop,on_flush) {\
173 Packet* next = ((batch != 0)? batch->first()->next() : 0 );\
174 Packet* p = batch->first();\
175 Packet* last = 0;\
176 int count = 0;\
177 for (;p != 0;p=next,next=(p==0?0:p->next())) {\
178 Packet* q = (fnt(p));\
179 if (q == 0) {\
180 if (last) {\
181 batch->set_count(count);\
182 batch->set_tail(last);\
183 on_flush(batch);\
184 }\
185 on_drop(p);\
186 count = 0;\
187 last = 0;\
188 batch = PacketBatch::start_head(next);\
189 continue;\
190 } else if (q != p) {\
191 if (last) {\
192 last->set_next(q);\
193 } else {\
194 batch = reinterpret_cast<PacketBatch*>(q);\
195 }\
196 q->set_next(next);\
197 }\
198 last = q;\
199 count++;\
200 }\
201 if (last) {\
202 batch->set_count(count);\
203 batch->set_tail(last);\
204 on_flush(batch);\
205 }\
206 }\
207
208
218#define EXECUTE_FOR_EACH_PACKET_ADD(fnt,batch) {\
219 Packet* next = ((batch != 0)? batch->first()->next() : 0 );\
220 Packet* p = batch->first();\
221 Packet* last = 0;\
222 int count = 0;\
223 for (;p != 0;p=next,next=(p==0?0:p->next())) {\
224 auto add = [&batch,&last,&count](Packet*q) {\
225 if (last) { \
226 last->set_next(q); \
227 } else { \
228 batch = reinterpret_cast<PacketBatch*>(q);\
229 }\
230 last = q;\
231 count++;\
232 };\
233 fnt(p,add);\
234 }\
235 if (likely(last)) {\
236 batch->set_count(count);\
237 batch->set_tail(last);\
238 last->set_next(0);\
239 } else {\
240 batch = 0;\
241 }\
242 }\
243
261#define CLASSIFY_EACH_PACKET(nbatches,fnt,cep_batch,on_finish)\
262 {\
263 PacketBatch* out[(nbatches)];\
264 bzero(out,sizeof(PacketBatch*)*(nbatches));\
265 PacketBatch* cep_next = ((cep_batch != 0)? reinterpret_cast<PacketBatch*>(cep_batch->first()->next()) : 0 );\
266 Packet* p = cep_batch->first();\
267 Packet* last = 0;\
268 int last_o = -1;\
269 int passed = 0;\
270 for (;p != 0;p=cep_next->first(),cep_next=(p==0?0:reinterpret_cast<PacketBatch*>(p->next()))) {\
271 int o = (fnt(p));\
272 if (o < 0 || o>=(int)(nbatches)) o = (nbatches - 1);\
273 if (o == last_o) {\
274 passed ++;\
275 } else {\
276 if (last == 0) {\
277 out[o] = reinterpret_cast<PacketBatch*>(p);\
278 reinterpret_cast<PacketBatch*>(p)->set_count(1);\
279 reinterpret_cast<PacketBatch*>(p)->set_tail(p);\
280 } else {\
281 out[last_o]->set_tail(last);\
282 out[last_o]->set_count(out[last_o]->count() + passed);\
283 if (!out[o]) {\
284 out[o] = reinterpret_cast<PacketBatch*>(p);\
285 out[o]->set_count(1);\
286 out[o]->set_tail(p);\
287 } else {\
288 out[o]->append_packet(p);\
289 }\
290 passed = 0;\
291 }\
292 }\
293 last = p;\
294 last_o = o;\
295 }\
296\
297 if (passed) {\
298 out[last_o]->set_tail(last);\
299 out[last_o]->set_count(out[last_o]->count() + passed);\
300 }\
301\
302 unsigned i = 0;\
303 for (; i < (unsigned)(nbatches); i++) {\
304 if (out[i]) {\
305 out[i]->tail()->set_next(0);\
306 (on_finish(i,out[i]));\
307 }\
308 }\
309 }
310
315#define CLASSIFY_EACH_PACKET_IGNORE(nbatches,fnt,cep_batch,on_finish)\
316 {\
317 PacketBatch* out[(nbatches)];\
318 bzero(out,sizeof(PacketBatch*)*(nbatches));\
319 PacketBatch* cep_next = ((cep_batch != 0)? reinterpret_cast<PacketBatch*>(cep_batch->first()->next()) : 0 );\
320 Packet* p = cep_batch->first();\
321 Packet* last = 0;\
322 int last_o = -1;\
323 int passed = 0;\
324 for (;p != 0;p=cep_next->first(),cep_next=(p==0?0:reinterpret_cast<PacketBatch*>(p->next()))) {\
325 int o = (fnt(p));\
326 if (o>=(nbatches)) o = (nbatches - 1);\
327 if (o == last_o) {\
328 passed ++;\
329 } else {\
330 if (last == 0) {\
331 if (o == -1) continue;\
332 out[o] = reinterpret_cast<PacketBatch*>(p);\
333 out[o]->set_count(1);\
334 out[o]->set_tail(p);\
335 } else {\
336 if (last_o != -1) {\
337 out[last_o]->set_tail(last);\
338 out[last_o]->set_count(out[last_o]->count() + passed);\
339 }\
340 if (o != -1) {\
341 if (!out[o]) {\
342 out[o] = reinterpret_cast<PacketBatch*>(p);\
343 out[o]->set_count(1);\
344 out[o]->set_tail(p);\
345 } else {\
346 out[o]->append_packet(p);\
347 }\
348 }\
349 passed = 0;\
350 }\
351 }\
352 last = p;\
353 last_o = o;\
354 }\
355\
356 if (passed && last_o != -1) {\
357 out[last_o]->set_tail(last);\
358 out[last_o]->set_count(out[last_o]->count() + passed);\
359 }\
360\
361 int i = 0;\
362 for (; i < (nbatches); i++) {\
363 if (out[i]) {\
364 out[i]->tail()->set_next(0);\
365 (on_finish(i,out[i]));\
366 }\
367 }\
368 }
369
370
384#define MAKE_BATCH(fnt,head,max) {\
385 head = PacketBatch::start_head(fnt);\
386 if (head != 0) {\
387 Packet* last = head->first();\
388 unsigned int count = 1;\
389 while (count < (unsigned)(max>0?max:BATCH_MAX_PULL)) {\
390 Packet* current = fnt;\
391 if (current == 0)\
392 break;\
393 last->set_next(current);\
394 last = current;\
395 count++;\
396 }\
397 head->make_tail(last,count);\
398 }\
399}
400
416
417//Consider a batch size bigger as bogus (prevent infinite loop on bad pointer manipulation)
418#define MAX_BATCH_SIZE 8192
419
420public :
421 /*
422 * Return the first packet of the batch
423 */
424 inline Packet* first() {
425 return (Packet*)this;
426 }
427
428 /*
429 * Set the tail of the batch
430 */
431 inline void set_tail(Packet* p) {
432 first()->set_prev(p);
433 }
434
435 /*
436 * Return the tail of the batch
437 */
438 inline Packet* tail() {
439 return first()->prev();
440 }
441
442 /*
443 * Append a simply-linked list of packet to the batch.
444 * One must therefore pass the tail and the number of packets to do it in constant time. Chances are you
445 * just created that list and can track taht.
446 */
447 inline void append_simple_list(Packet* lhead, Packet* ltail, int lcount) {
448 tail()->set_next(lhead);
449 set_tail(ltail);
450 ltail->set_next(0);
451 set_count(count() + lcount);
452 }
453
454 /*
455 * Append a proper PacketBatch to this batch.
456 */
457 inline void append_batch(PacketBatch* head) {
458 tail()->set_next(head->first());
459 set_tail(head->tail());
460 set_count(count() + head->count());
461 }
462
463 /*
464 * Append a packet to the list.
465 */
466 inline void append_packet(Packet* p) {
467 tail()->set_next(p);
468 set_tail(p);
469 set_count(count() + 1);
470 }
471
475 inline unsigned count() {
476 unsigned int r = BATCH_COUNT_ANNO(first());
477 assert(r); //If this is a batch, this anno has to be set
478 return r;
479 }
480
490 inline static PacketBatch* start_head(Packet* p) {
491 return reinterpret_cast<PacketBatch*>(p);
492 }
493
504 inline PacketBatch* make_tail(Packet* last, unsigned int count) {
506 if (last == 0) {
507 if (count != 1)
508 click_chatter("BUG in make_tail : last packet is the head, but count is %u",count);
509 set_tail(first());
510 first()->set_next(0);
511 } else {
512 set_tail(last);
513 last->set_next(0);
514 }
515 return this;
516 }
517
521 inline void set_count(unsigned int c) {
522 SET_BATCH_COUNT_ANNO(first(),c);
523 }
524
532 inline void cut(Packet* middle, int first_batch_count, PacketBatch* &second) {
533 if (middle == 0) {
534 second = 0;
535 click_chatter("BUG Warning : cutting a batch without a location to cut !");
536 return;
537 }
538
539 if (middle == tail()) {
540 second = 0;
541 return;
542 }
543
544 int total_count = count();
545
546 second = reinterpret_cast<PacketBatch*>(middle->next());
547 middle->set_next(0);
548
549 Packet* second_tail = tail();
550 set_tail(middle);
551
552 second->set_tail(second_tail);
553 second->set_count(total_count - first_batch_count);
554
555 set_count(first_batch_count);
556 }
557
565 inline void split(int first_batch_count, PacketBatch* &second, const bool &safe = false) {
566 Packet* middle = first();
567 if (unlikely(!safe)) {
568 assert(first_batch_count > 0);
569 }
570 for (int i = 0; i < first_batch_count - 1; i++) {
571 middle = middle->next();
572 if (unlikely(!safe && middle == 0)) {
573 second = 0;
574 break;
575 }
576 }
577
578 int total_count = count();
579
580 second = reinterpret_cast<PacketBatch*>(middle->next());
581 middle->set_next(0);
582
583 Packet* second_tail = tail();
584 set_tail(middle);
585
586 second->set_tail(second_tail);
587 second->set_count(total_count - first_batch_count);
588
589 set_count(first_batch_count);
590 }
591
592 inline PacketBatch* split(int first_batch_count) {
593 PacketBatch* second;
594 split(first_batch_count,second, false);
595 return second;
596 }
597
603 if (count() == 1)
604 return 0;
605 PacketBatch* poped = PacketBatch::start_head(first()->next());
606 poped->set_count(count() -1 );
607 poped->set_tail(tail());
608 return poped;
609 }
610
620 inline static PacketBatch* make_from_tailed_list(Packet* head, unsigned int size) {
621 PacketBatch* b = reinterpret_cast<PacketBatch*>(head);
622 b->set_count(size);
623 return b;
624 }
625
633 inline static PacketBatch* make_from_simple_list(Packet* head, Packet* tail, unsigned int size) {
634 PacketBatch* b = make_from_tailed_list(head,size);
635 b->set_tail(tail);
636 tail->set_next(0);
637 return b;
638 }
639
646 int size = 1;
647 Packet* next = head->next();
648 Packet* tail = head;
649 while (next != 0) {
650 size++;
651 tail = next;
652 next = tail->next();
653 }
654 PacketBatch* b = make_from_tailed_list(head,size);
655 b->set_tail(tail);
656 return b;
657 }
658
659
660
665 if (!p) return 0;
666 PacketBatch* b = reinterpret_cast<PacketBatch*>(p);
667 b->set_count(1);
668 b->set_tail(p);
669 p->set_next(0);
670 return b;
671 }
672
673#if !CLICK_LINUXMODULE
674 static PacketBatch *make_batch(unsigned char *data, uint16_t count, uint16_t *length,
675 Packet::buffer_destructor_type destructor,
676 void* argument = (void*) 0, const bool clear=true) CLICK_WARN_UNUSED_RESULT;
677#endif
678
682 inline Packet* begin() {
683 return first();
684 }
685
689 inline Packet* end() {
690 return tail();
691 }
692
696 inline void kill();
697
701 inline PacketBatch* clone_batch(const bool duplicate = false, const bool duplicate_data_only = false) {
702 PacketBatch* head = 0;
703 Packet* last = 0;
704 FOR_EACH_PACKET(this, p) {
705 Packet* q;
706 if (duplicate)
707 q = p->duplicate(0, 0, duplicate_data_only);
708 else
709 q = p->clone();
710 if (last == 0) {
711 head = start_head(q);
712 last = q;
713 } else {
714 last->set_next(q);
715 last = q;
716 }
717 }
718 return head->make_tail(last,count());
719 }
720
721#if HAVE_BATCH && HAVE_CLICK_PACKET_POOL
725 void recycle_batch(bool is_data);
726
727 void fast_kill();
728 void fast_kill_nonatomic();
729#else
730 inline void fast_kill() {
731 kill();
732 }
733
734 void fast_kill_nonatomic() {
735 kill();
736 }
737#endif
738};
739
743inline void PacketBatch::kill() {
744 FOR_EACH_PACKET_SAFE(this,p) {
745 p->kill();
746 }
747}
748
749#if HAVE_BATCH_RECYCLE
750#define BATCH_RECYCLE_START() \
751 WritablePacket* head_packet = 0;\
752 WritablePacket* head_data = 0;\
753 WritablePacket* last_packet = 0;\
754 WritablePacket* last_data = 0;\
755 unsigned int n_packet = 0;\
756 unsigned int n_data = 0;
757
758#define BATCH_RECYCLE_ADD_PACKET(p) {\
759 if (head_packet == 0) {\
760 head_packet = static_cast<WritablePacket*>(p);\
761 last_packet = static_cast<WritablePacket*>(p);\
762 } else {\
763 last_packet->set_next(p);\
764 last_packet = static_cast<WritablePacket*>(p);\
765 }\
766 n_packet++;}
767
768#define BATCH_RECYCLE_ADD_DATA_PACKET(p) {\
769 if (head_data == 0) {\
770 head_data = static_cast<WritablePacket*>(p);\
771 last_data = static_cast<WritablePacket*>(p);\
772 } else {\
773 last_data->set_next(p);\
774 last_data = static_cast<WritablePacket*>(p);\
775 }\
776 n_data++;}
777
778#define BATCH_RECYCLE_PACKET(p) {\
779 if (p->shared()) {\
780 p->kill();\
781 } else {\
782 BATCH_RECYCLE_UNKNOWN_PACKET(p);\
783 }\
784 }
785
786#define BATCH_RECYCLE_PACKET_NONATOMIC(p) {\
787 if (p->shared_nonatomic()) {\
788 p->kill_nonatomic();\
789 } else {\
790 BATCH_RECYCLE_UNKNOWN_PACKET(p);\
791 }\
792 }
793
794#if HAVE_DPDK_PACKET_POOL
795#define BATCH_RECYCLE_UNKNOWN_PACKET(p) {\
796 if (p->data_packet() == 0 && (DPDKDevice::is_dpdk_packet(p)) && p->buffer() != 0) {\
797 BATCH_RECYCLE_ADD_DATA_PACKET(p);\
798 } else {\
799 BATCH_RECYCLE_ADD_PACKET(p);}}
800#elif !defined(CLICK_NOINDIRECT)
801#define BATCH_RECYCLE_UNKNOWN_PACKET(p) {\
802 if (p->data_packet() == 0 && p->buffer_destructor() == 0 && p->buffer() != 0) {\
803 BATCH_RECYCLE_ADD_DATA_PACKET(p);\
804 } else {\
805 BATCH_RECYCLE_ADD_PACKET(p);}}
806#else
807#define BATCH_RECYCLE_UNKNOWN_PACKET(p) {\
808 if (p->buffer_destructor() == 0 && p->buffer() != 0) {\
809 BATCH_RECYCLE_ADD_DATA_PACKET(p);\
810 } else {\
811 BATCH_RECYCLE_ADD_PACKET(p);}}
812#endif
813
814#define BATCH_RECYCLE_END() \
815 if (last_packet) {\
816 last_packet->set_next(0);\
817 PacketBatch::make_from_simple_list(head_packet,last_packet,n_packet)->recycle_batch(false);\
818 }\
819 if (last_data) {\
820 last_data->set_next(0);\
821 PacketBatch::make_from_simple_list(head_data,last_data,n_data)->recycle_batch(true);\
822 }
823#else
824#define BATCH_RECYCLE_START() {}
825#define BATCH_RECYCLE_END() {}
826#define BATCH_RECYCLE_PACKET(p) {p->kill();}
827#define BATCH_RECYCLE_PACKET_NONATOMIC(p) {p->kill_nonatomic();}
828#endif
829
833#define BATCH_RECYCLE_PACKET_CONTEXT(p) {\
834 if (likely(is_fullpush())) {\
835 BATCH_RECYCLE_PACKET_NONATOMIC(p);\
836 } else {\
837 BATCH_RECYCLE_PACKET(p);\
838 }\
839 }
840
844#define BATCH_CREATE_INIT(batch) \
845 PacketBatch* batch = 0; \
846 int batch ## count = 0; \
847 Packet* batch ## last = 0;
848#define BATCH_CREATE_APPEND(batch,p) \
849 if (batch) { \
850 batch ## last->set_next(p); \
851 } else {\
852 batch = PacketBatch::start_head(p); \
853 }\
854 batch ## last = p;\
855 batch ## count++;
856#define BATCH_CREATE_FINISH(batch) \
857 if (batch) \
858 batch->make_tail(batch ## last, batch ## count)
859
861
862#if HAVE_BATCH && HAVE_CLICK_PACKET_POOL
868inline void PacketBatch::recycle_batch(bool is_data) {
869 if (is_data) {
870 WritablePacket::recycle_data_batch((WritablePacket*)this->first(),tail(),count());
871 } else {
872 WritablePacket::recycle_packet_batch((WritablePacket*)this->first(),tail(),count());
873 }
874}
875#endif
876
877CLICK_ENDDECLS
878#endif
Definition packetbatch.hh:415
void set_count(unsigned int c)
Definition packetbatch.hh:521
void kill()
Definition packetbatch.hh:743
unsigned count()
Definition packetbatch.hh:475
Packet * begin()
Definition packetbatch.hh:682
static PacketBatch * start_head(Packet *p)
Start a new batch.
Definition packetbatch.hh:490
static PacketBatch * make_from_simple_list(Packet *head, Packet *tail, unsigned int size)
Definition packetbatch.hh:633
PacketBatch * clone_batch(const bool duplicate=false, const bool duplicate_data_only=false)
Definition packetbatch.hh:701
PacketBatch * pop_front()
Definition packetbatch.hh:602
void split(int first_batch_count, PacketBatch *&second, const bool &safe=false)
Cut a batch in two batches.
Definition packetbatch.hh:565
PacketBatch * make_tail(Packet *last, unsigned int count)
Finish a batch started with start_head()
Definition packetbatch.hh:504
Packet * end()
Definition packetbatch.hh:689
static PacketBatch * make_from_simple_list(Packet *head)
Definition packetbatch.hh:645
void cut(Packet *middle, int first_batch_count, PacketBatch *&second)
Cut a batch in two batches.
Definition packetbatch.hh:532
static PacketBatch * make_from_tailed_list(Packet *head, unsigned int size)
Definition packetbatch.hh:620
static PacketBatch * make_from_packet(Packet *p)
Definition packetbatch.hh:664
A network packet.
Definition packet.hh:68
void kill()
Delete this packet.
Definition packet.hh:1804
void set_next(Packet *p)
Set the next packet annotation.
Definition packet.hh:1351
Packet * prev() const
Return the previous packet annotation.
Definition packet.hh:1363
PacketType
Values for packet_type_anno(). Must agree with Linux's PACKET_ constants in <linux/if_packet....
Definition packet.hh:490
Packet * clone(bool fast=false)
Create a clone of this packet.
Definition packet.cc:1104
Packet * next() const
Return the next packet annotation.
Definition packet.hh:1327
void set_prev(Packet *p)
Set the previous packet annotation.
Definition packet.hh:1387
A network packet believed not to be shared.
Definition packet.hh:1004
The Packet class models packets in Click.