FD.io VPP  v18.01.2-1-g9b554f3
Vector Packet Processing
route.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "vom/route.hpp"
17 #include "vom/route_cmds.hpp"
18 #include "vom/singular_db.hpp"
19 
20 namespace VOM {
21 namespace route {
22 ip_route::event_handler ip_route::m_evh;
23 singular_db<ip_route::key_t, ip_route> ip_route::m_db;
24 
25 const path::special_t path::special_t::STANDARD(0, "standard");
26 const path::special_t path::special_t::LOCAL(0, "local");
27 const path::special_t path::special_t::DROP(0, "standard");
28 const path::special_t path::special_t::UNREACH(0, "unreachable");
29 const path::special_t path::special_t::PROHIBIT(0, "prohibit");
30 
31 path::special_t::special_t(int v, const std::string& s)
32  : enum_base<path::special_t>(v, s)
33 {
34 }
35 
36 path::path(special_t special)
37  : m_type(special)
38  , m_nh_proto(nh_proto_t::IPV4)
39  , m_nh()
40  , m_rd(nullptr)
41  , m_interface(nullptr)
42  , m_weight(1)
43  , m_preference(0)
44 {
45 }
46 
47 path::path(const boost::asio::ip::address& nh,
48  const interface& interface,
49  uint8_t weight,
50  uint8_t preference)
51  : m_type(special_t::STANDARD)
52  , m_nh_proto(nh_proto_t::from_address(nh))
53  , m_nh(nh)
54  , m_rd(nullptr)
55  , m_interface(interface.singular())
56  , m_weight(weight)
57  , m_preference(preference)
58 {
59 }
60 
62  const boost::asio::ip::address& nh,
63  uint8_t weight,
64  uint8_t preference)
65  : m_type(special_t::STANDARD)
66  , m_nh_proto(nh_proto_t::from_address(nh))
67  , m_nh(nh)
68  , m_rd(rd.singular())
69  , m_interface(nullptr)
70  , m_weight(weight)
71  , m_preference(preference)
72 {
73 }
74 
76  const nh_proto_t& proto,
77  uint8_t weight,
78  uint8_t preference)
79  : m_type(special_t::STANDARD)
80  , m_nh_proto(proto)
81  , m_nh()
82  , m_rd(nullptr)
83  , m_interface(interface.singular())
84  , m_weight(weight)
85  , m_preference(preference)
86 {
87 }
88 
89 path::path(const path& p)
90  : m_type(p.m_type)
91  , m_nh_proto(p.m_nh_proto)
92  , m_nh(p.m_nh)
93  , m_rd(p.m_rd)
94  , m_interface(p.m_interface)
95  , m_weight(p.m_weight)
96  , m_preference(p.m_preference)
97 {
98 }
99 
100 bool
101 path::operator<(const path& p) const
102 {
103  if (m_type < p.m_type)
104  return true;
105  if (m_rd && !p.m_rd)
106  return false;
107  if (!m_rd && p.m_rd)
108  return true;
109  if (m_rd->table_id() < p.m_rd->table_id())
110  return true;
111  if (m_nh < p.m_nh)
112  return true;
113  if (m_interface && !p.m_interface)
114  return false;
115  if (!m_interface && p.m_interface)
116  return true;
117  if (m_interface->handle() < p.m_interface->handle())
118  return true;
119 
120  return (false);
121 }
122 
124 {
125 }
126 
127 bool
128 path::operator==(const path& p) const
129 {
130  bool result = true;
131  if (m_rd && !p.m_rd)
132  return false;
133  if (!m_rd && p.m_rd)
134  return false;
135  if (m_rd && p.m_rd)
136  result &= (*m_rd == *p.m_rd);
137  if (m_interface && !p.m_interface)
138  return false;
139  if (!m_interface && p.m_interface)
140  return false;
141  if (m_interface && p.m_interface)
142  result &= (*m_interface == *p.m_interface);
143  return (result && (m_type == p.m_type) && (m_nh == p.m_nh));
144 }
145 
146 std::string
148 {
149  std::ostringstream s;
150 
151  s << "path:["
152  << "type:" << m_type.to_string() << " proto:" << m_nh_proto.to_string()
153  << " neighbour:" << m_nh.to_string();
154  if (m_rd) {
155  s << " " << m_rd->to_string();
156  }
157  if (m_interface) {
158  s << " " << m_interface->to_string();
159  }
160  s << " weight:" << static_cast<int>(m_weight)
161  << " preference:" << static_cast<int>(m_preference) << "]";
162 
163  return (s.str());
164 }
165 
167 path::type() const
168 {
169  return m_type;
170 }
171 
174 {
175  return m_nh_proto;
176 }
177 
178 const boost::asio::ip::address&
179 path::nh() const
180 {
181  return m_nh;
182 }
183 
184 std::shared_ptr<route_domain>
185 path::rd() const
186 {
187  return m_rd;
188 }
189 
190 std::shared_ptr<interface>
191 path::itf() const
192 {
193  return m_interface;
194 }
195 
196 uint8_t
198 {
199  return m_weight;
200 }
201 
202 uint8_t
204 {
205  return m_preference;
206 }
207 
208 ip_route::ip_route(const prefix_t& prefix, const path& p)
209  : m_hw(false)
210  , m_rd(route_domain::get_default())
211  , m_prefix(prefix)
212  , m_paths({ p })
213 {
214 }
215 
217  : m_hw(false)
218  , m_rd(route_domain::get_default())
219  , m_prefix(prefix)
220  , m_paths()
221 {
222 }
223 
225  : m_hw(r.m_hw)
226  , m_rd(r.m_rd)
227  , m_prefix(r.m_prefix)
228  , m_paths(r.m_paths)
229 {
230 }
231 
232 ip_route::ip_route(const route_domain& rd, const prefix_t& prefix)
233  : m_hw(false)
234  , m_rd(rd.singular())
235  , m_prefix(prefix)
236  , m_paths()
237 {
238 }
239 
241  const prefix_t& prefix,
242  const path& p)
243  : m_hw(false)
244  , m_rd(rd.singular())
245  , m_prefix(prefix)
246  , m_paths({ p })
247 {
248 }
249 
251 {
252  sweep();
253 
254  // not in the DB anymore.
255  m_db.release(key(), this);
256  m_paths.clear();
257 }
258 
259 const ip_route::key_t
261 {
262  return (std::make_pair(m_rd->table_id(), m_prefix));
263 }
264 
265 bool
267 {
268  return ((key() == i.key()) && (m_paths == i.m_paths));
269 }
270 
271 void
273 {
274  m_paths.insert(path);
275 }
276 
277 void
279 {
280  m_paths.erase(path);
281 }
282 
283 void
284 ip_route::sweep()
285 {
286  if (m_hw) {
287  HW::enqueue(
288  new ip_route_cmds::delete_cmd(m_hw, m_rd->table_id(), m_prefix));
289  }
290  HW::write();
291 }
292 
293 void
295 {
296  if (m_hw) {
297  HW::enqueue(
298  new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, m_paths));
299  }
300 }
301 std::string
303 {
304  std::ostringstream s;
305  s << "route:[" << m_rd->to_string() << ", " << m_prefix.to_string() << " ["
306  << m_paths << "]"
307  << "]";
308 
309  return (s.str());
310 }
311 
312 void
313 ip_route::update(const ip_route& r)
314 {
315  /*
316 * create the table if it is not yet created
317 */
318  if (rc_t::OK != m_hw.rc()) {
319  HW::enqueue(
320  new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, m_paths));
321  }
322 }
323 
324 std::shared_ptr<ip_route>
325 ip_route::find_or_add(const ip_route& temp)
326 {
327  return (m_db.find_or_add(temp.key(), temp));
328 }
329 
330 std::shared_ptr<ip_route>
332 {
333  return (m_db.find(k));
334 }
335 
336 std::shared_ptr<ip_route>
338 {
339  return find_or_add(*this);
340 }
341 
342 void
343 ip_route::dump(std::ostream& os)
344 {
345  m_db.dump(os);
346 }
347 
348 ip_route::event_handler::event_handler()
349 {
350  OM::register_listener(this);
351  inspect::register_handler({ "ip-route" }, "ip route configurations", this);
352 }
353 
354 void
355 ip_route::event_handler::handle_replay()
356 {
357  m_db.replay();
358 }
359 
360 void
361 ip_route::event_handler::handle_populate(const client_db::key_t& key)
362 {
363  std::shared_ptr<ip_route_cmds::dump_v4_cmd> cmd_v4 =
364  std::make_shared<ip_route_cmds::dump_v4_cmd>();
365  std::shared_ptr<ip_route_cmds::dump_v6_cmd> cmd_v6 =
366  std::make_shared<ip_route_cmds::dump_v6_cmd>();
367 
368  HW::enqueue(cmd_v4);
369  HW::enqueue(cmd_v6);
370  HW::write();
371 
372  for (auto& record : *cmd_v4) {
373  auto& payload = record.get_payload();
374 
375  prefix_t pfx(0, payload.address, payload.address_length);
376 
377  /**
378  * populating the route domain here
379  */
380  route_domain rd_temp(payload.table_id);
381  std::shared_ptr<route_domain> rd = route_domain::find(rd_temp);
382  if (!rd) {
383  OM::commit(key, rd_temp);
384  }
385  ip_route ip_r(rd_temp, pfx);
386 
387  for (unsigned int i = 0; i < payload.count; i++) {
388  vapi_type_fib_path p = payload.path[i];
389  if (p.is_local) {
390  path path_v4(path::special_t::LOCAL);
391  ip_r.add(path_v4);
392  } else if (p.is_drop) {
393  path path_v4(path::special_t::DROP);
394  ip_r.add(path_v4);
395  } else if (p.is_unreach) {
397  ip_r.add(path_v4);
398  } else if (p.is_prohibit) {
400  ip_r.add(path_v4);
401  } else {
402  std::shared_ptr<interface> itf = interface::find(p.sw_if_index);
403  boost::asio::ip::address address = from_bytes(0, p.next_hop);
404  path path_v4(address, *itf, p.weight, p.preference);
405  ip_r.add(path_v4);
406  }
407  }
408  VOM_LOG(log_level_t::DEBUG) << "ip-route-dump: " << ip_r.to_string();
409 
410  /*
411  * Write each of the discovered interfaces into the OM,
412  * but disable the HW Command q whilst we do, so that no
413  * commands are sent to VPP
414  */
415  OM::commit(key, ip_r);
416  }
417 
418  for (auto& record : *cmd_v6) {
419  auto& payload = record.get_payload();
420 
421  prefix_t pfx(1, payload.address, payload.address_length);
422  route_domain rd_temp(payload.table_id);
423  std::shared_ptr<route_domain> rd = route_domain::find(rd_temp);
424  if (!rd) {
425  OM::commit(key, rd_temp);
426  }
427  ip_route ip_r(rd_temp, pfx);
428 
429  for (unsigned int i = 0; i < payload.count; i++) {
430  vapi_type_fib_path p = payload.path[i];
431  if (p.is_local) {
432  path path_v6(path::special_t::LOCAL);
433  ip_r.add(path_v6);
434  } else if (p.is_drop) {
435  path path_v6(path::special_t::DROP);
436  ip_r.add(path_v6);
437  } else if (p.is_unreach) {
439  ip_r.add(path_v6);
440  } else if (p.is_prohibit) {
442  ip_r.add(path_v6);
443  } else {
444  std::shared_ptr<interface> itf = interface::find(p.sw_if_index);
445  boost::asio::ip::address address = from_bytes(1, p.next_hop);
446  path path_v6(address, *itf, p.weight, p.preference);
447  ip_r.add(path_v6);
448  }
449  }
450  VOM_LOG(log_level_t::DEBUG) << "ip-route-dump: " << ip_r.to_string();
451 
452  /*
453  * Write each of the discovered interfaces into the OM,
454  * but disable the HW Command q whilst we do, so that no
455  * commands are sent to VPP
456  */
457  OM::commit(key, ip_r);
458  }
459 }
460 
462 ip_route::event_handler::order() const
463 {
464  return (dependency_t::BINDING);
465 }
466 
467 void
468 ip_route::event_handler::show(std::ostream& os)
469 {
470  m_db.dump(os);
471 }
472 
473 std::ostream&
474 operator<<(std::ostream& os, const ip_route::key_t& key)
475 {
476  os << "[" << key.first << ", " << key.second.to_string() << "]";
477 
478  return (os);
479 }
480 
481 std::ostream&
482 operator<<(std::ostream& os, const path_list_t& key)
483 {
484  os << "[";
485  for (auto k : key) {
486  os << k.to_string() << " ";
487  }
488  os << "]";
489 
490  return (os);
491 }
492 }
493 }
494 /*
495  * fd.io coding-style-patch-verification: ON
496  *
497  * Local Variables:
498  * eval: (c-set-style "mozilla")
499  * End:
500  */
void remove(const path &path)
remove a path.
Definition: route.cpp:278
nh_proto_t nh_proto() const
Definition: route.cpp:173
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
static const special_t STANDARD
A standard path type.
Definition: route.hpp:45
#define VOM_LOG(lvl)
Definition: logger.hpp:181
A command class that creates or updates the route.
Definition: route_cmds.hpp:32
const std::string key_t
In the opflex world each entity is known by a URI which can be converted into a string.
Definition: client_db.hpp:51
static std::shared_ptr< interface > find(const handle_t &h)
The the singular instance of the interface in the DB by handle.
Definition: interface.cpp:402
A path for IP or MPLS routes.
Definition: route.hpp:32
static void register_handler(const std::vector< std::string > &cmds, const std::string &help, command_handler *ch)
Register a command handler for inspection.
Definition: inspect.cpp:85
ip_route(const prefix_t &prefix)
Construct a route in the default table.
Definition: route.cpp:216
std::string to_string() const
convert to string format for debug purposes
Definition: route.cpp:147
static rc_t write()
Write/Execute all commands hitherto enqueued.
Definition: hw.cpp:225
static const log_level_t DEBUG
Definition: logger.hpp:32
std::shared_ptr< interface > itf() const
Definition: route.cpp:191
void add(const path &path)
Add a path.
Definition: route.cpp:272
static std::shared_ptr< route_domain > find(const route_domain &temp)
Find the instnace of the route domain in the OM.
A route-domain is a VRF.
static const special_t LOCAL
A local/for-us/recieve.
Definition: route.hpp:50
static const special_t DROP
drop path
Definition: route.hpp:55
~path()
Destructor.
Definition: route.cpp:123
const key_t key() const
Get the route&#39;s key.
Definition: route.cpp:260
std::ostream & operator<<(std::ostream &os, const ip_route::key_t &key)
Definition: route.cpp:474
A next-hop protocol describes the protocol of a peer to which packets are sent after matching a route...
Definition: prefix.hpp:60
rc_t rc() const
Get the HW return code.
Definition: hw.hpp:118
std::string to_string() const
convert to string format for debug purposes
Definition: prefix.cpp:170
std::string to_string() const
Convert to string for debugging.
Definition: route.cpp:302
static const special_t UNREACH
a path will return ICMP unreachables
Definition: route.hpp:60
#define v
Definition: acl.c:341
std::shared_ptr< route_domain > rd() const
Definition: route.cpp:185
~ip_route()
Destructor.
Definition: route.cpp:250
std::shared_ptr< ip_route > singular() const
Return the matching &#39;singular instance&#39;.
Definition: route.cpp:337
path(special_t special)
constructor for special paths
Definition: route.cpp:36
static const special_t PROHIBIT
a path will return ICMP prohibit
Definition: route.hpp:65
std::set< path > path_list_t
A path-list is a set of paths.
Definition: route.hpp:180
A representation of an interface in VPP.
Definition: interface.hpp:41
boost::asio::ip::address from_bytes(uint8_t is_ip6, uint8_t *bytes)
Convert a VPP byte stinrg into a boost addresss.
Definition: prefix.cpp:180
static rc_t commit(const client_db::key_t &key, const OBJ &obj)
Make the State in VPP reflect the expressed desired state.
Definition: om.hpp:202
Special path types.
Definition: route.hpp:38
dependency_t
There needs to be a strict order in which object types are read from VPP (at boot time) and replayed ...
Definition: types.hpp:43
uint8_t preference() const
Definition: route.cpp:203
static const rc_t OK
The HW write was successfull.
Definition: types.hpp:106
static void enqueue(cmd *f)
Enqueue A command for execution.
Definition: hw.cpp:189
A cmd class that deletes a route.
Definition: route_cmds.hpp:67
const boost::asio::ip::address & nh() const
Definition: route.cpp:179
Then L2/objects that bind to interfaces, BD, ACLS, etc.
bool operator==(const ip_route &i) const
Comparison operator.
Definition: route.cpp:266
static std::shared_ptr< ip_route > find(const ip_route &temp)
Find the instnace of the route domain in the OM.
The VPP Object Model (VOM) library.
Definition: acl_binding.cpp:19
void replay(void)
replay the object to create it in hardware
Definition: route.cpp:294
bool operator<(const path &p) const
Less than operator for set insertion.
Definition: route.cpp:101
A IP route.
Definition: route.hpp:190
static void dump(std::ostream &os)
Dump all route-doamin into the stream provided.
Definition: route.cpp:343
void show(char *chroot_path, int verbose)
Definition: svmtool.c:105
bool operator==(const path &p) const
comparison operator
Definition: route.cpp:128
special_t type() const
Getters.
Definition: route.cpp:167
uint8_t weight() const
Definition: route.cpp:197
const std::string & to_string() const
convert to string format for debug purposes
Definition: enum_base.hpp:36
static bool register_listener(listener *listener)
Register a listener of events.
Definition: om.cpp:124
A prefix defintion.
Definition: prefix.hpp:91
std::pair< route::table_id_t, prefix_t > key_t
The key for a route.
Definition: route.hpp:196