Skip to content

Commit e1c7af1

Browse files
committed
pcn-firewall: introduce datapath pipeline early break
this commit introduces the support for some firewall filtering pipeline modules to early break the pipeline if no rule is matched. the idea is that during the execution of the pipeline some modules are implemented in a way in wich the cost of checking if the resulting bitvector is all zero is almost negligible. this support enables to speedup the execution since is no longer needed to go through all the pipeline modules if this condition is matched. Signed-off-by: Matteo Bertrone <m.bertrone@gmail.com>
1 parent b64e0fa commit e1c7af1

6 files changed

Lines changed: 159 additions & 15 deletions

File tree

src/services/pcn-firewall/src/Firewall.h

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,16 +223,21 @@ class Firewall : public FirewallBase {
223223
};
224224

225225
class L4PortLookup : public Program {
226-
private:
227-
int type; // SOURCE or DESTINATION
228-
229226
public:
230227
L4PortLookup(const int &index, const ChainNameEnum &direction,
231228
const int &type, Firewall &outer);
229+
L4PortLookup(const int &index, const ChainNameEnum &chain, const int &type,
230+
Firewall &outer,
231+
const std::map<uint16_t, std::vector<uint64_t>> &ports);
232232
~L4PortLookup();
233233
std::string getCode();
234234
bool updateTableValue(uint16_t port, const std::vector<uint64_t> &value);
235235
void updateMap(const std::map<uint16_t, std::vector<uint64_t>> &ports);
236+
237+
private:
238+
int type; // SOURCE or DESTINATION
239+
bool wildcard_rule_;
240+
std::string wildcard_string_;
236241
};
237242

238243
class TcpFlagsLookup : public Program {
@@ -318,4 +323,29 @@ class Firewall : public FirewallBase {
318323

319324
static void replaceAll(std::string &str, const std::string &from,
320325
const std::string &to);
326+
327+
template <typename Iterator>
328+
static std::string fromContainerToMapString(Iterator begin, Iterator end,
329+
const std::string open,
330+
const std::string close,
331+
const std::string separator);
321332
};
333+
334+
template <typename Iterator>
335+
std::string Firewall::fromContainerToMapString(Iterator it, Iterator end,
336+
const std::string open,
337+
const std::string close,
338+
const std::string separator) {
339+
std::string result = open;
340+
bool first = true;
341+
int cnt = 0;
342+
for (; it != end; ++it) {
343+
cnt++;
344+
if (!first)
345+
result += separator;
346+
first = false;
347+
result += /*"-" + */ std::to_string((*it));
348+
}
349+
result += close;
350+
return result;
351+
}

src/services/pcn-firewall/src/datapaths/Firewall_IpLookup_dp.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,26 @@ static int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {
8787
} else {
8888
/*#pragma unroll does not accept a loop with a single iteration, so we need to
8989
* distinguish cases to avoid a verifier error.*/
90+
bool isAllZero = true;
9091
#if _NR_ELEMENTS == 1
9192
(result->bits)[0] = (result->bits)[0] & (ele->bits)[0];
93+
if (result->bits[0] != 0)
94+
isAllZero = false;
9295
#else
9396
#pragma unroll
9497
for (int i = 0; i < _NR_ELEMENTS; ++i) {
9598
/*This is the first module, it initializes the percpu*/
9699
(result->bits)[i] = (result->bits)[i] & (ele->bits)[i];
97-
}
98100

101+
if (result->bits[i] != 0)
102+
isAllZero = false;
103+
}
99104
#endif
105+
if (isAllZero) {
106+
pcn_log(ctx, LOG_DEBUG,
107+
"[_CHAIN_NAME][IP_TYPE]: Bitvector is all zero. Break pipeline");
108+
_DEFAULTACTION
109+
}
100110
} // if result == NULL
101111
} // if ele==NULL
102112
call_next_program(ctx, _NEXT_HOP_1);

