Skip to content

Commit 7305045

Browse files
Shadow and Span:
This commit introduces the following points: - create a namespace for each new shadow service - create a veth and configure the its parameters (if available) - creates a second "hidden" port for each new port created on the shadow service and connects it to the veth - manages incoming traffic on the second port (traffic generated by the namespace) and forwards it out - defines the method "pcn_pkt_redirect_ns()" useful to developers to send the packets to the namespace - handles the Span mode directly in the cube_tc class (only if active) Signed-off-by: francescomessina <francescomessina92@hotmail.com>
1 parent 0ffebeb commit 7305045

6 files changed

Lines changed: 287 additions & 7 deletions

File tree

src/libs/polycube/include/polycube/services/cube.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class Cube : public BaseCube {
5151
const bool get_shadow() const;
5252
const bool get_span() const;
5353
void set_span(const bool value);
54+
55+
const std::string get_veth_name_from_index(const int ifindex);
5456
private:
5557
std::shared_ptr<CubeIface> cube_; // pointer to the cube in polycubed
5658
packet_in_cb handle_packet_in;
@@ -192,5 +194,10 @@ void Cube<PortType>::set_span(const bool value) {
192194
return cube_->set_span(value);
193195
}
194196

197+
template <class PortType>
198+
const std::string Cube<PortType>::get_veth_name_from_index(const int ifindex) {
199+
return cube_->get_veth_name_from_index(ifindex);
200+
}
201+
195202
} // namespace service
196203
} // namespace polycube

src/libs/polycube/include/polycube/services/cube_iface.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ class CubeIface : virtual public BaseCubeIface {
8888
virtual const bool get_shadow() const = 0;
8989
virtual const bool get_span() const = 0;
9090
virtual void set_span(const bool value) = 0;
91+
92+
virtual const std::string get_veth_name_from_index(const int ifindex) = 0;
9193
};
9294

