blob: ece0768e63405b3cf2fbf1f37c94b2163ae341e4 [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/route.hpp"
Neale Ranns9ef1c0a2017-11-03 04:39:05 -070017#include "vom/route_cmds.hpp"
Neale Ranns812ed392017-10-16 04:20:13 -070018#include "vom/singular_db.hpp"
19
Neale Ranns812ed392017-10-16 04:20:13 -070020namespace VOM {
21namespace route {
22singular_db<ip_route::key_t, ip_route> ip_route::m_db;
23
24const path::special_t path::special_t::STANDARD(0, "standard");
25const path::special_t path::special_t::LOCAL(0, "local");
26const path::special_t path::special_t::DROP(0, "standard");
27const path::special_t path::special_t::UNREACH(0, "unreachable");
28const path::special_t path::special_t::PROHIBIT(0, "prohibit");
29
30path::special_t::special_t(int v, const std::string& s)
31 : enum_base<path::special_t>(v, s)
32{
33}
34
35path::path(special_t special)
36 : m_type(special)
37 , m_nh_proto(nh_proto_t::IPV4)
38 , m_nh()
39 , m_rd(nullptr)
40 , m_interface(nullptr)
41 , m_weight(1)
42 , m_preference(0)
43{
44}
45
46path::path(const boost::asio::ip::address& nh,
47 const interface& interface,
48 uint8_t weight,
49 uint8_t preference)
50 : m_type(special_t::STANDARD)
51 , m_nh_proto(nh_proto_t::from_address(nh))
52 , m_nh(nh)
53 , m_rd(nullptr)
54 , m_interface(interface.singular())
55 , m_weight(weight)
56 , m_preference(preference)
57{
58}
59
60path::path(const route_domain& rd,
61 const boost::asio::ip::address& nh,
62 uint8_t weight,
63 uint8_t preference)
64 : m_type(special_t::STANDARD)
65 , m_nh_proto(nh_proto_t::from_address(nh))
66 , m_nh(nh)
67 , m_rd(rd.singular())
68 , m_interface(nullptr)
69 , m_weight(weight)
70 , m_preference(preference)
71{
72}
73
74path::path(const interface& interface,
75 const nh_proto_t& proto,
76 uint8_t weight,
77 uint8_t preference)
78 : m_type(special_t::STANDARD)
79 , m_nh_proto(proto)
80 , m_nh()
81 , m_rd(nullptr)
82 , m_interface(interface.singular())
83 , m_weight(weight)
84 , m_preference(preference)
85{
86}
87
88path::path(const path& p)
89 : m_type(p.m_type)
90 , m_nh_proto(p.m_nh_proto)
91 , m_nh(p.m_nh)
92 , m_rd(p.m_rd)
93 , m_interface(p.m_interface)
94 , m_weight(p.m_weight)
95 , m_preference(p.m_preference)
96{
97}
98
99bool
100path::operator<(const path& p) const
101{
102 if (m_type < p.m_type)
103 return true;
104 if (m_rd->table_id() < p.m_rd->table_id())
105 return true;
106 if (m_nh < p.m_nh)
107 return true;
108 if (m_interface->handle() < p.m_interface->handle())
109 return true;
110
111 return (false);
112}
113
Neale Ranns812ed392017-10-16 04:20:13 -0700114std::string
115path::to_string() const
116{
117 std::ostringstream s;
118
119 s << "path:["
120 << "type:" << m_type.to_string() << " proto:" << m_nh_proto.to_string()
121 << " neighbour:" << m_nh.to_string();
122 if (m_rd) {
123 s << " " << m_rd->to_string();
124 }
125 if (m_interface) {
126 s << " " << m_interface->to_string();
127 }
128 s << " weight:" << static_cast<int>(m_weight)
129 << " preference:" << static_cast<int>(m_preference) << "]";
130
131 return (s.str());
132}
133
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700134path::special_t
135path::type() const
136{
137 return m_type;
138}
139
140nh_proto_t
141path::nh_proto() const
142{
143 return m_nh_proto;
144}
145
146const boost::asio::ip::address&
147path::nh() const
148{
149 return m_nh;
150}
151
152std::shared_ptr<route_domain>
153path::rd() const
154{
155 return m_rd;
156}
157
158std::shared_ptr<interface>
159path::itf() const
160{
161 return m_interface;
162}
163
164uint8_t
165path::weight() const
166{
167 return m_weight;
168}
169
170uint8_t
171path::preference() const
172{
173 return m_preference;
174}
175
Neale Ranns812ed392017-10-16 04:20:13 -0700176ip_route::ip_route(const prefix_t& prefix)
177 : m_hw(false)
178 , m_rd(route_domain::get_default())
179 , m_prefix(prefix)
180 , m_paths()
181{
182}
183
184ip_route::ip_route(const ip_route& r)
185 : m_hw(r.m_hw)
186 , m_rd(r.m_rd)
187 , m_prefix(r.m_prefix)
188 , m_paths(r.m_paths)
189{
190}
191
192ip_route::ip_route(const route_domain& rd, const prefix_t& prefix)
193 : m_hw(false)
194 , m_rd(rd.singular())
195 , m_prefix(prefix)
196 , m_paths()
197{
198}
199
200ip_route::~ip_route()
201{
202 sweep();
203
204 // not in the DB anymore.
205 m_db.release(std::make_pair(m_rd->table_id(), m_prefix), this);
206}
207
208void
209ip_route::add(const path& path)
210{
211 m_paths.insert(path);
212}
213
214void
215ip_route::remove(const path& path)
216{
217 m_paths.erase(path);
218}
219
220void
221ip_route::sweep()
222{
223 if (m_hw) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700224 HW::enqueue(
225 new ip_route_cmds::delete_cmd(m_hw, m_rd->table_id(), m_prefix));
Neale Ranns812ed392017-10-16 04:20:13 -0700226 }
227 HW::write();
228}
229
230void
231ip_route::replay()
232{
233 if (m_hw) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700234 HW::enqueue(
235 new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, m_paths));
Neale Ranns812ed392017-10-16 04:20:13 -0700236 }
237}
238std::string
239ip_route::to_string() const
240{
241 std::ostringstream s;
242 s << "route:[" << m_rd->to_string() << ", " << m_prefix.to_string() << " ["
243 << m_paths << "]"
244 << "]";
245
246 return (s.str());
247}
248
249void
250ip_route::update(const ip_route& r)
251{
252 /*
253* create the table if it is not yet created
254*/
255 if (rc_t::OK != m_hw.rc()) {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700256 HW::enqueue(
257 new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, m_paths));
Neale Ranns812ed392017-10-16 04:20:13 -0700258 }
259}
260
261std::shared_ptr<ip_route>
262ip_route::find_or_add(const ip_route& temp)
263{
264 return (m_db.find_or_add(std::make_pair(temp.m_rd->table_id(), temp.m_prefix),
265 temp));
266}
267
268std::shared_ptr<ip_route>
269ip_route::singular() const
270{
271 return find_or_add(*this);
272}
273
274void
275ip_route::dump(std::ostream& os)
276{
277 m_db.dump(os);
278}
279
280ip_route::event_handler::event_handler()
281{
282 OM::register_listener(this);
283 inspect::register_handler({ "ip-route" }, "ip route configurations", this);
284}
285
286void
287ip_route::event_handler::handle_replay()
288{
289 m_db.replay();
290}
291
292void
293ip_route::event_handler::handle_populate(const client_db::key_t& key)
294{
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700295 std::shared_ptr<ip_route_cmds::dump_v4_cmd> cmd_v4(
296 new ip_route_cmds::dump_v4_cmd());
297 std::shared_ptr<ip_route_cmds::dump_v6_cmd> cmd_v6(
298 new ip_route_cmds::dump_v6_cmd());
Neale Ranns812ed392017-10-16 04:20:13 -0700299
300 HW::enqueue(cmd_v4);
301 HW::enqueue(cmd_v6);
302 HW::write();
303
304 for (auto& record : *cmd_v4) {
305 auto& payload = record.get_payload();
306
307 prefix_t pfx(0, payload.address, payload.address_length);
308
309 /**
310* populating the route domain here
311*/
312 route_domain rd_temp(payload.table_id);
313 std::shared_ptr<route_domain> rd = route_domain::find(rd_temp);
314 if (!rd) {
315 OM::commit(key, rd_temp);
316 }
317 ip_route ip_r(rd_temp, pfx);
318
319 for (unsigned int i = 0; i < payload.count; i++) {
320 vapi_type_fib_path p = payload.path[i];
321 if (p.is_local) {
322 path path_v4(path::special_t::LOCAL);
323 ip_r.add(path_v4);
324 } else if (p.is_drop) {
325 path path_v4(path::special_t::DROP);
326 ip_r.add(path_v4);
327 } else if (p.is_unreach) {
328 path path_v4(path::special_t::UNREACH);
329 ip_r.add(path_v4);
330 } else if (p.is_prohibit) {
331 path path_v4(path::special_t::PROHIBIT);
332 ip_r.add(path_v4);
333 } else {
334 std::shared_ptr<interface> itf = interface::find(p.sw_if_index);
335 boost::asio::ip::address address = from_bytes(0, p.next_hop);
336 path path_v4(address, *itf, p.weight, p.preference);
337 ip_r.add(path_v4);
338 }
339 }
340 VOM_LOG(log_level_t::DEBUG) << "ip-route-dump: " << ip_r.to_string();
341
342 /*
343* Write each of the discovered interfaces into the OM,
344* but disable the HW Command q whilst we do, so that no
345* commands are sent to VPP
346*/
347 OM::commit(key, ip_r);
348 }
349
350 for (auto& record : *cmd_v6) {
351 auto& payload = record.get_payload();
352
353 prefix_t pfx(1, payload.address, payload.address_length);
354 route_domain rd_temp(payload.table_id);
355 std::shared_ptr<route_domain> rd = route_domain::find(rd_temp);
356 if (!rd) {
357 OM::commit(key, rd_temp);
358 }
359 ip_route ip_r(rd_temp, pfx);
360
361 for (unsigned int i = 0; i < payload.count; i++) {
362 vapi_type_fib_path p = payload.path[i];
363 if (p.is_local) {
364 path path_v6(path::special_t::LOCAL);
365 ip_r.add(path_v6);
366 } else if (p.is_drop) {
367 path path_v6(path::special_t::DROP);
368 ip_r.add(path_v6);
369 } else if (p.is_unreach) {
370 path path_v6(path::special_t::UNREACH);
371 ip_r.add(path_v6);
372 } else if (p.is_prohibit) {
373 path path_v6(path::special_t::PROHIBIT);
374 ip_r.add(path_v6);
375 } else {
376 std::shared_ptr<interface> itf = interface::find(p.sw_if_index);
377 boost::asio::ip::address address = from_bytes(1, p.next_hop);
378 path path_v6(address, *itf, p.weight, p.preference);
379 ip_r.add(path_v6);
380 }
381 }
382 VOM_LOG(log_level_t::DEBUG) << "ip-route-dump: " << ip_r.to_string();
383
384 /*
385* Write each of the discovered interfaces into the OM,
386* but disable the HW Command q whilst we do, so that no
387* commands are sent to VPP
388*/
389 OM::commit(key, ip_r);
390 }
391}
392
393dependency_t
394ip_route::event_handler::order() const
395{
396 return (dependency_t::BINDING);
397}
398
399void
400ip_route::event_handler::show(std::ostream& os)
401{
402 m_db.dump(os);
403}
404
405std::ostream&
406operator<<(std::ostream& os, const ip_route::key_t& key)
407{
408 os << "[" << key.first << ", " << key.second.to_string() << "]";
409
410 return (os);
411}
412
413std::ostream&
414operator<<(std::ostream& os, const path_list_t& key)
415{
416 os << "[";
417 for (auto k : key) {
418 os << k.to_string() << " ";
419 }
420 os << "]";
421
422 return (os);
423}
424}
425}
426/*
427 * fd.io coding-style-patch-verification: ON
428 *
429 * Local Variables:
430 * eval: (c-set-style "mozilla")
431 * End:
432 */