Add lisp-gpe ip6 data-plane support
[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   clib_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   clib_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   clib_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   clib_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_address_copy (ip_address_t * dst , ip_address_t * src)
271 {
272   clib_memcpy (dst, src, sizeof (ip_address_t));
273 }
274
275 void
276 ip_address_copy_addr (void * dst , ip_address_t * src)
277 {
278   clib_memcpy (dst, src, ip_address_size(src));
279 }
280
281 void *
282 ip_prefix_cast (gid_address_t * a)
283 {
284   return &gid_address_ippref(a);
285 }
286
287 u16
288 ip_prefix_size_to_write (void * pref)
289 {
290   ip_prefix_t *a = (ip_prefix_t *) pref;
291   return ip_address_size_to_write (&ip_prefix_addr (a));
292 }
293
294 u16
295 ip_prefix_write (u8 * p, void * pref)
296 {
297   ip_prefix_t *a = (ip_prefix_t *) pref;
298   switch (ip_prefix_version (a))
299   {
300     case IP4:
301       return ip4_address_put (p, &ip_prefix_v4 (a));
302       break;
303     case IP6:
304       return ip6_address_put (p, &ip_prefix_v6 (a));
305       break;
306   }
307   return 0;
308 }
309
310 u8
311 ip_prefix_length (void *a)
312 {
313   return ip_prefix_len((ip_prefix_t *) a);
314 }
315
316 void
317 ip_prefix_copy (void * dst , void * src)
318 {
319   clib_memcpy (dst, src, sizeof (ip_prefix_t));
320 }
321
322 int
323 ip_prefix_cmp(ip_prefix_t * p1, ip_prefix_t * p2)
324 {
325   int cmp = 0;
326   cmp = ip_address_cmp (&ip_prefix_addr(p1), &ip_prefix_addr(p2));
327   if (cmp == 0)
328   {
329     if (ip_prefix_len(p1) < ip_prefix_len(p2))
330     {
331       cmp = 1;
332     }
333     else
334     {
335       if (ip_prefix_len(p1) > ip_prefix_len(p2))
336         cmp = 2;
337     }
338   }
339   return cmp;
340 }
341
342 u8
343 gid_address_len (gid_address_t *a)
344 {
345   gid_address_type_t type = gid_address_type (a);
346   return (*addr_len_fcts[type])((*cast_fcts[type])(a));
347 }
348
349 u16
350 gid_address_put (u8 * b, gid_address_t * gid)
351 {
352   gid_address_type_t type = gid_address_type (gid);
353   return (*write_fcts[type])(b, (*cast_fcts[type])(gid));
354 }
355
356 u16
357 gid_address_size_to_put (gid_address_t * gid)
358 {
359   gid_address_type_t type = gid_address_type (gid);
360   return (*size_to_write_fcts[type])((*cast_fcts[type])(gid));
361 }
362
363 void *
364 gid_address_cast (gid_address_t * gid, gid_address_type_t type)
365 {
366   return (*cast_fcts[type])(gid);
367 }
368
369 void
370 gid_address_copy(gid_address_t * dst, gid_address_t * src)
371 {
372   gid_address_type_t type = gid_address_type(src);
373   (*copy_fcts[type])((*cast_fcts[type])(dst), (*cast_fcts[type])(src));
374   gid_address_type(dst) = type;
375 }
376
377 u32
378 gid_address_parse (u8 * offset, gid_address_t *a)
379 {
380   lisp_afi_e afi;
381   int len = 0;
382
383   if (!a)
384     return 0;
385
386   afi = clib_net_to_host_u16 (*((u16 *) offset));
387
388   switch (afi)
389     {
390     case LISP_AFI_NO_ADDR:
391       len = sizeof(u16);
392       gid_address_type(a) = NO_ADDRESS;
393       break;
394     case LISP_AFI_IP:
395       len = ip_address_parse (offset, afi, &gid_address_ip(a));
396       gid_address_type(a) = IP_PREFIX;
397       /* this should be modified outside if needed*/
398       gid_address_ippref_len(a) = 32;
399       break;
400     case LISP_AFI_IP6:
401       len = ip_address_parse (offset, afi, &gid_address_ip(a));
402       gid_address_type(a) = IP_PREFIX;
403       /* this should be modified outside if needed*/
404       gid_address_ippref_len(a) = 128;
405       break;
406     case LISP_AFI_LCAF:
407     default:
408       clib_warning("LISP AFI %d not supported!", afi);
409       return ~0;
410     }
411   return len;
412 }
413
414 /* Compare two gid_address_t.
415  * Returns:
416  *        -1: If they are from different afi
417  *             0: Both address are the same
418  *             1: Addr1 is bigger than addr2
419  *             2: Addr2 is bigger than addr1
420  */
421 int
422 gid_address_cmp (gid_address_t * a1, gid_address_t * a2)
423 {
424   int cmp = -1;
425   if (!a1 || !a2)
426     return -1;
427   if (gid_address_type(a1) != gid_address_type(a2))
428     return -1;
429
430   switch (gid_address_type(a1))
431     {
432     case NO_ADDRESS:
433       if (a1 == a2)
434         cmp = 0;
435       else
436         cmp = 2;
437       break;
438     case IP_PREFIX:
439       cmp = ip_prefix_cmp (&gid_address_ippref(a1), &gid_address_ippref(a2));
440       break;
441     default:
442       break;
443     }
444
445   return cmp;
446 }
447
448
449 u32
450 locator_parse (void * b, locator_t * loc)
451 {
452   locator_hdr_t * h;
453   u8 status = 1; /* locator up */
454   int len;
455
456   h = b;
457   if (!LOC_REACHABLE(h) && LOC_LOCAL(h))
458     status = 0;
459
460   len = gid_address_parse (LOC_ADDR(h), &loc->address);
461   if (len == ~0)
462     return len;
463
464   loc->state = status;
465   loc->local = 0;
466   loc->priority = LOC_PRIORITY(h);
467   loc->weight = LOC_WEIGHT(h);
468   loc->mpriority = LOC_MPRIORITY(h);
469   loc->mweight = LOC_MWEIGHT(h);
470
471   return sizeof(locator_hdr_t) + len;
472 }
473
474 void
475 locator_copy (locator_t * dst, locator_t * src)
476 {
477   /* TODO if gid become more complex, this will need to be changed! */
478   clib_memcpy (dst, src, sizeof(*dst));
479 }
480
481 u32
482 locator_cmp (locator_t * l1, locator_t * l2)
483 {
484   u32 ret = 0;
485   if ((ret = gid_address_cmp (&l1->address, &l2->address)) != 0)
486     return 1;
487
488   if (l1->priority != l2->priority)
489     return 1;
490   if (l1->weight != l2->weight)
491     return 1;
492   if (l1->mpriority != l2->mpriority)
493     return 1;
494   if (l1->mweight != l2->mweight)
495     return 1;
496   return 0;
497 }