1#ifndef CLICK_CTXELEMENT_HH
2#define CLICK_CTXELEMENT_HH
3#include <click/config.h>
6#include <click/flowbuffer.hh>
7#include <click/flow/common.hh>
13#include <click/flow/flowelement.hh>
20struct StackReleaseChain {
21 SubFlowRealeaseFnt previous_fnt;
62class CTXElement :
public VirtualFlowSpaceElement
65 friend class PathMerger;
73 CTXElement() CLICK_COLD;
78 ~CTXElement() CLICK_COLD;
81 const
char *class_name()
const {
return "CTXElement"; }
82 const char *port_count()
const {
return PORTS_1_1; }
83 const char *processing()
const {
return "h/hh"; }
84 virtual const size_t flow_data_size()
const {
return 0; };
85 void* cast(
const char*)
override;
88 static CounterInitFuture allStackInitialized;
89 Router::FctChildFuture _on_fcb_built_future;
99 virtual void addCTXElementInList(CTXElement* element,
int port);
106 static bool isCTXElement(
Element* element);
112 virtual int maxModificationLevel(
Element* stop);
122 void setAnnotationLastUseful(
Packet* packet,
bool value)
const;
129 bool getAnnotationLastUseful(
Packet* packet)
const;
139 inline char* searchInContent(
char *content,
const StringRef &pattern, uint32_t length);
147 void setInitialAck(
Packet *packet, uint32_t initialAck)
const;
155 uint32_t getInitialAck(
Packet *packet)
const;
162 void buildFunctionStack();
166 const int MODIFICATION_NONE = 0;
167 const int MODIFICATION_WRITABLE = 1;
168 const int MODIFICATION_STALL = 2;
169 const int MODIFICATION_REPLACE = 4;
170 const int MODIFICATION_RESIZE = 8;
179 virtual void removeBytes(
WritablePacket* packet, uint32_t position,
193 uint32_t length) CLICK_WARN_UNUSED_RESULT;
203 virtual void requestMorePackets(
Packet *packet,
bool force =
false);
211 virtual void closeConnection(
Packet *packet,
bool graceful);
216 virtual bool registerConnectionClose(StackReleaseChain* fcb_chain, SubFlowRealeaseFnt fnt,
void* thunk);
224 virtual bool isEstablished();
233 virtual bool isLastUsefulPacket(
Packet *packet);
242 virtual unsigned int determineFlowDirection();
252 void setAnnotationBit(
Packet* packet,
int bit,
bool value)
const;
261 bool getAnnotationBit(
Packet* packet,
int bit)
const;
263 CTXElement *previousCTXElement;
268 const int OFFSET_ANNOTATION_LASTUSEFUL = 0;
273class CTXSpaceElement :
public CTXElement {
279 virtual const size_t flow_data_size()
const {
return sizeof(T); }
284 inline T* fcb_data_for(FlowControlBlock* fcb) {
285 T* flowdata =
static_cast<T*
>((
void*)&fcb->data[_flow_data_offset]);
292 inline T* fcb_data() {
293 return fcb_data_for(fcb_stack);
296 void push_batch(
int port,
PacketBatch* head)
final {
298 push_flow(port, fcb_data(), head);
301 virtual void push_flow(
int port, T* flowdata,
PacketBatch* head) = 0;
320 this->startElement = startElement;
339 CTXElement* startElement;
343CTXSpaceElement<T>::CTXSpaceElement() : CTXElement() {
348CTXSpaceElement<T>::~CTXSpaceElement() {
373 struct AT :
public StackReleaseChain {
381 virtual const size_t flow_data_size()
const {
return sizeof(AT); }
394 AT* flowdata =
static_cast<AT*
>((
void*)&fcb->data[_flow_data_offset]);
405 static void release_fnt(FlowControlBlock* fcb,
void* thunk ) {
406 Derived* derived =
static_cast<Derived*
>(thunk);
407 AT* my_fcb =
reinterpret_cast<AT*
>(&fcb->data[derived->_flow_data_offset]);
408 derived->release_flow(&my_fcb->v);
409 if (my_fcb->previous_fnt)
410 my_fcb->previous_fnt(fcb, my_fcb->previous_thunk);
413 void push_batch(
int port,
PacketBatch* head)
final {
414 auto my_fcb = my_fcb_data();
416 if (
static_cast<Derived*
>(
this)->
new_flow(&my_fcb->v, head->first())) {
418 if (!this->registerConnectionClose(my_fcb, &release_fnt, (
void*)
this)) {
419 click_chatter(
"ERROR in %p{element}: No element handles the connection",
this);
426 static_cast<Derived*
>(
this)->push_flow(port, &my_fcb->v, head);
431 inline AT* my_fcb_data() {
432 return static_cast<AT*
>((
void*)&fcb_stack->data[_flow_data_offset]);
437template <
class Derived,
typename T>
438class StackBufferElement :
public CTXStateElement<Derived, BufferData<T>>
442 const char *processing() const final {
return Element::PUSH; }
446 auto it =
fcb_data->flowBuffer.enqueueAllIter(flow);
447 int action =
static_cast<Derived*
>(
this)->process_data(&
fcb_data->userdata,it);
449 this->closeConnection((it.current() ? it.current() : flow->first()), true);
452 }
else if (action > 0) {
453 this->closeConnection((it.current() ? it.current() : flow->first()), true);
454 this->checked_output_push_batch(action,
fcb_data->flowBuffer.dequeueAll());
462 this->requestMorePackets(it.current(),
false);
465 this->checked_output_push_batch(action,passed);
468 void release_flow(BufferData<T>* fcb) {
476template <
class Derived,
typename T>
477class StackChunkBufferElement :
public CTXStateElement<Derived, BufferData<T>>
481 const char *processing() const final {
return Element::PUSH; }
487 inline void release_stream(T*) {
494 auto it =
fcb_data->flowBuffer.enqueueAllChunkIter(flow);
495 int action =
static_cast<Derived*
>(
this)->process_data(&
fcb_data->userdata,it);
497 this->closeConnection((it.current() ? it.current() : flow->first()), true);
500 }
else if (action > 0) {
501 this->closeConnection((it.current() ? it.current() : flow->first()), true);
502 this->checked_output_push_batch(action,
fcb_data->flowBuffer.dequeueAll());
510 this->requestMorePackets(it.current(),
false);
513 this->checked_output_push_batch(action,passed);
516 void release_flow(BufferData<T>* fcb) {
517 static_cast<Derived*
>(
this)->release_stream(&fcb->userdata);
553 template <
typename T>
554 inline T clear_leftmost_set(
const T value) {
558 return value & (value - 1);
562 template <
typename T>
563 inline unsigned get_first_bit_set(
const T value) {
567 return __builtin_ctz(value);
572 inline unsigned get_first_bit_set<uint64_t>(
const uint64_t value) {
576 return __builtin_ctzl(value);
583inline size_t avx2_strstr_anysize(
const char* s,
size_t n,
const char* needle,
size_t k) {
585 const __m256i first = _mm256_set1_epi8(needle[0]);
586 const __m256i last = _mm256_set1_epi8(needle[k - 1]);
588 for (
size_t i = 0; i < n; i += 32) {
590 const __m256i block_first = _mm256_loadu_si256(
reinterpret_cast<const __m256i*
>(s + i));
591 const __m256i block_last = _mm256_loadu_si256(
reinterpret_cast<const __m256i*
>(s + i + k - 1));
593 const __m256i eq_first = _mm256_cmpeq_epi8(first, block_first);
594 const __m256i eq_last = _mm256_cmpeq_epi8(last, block_last);
596 uint32_t mask = _mm256_movemask_epi8(_mm256_and_si256(eq_first, eq_last));
600 const auto bitpos = bits::get_first_bit_set(mask);
602 if (memcmp(s + i + bitpos + 1, needle + 1, k - 2) == 0) {
606 mask = bits::clear_leftmost_set(mask);
610 return std::string::npos;
613inline size_t sse42_strstr_anysize(
const char* s,
size_t n,
const char* needle,
size_t k) {
614 const __m128i N = _mm_loadu_si128((__m128i*)needle);
616 for (
size_t i = 0; i < n; i += 16) {
618 const int mode = _SIDD_UBYTE_OPS
619 | _SIDD_CMP_EQUAL_ORDERED
622 const __m128i D = _mm_loadu_si128((__m128i*)(s + i));
623 const __m128i res = _mm_cmpestrm(N, k, D, n - i, mode);
624 uint64_t mask = _mm_cvtsi128_si64(res);
628 const auto bitpos = bits::get_first_bit_set(mask);
631 if (memcmp(s + i + bitpos + 1, needle + 1, k - 1) == 0) {
635 mask = bits::clear_leftmost_set(mask);
639 return std::string::npos;
642inline size_t sse2_strstr_anysize(
const char* s,
size_t n,
const char* needle,
size_t k) {
647 const __m128i first = _mm_set1_epi8(needle[0]);
648 const __m128i last = _mm_set1_epi8(needle[k - 1]);
650 for (
size_t i = 0; i < n; i += 16) {
652 const __m128i block_first = _mm_loadu_si128(
reinterpret_cast<const __m128i*
>(s + i));
653 const __m128i block_last = _mm_loadu_si128(
reinterpret_cast<const __m128i*
>(s + i + k - 1));
655 const __m128i eq_first = _mm_cmpeq_epi8(first, block_first);
656 const __m128i eq_last = _mm_cmpeq_epi8(last, block_last);
658 uint16_t mask = _mm_movemask_epi8(_mm_and_si128(eq_first, eq_last));
662 const auto bitpos = bits::get_first_bit_set(mask);
664 if (memcmp(s + i + bitpos + 1, needle + 1, k - 2) == 0) {
668 mask = bits::clear_leftmost_set(mask);
672 return std::string::npos;
676inline size_t aarch64_strstr_anysize(
const char* s,
size_t n,
const char* needle,
size_t k) {
681 const uint8x16_t first = vdupq_n_u8(needle[0]);
682 const uint8x16_t last = vdupq_n_u8(needle[k - 1]);
684 const uint8_t* ptr =
reinterpret_cast<const uint8_t*
>(s);
686 for (
size_t i = 0; i < n; i += 16) {
688 const uint8x16_t block_first = vld1q_u8(ptr + i);
689 const uint8x16_t block_last = vld1q_u8(ptr + i + k - 1);
691 const uint8x16_t eq_first = vceqq_u8(first, block_first);
692 const uint8x16_t eq_last = vceqq_u8(last, block_last);
693 const uint8x16_t pred_16 = vandq_u8(eq_first, eq_last);
697 mask = vgetq_lane_u64(vreinterpretq_u64_u8(pred_16), 0);
699 for (
int j=0; j < 8; j++) {
700 if ((mask & 0xff) && (memcmp(s + i + j + 1, needle + 1, k - 2) == 0)) {
708 mask = vgetq_lane_u64(vreinterpretq_u64_u8(pred_16), 1);
710 for (
int j=0; j < 8; j++) {
711 if ((mask & 0xff) && (memcmp(s + i + j + 8 + 1, needle + 1, k - 2) == 0)) {
720 return std::string::npos;
725inline char* CTXElement::searchInContent(
char *content,
const StringRef &pattern, uint32_t length) {
727 size_t pos = avx2_strstr_anysize(content, length, pattern.data(), pattern.length());
729 size_t pos = sse42_strstr_anysize(content, length, pattern.data(), pattern.length());
731 size_t pos = sse2_strstr_anysize(content, length, pattern.data(), pattern.length());
733 size_t pos = aarch64_strstr_anysize(content, length, pattern.data(), pattern.length());
735 if (pos == std::string::npos)
737 else return content + pos;
741extern CounterInitFuture _ctx_builded_init_future;
Definition ctxelement.hh:372
T * fcb_data_for(FlowControlBlock *fcb)
Definition ctxelement.hh:393
T * fcb_data()
Definition ctxelement.hh:401
bool new_flow(T *, Packet *)
Definition ctxelement.hh:386
Base class for Click elements.
Definition element.hh:42
This iterator allows to iterate the content in the buffer seamlessly accross the packets.
Definition flowbuffer.hh:216
This buffer allows to search, replace or remove data in the packets buffered as in a contiguous flow....
Definition flowbuffer.hh:40
Definition packetbatch.hh:415
A network packet.
Definition packet.hh:68
Base class for router configuration visitors.
Definition routervisitor.hh:17
This class defines a RouterVisitor that will be used to build the function stack Each element starts ...
Definition ctxelement.hh:313
~StackVisitor()
Destruct a StackVisitor.
Definition ctxelement.hh:326
StackVisitor(CTXElement *startElement)
Construct a StackVisitor.
Definition ctxelement.hh:318
bool visit(Element *e, bool, int port, Element *, int, int)
Visit the path of elements until we find a stack element. We will indicate to this element that we ar...
Definition ctxelement.cc:11
A network packet believed not to be shared.
Definition packet.hh:1004
The Router class implementing a router configuration.
Router configuration visitors for finding elements and ports.