blob: f943bf4a616a66137d8b49e875dbf53b1120da3b [file] [log] [blame]
Neale Ranns812ed392017-10-16 04:20:13 -07001/*
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"
Neale Ranns9ef1c0a2017-11-03 04:39:05 -070017#include "vom/interface_cmds.hpp"
18#include "vom/interface_factory.hpp"
19#include "vom/l3_binding_cmds.hpp"
Neale Ranns812ed392017-10-16 04:20:13 -070020#include "vom/logger.hpp"
21#include "vom/prefix.hpp"
22
23namespace VOM {
24/**
25 * A DB of all the interfaces, key on the name
26 */
Neale Rannsfd920602017-11-23 12:15:00 -080027singular_db<interface::key_t, interface> interface::m_db;
Neale Ranns812ed392017-10-16 04:20:13 -070028
29/**
30 * A DB of all the interfaces, key on VPP's handle
31 */
32std::map<handle_t, std::weak_ptr<interface>> interface::m_hdl_db;
33
34interface::event_handler interface::m_evh;
35
36/**
37 * Construct a new object matching the desried state
38 */
39interface::interface(const std::string& name,
40 interface::type_t itf_type,
Neale Ranns4ef42262018-02-20 08:10:44 -080041 interface::admin_state_t itf_state,
42 const std::string& tag)
Neale Ranns812ed392017-10-16 04:20:13 -070043 : m_hdl(handle_t::INVALID)
44 , m_name(name)
45 , m_type(itf_type)
46 , m_state(itf_state)
47 , m_table_id(route::DEFAULT_TABLE)
48 , m_l2_address(l2_address_t::ZERO, rc_t::UNSET)
49 , m_oper(oper_state_t::DOWN)
Neale Ranns4ef42262018-02-20 08:10:44 -080050 , m_tag(tag)
Neale Ranns812ed392017-10-16 04:20:13 -070051{
52}
53
Neale Ranns812ed392017-10-16 04:20:13 -070054interface::interface(const std::string& name,
55 interface::type_t itf_type,
56 interface::admin_state_t itf_state,
Neale Ranns4ef42262018-02-20 08:10:44 -080057 const route_domain& rd,
58 const std::string& tag)
Neale Ranns812ed392017-10-16 04:20:13 -070059 : m_hdl(handle_t::INVALID)
60 , m_name(name)
61 , m_type(itf_type)
62 , m_rd(rd.singular())
63 , m_state(itf_state)
64 , m_table_id(m_rd->table_id())
65 , m_l2_address(l2_address_t::ZERO, rc_t::UNSET)
66 , m_oper(oper_state_t::DOWN)
Neale Ranns4ef42262018-02-20 08:10:44 -080067 , m_tag(tag)
Neale Ranns812ed392017-10-16 04:20:13 -070068{
69}
70
71interface::interface(const interface& o)
72 : m_hdl(o.m_hdl)
73 , m_name(o.m_name)
74 , m_type(o.m_type)
75 , m_rd(o.m_rd)
76 , m_state(o.m_state)
77 , m_table_id(o.m_table_id)
78 , m_l2_address(o.m_l2_address)
79 , m_oper(o.m_oper)
Neale Ranns4ef42262018-02-20 08:10:44 -080080 , m_tag(o.m_tag)
Neale Ranns812ed392017-10-16 04:20:13 -070081{
82}
83
Neale Rannsfd920602017-11-23 12:15:00 -080084bool
85interface::operator==(const interface& i) const
86{
87 return ((key() == i.key()) &&
88 (m_l2_address.data() == i.m_l2_address.data()) &&
89 (m_state == i.m_state) && (m_rd == i.m_rd) && (m_type == i.m_type) &&
90 (m_oper == i.m_oper));
91}
92
Neale Ranns812ed392017-10-16 04:20:13 -070093interface::event_listener::event_listener()
94 : m_status(rc_t::NOOP)
95{
96}
97
98HW::item<bool>&
99interface::event_listener::status()
100{
101 return (m_status);
102}
103
104interface::stat_listener::stat_listener()
105 : m_status(rc_t::NOOP)
106{
107}
108
109HW::item<bool>&
110interface::stat_listener::status()
111{
112 return (m_status);
113}
114
115/**
116 * Return the interface type
117 */
118const interface::type_t&
119interface::type() const
120{
121 return (m_type);
122}
123
124const handle_t&
125interface::handle() const
126{
Neale Ranns263f9552017-11-15 02:52:13 -0800127 return (singular()->handle_i());
128}
129
130const handle_t&
131interface::handle_i() const
132{
Neale Ranns812ed392017-10-16 04:20:13 -0700133 return (m_hdl.data());
134}
135
136const l2_address_t&
137interface::l2_address() const
138{
139 return (m_l2_address.data());
140}
141
142interface::const_iterator_t
143interface::cbegin()
144{
145 return m_db.cbegin();
146}
147
148interface::const_iterator_t
149interface::cend()
150{
151 return m_db.cend();
152}
153
154void
155interface::sweep()
156{
Neale Ranns352ea0c2017-11-14 11:04:28 -0800157 if (m_table_id && (m_table_id.data() != route::DEFAULT_TABLE)) {
Neale Ranns812ed392017-10-16 04:20:13 -0700158 m_table_id.data() = route::DEFAULT_TABLE;
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700159 HW::enqueue(
160 new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl));
161 HW::enqueue(
162 new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV6, m_hdl));
Neale Ranns812ed392017-10-16 04:20:13 -0700163 }
164
Neale Rannsa2ee0292017-11-28 22:29:13 -0800165 if (m_stats) {
166 HW::enqueue(new interface_cmds::stats_disable_cmd(m_hdl.data()));
167 m_stats.reset();
168 }
Mohsin Kazmi5a4f96a2017-11-20 10:23:47 +0100169
Neale Ranns812ed392017-10-16 04:20:13 -0700170 // If the interface is up, bring it down
171 if (m_state && interface::admin_state_t::UP == m_state.data()) {
172 m_state.data() = interface::admin_state_t::DOWN;
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700173 HW::enqueue(new interface_cmds::state_change_cmd(m_state, m_hdl));
Neale Ranns812ed392017-10-16 04:20:13 -0700174 }
Mohsin Kazmi5a4f96a2017-11-20 10:23:47 +0100175
Neale Ranns812ed392017-10-16 04:20:13 -0700176 if (m_hdl) {
177 std::queue<cmd*> cmds;
178 HW::enqueue(mk_delete_cmd(cmds));
179 }
180 HW::write();
181}
182
183void
184interface::replay()
185{
186 if (m_hdl) {
187 std::queue<cmd*> cmds;
188 HW::enqueue(mk_create_cmd(cmds));
189 }
190
191 if (m_state && interface::admin_state_t::UP == m_state.data()) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700192 HW::enqueue(new interface_cmds::state_change_cmd(m_state, m_hdl));
Neale Ranns812ed392017-10-16 04:20:13 -0700193 }
194
Neale Ranns352ea0c2017-11-14 11:04:28 -0800195 if (m_table_id && (m_table_id.data() != route::DEFAULT_TABLE)) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700196 HW::enqueue(
197 new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl));
198 HW::enqueue(
199 new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV6, m_hdl));
Neale Ranns812ed392017-10-16 04:20:13 -0700200 }
201}
202
203interface::~interface()
204{
205 sweep();
206 release();
207}
208
209void
210interface::release()
211{
212 // not in the DB anymore.
213 m_db.release(m_name, this);
214}
215
216std::string
217interface::to_string() const
218{
219 std::ostringstream s;
220 s << "interface:[" << m_name << " type:" << m_type.to_string()
Neale Rannsfd920602017-11-23 12:15:00 -0800221 << " hdl:" << m_hdl.to_string() << " l2-address:["
222 << m_l2_address.to_string() << "]";
Neale Ranns812ed392017-10-16 04:20:13 -0700223
224 if (m_rd) {
225 s << " rd:" << m_rd->to_string();
226 }
227
228 s << " admin-state:" << m_state.to_string()
Neale Ranns4ef42262018-02-20 08:10:44 -0800229 << " oper-state:" << m_oper.to_string();
230
231 if (!m_tag.empty()) {
232 s << " tag:[" << m_tag << "]";
233 }
234
235 s << "]";
Neale Ranns812ed392017-10-16 04:20:13 -0700236
237 return (s.str());
238}
239
240const std::string&
241interface::name() const
242{
243 return (m_name);
244}
245
Neale Rannsfd920602017-11-23 12:15:00 -0800246const interface::key_t&
Neale Ranns812ed392017-10-16 04:20:13 -0700247interface::key() const
248{
249 return (name());
250}
251
252std::queue<cmd*>&
253interface::mk_create_cmd(std::queue<cmd*>& q)
254{
255 if (type_t::LOOPBACK == m_type) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700256 q.push(new interface_cmds::loopback_create_cmd(m_hdl, m_name));
Neale Ranns812ed392017-10-16 04:20:13 -0700257 } else if (type_t::BVI == m_type) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700258 q.push(new interface_cmds::loopback_create_cmd(m_hdl, m_name));
259 q.push(new interface_cmds::set_tag(m_hdl, m_name));
Neale Ranns4ef42262018-02-20 08:10:44 -0800260 /*
261 * set the m_tag for pretty-print
262 */
263 m_tag = m_name;
Neale Ranns812ed392017-10-16 04:20:13 -0700264 } else if (type_t::AFPACKET == m_type) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700265 q.push(new interface_cmds::af_packet_create_cmd(m_hdl, m_name));
Neale Ranns4ef42262018-02-20 08:10:44 -0800266 if (!m_tag.empty())
267 q.push(new interface_cmds::set_tag(m_hdl, m_tag));
Neale Ranns812ed392017-10-16 04:20:13 -0700268 } else if (type_t::TAP == m_type) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700269 q.push(new interface_cmds::tap_create_cmd(m_hdl, m_name));
Neale Ranns4ef42262018-02-20 08:10:44 -0800270 if (!m_tag.empty())
271 q.push(new interface_cmds::set_tag(m_hdl, m_tag));
272 } else if (type_t::VHOST == m_type) {
273 q.push(new interface_cmds::vhost_create_cmd(m_hdl, m_name, m_tag));
Neale Ranns088f0e22017-12-01 00:19:43 -0800274 } else {
275 m_hdl.set(rc_t::OK);
Neale Ranns812ed392017-10-16 04:20:13 -0700276 }
277
278 return (q);
279}
280
281std::queue<cmd*>&
282interface::mk_delete_cmd(std::queue<cmd*>& q)
283{
284 if ((type_t::LOOPBACK == m_type) || (type_t::BVI == m_type)) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700285 q.push(new interface_cmds::loopback_delete_cmd(m_hdl));
Neale Ranns812ed392017-10-16 04:20:13 -0700286 } else if (type_t::AFPACKET == m_type) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700287 q.push(new interface_cmds::af_packet_delete_cmd(m_hdl, m_name));
Neale Ranns812ed392017-10-16 04:20:13 -0700288 } else if (type_t::TAP == m_type) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700289 q.push(new interface_cmds::tap_delete_cmd(m_hdl));
Neale Ranns4ef42262018-02-20 08:10:44 -0800290 } else if (type_t::VHOST == m_type) {
291 q.push(new interface_cmds::vhost_delete_cmd(m_hdl, m_name));
Neale Ranns812ed392017-10-16 04:20:13 -0700292 }
293
294 return (q);
295}
296
297void
298interface::update(const interface& desired)
299{
300 /*
Neale Ranns352ea0c2017-11-14 11:04:28 -0800301 * the desired state is always that the interface should be created
302 */
Neale Ranns812ed392017-10-16 04:20:13 -0700303 if (rc_t::OK != m_hdl.rc()) {
304 std::queue<cmd*> cmds;
305 HW::enqueue(mk_create_cmd(cmds));
Neale Ranns8ac4ce82017-11-17 05:08:55 -0800306 /*
307 * interface create now, so we can barf early if it fails
308 */
309 HW::write();
Neale Ranns812ed392017-10-16 04:20:13 -0700310 }
311
312 /*
Neale Ranns8ac4ce82017-11-17 05:08:55 -0800313 * If the interface is not created do other commands should be issued
314 */
315 if (rc_t::OK != m_hdl.rc())
316 return;
317
318 /*
Neale Ranns352ea0c2017-11-14 11:04:28 -0800319 * change the interface state to that which is deisred
320 */
Neale Ranns812ed392017-10-16 04:20:13 -0700321 if (m_state.update(desired.m_state)) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700322 HW::enqueue(new interface_cmds::state_change_cmd(m_state, m_hdl));
Neale Ranns812ed392017-10-16 04:20:13 -0700323 }
324
325 /*
Neale Ranns352ea0c2017-11-14 11:04:28 -0800326 * change the interface state to that which is deisred
327 */
Neale Ranns812ed392017-10-16 04:20:13 -0700328 if (m_l2_address.update(desired.m_l2_address)) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700329 HW::enqueue(new interface_cmds::set_mac_cmd(m_l2_address, m_hdl));
Neale Ranns812ed392017-10-16 04:20:13 -0700330 }
331
332 /*
Neale Ranns352ea0c2017-11-14 11:04:28 -0800333 * If the interface is mapped into a route domain, set VPP's
334 * table ID
335 */
336 if (m_rd != desired.m_rd) {
337 /*
338 * changing route domains. need to remove all L3 bindings, swap the table
339 * then reapply the bindings.
340 */
341 auto it = l3_binding::cbegin();
342
343 while (it != l3_binding::cend()) {
344 if (it->second.lock()->itf().key() == key())
345 it->second.lock()->sweep();
346 ++it;
347 }
348 m_rd = desired.m_rd;
349 m_table_id.update(m_rd ? m_rd->table_id() : route::DEFAULT_TABLE);
350 HW::enqueue(
351 new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl));
352 HW::enqueue(
353 new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV6, m_hdl));
354 HW::write();
355
356 it = l3_binding::cbegin();
357 while (it != l3_binding::cend()) {
358 if (it->second.lock()->itf().key() == key())
359 it->second.lock()->replay(); //(*it->second.lock());
360 ++it;
361 }
362 } else if (!m_table_id && m_rd) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700363 HW::enqueue(
364 new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl));
365 HW::enqueue(
366 new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV6, m_hdl));
Neale Ranns812ed392017-10-16 04:20:13 -0700367 }
368}
369
370void
Neale Ranns4ef42262018-02-20 08:10:44 -0800371interface::set(const admin_state_t& state)
372{
373 m_state = state;
374}
375
376void
Neale Ranns812ed392017-10-16 04:20:13 -0700377interface::set(const l2_address_t& addr)
378{
379 assert(rc_t::UNSET == m_l2_address.rc());
380 m_l2_address.set(rc_t::NOOP);
381 m_l2_address.update(addr);
382}
383
384void
Neale Rannsa2ee0292017-11-28 22:29:13 -0800385interface::set(const handle_t& hdl)
386{
387 m_hdl = hdl;
388}
389
390void
Neale Ranns812ed392017-10-16 04:20:13 -0700391interface::set(const oper_state_t& state)
392{
393 m_oper = state;
394}
395
Mohsin Kazmi5a4f96a2017-11-20 10:23:47 +0100396void
Neale Ranns4ef42262018-02-20 08:10:44 -0800397interface::set(const std::string& tag)
398{
399 m_tag = tag;
400}
401
402void
Mohsin Kazmi5a4f96a2017-11-20 10:23:47 +0100403interface::enable_stats_i(interface::stat_listener& el)
404{
Neale Ranns088f0e22017-12-01 00:19:43 -0800405 if (!m_stats) {
406 m_stats.reset(new interface_cmds::stats_enable_cmd(el, handle_i()));
407 HW::enqueue(m_stats);
408 HW::write();
409 }
Mohsin Kazmi5a4f96a2017-11-20 10:23:47 +0100410}
411
412void
413interface::enable_stats(interface::stat_listener& el)
414{
415 singular()->enable_stats_i(el);
416}
417
Neale Ranns812ed392017-10-16 04:20:13 -0700418std::shared_ptr<interface>
419interface::singular_i() const
420{
Neale Rannsfd920602017-11-23 12:15:00 -0800421 return (m_db.find_or_add(key(), *this));
Neale Ranns812ed392017-10-16 04:20:13 -0700422}
423
424std::shared_ptr<interface>
425interface::singular() const
426{
427 return singular_i();
428}
429
430std::shared_ptr<interface>
Neale Rannsfd920602017-11-23 12:15:00 -0800431interface::find(const key_t& k)
Neale Ranns812ed392017-10-16 04:20:13 -0700432{
Neale Rannsfd920602017-11-23 12:15:00 -0800433 return (m_db.find(k));
Neale Ranns812ed392017-10-16 04:20:13 -0700434}
435
436std::shared_ptr<interface>
437interface::find(const handle_t& handle)
438{
439 return (m_hdl_db[handle].lock());
440}
441
442void
Neale Rannsfd920602017-11-23 12:15:00 -0800443interface::add(const key_t& key, const HW::item<handle_t>& item)
Neale Ranns812ed392017-10-16 04:20:13 -0700444{
Neale Rannsfd920602017-11-23 12:15:00 -0800445 std::shared_ptr<interface> sp = find(key);
Neale Ranns812ed392017-10-16 04:20:13 -0700446
447 if (sp && item) {
448 m_hdl_db[item.data()] = sp;
449 }
450}
451
452void
453interface::remove(const HW::item<handle_t>& item)
454{
455 m_hdl_db.erase(item.data());
456}
457
458void
459interface::dump(std::ostream& os)
460{
461 m_db.dump(os);
462}
463
464void
465interface::event_handler::handle_populate(const client_db::key_t& key)
466{
Neale Ranns4ef42262018-02-20 08:10:44 -0800467 std::shared_ptr<interface_cmds::vhost_dump_cmd> vcmd =
468 std::make_shared<interface_cmds::vhost_dump_cmd>();
469
470 HW::enqueue(vcmd);
471 HW::write();
472
473 for (auto& vhost_itf_record : *vcmd) {
474 std::shared_ptr<interface> vitf =
475 interface_factory::new_vhost_user_interface(
476 vhost_itf_record.get_payload());
477 VOM_LOG(log_level_t::DEBUG) << "dump: " << vitf->to_string();
478 OM::commit(key, *vitf);
479 }
480
Neale Ranns812ed392017-10-16 04:20:13 -0700481 /*
Neale Rannsfd920602017-11-23 12:15:00 -0800482 * dump VPP current states
483 */
Neale Ranns1d781552017-11-27 04:52:35 -0800484 std::shared_ptr<interface_cmds::dump_cmd> cmd =
485 std::make_shared<interface_cmds::dump_cmd>();
Neale Ranns812ed392017-10-16 04:20:13 -0700486
487 HW::enqueue(cmd);
488 HW::write();
489
490 for (auto& itf_record : *cmd) {
Neale Rannsa2ee0292017-11-28 22:29:13 -0800491 std::shared_ptr<interface> itf =
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700492 interface_factory::new_interface(itf_record.get_payload());
Neale Ranns812ed392017-10-16 04:20:13 -0700493
494 if (itf && interface::type_t::LOCAL != itf->type()) {
495 VOM_LOG(log_level_t::DEBUG) << "dump: " << itf->to_string();
496 /*
Neale Rannsfd920602017-11-23 12:15:00 -0800497 * Write each of the discovered interfaces into the OM,
498 * but disable the HW Command q whilst we do, so that no
499 * commands are sent to VPP
500 */
Neale Ranns812ed392017-10-16 04:20:13 -0700501 OM::commit(key, *itf);
502
503 /**
Neale Rannsfd920602017-11-23 12:15:00 -0800504 * Get the address configured on the interface
505 */
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700506 std::shared_ptr<l3_binding_cmds::dump_v4_cmd> dcmd =
507 std::make_shared<l3_binding_cmds::dump_v4_cmd>(
508 l3_binding_cmds::dump_v4_cmd(itf->handle()));
Neale Ranns812ed392017-10-16 04:20:13 -0700509
510 HW::enqueue(dcmd);
511 HW::write();
512
513 for (auto& l3_record : *dcmd) {
514 auto& payload = l3_record.get_payload();
515 const route::prefix_t pfx(payload.is_ipv6, payload.ip,
516 payload.prefix_length);
517
518 VOM_LOG(log_level_t::DEBUG) << "dump: " << pfx.to_string();
519
520 l3_binding l3(*itf, pfx);
521 OM::commit(key, l3);
522 }
523 }
524 }
525}
526
527interface::event_handler::event_handler()
528{
529 OM::register_listener(this);
530 inspect::register_handler({ "interface", "intf" }, "interfaces", this);
531}
532
533void
534interface::event_handler::handle_replay()
535{
536 m_db.replay();
537}
538
539dependency_t
540interface::event_handler::order() const
541{
542 return (dependency_t::INTERFACE);
543}
544
545void
546interface::event_handler::show(std::ostream& os)
547{
548 m_db.dump(os);
549}
Neale Rannsfd920602017-11-23 12:15:00 -0800550
551} // namespace VOM
552
Neale Ranns812ed392017-10-16 04:20:13 -0700553/*
554 * fd.io coding-style-patch-verification: ON
555 *
556 * Local Variables:
557 * eval: (c-set-style "mozilla")
558 * End:
559 */