ip: add the missing offload check
[vpp.git] / src / vnet / vxlan / vxlan_api.c
1 /*
2  *------------------------------------------------------------------
3  * vxlan_api.c - vxlan api
4  *
5  * Copyright (c) 2016 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vnet/vnet.h>
21 #include <vlibmemory/api.h>
22
23 #include <vnet/interface.h>
24 #include <vnet/api_errno.h>
25 #include <vnet/feature/feature.h>
26 #include <vnet/vxlan/vxlan.h>
27 #include <vnet/fib/fib_table.h>
28 #include <vnet/ip/ip_types_api.h>
29 #include <vnet/udp/udp_local.h>
30 #include <vnet/format_fns.h>
31 #include <vxlan/vxlan.api_enum.h>
32 #include <vxlan/vxlan.api_types.h>
33
34 static u16 msg_id_base;
35
36 #define REPLY_MSG_ID_BASE msg_id_base
37 #include <vlibapi/api_helper_macros.h>
38
39 static void
40 vl_api_vxlan_offload_rx_t_handler (vl_api_vxlan_offload_rx_t * mp)
41 {
42   vl_api_vxlan_offload_rx_reply_t *rmp;
43   int rv = 0;
44   u32 hw_if_index = ntohl (mp->hw_if_index);
45   u32 sw_if_index = ntohl (mp->sw_if_index);
46
47   if (!vnet_hw_interface_is_valid (vnet_get_main (), hw_if_index))
48     {
49       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
50       goto err;
51     }
52   VALIDATE_SW_IF_INDEX (mp);
53
54   u32 t_index = vnet_vxlan_get_tunnel_index (sw_if_index);
55   if (t_index == ~0)
56     {
57       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
58       goto err;
59     }
60
61   vxlan_main_t *vxm = &vxlan_main;
62   vxlan_tunnel_t *t = pool_elt_at_index (vxm->tunnels, t_index);
63   if (!ip46_address_is_ip4 (&t->dst))
64     {
65       rv = VNET_API_ERROR_INVALID_ADDRESS_FAMILY;
66       goto err;
67     }
68
69   vnet_main_t *vnm = vnet_get_main ();
70   vnet_hw_interface_t *hw_if = vnet_get_hw_interface (vnm, hw_if_index);
71   ip4_main_t *im = &ip4_main;
72   u32 rx_fib_index =
73     vec_elt (im->fib_index_by_sw_if_index, hw_if->sw_if_index);
74
75   if (t->encap_fib_index != rx_fib_index)
76     {
77       rv = VNET_API_ERROR_NO_SUCH_FIB;
78       goto err;
79     }
80
81   if (vnet_vxlan_add_del_rx_flow (hw_if_index, t_index, mp->enable))
82     {
83       rv = VNET_API_ERROR_UNSPECIFIED;
84       goto err;
85     }
86   BAD_SW_IF_INDEX_LABEL;
87 err:
88
89   REPLY_MACRO (VL_API_VXLAN_OFFLOAD_RX_REPLY);
90 }
91
92 static void
93   vl_api_sw_interface_set_vxlan_bypass_t_handler
94   (vl_api_sw_interface_set_vxlan_bypass_t * mp)
95 {
96   vl_api_sw_interface_set_vxlan_bypass_reply_t *rmp;
97   int rv = 0;
98   u32 sw_if_index = ntohl (mp->sw_if_index);
99
100   VALIDATE_SW_IF_INDEX (mp);
101
102   vnet_int_vxlan_bypass_mode (sw_if_index, mp->is_ipv6, mp->enable);
103   BAD_SW_IF_INDEX_LABEL;
104
105   REPLY_MACRO (VL_API_SW_INTERFACE_SET_VXLAN_BYPASS_REPLY);
106 }
107
108 static int
109 vxlan_add_del_tunnel_clean_input (vnet_vxlan_add_del_tunnel_args_t *a,
110                                   u32 encap_vrf_id)
111 {
112   a->is_ip6 = !ip46_address_is_ip4 (&a->src);
113
114   a->encap_fib_index = fib_table_find (fib_ip_proto (a->is_ip6), encap_vrf_id);
115   if (a->encap_fib_index == ~0)
116     {
117       return VNET_API_ERROR_NO_SUCH_FIB;
118     }
119
120   if (ip46_address_is_ip4 (&a->src) != ip46_address_is_ip4 (&a->dst))
121     {
122       return VNET_API_ERROR_INVALID_VALUE;
123     }
124
125   /* Check src & dst are different */
126   if (ip46_address_cmp (&a->dst, &a->src) == 0)
127     {
128       return VNET_API_ERROR_SAME_SRC_DST;
129     }
130   if (ip46_address_is_multicast (&a->dst) &&
131       !vnet_sw_if_index_is_api_valid (a->mcast_sw_if_index))
132     {
133       return VNET_API_ERROR_INVALID_SW_IF_INDEX;
134     }
135   return 0;
136 }
137
138 static void
139 vl_api_vxlan_add_del_tunnel_t_handler (vl_api_vxlan_add_del_tunnel_t *mp)
140 {
141   vl_api_vxlan_add_del_tunnel_reply_t *rmp;
142   u32 sw_if_index = ~0;
143   int rv = 0;
144
145   vnet_vxlan_add_del_tunnel_args_t a = {
146     .is_add = mp->is_add,
147     .instance = ntohl (mp->instance),
148     .mcast_sw_if_index = ntohl (mp->mcast_sw_if_index),
149     .decap_next_index = ntohl (mp->decap_next_index),
150     .vni = ntohl (mp->vni),
151   };
152   ip_address_decode (&mp->src_address, &a.src);
153   ip_address_decode (&mp->dst_address, &a.dst);
154
155   rv = vxlan_add_del_tunnel_clean_input (&a, ntohl (mp->encap_vrf_id));
156   if (rv)
157     goto out;
158   a.dst_port = a.is_ip6 ? UDP_DST_PORT_vxlan6 : UDP_DST_PORT_vxlan,
159   a.src_port = a.is_ip6 ? UDP_DST_PORT_vxlan6 : UDP_DST_PORT_vxlan,
160   rv = vnet_vxlan_add_del_tunnel (&a, &sw_if_index);
161
162 out:
163   REPLY_MACRO2(VL_API_VXLAN_ADD_DEL_TUNNEL_REPLY,
164   ({
165     rmp->sw_if_index = ntohl (sw_if_index);
166   }));
167 }
168
169 static void
170 vl_api_vxlan_add_del_tunnel_v2_t_handler (vl_api_vxlan_add_del_tunnel_v2_t *mp)
171 {
172   vl_api_vxlan_add_del_tunnel_v2_reply_t *rmp;
173   u32 sw_if_index = ~0;
174   int rv = 0;
175
176   vnet_vxlan_add_del_tunnel_args_t a = {
177     .is_add = mp->is_add,
178     .instance = ntohl (mp->instance),
179     .mcast_sw_if_index = ntohl (mp->mcast_sw_if_index),
180     .decap_next_index = ntohl (mp->decap_next_index),
181     .vni = ntohl (mp->vni),
182     .dst_port = ntohs (mp->dst_port),
183     .src_port = ntohs (mp->src_port),
184   };
185
186   ip_address_decode (&mp->src_address, &a.src);
187   ip_address_decode (&mp->dst_address, &a.dst);
188
189   rv = vxlan_add_del_tunnel_clean_input (&a, ntohl (mp->encap_vrf_id));
190   if (rv)
191     goto out;
192   rv = vnet_vxlan_add_del_tunnel (&a, &sw_if_index);
193 out:
194   REPLY_MACRO2 (VL_API_VXLAN_ADD_DEL_TUNNEL_V2_REPLY,
195                 ({ rmp->sw_if_index = ntohl (sw_if_index); }));
196 }
197
198 static void
199 vl_api_vxlan_add_del_tunnel_v3_t_handler (vl_api_vxlan_add_del_tunnel_v3_t *mp)
200 {
201   vl_api_vxlan_add_del_tunnel_v3_reply_t *rmp;
202   u32 sw_if_index = ~0;
203   int rv = 0;
204
205   vnet_vxlan_add_del_tunnel_args_t a = {
206     .is_add = mp->is_add,
207     .instance = ntohl (mp->instance),
208     .mcast_sw_if_index = ntohl (mp->mcast_sw_if_index),
209     .decap_next_index = ntohl (mp->decap_next_index),
210     .vni = ntohl (mp->vni),
211     .dst_port = ntohs (mp->dst_port),
212     .src_port = ntohs (mp->src_port),
213     .is_l3 = mp->is_l3,
214   };
215
216   ip_address_decode (&mp->src_address, &a.src);
217   ip_address_decode (&mp->dst_address, &a.dst);
218
219   rv = vxlan_add_del_tunnel_clean_input (&a, ntohl (mp->encap_vrf_id));
220   if (rv)
221     goto out;
222   rv = vnet_vxlan_add_del_tunnel (&a, &sw_if_index);
223 out:
224   REPLY_MACRO2 (VL_API_VXLAN_ADD_DEL_TUNNEL_V3_REPLY,
225                 ({ rmp->sw_if_index = ntohl (sw_if_index); }));
226 }
227
228 static void send_vxlan_tunnel_details
229   (vxlan_tunnel_t * t, vl_api_registration_t * reg, u32 context)
230 {
231   vl_api_vxlan_tunnel_details_t *rmp;
232   ip4_main_t *im4 = &ip4_main;
233   ip6_main_t *im6 = &ip6_main;
234
235   rmp = vl_msg_api_alloc (sizeof (*rmp));
236   clib_memset (rmp, 0, sizeof (*rmp));
237   rmp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_VXLAN_TUNNEL_DETAILS);
238
239   ip_address_encode (&t->src, IP46_TYPE_ANY, &rmp->src_address);
240   ip_address_encode (&t->dst, IP46_TYPE_ANY, &rmp->dst_address);
241
242   if (ip46_address_is_ip4 (&t->dst))
243     rmp->encap_vrf_id = htonl (im4->fibs[t->encap_fib_index].ft_table_id);
244   else
245     rmp->encap_vrf_id = htonl (im6->fibs[t->encap_fib_index].ft_table_id);
246
247   rmp->instance = htonl (t->user_instance);
248   rmp->mcast_sw_if_index = htonl (t->mcast_sw_if_index);
249   rmp->vni = htonl (t->vni);
250   rmp->decap_next_index = htonl (t->decap_next_index);
251   rmp->sw_if_index = htonl (t->sw_if_index);
252   rmp->context = context;
253
254   vl_api_send_msg (reg, (u8 *) rmp);
255 }
256
257 static void vl_api_vxlan_tunnel_dump_t_handler
258   (vl_api_vxlan_tunnel_dump_t * mp)
259 {
260   vl_api_registration_t *reg;
261   vxlan_main_t *vxm = &vxlan_main;
262   vxlan_tunnel_t *t;
263   u32 sw_if_index;
264
265   reg = vl_api_client_index_to_registration (mp->client_index);
266   if (!reg)
267     return;
268
269   sw_if_index = ntohl (mp->sw_if_index);
270
271   if (~0 == sw_if_index)
272     {
273       pool_foreach (t, vxm->tunnels)
274         send_vxlan_tunnel_details(t, reg, mp->context);
275     }
276   else
277     {
278       if ((sw_if_index >= vec_len (vxm->tunnel_index_by_sw_if_index)) ||
279           (~0 == vxm->tunnel_index_by_sw_if_index[sw_if_index]))
280         {
281           return;
282         }
283       t = &vxm->tunnels[vxm->tunnel_index_by_sw_if_index[sw_if_index]];
284       send_vxlan_tunnel_details (t, reg, mp->context);
285     }
286 }
287
288 static void
289 send_vxlan_tunnel_v2_details (vxlan_tunnel_t *t, vl_api_registration_t *reg,
290                               u32 context)
291 {
292   vl_api_vxlan_tunnel_v2_details_t *rmp;
293   ip4_main_t *im4 = &ip4_main;
294   ip6_main_t *im6 = &ip6_main;
295
296   rmp = vl_msg_api_alloc (sizeof (*rmp));
297   clib_memset (rmp, 0, sizeof (*rmp));
298   rmp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_VXLAN_TUNNEL_V2_DETAILS);
299
300   ip_address_encode (&t->src, IP46_TYPE_ANY, &rmp->src_address);
301   ip_address_encode (&t->dst, IP46_TYPE_ANY, &rmp->dst_address);
302   rmp->src_port = htons (t->src_port);
303   rmp->dst_port = htons (t->dst_port);
304
305   if (ip46_address_is_ip4 (&t->dst))
306     rmp->encap_vrf_id = htonl (im4->fibs[t->encap_fib_index].ft_table_id);
307   else
308     rmp->encap_vrf_id = htonl (im6->fibs[t->encap_fib_index].ft_table_id);
309
310   rmp->instance = htonl (t->user_instance);
311   rmp->mcast_sw_if_index = htonl (t->mcast_sw_if_index);
312   rmp->vni = htonl (t->vni);
313   rmp->decap_next_index = htonl (t->decap_next_index);
314   rmp->sw_if_index = htonl (t->sw_if_index);
315   rmp->context = context;
316
317   vl_api_send_msg (reg, (u8 *) rmp);
318 }
319
320 static void
321 vl_api_vxlan_tunnel_v2_dump_t_handler (vl_api_vxlan_tunnel_v2_dump_t *mp)
322 {
323   vl_api_registration_t *reg;
324   vxlan_main_t *vxm = &vxlan_main;
325   vxlan_tunnel_t *t;
326   u32 sw_if_index;
327
328   reg = vl_api_client_index_to_registration (mp->client_index);
329   if (!reg)
330     return;
331
332   sw_if_index = ntohl (mp->sw_if_index);
333
334   if (~0 == sw_if_index)
335     {
336       pool_foreach (t, vxm->tunnels)
337         send_vxlan_tunnel_v2_details (t, reg, mp->context);
338     }
339   else
340     {
341       if ((sw_if_index >= vec_len (vxm->tunnel_index_by_sw_if_index)) ||
342           (~0 == vxm->tunnel_index_by_sw_if_index[sw_if_index]))
343         {
344           return;
345         }
346       t = &vxm->tunnels[vxm->tunnel_index_by_sw_if_index[sw_if_index]];
347       send_vxlan_tunnel_v2_details (t, reg, mp->context);
348     }
349 }
350
351 #include <vxlan/vxlan.api.c>
352 static clib_error_t *
353 vxlan_api_hookup (vlib_main_t * vm)
354 {
355   api_main_t *am = vlibapi_get_main ();
356
357   vl_api_increase_msg_trace_size (am, VL_API_VXLAN_ADD_DEL_TUNNEL,
358                                   16 * sizeof (u32));
359
360   /*
361    * Set up the (msg_name, crc, message-id) table
362    */
363   msg_id_base = setup_message_id_table ();
364
365   return 0;
366 }
367
368 VLIB_API_INIT_FUNCTION (vxlan_api_hookup);
369
370 /*
371  * fd.io coding-style-patch-verification: ON
372  *
373  * Local Variables:
374  * eval: (c-set-style "gnu")
375  * End:
376  */