Add support for LCAF Instance ID
[vpp.git] / vnet / vnet / lisp-cp / lisp_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/lisp-cp/lisp_types.h>
17
18 typedef u16 (*size_to_write_fct)(void *);
19 typedef void * (*cast_fct)(gid_address_t *);
20 typedef u16 (*serdes_fct)(u8 *, void *);
21 typedef u8 (*addr_len_fct)(void *);
22 typedef void (*copy_fct)(void *, void *);
23 typedef void (*free_fct)(void *);
24 typedef int (*cmp_fct)(void *, void *);
25
26 u16 vni_write (u8 * p, void * a);
27 u16 vni_parse (u8 * p, void * a);
28 u16 vni_size_to_write (void * a);
29 void vni_free (void * a);
30 void vni_copy (void * dst, void * src);
31 u16 vni_length (void * a);
32 int vni_cmp (void *, void *);
33
34 u16 no_addr_size_to_write (void *);
35 u16 no_addr_write (u8 * p, void * a);
36 u16 no_addr_parse (u8 * p, void * a);
37 void no_addr_free (void * a);
38 void no_addr_copy (void *, void *);
39 u16 no_addr_length (void * a);
40 int no_addr_cmp (void * a1, void * a2);
41
42 size_to_write_fct size_to_write_fcts[GID_ADDR_TYPES] =
43   { ip_prefix_size_to_write, lcaf_size_to_write };
44 serdes_fct write_fcts[GID_ADDR_TYPES] =
45   { ip_prefix_write, lcaf_write };
46 cast_fct cast_fcts[GID_ADDR_TYPES] =
47   { ip_prefix_cast, lcaf_cast };
48 addr_len_fct addr_len_fcts[GID_ADDR_TYPES] =
49   { ip_prefix_length, lcaf_prefix_length };
50 copy_fct copy_fcts[GID_ADDR_TYPES] =
51   { ip_prefix_copy, lcaf_copy };
52
53 cmp_fct lcaf_cmp_fcts[LCAF_TYPES] =
54   {
55     no_addr_cmp,
56     NULL,
57     vni_cmp
58   };
59
60 size_to_write_fct lcaf_body_length_fcts[LCAF_TYPES] =
61   {
62     no_addr_length,
63     NULL,
64     vni_length
65   };
66
67 copy_fct lcaf_copy_fcts[LCAF_TYPES] =
68   {
69     no_addr_copy,
70     NULL,
71     vni_copy
72   };
73
74 free_fct lcaf_free_fcts[LCAF_TYPES] =
75   {
76     no_addr_free,
77     NULL,
78     vni_free
79   };
80
81 size_to_write_fct lcaf_size_to_write_fcts[LCAF_TYPES] =
82   {
83     no_addr_size_to_write,
84     NULL,
85     vni_size_to_write
86   };
87
88 serdes_fct lcaf_write_fcts[LCAF_TYPES] =
89   {
90     no_addr_write,
91     NULL,
92     vni_write
93   };
94
95 serdes_fct lcaf_parse_fcts[LCAF_TYPES] =
96   {
97     no_addr_parse,
98     NULL,
99     vni_parse
100   };
101
102 u8 *
103 format_ip_address (u8 * s, va_list * args)
104 {
105   ip_address_t * a = va_arg (*args, ip_address_t *);
106   u8 ver = ip_addr_version(a);
107   if (ver == IP4)
108     {
109       return format (s, "%U", format_ip4_address, &ip_addr_v4(a));
110     }
111   else if (ver == IP6)
112     {
113       return format (s, "%U", format_ip6_address, &ip_addr_v6(a));
114     }
115   else
116     {
117       clib_warning ("Can't format IP version %d!", ver);
118       return 0;
119     }
120 }
121
122 uword
123 unformat_ip_address (unformat_input_t * input, va_list * args)
124 {
125   ip_address_t * a = va_arg(*args, ip_address_t *);
126   if (unformat(input, "%U", unformat_ip4_address, &ip_addr_v4(a)))
127     ip_addr_version(a) = IP4;
128   else if (unformat_user (input, unformat_ip6_address, &ip_addr_v6(a)))
129     ip_addr_version(a) = IP6;
130   else
131     return 0;
132   return 1;
133 }
134
135 u8 *
136 format_ip_prefix (u8 * s, va_list * args)
137 {
138   ip_prefix_t * a = va_arg (*args, ip_prefix_t *);
139   return format (s, "%U/%d", format_ip_address, &ip_prefix_addr(a), ip_prefix_len(a));
140 }
141
142 uword
143 unformat_ip_prefix (unformat_input_t * input, va_list * args)
144 {
145   ip_prefix_t * a = va_arg(*args, ip_prefix_t *);
146   return unformat (input, "%U/%d", unformat_ip_address, &ip_prefix_addr(a),
147                    &ip_prefix_len(a));
148 }
149
150 u8 *
151 format_gid_address (u8 * s, va_list * args)
152 {
153   gid_address_t * a = va_arg(*args, gid_address_t *);
154   u8 type = gid_address_type(a);
155   switch (type)
156     {
157     case GID_ADDR_IP_PREFIX:
158       return format (s, "%U", format_ip_prefix, &gid_address_ippref(a));
159     default:
160       clib_warning("Can't format gid type %d", type);
161       return 0;
162     }
163 }
164
165 uword
166 unformat_gid_address (unformat_input_t * input, va_list * args)
167 {
168   gid_address_t * a = va_arg(*args, gid_address_t *);
169   if (unformat (input, "%U", unformat_ip_prefix, &gid_address_ippref(a)))
170     gid_address_type(a) = GID_ADDR_IP_PREFIX;
171   else
172     return 0;
173   return 1;
174 }
175
176 u16
177 ip_address_size (ip_address_t * a)
178 {
179   switch (ip_addr_version (a))
180   {
181     case IP4:
182       return sizeof(ip4_address_t);
183       break;
184     case IP6:
185       return sizeof(ip6_address_t);
186       break;
187   }
188   return 0;
189 }
190
191 u16
192 ip_version_to_size (u8 ver)
193 {
194   switch (ver)
195   {
196     case IP4:
197       return sizeof(ip4_address_t);
198       break;
199     case IP6:
200       return sizeof(ip6_address_t);
201       break;
202   }
203   return 0;
204 }
205
206 u8
207 ip_version_to_max_plen (u8 ver)
208 {
209   switch (ver)
210   {
211     case IP4:
212       return 32;
213       break;
214     case IP6:
215       return 128;
216       break;
217   }
218   return 0;
219 }
220
221 always_inline lisp_afi_e
222 ip_version_to_iana_afi (u16 version)
223 {
224   switch (version)
225     {
226     case IP4:
227       return LISP_AFI_IP;
228     case IP6:
229       return LISP_AFI_IP6;
230     default:
231       return 0;
232     }
233   return 0;
234 }
235
236 always_inline u8
237 ip_iana_afi_to_version (lisp_afi_e afi)
238 {
239   switch (afi)
240     {
241     case LISP_AFI_IP:
242       return IP4;
243     case LISP_AFI_IP6:
244       return IP6;
245     default:
246       return 0;
247     }
248   return 0;
249 }
250
251 u16
252 ip_address_size_to_write (ip_address_t * a)
253 {
254   return ip_address_size (a) + sizeof (u16);
255 }
256
257 u16
258 ip_address_iana_afi(ip_address_t *a)
259 {
260     return ip_version_to_iana_afi(ip_addr_version(a));
261 }
262
263 u8
264 ip_address_max_len (u8 version)
265 {
266   return version == IP4 ? 32 : 128;
267 }
268
269 u16
270 ip4_address_size_to_put ()
271 {
272   // return sizeof(u16) + sizeof (ip4_address_t);
273   return 6;
274 }
275
276 u16
277 ip6_address_size_to_put ()
278 {
279   //return sizeof(u16) + sizeof (ip6_address_t);
280   return 18;
281 }
282
283 u32
284 ip4_address_put (u8 * b, ip4_address_t * a)
285 {
286   *(u16 *)b = clib_host_to_net_u16(ip_version_to_iana_afi(IP4));
287   u8 *p = b + sizeof (u16);
288   clib_memcpy (p, a, sizeof(*a));
289   return ip4_address_size_to_put();
290 }
291
292 u32
293 ip6_address_put (u8 * b, ip6_address_t * a)
294 {
295   *(u16 *)b = clib_host_to_net_u16(ip_version_to_iana_afi(IP6));
296   u8 *p = b + sizeof (u16);
297   clib_memcpy (p, a, sizeof(*a));
298   return ip6_address_size_to_put();
299 }
300
301 u32
302 ip_address_put (u8 * b, ip_address_t * a)
303 {
304   u32 len = ip_address_size (a);
305   *(u16 *) b = clib_host_to_net_u16(ip_address_iana_afi (a));
306   u8 * p = b + sizeof (u16);
307   clib_memcpy (p, &ip_addr_addr (a), len);
308   return (len + sizeof (u16));
309 }
310
311 u32
312 ip_address_parse(void * offset, u16 iana_afi, ip_address_t *dst)
313 {
314   ip_addr_version(dst) = ip_iana_afi_to_version (iana_afi);
315   u8 size = ip_version_to_size (ip_addr_version(dst));
316   clib_memcpy (&ip_addr_addr(dst), offset + sizeof(u16), size);
317   return(sizeof(u16) + size);
318 }
319
320 u32
321 lcaf_hdr_parse (void * offset, lcaf_t * lcaf)
322 {
323   lcaf_hdr_t * lh = offset;
324   lcaf->type = lh->type;
325
326   /* this is a bit of hack: since the LCAF Instance ID is the
327     only message that uses reserved2 field, we can set it here.
328     If any LCAF format starts using reserved2 field as well this needs
329     to be moved elsewhere */
330   lcaf_vni_len (lcaf) = lh->reserved2;
331
332   return sizeof (lh[0]);
333 }
334
335 u16
336 vni_parse (u8 * p, void * a)
337 {
338   vni_t * v = a;
339   u16 size = 0;
340   vni_vni (v) = clib_net_to_host_u32 ( *(u32 *) p);
341   size += sizeof (u32);
342
343   vni_gid (v) = clib_mem_alloc (sizeof (gid_address_t));
344   gid_address_t * gid = vni_gid (v);
345   memset (gid, 0, sizeof (gid[0]));
346
347   size += gid_address_parse (p + size, gid);
348   return size;
349 }
350
351 u16
352 no_addr_parse (u8 * p, void * a)
353 {
354   /* do nothing */
355   return 0;
356 }
357
358 u32
359 lcaf_parse (void * offset, gid_address_t *addr)
360 {
361   /* skip AFI type */
362   offset += sizeof (u16);
363   lcaf_t * lcaf = &gid_address_lcaf (addr);
364
365   u32 size = lcaf_hdr_parse (offset, lcaf);
366   u8 type = lcaf_type (lcaf);
367
368   if (!lcaf_parse_fcts[type])
369     {
370       clib_warning ("Unsupported LCAF type: %u", type);
371       return ~0;
372     }
373   size += (*lcaf_parse_fcts[type])(offset + size, lcaf);
374   return sizeof (u16) + size;
375 }
376
377 void
378 vni_free (void * a)
379 {
380   vni_t * v = a;
381   gid_address_free (vni_gid (v));
382   clib_mem_free (vni_gid (v));
383 }
384
385 void
386 no_addr_free (void * a)
387 {
388   /* nothing to do */
389 }
390
391 void
392 gid_address_free (gid_address_t *a)
393 {
394   if (gid_address_type (a) != GID_ADDR_LCAF)
395     return;
396
397   lcaf_t * lcaf = &gid_address_lcaf (a);
398   u8 lcaf_type = lcaf_type (lcaf);
399   (*lcaf_free_fcts[lcaf_type])(lcaf);
400 }
401
402 int
403 ip_address_cmp (ip_address_t * ip1, ip_address_t * ip2)
404 {
405   int res = 0;
406   if (ip_addr_version (ip1) != ip_addr_version(ip2))
407     return -1;
408   res = memcmp (&ip_addr_addr(ip1), &ip_addr_addr(ip2), ip_address_size (ip1));
409
410   if (res < 0)
411     res = 2;
412   else if (res > 0)
413     res = 1;
414
415   return res;
416 }
417
418 void
419 ip_address_copy (ip_address_t * dst , ip_address_t * src)
420 {
421   clib_memcpy (dst, src, sizeof (ip_address_t));
422 }
423
424 void
425 ip_address_copy_addr (void * dst , ip_address_t * src)
426 {
427   clib_memcpy (dst, src, ip_address_size(src));
428 }
429
430 void *
431 ip_prefix_cast (gid_address_t * a)
432 {
433   return &gid_address_ippref(a);
434 }
435
436 u16
437 ip_prefix_size_to_write (void * pref)
438 {
439   ip_prefix_t *a = (ip_prefix_t *) pref;
440   return ip_address_size_to_write (&ip_prefix_addr (a));
441 }
442
443 u16
444 ip_prefix_write (u8 * p, void * pref)
445 {
446   ip_prefix_t *a = (ip_prefix_t *) pref;
447   switch (ip_prefix_version (a))
448   {
449     case IP4:
450       return ip4_address_put (p, &ip_prefix_v4 (a));
451       break;
452     case IP6:
453       return ip6_address_put (p, &ip_prefix_v6 (a));
454       break;
455   }
456   return 0;
457 }
458
459 u8
460 ip_prefix_length (void *a)
461 {
462   return ip_prefix_len((ip_prefix_t *) a);
463 }
464
465 void
466 ip_prefix_copy (void * dst , void * src)
467 {
468   clib_memcpy (dst, src, sizeof (ip_prefix_t));
469 }
470
471 int
472 ip_prefix_cmp(ip_prefix_t * p1, ip_prefix_t * p2)
473 {
474   int cmp = 0;
475   cmp = ip_address_cmp (&ip_prefix_addr(p1), &ip_prefix_addr(p2));
476   if (cmp == 0)
477   {
478     if (ip_prefix_len(p1) < ip_prefix_len(p2))
479     {
480       cmp = 1;
481     }
482     else
483     {
484       if (ip_prefix_len(p1) > ip_prefix_len(p2))
485         cmp = 2;
486     }
487   }
488   return cmp;
489 }
490
491 void
492 no_addr_copy (void * dst, void * src)
493 {
494   /* nothing to do */
495 }
496
497 void
498 vni_copy (void * dst, void * src)
499 {
500   vni_t * vd = dst;
501   vni_t * vs = src;
502
503   clib_memcpy (vd, vs, sizeof (vd[0]));
504   vni_gid (vd) = clib_mem_alloc (sizeof (gid_address_t));
505   gid_address_copy (vni_gid (vd), vni_gid (vs));
506 }
507
508 void
509 lcaf_copy (void * dst , void * src)
510 {
511   lcaf_t * lcaf_dst = dst;
512   lcaf_t * lcaf_src = src;
513
514   lcaf_type (lcaf_dst) = lcaf_type (lcaf_src);
515   (*lcaf_copy_fcts[lcaf_type (lcaf_src)])(dst, src);
516 }
517
518 u8
519 lcaf_prefix_length (void *a)
520 {
521   return 0;
522 }
523
524 void *
525 lcaf_cast (gid_address_t * a)
526 {
527   return &gid_address_lcaf (a);
528 }
529
530 u16
531 no_addr_length (void * a)
532 {
533   return 0;
534 }
535
536 u16
537 vni_length (void * a)
538 {
539   vni_t * v = a;
540   return (sizeof (u32) /* VNI size */
541    + gid_address_size_to_put (vni_gid (v)) /* vni body size*/);
542 }
543
544 u16
545 lcaf_write (u8 * p, void * a)
546 {
547   u16 size = 0, len;
548   lcaf_t * lcaf = a;
549   u8 type = lcaf_type (lcaf);
550   lcaf_hdr_t _h, *h = &_h;
551
552   *(u16 *) p = clib_host_to_net_u16 (LISP_AFI_LCAF);
553   size += sizeof (u16);
554   memset (h, 0, sizeof (h[0]));
555   LCAF_TYPE (h) = type;
556   u16 lcaf_len = (*lcaf_body_length_fcts[type])(lcaf);
557   LCAF_LENGTH (h) = clib_host_to_net_u16 (lcaf_len);
558
559   if (LCAF_INSTANCE_ID == type)
560     LCAF_RES2 (h) = lcaf_vni_len(lcaf);
561
562   clib_memcpy (p + size, h, sizeof (h[0]));
563   size += sizeof (h[0]);
564   len = (*lcaf_write_fcts[type])(p + size, lcaf);
565
566   if (~0 == len)
567     return ~0;
568
569   return size + len;
570 }
571
572 u16
573 vni_write (u8 * p, void * a)
574 {
575   vni_t * v = a;
576   u16 size = 0, len;
577
578   *(u32 *)p = clib_host_to_net_u32 (vni_vni (v));
579   size += sizeof (u32);
580   len = gid_address_put (p + size, vni_gid (v));
581
582   if (~0 == len)
583     return ~0;
584
585   return size + len;
586 }
587
588 u16
589 no_addr_write (u8 * p, void * a)
590 {
591   /* do nothing; return AFI field size */
592   return sizeof (u16);
593 }
594
595 u16
596 no_addr_size_to_write (void * a)
597 {
598   return sizeof (u16); /* AFI field length */
599 }
600
601 u16
602 vni_size_to_write (void * a)
603 {
604   vni_t * v =  a;
605   u16 size = sizeof (vni_vni (v));
606
607   gid_address_t * gid = vni_gid (v);
608   return (size + sizeof (lcaf_hdr_t)
609     + gid_address_size_to_put (gid));
610 }
611
612 u16
613 lcaf_size_to_write (void * a)
614 {
615   lcaf_t * lcaf = (lcaf_t *) a;
616   u32 size = 0, len;
617   u8 type = lcaf_type (lcaf);
618
619   size += sizeof (u16); /* AFI size */
620
621   len = (*lcaf_size_to_write_fcts[type])(lcaf);
622   if (~0 == len)
623     return ~0;
624
625   return size + len;
626 }
627
628 u8
629 gid_address_len (gid_address_t *a)
630 {
631   gid_address_type_t type = gid_address_type (a);
632   return (*addr_len_fcts[type])((*cast_fcts[type])(a));
633 }
634
635 u16
636 gid_address_put (u8 * b, gid_address_t * gid)
637 {
638   gid_address_type_t type = gid_address_type (gid);
639   return (*write_fcts[type])(b, (*cast_fcts[type])(gid));
640 }
641
642 u16
643 gid_address_size_to_put (gid_address_t * gid)
644 {
645   gid_address_type_t type = gid_address_type (gid);
646   return (*size_to_write_fcts[type])((*cast_fcts[type])(gid));
647 }
648
649 void *
650 gid_address_cast (gid_address_t * gid, gid_address_type_t type)
651 {
652   return (*cast_fcts[type])(gid);
653 }
654
655 void
656 gid_address_copy(gid_address_t * dst, gid_address_t * src)
657 {
658   gid_address_type_t type = gid_address_type(src);
659   (*copy_fcts[type])((*cast_fcts[type])(dst), (*cast_fcts[type])(src));
660   gid_address_type(dst) = type;
661 }
662
663 u32
664 gid_address_parse (u8 * offset, gid_address_t *a)
665 {
666   lisp_afi_e afi;
667   int len = 0;
668
669   if (!a)
670     return 0;
671
672   afi = clib_net_to_host_u16 (*((u16 *) offset));
673
674   switch (afi)
675     {
676     case LISP_AFI_NO_ADDR:
677       len = sizeof(u16);
678       gid_address_type(a) = GID_ADDR_NO_ADDRESS;
679       break;
680     case LISP_AFI_IP:
681       len = ip_address_parse (offset, afi, &gid_address_ip(a));
682       gid_address_type(a) = GID_ADDR_IP_PREFIX;
683       /* this should be modified outside if needed*/
684       gid_address_ippref_len(a) = 32;
685       break;
686     case LISP_AFI_IP6:
687       len = ip_address_parse (offset, afi, &gid_address_ip(a));
688       gid_address_type(a) = GID_ADDR_IP_PREFIX;
689       /* this should be modified outside if needed*/
690       gid_address_ippref_len(a) = 128;
691       break;
692     case LISP_AFI_LCAF:
693       len = lcaf_parse (offset, a);
694       gid_address_type(a) = GID_ADDR_LCAF;
695       break;
696     default:
697       clib_warning("LISP AFI %d not supported!", afi);
698       return ~0;
699     }
700   return len;
701 }
702
703 int
704 no_addr_cmp (void * a1, void * a2)
705 {
706   return 0;
707 }
708
709 int
710 vni_cmp (void * a1, void * a2)
711 {
712   vni_t * v1 = a1;
713   vni_t * v2 = a2;
714
715   if (vni_mask_len (v1) != vni_mask_len (v2))
716     return -1;
717   if (vni_vni (v1) != vni_vni (v2))
718     return -1;
719   return gid_address_cmp (vni_gid (v1), vni_gid (v2));
720 }
721
722 /* Compare two gid_address_t.
723  * Returns:
724  *        -1: If they are from different afi
725  *             0: Both address are the same
726  *             1: Addr1 is bigger than addr2
727  *             2: Addr2 is bigger than addr1
728  */
729 int
730 gid_address_cmp (gid_address_t * a1, gid_address_t * a2)
731 {
732   lcaf_t * lcaf1, * lcaf2;
733   int cmp = -1;
734   if (!a1 || !a2)
735     return -1;
736   if (gid_address_type(a1) != gid_address_type(a2))
737     return -1;
738
739   switch (gid_address_type(a1))
740     {
741     case GID_ADDR_NO_ADDRESS:
742       if (a1 == a2)
743         cmp = 0;
744       else
745         cmp = 2;
746       break;
747     case GID_ADDR_IP_PREFIX:
748       cmp = ip_prefix_cmp (&gid_address_ippref(a1), &gid_address_ippref(a2));
749       break;
750     case GID_ADDR_LCAF:
751       lcaf1 = &gid_address_lcaf (a1);
752       lcaf2 = &gid_address_lcaf (a2);
753       if (lcaf_type (lcaf1) == lcaf_type (lcaf2))
754         cmp = (*lcaf_cmp_fcts[lcaf_type (lcaf1)])(lcaf1, lcaf2);
755       break;
756     default:
757       break;
758     }
759
760   return cmp;
761 }
762
763
764 u32
765 locator_parse (void * b, locator_t * loc)
766 {
767   locator_hdr_t * h;
768   u8 status = 1; /* locator up */
769   int len;
770
771   h = b;
772   if (!LOC_REACHABLE(h) && LOC_LOCAL(h))
773     status = 0;
774
775   len = gid_address_parse (LOC_ADDR(h), &loc->address);
776   if (len == ~0)
777     return len;
778
779   loc->state = status;
780   loc->local = 0;
781   loc->priority = LOC_PRIORITY(h);
782   loc->weight = LOC_WEIGHT(h);
783   loc->mpriority = LOC_MPRIORITY(h);
784   loc->mweight = LOC_MWEIGHT(h);
785
786   return sizeof(locator_hdr_t) + len;
787 }
788
789 void
790 locator_copy (locator_t * dst, locator_t * src)
791 {
792   /* TODO if gid become more complex, this will need to be changed! */
793   clib_memcpy (dst, src, sizeof(*dst));
794   if (!src->local)
795     gid_address_copy (&dst->address, &src->address);
796 }
797
798 u32
799 locator_cmp (locator_t * l1, locator_t * l2)
800 {
801   u32 ret = 0;
802   if ((ret = gid_address_cmp (&l1->address, &l2->address)) != 0)
803     return 1;
804
805   if (l1->priority != l2->priority)
806     return 1;
807   if (l1->weight != l2->weight)
808     return 1;
809   if (l1->mpriority != l2->mpriority)
810     return 1;
811   if (l1->mweight != l2->mweight)
812     return 1;
813   return 0;
814 }
815
816 void
817 locator_free (locator_t * l)
818 {
819   if (!l->local)
820     gid_address_free (&l->address);
821 }