blob: 269c28f1f5452703cb5bf99e764ed9f1ee98484f [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 <boost/algorithm/string.hpp>
17#include <sstream>
18
19#include "vom/prefix.hpp"
20
21namespace VOM {
22/*
23 * Keep this in sync with VPP's fib_protocol_t
24 */
25const l3_proto_t l3_proto_t::IPV4(0, "ipv4");
26const l3_proto_t l3_proto_t::IPV6(1, "ipv6");
27const l3_proto_t l3_proto_t::MPLS(2, "mpls");
28
29l3_proto_t::l3_proto_t(int v, const std::string& s)
30 : enum_base<l3_proto_t>(v, s)
31{
32}
33
34bool
35l3_proto_t::is_ipv6()
36{
37 return (*this == IPV6);
38}
39
40bool
41l3_proto_t::is_ipv4()
42{
43 return (*this == IPV4);
44}
45
46const l3_proto_t&
47l3_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/*
57 * Keep this in sync with VPP's dpo_proto_t
58 */
59const nh_proto_t nh_proto_t::IPV4(0, "ipv4");
60const nh_proto_t nh_proto_t::IPV6(1, "ipv6");
61const nh_proto_t nh_proto_t::MPLS(2, "mpls");
62const nh_proto_t nh_proto_t::ETHERNET(3, "ethernet");
63
64nh_proto_t::nh_proto_t(int v, const std::string& s)
65 : enum_base<nh_proto_t>(v, s)
66{
67}
68
69const nh_proto_t&
70nh_proto_t::from_address(const boost::asio::ip::address& addr)
71{
72 if (addr.is_v6()) {
73 return IPV6;
74 }
75
76 return IPV4;
77}
78
79/**
80 * The all Zeros prefix
81 */
82const route::prefix_t route::prefix_t::ZERO("0.0.0.0", 0);
83const route::prefix_t route::prefix_t::ZEROv6("::", 0);
84
85route::prefix_t::prefix_t(const boost::asio::ip::address& addr, uint8_t len)
86 : m_addr(addr)
87 , m_len(len)
88{
89}
90
91route::prefix_t::prefix_t(const boost::asio::ip::address& addr)
92 : m_addr(addr)
93 , m_len(VOM::mask_width(addr))
94{
95}
96
97route::prefix_t::prefix_t(const std::string& s, uint8_t len)
98 : m_addr(boost::asio::ip::address::from_string(s))
99 , m_len(len)
100{
101}
102
103route::prefix_t::prefix_t(const prefix_t& o)
104 : m_addr(o.m_addr)
105 , m_len(o.m_len)
106{
107}
108
109route::prefix_t::prefix_t()
110 : m_addr()
111 , m_len(0)
112{
113}
114
115route::prefix_t::~prefix_t()
116{
117}
118
119route::prefix_t&
120route::prefix_t::operator=(const route::prefix_t& o)
121{
122 m_addr = o.m_addr;
123 m_len = o.m_len;
124
125 return (*this);
126}
127
128const boost::asio::ip::address&
129route::prefix_t::address() const
130{
131 return (m_addr);
132}
133
134uint8_t
135route::prefix_t::mask_width() const
136{
137 return (m_len);
138}
139
140bool
141route::prefix_t::operator<(const route::prefix_t& o) const
142{
143 if (m_len == o.m_len) {
144 return (m_addr < o.m_addr);
145 } else {
146 return (m_len < o.m_len);
147 }
148}
149
150bool
151route::prefix_t::operator==(const route::prefix_t& o) const
152{
153 return (m_len == o.m_len && m_addr == o.m_addr);
154}
155
156bool
157route::prefix_t::operator!=(const route::prefix_t& o) const
158{
159 return (!(*this == o));
160}
161
162std::string
163route::prefix_t::to_string() const
164{
165 std::ostringstream s;
166
167 s << m_addr.to_string() << "/" << std::to_string(m_len);
168
169 return (s.str());
170}
171
172boost::asio::ip::address
173from_bytes(uint8_t is_ip6, uint8_t* bytes)
174{
175 boost::asio::ip::address addr;
176
177 if (is_ip6) {
178 std::array<uint8_t, 16> a;
179 std::copy(bytes, bytes + 16, std::begin(a));
180 boost::asio::ip::address_v6 v6(a);
181 addr = v6;
182 } else {
183 std::array<uint8_t, 4> a;
184 std::copy(bytes, bytes + 4, std::begin(a));
185 boost::asio::ip::address_v4 v4(a);
186 addr = v4;
187 }
188
189 return (addr);
190}
191
192route::prefix_t::prefix_t(uint8_t is_ip6, uint8_t* addr, uint8_t len)
193 : m_addr(from_bytes(is_ip6, addr))
194 , m_len(len)
195{
196}
197void
198to_bytes(const boost::asio::ip::address_v6& addr, uint8_t* array)
199{
200 memcpy(array, addr.to_bytes().data(), 16);
201}
202
203void
204to_bytes(const boost::asio::ip::address_v4& addr, uint8_t* array)
205{
206 memcpy(array, addr.to_bytes().data(), 4);
207}
208
209void
210to_bytes(const boost::asio::ip::address& addr, uint8_t* is_ip6, uint8_t* array)
211{
212 if (addr.is_v6()) {
213 *is_ip6 = 1;
214 to_bytes(addr.to_v6(), array);
215 } else {
216 *is_ip6 = 0;
217 to_bytes(addr.to_v4(), array);
218 }
219}
220
221uint32_t
222mask_width(const boost::asio::ip::address& addr)
223{
224 if (addr.is_v6()) {
225 return 128;
226 }
227 return 32;
228}
229
230void
231route::prefix_t::to_vpp(uint8_t* is_ip6, uint8_t* addr, uint8_t* len) const
232{
233 *len = m_len;
234 to_bytes(m_addr, is_ip6, addr);
235}
236
237l3_proto_t
238route::prefix_t::l3_proto() const
239{
240 if (m_addr.is_v6()) {
241 return (l3_proto_t::IPV6);
242 } else {
243 return (l3_proto_t::IPV4);
244 }
245
246 return (l3_proto_t::IPV4);
247}
248
249std::ostream&
250operator<<(std::ostream& os, const route::prefix_t& pfx)
251{
252 os << pfx.to_string();
253
254 return (os);
255}
256
257boost::asio::ip::address_v4
258operator|(const boost::asio::ip::address_v4& addr1,
259 const boost::asio::ip::address_v4& addr2)
260{
261 uint32_t a;
262 a = addr1.to_ulong() | addr2.to_ulong();
263 boost::asio::ip::address_v4 addr(a);
264 return (addr);
265}
266
267boost::asio::ip::address_v4 operator&(const boost::asio::ip::address_v4& addr1,
268 const boost::asio::ip::address_v4& addr2)
269{
270 uint32_t a;
271 a = addr1.to_ulong() & addr2.to_ulong();
272 boost::asio::ip::address_v4 addr(a);
273 return (addr);
274}
275
276boost::asio::ip::address_v4 operator~(const boost::asio::ip::address_v4& addr1)
277{
278 uint32_t a;
279 a = ~addr1.to_ulong();
280 boost::asio::ip::address_v4 addr(a);
281 return (addr);
282}
283
Neale Rannsd3464b52017-12-07 08:48:02 -0800284boost::asio::ip::address_v6
285operator|(const boost::asio::ip::address_v6& addr1,
286 const boost::asio::ip::address_v6& addr2)
Neale Ranns812ed392017-10-16 04:20:13 -0700287{
Neale Rannsd3464b52017-12-07 08:48:02 -0800288 boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
289 boost::asio::ip::address_v6::bytes_type b2 = addr2.to_bytes();
Neale Ranns812ed392017-10-16 04:20:13 -0700290
Neale Rannsd3464b52017-12-07 08:48:02 -0800291 for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
292 ii < b1.max_size(); ii++) {
293 b1[ii] |= b2[ii];
294 }
295
296 boost::asio::ip::address_v6 addr(b1);
Neale Ranns812ed392017-10-16 04:20:13 -0700297 return (addr);
298}
299
Neale Rannsd3464b52017-12-07 08:48:02 -0800300boost::asio::ip::address_v6 operator&(const boost::asio::ip::address_v6& addr1,
301 const boost::asio::ip::address_v6& addr2)
Neale Ranns812ed392017-10-16 04:20:13 -0700302{
Neale Rannsd3464b52017-12-07 08:48:02 -0800303 boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
304 boost::asio::ip::address_v6::bytes_type b2 = addr2.to_bytes();
305
306 for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
307 ii < b1.max_size(); ii++) {
308 b1[ii] &= b2[ii];
309 }
310
311 boost::asio::ip::address_v6 addr(b1);
312 return (addr);
Neale Ranns812ed392017-10-16 04:20:13 -0700313}
314
Neale Rannsd3464b52017-12-07 08:48:02 -0800315boost::asio::ip::address_v6 operator~(const boost::asio::ip::address_v6& addr1)
316{
317 boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
318
319 for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
320 ii < b1.max_size(); ii++) {
321 b1[ii] = ~b1[ii];
322 }
323
324 boost::asio::ip::address_v6 addr(b1);
325 return (addr);
326}
327boost::asio::ip::address
328operator|(const boost::asio::ip::address& addr1,
329 const boost::asio::ip::address& addr2)
330{
331 if (addr1.is_v6())
332 return (addr1.to_v6() | addr2.to_v6());
333 else
334 return (addr1.to_v4() | addr2.to_v4());
335}
336
337boost::asio::ip::address operator&(const boost::asio::ip::address& addr1,
338 const boost::asio::ip::address& addr2)
339{
340 if (addr1.is_v6())
341 return (addr1.to_v6() & addr2.to_v6());
342 else
343 return (addr1.to_v4() & addr2.to_v4());
344}
345
346boost::asio::ip::address operator~(const boost::asio::ip::address& addr1)
347{
348 if (addr1.is_v6())
349 return ~(addr1.to_v6());
350 else
351 return ~(addr1.to_v4());
352}
353
354boost::asio::ip::address
355route::prefix_t::mask() const
356{
357 if (m_addr.is_v6()) {
358 boost::asio::ip::address_v6::bytes_type b =
359 boost::asio::ip::address_v6::any().to_bytes();
360
361 uint8_t n_bits = mask_width();
362
363 for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
364 ii < b.max_size(); ii++) {
365 for (int8_t bit = 7; bit >= 0 && n_bits; bit--) {
366 b[ii] |= (1 << bit);
367 n_bits--;
368 }
369 if (!n_bits)
370 break;
371 }
372
373 return (boost::asio::ip::address_v6(b));
374 } else {
375 uint32_t a;
376
377 a = ~((1 << (32 - mask_width())) - 1);
378
379 return (boost::asio::ip::address_v4(a));
380 }
381}
382
383route::prefix_t
384route::prefix_t::low() const
385{
386 prefix_t pfx(*this);
387
388 pfx.m_addr = pfx.m_addr & pfx.mask();
389
390 return (pfx);
391}
392
393route::prefix_t
Neale Ranns812ed392017-10-16 04:20:13 -0700394route::prefix_t::high() const
395{
Neale Rannsd3464b52017-12-07 08:48:02 -0800396 prefix_t pfx(*this);
397
398 pfx.m_addr = pfx.m_addr | ~pfx.mask();
399
400 return (pfx);
Neale Ranns812ed392017-10-16 04:20:13 -0700401}
Neale Rannsd3464b52017-12-07 08:48:02 -0800402
403}; // namespace VOM
404
Neale Ranns812ed392017-10-16 04:20:13 -0700405/*
406 * fd.io coding-style-patch-verification: ON
407 *
408 * Local Variables:
409 * eval: (c-set-style "mozilla")
410 * End:
411 */