Skip to content

Commit

Permalink
Merge pull request #140 from francescomessina/shadow_mode
Browse files Browse the repository at this point in the history
Add Shadow Services
  • Loading branch information
frisso committed Jun 20, 2019
2 parents 19b8ab7 + ca8f301 commit 2692c3f
Show file tree
Hide file tree
Showing 40 changed files with 1,266 additions and 34 deletions.
56 changes: 55 additions & 1 deletion Documentation/cubes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ A standard cube:
| +----------+ |
port1---|-| |-|---port3
| | core | |
port2---|-| |-|---port3
port2---|-| |-|---port4
| +----------+ |
| |
+--------------+
Expand Down Expand Up @@ -71,6 +71,44 @@ Following is example topology composed by standard and transparent cubes.

``polycubectl ?`` shows available cubes installed on your system.


A shadow cube:
Only a standard cube can be **Shadow** type;
- ``polycubectl <cubetype> add <cubename> shadow=true``.

A shadow cube is associated with a Linux network namespace;

The parameters between the shadow cube and the namespace are aligned;

A port defined on a shadow cube is also visible from the network namespace:
- the user can decide to configure the ports using Linux (e.g. ifconfig or the ip command) or polycubectl;

for example: "``polycubectl <cubename> ports <PortName> set ip=<IpAddress>``" it is the same as "``ip netns exec pcn-<cubename> ifconfig <PortName> <IpAddress>``".
- the developer can let Linux handle some traffic by sending it to the namespace (e.g. ARP, ICMP, but in general all those protocols able to be managed by a tool running inside the namespace);

::

+--------------+
port1---| |---port3
| namespace |
port2---| |---port4
Linux +--------------+
____________________________________________________________

::

Polycube shadow cube
+--------------+
| |
| +----------+ |
port1---|-| |-|---port3
| | core | |
port2---|-| |-|---port4
| +----------+ |
| |
+--------------+


Cubes structure
---------------

Expand Down Expand Up @@ -177,3 +215,19 @@ These primitives allow to associate transparent cubes to standard cube's ports o
polycubectl attach firewall1 r1:port2

polycubectl attach firewall0 veth1


Span Mode
---------

The shadow cubes have a mode called **span**.

The span mode when activated shows all the traffic seen by the service also to the namespace.
- To activate the span mode the command used is "``polycubectl <cubename> set span=true``".

Span mode is very useful for debugging; On a shadow cube in span mode programs such as Wireshark or Tcpdump can sniff the traffic.

However, the span mode consumes many resources when it is active, so it is disabled by default and it is recommended to use it only when necessary.

N.B. Span mode duplicates traffic so that it is shown by the namespace, the cube continues to handle traffic.
For this reason, for example, if we have a shadow router with active span mode we should not have Ip forwarding active on Linux, otherwise the router service forwards packets and copies them to the namespace, the namespace forwards again packets and there will be duplications.
4 changes: 3 additions & 1 deletion Documentation/developers/controlplane.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ Generating PacketOut events

The ``Port`` class contains the ``send_packet_out(EthernetII &packet, bool recirculate = false)`` method that allows to inject packets into the datapath, the recirculate parameter allows to specify if the packet should be sent out of the port (`recirculate = false`) or received through the port (`recirculate = true`).

Only in shadow services the ``Port`` class contains the ``send_packet_ns(EthernetII &packet)`` method that allows to send packets into the service namespace.

A reference to a port can be got using the `get_port` function of the Cube base class.

Debugging and logging in the control plane
Expand All @@ -106,4 +108,4 @@ Usage example:

::

logger()->info("Connected port {0}", port_name);
logger()->info("Connected port {0}", port_name);
3 changes: 2 additions & 1 deletion Documentation/developers/datapath.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Polycube architecture adds a wrapper around the user's code, this wrapper calls

- **pcn_pkt_controller_with_metadata(struct __sk_buff *skb, struct pkt_metadata *md, u16 reason, u32 metadata[3])**: Sends the packet to the custom code running in the control path. In addition to the reason the user can also send some additional medatada.

- **pcn_pkt_redirect_ns(struct __sk_buff *skb, struct pkt_metadata *md, u16 port)**: (it is only available for shadow services) sends the packet to the namespace as if it came from the port indicated as parameter

