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