Source VRF Select
[vpp.git] / src / vnet / fib / fib_api.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/vnet.h>
17 #include <vlibmemory/api.h>
18 #include <vnet/fib/fib_api.h>
19 #include <vnet/fib/fib_table.h>
20 #include <vnet/bier/bier_disp_table.h>
21 #include <vnet/dpo/ip_null_dpo.h>
22
23 #include <vnet/vnet_msg_enum.h>
24
25 #define vl_typedefs             /* define message structures */
26 #include <vnet/vnet_all_api_h.h>
27 #undef vl_typedefs
28
29 #define vl_endianfun            /* define message structures */
30 #include <vnet/vnet_all_api_h.h>
31 #undef vl_endianfun
32
33 /* instantiate all the print functions we know about */
34 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
35 #define vl_printfun
36 #include <vnet/vnet_all_api_h.h>
37 #undef vl_printfun
38
39 #include <vlibapi/api_helper_macros.h>
40
41 int
42 fib_path_api_parse (const vl_api_fib_path_t *in,
43                     fib_route_path_t *out)
44 {
45     fib_route_path_flags_t path_flags;
46     mpls_label_t next_hop_via_label;
47     int rv = 0, n_labels;
48     u8 ii;
49
50     path_flags = FIB_ROUTE_PATH_FLAG_NONE;
51     next_hop_via_label = ntohl (in->via_label);
52     memset(out, 0, sizeof(*out));
53     out->frp_sw_if_index = ~0;
54
55     out->frp_proto = in->afi;
56     // .frp_addr = (NULL == next_hop ? zero_addr : *next_hop),
57     out->frp_sw_if_index = ntohl(in->sw_if_index);
58     out->frp_fib_index = ntohl(in->table_id);
59     out->frp_weight = in->weight;
60     out->frp_preference = in->preference;
61
62     /*
63      * the special INVALID label meams we are not recursing via a
64      * label. Exp-null value is never a valid via-label so that
65      * also means it's not a via-label and means clients that set
66      * it to 0 by default get the expected behaviour
67      */
68     if ((MPLS_LABEL_INVALID != next_hop_via_label) &&
69         (0 != next_hop_via_label))
70     {
71         out->frp_proto = DPO_PROTO_MPLS;
72         out->frp_local_label = next_hop_via_label;
73         out->frp_eos = MPLS_NON_EOS;
74     }
75
76     n_labels = in->n_labels;
77     if (n_labels == 0)
78         ;
79     else
80     {
81         vec_validate (out->frp_label_stack, n_labels - 1);
82         for (ii = 0; ii < n_labels; ii++)
83         {
84             out->frp_label_stack[ii].fml_value =
85                 ntohl(in->label_stack[ii].label);
86             out->frp_label_stack[ii].fml_ttl =
87                 in->label_stack[ii].ttl;
88             out->frp_label_stack[ii].fml_exp =
89                 in->label_stack[ii].exp;
90             out->frp_label_stack[ii].fml_mode =
91                 (in->label_stack[ii].is_uniform ?
92                  FIB_MPLS_LSP_MODE_UNIFORM :
93                  FIB_MPLS_LSP_MODE_PIPE);
94         }
95     }
96
97     if (in->is_dvr)
98         path_flags |= FIB_ROUTE_PATH_DVR;
99     if (in->is_resolve_host)
100         path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
101     if (in->is_resolve_attached)
102         path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
103     /* if (in->is_interface_rx) */
104     /*     path_flags |= FIB_ROUTE_PATH_INTF_RX; */
105     /* if (in->is_rpf_id) */
106     /*     path_flags |= FIB_ROUTE_PATH_RPF_ID; */
107     if (in->is_source_lookup)
108         path_flags |= FIB_ROUTE_PATH_SOURCE_LOOKUP;
109
110     if (in->is_udp_encap)
111     {
112         path_flags |= FIB_ROUTE_PATH_UDP_ENCAP;
113         out->frp_udp_encap_id = ntohl(in->next_hop_id);
114     }
115     else
116     {
117         if (DPO_PROTO_IP4 == in->afi)
118         {
119             clib_memcpy (&out->frp_addr.ip4,
120                          in->next_hop,
121                          sizeof (out->frp_addr.ip4));
122         }
123         else if (DPO_PROTO_IP6 == in->afi)
124         {
125             clib_memcpy (&out->frp_addr.ip6,
126                          in->next_hop,
127                          sizeof (out->frp_addr.ip6));
128         }
129
130         if (ip46_address_is_zero(&out->frp_addr))
131         {
132             if (DPO_PROTO_BIER == in->afi)
133             {
134                 index_t bdti;
135
136                 bdti = bier_disp_table_find(ntohl(in->table_id));
137
138                 if (INDEX_INVALID != bdti)
139                 {
140                     out->frp_fib_index = bdti;
141                     out->frp_proto = DPO_PROTO_BIER;
142                 }
143                 else
144                 {
145                     rv = VNET_API_ERROR_NO_SUCH_FIB;
146                 }
147             }
148             else if (out->frp_sw_if_index == ~0 &&
149                      out->frp_fib_index != ~0)
150             {
151                 path_flags |= FIB_ROUTE_PATH_DEAG;
152             }
153         }
154     }
155
156     out->frp_flags = path_flags;
157
158     return (rv);
159 }
160
161 void
162 fib_prefix_to_api (const fib_prefix_t *pfx,
163                    u8 address[16],
164                    u8 *length,
165                    u8 *is_ip6)
166 {
167     *length = pfx->fp_len;
168     *is_ip6 = (FIB_PROTOCOL_IP6 == pfx->fp_proto ? 1 : 0);
169
170     if (FIB_PROTOCOL_IP6 == pfx->fp_proto)
171     {
172         memcpy (address, &pfx->fp_addr.ip6, sizeof (pfx->fp_addr.ip6));
173     }
174     else
175     {
176         memcpy (address, &pfx->fp_addr.ip4, sizeof (pfx->fp_addr.ip4));
177     }
178 }
179
180 static void
181 fib_api_path_copy_next_hop (const fib_route_path_encode_t * api_rpath, void *fp_arg)
182 {
183   int is_ip4;
184   vl_api_fib_path_t *fp = (vl_api_fib_path_t *) fp_arg;
185
186   if (api_rpath->rpath.frp_proto == DPO_PROTO_IP4)
187     fp->afi = IP46_TYPE_IP4;
188   else if (api_rpath->rpath.frp_proto == DPO_PROTO_IP6)
189     fp->afi = IP46_TYPE_IP6;
190   else
191     {
192       is_ip4 = ip46_address_is_ip4 (&api_rpath->rpath.frp_addr);
193       if (is_ip4)
194         fp->afi = IP46_TYPE_IP4;
195       else
196         fp->afi = IP46_TYPE_IP6;
197     }
198   if (fp->afi == IP46_TYPE_IP4)
199     memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip4,
200             sizeof (api_rpath->rpath.frp_addr.ip4));
201   else
202     memcpy (fp->next_hop, &api_rpath->rpath.frp_addr.ip6,
203             sizeof (api_rpath->rpath.frp_addr.ip6));
204 }
205
206 void
207 fib_api_path_encode (const fib_route_path_encode_t * api_rpath,
208                      vl_api_fib_path_t *out)
209 {
210     memset (out, 0, sizeof (*out));
211     switch (api_rpath->dpo.dpoi_type)
212     {
213     case DPO_RECEIVE:
214         out->is_local = true;
215         break;
216     case DPO_DROP:
217         out->is_drop = true;
218         break;
219     case DPO_IP_NULL:
220         switch (ip_null_dpo_get_action(api_rpath->dpo.dpoi_index))
221         {
222         case IP_NULL_ACTION_NONE:
223             out->is_drop = true;
224             break;
225         case IP_NULL_ACTION_SEND_ICMP_UNREACH:
226             out->is_unreach = true;
227             break;
228         case IP_NULL_ACTION_SEND_ICMP_PROHIBIT:
229             out->is_prohibit = true;
230             break;
231         default:
232             break;
233         }
234         break;
235     default:
236         break;
237     }
238     out->weight = api_rpath->rpath.frp_weight;
239     out->preference = api_rpath->rpath.frp_preference;
240     out->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
241     out->afi = api_rpath->rpath.frp_proto;
242     fib_api_path_copy_next_hop (api_rpath, out);
243
244     if (0 != api_rpath->rpath.frp_fib_index)
245     {
246         if ((DPO_PROTO_IP6 == api_rpath->rpath.frp_proto) ||
247             (DPO_PROTO_IP4 == api_rpath->rpath.frp_proto))
248         {
249             fib_table_t *fib;
250
251             fib = fib_table_get (api_rpath->rpath.frp_fib_index,
252                                  dpo_proto_to_fib(api_rpath->rpath.frp_proto));
253
254             out->table_id = htonl (fib->ft_table_id);
255         }
256     }
257
258     if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_DVR)
259     {
260         out->is_dvr = 1;
261     }
262     if (api_rpath->rpath.frp_flags & FIB_ROUTE_PATH_UDP_ENCAP)
263     {
264         out->is_udp_encap = 1;
265         out->next_hop_id = api_rpath->rpath.frp_udp_encap_id;
266     }
267 }
268
269 fib_protocol_t
270 fib_proto_from_api_address_family (int af)
271 {
272     switch (clib_net_to_host_u32 (af))
273     {
274     case ADDRESS_IP4:
275         return (FIB_PROTOCOL_IP4);
276     case ADDRESS_IP6:
277         return (FIB_PROTOCOL_IP6);
278     }
279
280     ASSERT(0);
281     return (FIB_PROTOCOL_IP4);
282 }
283
284 int
285 fib_proto_to_api_address_family (fib_protocol_t fproto)
286 {
287     switch (fproto)
288     {
289     case FIB_PROTOCOL_IP4:
290         return (clib_net_to_host_u32 (ADDRESS_IP4));
291     case FIB_PROTOCOL_IP6:
292         return (clib_net_to_host_u32 (ADDRESS_IP6));
293     default:
294         break;
295     }
296
297     ASSERT(0);
298     return (clib_net_to_host_u32 (ADDRESS_IP4));
299 }