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