dhcp ip: DSCP settings for transmitted DHCP packets
[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() const
36 {
37   return (*this == IPV6);
38 }
39
40 bool
41 l3_proto_t::is_ipv4() const
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 const ip_dscp_t ip_dscp_t::DSCP_CS0(0, "CS0");
100 const ip_dscp_t ip_dscp_t::DSCP_CS1(8, "CS1");
101 const ip_dscp_t ip_dscp_t::DSCP_CS2(16, "CS2");
102 const ip_dscp_t ip_dscp_t::DSCP_CS3(24, "CS3");
103 const ip_dscp_t ip_dscp_t::DSCP_CS4(32, "CS4");
104 const ip_dscp_t ip_dscp_t::DSCP_CS5(40, "CS5");
105 const ip_dscp_t ip_dscp_t::DSCP_CS6(48, "CS6");
106 const ip_dscp_t ip_dscp_t::DSCP_CS7(50, "CS7");
107 const ip_dscp_t ip_dscp_t::DSCP_AF11(10, "AF11");
108 const ip_dscp_t ip_dscp_t::DSCP_AF12(12, "AF12");
109 const ip_dscp_t ip_dscp_t::DSCP_AF13(14, "AF13");
110 const ip_dscp_t ip_dscp_t::DSCP_AF21(18, "AF21");
111 const ip_dscp_t ip_dscp_t::DSCP_AF22(20, "AF22");
112 const ip_dscp_t ip_dscp_t::DSCP_AF23(22, "AF23");
113 const ip_dscp_t ip_dscp_t::DSCP_AF31(26, "AF31");
114 const ip_dscp_t ip_dscp_t::DSCP_AF32(28, "AF32");
115 const ip_dscp_t ip_dscp_t::DSCP_AF33(30, "AF33");
116 const ip_dscp_t ip_dscp_t::DSCP_AF41(34, "AF41");
117 const ip_dscp_t ip_dscp_t::DSCP_AF42(36, "AF42");
118 const ip_dscp_t ip_dscp_t::DSCP_AF43(38, "AF43");
119 const ip_dscp_t ip_dscp_t::DSCP_EF(46, "EF");
120
121 ip_dscp_t::ip_dscp_t(int v, const std::string& s)
122   : enum_base<ip_dscp_t>(v, s)
123 {
124 }
125 ip_dscp_t::ip_dscp_t(int v)
126   : enum_base<ip_dscp_t>(v, std::to_string(v))
127 {
128 }
129
130 /**
131  * The all Zeros prefix
132  */
133 const route::prefix_t route::prefix_t::ZERO("0.0.0.0", 0);
134 const route::prefix_t route::prefix_t::ZEROv6("::", 0);
135
136 route::prefix_t::prefix_t(const boost::asio::ip::address& addr, uint8_t len)
137   : m_addr(addr)
138   , m_len(len)
139 {
140 }
141
142 route::prefix_t::prefix_t(const boost::asio::ip::address& addr)
143   : m_addr(addr)
144   , m_len(VOM::mask_width(addr))
145 {
146 }
147
148 route::prefix_t::prefix_t(const std::string& s, uint8_t len)
149   : m_addr(boost::asio::ip::address::from_string(s))
150   , m_len(len)
151 {
152 }
153
154 route::prefix_t::prefix_t(const prefix_t& o)
155   : m_addr(o.m_addr)
156   , m_len(o.m_len)
157 {
158 }
159
160 route::prefix_t::prefix_t()
161   : m_addr()
162   , m_len(0)
163 {
164 }
165
166 route::prefix_t::~prefix_t()
167 {
168 }
169
170 route::prefix_t&
171 route::prefix_t::operator=(const route::prefix_t& o)
172 {
173   m_addr = o.m_addr;
174   m_len = o.m_len;
175
176   return (*this);
177 }
178
179 const boost::asio::ip::address&
180 route::prefix_t::address() const
181 {
182   return (m_addr);
183 }
184
185 uint8_t
186 route::prefix_t::mask_width() const
187 {
188   return (m_len);
189 }
190
191 bool
192 route::prefix_t::operator<(const route::prefix_t& o) const
193 {
194   if (m_len == o.m_len) {
195     return (m_addr < o.m_addr);
196   } else {
197     return (m_len < o.m_len);
198   }
199 }
200
201 bool
202 route::prefix_t::operator==(const route::prefix_t& o) const
203 {
204   return (m_len == o.m_len && m_addr == o.m_addr);
205 }
206
207 bool
208 route::prefix_t::operator!=(const route::prefix_t& o) const
209 {
210   return (!(*this == o));
211 }
212
213 std::string
214 route::prefix_t::to_string() const
215 {
216   std::ostringstream s;
217
218   s << m_addr.to_string() << "/" << std::to_string(m_len);
219
220   return (s.str());
221 }
222
223 boost::asio::ip::address
224 from_bytes(uint8_t is_ip6, const uint8_t* bytes)
225 {
226   boost::asio::ip::address addr;
227
228   if (is_ip6) {
229     std::array<uint8_t, 16> a;
230     std::copy(bytes, bytes + 16, std::begin(a));
231     boost::asio::ip::address_v6 v6(a);
232     addr = v6;
233   } else {
234     std::array<uint8_t, 4> a;
235     std::copy(bytes, bytes + 4, std::begin(a));
236     boost::asio::ip::address_v4 v4(a);
237     addr = v4;
238   }
239
240   return (addr);
241 }
242
243 route::prefix_t::prefix_t(uint8_t is_ip6, uint8_t* addr, uint8_t len)
244   : m_addr(from_bytes(is_ip6, addr))
245   , m_len(len)
246 {
247 }
248 void
249 to_bytes(const boost::asio::ip::address_v6& addr, uint8_t* array)
250 {
251   memcpy(array, addr.to_bytes().data(), 16);
252 }
253
254 void
255 to_bytes(const boost::asio::ip::address_v4& addr, uint8_t* array)
256 {
257   memcpy(array, addr.to_bytes().data(), 4);
258 }
259
260 void
261 to_bytes(const boost::asio::ip::address& addr, uint8_t* is_ip6, uint8_t* array)
262 {
263   if (addr.is_v6()) {
264     *is_ip6 = 1;
265     to_bytes(addr.to_v6(), array);
266   } else {
267     *is_ip6 = 0;
268     to_bytes(addr.to_v4(), array);
269   }
270 }
271
272 uint32_t
273 mask_width(const boost::asio::ip::address& addr)
274 {
275   if (addr.is_v6()) {
276     return 128;
277   }
278   return 32;
279 }
280
281 void
282 route::prefix_t::to_vpp(uint8_t* is_ip6, uint8_t* addr, uint8_t* len) const
283 {
284   *len = m_len;
285   to_bytes(m_addr, is_ip6, addr);
286 }
287
288 l3_proto_t
289 route::prefix_t::l3_proto() const
290 {
291   if (m_addr.is_v6()) {
292     return (l3_proto_t::IPV6);
293   } else {
294     return (l3_proto_t::IPV4);
295   }
296
297   return (l3_proto_t::IPV4);
298 }
299
300 std::ostream&
301 operator<<(std::ostream& os, const route::prefix_t& pfx)
302 {
303   os << pfx.to_string();
304
305   return (os);
306 }
307
308 boost::asio::ip::address_v4
309 operator|(const boost::asio::ip::address_v4& addr1,
310           const boost::asio::ip::address_v4& addr2)
311 {
312   uint32_t a;
313   a = addr1.to_ulong() | addr2.to_ulong();
314   boost::asio::ip::address_v4 addr(a);
315   return (addr);
316 }
317
318 boost::asio::ip::address_v4 operator&(const boost::asio::ip::address_v4& addr1,
319                                       const boost::asio::ip::address_v4& addr2)
320 {
321   uint32_t a;
322   a = addr1.to_ulong() & addr2.to_ulong();
323   boost::asio::ip::address_v4 addr(a);
324   return (addr);
325 }
326
327 boost::asio::ip::address_v4 operator~(const boost::asio::ip::address_v4& addr1)
328 {
329   uint32_t a;
330   a = ~addr1.to_ulong();
331   boost::asio::ip::address_v4 addr(a);
332   return (addr);
333 }
334
335 boost::asio::ip::address_v6
336 operator|(const boost::asio::ip::address_v6& addr1,
337           const boost::asio::ip::address_v6& addr2)
338 {
339   boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
340   boost::asio::ip::address_v6::bytes_type b2 = addr2.to_bytes();
341
342   for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
343        ii < b1.max_size(); ii++) {
344     b1[ii] |= b2[ii];
345   }
346
347   boost::asio::ip::address_v6 addr(b1);
348   return (addr);
349 }
350
351 boost::asio::ip::address_v6 operator&(const boost::asio::ip::address_v6& addr1,
352                                       const boost::asio::ip::address_v6& addr2)
353 {
354   boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
355   boost::asio::ip::address_v6::bytes_type b2 = addr2.to_bytes();
356
357   for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
358        ii < b1.max_size(); ii++) {
359     b1[ii] &= b2[ii];
360   }
361
362   boost::asio::ip::address_v6 addr(b1);
363   return (addr);
364 }
365
366 boost::asio::ip::address_v6 operator~(const boost::asio::ip::address_v6& addr1)
367 {
368   boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
369
370   for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
371        ii < b1.max_size(); ii++) {
372     b1[ii] = ~b1[ii];
373   }
374
375   boost::asio::ip::address_v6 addr(b1);
376   return (addr);
377 }
378 boost::asio::ip::address
379 operator|(const boost::asio::ip::address& addr1,
380           const boost::asio::ip::address& addr2)
381 {
382   if (addr1.is_v6())
383     return (addr1.to_v6() | addr2.to_v6());
384   else
385     return (addr1.to_v4() | addr2.to_v4());
386 }
387
388 boost::asio::ip::address operator&(const boost::asio::ip::address& addr1,
389                                    const boost::asio::ip::address& addr2)
390 {
391   if (addr1.is_v6())
392     return (addr1.to_v6() & addr2.to_v6());
393   else
394     return (addr1.to_v4() & addr2.to_v4());
395 }
396
397 boost::asio::ip::address operator~(const boost::asio::ip::address& addr1)
398 {
399   if (addr1.is_v6())
400     return ~(addr1.to_v6());
401   else
402     return ~(addr1.to_v4());
403 }
404
405 boost::asio::ip::address
406 route::prefix_t::mask() const
407 {
408   if (m_addr.is_v6()) {
409     boost::asio::ip::address_v6::bytes_type b =
410       boost::asio::ip::address_v6::any().to_bytes();
411
412     uint8_t n_bits = mask_width();
413
414     for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
415          ii < b.max_size(); ii++) {
416       for (int8_t bit = 7; bit >= 0 && n_bits; bit--) {
417         b[ii] |= (1 << bit);
418         n_bits--;
419       }
420       if (!n_bits)
421         break;
422     }
423
424     return (boost::asio::ip::address_v6(b));
425   } else {
426     uint32_t a;
427
428     a = ~((1 << (32 - mask_width())) - 1);
429
430     return (boost::asio::ip::address_v4(a));
431   }
432 }
433
434 route::prefix_t
435 route::prefix_t::low() const
436 {
437   prefix_t pfx(*this);
438
439   pfx.m_addr = pfx.m_addr & pfx.mask();
440
441   return (pfx);
442 }
443
444 route::prefix_t
445 route::prefix_t::high() const
446 {
447   prefix_t pfx(*this);
448
449   pfx.m_addr = pfx.m_addr | ~pfx.mask();
450
451   return (pfx);
452 }
453
454 /**
455  * The all Zeros prefix
456  */
457 const route::mprefix_t route::mprefix_t::ZERO;
458 const route::mprefix_t route::mprefix_t::ZEROv6;
459
460 route::mprefix_t::mprefix_t(const boost::asio::ip::address& gaddr, uint8_t len)
461   : m_gaddr(gaddr)
462   , m_saddr()
463   , m_len(len)
464 {
465 }
466
467 route::mprefix_t::mprefix_t(const boost::asio::ip::address& gaddr)
468   : m_gaddr(gaddr)
469   , m_saddr()
470   , m_len(VOM::mask_width(gaddr))
471 {
472 }
473
474 route::mprefix_t::mprefix_t(const boost::asio::ip::address& saddr,
475                             const boost::asio::ip::address& gaddr)
476   : m_gaddr(gaddr)
477   , m_saddr(saddr)
478   , m_len(2 * VOM::mask_width(gaddr))
479 {
480 }
481
482 route::mprefix_t::mprefix_t(const boost::asio::ip::address& saddr,
483                             const boost::asio::ip::address& gaddr,
484                             uint16_t len)
485   : m_gaddr(gaddr)
486   , m_saddr(saddr)
487   , m_len(len)
488 {
489 }
490
491 route::mprefix_t::mprefix_t(const mprefix_t& o)
492   : m_gaddr(o.m_gaddr)
493   , m_saddr(o.m_saddr)
494   , m_len(o.m_len)
495 {
496 }
497 route::mprefix_t::mprefix_t()
498   : m_gaddr()
499   , m_saddr()
500   , m_len(0)
501 {
502 }
503
504 route::mprefix_t::~mprefix_t()
505 {
506 }
507
508 const boost::asio::ip::address&
509 route::mprefix_t::grp_address() const
510 {
511   return (m_gaddr);
512 }
513
514 const boost::asio::ip::address&
515 route::mprefix_t::src_address() const
516 {
517   return (m_saddr);
518 }
519
520 uint8_t
521 route::mprefix_t::mask_width() const
522 {
523   return (m_len);
524 }
525
526 l3_proto_t
527 route::mprefix_t::l3_proto() const
528 {
529   if (m_gaddr.is_v6()) {
530     return (l3_proto_t::IPV6);
531   } else {
532     return (l3_proto_t::IPV4);
533   }
534
535   return (l3_proto_t::IPV4);
536 }
537
538 route::mprefix_t&
539 route::mprefix_t::operator=(const route::mprefix_t& o)
540 {
541   m_gaddr = o.m_gaddr;
542   m_saddr = o.m_saddr;
543   m_len = o.m_len;
544
545   return (*this);
546 }
547
548 bool
549 route::mprefix_t::operator<(const route::mprefix_t& o) const
550 {
551   if (m_len == o.m_len) {
552     if (m_saddr == o.m_saddr)
553       return (m_gaddr < o.m_gaddr);
554     else
555       return (m_saddr < o.m_saddr);
556   } else {
557     return (m_len < o.m_len);
558   }
559 }
560
561 bool
562 route::mprefix_t::operator==(const route::mprefix_t& o) const
563 {
564   return (m_len == o.m_len && m_gaddr == o.m_gaddr && m_saddr == o.m_saddr);
565 }
566
567 bool
568 route::mprefix_t::operator!=(const route::mprefix_t& o) const
569 {
570   return (!(*this == o));
571 }
572
573 std::string
574 route::mprefix_t::to_string() const
575 {
576   std::ostringstream s;
577
578   s << "(" << m_saddr.to_string() << "," << m_gaddr.to_string() << "/"
579     << std::to_string(m_len) << ")";
580
581   return (s.str());
582 }
583
584 }; // namespace VOM
585
586 /*
587  * fd.io coding-style-patch-verification: ON
588  *
589  * Local Variables:
590  * eval: (c-set-style "mozilla")
591  * End:
592  */