src/services/pcn-firewall/src/datapaths/Firewall_L4PortLookup_dp.c

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ static __always_inline struct elements *getBitVect(uint16_t *key) {
5757
#endif
5858

5959
static int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {
60+
#if _WILDCARD_RULE
61+
u64 wildcard_ele[_MAXRULES] = _WILDCARD_BITVECTOR;
62+
#endif
63+
6064
/*The struct elements and the lookup table are defined only if _NR_ELEMENTS>0,
6165
* so
6266
* this code has to be used only in this case.*/
@@ -78,35 +82,79 @@ static int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {
7882
_TYPEPort = pkt->_TYPEPort;
7983
}
8084

81-
struct elements *ele = getBitVect(&_TYPEPort);
85+
// Ports are stored in an hashmap
86+
// A. map[0] (if exists) contains wildcard match
87+
// B. map[port] (if some exists) contain ports matching
88+
89+
// if no match in A. and B.
90+
// we assume current bitvector is 0x000000...
91+
// also AND returns 0x0000...
92+
// so we can apply DEFAULT action with no additional cost.
8293

83-
if (ele == NULL) {
84-
_TYPEPort = 0;
85-
ele = getBitVect(&_TYPEPort);
86-
if (ele == NULL) {
87-
pcn_log(ctx, LOG_DEBUG, "[_CHAIN_NAME][L4PortLookup_TYPE]: No match");
88-
_DEFAULTACTION
89-
}
90-
}
9194
struct elements *result = getShared();
95+
96+
bool isAllZero = true;
9297
if (result == NULL) {
9398
/*Can't happen. The PERCPU is preallocated.*/
9499
return RX_DROP;
95100
} else {
101+
struct elements *ele = getBitVect(&_TYPEPort);
102+
103+
if (ele == NULL) {
104+
// if lookup with port fails, we have to
105+
// a. verify if we have a wildcard key (0)
106+
// b. if so, use to bitvector from wildcard key
107+
108+
#if _WILDCARD_RULE
109+
pcn_log(ctx, LOG_DEBUG, "[_CHAIN_NAME][L4PortLookup_TYPE]: +WILDCARD RULE+");
110+
goto WILDCARD;
111+
#else
112+
pcn_log(ctx, LOG_DEBUG, "[_CHAIN_NAME][L4PortLookup_TYPE]: No match. ");
113+
_DEFAULTACTION
114+
#endif
115+
}
116+
96117
/*#pragma unroll does not accept a loop with a single iteration, so we need to
97-
* distinguish cases to avoid a verifier error.*/
118+
* distinguish cases to avoid a verifier error.*/
98119
#if _NR_ELEMENTS == 1
99120
(result->bits)[0] = (ele->bits)[0] & (result->bits)[0];
121+
if (result->bits[0] != 0)
122+
isAllZero = false;
123+
goto NEXT;
124+
125+
#if _WILDCARD_RULE
126+
WILDCARD:;
127+
(result->bits)[0] = wildcard_ele[0] & (result->bits)[0];
128+
if (result->bits[0] != 0)
129+
isAllZero = false;
130+
#endif
100131
#else
101132
int i = 0;
102133
#pragma unroll
103134
for (i = 0; i < _NR_ELEMENTS; ++i) {
104135
(result->bits)[i] = (result->bits)[i] & (ele->bits)[i];
136+
if (result->bits[i] != 0)
137+
isAllZero = false;
105138
}
106-
139+
goto NEXT;
140+
#if _WILDCARD_RULE
141+
WILDCARD:;
142+
#pragma unroll
143+
for (i = 0; i < _NR_ELEMENTS; ++i) {
144+
(result->bits)[i] = wildcard_ele[i] & (result->bits)[i];
145+
if (result->bits[i] != 0)
146+
isAllZero = false;
147+
}
148+
#endif
107149
#endif
108150
} // if result == NULL
109151

152+
NEXT:;
153+
if (isAllZero) {
154+
pcn_log(ctx, LOG_DEBUG,
155+
"[_CHAIN_NAME][L4PortLookup_TYPE]: Bitvector is all zero. Break pipeline");
156+
_DEFAULTACTION
157+
}
110158
call_next_program(ctx, _NEXT_HOP_1);
111159
#else
112160
return RX_DROP;

src/services/pcn-firewall/src/datapaths/Firewall_L4ProtocolLookup_dp.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,29 @@ static int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {
8484
/*Can't happen. The PERCPU is preallocated.*/
8585
return RX_DROP;
8686
} else {
87+
bool isAllZero = true;
8788
/*#pragma unroll does not accept a loop with a single iteration, so we need to
8889
* distinguish cases to avoid a verifier error.*/
8990
#if _NR_ELEMENTS == 1
9091
(result->bits)[0] = (ele->bits)[0] & (result->bits)[0];
92+
if (result->bits[0])
93+
isAllZero = false;
9194
#else
9295
int i = 0;
9396
#pragma unroll
9497
for (i = 0; i < _NR_ELEMENTS; ++i) {
9598
(result->bits)[i] = (result->bits)[i] & (ele->bits)[i];
99+
100+
if (result->bits[i])
101+
isAllZero = false;
96102
}
97103

98104
#endif
105+
if (isAllZero) {
106+
pcn_log(ctx, LOG_DEBUG,
107+
"[_CHAIN_NAME][L4ProtoLookup]: Bitvector is all zero. Break pipeline");
108+
_DEFAULTACTION
109+
}
99110
} // if result == NULL
100111

101112
call_next_program(ctx, _NEXT_HOP_1);

src/services/pcn-firewall/src/datapaths/Firewall_TcpFlagsLookup_dp.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,11 @@ static int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {
8888
} else {
8989
/*#pragma unroll does not accept a loop with a single iteration, so we need to
9090
* distinguish cases to avoid a verifier error.*/
91+
bool isAllZero = true;
9192
#if _NR_ELEMENTS == 1
9293
(result->bits)[0] = (result->bits)[0] & (ele->bits)[0];
94+
if (result->bits[0])
95+
isAllZero = false;
9396
pcn_log(ctx, LOG_DEBUG,
9497
"[_CHAIN_NAME][TCPFlagsLookup]: Match found. Bitvec: %llu, result %llu.",
9598
(ele->bits)[0], (result->bits)[0]);
@@ -98,9 +101,16 @@ static int handle_rx(struct CTXTYPE *ctx, struct pkt_metadata *md) {
98101
#pragma unroll
99102
for (i = 0; i < _NR_ELEMENTS; ++i) {
100103
(result->bits)[i] = (result->bits)[i] & (ele->bits)[i];
104+
if (result->bits[i])
105+
isAllZero = false;
101106
}
102107

103108
#endif
109+
if (isAllZero) {
110+
pcn_log(ctx, LOG_DEBUG,
111+
"[_CHAIN_NAME][TCPFlagsLookup]: Bitvector is all zero. Break pipeline.");
112+
_DEFAULTACTION
113+
}
104114
} // if result == NULL
105115
} // if ele==NULL
106116

src/services/pcn-firewall/src/modules/L4PortLookup.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,34 @@ Firewall::L4PortLookup::L4PortLookup(const int &index,
2222
const int &type, Firewall &outer)
2323
: Firewall::Program(firewall_code_l4portlookup, index, direction, outer) {
2424
this->type = type;
25+
26+
wildcard_rule_ = false;
27+
wildcard_string_ = "";
28+
29+
load();
30+
}
31+
32+
Firewall::L4PortLookup::L4PortLookup(const int &index,
33+
const ChainNameEnum &direction,
34+
const int &type, Firewall &outer,
35+
const std::map<uint16_t, std::vector<uint64_t>> &ports)
36+
: Firewall::Program(firewall_code_l4portlookup, index, direction, outer) {
37+
38+
this->type = type;
39+
40+
auto it = ports.find(0);
41+
if (it == ports.end()) {
42+
wildcard_rule_ = false;
43+
wildcard_string_ = "";
44+
// std::cout << "-- wildcard NO --+" << std::endl;
45+
} else {
46+
wildcard_rule_ = true;
47+
wildcard_string_ = fromContainerToMapString(
48+
it->second.begin(), it->second.end(), "{", "}", ",");
49+
// std::cout << "-- wildcard YES --+" << std::endl;
50+
// std::cout << wildcardString << std::endl;
51+
}
52+
2553
load();
2654
}
2755

@@ -54,6 +82,13 @@ std::string Firewall::L4PortLookup::getCode() {
5482
/*Replacing the default action*/
5583
replaceAll(noMacroCode, "_DEFAULTACTION", defaultActionString());
5684

85+
if (wildcard_rule_) {
86+
replaceAll(noMacroCode, "_WILDCARD_RULE", std::to_string(1));
87+
replaceAll(noMacroCode, "_WILDCARD_BITVECTOR", wildcard_string_);
88+
} else {
89+
replaceAll(noMacroCode, "_WILDCARD_RULE", std::to_string(0));
90+
}
91+
5792
return noMacroCode;
5893
}
5994

0 commit comments

Comments
 (0)