fib: fib api updates
[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           // vapi_type_fib_path& p = payload.route.paths[i];
438           /* if (p.is_local) { */
439           /*   path path_v4(path::special_t::LOCAL); */
440           /*   ip_r.add(path_v4); */
441           /* } */
442           /* } else if (p.is_drop) { */
443           /*   path path_v4(path::special_t::DROP); */
444           /*   ip_r.add(path_v4); */
445           /* } else if (p.is_unreach) { */
446           /*   path path_v4(path::special_t::UNREACH); */
447           /*   ip_r.add(path_v4); */
448           /* } else if (p.is_prohibit) { */
449           /*   path path_v4(path::special_t::PROHIBIT); */
450           /*   ip_r.add(path_v4); */
451           /* } else { */
452           /*   boost::asio::ip::address address = from_bytes(0, p.next_hop);
453            */
454           /*   std::shared_ptr<interface> itf =
455            * interface::find(p.sw_if_index); */
456           /*   if (itf) { */
457           /*     if (p.is_dvr) { */
458           /*       path path_v4(*itf, nh_proto_t::IPV4,
459            * route::path::flags_t::DVR,
460            */
461           /*                    p.weight, p.preference); */
462           /*       ip_r.add(path_v4); */
463           /*     } else { */
464           /*       path path_v4(address, *itf, p.weight, p.preference); */
465           /*       ip_r.add(path_v4); */
466           /*     } */
467           /*   } else { */
468           /*     path path_v4(rd_temp, address, p.weight, p.preference); */
469           /*     ip_r.add(path_v4); */
470           /*   } */
471           /* } */
472         }
473
474         VOM_LOG(log_level_t::DEBUG) << "ip-route-dump: " << ip_r.to_string();
475
476         /*
477          * Write each of the discovered interfaces into the OM,
478          * but disable the HW Command q whilst we do, so that no
479          * commands are sent to VPP
480          */
481         OM::commit(key, ip_r);
482       }
483     }
484   }
485 }
486
487 dependency_t
488 ip_route::event_handler::order() const
489 {
490   return (dependency_t::TABLE);
491 }
492
493 void
494 ip_route::event_handler::show(std::ostream& os)
495 {
496   db_dump(m_db, os);
497 }
498
499 ip_mroute::ip_mroute(const mprefix_t& mprefix)
500   : m_hw(false)
501   , m_rd(route_domain::get_default())
502   , m_mprefix(mprefix)
503   , m_paths()
504 {
505 }
506
507 ip_mroute::ip_mroute(const ip_mroute& r)
508   : m_hw(r.m_hw)
509   , m_rd(r.m_rd)
510   , m_mprefix(r.m_mprefix)
511   , m_paths(r.m_paths)
512 {
513 }
514
515 ip_mroute::ip_mroute(const route_domain& rd, const mprefix_t& mprefix)
516   : m_hw(false)
517   , m_rd(rd.singular())
518   , m_mprefix(mprefix)
519   , m_paths()
520 {
521 }
522
523 void
524 ip_mroute::add(const path& path, const itf_flags_t& flag)
525 {
526   m_paths.insert(std::make_pair(path, flag));
527 }
528
529 ip_mroute::~ip_mroute()
530 {
531   sweep();
532   m_db.release(key(), this);
533 }
534
535 const ip_mroute::key_t
536 ip_mroute::key() const
537 {
538   return (std::make_pair(m_rd->table_id(), m_mprefix));
539 }
540
541 bool
542 ip_mroute::operator==(const ip_mroute& i) const
543 {
544   return ((key() == i.key()) && (m_paths == i.m_paths));
545 }
546
547 void
548 ip_mroute::sweep()
549 {
550   if (m_hw) {
551     for (auto& p : m_paths)
552       HW::enqueue(new ip_mroute_cmds::delete_cmd(m_hw, m_rd->table_id(),
553                                                  m_mprefix, p.first, p.second));
554   }
555   HW::write();
556 }
557
558 void
559 ip_mroute::replay()
560 {
561   if (m_hw) {
562     for (auto& p : m_paths)
563       HW::enqueue(new ip_mroute_cmds::update_cmd(m_hw, m_rd->table_id(),
564                                                  m_mprefix, p.first, p.second));
565   }
566 }
567 std::string
568 ip_mroute::to_string() const
569 {
570   std::ostringstream s;
571   s << "route:[" << m_rd->to_string() << ", " << m_mprefix.to_string() << " ["
572     << m_paths << "]"
573     << "]";
574
575   return (s.str());
576 }
577
578 void
579 ip_mroute::update(const ip_mroute& r)
580 {
581   if (rc_t::OK != m_hw.rc()) {
582     for (auto& p : m_paths)
583       HW::enqueue(new ip_mroute_cmds::update_cmd(m_hw, m_rd->table_id(),
584                                                  m_mprefix, p.first, p.second));
585   }
586 }
587
588 std::shared_ptr<ip_mroute>
589 ip_mroute::find_or_add(const ip_mroute& temp)
590 {
591   return (m_db.find_or_add(temp.key(), temp));
592 }
593
594 std::shared_ptr<ip_mroute>
595 ip_mroute::find(const key_t& k)
596 {
597   return (m_db.find(k));
598 }
599
600 std::shared_ptr<ip_mroute>
601 ip_mroute::singular() const
602 {
603   return find_or_add(*this);
604 }
605
606 void
607 ip_mroute::dump(std::ostream& os)
608 {
609   db_dump(m_db, os);
610 }
611
612 ip_mroute::event_handler::event_handler()
613 {
614   OM::register_listener(this);
615   inspect::register_handler({ "ip-mroute" },
616                             "ip multicast route configurations", this);
617 }
618
619 void
620 ip_mroute::event_handler::handle_replay()
621 {
622   m_db.replay();
623 }
624
625 void
626 ip_mroute::event_handler::handle_populate(const client_db::key_t& key)
627 {
628   // for each known route-domain
629   auto it = route_domain::cbegin();
630
631   while (it != route_domain::cend()) {
632
633     std::vector<l3_proto_t> l3s = { l3_proto_t::IPV4, l3_proto_t::IPV4 };
634
635     for (auto l3 : l3s) {
636       std::shared_ptr<ip_mroute_cmds::dump_cmd> cmd =
637         std::make_shared<ip_mroute_cmds::dump_cmd>(
638           it->second.lock()->table_id(), l3);
639
640       HW::enqueue(cmd);
641       HW::write();
642
643       VOM_LOG(log_level_t::DEBUG) << "ip-mroute-dump: ";
644
645       for (auto& record : *cmd) {
646         auto& payload = record.get_payload();
647
648         std::shared_ptr<route_domain> rd =
649           route_domain::find(payload.route.table_id);
650
651         if (!rd) {
652           continue;
653         }
654
655         mprefix_t pfx = from_api(payload.route.prefix);
656         ip_mroute ip_r(*rd, pfx);
657
658         for (unsigned int i = 0; i < payload.route.n_paths; i++) {
659           ip_r.add(from_api(payload.route.paths[i].path),
660                    from_api(payload.route.paths[i].itf_flags));
661         }
662
663         VOM_LOG(log_level_t::DEBUG) << "ip-mroute-dump: " << ip_r.to_string();
664
665         /*
666          * Write each of the discovered interfaces into the OM,
667          * but disable the HW Command q whilst we do, so that no
668          * commands are sent to VPP
669          */
670         OM::commit(key, ip_r);
671       }
672     }
673   }
674 }
675
676 dependency_t
677 ip_mroute::event_handler::order() const
678 {
679   return (dependency_t::TABLE);
680 }
681
682 void
683 ip_mroute::event_handler::show(std::ostream& os)
684 {
685   db_dump(m_db, os);
686 }
687
688 std::ostream&
689 operator<<(std::ostream& os, const ip_route::key_t& key)
690 {
691   os << "[" << key.first << ", " << key.second.to_string() << "]";
692
693   return (os);
694 }
695
696 std::ostream&
697 operator<<(std::ostream& os, const ip_mroute::key_t& key)
698 {
699   os << "[" << key.first << ", " << key.second.to_string() << "]";
700
701   return (os);
702 }
703
704 std::ostream&
705 operator<<(std::ostream& os, const path_list_t& key)
706 {
707   os << "[";
708   for (auto k : key) {
709     os << k.to_string() << " ";
710   }
711   os << "]";
712
713   return (os);
714 }
715
716 std::ostream&
717 operator<<(std::ostream& os, const mpath_list_t& key)
718 {
719   os << "[";
720   for (auto k : key) {
721     os << "[" << k.first.to_string() << ", " << k.second.to_string() << "]";
722   }
723   os << "]";
724
725   return (os);
726 }
727
728 }; // namespace route
729 }; // namespace VOM
730
731 /*
732  * fd.io coding-style-patch-verification: ON
733  *
734  * Local Variables:
735  * eval: (c-set-style "mozilla")
736  * End:
737  */