Skip to content

Commit

Permalink
Merge pull request #249 from polycube-network/jpi-attach-pr
Browse files Browse the repository at this point in the history
fix polycubed crash & add a CLI to check the cubes given a interface
  • Loading branch information
goldenrye committed Dec 7, 2019
2 parents 41c47cf + bf62045 commit 2341f85
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 23 deletions.
85 changes: 65 additions & 20 deletions src/polycubed/src/extiface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const std::string PARAMETER_MAC = "MAC";
const std::string PARAMETER_IP = "IP";
const std::string PARAMETER_PEER = "PEER";

std::set<std::string> ExtIface::used_ifaces;
std::map<std::string, ExtIface*> ExtIface::used_ifaces;

ExtIface::ExtIface(const std::string &iface)
: PeerIface(iface_mutex_),
Expand All @@ -43,7 +43,7 @@ ExtIface::ExtIface(const std::string &iface)
throw std::runtime_error("Iface already in use");
}

used_ifaces.insert(iface);
used_ifaces.insert({iface, this});

// Save the ifindex
ifindex_iface = if_nametoindex(iface.c_str());
Expand All @@ -60,6 +60,14 @@ ExtIface::~ExtIface() {
used_ifaces.erase(iface_);
}

ExtIface* ExtIface::get_extiface(const std::string &iface_name) {
if (used_ifaces.count(iface_name) == 0) {
return NULL;
}

return used_ifaces[iface_name];
}

uint16_t ExtIface::get_index() const {
return index_;
}
Expand Down Expand Up @@ -172,39 +180,82 @@ void ExtIface::set_next(uint16_t next, ProgramType type) {
}
}

TransparentCube* ExtIface::get_next_cube(ProgramType type) {
auto next = get_next(type);
for (auto &it : cubes_) {
if (it->get_index(type) == next) {
return it;
}
}
return NULL;
}

uint16_t ExtIface::get_next(ProgramType type) {
int zero = 0;
unsigned int value = 0;
auto program = (type == ProgramType::INGRESS) ? &ingress_program_ : &egress_program_;
auto index_map = program->get_array_table<uint32_t>("index_map");
auto st = index_map.get_value(zero, value);
if (st.code() == -1) {
logger->error("failed to get interface {0} nexthop", get_iface_name());
}

return value & 0xffff;
}

std::vector<std::string> ExtIface::get_service_chain(ProgramType type) {
std::vector<std::string> chain;
TransparentCube *cube;
auto nh = get_next(type);

while (nh != 0xffff) {
cube = NULL;
for (auto c : cubes_) {
if (c->get_index(type) == nh) {
cube = c;
break;
}
}
chain.push_back(cube ? cube->get_name() : "unknown");
nh = cube->get_next(type);
}
chain.push_back(nh==0xffff ? "stack" : "unknown");

return chain;
}

