Skip to content

Commit 964f880

Browse files
committed
This commit extends the get_if_topology CLI to support traversing the bpf program
index chain (service chain) for each interface and dump them. Since the head index was fetched from the data plane directly and each next service is fetched from the cubes, the service chain can be regarded as a real reflection of service chain in the data. Also Fixed a few issues in existing implementation. Signed-off-by: Jianwen Pi<jianwpi@gmail.com>
1 parent 19d8367 commit 964f880

7 files changed

Lines changed: 121 additions & 14 deletions

File tree

src/polycubed/src/extiface.cpp

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -180,39 +180,82 @@ void ExtIface::set_next(uint16_t next, ProgramType type) {
180180
}
181181
}
182182

183+
TransparentCube* ExtIface::get_next_cube(ProgramType type) {
184+
auto next = get_next(type);
185+
for (auto &it : cubes_) {
186+
if (it->get_index(type) == next) {
187+
return it;
188+
}
189+
}
190+
return NULL;
191+
}
192+
193+
uint16_t ExtIface::get_next(ProgramType type) {
194+
int zero = 0;
195+
unsigned int value = 0;
196+
auto program = (type == ProgramType::INGRESS) ? &ingress_program_ : &egress_program_;
197+
auto index_map = program->get_array_table<uint32_t>("index_map");
198+
auto st = index_map.get_value(zero, value);
199+
if (st.code() == -1) {
200+
logger->error("failed to get interface {0} nexthop", get_iface_name());
201+
}
202+
203+
return value & 0xffff;
204+
}
205+
206+
std::vector<std::string> ExtIface::get_service_chain(ProgramType type) {
207+
std::vector<std::string> chain;
208+
TransparentCube *cube;
209+
auto nh = get_next(type);
210+
211+
while (nh != 0xffff) {
212+
cube = NULL;
213+
for (auto c : cubes_) {
214+
if (c->get_index(type) == nh) {
215+
cube = c;
216+
break;
217+
}
218+
}
219+
chain.push_back(cube ? cube->get_name() : "unknown");
220+
nh = cube->get_next(type);
221+
}
222+
chain.push_back(nh==0xffff ? "stack" : "unknown");
223+
224+
return chain;
225+
}
226+
183227
void ExtIface::update_indexes() {
184228
int i;
185229

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

188-
std::vector<uint16_t> ingress_indexes(cubes_.size());
189-
std::vector<uint16_t> egress_indexes(cubes_.size());
232+
std::vector<uint16_t> ingress_indexes(cubes_.size(), 0xffff) ;
233+
std::vector<uint16_t> egress_indexes(cubes_.size(), 0xffff);
190234

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

196-
// ingress chain: NIC -> cube[N-1] -> ... -> cube[0] -> stack (or peer)
240+
// ingress chain: NIC -> cube[0] -> ... -> cube[n-1] -> stack (or peer)
197241
// CASE2: cube[0] -> stack (or)
198-
for (i = 0; i < cubes_.size(); i++) {
199-
if (ingress_indexes[i]) {
242+
for (i = cubes_.size() - 1; i >= 0; i--) {
243+
if (ingress_indexes[i] != 0xffff) {
200244
cubes_[i]->set_next(peer_ ? peer_->get_index() : 0xffff,
201245
ProgramType::INGRESS);
202246
break;
203247
}
204248
}
205249

206-
// cube[N-1] -> ... -> cube[0]
207-
for (int j = i + 1; j < cubes_.size(); j++) {
208-
if (ingress_indexes[j]) {
250+
for (int j = i - 1; j >= 0; j--) {
251+
if (ingress_indexes[j] != 0xffff) {
209252
cubes_[j]->set_next(ingress_indexes[i], ProgramType::INGRESS);
210253
i = j;
211254
}
212255
}
213256

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

223266
// cube[0] -> "egress"
224267
for (i = 0; i < cubes_.size(); i++) {
225-
if (egress_indexes[i]) {
268+
if (egress_indexes[i] != 0xffff) {
226269
cubes_[i]->set_next(0xffff, ProgramType::EGRESS);
227270
break;
228271
}
@@ -235,14 +278,14 @@ void ExtIface::update_indexes() {
235278

236279
// cubes[N-1] -> ... -> cube[0]
237280
for (int j = i + 1; j < cubes_.size(); j++) {
238-
if (egress_indexes[j]) {
281+
if (egress_indexes[j] != 0xffff) {
239282
cubes_[j]->set_next(egress_indexes[i], ProgramType::EGRESS);
240283
i = j;
241284
}
242285
}
243286

244287
// "nic" -> cubes[N-1] or peer
245-
if (i < cubes_.size() && egress_indexes[i]) {
288+
if (i < cubes_.size() && egress_indexes[i] != 0xffff) {
246289
set_next(egress_indexes[i], ProgramType::EGRESS);
247290
} else {
248291
Port *peer_port = dynamic_cast<Port *>(peer_);

src/polycubed/src/extiface.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class ExtIface : public PeerIface {
6666
std::string get_parameter(const std::string &param_name) override;
6767
void set_parameter(const std::string &param_name,
6868
const std::string &value) override;
69+
uint16_t get_next(ProgramType type);
70+
TransparentCube* get_next_cube(ProgramType type);
71+
std::vector<std::string> get_service_chain(ProgramType type);
6972

7073
protected:
7174
// 2 maps: one for IP events and one for MAC events

src/polycubed/src/peer_iface.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,32 @@ std::vector<std::string> PeerIface::get_cubes_names() const {
124124
return cubes_names;
125125
}
126126

127+
std::vector<uint16_t> PeerIface::get_cubes_ingress_index() const {
128+
std::lock_guard<std::mutex> guard(mutex_);
129+
130+
std::vector<uint16_t> ingress_indices;
131+
132+
for (auto &cube : cubes_) {
133+
ingress_indices.push_back(cube->get_index(ProgramType::INGRESS));
134+
}
135+
136+
return ingress_indices;
137+
}
138+
139+
std::vector<uint16_t> PeerIface::get_cubes_egress_index() const {
140+
std::lock_guard<std::mutex> guard(mutex_);
141+
142+
std::vector<uint16_t> egress_indices;
143+
144+
for (auto &cube : cubes_) {
145+
egress_indices.push_back(cube->get_index(ProgramType::EGRESS));
146+
}
147+
148+
return egress_indices;
149+
}
150+
151+
152+
127153
PeerIface::CubePositionComparison PeerIface::compare_position(
128154
const std::string &cube1, const std::string &cube2) {
129155
// cube position, index 0 is the innermost one
@@ -157,4 +183,4 @@ PeerIface::CubePositionComparison PeerIface::compare_position(
157183
}
158184

159185
} // namespace polycubed
160-
} // namespace polycube
186+
} // namespace polycube

src/polycubed/src/peer_iface.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class PeerIface {
5252
const std::string &other);
5353
void remove_cube(const std::string &type);
5454
std::vector<std::string> get_cubes_names() const;
55+
std::vector<uint16_t> get_cubes_ingress_index() const;
56+
std::vector<uint16_t> get_cubes_egress_index() const;
5557

5658
protected:
5759
enum class CubePositionComparison {

src/polycubed/src/polycubed_core.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,35 @@ std::string PolycubedCore::get_if_topology(const std::string &if_name) {
213213

214214
auto extIface = polycube::polycubed::ExtIface::get_extiface(if_name);
215215
if (extIface != NULL) {
216-
j["cubes"] = extIface->get_cubes_names();
216+
auto names = extIface->get_cubes_names();
217+
auto ingress_indices = extIface->get_cubes_ingress_index();
218+
auto egress_indices = extIface->get_cubes_egress_index();
219+
std::vector<std::string> cubes_info;
220+
std::ostringstream stream;
221+
for (int i=0; i<names.size(); i++) {
222+
stream.str("");
223+
stream << names[i] << ",\t" << ingress_indices[i] << ",\t" << egress_indices[i];
224+
cubes_info.push_back(std::string(stream.str()));
225+
}
226+
j["cubes, ingress_index, egress_index"] = cubes_info;
227+
228+
stream.str("");
229+
auto i_serv_chain = extIface->get_service_chain(ProgramType::INGRESS);
230+
for (auto service : i_serv_chain) {
231+
stream << service;
232+
if (service != std::string("stack"))
233+
stream << " ---> ";
234+
}
235+
j["ingress service chain"] = stream.str();
236+
237+
stream.str("");
238+
auto e_serv_chain = extIface->get_service_chain(ProgramType::EGRESS);
239+
for (auto service : e_serv_chain) {
240+
stream << service;
241+
if (service != std::string("stack"))
242+
stream << " ---> ";
243+
}
244+
j["egress service chain"] = stream.str();
217245
}
218246
return j.dump(4);
219247
}

src/polycubed/src/transparent_cube.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ void TransparentCube::set_next(uint16_t next, ProgramType type) {
7171
reload_all();
7272
}
7373

74+
uint16_t TransparentCube::get_next(ProgramType type) {
75+
return type == ProgramType::INGRESS ? ingress_next_ : egress_next_;
76+
}
77+
7478
void TransparentCube::set_parent(PeerIface *parent) {
7579
parent_ = parent;
7680
if (parent_) {

src/polycubed/src/transparent_cube.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class TransparentCube : public BaseCube, public TransparentCubeIface {
3636
virtual ~TransparentCube();
3737

3838
void set_next(uint16_t next, ProgramType type);
39+
uint16_t get_next(ProgramType type);
3940
void set_parent(PeerIface *parent);
4041
PeerIface *get_parent();
4142
void set_parameter(const std::string &parameter, const std::string &value);

0 commit comments

Comments
 (0)