Skip to content

Commit 51b562f

Browse files
committed
pcn-firewall: implement support for insert/delete
this commit introduces the support for: - insert: insert a rule at position id and translate forward all the following rules. by default inserts in position id=0 that means at the beginning of the ruleset - delete: delete a rule taking as parameter the rule fields (not the id). This could help in scenarios in witch we don't care about indexes. if multiple rules are present with same fields then the firts matching is taken Signed-off-by: Matteo Bertrone <m.bertrone@gmail.com>
1 parent 7e5502d commit 51b562f

6 files changed

Lines changed: 270 additions & 3 deletions

File tree

src/services/pcn-firewall/src/Chain.cpp

Lines changed: 149 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,9 +589,156 @@ void Chain::delRuleList() {
589589
}
590590

591591
ChainInsertOutputJsonObject Chain::insert(ChainInsertInputJsonObject input) {
592-
throw std::runtime_error("Chain::ChainInsertOutput: Method not implemented");
592+
ChainRuleJsonObject conf;
593+
594+
if (input.conntrackIsSet()) {
595+
conf.setConntrack(input.getConntrack());
596+
}
597+
if (input.srcIsSet()) {
598+
conf.setSrc(input.getSrc());
599+
}
600+
if (input.dstIsSet()) {
601+
conf.setDst(input.getDst());
602+
}
603+
if (input.sportIsSet()) {
604+
conf.setSport(input.getSport());
605+
}
606+
if (input.dportIsSet()) {
607+
conf.setDport(input.getDport());
608+
}
609+
if (input.tcpflagsIsSet()) {
610+
conf.setTcpflags(input.getTcpflags());
611+
}
612+
if (input.l4protoIsSet()) {
613+
conf.setL4proto(input.getL4proto());
614+
}
615+
if (input.actionIsSet()) {
616+
conf.setAction(input.getAction());
617+
} else {
618+
conf.setAction(ActionEnum::DROP);
619+
}
620+
621+
uint32_t id = 0;
622+
if (input.idIsSet()) {
623+
id = input.getId();
624+
}
625+
626+
if (id > rules_.size()) {
627+
throw std::runtime_error("id not allowed");
628+
}
629+
630+
auto newRule = std::make_shared<ChainRule>(*this, conf);
631+
632+
ChainStatsJsonObject confStats;
633+
auto newStats = std::make_shared<ChainStats>(*this, confStats);
634+
635+
getStatsList();
636+
637+
if (newRule == nullptr) {
638+
// Totally useless, but it is needed to avoid the compiler making wrong
639+
// assumptions and reordering
640+
throw new std::runtime_error("I won't be thrown");
641+
642+
} else if (rules_.size() >= id && newRule != nullptr) {
643+
rules_.resize(rules_.size() + 1);
644+
counters_.resize(counters_.size() + 1);
645+
}
646+
647+
// 0, 1, 2, 3
648+
// insert @2
649+
// 0, 1, 2*, 2->3, 3->4
650+
651+
// for rules before id
652+
// nothing
653+
654+
// for rules starting from id to rules size-1
655+
// move ahead i -> i+i
656+
// btw, better to start from the end of the array
657+
// for rules starting from size-1 to id
658+
// move ahead i -> i+i
659+
660+
int i = 0;
661+
int id_int = (int)id;
662+
663+
// ids are 0,1,2
664+
// size=3
665+
// id = 1 (insert)
666+
667+
// new size = 4
668+
669+
// from 1 to 2
670+
// move 2->3
671+
// move 1->2,
672+
// replace 1
673+
674+
for (i = rules_.size() - 2; i >= id_int; i--) {
675+
rules_[i + 1] = rules_[i];
676+
counters_[i + 1] = counters_[i];
677+
if (rules_[i + 1] != nullptr) {
678+
rules_[i + 1]->id = i + 1;
679+
}
680+
if (counters_[i + 1] != nullptr) {
681+
counters_[i + 1]->counter.setId(i + 1);
682+
}
683+
}
684+
685+
rules_[id] = newRule;
686+
rules_[id]->id = id;
687+
688+
counters_[id] = newStats;
689+
counters_[id]->counter.setPkts(0);
690+
counters_[id]->counter.setBytes(0);
691+
counters_[id]->counter.setId(id);
692+
693+
if (parent_.interactive_) {
694+
updateChain();
695+
}
696+
697+
// set fields for return object
698+
ChainInsertOutputJsonObject result;
699+
result.setId(id);
700+
701+
return result;
593702
}
594703