9395
class TransparentCubeIface : virtual public BaseCubeIface {

src/polycubed/src/cube.cpp

Lines changed: 119 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@
1616

1717
#include "cube.h"
1818

19+
#include <net/if.h>
1920
#include "port_tc.h"
2021
#include "port_xdp.h"
22+
#include "utils/ns.h"
23+
#include "polycube/services/utils.h"
24+
25+
const std::string prefix_ns = "pcn-";
26+
const std::string prefix_port = "ns_port_";
2127

2228
namespace polycube {
2329
namespace polycubed {
@@ -26,7 +32,7 @@ Cube::Cube(const std::string &name, const std::string &service_name,
2632
PatchPanel &patch_panel_ingress, PatchPanel &patch_panel_egress,
2733
LogLevel level, CubeType type, bool shadow, bool span)
2834
: BaseCube(name, service_name, MASTER_CODE, patch_panel_ingress,
29-
patch_panel_egress, level, type) {
35+
patch_panel_egress, level, type), shadow_(shadow), span_(span) {
3036
std::lock_guard<std::mutex> guard(bcc_mutex);
3137

3238
auto forward_ = master_program_->get_array_table<uint32_t>("forward_chain_");
@@ -37,14 +43,25 @@ Cube::Cube(const std::string &name, const std::string &service_name,
3743
for (uint16_t i = 0; i < _POLYCUBE_MAX_PORTS; i++)
3844
free_ports_.insert(i);
3945

40-
shadow_ = shadow;
41-
span_ = span;
46+
if (!shadow_ && span_) {
47+
throw std::runtime_error("Span mode is not present in no-shadow services");
48+
}
49+
if (shadow_) {
50+
std::string name_ns = prefix_ns + name;
51+
Namespace ns = Namespace::create(name_ns);
52+
ns.set_random_id();
53+
}
4254
}
4355

4456
Cube::~Cube() {
4557
for (auto &it : ports_by_name_) {
4658
it.second->set_peer("");
4759
}
60+
if (get_shadow()) {
61+
std::string name_ns = prefix_ns + get_name();
62+
Namespace ns = Namespace::open(name_ns);
63+
ns.remove();
64+
}
4865
}
4966

5067
std::string Cube::get_wrapper_code() {
@@ -104,6 +121,9 @@ std::shared_ptr<PortIface> Cube::add_port(const std::string &name,
104121
if (ports_by_name_.count(name) != 0) {
105122
throw std::runtime_error("Port " + name + " already exists");
106123
}
124+
if (get_shadow() && (name.find(prefix_port) != std::string::npos)) {
125+
throw std::runtime_error("Port name cannot contain '" + prefix_port + "'");
126+
}
107127
auto id = allocate_port_id();
108128

109129
std::shared_ptr<PortIface> port;
@@ -133,6 +153,61 @@ std::shared_ptr<PortIface> Cube::add_port(const std::string &name,
133153
throw;
134154
}
135155

156+
if (get_shadow()) {
157+
// create a veth and move it in the namespace
158+
std::string name_peerB = get_name() + "-" + name;
159+
std::shared_ptr<Veth> veth = std::make_shared<Veth>(Veth::create(name, name_peerB));
160+
VethPeer peerA = veth->get_peerA();
161+
VethPeer peerB = veth->get_peerB();
162+
int ifindex = if_nametoindex(name.c_str());
163+
164+
peerB.set_status(IFACE_STATUS::UP);
165+
peerA.set_namespace(prefix_ns + get_name());
166+
peerA.set_status(IFACE_STATUS::UP);
167+
if (conf.count("ip") && conf.count("netmask")) {
168+
int prefix = polycube::service::utils::get_netmask_length(conf.at("netmask").get<std::string>());
169+
peerA.set_ip(conf.at("ip").get<std::string>(), prefix);
170+
} else if (conf.count("ipv6")) {
171+
peerA.set_ipv6(conf.at("ipv6").get<std::string>());
172+
}
173+
if (conf.count("mac")) {
174+
peerA.set_mac(conf.at("mac").get<std::string>());
175+
}
176+
177+
std::string name2 = prefix_port + name;
178+
nlohmann::json conf2 = nlohmann::json::object();
179+
conf2["name"] = name2;
180+
conf2["peer"] = name_peerB;
181+
182+
auto id2 = allocate_port_id();
183+
std::shared_ptr<PortIface> port2;
184+
185+
switch (type_) {
186+
case CubeType::TC:
187+
port2 = std::make_shared<PortTC>(*this, name2, id2, conf2);
188+
break;
189+
case CubeType::XDP_SKB:
190+
case CubeType::XDP_DRV:
191+
port2 = std::make_shared<PortXDP>(*this, name2, id2, conf2);
192+
break;
193+
}
194+
195+
ports_by_name_.emplace(name2, port2);
196+
ports_by_index_.emplace(id2, port2);
197+
veth_by_name_.emplace(name, veth);
198+
ifindex_veth_.emplace(ifindex, name);
199+
200+
try {
201+
port2->set_peer(name_peerB);
202+
} catch(...) {
203+
ports_by_name_.erase(name2);
204+
ports_by_index_.erase(id2);
205+
veth_by_name_.erase(name);
206+
ifindex_veth_.erase(ifindex);
207+
throw;
208+
}
209+
}
210+
136211
return std::move(port);
137212
}
138213

@@ -154,6 +229,32 @@ void Cube::remove_port(const std::string &name) {
154229
ports_by_name_.erase(name);
155230
ports_by_index_.erase(index);
156231
release_port_id(index);
232+
233+
cube_mutex_.unlock();
234+
if (get_shadow()) {
235+
// remove the veth
236+
try {
237+
veth_by_name_.at(name)->remove();
238+
veth_by_name_.erase(name);
239+
} catch (...) {
240+
logger->trace("veth {0} not found", name);
241+
}
242+
243+
for (auto const& [key, val] : ifindex_veth_) {
244+
if (val == name) {
245+
ifindex_veth_.erase(key);
246+
break;
247+
}
248+
}
249+
250+
// remove the second port
251+
std::string name2 = prefix_port + name;
252+
ports_by_name_.at(name2)->set_peer("");
253+
auto index2 = ports_by_name_.at(name2)->index();
254+
ports_by_name_.erase(name2);
255+
ports_by_index_.erase(index2);
256+
release_port_id(index2);
257+
}
157258
}
158259

159260
std::shared_ptr<PortIface> Cube::get_port(const std::string &name) {
@@ -183,7 +284,21 @@ const bool Cube::get_span() const {
183284
}
184285

185286
void Cube::set_span(const bool value) {
186-
span_ = value;
287+
if (shadow_)
288+
span_ = value;
289+
else
290+
throw std::runtime_error("Span mode is not present in no-shadow services");
291+
}
292+
293+
/* returns the name of the veth given the ifindex */
294+
const std::string Cube::get_veth_name_from_index(const int ifindex) {
295+
std::string name;
296+
try {
297+
name = ifindex_veth_.at(ifindex);
298+
} catch (...) {
299+
name = "";
300+
}
301+
return name;
187302
}
188303

189304
const std::string Cube::MASTER_CODE = R"(

src/polycubed/src/cube.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "polycube/services/guid.h"
2626
#include "polycube/services/json.hpp"
2727
#include "polycube/services/port_iface.h"
28+
#include "utils/veth.h"
2829

2930
#include <api/BPF.h>
3031
#include <api/BPFTable.h>
@@ -44,6 +45,8 @@ using polycube::service::CubeIface;
4445
using polycube::service::PortIface;
4546
using polycube::service::ProgramType;
4647
using polycube::service::CubeType;
48+
using polycube::service::PacketIn;
49+
using polycube::service::PortStatus;
4750

4851
namespace polycube {
4952
namespace polycubed {
@@ -69,6 +72,8 @@ class Cube : public BaseCube, public CubeIface {
6972
const bool get_shadow() const;
7073
const bool get_span() const;
7174
void set_span(const bool value);
75+
76+
const std::string get_veth_name_from_index(const int ifindex);
7277
protected:
7378
static std::string get_wrapper_code();
7479
uint16_t allocate_port_id();
@@ -80,8 +85,11 @@ class Cube : public BaseCube, public CubeIface {
8085
std::map<int, std::shared_ptr<PortIface>> ports_by_index_;
8186
std::set<uint16_t> free_ports_; // keeps track of available ports
8287

88+
std::map<std::string, std::shared_ptr<Veth>> veth_by_name_;
89+
std::map<int, std::string> ifindex_veth_;
8390
bool shadow_;
8491
bool span_;
92+
8593
private:
8694
// ebpf wrappers
8795
static const std::string MASTER_CODE;

0 commit comments

Comments
 (0)