a04d36ff8d05b9400e473d1a8c020edda8ad0aab
[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     cmp = ip_prefix_len(p1) < ip_prefix_len(p2) ? 1 : 2; /* XXX ? */
317   return cmp;
318 }
319
320 u8
321 gid_address_len (gid_address_t *a)
322 {
323   gid_address_type_t type = gid_address_type (a);
324   return (*addr_len_fcts[type])((*cast_fcts[type])(a));
325 }
326
327 u16
328 gid_address_put (u8 * b, gid_address_t * gid)
329 {
330   gid_address_type_t type = gid_address_type (gid);
331   return (*write_fcts[type])(b, (*cast_fcts[type])(gid));
332 }
333
334 u16
335 gid_address_size_to_put (gid_address_t * gid)
336 {
337   gid_address_type_t type = gid_address_type (gid);
338   return (*size_to_write_fcts[type])((*cast_fcts[type])(gid));
339 }
340
341 void *
342 gid_address_cast (gid_address_t * gid, gid_address_type_t type)
343 {
344   return (*cast_fcts[type])(gid);
345 }
346
347 void
348 gid_address_copy(gid_address_t * dst, gid_address_t * src)
349 {
350   gid_address_type_t type = gid_address_type(src);
351   (*copy_fcts[type])((*cast_fcts[type])(dst), (*cast_fcts[type])(src));
352   gid_address_type(dst) = type;
353 }
354
355 u32
356 gid_address_parse (u8 * offset, gid_address_t *a)
357 {
358   lisp_afi_e afi;
359   int len = 0;
360
361   if (!a)
362     return 0;
363
364   afi = clib_net_to_host_u16 (*((u16 *) offset));
365
366   switch (afi)
367     {
368     case LISP_AFI_NO_ADDR:
369       len = sizeof(u16);
370       gid_address_type(a) = NO_ADDRESS;
371       break;
372     case LISP_AFI_IP:
373       len = ip_address_parse (offset, afi, &gid_address_ip(a));
374       gid_address_type(a) = IP_PREFIX;
375       /* this should be modified outside if needed*/
376       gid_address_ippref_len(a) = 32;
377       break;
378     case LISP_AFI_IP6:
379       len = ip_address_parse (offset, afi, &gid_address_ip(a));
380       gid_address_type(a) = IP_PREFIX;
381       /* this should be modified outside if needed*/
382       gid_address_ippref_len(a) = 128;
383       break;
384     case LISP_AFI_LCAF:
385     default:
386       clib_warning("LISP AFI %d not supported!", afi);
387       return ~0;
388     }
389   return len;
390 }
391
392 /* Compare two gid_address_t.
393  * Returns:
394  *        -1: If they are from different afi
395  *             0: Both address are the same
396  *             1: Addr1 is bigger than addr2
397  *             2: Addr2 is bigger than addr1
398  */
399 int
400 gid_address_cmp (gid_address_t * a1, gid_address_t * a2)
401 {
402   int cmp = -1;
403   if (!a1 || !a2)
404     return -1;
405   if (gid_address_type(a1) != gid_address_type(a2))
406     return -1;
407
408   switch (gid_address_type(a1))
409     {
410     case NO_ADDRESS:
411       if (a1 == a2)
412         cmp = 0;
413       else
414         cmp = 2;
415       break;
416     case IP_PREFIX:
417       cmp = ip_prefix_cmp (&gid_address_ippref(a1), &gid_address_ippref(a2));
418       break;
419     default:
420       break;
421     }
422
423   return cmp;
424 }
425
426
427 u32
428 locator_parse (void * b, locator_t * loc)
429 {
430   locator_hdr_t * h;
431   u8 status = 1; /* locator up */
432   int len;
433
434   h = b;
435   if (!LOC_REACHABLE(h) && LOC_LOCAL(h))
436     status = 0;
437
438   len = gid_address_parse (LOC_ADDR(h), &loc->address);
439   if (len == ~0)
440     return len;
441
442   loc->state = status;
443   loc->local = 0;
444   loc->priority = LOC_PRIORITY(h);
445   loc->weight = LOC_WEIGHT(h);
446   loc->mpriority = LOC_MPRIORITY(h);
447   loc->mweight = LOC_MWEIGHT(h);
448
449   return sizeof(locator_hdr_t) + len;
450 }
451
452 void
453 locator_copy (locator_t * dst, locator_t * src)
454 {
455   /* TODO if gid become more complex, this will need to be changed! */
456   memcpy (dst, src, sizeof(*dst));
457 }
458
459 u32
460 locator_cmp (locator_t * l1, locator_t * l2)
461 {
462   u32 ret = 0;
463   if ((ret = gid_address_cmp (&l1->address, &l2->address)) != 0)
464     return 1;
465
466   if (l1->priority != l2->priority)
467     return 1;
468   if (l1->weight != l2->weight)
469     return 1;
470   if (l1->mpriority != l2->mpriority)
471     return 1;
472   if (l1->mweight != l2->mweight)
473     return 1;
474   return 0;
475 }