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