vxlan: add udp-port configuration support
[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
29 #include <vnet/ip/ip_types_api.h>
30 #include <vnet/udp/udp_local.h>
31
32 #include <vnet/vnet_msg_enum.h>
33
34 #define vl_typedefs             /* define message structures */
35 #include <vnet/vnet_all_api_h.h>
36 #undef vl_typedefs
37
38 #define vl_endianfun            /* define message structures */
39 #include <vnet/vnet_all_api_h.h>
40 #undef vl_endianfun
41
42 /* instantiate all the print functions we know about */
43 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
44 #define vl_printfun
45 #include <vnet/vnet_all_api_h.h>
46 #undef vl_printfun
47
48 #include <vlibapi/api_helper_macros.h>
49
50 #define foreach_vpe_api_msg                                                   \
51   _ (SW_INTERFACE_SET_VXLAN_BYPASS, sw_interface_set_vxlan_bypass)            \
52   _ (VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel)                              \
53   _ (VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump)                                    \
54   _ (VXLAN_ADD_DEL_TUNNEL_V2, vxlan_add_del_tunnel_v2)                        \
55   _ (VXLAN_TUNNEL_V2_DUMP, vxlan_tunnel_v2_dump)                              \
56   _ (VXLAN_OFFLOAD_RX, vxlan_offload_rx)
57
58 static void
59 vl_api_vxlan_offload_rx_t_handler (vl_api_vxlan_offload_rx_t * mp)
60 {
61   vl_api_vxlan_offload_rx_reply_t *rmp;
62   int rv = 0;
63   u32 hw_if_index = ntohl (mp->hw_if_index);
64   u32 sw_if_index = ntohl (mp->sw_if_index);
65
66   if (!vnet_hw_interface_is_valid (vnet_get_main (), hw_if_index))
67     {
68       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
69       goto err;
70     }
71   VALIDATE_SW_IF_INDEX (mp);
72
73   u32 t_index = vnet_vxlan_get_tunnel_index (sw_if_index);
74   if (t_index == ~0)
75     {
76       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
77       goto err;
78     }
79
80   vxlan_main_t *vxm = &vxlan_main;
81   vxlan_tunnel_t *t = pool_elt_at_index (vxm->tunnels, t_index);
82   if (!ip46_address_is_ip4 (&t->dst))
83     {
84       rv = VNET_API_ERROR_INVALID_ADDRESS_FAMILY;
85       goto err;
86     }
87
88   vnet_main_t *vnm = vnet_get_main ();
89   vnet_hw_interface_t *hw_if = vnet_get_hw_interface (vnm, hw_if_index);
90   ip4_main_t *im = &ip4_main;
91   u32 rx_fib_index =
92     vec_elt (im->fib_index_by_sw_if_index, hw_if->sw_if_index);
93
94   if (t->encap_fib_index != rx_fib_index)
95     {
96       rv = VNET_API_ERROR_NO_SUCH_FIB;
97       goto err;
98     }
99
100   if (vnet_vxlan_add_del_rx_flow (hw_if_index, t_index, mp->enable))
101     {
102       rv = VNET_API_ERROR_UNSPECIFIED;
103       goto err;
104     }
105   BAD_SW_IF_INDEX_LABEL;
106 err:
107
108   REPLY_MACRO (VL_API_VXLAN_OFFLOAD_RX_REPLY);
109 }
110
111 static void
112   vl_api_sw_interface_set_vxlan_bypass_t_handler
113   (vl_api_sw_interface_set_vxlan_bypass_t * mp)
114 {
115   vl_api_sw_interface_set_vxlan_bypass_reply_t *rmp;
116   int rv = 0;
117   u32 sw_if_index = ntohl (mp->sw_if_index);
118
119   VALIDATE_SW_IF_INDEX (mp);
120
121   vnet_int_vxlan_bypass_mode (sw_if_index, mp->is_ipv6, mp->enable);
122   BAD_SW_IF_INDEX_LABEL;
123
124   REPLY_MACRO (VL_API_SW_INTERFACE_SET_VXLAN_BYPASS_REPLY);
125 }
126
127 static void vl_api_vxlan_add_del_tunnel_t_handler
128   (vl_api_vxlan_add_del_tunnel_t * mp)
129 {
130   vl_api_vxlan_add_del_tunnel_reply_t *rmp;
131   int rv = 0;
132   bool is_ipv6;
133   u32 fib_index;
134   ip46_address_t src, dst;
135
136   ip_address_decode (&mp->src_address, &src);
137   ip_address_decode (&mp->dst_address, &dst);
138
139   if (ip46_address_is_ip4 (&src) != ip46_address_is_ip4 (&dst))
140     {
141       rv = VNET_API_ERROR_INVALID_VALUE;
142       goto out;
143     }
144
145   is_ipv6 = !ip46_address_is_ip4 (&src);
146
147   fib_index = fib_table_find (fib_ip_proto (is_ipv6),
148                               ntohl (mp->encap_vrf_id));
149   if (fib_index == ~0)
150     {
151       rv = VNET_API_ERROR_NO_SUCH_FIB;
152       goto out;
153     }
154
155   vnet_vxlan_add_del_tunnel_args_t a = {
156     .is_add = mp->is_add,
157     .is_ip6 = is_ipv6,
158     .instance = ntohl (mp->instance),
159     .mcast_sw_if_index = ntohl (mp->mcast_sw_if_index),
160     .encap_fib_index = fib_index,
161     .decap_next_index = ntohl (mp->decap_next_index),
162     .vni = ntohl (mp->vni),
163     .dst = dst,
164     .src = src,
165     .dst_port = is_ipv6 ? UDP_DST_PORT_vxlan6 : UDP_DST_PORT_vxlan,
166     .src_port = is_ipv6 ? UDP_DST_PORT_vxlan6 : UDP_DST_PORT_vxlan,
167   };
168
169   /* Check src & dst are different */
170   if (ip46_address_cmp (&a.dst, &a.src) == 0)
171     {
172       rv = VNET_API_ERROR_SAME_SRC_DST;
173       goto out;
174     }
175   if (ip46_address_is_multicast (&a.dst) &&
176       !vnet_sw_if_index_is_api_valid (a.mcast_sw_if_index))
177     {
178       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
179       goto out;
180     }
181
182   u32 sw_if_index = ~0;
183   rv = vnet_vxlan_add_del_tunnel (&a, &sw_if_index);
184
185 out:
186   REPLY_MACRO2(VL_API_VXLAN_ADD_DEL_TUNNEL_REPLY,
187   ({
188     rmp->sw_if_index = ntohl (sw_if_index);
189   }));
190 }
191
192 static void
193 vl_api_vxlan_add_del_tunnel_v2_t_handler (vl_api_vxlan_add_del_tunnel_v2_t *mp)
194 {
195   vl_api_vxlan_add_del_tunnel_v2_reply_t *rmp;
196   int rv = 0;
197   bool is_ipv6;
198   u32 fib_index;
199   ip46_address_t src, dst;
200
201   ip_address_decode (&mp->src_address, &src);
202   ip_address_decode (&mp->dst_address, &dst);
203
204   if (ip46_address_is_ip4 (&src) != ip46_address_is_ip4 (&dst))
205     {
206       rv = VNET_API_ERROR_INVALID_VALUE;
207       goto out;
208     }
209
210   is_ipv6 = !ip46_address_is_ip4 (&src);
211
212   fib_index =
213     fib_table_find (fib_ip_proto (is_ipv6), ntohl (mp->encap_vrf_id));
214   if (fib_index == ~0)
215     {
216       rv = VNET_API_ERROR_NO_SUCH_FIB;
217       goto out;
218     }
219
220   vnet_vxlan_add_del_tunnel_args_t a = {
221     .is_add = mp->is_add,
222     .is_ip6 = is_ipv6,
223     .instance = ntohl (mp->instance),
224     .mcast_sw_if_index = ntohl (mp->mcast_sw_if_index),
225     .encap_fib_index = fib_index,
226     .decap_next_index = ntohl (mp->decap_next_index),
227     .vni = ntohl (mp->vni),
228     .dst = dst,
229     .src = src,
230     .dst_port = ntohs (mp->dst_port),
231     .src_port = ntohs (mp->src_port),
232   };
233
234   /* Check src & dst are different */
235   if (ip46_address_cmp (&a.dst, &a.src) == 0)
236     {
237       rv = VNET_API_ERROR_SAME_SRC_DST;
238       goto out;
239     }
240   if (ip46_address_is_multicast (&a.dst) &&
241       !vnet_sw_if_index_is_api_valid (a.mcast_sw_if_index))
242     {
243       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
244       goto out;
245     }
246
247   u32 sw_if_index = ~0;
248   rv = vnet_vxlan_add_del_tunnel (&a, &sw_if_index);
249
250 out:
251   REPLY_MACRO2 (VL_API_VXLAN_ADD_DEL_TUNNEL_V2_REPLY,
252                 ({ rmp->sw_if_index = ntohl (sw_if_index); }));
253 }
254
255 static void send_vxlan_tunnel_details
256   (vxlan_tunnel_t * t, vl_api_registration_t * reg, u32 context)
257 {
258   vl_api_vxlan_tunnel_details_t *rmp;
259   ip4_main_t *im4 = &ip4_main;
260   ip6_main_t *im6 = &ip6_main;
261
262   rmp = vl_msg_api_alloc (sizeof (*rmp));
263   clib_memset (rmp, 0, sizeof (*rmp));
264   rmp->_vl_msg_id = ntohs (VL_API_VXLAN_TUNNEL_DETAILS);
265
266   ip_address_encode (&t->src, IP46_TYPE_ANY, &rmp->src_address);
267   ip_address_encode (&t->dst, IP46_TYPE_ANY, &rmp->dst_address);
268
269   if (ip46_address_is_ip4 (&t->dst))
270     rmp->encap_vrf_id = htonl (im4->fibs[t->encap_fib_index].ft_table_id);
271   else
272     rmp->encap_vrf_id = htonl (im6->fibs[t->encap_fib_index].ft_table_id);
273
274   rmp->instance = htonl (t->user_instance);
275   rmp->mcast_sw_if_index = htonl (t->mcast_sw_if_index);
276   rmp->vni = htonl (t->vni);
277   rmp->decap_next_index = htonl (t->decap_next_index);
278   rmp->sw_if_index = htonl (t->sw_if_index);
279   rmp->context = context;
280
281   vl_api_send_msg (reg, (u8 *) rmp);
282 }
283
284 static void vl_api_vxlan_tunnel_dump_t_handler
285   (vl_api_vxlan_tunnel_dump_t * mp)
286 {
287   vl_api_registration_t *reg;
288   vxlan_main_t *vxm = &vxlan_main;
289   vxlan_tunnel_t *t;
290   u32 sw_if_index;
291
292   reg = vl_api_client_index_to_registration (mp->client_index);
293   if (!reg)
294     return;
295
296   sw_if_index = ntohl (mp->sw_if_index);
297
298   if (~0 == sw_if_index)
299     {
300       pool_foreach (t, vxm->tunnels)
301         send_vxlan_tunnel_details(t, reg, mp->context);
302     }
303   else
304     {
305       if ((sw_if_index >= vec_len (vxm->tunnel_index_by_sw_if_index)) ||
306           (~0 == vxm->tunnel_index_by_sw_if_index[sw_if_index]))
307         {
308           return;
309         }
310       t = &vxm->tunnels[vxm->tunnel_index_by_sw_if_index[sw_if_index]];
311       send_vxlan_tunnel_details (t, reg, mp->context);
312     }
313 }
314
315 static void
316 send_vxlan_tunnel_v2_details (vxlan_tunnel_t *t, vl_api_registration_t *reg,
317                               u32 context)
318 {
319   vl_api_vxlan_tunnel_v2_details_t *rmp;
320   ip4_main_t *im4 = &ip4_main;
321   ip6_main_t *im6 = &ip6_main;
322
323   rmp = vl_msg_api_alloc (sizeof (*rmp));
324   clib_memset (rmp, 0, sizeof (*rmp));
325   rmp->_vl_msg_id = ntohs (VL_API_VXLAN_TUNNEL_V2_DETAILS);
326
327   ip_address_encode (&t->src, IP46_TYPE_ANY, &rmp->src_address);
328   ip_address_encode (&t->dst, IP46_TYPE_ANY, &rmp->dst_address);
329   rmp->src_port = htons (t->src_port);
330   rmp->dst_port = htons (t->dst_port);
331
332   if (ip46_address_is_ip4 (&t->dst))
333     rmp->encap_vrf_id = htonl (im4->fibs[t->encap_fib_index].ft_table_id);
334   else
335     rmp->encap_vrf_id = htonl (im6->fibs[t->encap_fib_index].ft_table_id);
336
337   rmp->instance = htonl (t->user_instance);
338   rmp->mcast_sw_if_index = htonl (t->mcast_sw_if_index);
339   rmp->vni = htonl (t->vni);
340   rmp->decap_next_index = htonl (t->decap_next_index);
341   rmp->sw_if_index = htonl (t->sw_if_index);
342   rmp->context = context;
343
344   vl_api_send_msg (reg, (u8 *) rmp);
345 }
346
347 static void
348 vl_api_vxlan_tunnel_v2_dump_t_handler (vl_api_vxlan_tunnel_v2_dump_t *mp)
349 {
350   vl_api_registration_t *reg;
351   vxlan_main_t *vxm = &vxlan_main;
352   vxlan_tunnel_t *t;
353   u32 sw_if_index;
354
355   reg = vl_api_client_index_to_registration (mp->client_index);
356   if (!reg)
357     return;
358
359   sw_if_index = ntohl (mp->sw_if_index);
360
361   if (~0 == sw_if_index)
362     {
363       pool_foreach (t, vxm->tunnels)
364         send_vxlan_tunnel_v2_details (t, reg, mp->context);
365     }
366   else
367     {
368       if ((sw_if_index >= vec_len (vxm->tunnel_index_by_sw_if_index)) ||
369           (~0 == vxm->tunnel_index_by_sw_if_index[sw_if_index]))
370         {
371           return;
372         }
373       t = &vxm->tunnels[vxm->tunnel_index_by_sw_if_index[sw_if_index]];
374       send_vxlan_tunnel_v2_details (t, reg, mp->context);
375     }
376 }
377
378 /*
379  * vpe_api_hookup
380  * Add vpe's API message handlers to the table.
381  * vlib has already mapped shared memory and
382  * added the client registration handlers.
383  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
384  */
385 #define vl_msg_name_crc_list
386 #include <vnet/vnet_all_api_h.h>
387 #undef vl_msg_name_crc_list
388
389 static void
390 setup_message_id_table (api_main_t * am)
391 {
392 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
393   foreach_vl_msg_name_crc_vxlan;
394 #undef _
395 }
396
397 static clib_error_t *
398 vxlan_api_hookup (vlib_main_t * vm)
399 {
400   api_main_t *am = vlibapi_get_main ();
401
402 #define _(N,n)                                                  \
403     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
404                            vl_api_##n##_t_handler,              \
405                            vl_noop_handler,                     \
406                            vl_api_##n##_t_endian,               \
407                            vl_api_##n##_t_print,                \
408                            sizeof(vl_api_##n##_t), 1);
409   foreach_vpe_api_msg;
410 #undef _
411
412   am->api_trace_cfg[VL_API_VXLAN_ADD_DEL_TUNNEL].size += 16 * sizeof (u32);
413
414   /*
415    * Set up the (msg_name, crc, message-id) table
416    */
417   setup_message_id_table (am);
418
419   return 0;
420 }
421
422 VLIB_API_INIT_FUNCTION (vxlan_api_hookup);
423
424 /*
425  * fd.io coding-style-patch-verification: ON
426  *
427  * Local Variables:
428  * eval: (c-set-style "gnu")
429  * End:
430  */