VPP Object Model (VOM)
[vpp.git] / src / vpp-api / 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 /*
57  * Keep this in sync with VPP's dpo_proto_t
58  */
59 const nh_proto_t nh_proto_t::IPV4(0, "ipv4");
60 const nh_proto_t nh_proto_t::IPV6(1, "ipv6");
61 const nh_proto_t nh_proto_t::MPLS(2, "mpls");
62 const nh_proto_t nh_proto_t::ETHERNET(3, "ethernet");
63
64 nh_proto_t::nh_proto_t(int v, const std::string& s)
65   : enum_base<nh_proto_t>(v, s)
66 {
67 }
68
69 const nh_proto_t&
70 nh_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  */
82 const route::prefix_t route::prefix_t::ZERO("0.0.0.0", 0);
83 const route::prefix_t route::prefix_t::ZEROv6("::", 0);
84
85 route::prefix_t::prefix_t(const boost::asio::ip::address& addr, uint8_t len)
86   : m_addr(addr)
87   , m_len(len)
88 {
89 }
90
91 route::prefix_t::prefix_t(const boost::asio::ip::address& addr)
92   : m_addr(addr)
93   , m_len(VOM::mask_width(addr))
94 {
95 }
96
97 route::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
103 route::prefix_t::prefix_t(const prefix_t& o)
104   : m_addr(o.m_addr)
105   , m_len(o.m_len)
106 {
107 }
108
109 route::prefix_t::prefix_t()
110   : m_addr()
111   , m_len(0)
112 {
113 }
114
115 route::prefix_t::~prefix_t()
116 {
117 }
118
119 route::prefix_t&
120 route::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
128 const boost::asio::ip::address&
129 route::prefix_t::address() const
130 {
131   return (m_addr);
132 }
133
134 uint8_t
135 route::prefix_t::mask_width() const
136 {
137   return (m_len);
138 }
139
140 bool
141 route::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
150 bool
151 route::prefix_t::operator==(const route::prefix_t& o) const
152 {
153   return (m_len == o.m_len && m_addr == o.m_addr);
154 }
155
156 bool
157 route::prefix_t::operator!=(const route::prefix_t& o) const
158 {
159   return (!(*this == o));
160 }
161
162 std::string
163 route::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
172 boost::asio::ip::address
173 from_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
192 route::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 }
197 void
198 to_bytes(const boost::asio::ip::address_v6& addr, uint8_t* array)
199 {
200   memcpy(array, addr.to_bytes().data(), 16);
201 }
202
203 void
204 to_bytes(const boost::asio::ip::address_v4& addr, uint8_t* array)
205 {
206   memcpy(array, addr.to_bytes().data(), 4);
207 }
208
209 void
210 to_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
221 uint32_t
222 mask_width(const boost::asio::ip::address& addr)
223 {
224   if (addr.is_v6()) {
225     return 128;
226   }
227   return 32;
228 }
229
230 void
231 route::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
237 l3_proto_t
238 route::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
249 std::ostream&
250 operator<<(std::ostream& os, const route::prefix_t& pfx)
251 {
252   os << pfx.to_string();
253
254   return (os);
255 }
256
257 boost::asio::ip::address_v4
258 operator|(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
267 boost::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
276 boost::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
284 boost::asio::ip::address_v4
285 route::prefix_t::mask() const
286 {
287   uint32_t a;
288
289   a = ~((1 << mask_width()) - 1);
290   boost::asio::ip::address_v4 addr(a);
291   return (addr);
292 }
293
294 boost::asio::ip::address_v4
295 route::prefix_t::low() const
296 {
297   boost::asio::ip::address_v4 low;
298   low = address().to_v4() & mask();
299   return (low);
300 }
301
302 boost::asio::ip::address_v4
303 route::prefix_t::high() const
304 {
305   boost::asio::ip::address_v4 high;
306   high = address().to_v4() | ~mask();
307   return (high);
308 }
309 }
310 /*
311  * fd.io coding-style-patch-verification: ON
312  *
313  * Local Variables:
314  * eval: (c-set-style "mozilla")
315  * End:
316  */