595704
void Chain::deletes(ChainDeleteInputJsonObject input) {
596-
throw std::runtime_error("Chain::: Method not implemented");
705+
ChainRuleJsonObject conf;
706+
707+
if (input.conntrackIsSet()) {
708+
conf.setConntrack(input.getConntrack());
709+
}
710+
if (input.srcIsSet()) {
711+
conf.setSrc(input.getSrc());
712+
}
713+
if (input.dstIsSet()) {
714+
conf.setDst(input.getDst());
715+
}
716+
if (input.sportIsSet()) {
717+
conf.setSport(input.getSport());
718+
}
719+
if (input.dportIsSet()) {
720+
conf.setDport(input.getDport());
721+
}
722+
if (input.tcpflagsIsSet()) {
723+
conf.setTcpflags(input.getTcpflags());
724+
}
725+
if (input.l4protoIsSet()) {
726+
conf.setL4proto(input.getL4proto());
727+
}
728+
if (input.actionIsSet()) {
729+
conf.setAction(input.getAction());
730+
} else {
731+
conf.setAction(ActionEnum::DROP);
732+
}
733+
734+
for (int i = 0; i < rules_.size(); i++) {
735+
if (rules_[i] != nullptr) {
736+
ChainRule c(*this, conf);
737+
if (rules_[i]->equal(c)) {
738+
delRule(i);
739+
return;
740+
}
741+
}
742+
}
743+
throw std::runtime_error("no matching rule to delete");
597744
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <condition_variable>
2121
#include <mutex>
2222
#include <thread>
23+
#include <memory>
2324

2425
#include "base/ChainBase.h"
2526

src/services/pcn-firewall/src/ChainRule.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,64 @@ uint32_t ChainRule::getId() {
194194
// This method retrieves the id value.
195195
return id;
196196
}
197+
198+
bool ChainRule::equal(ChainRule &cmp) {
199+
if (ipSrcIsSet != cmp.ipSrcIsSet)
200+
return false;
201+
if (ipSrcIsSet) {
202+
if (ipSrc.toString() != cmp.ipSrc.toString())
203+
return false;
204+
}
205+
206+
if (ipDstIsSet != cmp.ipDstIsSet)
207+
return false;
208+
if (ipDstIsSet) {
209+
if (ipDst.toString() != cmp.ipDst.toString())
210+
return false;
211+
}
212+
213+
if (srcPortIsSet != cmp.srcPortIsSet)
214+
return false;
215+
if (srcPortIsSet) {
216+
if (srcPort != cmp.srcPort)
217+
return false;
218+
}
219+
220+
if (dstPortIsSet != cmp.dstPortIsSet)
221+
return false;
222+
if (dstPortIsSet) {
223+
if (dstPort != cmp.dstPort)
224+
return false;
225+
}
226+
227+
if (l4ProtoIsSet != cmp.l4ProtoIsSet)
228+
return false;
229+
if (l4ProtoIsSet) {
230+
if (l4Proto != cmp.l4Proto)
231+
return false;
232+
}
233+
234+
if (tcpFlagsIsSet != cmp.tcpFlagsIsSet)
235+
return false;
236+
if (tcpFlagsIsSet) {
237+
if ((flagsSet != cmp.flagsSet) || ((flagsNotSet != cmp.flagsNotSet)))
238+
return false;
239+
}
240+
241+
if (actionIsSet != cmp.actionIsSet)
242+
return false;
243+
244+
if (actionIsSet) {
245+
if (action != cmp.action)
246+
return false;
247+
}
248+
249+
if (conntrackIsSet != cmp.conntrackIsSet)
250+
return false;
251+
if (conntrackIsSet) {
252+
if (conntrack != cmp.conntrack)
253+
return false;
254+
}
255+
256+
return true;
257+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class ChainRule : public ChainRuleBase {
3535
void update(const ChainRuleJsonObject &conf) override;
3636
ChainRuleJsonObject toJsonObject() override;
3737

38+
bool equal(ChainRule &cmp);
39+
3840
/// <summary>
3941
/// Description of the rule.
4042
/// </summary>

src/services/pcn-firewall/src/api/FirewallApiImpl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ create_firewall_chain_delete_by_id(const std::string &name, const ChainNameEnum
160160
auto firewall = get_cube(name);
161161
auto chain = firewall->getChain(chainName);
162162

163-
// return chain->delete(value);
163+
return chain->deletes(value);
164164
}
165165

166166
/**
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# PING testing rule appending
2+
3+
source "${BASH_SOURCE%/*}/../helpers.bash"
4+
5+
function fwcleanup {
6+
set +e
7+
polycubectl firewall del fw
8+
delete_veth 2
9+
}
10+
trap fwcleanup EXIT
11+
12+
echo -e '\nTest insert \n'
13+
set -e
14+
set -x
15+
16+
create_veth 2
17+
18+
polycubectl firewall add fw loglevel=DEBUG
19+
polycubectl attach fw veth1
20+
21+
# test simple insert rules
22+
polycubectl firewall fw chain INGRESS insert src=10.0.0.1 dst=10.0.0.2 l4proto=ICMP action=FORWARD
23+
24+
polycubectl firewall fw chain EGRESS insert src=10.0.0.2/32 dst=10.0.0.1/32 l4proto=ICMP action=FORWARD
25+
26+
sudo ip netns exec ns1 ping 10.0.0.2 -c 2 -i 0.5 -w 1
27+
28+
29+
polycubectl firewall fw chain INGRESS insert src=10.0.0.1 dst=10.0.0.2 l4proto=ICMP action=DROP
30+
31+
test_fail sudo ip netns exec ns1 ping 10.0.0.2 -c 2 -i 0.5 -w 1
32+
33+
34+
polycubectl firewall fw chain INGRESS delete src=10.0.0.1 dst=10.0.0.2 l4proto=ICMP action=DROP
35+
36+
polycubectl firewall fw chain INGRESS show
37+
38+
sudo ip netns exec ns1 ping 10.0.0.2 -c 2 -i 0.5 -w 1
39+
40+
# test insert rule in specific position
41+
polycubectl firewall fw chain INGRESS insert id=1 src=10.0.0.1 dst=10.0.0.2 l4proto=ICMP action=DROP
42+
43+
polycubectl firewall fw chain INGRESS show
44+
45+
sudo ip netns exec ns1 ping 10.0.0.2 -c 2 -i 0.5 -w 1
46+
47+
# test wrong position
48+
set +e
49+
polycubectl firewall fw chain INGRESS insert id=2 src=10.0.0.1 dst=10.0.0.2 l4proto=ICMP action=DROP
50+
polycubectl firewall fw chain INGRESS insert id=5 src=10.0.0.1 dst=10.0.0.2 l4proto=ICMP action=DROP
51+
polycubectl firewall fw chain INGRESS insert id=-1 src=10.0.0.1 dst=10.0.0.2 l4proto=ICMP action=DROP
52+
set -e
53+
54+
polycubectl firewall fw chain INGRESS show
55+
56+
sudo ip netns exec ns1 ping 10.0.0.2 -c 2 -i 0.5 -w 1

0 commit comments

Comments
 (0)