a71f4194a18fbda939efd3068d68a1dcc0d6c8d0
[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 vnet_link_t
343 fib_forw_chain_type_to_link_type (fib_forward_chain_type_t fct)
344 {
345     switch (fct)
346     {
347     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
348     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
349         return (VNET_LINK_IP4);
350     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
351     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
352         return (VNET_LINK_IP6);
353     case FIB_FORW_CHAIN_TYPE_ETHERNET:
354         return (VNET_LINK_ETHERNET);
355     case FIB_FORW_CHAIN_TYPE_NSH:
356         return (VNET_LINK_NSH);
357     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
358     case FIB_FORW_CHAIN_TYPE_BIER:
359         /*
360          * insufficient information to to convert
361          */
362         ASSERT(0);
363         break;
364     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
365         return (VNET_LINK_MPLS);
366     }
367     return (VNET_LINK_IP4);
368 }
369
370 fib_forward_chain_type_t
371 fib_forw_chain_type_from_link_type (vnet_link_t link_type)
372 {
373     switch (link_type)
374     {
375     case VNET_LINK_IP4:
376         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
377     case VNET_LINK_IP6:
378         return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
379     case VNET_LINK_MPLS:
380         return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
381     case VNET_LINK_ETHERNET:
382         return (FIB_FORW_CHAIN_TYPE_ETHERNET);
383     case VNET_LINK_NSH:
384         return (FIB_FORW_CHAIN_TYPE_NSH);
385     case VNET_LINK_ARP:
386         break;
387     }
388
389     ASSERT(0);
390     return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
391 }
392
393 dpo_proto_t
394 fib_forw_chain_type_to_dpo_proto (fib_forward_chain_type_t fct)
395 {
396     switch (fct)
397     {
398     case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
399     case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
400         return (DPO_PROTO_IP4);
401     case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
402     case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
403         return (DPO_PROTO_IP6);
404     case FIB_FORW_CHAIN_TYPE_ETHERNET:
405         return (DPO_PROTO_ETHERNET);
406     case FIB_FORW_CHAIN_TYPE_NSH:
407         return (DPO_PROTO_NSH);
408     case FIB_FORW_CHAIN_TYPE_BIER:
409         return (DPO_PROTO_BIER);
410     case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
411     case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
412         return (DPO_PROTO_MPLS);
413     }
414     return (DPO_PROTO_IP4);
415 }
416
417 uword
418 unformat_fib_route_path (unformat_input_t * input, va_list * args)
419 {
420     fib_route_path_t *rpath = va_arg (*args, fib_route_path_t *);
421     u32 *payload_proto = va_arg (*args, u32*);
422     u32 weight, preference, udp_encap_id, fi;
423     mpls_label_t out_label;
424     vnet_main_t *vnm;
425
426     vnm = vnet_get_main ();
427     memset(rpath, 0, sizeof(*rpath));
428     rpath->frp_weight = 1;
429     rpath->frp_sw_if_index = ~0;
430
431     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
432     {
433         if (unformat (input, "%U %U",
434                       unformat_ip4_address,
435                       &rpath->frp_addr.ip4,
436                       unformat_vnet_sw_interface, vnm,
437                       &rpath->frp_sw_if_index))
438         {
439             rpath->frp_proto = DPO_PROTO_IP4;
440         }
441         else if (unformat (input, "%U %U",
442                            unformat_ip6_address,
443                            &rpath->frp_addr.ip6,
444                            unformat_vnet_sw_interface, vnm,
445                            &rpath->frp_sw_if_index))
446         {
447             rpath->frp_proto = DPO_PROTO_IP6;
448         }
449         else if (unformat (input, "weight %u", &weight))
450         {
451             rpath->frp_weight = weight;
452         }
453         else if (unformat (input, "preference %u", &preference))
454         {
455             rpath->frp_preference = preference;
456         }
457         else if (unformat (input, "%U next-hop-table %d",
458                            unformat_ip4_address,
459                            &rpath->frp_addr.ip4,
460                            &rpath->frp_fib_index))
461         {
462             rpath->frp_sw_if_index = ~0;
463             rpath->frp_proto = DPO_PROTO_IP4;
464
465             /*
466              * the user enter table-ids, convert to index
467              */
468             fi = fib_table_find (FIB_PROTOCOL_IP4, rpath->frp_fib_index);
469             if (~0 == fi)
470                 return 0;
471             rpath->frp_fib_index = fi;
472         }
473         else if (unformat (input, "%U next-hop-table %d",
474                            unformat_ip6_address,
475                            &rpath->frp_addr.ip6,
476                            &rpath->frp_fib_index))
477         {
478             rpath->frp_sw_if_index = ~0;
479             rpath->frp_proto = DPO_PROTO_IP6;
480             fi = fib_table_find (FIB_PROTOCOL_IP6, rpath->frp_fib_index);
481             if (~0 == fi)
482                 return 0;
483             rpath->frp_fib_index = fi;
484         }
485         else if (unformat (input, "%U",
486                            unformat_ip4_address,
487                            &rpath->frp_addr.ip4))
488         {
489             /*
490              * the recursive next-hops are by default in the default table
491              */
492             rpath->frp_fib_index = 0;
493             rpath->frp_sw_if_index = ~0;
494             rpath->frp_proto = DPO_PROTO_IP4;
495         }
496         else if (unformat (input, "%U",
497                            unformat_ip6_address,
498                            &rpath->frp_addr.ip6))
499         {
500             rpath->frp_fib_index = 0;
501             rpath->frp_sw_if_index = ~0;
502             rpath->frp_proto = DPO_PROTO_IP6;
503         }
504         else if (unformat (input, "udp-encap %d", &udp_encap_id))
505         {
506             rpath->frp_udp_encap_id = udp_encap_id;
507             rpath->frp_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
508             rpath->frp_proto = *payload_proto;
509         }
510         else if (unformat (input, "lookup in table %d", &rpath->frp_fib_index))
511         {
512             rpath->frp_proto = *payload_proto;
513             rpath->frp_sw_if_index = ~0;
514             rpath->frp_flags |= FIB_ROUTE_PATH_DEAG;
515         }
516         else if (unformat (input, "resolve-via-host"))
517         {
518             rpath->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
519         }
520         else if (unformat (input, "resolve-via-attached"))
521         {
522             rpath->frp_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
523         }
524         else if (unformat (input,
525                            "ip4-lookup-in-table %d",
526                            &rpath->frp_fib_index))
527         {
528             rpath->frp_proto = DPO_PROTO_IP4;
529             *payload_proto = DPO_PROTO_IP4;
530             fi = fib_table_find (FIB_PROTOCOL_IP4, rpath->frp_fib_index);
531             if (~0 == fi)
532                 return 0;
533             rpath->frp_fib_index = fi;
534         }
535         else if (unformat (input,
536                            "ip6-lookup-in-table %d",
537                            &rpath->frp_fib_index))
538         {
539             rpath->frp_proto = DPO_PROTO_IP6;
540             *payload_proto = DPO_PROTO_IP6;
541             fi = fib_table_find (FIB_PROTOCOL_IP6, rpath->frp_fib_index);
542             if (~0 == fi)
543                 return 0;
544             rpath->frp_fib_index = fi;
545         }
546         else if (unformat (input,
547                            "mpls-lookup-in-table %d",
548                            &rpath->frp_fib_index))
549         {
550             rpath->frp_proto = DPO_PROTO_MPLS;
551             *payload_proto = DPO_PROTO_MPLS;
552             fi = fib_table_find (FIB_PROTOCOL_MPLS, rpath->frp_fib_index);
553             if (~0 == fi)
554                 return 0;
555             rpath->frp_fib_index = fi;
556         }
557         else if (unformat (input, "src-lookup"))
558         {
559             rpath->frp_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
560         }
561         else if (unformat (input,
562                            "l2-input-on %U",
563                            unformat_vnet_sw_interface, vnm,
564                            &rpath->frp_sw_if_index))
565         {
566             rpath->frp_proto = DPO_PROTO_ETHERNET;
567             *payload_proto = DPO_PROTO_ETHERNET;
568             rpath->frp_flags |= FIB_ROUTE_PATH_INTF_RX;
569         }
570         else if (unformat (input, "via-label %U",
571                            unformat_mpls_unicast_label,
572                            &rpath->frp_local_label))
573         {
574             rpath->frp_eos = MPLS_NON_EOS;
575             rpath->frp_proto = DPO_PROTO_MPLS;
576             rpath->frp_sw_if_index = ~0;
577         }
578         else if (unformat (input, "rx-ip4 %U",
579                            unformat_vnet_sw_interface, vnm,
580                            &rpath->frp_sw_if_index))
581         {
582             rpath->frp_proto = DPO_PROTO_IP4;
583             rpath->frp_flags = FIB_ROUTE_PATH_INTF_RX;
584         }
585         else if (unformat (input, "out-labels"))
586         {
587             while (unformat (input, "%U",
588                              unformat_mpls_unicast_label, &out_label))
589             {
590                 fib_mpls_label_t fml = {
591                     .fml_value = out_label,
592                 };
593                 vec_add1(rpath->frp_label_stack, fml);
594             }
595         }
596         else if (unformat (input, "%U",
597                            unformat_vnet_sw_interface, vnm,
598                            &rpath->frp_sw_if_index))
599         {
600             rpath->frp_proto = *payload_proto;
601         }
602         else
603         {
604             return (0);
605         }
606     }
607
608     return (1);
609 }