void ExtIface::update_indexes() {
int i;

// TODO: could we avoid to recalculate in case there is not peer?

std::vector<uint16_t> ingress_indexes(cubes_.size());
std::vector<uint16_t> egress_indexes(cubes_.size());
std::vector<uint16_t> ingress_indexes(cubes_.size(), 0xffff) ;
std::vector<uint16_t> egress_indexes(cubes_.size(), 0xffff);

for (i = 0; i < cubes_.size(); i++) {
ingress_indexes[i] = cubes_[i]->get_index(ProgramType::INGRESS);
egress_indexes[i] = cubes_[i]->get_index(ProgramType::EGRESS);
}

// ingress chain: NIC -> cube[N-1] -> ... -> cube[0] -> stack (or peer)
// ingress chain: NIC -> cube[0] -> ... -> cube[n-1] -> stack (or peer)
// CASE2: cube[0] -> stack (or)
for (i = 0; i < cubes_.size(); i++) {
if (ingress_indexes[i]) {
for (i = cubes_.size() - 1; i >= 0; i--) {
if (ingress_indexes[i] != 0xffff) {
cubes_[i]->set_next(peer_ ? peer_->get_index() : 0xffff,
ProgramType::INGRESS);
break;
}
}

// cube[N-1] -> ... -> cube[0]
for (int j = i + 1; j < cubes_.size(); j++) {
if (ingress_indexes[j]) {
for (int j = i - 1; j >= 0; j--) {
if (ingress_indexes[j] != 0xffff) {
cubes_[j]->set_next(ingress_indexes[i], ProgramType::INGRESS);
i = j;
}
}

// CASE4: NIC -> cube[N-1] or peer
if (i < cubes_.size() && ingress_indexes[i]) {
if (i >= 0 && ingress_indexes[i] != 0xffff) {
set_next(ingress_indexes[i], ProgramType::INGRESS);
} else {
set_next(peer_ ? peer_->get_index() : 0, ProgramType::INGRESS);
Expand All @@ -214,7 +265,7 @@ void ExtIface::update_indexes() {

// cube[0] -> "egress"
for (i = 0; i < cubes_.size(); i++) {
if (egress_indexes[i]) {
if (egress_indexes[i] != 0xffff) {
cubes_[i]->set_next(0xffff, ProgramType::EGRESS);
break;
}
Expand All @@ -227,14 +278,14 @@ void ExtIface::update_indexes() {

// cubes[N-1] -> ... -> cube[0]
for (int j = i + 1; j < cubes_.size(); j++) {
if (egress_indexes[j]) {
if (egress_indexes[j] != 0xffff) {
cubes_[j]->set_next(egress_indexes[i], ProgramType::EGRESS);
i = j;
}
}

// "nic" -> cubes[N-1] or peer
if (i < cubes_.size() && egress_indexes[i]) {
if (i < cubes_.size() && egress_indexes[i] != 0xffff) {
set_next(egress_indexes[i], ProgramType::EGRESS);
} else {
Port *peer_port = dynamic_cast<Port *>(peer_);
Expand All @@ -243,12 +294,6 @@ void ExtIface::update_indexes() {
}
}

// in external ifaces the cubes must be allocated in the inverse order.
// first is the one that hits ingress traffic.
int ExtIface::calculate_cube_index(int index) {
return 0 - index;
}

bool ExtIface::is_used() const {
std::lock_guard<std::mutex> guard(iface_mutex_);
return cubes_.size() > 0 || peer_ != nullptr;
Expand Down
13 changes: 11 additions & 2 deletions src/polycubed/src/extiface.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ class ExtIface : public PeerIface {
ExtIface(const ExtIface &) = delete;
ExtIface &operator=(const ExtIface &) = delete;

/* return ExtIface pointer given interface name
* or return null if
* - either the interface name doesn't exist
* - or no extiface created for the interface name
*/
static ExtIface* get_extiface(const std::string &iface_name);

uint16_t get_index() const override;
uint16_t get_port_id() const override;
void set_peer_iface(PeerIface *peer) override;
Expand All @@ -59,6 +66,9 @@ class ExtIface : public PeerIface {
std::string get_parameter(const std::string &param_name) override;
void set_parameter(const std::string &param_name,
const std::string &value) override;
uint16_t get_next(ProgramType type);
TransparentCube* get_next_cube(ProgramType type);
std::vector<std::string> get_service_chain(ProgramType type);

protected:
// 2 maps: one for IP events and one for MAC events
Expand All @@ -71,7 +81,7 @@ class ExtIface : public PeerIface {

std::mutex event_mutex;

static std::set<std::string> used_ifaces;
static std::map<std::string, ExtIface*> used_ifaces;
int load_ingress();
int load_egress();
int load_tx();
Expand All @@ -82,7 +92,6 @@ class ExtIface : public PeerIface {
virtual bpf_prog_type get_program_type() const = 0;

void update_indexes() override;
int calculate_cube_index(int index) override;

ebpf::BPF ingress_program_;
ebpf::BPF egress_program_;
Expand Down
28 changes: 27 additions & 1 deletion src/polycubed/src/peer_iface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,32 @@ std::vector<std::string> PeerIface::get_cubes_names() const {
return cubes_names;
}

std::vector<uint16_t> PeerIface::get_cubes_ingress_index() const {
std::lock_guard<std::mutex> guard(mutex_);

std::vector<uint16_t> ingress_indices;

for (auto &cube : cubes_) {
ingress_indices.push_back(cube->get_index(ProgramType::INGRESS));
}

return ingress_indices;
}

std::vector<uint16_t> PeerIface::get_cubes_egress_index() const {
std::lock_guard<std::mutex> guard(mutex_);

std::vector<uint16_t> egress_indices;

for (auto &cube : cubes_) {
egress_indices.push_back(cube->get_index(ProgramType::EGRESS));
}

return egress_indices;
}



PeerIface::CubePositionComparison PeerIface::compare_position(
const std::string &cube1, const std::string &cube2) {
// cube position, index 0 is the innermost one
Expand Down Expand Up @@ -157,4 +183,4 @@ PeerIface::CubePositionComparison PeerIface::compare_position(
}

} // namespace polycubed
} // namespace polycube
} // namespace polycube
2 changes: 2 additions & 0 deletions src/polycubed/src/peer_iface.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class PeerIface {
const std::string &other);
void remove_cube(const std::string &type);
std::vector<std::string> get_cubes_names() const;
std::vector<uint16_t> get_cubes_ingress_index() const;
std::vector<uint16_t> get_cubes_egress_index() const;

protected:
enum class CubePositionComparison {
Expand Down
38 changes: 38 additions & 0 deletions src/polycubed/src/polycubed_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,44 @@ std::string PolycubedCore::topology() {
return j.dump(4);
}

std::string PolycubedCore::get_if_topology(const std::string &if_name) {
json j = {{"name", if_name}};

auto extIface = polycube::polycubed::ExtIface::get_extiface(if_name);
if (extIface != NULL) {
auto names = extIface->get_cubes_names();
auto ingress_indices = extIface->get_cubes_ingress_index();
auto egress_indices = extIface->get_cubes_egress_index();
std::vector<std::string> cubes_info;
std::ostringstream stream;
for (int i=0; i<names.size(); i++) {
stream.str("");
stream << names[i] << ",\t" << ingress_indices[i] << ",\t" << egress_indices[i];
cubes_info.push_back(std::string(stream.str()));
}
j["cubes, ingress_index, egress_index"] = cubes_info;

stream.str("");
auto i_serv_chain = extIface->get_service_chain(ProgramType::INGRESS);
for (auto service : i_serv_chain) {
stream << service;
if (service != std::string("stack"))
stream << " ---> ";
}
j["ingress service chain"] = stream.str();

stream.str("");
auto e_serv_chain = extIface->get_service_chain(ProgramType::EGRESS);
for (auto service : e_serv_chain) {
stream << service;
if (service != std::string("stack"))
stream << " ---> ";
}
j["egress service chain"] = stream.str();
}
return j.dump(4);
}

std::string get_port_peer(const std::string &port) {
std::smatch match;
std::regex rule("(\\S+):(\\S+)");
Expand Down
1 change: 1 addition & 0 deletions src/polycubed/src/polycubed_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class PolycubedCore {
std::string get_netdevs();

std::string topology();
std::string get_if_topology(const std::string &if_name);

void connect(const std::string &peer1, const std::string &peer2);
void disconnect(const std::string &peer1, const std::string &peer2);
Expand Down
15 changes: 15 additions & 0 deletions src/polycubed/src/rest_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ void RestServer::setup_routes() {
// topology
router_->get(base + std::string("/topology"),
bind(&RestServer::topology, this));
router_->get(base + std::string("/topology/:ifname"),
bind(&RestServer::get_if_topology, this));

router_->options(base + std::string("/topology"),
bind(&RestServer::topology_help, this));
Expand Down Expand Up @@ -830,6 +832,19 @@ void RestServer::topology(const Pistache::Rest::Request &request,
}
}

void RestServer::get_if_topology(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response) {
logRequest(request);
try {
auto ifname = request.param(":ifname").as<std::string>();
std::string retJsonStr = core.get_if_topology(ifname);
response.send(Pistache::Http::Code::Ok, retJsonStr);
} catch (const std::runtime_error &e) {
logger->error("{0}", e.what());
response.send(Pistache::Http::Code::Bad_Request, e.what());
}
}

void RestServer::topology_help(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response) {
json j = json::object();
Expand Down
2 changes: 2 additions & 0 deletions src/polycubed/src/rest_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ class RestServer {
Pistache::Http::ResponseWriter response);
void topology(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response);
void get_if_topology(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response);
void topology_help(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response);

Expand Down
4 changes: 4 additions & 0 deletions src/polycubed/src/transparent_cube.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ void TransparentCube::set_next(uint16_t next, ProgramType type) {
reload_all();
}

uint16_t TransparentCube::get_next(ProgramType type) {
return type == ProgramType::INGRESS ? ingress_next_ : egress_next_;
}

void TransparentCube::set_parent(PeerIface *parent) {
parent_ = parent;
if (parent_) {
Expand Down
1 change: 1 addition & 0 deletions src/polycubed/src/transparent_cube.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class TransparentCube : public BaseCube, public TransparentCubeIface {
virtual ~TransparentCube();

void set_next(uint16_t next, ProgramType type);
uint16_t get_next(ProgramType type);
void set_parent(PeerIface *parent);
PeerIface *get_parent();
void set_parameter(const std::string &parameter, const std::string &value);
Expand Down

0 comments on commit 2341f85

Please sign in to comment.