misc: fix a trunccation on vhost dump
[vpp.git] / src / vat / ip_types.c
1 /*
2  * Copyright (c) 2016 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 <vnet/ip/ip_types.h>
17 #include <vnet/ip/format.h>
18 #include <vnet/ip/ip.h>
19
20 u8 *
21 format_ip_address (u8 * s, va_list * args)
22 {
23   ip_address_t *a = va_arg (*args, ip_address_t *);
24   u8 ver = ip_addr_version (a);
25   if (ver == AF_IP4)
26     {
27       return format (s, "%U", format_ip4_address, &ip_addr_v4 (a));
28     }
29   else if (ver == AF_IP6)
30     {
31       return format (s, "%U", format_ip6_address, &ip_addr_v6 (a));
32     }
33   else
34     {
35       clib_warning ("Can't format IP version %d!", ver);
36       return 0;
37     }
38 }
39
40 uword
41 unformat_ip_address (unformat_input_t * input, va_list * args)
42 {
43   ip_address_t *a = va_arg (*args, ip_address_t *);
44
45   clib_memset (a, 0, sizeof (*a));
46   if (unformat (input, "%U", unformat_ip4_address, &ip_addr_v4 (a)))
47     ip_addr_version (a) = AF_IP4;
48   else if (unformat_user (input, unformat_ip6_address, &ip_addr_v6 (a)))
49     ip_addr_version (a) = AF_IP6;
50   else
51     return 0;
52   return 1;
53 }
54
55 u8 *
56 format_ip_prefix (u8 * s, va_list * args)
57 {
58   ip_prefix_t *a = va_arg (*args, ip_prefix_t *);
59   return format (s, "%U/%d", format_ip_address, &ip_prefix_addr (a),
60                  ip_prefix_len (a));
61 }
62
63 uword
64 unformat_ip_prefix (unformat_input_t * input, va_list * args)
65 {
66   ip_prefix_t *a = va_arg (*args, ip_prefix_t *);
67   /* %d writes more than a u8 */
68   int plen;
69   if (unformat (input, "%U/%d", unformat_ip_address, &ip_prefix_addr (a),
70                 &plen))
71     {
72       ip_prefix_len (a) = plen;
73       if ((ip_prefix_version (a) == AF_IP4 && 32 < ip_prefix_len (a)) ||
74           (ip_prefix_version (a) == AF_IP6 && 128 < ip_prefix_len (a)))
75         {
76           clib_warning ("Prefix length to big: %d!", ip_prefix_len (a));
77           return 0;
78         }
79       ip_prefix_normalize (a);
80     }
81   else
82     return 0;
83   return 1;
84 }
85
86 u16
87 ip_address_size (const ip_address_t * a)
88 {
89   switch (ip_addr_version (a))
90     {
91     case AF_IP4:
92       return sizeof (ip4_address_t);
93       break;
94     case AF_IP6:
95       return sizeof (ip6_address_t);
96       break;
97     }
98   return 0;
99 }
100
101 bool
102 ip_address_is_zero (const ip_address_t * ip)
103 {
104   switch (ip_addr_version (ip))
105     {
106     case AF_IP4:
107       return (ip_addr_v4 (ip).as_u32 == 0);
108     case AF_IP6:
109       return (ip_addr_v6 (ip).as_u64[0] == 0 &&
110               ip_addr_v6 (ip).as_u64[1] == 0);
111       break;
112     }
113   return false;
114 }
115
116 int
117 ip_address_cmp (const ip_address_t * ip1, const ip_address_t * ip2)
118 {
119   int res = 0;
120   if (ip_addr_version (ip1) != ip_addr_version (ip2))
121     return -1;
122   res = ip46_address_cmp (&ip_addr_46 (ip1), &ip_addr_46 (ip2));
123
124   if (res < 0)
125     res = 2;
126   else if (res > 0)
127     res = 1;
128
129   return res;
130 }
131
132 void
133 ip_address_copy (ip_address_t * dst, const ip_address_t * src)
134 {
135   if (AF_IP4 == ip_addr_version (src))
136     {
137       /* don't copy any garbage from the union */
138       clib_memset (dst, 0, sizeof (*dst));
139       ip_addr_v4 (dst) = ip_addr_v4 (src);
140       dst->version = AF_IP4;
141     }
142   else
143     {
144       clib_memcpy (dst, src, sizeof (ip_address_t));
145     }
146 }
147
148 u8 *
149 ip_addr_bytes (ip_address_t * ip)
150 {
151   switch (ip->version)
152     {
153     case AF_IP4:
154       return (u8 *) & ip_addr_v4 (ip);
155     case AF_IP6:
156       return (u8 *) & ip_addr_v6 (ip);
157       break;
158     }
159   ASSERT (0);
160   return (NULL);
161 }
162
163 void
164 ip_address_copy_addr (void *dst, const ip_address_t * src)
165 {
166   switch (src->version)
167     {
168     case AF_IP4:
169       clib_memcpy (dst, &ip_addr_v4 (src), ip_address_size (src));
170       break;
171     case AF_IP6:
172       clib_memcpy (dst, &ip_addr_v6 (src), ip_address_size (src));
173       break;
174     }
175 }
176
177 u16
178 ip_version_to_size (ip_address_family_t af)
179 {
180   switch (af)
181     {
182     case AF_IP4:
183       return sizeof (ip4_address_t);
184       break;
185     case AF_IP6:
186       return sizeof (ip6_address_t);
187       break;
188     }
189   return 0;
190 }
191
192 vnet_link_t
193 ip_address_family_to_link_type (ip_address_family_t af)
194 {
195   switch (af)
196     {
197     case AF_IP4:
198       return (VNET_LINK_IP4);
199     case AF_IP6:
200       return (VNET_LINK_IP6);
201     }
202   ASSERT (0);
203   return (VNET_LINK_IP4);
204 }
205
206
207 void
208 ip_address_set (ip_address_t * dst, const void *src, u8 version)
209 {
210   ip_addr_version (dst) = version;
211
212   switch (version)
213     {
214     case AF_IP4:
215       ip_addr_v4 (dst) = *(ip4_address_t *) src;
216       break;
217     case AF_IP6:
218       ip_addr_v6 (dst) = *(ip6_address_t *) src;
219       break;
220     }
221 }
222
223 fib_protocol_t
224 ip_address_family_to_fib_proto (ip_address_family_t af)
225 {
226   switch (af)
227     {
228     case AF_IP4:
229       return (FIB_PROTOCOL_IP4);
230     case AF_IP6:
231       return (FIB_PROTOCOL_IP6);
232     }
233   ASSERT (0);
234   return (FIB_PROTOCOL_IP4);
235 }
236
237 ip_address_family_t
238 ip_address_family_from_fib_proto (fib_protocol_t fp)
239 {
240   switch (fp)
241     {
242     case FIB_PROTOCOL_IP4:
243       return (AF_IP4);
244     case FIB_PROTOCOL_IP6:
245       return (AF_IP6);
246     case FIB_PROTOCOL_MPLS:
247       ASSERT (0);
248     }
249   return (AF_IP4);
250 }
251
252 fib_protocol_t
253 ip_address_to_46 (const ip_address_t * addr, ip46_address_t * a)
254 {
255   *a = ip_addr_46 (addr);
256   return (ip_address_family_to_fib_proto (ip_addr_version (addr)));
257 }
258
259 void
260 ip_address_from_46 (const ip46_address_t * nh,
261                     fib_protocol_t fproto, ip_address_t * ip)
262 {
263   ip_addr_46 (ip) = *nh;
264   ip_addr_version (ip) = ip_address_family_from_fib_proto (fproto);
265 }
266
267 static void
268 ip_prefix_normalize_ip4 (ip4_address_t * ip4, u8 preflen)
269 {
270   u32 mask = ~0;
271
272   ASSERT (ip4);
273
274   if (32 <= preflen)
275     {
276       return;
277     }
278
279   mask = pow2_mask (preflen) << (32 - preflen);
280   mask = clib_host_to_net_u32 (mask);
281   ip4->data_u32 &= mask;
282 }
283
284 static void
285 ip_prefix_normalize_ip6 (ip6_address_t * ip6, u8 preflen)
286 {
287   u8 mask_6[16];
288   u32 *m;
289   u8 j, i0, i1;
290
291   ASSERT (ip6);
292
293   clib_memset (mask_6, 0, sizeof (mask_6));
294
295   if (128 <= preflen)
296     {
297       return;
298     }
299
300   i1 = preflen % 32;
301   i0 = preflen / 32;
302   m = (u32 *) & mask_6[0];
303
304   for (j = 0; j < i0; j++)
305     {
306       m[j] = ~0;
307     }
308
309   if (i1)
310     {
311       m[i0] = clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
312     }
313
314   for (j = 0; j < sizeof (mask_6); j++)
315     {
316       ip6->as_u8[j] &= mask_6[j];
317     }
318 }
319
320 void
321 ip_prefix_normalize (ip_prefix_t * a)
322 {
323   u8 preflen = ip_prefix_len (a);
324
325   switch (ip_prefix_version (a))
326     {
327     case AF_IP4:
328       ip_prefix_normalize_ip4 (&ip_prefix_v4 (a), preflen);
329       break;
330
331     case AF_IP6:
332       ip_prefix_normalize_ip6 (&ip_prefix_v6 (a), preflen);
333       break;
334
335     default:
336       ASSERT (0);
337     }
338 }
339
340 void
341 ip_prefix_copy (void *dst, void *src)
342 {
343   clib_memcpy (dst, src, sizeof (ip_prefix_t));
344 }
345
346 int
347 ip_prefix_cmp (ip_prefix_t * p1, ip_prefix_t * p2)
348 {
349   int cmp = 0;
350
351   ip_prefix_normalize (p1);
352   ip_prefix_normalize (p2);
353
354   cmp = ip_address_cmp (&ip_prefix_addr (p1), &ip_prefix_addr (p2));
355   if (cmp == 0)
356     {
357       if (ip_prefix_len (p1) < ip_prefix_len (p2))
358         {
359           cmp = 1;
360         }
361       else
362         {
363           if (ip_prefix_len (p1) > ip_prefix_len (p2))
364             cmp = 2;
365         }
366     }
367   return cmp;
368 }
369
370 static bool
371 ip4_prefix_validate (const ip_prefix_t * ip)
372 {
373   ip4_address_t ip4_addr, ip4_mask;
374
375   if (ip_prefix_len (ip) > 32)
376     return (false);
377
378   ip4_addr = ip_prefix_v4 (ip);
379   ip4_preflen_to_mask (ip_prefix_len (ip), &ip4_mask);
380
381   return ((ip4_addr.as_u32 & ip4_mask.as_u32) == ip4_addr.as_u32);
382 }
383
384 static bool
385 ip6_prefix_validate (const ip_prefix_t * ip)
386 {
387   ip6_address_t ip6_addr, ip6_mask;
388
389   if (ip_prefix_len (ip) > 128)
390     return (false);
391
392   ip6_addr = ip_prefix_v6 (ip);
393   ip6_preflen_to_mask (ip_prefix_len (ip), &ip6_mask);
394
395   return (((ip6_addr.as_u64[0] & ip6_mask.as_u64[0]) == ip6_addr.as_u64[0]) &&
396           ((ip6_addr.as_u64[1] & ip6_mask.as_u64[1]) == ip6_addr.as_u64[1]));
397 }
398
399 bool
400 ip_prefix_validate (const ip_prefix_t * ip)
401 {
402   switch (ip_prefix_version (ip))
403     {
404     case AF_IP4:
405       return (ip4_prefix_validate (ip));
406     case AF_IP6:
407       return (ip6_prefix_validate (ip));
408     }
409   ASSERT (0);
410   return (false);
411 }
412
413 void
414 ip4_address_normalize (ip4_address_t * ip4, u8 preflen)
415 {
416   ASSERT (preflen <= 32);
417   if (preflen == 0)
418     ip4->data_u32 = 0;
419   else
420     ip4->data_u32 &= clib_net_to_host_u32 (0xffffffff << (32 - preflen));
421 }
422
423 void
424 ip6_address_normalize (ip6_address_t * ip6, u8 preflen)
425 {
426   ASSERT (preflen <= 128);
427   if (preflen == 0)
428     {
429       ip6->as_u64[0] = 0;
430       ip6->as_u64[1] = 0;
431     }
432   else if (preflen <= 64)
433     {
434       ip6->as_u64[0] &=
435         clib_host_to_net_u64 (0xffffffffffffffffL << (64 - preflen));
436       ip6->as_u64[1] = 0;
437     }
438   else
439     ip6->as_u64[1] &=
440       clib_host_to_net_u64 (0xffffffffffffffffL << (128 - preflen));
441 }
442
443 void
444 ip4_preflen_to_mask (u8 pref_len, ip4_address_t * ip)
445 {
446   if (pref_len == 0)
447     ip->as_u32 = 0;
448   else
449     ip->as_u32 = clib_host_to_net_u32 (~((1 << (32 - pref_len)) - 1));
450 }
451
452 u32
453 ip4_mask_to_preflen (ip4_address_t * mask)
454 {
455   if (mask->as_u32 == 0)
456     return 0;
457   return (32 - log2_first_set (clib_net_to_host_u32 (mask->as_u32)));
458 }
459
460 void
461 ip4_prefix_max_address_host_order (ip4_address_t * ip, u8 plen,
462                                    ip4_address_t * res)
463 {
464   u32 not_mask;
465   not_mask = (1 << (32 - plen)) - 1;
466   res->as_u32 = clib_net_to_host_u32 (ip->as_u32) + not_mask;
467 }
468
469 void
470 ip6_preflen_to_mask (u8 pref_len, ip6_address_t * mask)
471 {
472   if (pref_len == 0)
473     {
474       mask->as_u64[0] = 0;
475       mask->as_u64[1] = 0;
476     }
477   else if (pref_len <= 64)
478     {
479       mask->as_u64[0] =
480         clib_host_to_net_u64 (0xffffffffffffffffL << (64 - pref_len));
481       mask->as_u64[1] = 0;
482     }
483   else
484     {
485       mask->as_u64[0] = 0xffffffffffffffffL;
486       mask->as_u64[1] =
487         clib_host_to_net_u64 (0xffffffffffffffffL << (128 - pref_len));
488     }
489 }
490
491 void
492 ip6_prefix_max_address_host_order (ip6_address_t * ip, u8 plen,
493                                    ip6_address_t * res)
494 {
495   u64 not_mask;
496   if (plen == 0)
497     {
498       res->as_u64[0] = 0xffffffffffffffffL;
499       res->as_u64[1] = 0xffffffffffffffffL;
500     }
501   else if (plen <= 64)
502     {
503       not_mask = ((u64) 1 << (64 - plen)) - 1;
504       res->as_u64[0] = clib_net_to_host_u64 (ip->as_u64[0]) + not_mask;
505       res->as_u64[1] = 0xffffffffffffffffL;
506     }
507   else
508     {
509       not_mask = ((u64) 1 << (128 - plen)) - 1;
510       res->as_u64[1] = clib_net_to_host_u64 (ip->as_u64[1]) + not_mask;
511     }
512 }
513
514 u32
515 ip6_mask_to_preflen (ip6_address_t * mask)
516 {
517   if (mask->as_u64[1] != 0)
518     return 128 - log2_first_set (clib_net_to_host_u64 (mask->as_u64[1]));
519   if (mask->as_u64[0] != 0)
520     return 64 - log2_first_set (clib_net_to_host_u64 (mask->as_u64[0]));
521   return 0;
522 }
523
524 /*
525  * fd.io coding-style-patch-verification: ON
526  *
527  * Local Variables:
528  * eval: (c-set-style "gnu")
529  * End:
530  */