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