vxlan: vxlan/vxlan.api API cleanup
[vpp.git] / extras / vom / vom / route.cpp
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/api_types.hpp"
18 #include "vom/mroute_cmds.hpp"
19 #include "vom/route_api_types.hpp"
20 #include "vom/route_cmds.hpp"
21 #include "vom/singular_db_funcs.hpp"
22
23 namespace VOM {
24 namespace route {
25 ip_route::event_handler ip_route::m_evh;
26 ip_mroute::event_handler ip_mroute::m_evh;
27 singular_db<ip_route::key_t, ip_route> ip_route::m_db;
28 singular_db<ip_mroute::key_t, ip_mroute> ip_mroute::m_db;
29
30 const path::special_t path::special_t::STANDARD(0, "standard");
31 const path::special_t path::special_t::LOCAL(1, "local");
32 const path::special_t path::special_t::DROP(2, "standard");
33 const path::special_t path::special_t::UNREACH(3, "unreachable");
34 const path::special_t path::special_t::PROHIBIT(4, "prohibit");
35
36 path::special_t::special_t(int v, const std::string& s)
37   : enum_base<path::special_t>(v, s)
38 {
39 }
40
41 const path::flags_t path::flags_t::NONE(0, "none");
42 const path::flags_t path::flags_t::DVR((1 << 0), "dvr");
43
44 path::flags_t::flags_t(int v, const std::string& s)
45   : enum_base<path::flags_t>(v, s)
46 {
47 }
48
49 const itf_flags_t itf_flags_t::NONE(0, "none");
50 const itf_flags_t itf_flags_t::ACCEPT((1 << 1), "accept");
51 const itf_flags_t itf_flags_t::FORWARD((1 << 2), "forward");
52
53 itf_flags_t::itf_flags_t(int v, const std::string& s)
54   : enum_base<itf_flags_t>(v, s)
55 {
56 }
57
58 path::path(special_t special, const nh_proto_t& proto)
59   : m_type(special)
60   , m_nh_proto(proto)
61   , m_flags(flags_t::NONE)
62   , m_nh()
63   , m_rd(nullptr)
64   , m_interface(nullptr)
65   , m_weight(1)
66   , m_preference(0)
67 {
68 }
69
70 path::path(const boost::asio::ip::address& nh,
71            const interface& interface,
72            uint8_t weight,
73            uint8_t preference)
74   : m_type(special_t::STANDARD)
75   , m_nh_proto(nh_proto_t::from_address(nh))
76   , m_flags(flags_t::NONE)
77   , m_nh(nh)
78   , m_rd(nullptr)
79   , m_interface(interface.singular())
80   , m_weight(weight)
81   , m_preference(preference)
82 {
83 }
84
85 path::path(const route_domain& rd,
86            const boost::asio::ip::address& nh,
87            uint8_t weight,
88            uint8_t preference)
89   : m_type(special_t::STANDARD)
90   , m_nh_proto(nh_proto_t::from_address(nh))
91   , m_flags(flags_t::NONE)
92   , m_nh(nh)
93   , m_rd(rd.singular())
94   , m_interface(nullptr)
95   , m_weight(weight)
96   , m_preference(preference)
97 {
98 }
99
100 path::path(const interface& interface,
101            const nh_proto_t& proto,
102            const flags_t& flags,
103            uint8_t weight,
104            uint8_t preference)
105   : m_type(special_t::STANDARD)
106   , m_nh_proto(proto)
107   , m_flags(flags)
108   , m_nh()
109   , m_rd(nullptr)
110   , m_interface(interface.singular())
111   , m_weight(weight)
112   , m_preference(preference)
113 {
114 }
115
116 path::path(const path& p)
117   : m_type(p.m_type)
118   , m_nh_proto(p.m_nh_proto)
119   , m_flags(p.m_flags)
120   , m_nh(p.m_nh)
121   , m_rd(p.m_rd)
122   , m_interface(p.m_interface)
123   , m_weight(p.m_weight)
124   , m_preference(p.m_preference)
125 {
126 }
127
128 bool
129 path::operator<(const path& p) const
130 {
131   if (m_nh_proto < p.m_nh_proto)
132     return true;
133   if (m_flags < p.m_flags)
134     return true;
135   if (m_type < p.m_type)
136     return true;
137   if (m_rd && !p.m_rd)
138     return false;
139   if (!m_rd && p.m_rd)
140     return true;
141   if (m_rd && p.m_rd) {
142     if (m_rd->table_id() < p.m_rd->table_id())
143       return true;
144     else if (m_rd->table_id() > p.m_rd->table_id())
145       return false;
146   }
147   if (m_nh < p.m_nh)
148     return true;
149   if (m_interface && !p.m_interface)
150     return false;
151   if (!m_interface && p.m_interface)
152     return true;
153   if (m_interface && p.m_interface) {
154     if (m_interface->handle() < p.m_interface->handle())
155       return true;
156     if (p.m_interface->handle() < m_interface->handle())
157       return false;
158   }
159
160   return (false);
161 }
162
163 path::~path()
164 {
165 }
166
167 bool
168 path::operator==(const path& p) const
169 {
170   bool result = true;
171   if (m_rd && !p.m_rd)
172     return false;
173   if (!m_rd && p.m_rd)
174     return false;
175   if (m_rd && p.m_rd)
176     result &= (*m_rd == *p.m_rd);
177   if (m_interface && !p.m_interface)
178     return false;
179   if (!m_interface && p.m_interface)
180     return false;
181   if (m_interface && p.m_interface)
182     result &= (*m_interface == *p.m_interface);
183   return (result && (m_type == p.m_type) && (m_nh == p.m_nh) &&
184           (m_nh_proto == p.m_nh_proto) && (m_flags == p.m_flags));
185 }
186
187 std::string
188 path::to_string() const
189 {
190   std::ostringstream s;
191
192   s << "path:["
193     << "type:" << m_type.to_string() << " proto:" << m_nh_proto.to_string()
194     << " flags:" << m_flags.to_string() << " neighbour:" << m_nh.to_string();
195   if (m_rd) {
196     s << " " << m_rd->to_string();
197   }
198   if (m_interface) {
199     s << " " << m_interface->to_string();
200   }
201   s << " weight:" << static_cast<int>(m_weight)
202     << " preference:" << static_cast<int>(m_preference) << "]";
203
204   return (s.str());
205 }
206
207 path::special_t
208 path::type() const
209 {
210   return m_type;
211 }
212
213 nh_proto_t
214 path::nh_proto() const
215 {
216   return m_nh_proto;
217 }
218
219 path::flags_t
220 path::flags() const
221 {
222   return m_flags;
223 }
224
225 const boost::asio::ip::address&
226 path::nh() const
227 {
228   return m_nh;
229 }
230
231 std::shared_ptr<route_domain>
232 path::rd() const
233 {
234   return m_rd;
235 }
236
237 std::shared_ptr<interface>
238 path::itf() const
239 {
240   return m_interface;
241 }
242
243 uint8_t
244 path::weight() const
245 {
246   return m_weight;
247 }
248
249 uint8_t
250 path::preference() const
251 {
252   return m_preference;
253 }
254
255 ip_route::ip_route(const prefix_t& prefix, const path& p)
256   : m_hw(false)
257   , m_rd(route_domain::get_default())
258   , m_prefix(prefix)
259   , m_paths({ p })
260 {
261 }
262
263 ip_route::ip_route(const prefix_t& prefix)
264   : m_hw(false)
265   , m_rd(route_domain::get_default())
266   , m_prefix(prefix)
267   , m_paths()
268 {
269 }
270
271 ip_route::ip_route(const ip_route& r)
272   : m_hw(r.m_hw)
273   , m_rd(r.m_rd)
274   , m_prefix(r.m_prefix)
275   , m_paths(r.m_paths)
276 {
277 }
278
279 ip_route::ip_route(const route_domain& rd, const prefix_t& prefix)
280   : m_hw(false)
281   , m_rd(rd.singular())
282   , m_prefix(prefix)
283   , m_paths()
284 {
285 }
286
287 ip_route::ip_route(const route_domain& rd,
288                    const prefix_t& prefix,
289                    const path& p)
290   : m_hw(false)
291   , m_rd(rd.singular())
292   , m_prefix(prefix)
293   , m_paths({ p })
294 {
295 }
296
297 ip_route::~ip_route()
298 {
299   sweep();
300
301   // not in the DB anymore.
302   m_db.release(key(), this);
303   m_paths.clear();
304 }
305
306 const ip_route::key_t
307 ip_route::key() const
308 {
309   return (std::make_pair(m_rd->table_id(), m_prefix));
310 }
311
312 bool
313 ip_route::operator==(const ip_route& i) const
314 {
315   return ((key() == i.key()) && (m_paths == i.m_paths));
316 }
317
318 void
319 ip_route::add(const path& path)
320 {
321   m_paths.insert(path);
322 }
323
324 void
325 ip_route::remove(const path& path)
326 {
327   m_paths.erase(path);
328 }
329
330 void
331 ip_route::sweep()
332 {
333   if (m_hw) {
334     HW::enqueue(
335       new ip_route_cmds::delete_cmd(m_hw, m_rd->table_id(), m_prefix));
336   }
337   HW::write();
338 }
339
340 void
341 ip_route::replay()
342 {
343   if (m_hw) {
344     HW::enqueue(
345       new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, m_paths));
346   }
347 }
348 std::string
349 ip_route::to_string() const
350 {
351   std::ostringstream s;
352   s << "route:[" << m_rd->to_string() << ", " << m_prefix.to_string() << " ["
353     << m_paths << "]"
354     << "]";
355
356   return (s.str());
357 }
358
359 void
360 ip_route::update(const ip_route& r)
361 {
362   m_paths = r.m_paths;
363   HW::enqueue(
364     new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, m_paths));
365 }
366
367 std::shared_ptr<ip_route>
368 ip_route::find_or_add(const ip_route& temp)
369 {
370   return (m_db.find_or_add(temp.key(), temp));
371 }
372
373 std::shared_ptr<ip_route>
374 ip_route::find(const key_t& k)
375 {
376   return (m_db.find(k));
377 }
378
379 std::shared_ptr<ip_route>
380 ip_route::singular() const
381 {
382   return find_or_add(*this);
383 }
384
385 void
386 ip_route::dump(std::ostream& os)
387 {
388   db_dump(m_db, os);
389 }
390
391 ip_route::event_handler::event_handler()
392 {
393   OM::register_listener(this);
394   inspect::register_handler({ "ip-route" }, "ip route configurations", this);
395 }
396
397 void
398 ip_route::event_handler::handle_replay()
399 {
400   m_db.replay();
401 }
402
403 void
404 ip_route::event_handler::handle_populate(const client_db::key_t& key)
405 {
406   // for each known route-domain
407   auto it = route_domain::cbegin();
408
409   while (it != route_domain::cend()) {
410
411     std::vector<l3_proto_t> l3s = { l3_proto_t::IPV4, l3_proto_t::IPV4 };
412
413     for (auto l3 : l3s) {
414       std::shared_ptr<ip_route_cmds::dump_cmd> cmd =
415         std::make_shared<ip_route_cmds::dump_cmd>(it->second.lock()->table_id(),
416                                                   l3);
417
418       HW::enqueue(cmd);
419       HW::write();
420
421       for (auto& record : *cmd) {
422         auto& payload = record.get_payload();
423
424         std::shared_ptr<route_domain> rd =
425           route_domain::find(payload.route.table_id);
426
427         if (!rd) {
428           continue;
429         }
430
431         prefix_t pfx = from_api(payload.route.prefix);
432         ip_route ip_r(*rd, pfx);
433
434         for (unsigned int i = 0; i < payload.route.n_paths; i++) {
435           ip_r.add(from_api(payload.route.paths[i]));
436         }
437
438         VOM_LOG(log_level_t::DEBUG) << "ip-route-dump: " << ip_r.to_string();
439
440         /*
441          * Write each of the discovered interfaces into the OM,
442          * but disable the HW Command q whilst we do, so that no
443          * commands are sent to VPP
444          */
445         OM::commit(key, ip_r);
446       }
447     }
448     ++it;
449   }
450 }
451
452 dependency_t
453 ip_route::event_handler::order() const
454 {
455   return (dependency_t::TABLE);
456 }
457
458 void
459 ip_route::event_handler::show(std::ostream& os)
460 {
461   db_dump(m_db, os);
462 }
463
464 ip_mroute::ip_mroute(const mprefix_t& mprefix)
465   : m_hw(false)
466   , m_rd(route_domain::get_default())
467   , m_mprefix(mprefix)
468   , m_paths()
469 {
470 }
471
472 ip_mroute::ip_mroute(const ip_mroute& r)
473   : m_hw(r.m_hw)
474   , m_rd(r.m_rd)
475   , m_mprefix(r.m_mprefix)
476   , m_paths(r.m_paths)
477 {
478 }
479
480 ip_mroute::ip_mroute(const route_domain& rd, const mprefix_t& mprefix)
481   : m_hw(false)
482   , m_rd(rd.singular())
483   , m_mprefix(mprefix)
484   , m_paths()
485 {
486 }
487
488 void
489 ip_mroute::add(const path& path, const itf_flags_t& flag)
490 {
491   m_paths.insert(std::make_pair(path, flag));
492 }
493
494 ip_mroute::~ip_mroute()
495 {
496   sweep();
497   m_db.release(key(), this);
498 }
499
500 const ip_mroute::key_t
501 ip_mroute::key() const
502 {
503   return (std::make_pair(m_rd->table_id(), m_mprefix));
504 }
505
506 bool
507 ip_mroute::operator==(const ip_mroute& i) const
508 {
509   return ((key() == i.key()) && (m_paths == i.m_paths));
510 }
511
512 void
513 ip_mroute::sweep()
514 {
515   if (m_hw) {
516     for (auto& p : m_paths)
517       HW::enqueue(new ip_mroute_cmds::delete_cmd(m_hw, m_rd->table_id(),
518                                                  m_mprefix, p.first, p.second));
519   }
520   HW::write();
521 }
522
523 void
524 ip_mroute::replay()
525 {
526   if (m_hw) {
527     for (auto& p : m_paths)
528       HW::enqueue(new ip_mroute_cmds::update_cmd(m_hw, m_rd->table_id(),
529                                                  m_mprefix, p.first, p.second));
530   }
531 }
532 std::string
533 ip_mroute::to_string() const
534 {
535   std::ostringstream s;
536   s << "route:[" << m_rd->to_string() << ", " << m_mprefix.to_string() << " ["
537     << m_paths << "]"
538     << "]";
539
540   return (s.str());
541 }
542
543 void
544 ip_mroute::update(const ip_mroute& r)
545 {
546   if (rc_t::OK != m_hw.rc()) {
547     for (auto& p : m_paths)
548       HW::enqueue(new ip_mroute_cmds::update_cmd(m_hw, m_rd->table_id(),
549                                                  m_mprefix, p.first, p.second));
550   }
551 }
552
553 std::shared_ptr<ip_mroute>
554 ip_mroute::find_or_add(const ip_mroute& temp)
555 {
556   return (m_db.find_or_add(temp.key(), temp));
557 }
558
559 std::shared_ptr<ip_mroute>
560 ip_mroute::find(const key_t& k)
561 {
562   return (m_db.find(k));
563 }
564
565 std::shared_ptr<ip_mroute>
566 ip_mroute::singular() const
567 {
568   return find_or_add(*this);
569 }
570
571 void
572 ip_mroute::dump(std::ostream& os)
573 {
574   db_dump(m_db, os);
575 }
576
577 ip_mroute::event_handler::event_handler()
578 {
579   OM::register_listener(this);
580   inspect::register_handler({ "ip-mroute" },
581                             "ip multicast route configurations", this);
582 }
583
584 void
585 ip_mroute::event_handler::handle_replay()
586 {
587   m_db.replay();
588 }
589
590 void
591 ip_mroute::event_handler::handle_populate(const client_db::key_t& key)
592 {
593   // for each known route-domain
594   auto it = route_domain::cbegin();
595
596   while (it != route_domain::cend()) {
597
598     std::vector<l3_proto_t> l3s = { l3_proto_t::IPV4, l3_proto_t::IPV4 };
599
600     for (auto l3 : l3s) {
601       std::shared_ptr<ip_mroute_cmds::dump_cmd> cmd =
602         std::make_shared<ip_mroute_cmds::dump_cmd>(
603           it->second.lock()->table_id(), l3);
604
605       HW::enqueue(cmd);
606       HW::write();
607
608       VOM_LOG(log_level_t::DEBUG) << "ip-mroute-dump: ";
609
610       for (auto& record : *cmd) {
611         auto& payload = record.get_payload();
612
613         std::shared_ptr<route_domain> rd =
614           route_domain::find(payload.route.table_id);
615
616         if (!rd) {
617           continue;
618         }
619
620         mprefix_t pfx = from_api(payload.route.prefix);
621         ip_mroute ip_r(*rd, pfx);
622
623         for (unsigned int i = 0; i < payload.route.n_paths; i++) {
624           ip_r.add(from_api(payload.route.paths[i].path),
625                    from_api(payload.route.paths[i].itf_flags));
626         }
627
628         VOM_LOG(log_level_t::DEBUG) << "ip-mroute-dump: " << ip_r.to_string();
629
630         /*
631          * Write each of the discovered interfaces into the OM,
632          * but disable the HW Command q whilst we do, so that no
633          * commands are sent to VPP
634          */
635         OM::commit(key, ip_r);
636       }
637     }
638     ++it;
639   }
640 }
641
642 dependency_t
643 ip_mroute::event_handler::order() const
644 {
645   return (dependency_t::TABLE);
646 }
647
648 void
649 ip_mroute::event_handler::show(std::ostream& os)
650 {
651   db_dump(m_db, os);
652 }
653
654 std::ostream&
655 operator<<(std::ostream& os, const ip_route::key_t& key)
656 {
657   os << "[" << key.first << ", " << key.second.to_string() << "]";
658
659   return (os);
660 }
661
662 std::ostream&
663 operator<<(std::ostream& os, const ip_mroute::key_t& key)
664 {
665   os << "[" << key.first << ", " << key.second.to_string() << "]";
666
667   return (os);
668 }
669
670 std::ostream&
671 operator<<(std::ostream& os, const path_list_t& key)
672 {
673   os << "[";
674   for (auto k : key) {
675     os << k.to_string() << " ";
676   }
677   os << "]";
678
679   return (os);
680 }
681
682 std::ostream&
683 operator<<(std::ostream& os, const mpath_list_t& key)
684 {
685   os << "[";
686   for (auto k : key) {
687     os << "[" << k.first.to_string() << ", " << k.second.to_string() << "]";
688   }
689   os << "]";
690
691   return (os);
692 }
693
694 }; // namespace route
695 }; // namespace VOM
696
697 /*
698  * fd.io coding-style-patch-verification: ON
699  *
700  * Local Variables:
701  * eval: (c-set-style "mozilla")
702  * End:
703  */