VOM: mroutes
[vpp.git] / extras / vom / vom / prefix.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 <boost/algorithm/string.hpp>
17 #include <sstream>
18
19 #include "vom/prefix.hpp"
20
21 namespace VOM {
22 /*
23  * Keep this in sync with VPP's fib_protocol_t
24  */
25 const l3_proto_t l3_proto_t::IPV4(0, "ipv4");
26 const l3_proto_t l3_proto_t::IPV6(1, "ipv6");
27 const l3_proto_t l3_proto_t::MPLS(2, "mpls");
28
29 l3_proto_t::l3_proto_t(int v, const std::string& s)
30   : enum_base<l3_proto_t>(v, s)
31 {
32 }
33
34 bool
35 l3_proto_t::is_ipv6()
36 {
37   return (*this == IPV6);
38 }
39
40 bool
41 l3_proto_t::is_ipv4()
42 {
43   return (*this == IPV4);
44 }
45
46 const l3_proto_t&
47 l3_proto_t::from_address(const boost::asio::ip::address& addr)
48 {
49   if (addr.is_v6()) {
50     return IPV6;
51   }
52
53   return IPV4;
54 }
55
56 const nh_proto_t&
57 l3_proto_t::to_nh_proto() const
58 {
59   if (*this == IPV4)
60     return nh_proto_t::IPV4;
61   else if (*this == IPV6)
62     return nh_proto_t::IPV6;
63   else if (*this == MPLS)
64     return nh_proto_t::MPLS;
65
66   return nh_proto_t::IPV4;
67 }
68
69 std::ostream&
70 operator<<(std::ostream& os, const l3_proto_t& l3p)
71 {
72   os << l3p.to_string();
73   return os;
74 }
75
76 /*
77  * Keep this in sync with VPP's dpo_proto_t
78  */
79 const nh_proto_t nh_proto_t::IPV4(0, "ipv4");
80 const nh_proto_t nh_proto_t::IPV6(1, "ipv6");
81 const nh_proto_t nh_proto_t::MPLS(2, "mpls");
82 const nh_proto_t nh_proto_t::ETHERNET(3, "ethernet");
83
84 nh_proto_t::nh_proto_t(int v, const std::string& s)
85   : enum_base<nh_proto_t>(v, s)
86 {
87 }
88
89 const nh_proto_t&
90 nh_proto_t::from_address(const boost::asio::ip::address& addr)
91 {
92   if (addr.is_v6()) {
93     return IPV6;
94   }
95
96   return IPV4;
97 }
98
99 /**
100  * The all Zeros prefix
101  */
102 const route::prefix_t route::prefix_t::ZERO("0.0.0.0", 0);
103 const route::prefix_t route::prefix_t::ZEROv6("::", 0);
104
105 route::prefix_t::prefix_t(const boost::asio::ip::address& addr, uint8_t len)
106   : m_addr(addr)
107   , m_len(len)
108 {
109 }
110
111 route::prefix_t::prefix_t(const boost::asio::ip::address& addr)
112   : m_addr(addr)
113   , m_len(VOM::mask_width(addr))
114 {
115 }
116
117 route::prefix_t::prefix_t(const std::string& s, uint8_t len)
118   : m_addr(boost::asio::ip::address::from_string(s))
119   , m_len(len)
120 {
121 }
122
123 route::prefix_t::prefix_t(const prefix_t& o)
124   : m_addr(o.m_addr)
125   , m_len(o.m_len)
126 {
127 }
128
129 route::prefix_t::prefix_t()
130   : m_addr()
131   , m_len(0)
132 {
133 }
134
135 route::prefix_t::~prefix_t()
136 {
137 }
138
139 route::prefix_t&
140 route::prefix_t::operator=(const route::prefix_t& o)
141 {
142   m_addr = o.m_addr;
143   m_len = o.m_len;
144
145   return (*this);
146 }
147
148 const boost::asio::ip::address&
149 route::prefix_t::address() const
150 {
151   return (m_addr);
152 }
153
154 uint8_t
155 route::prefix_t::mask_width() const
156 {
157   return (m_len);
158 }
159
160 bool
161 route::prefix_t::operator<(const route::prefix_t& o) const
162 {
163   if (m_len == o.m_len) {
164     return (m_addr < o.m_addr);
165   } else {
166     return (m_len < o.m_len);
167   }
168 }
169
170 bool
171 route::prefix_t::operator==(const route::prefix_t& o) const
172 {
173   return (m_len == o.m_len && m_addr == o.m_addr);
174 }
175
176 bool
177 route::prefix_t::operator!=(const route::prefix_t& o) const
178 {
179   return (!(*this == o));
180 }
181
182 std::string
183 route::prefix_t::to_string() const
184 {
185   std::ostringstream s;
186
187   s << m_addr.to_string() << "/" << std::to_string(m_len);
188
189   return (s.str());
190 }
191
192 boost::asio::ip::address
193 from_bytes(uint8_t is_ip6, const uint8_t* bytes)
194 {
195   boost::asio::ip::address addr;
196
197   if (is_ip6) {
198     std::array<uint8_t, 16> a;
199     std::copy(bytes, bytes + 16, std::begin(a));
200     boost::asio::ip::address_v6 v6(a);
201     addr = v6;
202   } else {
203     std::array<uint8_t, 4> a;
204     std::copy(bytes, bytes + 4, std::begin(a));
205     boost::asio::ip::address_v4 v4(a);
206     addr = v4;
207   }
208
209   return (addr);
210 }
211
212 route::prefix_t::prefix_t(uint8_t is_ip6, uint8_t* addr, uint8_t len)
213   : m_addr(from_bytes(is_ip6, addr))
214   , m_len(len)
215 {
216 }
217 void
218 to_bytes(const boost::asio::ip::address_v6& addr, uint8_t* array)
219 {
220   memcpy(array, addr.to_bytes().data(), 16);
221 }
222
223 void
224 to_bytes(const boost::asio::ip::address_v4& addr, uint8_t* array)
225 {
226   memcpy(array, addr.to_bytes().data(), 4);
227 }
228
229 void
230 to_bytes(const boost::asio::ip::address& addr, uint8_t* is_ip6, uint8_t* array)
231 {
232   if (addr.is_v6()) {
233     *is_ip6 = 1;
234     to_bytes(addr.to_v6(), array);
235   } else {
236     *is_ip6 = 0;
237     to_bytes(addr.to_v4(), array);
238   }
239 }
240
241 uint32_t
242 mask_width(const boost::asio::ip::address& addr)
243 {
244   if (addr.is_v6()) {
245     return 128;
246   }
247   return 32;
248 }
249
250 void
251 route::prefix_t::to_vpp(uint8_t* is_ip6, uint8_t* addr, uint8_t* len) const
252 {
253   *len = m_len;
254   to_bytes(m_addr, is_ip6, addr);
255 }
256
257 l3_proto_t
258 route::prefix_t::l3_proto() const
259 {
260   if (m_addr.is_v6()) {
261     return (l3_proto_t::IPV6);
262   } else {
263     return (l3_proto_t::IPV4);
264   }
265
266   return (l3_proto_t::IPV4);
267 }
268
269 std::ostream&
270 operator<<(std::ostream& os, const route::prefix_t& pfx)
271 {
272   os << pfx.to_string();
273
274   return (os);
275 }
276
277 boost::asio::ip::address_v4
278 operator|(const boost::asio::ip::address_v4& addr1,
279           const boost::asio::ip::address_v4& addr2)
280 {
281   uint32_t a;
282   a = addr1.to_ulong() | addr2.to_ulong();
283   boost::asio::ip::address_v4 addr(a);
284   return (addr);
285 }
286
287 boost::asio::ip::address_v4 operator&(const boost::asio::ip::address_v4& addr1,
288                                       const boost::asio::ip::address_v4& addr2)
289 {
290   uint32_t a;
291   a = addr1.to_ulong() & addr2.to_ulong();
292   boost::asio::ip::address_v4 addr(a);
293   return (addr);
294 }
295
296 boost::asio::ip::address_v4 operator~(const boost::asio::ip::address_v4& addr1)
297 {
298   uint32_t a;
299   a = ~addr1.to_ulong();
300   boost::asio::ip::address_v4 addr(a);
301   return (addr);
302 }
303
304 boost::asio::ip::address_v6
305 operator|(const boost::asio::ip::address_v6& addr1,
306           const boost::asio::ip::address_v6& addr2)
307 {
308   boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
309   boost::asio::ip::address_v6::bytes_type b2 = addr2.to_bytes();
310
311   for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
312        ii < b1.max_size(); ii++) {
313     b1[ii] |= b2[ii];
314   }
315
316   boost::asio::ip::address_v6 addr(b1);
317   return (addr);
318 }
319
320 boost::asio::ip::address_v6 operator&(const boost::asio::ip::address_v6& addr1,
321                                       const boost::asio::ip::address_v6& addr2)
322 {
323   boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
324   boost::asio::ip::address_v6::bytes_type b2 = addr2.to_bytes();
325
326   for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
327        ii < b1.max_size(); ii++) {
328     b1[ii] &= b2[ii];
329   }
330
331   boost::asio::ip::address_v6 addr(b1);
332   return (addr);
333 }
334
335 boost::asio::ip::address_v6 operator~(const boost::asio::ip::address_v6& addr1)
336 {
337   boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
338
339   for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
340        ii < b1.max_size(); ii++) {
341     b1[ii] = ~b1[ii];
342   }
343
344   boost::asio::ip::address_v6 addr(b1);
345   return (addr);
346 }
347 boost::asio::ip::address
348 operator|(const boost::asio::ip::address& addr1,
349           const boost::asio::ip::address& addr2)
350 {
351   if (addr1.is_v6())
352     return (addr1.to_v6() | addr2.to_v6());
353   else
354     return (addr1.to_v4() | addr2.to_v4());
355 }
356
357 boost::asio::ip::address operator&(const boost::asio::ip::address& addr1,
358                                    const boost::asio::ip::address& addr2)
359 {
360   if (addr1.is_v6())
361     return (addr1.to_v6() & addr2.to_v6());
362   else
363     return (addr1.to_v4() & addr2.to_v4());
364 }
365
366 boost::asio::ip::address operator~(const boost::asio::ip::address& addr1)
367 {
368   if (addr1.is_v6())
369     return ~(addr1.to_v6());
370   else
371     return ~(addr1.to_v4());
372 }
373
374 boost::asio::ip::address
375 route::prefix_t::mask() const
376 {
377   if (m_addr.is_v6()) {
378     boost::asio::ip::address_v6::bytes_type b =
379       boost::asio::ip::address_v6::any().to_bytes();
380
381     uint8_t n_bits = mask_width();
382
383     for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
384          ii < b.max_size(); ii++) {
385       for (int8_t bit = 7; bit >= 0 && n_bits; bit--) {
386         b[ii] |= (1 << bit);
387         n_bits--;
388       }
389       if (!n_bits)
390         break;
391     }
392
393     return (boost::asio::ip::address_v6(b));
394   } else {
395     uint32_t a;
396
397     a = ~((1 << (32 - mask_width())) - 1);
398
399     return (boost::asio::ip::address_v4(a));
400   }
401 }
402
403 route::prefix_t
404 route::prefix_t::low() const
405 {
406   prefix_t pfx(*this);
407
408   pfx.m_addr = pfx.m_addr & pfx.mask();
409
410   return (pfx);
411 }
412
413 route::prefix_t
414 route::prefix_t::high() const
415 {
416   prefix_t pfx(*this);
417
418   pfx.m_addr = pfx.m_addr | ~pfx.mask();
419
420   return (pfx);
421 }
422
423 /**
424  * The all Zeros prefix
425  */
426 const route::mprefix_t route::mprefix_t::ZERO;
427 const route::mprefix_t route::mprefix_t::ZEROv6;
428
429 route::mprefix_t::mprefix_t(const boost::asio::ip::address& gaddr, uint8_t len)
430   : m_gaddr(gaddr)
431   , m_saddr()
432   , m_len(len)
433 {
434 }
435
436 route::mprefix_t::mprefix_t(const boost::asio::ip::address& gaddr)
437   : m_gaddr(gaddr)
438   , m_saddr()
439   , m_len(VOM::mask_width(gaddr))
440 {
441 }
442
443 route::mprefix_t::mprefix_t(const boost::asio::ip::address& saddr,
444                             const boost::asio::ip::address& gaddr)
445   : m_gaddr(gaddr)
446   , m_saddr(saddr)
447   , m_len(2 * VOM::mask_width(gaddr))
448 {
449 }
450
451 route::mprefix_t::mprefix_t(const boost::asio::ip::address& saddr,
452                             const boost::asio::ip::address& gaddr,
453                             uint16_t len)
454   : m_gaddr(gaddr)
455   , m_saddr(saddr)
456   , m_len(len)
457 {
458 }
459
460 route::mprefix_t::mprefix_t(const mprefix_t& o)
461   : m_gaddr(o.m_gaddr)
462   , m_saddr(o.m_saddr)
463   , m_len(o.m_len)
464 {
465 }
466 route::mprefix_t::mprefix_t()
467   : m_gaddr()
468   , m_saddr()
469   , m_len(0)
470 {
471 }
472
473 route::mprefix_t::~mprefix_t()
474 {
475 }
476
477 const boost::asio::ip::address&
478 route::mprefix_t::grp_address() const
479 {
480   return (m_gaddr);
481 }
482
483 const boost::asio::ip::address&
484 route::mprefix_t::src_address() const
485 {
486   return (m_saddr);
487 }
488
489 uint8_t
490 route::mprefix_t::mask_width() const
491 {
492   return (m_len);
493 }
494
495 void
496 route::mprefix_t::to_vpp(uint8_t* is_ip6,
497                          uint8_t* saddr,
498                          uint8_t* gaddr,
499                          uint16_t* len) const
500 {
501   *len = m_len;
502   to_bytes(m_saddr, is_ip6, saddr);
503   to_bytes(m_gaddr, is_ip6, gaddr);
504 }
505
506 route::mprefix_t&
507 route::mprefix_t::operator=(const route::mprefix_t& o)
508 {
509   m_gaddr = o.m_gaddr;
510   m_saddr = o.m_saddr;
511   m_len = o.m_len;
512
513   return (*this);
514 }
515
516 bool
517 route::mprefix_t::operator<(const route::mprefix_t& o) const
518 {
519   if (m_len == o.m_len) {
520     if (m_saddr == o.m_saddr)
521       return (m_gaddr < o.m_gaddr);
522     else
523       return (m_saddr < o.m_saddr);
524   } else {
525     return (m_len < o.m_len);
526   }
527 }
528
529 bool
530 route::mprefix_t::operator==(const route::mprefix_t& o) const
531 {
532   return (m_len == o.m_len && m_gaddr == o.m_gaddr && m_saddr == o.m_saddr);
533 }
534
535 bool
536 route::mprefix_t::operator!=(const route::mprefix_t& o) const
537 {
538   return (!(*this == o));
539 }
540
541 std::string
542 route::mprefix_t::to_string() const
543 {
544   std::ostringstream s;
545
546   s << "(" << m_saddr.to_string() << "," << m_gaddr.to_string() << "/"
547     << std::to_string(m_len) << ")";
548
549   return (s.str());
550 }
551
552 }; // namespace VOM
553
554 /*
555  * fd.io coding-style-patch-verification: ON
556  *
557  * Local Variables:
558  * eval: (c-set-style "mozilla")
559  * End:
560  */