Add unit test infrastructure for LISP protocol
[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 (*write_fct)(u8 *, void *);
21 typedef u8 (*addr_len_fct)(void *);
22 typedef void (*copy_fct)(void *, void *);
23
24 size_to_write_fct size_to_write_fcts[GID_ADDR_TYPES] =
25   { ip_prefix_size_to_write };
26 write_fct write_fcts[GID_ADDR_TYPES] =
27   { ip_prefix_write };
28 cast_fct cast_fcts[GID_ADDR_TYPES] =
29   { ip_prefix_cast };
30 addr_len_fct addr_len_fcts[GID_ADDR_TYPES] =
31   { ip_prefix_length };
32 copy_fct copy_fcts[GID_ADDR_TYPES] =
33   { ip_prefix_copy };
34
35 u8 *
36 format_ip_address (u8 * s, va_list * args)
37 {
38   ip_address_t * a = va_arg (*args, ip_address_t *);
39   u8 ver = ip_addr_version(a);
40   if (ver == IP4)
41     {
42       return format (s, "%U", format_ip4_address, &ip_addr_v4(a));
43     }
44   else if (ver == IP6)
45     {
46       return format (s, "%U", format_ip6_address, &ip_addr_v6(a));
47     }
48   else
49     {
50       clib_warning ("Can't format IP version %d!", ver);
51       return 0;
52     }
53 }
54
55 uword
56 unformat_ip_address (unformat_input_t * input, va_list * args)
57 {
58   ip_address_t * a = va_arg(*args, ip_address_t *);
59   if (unformat(input, "%U", unformat_ip4_address, &ip_addr_v4(a)))
60     ip_addr_version(a) = IP4;
61   else if (unformat_user (input, unformat_ip6_address, &ip_addr_v6(a)))
62     ip_addr_version(a) = IP6;
63   else
64     return 0;
65   return 1;
66 }
67
68 u8 *
69 format_ip_prefix (u8 * s, va_list * args)
70 {
71   ip_prefix_t * a = va_arg (*args, ip_prefix_t *);
72   return format (s, "%U/%d", format_ip_address, &ip_prefix_addr(a), ip_prefix_len(a));
73 }
74
75 uword
76 unformat_ip_prefix (unformat_input_t * input, va_list * args)
77 {
78   ip_prefix_t * a = va_arg(*args, ip_prefix_t *);
79   return unformat (input, "%U/%d", unformat_ip_address, &ip_prefix_addr(a),
80                    &ip_prefix_len(a));
81 }
82
83 u8 *
84 format_gid_address (u8 * s, va_list * args)
85 {
86   gid_address_t * a = va_arg(*args, gid_address_t *);
87   u8 type = gid_address_type(a);
88   switch (type)
89     {
90     case IP_PREFIX:
91       return format (s, "%U", format_ip_prefix, &gid_address_ippref(a));
92     default:
93       clib_warning("Can't format gid type %d", type);
94       return 0;
95     }
96 }
97
98 uword
99 unformat_gid_address (unformat_input_t * input, va_list * args)
100 {
101   gid_address_t * a = va_arg(*args, gid_address_t *);
102   if (unformat (input, "%U", unformat_ip_prefix, &gid_address_ippref(a)))
103     gid_address_type(a) = IP_PREFIX;
104   else
105     return 0;
106   return 1;
107 }
108
109 u16
110 ip_address_size (ip_address_t * a)
111 {
112   switch (ip_addr_version (a))
113   {
114     case IP4:
115       return sizeof(ip4_address_t);
116       break;
117     case IP6:
118       return sizeof(ip6_address_t);
119       break;
120   }
121   return 0;
122 }
123
124 u16
125 ip_version_to_size (u8 ver)
126 {
127   switch (ver)
128   {
129     case IP4:
130       return sizeof(ip4_address_t);
131       break;
132     case IP6:
133       return sizeof(ip6_address_t);
134       break;
135   }
136   return 0;
137 }
138
139 u8
140 ip_version_to_max_plen (u8 ver)
141 {
142   switch (ver)
143   {
144     case IP4:
145       return 32;
146       break;
147     case IP6:
148       return 128;
149       break;
150   }
151   return 0;
152 }
153
154 always_inline lisp_afi_e
155 ip_version_to_iana_afi (u16 version)
156 {
157   switch (version)
158     {
159     case IP4:
160       return LISP_AFI_IP;
161     case IP6:
162       return LISP_AFI_IP6;
163     default:
164       return 0;
165     }
166   return 0;
167 }
168
169 always_inline u8
170 ip_iana_afi_to_version (lisp_afi_e afi)
171 {
172   switch (afi)
173     {
174     case LISP_AFI_IP:
175       return IP4;
176     case LISP_AFI_IP6:
177       return IP6;
178     default:
179       return 0;
180     }
181   return 0;
182 }
183
184 u16
185 ip_address_size_to_write (ip_address_t * a)
186 {
187   return ip_address_size (a) + sizeof (u16);
188 }
189
190 u16
191 ip_address_iana_afi(ip_address_t *a)
192 {
193     return ip_version_to_iana_afi(ip_addr_version(a));
194 }
195
196 u8
197 ip_address_max_len (u8 version)
198 {
199   return version == IP4 ? 32 : 128;
200 }
201
202 u16
203 ip4_address_size_to_put ()
204 {
205   // return sizeof(u16) + sizeof (ip4_address_t);
206   return 6;
207 }
208
209 u16
210 ip6_address_size_to_put ()
211 {
212   //return sizeof(u16) + sizeof (ip6_address_t);
213   return 18;
214 }
215
216 u32
217 ip4_address_put (u8 * b, ip4_address_t * a)
218 {
219   *(u16 *)b = clib_host_to_net_u16(ip_version_to_iana_afi(IP4));
220   u8 *p = b + sizeof (u16);
221   memcpy (p, a, sizeof(*a));
222   return ip4_address_size_to_put();
223 }
224
225 u32
226 ip6_address_put (u8 * b, ip6_address_t * a)
227 {
228   *(u16 *)b = clib_host_to_net_u16(ip_version_to_iana_afi(IP6));
229   u8 *p = b + sizeof (u16);
230   memcpy (p, a, sizeof(*a));
231   return ip6_address_size_to_put();
232 }
233
234 u32
235 ip_address_put (u8 * b, ip_address_t * a)
236 {
237   u32 len = ip_address_size (a);
238   *(u16 *) b = clib_host_to_net_u16(ip_address_iana_afi (a));
239   u8 * p = b + sizeof (u16);
240   memcpy (p, &ip_addr_addr (a), len);
241   return (len + sizeof (u16));
242 }
243
244 u32
245 ip_address_parse(void * offset, u16 iana_afi, ip_address_t *dst)
246 {
247   ip_addr_version(dst) = ip_iana_afi_to_version (iana_afi);
248   u8 size = ip_version_to_size (ip_addr_version(dst));
249   memcpy (&ip_addr_addr(dst), offset + sizeof(u16), size);
250   return(sizeof(u16) + size);
251 }
252
253 int
254 ip_address_cmp (ip_address_t * ip1, ip_address_t * ip2)
255 {
256   int res = 0;
257   if (ip_addr_version (ip1) != ip_addr_version(ip2))
258     return -1;
259   res = memcmp (&ip_addr_addr(ip1), &ip_addr_addr(ip2), ip_address_size (ip1));
260
261   if (res < 0)
262     res = 2;
263   else if (res > 0)
264     res = 1;
265
266   return res;
267 }
268
269 void *
270 ip_prefix_cast (gid_address_t * a)
271 {
272   return &gid_address_ippref(a);
273 }
274
275 u16
276 ip_prefix_size_to_write (void * pref)
277 {
278   ip_prefix_t *a = (ip_prefix_t *) pref;
279   return ip_address_size_to_write (&ip_prefix_addr (a));
280 }
281
282 u16
283 ip_prefix_write (u8 * p, void * pref)
284 {
285   ip_prefix_t *a = (ip_prefix_t *) pref;
286   switch (ip_prefix_version (a))
287   {
288     case IP4:
289       return ip4_address_put (p, &ip_prefix_v4 (a));
290       break;
291     case IP6:
292       return ip6_address_put (p, &ip_prefix_v6 (a));
293       break;
294   }
295   return 0;
296 }
297
298 u8
299 ip_prefix_length (void *a)
300 {
301   return ip_prefix_len((ip_prefix_t *) a);
302 }
303
304 void
305 ip_prefix_copy (void * dst , void * src)
306 {
307   memcpy (dst, src, sizeof (ip_prefix_t));
308 }
309
310 int
311 ip_prefix_cmp(ip_prefix_t * p1, ip_prefix_t * p2)
312 {
313   int cmp = 0;
314   cmp = ip_address_cmp (&ip_prefix_addr(p1), &ip_prefix_addr(p2));
315   if (cmp == 0)
316   {
317     if (ip_prefix_len(p1) < ip_prefix_len(p2))
318     {
319       cmp = 1;
320     }
321     else
322     {
323       if (ip_prefix_len(p1) > ip_prefix_len(p2))
324         cmp = 2;
325     }
326   }
327   return cmp;
328 }
329
330 u8
331 gid_address_len (gid_address_t *a)
332 {
333   gid_address_type_t type = gid_address_type (a);
334   return (*addr_len_fcts[type])((*cast_fcts[type])(a));
335 }
336
337 u16
338 gid_address_put (u8 * b, gid_address_t * gid)
339 {
340   gid_address_type_t type = gid_address_type (gid);
341   return (*write_fcts[type])(b, (*cast_fcts[type])(gid));
342 }
343
344 u16
345 gid_address_size_to_put (gid_address_t * gid)
346 {
347   gid_address_type_t type = gid_address_type (gid);
348   return (*size_to_write_fcts[type])((*cast_fcts[type])(gid));
349 }
350
351 void *
352 gid_address_cast (gid_address_t * gid, gid_address_type_t type)
353 {
354   return (*cast_fcts[type])(gid);
355 }
356
357 void
358 gid_address_copy(gid_address_t * dst, gid_address_t * src)
359 {
360   gid_address_type_t type = gid_address_type(src);
361   (*copy_fcts[type])((*cast_fcts[type])(dst), (*cast_fcts[type])(src));
362   gid_address_type(dst) = type;
363 }
364
365 u32
366 gid_address_parse (u8 * offset, gid_address_t *a)
367 {
368   lisp_afi_e afi;
369   int len = 0;
370
371   if (!a)
372     return 0;
373
374   afi = clib_net_to_host_u16 (*((u16 *) offset));
375
376   switch (afi)
377     {
378     case LISP_AFI_NO_ADDR:
379       len = sizeof(u16);
380       gid_address_type(a) = NO_ADDRESS;
381       break;
382     case LISP_AFI_IP:
383       len = ip_address_parse (offset, afi, &gid_address_ip(a));
384       gid_address_type(a) = IP_PREFIX;
385       /* this should be modified outside if needed*/
386       gid_address_ippref_len(a) = 32;
387       break;
388     case LISP_AFI_IP6:
389       len = ip_address_parse (offset, afi, &gid_address_ip(a));
390       gid_address_type(a) = IP_PREFIX;
391       /* this should be modified outside if needed*/
392       gid_address_ippref_len(a) = 128;
393       break;
394     case LISP_AFI_LCAF:
395     default:
396       clib_warning("LISP AFI %d not supported!", afi);
397       return ~0;
398     }
399   return len;
400 }
401
402 /* Compare two gid_address_t.
403  * Returns:
404  *        -1: If they are from different afi
405  *             0: Both address are the same
406  *             1: Addr1 is bigger than addr2
407  *             2: Addr2 is bigger than addr1
408  */
409 int
410 gid_address_cmp (gid_address_t * a1, gid_address_t * a2)
411 {
412   int cmp = -1;
413   if (!a1 || !a2)
414     return -1;
415   if (gid_address_type(a1) != gid_address_type(a2))
416     return -1;
417
418   switch (gid_address_type(a1))
419     {
420     case NO_ADDRESS:
421       if (a1 == a2)
422         cmp = 0;
423       else
424         cmp = 2;
425       break;
426     case IP_PREFIX:
427       cmp = ip_prefix_cmp (&gid_address_ippref(a1), &gid_address_ippref(a2));
428       break;
429     default:
430       break;
431     }
432
433   return cmp;
434 }
435
436
437 u32
438 locator_parse (void * b, locator_t * loc)
439 {
440   locator_hdr_t * h;
441   u8 status = 1; /* locator up */
442   int len;
443
444   h = b;
445   if (!LOC_REACHABLE(h) && LOC_LOCAL(h))
446     status = 0;
447
448   len = gid_address_parse (LOC_ADDR(h), &loc->address);
449   if (len == ~0)
450     return len;
451
452   loc->state = status;
453   loc->local = 0;
454   loc->priority = LOC_PRIORITY(h);
455   loc->weight = LOC_WEIGHT(h);
456   loc->mpriority = LOC_MPRIORITY(h);
457   loc->mweight = LOC_MWEIGHT(h);
458
459   return sizeof(locator_hdr_t) + len;
460 }
461
462 void
463 locator_copy (locator_t * dst, locator_t * src)
464 {
465   /* TODO if gid become more complex, this will need to be changed! */
466   memcpy (dst, src, sizeof(*dst));
467 }
468
469 u32
470 locator_cmp (locator_t * l1, locator_t * l2)
471 {
472   u32 ret = 0;
473   if ((ret = gid_address_cmp (&l1->address, &l2->address)) != 0)
474     return 1;
475
476   if (l1->priority != l2->priority)
477     return 1;
478   if (l1->weight != l2->weight)
479     return 1;
480   if (l1->mpriority != l2->mpriority)
481     return 1;
482   if (l1->mweight != l2->mweight)
483     return 1;
484   return 0;
485 }