dcb1c3a659c43f059ccb017682bc828f25fd1a82
[vpp.git] / src / vnet / fib / fib_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.h>
17
18 #include <vnet/fib/fib_types.h>
19 #include <vnet/fib/fib_internal.h>
20 #include <vnet/fib/fib_table.h>
21 #include <vnet/mfib/mfib_types.h>
22 #include <vnet/mpls/mpls.h>
23
24 /*
25  * arrays of protocol and link names
26  */
27 static const char* fib_protocol_names[] = FIB_PROTOCOLS;
28 static const char* vnet_link_names[] = VNET_LINKS;
29 static const char* fib_forw_chain_names[] = FIB_FORW_CHAINS;
30 static const char* fib_mpls_lsp_mode_names[] = FIB_MPLS_LSP_MODES;
31
32 u8 *
33 format_fib_protocol (u8 * s, va_list * ap)
34 {
35     fib_protocol_t proto = va_arg(*ap, int); // fib_protocol_t promotion
36
37     return (format (s, "%s", fib_protocol_names[proto]));
38 }
39
40 u8 *
41 format_vnet_link (u8 * s, va_list * ap)
42 {
43     vnet_link_t link = va_arg(*ap, int); // vnet_link_t promotion
44
45     return (format (s, "%s", vnet_link_names[link]));
46 }
47
48 u8 *
49 format_fib_forw_chain_type (u8 * s, va_list * args)
50 {
51     fib_forward_chain_type_t fct = va_arg(*args, int);
52
53     return (format (s, "%s", fib_forw_chain_names[fct]));
54 }
55
56 u8 *
57 format_fib_mpls_lsp_mode(u8 *s, va_list *ap)
58 {
59     fib_mpls_lsp_mode_t mode = va_arg(*ap, int);
60
61     return (format (s, "%s", fib_mpls_lsp_mode_names[mode])); 
62 }
63
64 u8 *
65 format_fib_mpls_label (u8 *s, va_list *ap)
66 {
67     fib_mpls_label_t *label = va_arg(*ap, fib_mpls_label_t *);
68
69     s = format(s, "%U %U ttl:%d exp:%d",
70                format_mpls_unicast_label,
71                label->fml_value,
72                format_fib_mpls_lsp_mode,
73                label->fml_mode,
74                label->fml_ttl,
75                label->fml_exp);
76
77     return (s);
78 }
79
80 void
81 fib_prefix_from_ip46_addr (const ip46_address_t *addr,
82                            fib_prefix_t *pfx)
83 {
84     ASSERT(!ip46_address_is_zero(addr));
85
86     pfx->fp_proto = ((ip46_address_is_ip4(addr) ?
87                       FIB_PROTOCOL_IP4 :
88                       FIB_PROTOCOL_IP6));
89     pfx->fp_len = ((ip46_address_is_ip4(addr) ?
90                     32 : 128));
91     pfx->fp_addr = *addr;
92     pfx->___fp___pad = 0;
93 }
94
95 void
96 fib_prefix_from_mpls_label (mpls_label_t label,
97                             mpls_eos_bit_t eos,
98                             fib_prefix_t *pfx)
99 {
100     pfx->fp_proto = FIB_PROTOCOL_MPLS;
101     pfx->fp_len = 21;
102     pfx->fp_label = label;
103     pfx->fp_eos = eos;
104     pfx->___fp___pad = 0;
105 }
106
107 void
108 fib_prefix_copy (fib_prefix_t *dst,
109                  const fib_prefix_t *src)
110 {
111     clib_memcpy(dst, src, sizeof(*dst));
112 }
113
114 int
115 fib_prefix_cmp (const fib_prefix_t *p1,
116                 const fib_prefix_t *p2)
117 {
118     int res;
119
120     res = (p1->fp_proto - p2->fp_proto);
121
122     if (0 == res)
123     {
124         switch (p1->fp_proto)
125         {
126         case FIB_PROTOCOL_IP4:
127         case FIB_PROTOCOL_IP6:
128             res = (p1->fp_len - p2->fp_len);
129
130             if (0 == res)
131             {
132                 res = ip46_address_cmp(&p1->fp_addr, &p2->fp_addr);
133             }
134             break;
135         case FIB_PROTOCOL_MPLS:
136             res = (p1->fp_label - p2->fp_label);
137
138             if (0 == res)
139             {
140                 res = (p1->fp_eos - p2->fp_eos);
141             }
142             break;
143         }
144     }
145
146     return (res);
147 }
148
149 int
150 fib_prefix_is_cover (const fib_prefix_t *p1,
151                      const fib_prefix_t *p2)
152 {
153     switch (p1->fp_proto)
154     {
155     case FIB_PROTOCOL_IP4:
156         return (ip4_destination_matches_route(&ip4_main,
157                                               &p1->fp_addr.ip4,
158                                               &p2->fp_addr.ip4,
159                                               p1->fp_len));
160     case FIB_PROTOCOL_IP6:
161         return (ip6_destination_matches_route(&ip6_main,
162                                               &p1->fp_addr.ip6,
163                                               &p2->fp_addr.ip6,
164                                               p1->fp_len));
165     case FIB_PROTOCOL_MPLS:
166         break;
167     }
168     return (0);
169 }
170
171 u8
172 fib_prefix_get_host_length (fib_protocol_t proto)
173 {
174     switch (proto)
175     {
176     case FIB_PROTOCOL_IP4:
177         return (32);
178     case FIB_PROTOCOL_IP6:
179         return (128);
180     case FIB_PROTOCOL_MPLS:
181         return (21);
182     }
183     return (0);
184 }
185
186 int
187 fib_prefix_is_host (const fib_prefix_t *prefix)
188 {
189     switch (prefix->fp_proto)
190     {
191     case FIB_PROTOCOL_IP4:
192         return (prefix->fp_len == 32);
193     case FIB_PROTOCOL_IP6:
194         return (prefix->fp_len == 128);
195     case FIB_PROTOCOL_MPLS:
196         return (!0);
197     }
198     return (0);
199 }
200
201 u8 *
202 format_fib_prefix (u8 * s, va_list * args)
203 {
204     fib_prefix_t *fp = va_arg (*args, fib_prefix_t *);
205
206     /*
207      * protocol specific so it prints ::/0 correctly.
208      */
209     switch (fp->fp_proto)
210     {
211     case FIB_PROTOCOL_IP6:
212     {
213         ip6_address_t p6 = fp->fp_addr.ip6;
214
215         ip6_address_mask(&p6, &(ip6_main.fib_masks[fp->fp_len]));
216         s = format (s, "%U", format_ip6_address, &p6);
217         break;
218     }
219     case FIB_PROTOCOL_IP4:
220     {
221         ip4_address_t p4 = fp->fp_addr.ip4;
222         p4.as_u32 &= ip4_main.fib_masks[fp->fp_len];
223
224         s = format (s, "%U", format_ip4_address, &p4);
225         break;
226     }
227     case FIB_PROTOCOL_MPLS:
228         s = format (s, "%U:%U",
229                     format_mpls_unicast_label, fp->fp_label,
230                     format_mpls_eos_bit, fp->fp_eos);
231         break;
232     }
233     s = format (s, "/%d", fp->fp_len);
234
235     return (s);
236 }
237
238 int
239 fib_route_path_cmp (const fib_route_path_t *rpath1,
240                     const fib_route_path_t *rpath2)
241 {
242     int res;
243
244     res = ip46_address_cmp(&rpath1->frp_addr,
245                            &rpath2->frp_addr);
246
247     if (0 != res) return (res);
248
249     res = (rpath1->frp_sw_if_index - rpath2->frp_sw_if_index);
250
251     if (0 != res) return (res);
252
253     if (ip46_address_is_zero(&rpath1->frp_addr))
254     {
255         res = rpath1->frp_fib_index - rpath2->frp_fib_index;
256     }
257
258     return (res);
259 }
260
261 dpo_proto_t
262 fib_proto_to_dpo (fib_protocol_t fib_proto)
263 {
264     switch (fib_proto)
265     {
266     case FIB_PROTOCOL_IP6:
267         return (DPO_PROTO_IP6);
268     case FIB_PROTOCOL_IP4:
269         return (DPO_PROTO_IP4);
270     case FIB_PROTOCOL_MPLS:
271         return (DPO_PROTO_MPLS);
272     }
273     ASSERT(0);
274     return (0);
275 }
276
277 fib_protocol_t
278 dpo_proto_to_fib (dpo_proto_t dpo_proto)
279 {
280     switch (dpo_proto)
281     {
282     case DPO_PROTO_IP6:
283         return (FIB_PROTOCOL_IP6);
284     case DPO_PROTO_IP4:
285         return (FIB_PROTOCOL_IP4);
286     case DPO_PROTO_MPLS:
287         return (FIB_PROTOCOL_MPLS);
288     default:
289         break;
290     }
291     ASSERT(0);
292     return (0);
293 }
294
295 vnet_link_t
296 fib_proto_to_link (fib_protocol_t proto)
297 {
298     switch (proto)
299     {
300     case FIB_PROTOCOL_IP4:
301         return (VNET_LINK_IP4);
302     case FIB_PROTOCOL_IP6:
303         return (VNET_LINK_IP6);
304     case FIB_PROTOCOL_MPLS:
305         return (VNET_LINK_MPLS);
306     }
307     ASSERT(0);
308     return (0);
309 }
310
311 ip46_type_t
312 fib_proto_to_ip46 (fib_protocol_t fproto)
313 {
314     switch (fproto)
315     {
316     case FIB_PROTOCOL_IP4:
317         return (IP46_TYPE_IP4);
318     case FIB_PROTOCOL_IP6:
319         return (IP46_TYPE_IP6);
320     case FIB_PROTOCOL_MPLS:
321         return (IP46_TYPE_ANY);
322     }
323     ASSERT(0);
324     return (IP46_TYPE_ANY);
325 }
326
327 fib_protocol_t
328 fib_proto_from_ip46 (ip46_type_t iproto)
329 {
330     switch (iproto)
331     {
332     case IP46_TYPE_IP4:
333         return FIB_PROTOCOL_IP4;
334     case IP46_TYPE_IP6:
335         return FIB_PROTOCOL_IP6;
336     case IP46_TYPE_ANY:
337         ASSERT(0);
338         return FIB_PROTOCOL_IP4;
339     }
340
341     ASSERT(0);
342     return FIB_PROTOCOL_IP4;
343 }
344
345 fib_forward_chain_type_t
346 fib_forw_chain_type_from_dpo_proto (dpo_proto_t proto)
347 {
348     switch (proto)
349     {
350     case DPO_PROTO_IP4:
351         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
352     case DPO_PROTO_IP6:
353         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
354     case DPO_PROTO_MPLS:
355         return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
356     case DPO_PROTO_ETHERNET:
357         return (FIB_FORW_CHAIN_TYPE_ETHERNET);
358     case DPO_PROTO_NSH:
359         return (FIB_FORW_CHAIN_TYPE_NSH);
360     case DPO_PROTO_BIER:
361         return (FIB_FORW_CHAIN_TYPE_BIER);
362     }
363     ASSERT(0);
364     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
365 }
366
367 fib_forward_chain_type_t
368 fib_forw_chain_type_from_fib_proto (fib_protocol_t proto)
369 {
370     switch (proto)
371     {
372     case FIB_PROTOCOL_IP4:
373         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
374     case FIB_PROTOCOL_IP6:
375         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
376     case FIB_PROTOCOL_MPLS:
377         return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
378     }
379     ASSERT(0);
380     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
381 }
382
383 vnet_link_t
384 fib_forw_chain_type_to_link_type (fib_forward_chain_type_t fct)
385 {
386     switch (fct)
387     {
388     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
389     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
390         return (VNET_LINK_IP4);
391     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
392     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
393         return (VNET_LINK_IP6);
394     case FIB_FORW_CHAIN_TYPE_ETHERNET:
395         return (VNET_LINK_ETHERNET);
396     case FIB_FORW_CHAIN_TYPE_NSH:
397         return (VNET_LINK_NSH);
398     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
399     case FIB_FORW_CHAIN_TYPE_BIER:
400         /*
401          * insufficient information to to convert
402          */
403         ASSERT(0);
404         break;
405     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
406         return (VNET_LINK_MPLS);
407     }
408     return (VNET_LINK_IP4);
409 }
410
411 fib_forward_chain_type_t
412 fib_forw_chain_type_from_link_type (vnet_link_t link_type)
413 {
414     switch (link_type)
415     {
416     case VNET_LINK_IP4:
417         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
418     case VNET_LINK_IP6:
419         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
420     case VNET_LINK_MPLS:
421         return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
422     case VNET_LINK_ETHERNET:
423         return (FIB_FORW_CHAIN_TYPE_ETHERNET);
424     case VNET_LINK_NSH:
425         return (FIB_FORW_CHAIN_TYPE_NSH);
426     case VNET_LINK_ARP:
427         break;
428     }
429
430     ASSERT(0);
431     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
432 }
433
434 dpo_proto_t
435 fib_forw_chain_type_to_dpo_proto (fib_forward_chain_type_t fct)
436 {
437     switch (fct)
438     {
439     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
440     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
441         return (DPO_PROTO_IP4);
442     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
443     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
444         return (DPO_PROTO_IP6);
445     case FIB_FORW_CHAIN_TYPE_ETHERNET:
446         return (DPO_PROTO_ETHERNET);
447     case FIB_FORW_CHAIN_TYPE_NSH:
448         return (DPO_PROTO_NSH);
449     case FIB_FORW_CHAIN_TYPE_BIER:
450         return (DPO_PROTO_BIER);
451     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
452     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
453         return (DPO_PROTO_MPLS);
454     }
455     return (DPO_PROTO_IP4);
456 }
457
458 uword
459 unformat_fib_route_path (unformat_input_t * input, va_list * args)
460 {
461     fib_route_path_t *rpath = va_arg (*args, fib_route_path_t *);
462     dpo_proto_t *payload_proto = va_arg (*args, void*);
463     u32 weight, preference, udp_encap_id, fi;
464     mpls_label_t out_label;
465     vnet_main_t *vnm;
466
467     vnm = vnet_get_main ();
468     clib_memset(rpath, 0, sizeof(*rpath));
469     rpath->frp_weight = 1;
470     rpath->frp_sw_if_index = ~0;
471
472     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
473     {
474         if (unformat (input, "%U %U",
475                       unformat_ip4_address,
476                       &rpath->frp_addr.ip4,
477                       unformat_vnet_sw_interface, vnm,
478                       &rpath->frp_sw_if_index))
479         {
480             rpath->frp_proto = DPO_PROTO_IP4;
481         }
482         else if (unformat (input, "%U %U",
483                            unformat_ip6_address,
484                            &rpath->frp_addr.ip6,
485                            unformat_vnet_sw_interface, vnm,
486                            &rpath->frp_sw_if_index))
487         {
488             rpath->frp_proto = DPO_PROTO_IP6;
489         }
490         else if (unformat (input, "weight %u", &weight))
491         {
492             rpath->frp_weight = weight;
493         }
494         else if (unformat (input, "preference %u", &preference))
495         {
496             rpath->frp_preference = preference;
497         }
498         else if (unformat (input, "%U next-hop-table %d",
499                            unformat_ip4_address,
500                            &rpath->frp_addr.ip4,
501                            &rpath->frp_fib_index))
502         {
503             rpath->frp_sw_if_index = ~0;
504             rpath->frp_proto = DPO_PROTO_IP4;
505
506             /*
507              * the user enter table-ids, convert to index
508              */
509             fi = fib_table_find (FIB_PROTOCOL_IP4, rpath->frp_fib_index);
510             if (~0 == fi)
511                 return 0;
512             rpath->frp_fib_index = fi;
513         }
514         else if (unformat (input, "%U next-hop-table %d",
515                            unformat_ip6_address,
516                            &rpath->frp_addr.ip6,
517                            &rpath->frp_fib_index))
518         {
519             rpath->frp_sw_if_index = ~0;
520             rpath->frp_proto = DPO_PROTO_IP6;
521             fi = fib_table_find (FIB_PROTOCOL_IP6, rpath->frp_fib_index);
522             if (~0 == fi)
523                 return 0;
524             rpath->frp_fib_index = fi;
525         }
526         else if (unformat (input, "%U",
527                            unformat_ip4_address,
528                            &rpath->frp_addr.ip4))
529         {
530             /*
531              * the recursive next-hops are by default in the default table
532              */
533             rpath->frp_fib_index = 0;
534             rpath->frp_sw_if_index = ~0;
535             rpath->frp_proto = DPO_PROTO_IP4;
536         }
537         else if (unformat (input, "%U",
538                            unformat_ip6_address,
539                            &rpath->frp_addr.ip6))
540         {
541             rpath->frp_fib_index = 0;
542             rpath->frp_sw_if_index = ~0;
543             rpath->frp_proto = DPO_PROTO_IP6;
544         }
545         else if (unformat (input, "udp-encap %d", &udp_encap_id))
546         {
547             rpath->frp_udp_encap_id = udp_encap_id;
548             rpath->frp_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
549             rpath->frp_proto = *payload_proto;
550         }
551         else if (unformat (input, "lookup in table %d", &rpath->frp_fib_index))
552         {
553             rpath->frp_proto = *payload_proto;
554             rpath->frp_sw_if_index = ~0;
555             rpath->frp_flags |= FIB_ROUTE_PATH_DEAG;
556         }
557         else if (unformat (input, "resolve-via-host"))
558         {
559             rpath->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
560         }
561         else if (unformat (input, "resolve-via-attached"))
562         {
563             rpath->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
564         }
565         else if (unformat (input, "pop-pw-cw"))
566         {
567             rpath->frp_flags |= FIB_ROUTE_PATH_POP_PW_CW;
568         }
569         else if (unformat (input,
570                            "ip4-lookup-in-table %d",
571                            &rpath->frp_fib_index))
572         {
573             rpath->frp_proto = DPO_PROTO_IP4;
574             *payload_proto = DPO_PROTO_IP4;
575             fi = fib_table_find (FIB_PROTOCOL_IP4, rpath->frp_fib_index);
576             if (~0 == fi)
577                 return 0;
578             rpath->frp_fib_index = fi;
579         }
580         else if (unformat (input,
581                            "ip6-lookup-in-table %d",
582                            &rpath->frp_fib_index))
583         {
584             rpath->frp_proto = DPO_PROTO_IP6;
585             *payload_proto = DPO_PROTO_IP6;
586             fi = fib_table_find (FIB_PROTOCOL_IP6, rpath->frp_fib_index);
587             if (~0 == fi)
588                 return 0;
589             rpath->frp_fib_index = fi;
590         }
591         else if (unformat (input,
592                            "mpls-lookup-in-table %d",
593                            &rpath->frp_fib_index))
594         {
595             rpath->frp_proto = DPO_PROTO_MPLS;
596             *payload_proto = DPO_PROTO_MPLS;
597             fi = fib_table_find (FIB_PROTOCOL_MPLS, rpath->frp_fib_index);
598             if (~0 == fi)
599                 return 0;
600             rpath->frp_fib_index = fi;
601         }
602         else if (unformat (input, "src-lookup"))
603         {
604             rpath->frp_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
605         }
606         else if (unformat (input,
607                            "l2-input-on %U",
608                            unformat_vnet_sw_interface, vnm,
609                            &rpath->frp_sw_if_index))
610         {
611             rpath->frp_proto = DPO_PROTO_ETHERNET;
612             *payload_proto = DPO_PROTO_ETHERNET;
613             rpath->frp_flags |= FIB_ROUTE_PATH_INTF_RX;
614         }
615         else if (unformat (input, "via-label %U",
616                            unformat_mpls_unicast_label,
617                            &rpath->frp_local_label))
618         {
619             rpath->frp_eos = MPLS_NON_EOS;
620             rpath->frp_proto = DPO_PROTO_MPLS;
621             rpath->frp_sw_if_index = ~0;
622         }
623         else if (unformat (input, "rx-ip4 %U",
624                            unformat_vnet_sw_interface, vnm,
625                            &rpath->frp_sw_if_index))
626         {
627             rpath->frp_proto = DPO_PROTO_IP4;
628             rpath->frp_flags = FIB_ROUTE_PATH_INTF_RX;
629         }
630       else if (unformat (input, "local"))
631         {
632           clib_memset (&rpath->frp_addr, 0, sizeof (rpath->frp_addr));
633           rpath->frp_sw_if_index = ~0;
634           rpath->frp_weight = 1;
635           rpath->frp_flags |= FIB_ROUTE_PATH_LOCAL;
636         }
637       else if (unformat (input, "%U",
638                          unformat_mfib_itf_flags, &rpath->frp_mitf_flags))
639         ;
640       else if (unformat (input, "out-labels"))
641         {
642             while (unformat (input, "%U",
643                              unformat_mpls_unicast_label, &out_label))
644             {
645                 fib_mpls_label_t fml = {
646                     .fml_value = out_label,
647                 };
648                 vec_add1(rpath->frp_label_stack, fml);
649             }
650         }
651         else if (unformat (input, "%U",
652                            unformat_vnet_sw_interface, vnm,
653                            &rpath->frp_sw_if_index))
654         {
655             rpath->frp_proto = *payload_proto;
656         }
657         else if (unformat (input, "via"))
658         {
659             /* new path, back up and return */
660             unformat_put_input (input);
661             unformat_put_input (input);
662             unformat_put_input (input);
663             unformat_put_input (input);
664             break;
665         }
666         else
667         {
668             return (0);
669         }
670     }
671
672     return (1);
673 }