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