FD.io VPP  v18.01.2-1-g9b554f3
Vector Packet Processing
interface.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/interface.hpp"
17 #include "vom/interface_cmds.hpp"
19 #include "vom/l3_binding_cmds.hpp"
20 #include "vom/logger.hpp"
21 #include "vom/prefix.hpp"
22 
23 namespace VOM {
24 /**
25  * A DB of all the interfaces, key on the name
26  */
27 singular_db<interface::key_t, interface> interface::m_db;
28 
29 /**
30  * A DB of all the interfaces, key on VPP's handle
31  */
32 std::map<handle_t, std::weak_ptr<interface>> interface::m_hdl_db;
33 
34 interface::event_handler interface::m_evh;
35 
36 /**
37  * Construct a new object matching the desried state
38  */
39 interface::interface(const std::string& name,
40  interface::type_t itf_type,
41  interface::admin_state_t itf_state)
42  : m_hdl(handle_t::INVALID)
43  , m_name(name)
44  , m_type(itf_type)
45  , m_state(itf_state)
46  , m_table_id(route::DEFAULT_TABLE)
47  , m_l2_address(l2_address_t::ZERO, rc_t::UNSET)
48  , m_oper(oper_state_t::DOWN)
49 {
50 }
51 
52 interface::interface(const std::string& name,
53  interface::type_t itf_type,
54  interface::admin_state_t itf_state,
55  const route_domain& rd)
56  : m_hdl(handle_t::INVALID)
57  , m_name(name)
58  , m_type(itf_type)
59  , m_rd(rd.singular())
60  , m_state(itf_state)
61  , m_table_id(m_rd->table_id())
62  , m_l2_address(l2_address_t::ZERO, rc_t::UNSET)
63  , m_oper(oper_state_t::DOWN)
64 {
65 }
66 
68  : m_hdl(o.m_hdl)
69  , m_name(o.m_name)
70  , m_type(o.m_type)
71  , m_rd(o.m_rd)
72  , m_state(o.m_state)
73  , m_table_id(o.m_table_id)
74  , m_l2_address(o.m_l2_address)
75  , m_oper(o.m_oper)
76 {
77 }
78 
79 bool
81 {
82  return ((key() == i.key()) &&
83  (m_l2_address.data() == i.m_l2_address.data()) &&
84  (m_state == i.m_state) && (m_rd == i.m_rd) && (m_type == i.m_type) &&
85  (m_oper == i.m_oper));
86 }
87 
89  : m_status(rc_t::NOOP)
90 {
91 }
92 
95 {
96  return (m_status);
97 }
98 
100  : m_status(rc_t::NOOP)
101 {
102 }
103 
106 {
107  return (m_status);
108 }
109 
110 /**
111  * Return the interface type
112  */
113 const interface::type_t&
115 {
116  return (m_type);
117 }
118 
119 const handle_t&
121 {
122  return (singular()->handle_i());
123 }
124 
125 const handle_t&
126 interface::handle_i() const
127 {
128  return (m_hdl.data());
129 }
130 
131 const l2_address_t&
133 {
134  return (m_l2_address.data());
135 }
136 
139 {
140  return m_db.cbegin();
141 }
142 
145 {
146  return m_db.cend();
147 }
148 
149 void
151 {
152  if (m_table_id && (m_table_id.data() != route::DEFAULT_TABLE)) {
153  m_table_id.data() = route::DEFAULT_TABLE;
154  HW::enqueue(
156  HW::enqueue(
158  }
159 
160  if (m_stats) {
162  m_stats.reset();
163  }
164 
165  // If the interface is up, bring it down
166  if (m_state && interface::admin_state_t::UP == m_state.data()) {
167  m_state.data() = interface::admin_state_t::DOWN;
169  }
170 
171  if (m_hdl) {
172  std::queue<cmd*> cmds;
173  HW::enqueue(mk_delete_cmd(cmds));
174  }
175  HW::write();
176 }
177 
178 void
179 interface::replay()
180 {
181  if (m_hdl) {
182  std::queue<cmd*> cmds;
183  HW::enqueue(mk_create_cmd(cmds));
184  }
185 
186  if (m_state && interface::admin_state_t::UP == m_state.data()) {
188  }
189 
190  if (m_table_id && (m_table_id.data() != route::DEFAULT_TABLE)) {
191  HW::enqueue(
193  HW::enqueue(
195  }
196 }
197 
199 {
200  sweep();
201  release();
202 }
203 
204 void
206 {
207  // not in the DB anymore.
208  m_db.release(m_name, this);
209 }
210 
211 std::string
213 {
214  std::ostringstream s;
215  s << "interface:[" << m_name << " type:" << m_type.to_string()
216  << " hdl:" << m_hdl.to_string() << " l2-address:["
217  << m_l2_address.to_string() << "]";
218 
219  if (m_rd) {
220  s << " rd:" << m_rd->to_string();
221  }
222 
223  s << " admin-state:" << m_state.to_string()
224  << " oper-state:" << m_oper.to_string() << "]";
225 
226  return (s.str());
227 }
228 
229 const std::string&
231 {
232  return (m_name);
233 }
234 
235 const interface::key_t&
237 {
238  return (name());
239 }
240 
241 std::queue<cmd*>&
242 interface::mk_create_cmd(std::queue<cmd*>& q)
243 {
244  if (type_t::LOOPBACK == m_type) {
245  q.push(new interface_cmds::loopback_create_cmd(m_hdl, m_name));
246  } else if (type_t::BVI == m_type) {
247  q.push(new interface_cmds::loopback_create_cmd(m_hdl, m_name));
248  q.push(new interface_cmds::set_tag(m_hdl, m_name));
249  } else if (type_t::AFPACKET == m_type) {
250  q.push(new interface_cmds::af_packet_create_cmd(m_hdl, m_name));
251  } else if (type_t::TAP == m_type) {
252  q.push(new interface_cmds::tap_create_cmd(m_hdl, m_name));
253  } else {
254  m_hdl.set(rc_t::OK);
255  }
256 
257  return (q);
258 }
259 
260 std::queue<cmd*>&
261 interface::mk_delete_cmd(std::queue<cmd*>& q)
262 {
263  if ((type_t::LOOPBACK == m_type) || (type_t::BVI == m_type)) {
265  } else if (type_t::AFPACKET == m_type) {
266  q.push(new interface_cmds::af_packet_delete_cmd(m_hdl, m_name));
267  } else if (type_t::TAP == m_type) {
269  }
270 
271  return (q);
272 }
273 
274 void
275 interface::update(const interface& desired)
276 {
277  /*
278  * the desired state is always that the interface should be created
279  */
280  if (rc_t::OK != m_hdl.rc()) {
281  std::queue<cmd*> cmds;
282  HW::enqueue(mk_create_cmd(cmds));
283  /*
284  * interface create now, so we can barf early if it fails
285  */
286  HW::write();
287  }
288 
289  /*
290  * If the interface is not created do other commands should be issued
291  */
292  if (rc_t::OK != m_hdl.rc())
293  return;
294 
295  /*
296  * change the interface state to that which is deisred
297  */
298  if (m_state.update(desired.m_state)) {
300  }
301 
302  /*
303  * change the interface state to that which is deisred
304  */
305  if (m_l2_address.update(desired.m_l2_address)) {
306  HW::enqueue(new interface_cmds::set_mac_cmd(m_l2_address, m_hdl));
307  }
308 
309  /*
310  * If the interface is mapped into a route domain, set VPP's
311  * table ID
312  */
313  if (m_rd != desired.m_rd) {
314  /*
315  * changing route domains. need to remove all L3 bindings, swap the table
316  * then reapply the bindings.
317  */
318  auto it = l3_binding::cbegin();
319 
320  while (it != l3_binding::cend()) {
321  if (it->second.lock()->itf().key() == key())
322  it->second.lock()->sweep();
323  ++it;
324  }
325  m_rd = desired.m_rd;
326  m_table_id.update(m_rd ? m_rd->table_id() : route::DEFAULT_TABLE);
327  HW::enqueue(
329  HW::enqueue(
331  HW::write();
332 
333  it = l3_binding::cbegin();
334  while (it != l3_binding::cend()) {
335  if (it->second.lock()->itf().key() == key())
336  it->second.lock()->replay(); //(*it->second.lock());
337  ++it;
338  }
339  } else if (!m_table_id && m_rd) {
340  HW::enqueue(
342  HW::enqueue(
344  }
345 }
346 
347 void
349 {
350  assert(rc_t::UNSET == m_l2_address.rc());
351  m_l2_address.set(rc_t::NOOP);
352  m_l2_address.update(addr);
353 }
354 
355 void
357 {
358  m_hdl = hdl;
359 }
360 
361 void
363 {
364  m_oper = state;
365 }
366 
367 void
368 interface::enable_stats_i(interface::stat_listener& el)
369 {
370  if (!m_stats) {
371  m_stats.reset(new interface_cmds::stats_enable_cmd(el, handle_i()));
372  HW::enqueue(m_stats);
373  HW::write();
374  }
375 }
376 
377 void
379 {
380  singular()->enable_stats_i(el);
381 }
382 
383 std::shared_ptr<interface>
385 {
386  return (m_db.find_or_add(key(), *this));
387 }
388 
389 std::shared_ptr<interface>
391 {
392  return singular_i();
393 }
394 
395 std::shared_ptr<interface>
397 {
398  return (m_db.find(k));
399 }
400 
401 std::shared_ptr<interface>
403 {
404  return (m_hdl_db[handle].lock());
405 }
406 
407 void
409 {
410  std::shared_ptr<interface> sp = find(key);
411 
412  if (sp && item) {
413  m_hdl_db[item.data()] = sp;
414  }
415 }
416 
417 void
419 {
420  m_hdl_db.erase(item.data());
421 }
422 
423 void
424 interface::dump(std::ostream& os)
425 {
426  m_db.dump(os);
427 }
428 
429 void
430 interface::event_handler::handle_populate(const client_db::key_t& key)
431 {
432  /*
433  * dump VPP current states
434  */
435  std::shared_ptr<interface_cmds::dump_cmd> cmd =
436  std::make_shared<interface_cmds::dump_cmd>();
437 
438  HW::enqueue(cmd);
439  HW::write();
440 
441  for (auto& itf_record : *cmd) {
442  std::shared_ptr<interface> itf =
443  interface_factory::new_interface(itf_record.get_payload());
444 
445  if (itf && interface::type_t::LOCAL != itf->type()) {
446  VOM_LOG(log_level_t::DEBUG) << "dump: " << itf->to_string();
447  /*
448  * Write each of the discovered interfaces into the OM,
449  * but disable the HW Command q whilst we do, so that no
450  * commands are sent to VPP
451  */
452  OM::commit(key, *itf);
453 
454  /**
455  * Get the address configured on the interface
456  */
457  std::shared_ptr<l3_binding_cmds::dump_v4_cmd> dcmd =
458  std::make_shared<l3_binding_cmds::dump_v4_cmd>(
459  l3_binding_cmds::dump_v4_cmd(itf->handle()));
460 
461  HW::enqueue(dcmd);
462  HW::write();
463 
464  for (auto& l3_record : *dcmd) {
465  auto& payload = l3_record.get_payload();
466  const route::prefix_t pfx(payload.is_ipv6, payload.ip,
467  payload.prefix_length);
468 
469  VOM_LOG(log_level_t::DEBUG) << "dump: " << pfx.to_string();
470 
471  l3_binding l3(*itf, pfx);
472  OM::commit(key, l3);
473  }
474  }
475  }
476 }
477 
478 interface::event_handler::event_handler()
479 {
480  OM::register_listener(this);
481  inspect::register_handler({ "interface", "intf" }, "interfaces", this);
482 }
483 
484 void
485 interface::event_handler::handle_replay()
486 {
487  m_db.replay();
488 }
489 
491 interface::event_handler::order() const
492 {
493  return (dependency_t::INTERFACE);
494 }
495 
496 void
497 interface::event_handler::show(std::ostream& os)
498 {
499  m_db.dump(os);
500 }
501 
502 } // namespace VOM
503 
504 /*
505  * fd.io coding-style-patch-verification: ON
506  *
507  * Local Variables:
508  * eval: (c-set-style "mozilla")
509  * End:
510  */
static const rc_t NOOP
The HW write/update action was/has not been attempted.
Definition: types.hpp:101
void release()
release/remove an interface form the singular store
Definition: interface.cpp:205
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
A command class represents our desire to recieve interface stats.
virtual ~interface()
Destructor.
Definition: interface.cpp:198
static void dump(std::ostream &os)
Dump all interfaces into the stream provided.
Definition: interface.cpp:424
#define VOM_LOG(lvl)
Definition: logger.hpp:181
static const type_t AFPACKET
AF-Packet interface type.
Definition: interface.hpp:79
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
HW::item< handle_t > m_hdl
The SW interface handle VPP has asigned to the interface.
Definition: interface.hpp:439
virtual void sweep(void)
Sweep/reap the object if still stale.
Definition: interface.cpp:150
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
static rc_t write()
Write/Execute all commands hitherto enqueued.
Definition: hw.cpp:225
HW::item< bool > & status()
Return the HW::item representing the status.
Definition: interface.cpp:94
A command class to set tag on interfaces.
Error codes that VPP will return during a HW write.
Definition: types.hpp:84
static const log_level_t DEBUG
Definition: logger.hpp:32
static const_iterator_t cbegin()
Definition: l3_binding.cpp:93
A command class to create TAP interfaces in VPP.
std::string to_string() const
convert to string format for debug purposes
Definition: hw.hpp:160
const handle_t & handle() const
Return VPP&#39;s handle to this object.
Definition: interface.cpp:120
The oper state of the interface.
Definition: interface.hpp:134
Type def of a L2 address as read from VPP.
Definition: types.hpp:265
A route-domain is a VRF.
T & data()
Return the data read/written.
Definition: hw.hpp:108
static const_iterator_t cbegin()
Definition: interface.cpp:138
static singular_db< key_t, interface > m_db
A map of all interfaces key against the interface&#39;s name.
Definition: interface.hpp:471
static const type_t LOCAL
Local interface type (specific to VPP)
Definition: interface.hpp:87
A command class that binds an interface to an L3 table.
rc_t rc() const
Get the HW return code.
Definition: hw.hpp:118
static const l3_proto_t IPV4
Definition: prefix.hpp:35
static const_iterator_t cend()
Definition: l3_binding.cpp:99
static const l3_proto_t IPV6
Definition: prefix.hpp:36
HW::item< bool > m_status
The status of the subscription.
Definition: interface.hpp:375
A command class to delete TAP interfaces in VPP.
static const table_id_t DEFAULT_TABLE
The table-id for the default table.
Definition: prefix.hpp:86
virtual std::queue< cmd * > & mk_create_cmd(std::queue< cmd * > &cmds)
Virtual functions to construct an interface create commands.
Definition: interface.cpp:242
std::string to_string() const
convert to string format for debug purposes
Definition: prefix.cpp:170
static void remove(const HW::item< handle_t > &item)
remove an interface from the DB keyed on handle
Definition: interface.cpp:418
event_listener()
Default Constructor.
Definition: interface.cpp:88
const l2_address_t & l2_address() const
Return the L2 Address.
Definition: interface.cpp:132
A class that listens to interface Stats.
Definition: interface.hpp:381
stat_listener()
Default Constructor.
Definition: interface.cpp:99
virtual bool operator==(const interface &i) const
Comparison operator - only used for UT.
Definition: interface.cpp:80
static std::shared_ptr< interface > new_interface(const vapi_payload_sw_interface_details &vd)
Factory method to construct a new interface from the VPP record.
A command class to create Loopback interfaces in VPP.
A cmd class that changes the admin state.
static void add(const key_t &name, const HW::item< handle_t > &item)
Add an interface to the DB keyed on handle.
Definition: interface.cpp:408
A command class that binds an interface to an L3 table.
The admin state of the interface.
Definition: interface.hpp:108
A representation of an interface in VPP.
Definition: interface.hpp:41
HW::item< bool > & status()
Return the HW::item representing the status.
Definition: interface.cpp:105
A command class to create af_packet interfaces in VPP.
A type declaration of an interface handle in VPP.
Definition: types.hpp:164
std::shared_ptr< interface > singular() const
Return the matching&#39;singular&#39; of the interface.
Definition: interface.cpp:390
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
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
static const rc_t OK
The HW write was successfull.
Definition: types.hpp:106
const std::string & name() const
Return the interface type.
Definition: interface.cpp:230
static void enqueue(cmd *f)
Enqueue A command for execution.
Definition: hw.cpp:189
virtual std::shared_ptr< interface > singular_i() const
Return the matching &#39;singular&#39; of the interface.
Definition: interface.cpp:384
vhost_vring_state_t state
Definition: vhost-user.h:82
A cmd class that Dumps all the IPv4 L3 configs.
A command class represents our desire to recieve interface stats.
An interface type.
Definition: interface.hpp:58
virtual std::queue< cmd * > & mk_delete_cmd(std::queue< cmd * > &cmds)
Virtual functions to construct an interface delete commands.
Definition: interface.cpp:261
interface(const std::string &name, type_t type, admin_state_t state)
Construct a new object matching the desried state.
Definition: interface.cpp:39
A command class to delete af-packet interfaces in VPP.
The VPP Object Model (VOM) library.
Definition: acl_binding.cpp:19
A command class to delete loopback interfaces in VPP.
static const admin_state_t UP
Admin UP state.
Definition: interface.hpp:117
A representation of a method call to VPP.
Definition: cmd.hpp:32
static const rc_t UNSET
The value un-set.
Definition: types.hpp:96
Definition: hash.c:482
void set(const rc_t &rc)
Set the HW return code - should only be called from the family of Command objects.
Definition: hw.hpp:124
static const type_t BVI
A brideged Virtual interface (aka SVI or IRB)
Definition: interface.hpp:67
HW::item< bool > m_status
The status of the subscription.
Definition: interface.hpp:405
void show(char *chroot_path, int verbose)
Definition: svmtool.c:105
void set(const l2_address_t &addr)
Set the L2 Address.
Definition: interface.cpp:348
static const admin_state_t DOWN
Admin DOWN state.
Definition: interface.hpp:113
A representation of L3 configuration on an interface.
Definition: l3_binding.hpp:30
static const type_t TAP
TAP interface type.
Definition: interface.hpp:91
static const_iterator_t cend()
Definition: interface.cpp:144
singular_db< const std::string, interface >::const_iterator const_iterator_t
The iterator type.
Definition: interface.hpp:53
virtual std::string to_string(void) const
convert to string format for debug purposes
Definition: interface.cpp:212
vhost_vring_addr_t addr
Definition: vhost-user.h:83
static const type_t LOOPBACK
loopback interface type
Definition: interface.hpp:83
std::string key_t
The key for interface&#39;s key.
Definition: interface.hpp:47
const type_t & type() const
Return the interface type.
Definition: interface.cpp:114
static bool register_listener(listener *listener)
Register a listener of events.
Definition: om.cpp:124
A prefix defintion.
Definition: prefix.hpp:91
const key_t & key() const
Return the interface type.
Definition: interface.cpp:236
void enable_stats(stat_listener &el)
Enable stats for this interface.
Definition: interface.cpp:378
interfaces are the root of the dependency graph