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