Checksum calculation
********************

Expand Down Expand Up @@ -107,4 +109,3 @@ Usage example:
::

pcn_pkt_log(ctx, LOG_DEBUG);

25 changes: 25 additions & 0 deletions src/libs/polycube/include/polycube/services/cube.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ class Cube : public BaseCube {
void set_conf(const nlohmann::json &conf);
nlohmann::json to_json() const;

const bool get_shadow() const;
const bool get_span() const;
void set_span(const bool value);

const std::string get_veth_name_from_index(const int ifindex);
private:
std::shared_ptr<CubeIface> cube_; // pointer to the cube in polycubed
packet_in_cb handle_packet_in;
Expand Down Expand Up @@ -174,5 +179,25 @@ nlohmann::json Cube<PortType>::to_json() const {
return cube_->to_json();
}

template <class PortType>
const bool Cube<PortType>::get_shadow() const {
return cube_->get_shadow();
}

template <class PortType>
const bool Cube<PortType>::get_span() const {
return cube_->get_span();
}

template <class PortType>
void Cube<PortType>::set_span(const bool value) {
return cube_->set_span(value);
}

template <class PortType>
const std::string Cube<PortType>::get_veth_name_from_index(const int ifindex) {
return cube_->get_veth_name_from_index(ifindex);
}

} // namespace service
} // namespace polycube
6 changes: 6 additions & 0 deletions src/libs/polycube/include/polycube/services/cube_iface.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ class CubeIface : virtual public BaseCubeIface {

virtual void set_conf(const nlohmann::json &conf) = 0;
virtual nlohmann::json to_json() const = 0;

virtual const bool get_shadow() const = 0;
virtual const bool get_span() const = 0;
virtual void set_span(const bool value) = 0;

virtual const std::string get_veth_name_from_index(const int ifindex) = 0;
};

class TransparentCubeIface : virtual public BaseCubeIface {
Expand Down
1 change: 1 addition & 0 deletions src/libs/polycube/include/polycube/services/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class Port {
Port(std::shared_ptr<PortIface> port);
~Port();
void send_packet_out(EthernetII &packet, bool recirculate = false);
void send_packet_ns(EthernetII &packet);
int index() const;
std::string name() const;
void set_peer(const std::string &peer);
Expand Down
1 change: 1 addition & 0 deletions src/libs/polycube/include/polycube/services/port_iface.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class PortIface {
public:
virtual void send_packet_out(const std::vector<uint8_t> &packet,
bool recirculate = false) = 0;
virtual void send_packet_ns(const std::vector<uint8_t> &packet) = 0;
virtual uint16_t index() const = 0;
virtual bool operator==(const PortIface &rhs) const = 0;
virtual std::string name() const = 0;
Expand Down
8 changes: 8 additions & 0 deletions src/libs/polycube/include/polycube/services/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ std::string get_ip_from_string(const std::string &ipv_net);
* length" -> 24 in this case */
std::string get_netmask_from_string(const std::string &ipv_net);

/* Take in ingress a string like 255.255.255.0 and return the "prefix
* length" -> 24 in this case */
uint32_t get_netmask_length(const std::string &netmask_string);

/* Take in ingress a prefix length like 24 and return the
* "netmask" -> 255.255.255.0 in this case */
std::string get_netmask_from_CIDR(const int cidr);

/*
* formats a debug string, custom specifiers are evaluated by a
* custom implemented logic
Expand Down
9 changes: 9 additions & 0 deletions src/libs/polycube/src/port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Port::impl {
impl(Port &op);
~impl();
void send_packet_out(EthernetII &packet, bool recirculate);
void send_packet_ns(EthernetII &packet);
int index() const;
std::string name() const;
void set_peer(const std::string &peer);
Expand Down Expand Up @@ -104,6 +105,10 @@ void Port::impl::send_packet_out(EthernetII &packet, bool recirculate) {
port_->send_packet_out(packet.serialize(), recirculate);
}

void Port::impl::send_packet_ns(EthernetII &packet) {
port_->send_packet_ns(packet.serialize());
}

PortStatus Port::impl::get_status() const {
return port_->get_status();
}
Expand All @@ -129,6 +134,10 @@ void Port::send_packet_out(EthernetII &packet, bool recirculate) {
return pimpl_->send_packet_out(packet, recirculate);
}

void Port::send_packet_ns(EthernetII &packet) {
return pimpl_->send_packet_ns(packet);
}

int Port::index() const {
return pimpl_->index();
}
Expand Down
30 changes: 30 additions & 0 deletions src/libs/polycube/src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,36 @@ std::string get_netmask_from_string(const std::string &ipv) {
return ipv_net.substr(pos + 1, std::string::npos);
}

uint32_t get_netmask_length(const std::string &netmask_string) {
struct in_addr buf;
char address[100];
int res = inet_pton(
AF_INET, netmask_string.c_str(),
&buf); /*convert ip address in binary form in network byte order */

if (res == 1) {
uint32_t counter = 0;
int n = buf.s_addr;
while (n) {
counter++;
n &= (n - 1);
}
return counter;
} else
throw std::runtime_error("IP Address is not in a valid format");
}

std::string get_netmask_from_CIDR(const int cidr) {
uint32_t ipv4Netmask;

ipv4Netmask = 0xFFFFFFFF;
ipv4Netmask <<= 32 - cidr;
ipv4Netmask = ntohl(ipv4Netmask);
struct in_addr addr = {ipv4Netmask};

return inet_ntoa(addr);
}

} // namespace utils
} // namespace service
} // namespace polycube
67 changes: 66 additions & 1 deletion src/polycubed/src/base_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,69 @@ Response BaseModel::set_port_peer(const std::string &cube_name,
return Response{kOk, ::strdup("")};
}

} // namespace polycube::polycubed
Response BaseModel::get_shadow(const std::string &cube_name) const {
auto cube_ = ServiceController::get_cube(cube_name);
if (cube_ == nullptr) {
return Response{kNoContent, ::strdup("Cube does not exist")};
}

// TODO: is this case even possible?
auto cube = std::dynamic_pointer_cast<CubeIface>(cube_);
if (cube == nullptr) {
return Response{kNoContent, ::strdup("Cube is transparent")};
}

std::string _shadow;
if (cube->get_shadow()) {
_shadow = "true";
} else {
_shadow = "false";
}
auto shadow = "\"" + _shadow + "\"";

return Response{kOk, ::strdup(shadow.data())};
}

Response BaseModel::get_span(const std::string &cube_name) const {
auto cube_ = ServiceController::get_cube(cube_name);
if (cube_ == nullptr) {
return Response{kNoContent, ::strdup("Cube does not exist")};
}

// TODO: is this case even possible?
auto cube = std::dynamic_pointer_cast<CubeIface>(cube_);
if (cube == nullptr) {
return Response{kNoContent, ::strdup("Cube is transparent")};
}

std::string _span;
if (cube->get_span()) {
_span = "true";
} else {
_span = "false";
}
auto span = "\"" + _span + "\"";

return Response{kOk, ::strdup(span.data())};
}

Response BaseModel::set_span(const std::string &cube_name,
const nlohmann::json &json) {
auto cube_ = ServiceController::get_cube(cube_name);
if (cube_ == nullptr) {
return Response{kNoContent, ::strdup("Cube does not exist")};
}

// TODO: is this case even possible?
auto cube = std::dynamic_pointer_cast<CubeIface>(cube_);
if (cube == nullptr) {
return Response{kNoContent, ::strdup("Cube is transparent")};
}

auto _span = json.get<bool>();
cube->set_span(_span);

return Response{kOk, ::strdup("")};
}

} // namespace polycube::polycubed
6 changes: 5 additions & 1 deletion src/polycubed/src/base_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ class BaseModel {
Response set_port_peer(const std::string &cube_name,
const std::string &port_name,
const nlohmann::json &json);
Response get_shadow(const std::string &cube_name) const;
Response get_span(const std::string &cube_name) const;
Response set_span(const std::string &cube_name,
const nlohmann::json &json);
};

} // namespace polycube::polycubed
} // namespace polycube::polycubed

0 comments on commit 2692c3f

Please sign in to comment.