udp: fix csum computation when offload disabled
[vpp.git] / src / vnet / ip6-nd / ip6_nd_api.c
1 /*
2  *------------------------------------------------------------------
3  * ip_api.c - vnet ip 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 <stddef.h>
21
22 #include <vnet/ip6-nd/ip6_nd.h>
23 #include <vnet/ip6-nd/ip6_ra.h>
24
25 #include <vnet/fib/fib_table.h>
26 #include <vnet/ip/ip_types_api.h>
27
28 #include <vpp/app/version.h>
29
30 #include <vlibapi/api.h>
31 #include <vlibmemory/api.h>
32
33 /* define message IDs */
34 #include <vnet/format_fns.h>
35 #include <vnet/ip6-nd/ip6_nd.api_enum.h>
36 #include <vnet/ip6-nd/ip6_nd.api_types.h>
37
38 /**
39  * Base message ID fot the plugin
40  */
41 static u32 ip6_nd_base_msg_id;
42 #define REPLY_MSG_ID_BASE ip6_nd_base_msg_id
43
44 #include <vlibapi/api_helper_macros.h>
45
46 static void
47 send_ip6nd_proxy_details (vl_api_registration_t * reg,
48                           u32 context,
49                           const ip46_address_t * addr, u32 sw_if_index)
50 {
51   vl_api_ip6nd_proxy_details_t *mp;
52
53   mp = vl_msg_api_alloc (sizeof (*mp));
54   clib_memset (mp, 0, sizeof (*mp));
55   mp->_vl_msg_id = ntohs (VL_API_IP6ND_PROXY_DETAILS);
56   mp->context = context;
57   mp->sw_if_index = htonl (sw_if_index);
58
59   ip6_address_encode (&addr->ip6, mp->ip);
60
61   vl_api_send_msg (reg, (u8 *) mp);
62 }
63
64 typedef struct api_ip6nd_proxy_fib_table_walk_ctx_t_
65 {
66   u32 *indices;
67 } api_ip6nd_proxy_fib_table_walk_ctx_t;
68
69 static fib_table_walk_rc_t
70 api_ip6nd_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
71 {
72   api_ip6nd_proxy_fib_table_walk_ctx_t *ctx = arg;
73
74   if (fib_entry_is_sourced (fei, FIB_SOURCE_IP6_ND_PROXY))
75     {
76       vec_add1 (ctx->indices, fei);
77     }
78
79   return (FIB_TABLE_WALK_CONTINUE);
80 }
81
82 static void
83 vl_api_ip6nd_proxy_dump_t_handler (vl_api_ip6nd_proxy_dump_t * mp)
84 {
85   ip6_main_t *im6 = &ip6_main;
86   u32 fib_index;
87   api_ip6nd_proxy_fib_table_walk_ctx_t ctx = {
88     .indices = NULL,
89   };
90   fib_node_index_t *feip;
91   const fib_prefix_t *pfx;
92   vl_api_registration_t *reg;
93
94   reg = vl_api_client_index_to_registration (mp->client_index);
95   if (!reg)
96     return;
97
98   pool_foreach_index (fib_index, im6->fibs)
99     {
100       fib_table_walk (fib_index, FIB_PROTOCOL_IP6,
101                       api_ip6nd_proxy_fib_table_walk, &ctx);
102     }
103
104   vec_sort_with_function (ctx.indices, fib_entry_cmp_for_sort);
105
106   vec_foreach (feip, ctx.indices)
107   {
108     pfx = fib_entry_get_prefix (*feip);
109
110     send_ip6nd_proxy_details (reg,
111                               mp->context,
112                               &pfx->fp_addr,
113                               fib_entry_get_resolving_interface (*feip));
114   }
115
116   vec_free (ctx.indices);
117 }
118
119 static void
120 vl_api_ip6nd_proxy_enable_disable_t_handler (
121   vl_api_ip6nd_proxy_enable_disable_t *mp)
122 {
123   vl_api_ip6nd_proxy_enable_disable_reply_t *rmp;
124   int rv = 0;
125
126   VALIDATE_SW_IF_INDEX (mp);
127
128   if (mp->is_enable)
129     rv = ip6_nd_proxy_enable_disable (ntohl (mp->sw_if_index), 1);
130   else
131     rv = ip6_nd_proxy_enable_disable (ntohl (mp->sw_if_index), 0);
132
133   BAD_SW_IF_INDEX_LABEL;
134   REPLY_MACRO (VL_API_IP6ND_PROXY_ENABLE_DISABLE_REPLY);
135 }
136
137 static void
138 vl_api_ip6nd_proxy_add_del_t_handler (vl_api_ip6nd_proxy_add_del_t * mp)
139 {
140   vl_api_ip6nd_proxy_add_del_reply_t *rmp;
141   ip6_address_t ip6;
142   int rv = 0;
143
144   VALIDATE_SW_IF_INDEX (mp);
145
146   ip6_address_decode (mp->ip, &ip6);
147   if (mp->is_add)
148     rv = ip6_nd_proxy_add (ntohl (mp->sw_if_index), &ip6);
149   else
150     rv = ip6_nd_proxy_del (ntohl (mp->sw_if_index), &ip6);
151
152   BAD_SW_IF_INDEX_LABEL;
153   REPLY_MACRO (VL_API_IP6ND_PROXY_ADD_DEL_REPLY);
154 }
155
156 static void
157   vl_api_sw_interface_ip6nd_ra_config_t_handler
158   (vl_api_sw_interface_ip6nd_ra_config_t * mp)
159 {
160   vl_api_sw_interface_ip6nd_ra_config_reply_t *rmp;
161   vlib_main_t *vm = vlib_get_main ();
162   int rv = 0;
163   u8 is_no, suppress, managed, other, ll_option, send_unicast, cease,
164     default_router;
165
166   is_no = mp->is_no == 1;
167   suppress = mp->suppress == 1;
168   managed = mp->managed == 1;
169   other = mp->other == 1;
170   ll_option = mp->ll_option == 1;
171   send_unicast = mp->send_unicast == 1;
172   cease = mp->cease == 1;
173   default_router = mp->default_router == 1;
174
175   VALIDATE_SW_IF_INDEX (mp);
176
177   rv = ip6_ra_config (vm, ntohl (mp->sw_if_index),
178                       suppress, managed, other,
179                       ll_option, send_unicast, cease,
180                       default_router, ntohl (mp->lifetime),
181                       ntohl (mp->initial_count),
182                       ntohl (mp->initial_interval),
183                       ntohl (mp->max_interval),
184                       ntohl (mp->min_interval), is_no);
185
186   BAD_SW_IF_INDEX_LABEL;
187
188   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_CONFIG_REPLY);
189 }
190
191 static void
192   vl_api_sw_interface_ip6nd_ra_prefix_t_handler
193   (vl_api_sw_interface_ip6nd_ra_prefix_t * mp)
194 {
195   vlib_main_t *vm = vlib_get_main ();
196   vl_api_sw_interface_ip6nd_ra_prefix_reply_t *rmp;
197   fib_prefix_t pfx;
198   int rv = 0;
199   u8 is_no, use_default, no_advertise, off_link, no_autoconfig, no_onlink;
200
201   VALIDATE_SW_IF_INDEX (mp);
202
203   ip_prefix_decode (&mp->prefix, &pfx);
204   is_no = mp->is_no == 1;
205   use_default = mp->use_default == 1;
206   no_advertise = mp->no_advertise == 1;
207   off_link = mp->off_link == 1;
208   no_autoconfig = mp->no_autoconfig == 1;
209   no_onlink = mp->no_onlink == 1;
210
211   rv = ip6_ra_prefix (vm, ntohl (mp->sw_if_index),
212                       &pfx.fp_addr.ip6,
213                       pfx.fp_len, use_default,
214                       ntohl (mp->val_lifetime),
215                       ntohl (mp->pref_lifetime), no_advertise,
216                       off_link, no_autoconfig, no_onlink, is_no);
217
218   BAD_SW_IF_INDEX_LABEL;
219   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY);
220 }
221
222 static void
223 ip6_radv_prefix_encode (f64 now, const ip6_radv_prefix_t *in,
224                         vl_api_ip6nd_ra_prefix_t *out)
225 {
226   fib_prefix_t in_ip6_pfx = {
227     .fp_addr = {
228       .ip6 = in->prefix,
229     },
230     .fp_len = in->prefix_len,
231     .fp_proto = FIB_PROTOCOL_IP6,
232   };
233
234   ip_prefix_encode (&in_ip6_pfx, &out->prefix);
235
236   out->onlink_flag = in->adv_on_link_flag;
237   out->autonomous_flag = in->adv_autonomous_flag;
238   out->val_lifetime = htonl (in->adv_valid_lifetime_in_secs);
239   out->pref_lifetime = htonl (in->adv_pref_lifetime_in_secs);
240
241   if (in->adv_valid_lifetime_in_secs != ~0)
242     {
243       out->valid_lifetime_expires =
244         clib_host_to_net_f64 (in->valid_lifetime_expires - now);
245     }
246
247   if (in->adv_pref_lifetime_in_secs != ~0)
248     {
249       out->pref_lifetime_expires =
250         clib_host_to_net_f64 (in->pref_lifetime_expires - now);
251     }
252
253   out->decrement_lifetime_flag = in->decrement_lifetime_flag;
254   out->no_advertise = (in->enabled == 0);
255 }
256
257 static void
258 send_sw_interface_ip6nd_ra_details (vl_api_registration_t *reg, u32 context,
259                                     ip6_ra_t *radv_info)
260 {
261   vl_api_sw_interface_ip6nd_ra_details_t *rmp = 0;
262   vl_api_ip6nd_ra_prefix_t *api_radv_pfx;
263   u32 n_prefixes = pool_elts (radv_info->adv_prefixes_pool);
264   ip6_radv_prefix_t *radv_pfx;
265   u32 msg_size = sizeof (*rmp) + n_prefixes * sizeof (*api_radv_pfx);
266   vlib_main_t *vm = vlib_get_main ();
267   f64 now = vlib_time_now (vm);
268
269   rmp = vl_msg_api_alloc (msg_size);
270   if (!rmp)
271     return;
272   clib_memset (rmp, 0, msg_size);
273   rmp->_vl_msg_id =
274     ntohs (VL_API_SW_INTERFACE_IP6ND_RA_DETAILS + REPLY_MSG_ID_BASE);
275   rmp->context = context;
276
277   rmp->sw_if_index = htonl (radv_info->sw_if_index);
278   rmp->cur_hop_limit = radv_info->curr_hop_limit;
279   rmp->adv_managed_flag = radv_info->adv_managed_flag;
280   rmp->adv_other_flag = radv_info->adv_other_flag;
281   rmp->adv_router_lifetime = htons (radv_info->adv_router_lifetime_in_sec);
282   rmp->adv_neighbor_reachable_time =
283     htonl (radv_info->adv_neighbor_reachable_time_in_msec);
284   rmp->adv_retransmit_interval = htonl (
285     radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations);
286   rmp->adv_link_mtu = htonl (radv_info->adv_link_mtu);
287   rmp->send_radv = radv_info->send_radv;
288   rmp->cease_radv = radv_info->cease_radv;
289   rmp->send_unicast = radv_info->send_unicast;
290   rmp->adv_link_layer_address = radv_info->adv_link_layer_address;
291   rmp->max_radv_interval = clib_host_to_net_f64 (radv_info->max_radv_interval);
292   rmp->min_radv_interval = clib_host_to_net_f64 (radv_info->min_radv_interval);
293
294   if (radv_info->last_radv_time > 0.0)
295     {
296       rmp->last_radv_time =
297         clib_host_to_net_f64 (now - radv_info->last_radv_time);
298     }
299
300   if ((radv_info->next_multicast_time - radv_info->last_multicast_time) > 0.0)
301     {
302       rmp->last_multicast_time =
303         clib_host_to_net_f64 (now - radv_info->last_multicast_time);
304       rmp->next_multicast_time =
305         clib_host_to_net_f64 (radv_info->next_multicast_time - now);
306     }
307
308   rmp->initial_adverts_count = htonl (radv_info->initial_adverts_count);
309   rmp->initial_adverts_interval =
310     clib_host_to_net_f64 (radv_info->initial_adverts_interval);
311   rmp->initial_adverts_sent = (radv_info->initial_adverts_sent == 0);
312   rmp->n_advertisements_sent = htonl (radv_info->n_advertisements_sent);
313   rmp->n_solicitations_rcvd = htonl (radv_info->n_solicitations_rcvd);
314   rmp->n_solicitations_dropped = htonl (radv_info->n_solicitations_dropped);
315   rmp->n_prefixes = htonl (n_prefixes);
316
317   api_radv_pfx = rmp->prefixes;
318   pool_foreach (radv_pfx, radv_info->adv_prefixes_pool)
319     {
320       ip6_radv_prefix_encode (now, radv_pfx, api_radv_pfx);
321
322       api_radv_pfx++;
323     }
324
325   vl_api_send_msg (reg, (u8 *) rmp);
326 }
327
328 typedef struct
329 {
330   u32 *sw_if_indices;
331 } api_dump_ip6_ra_itf_walk_ctx_t;
332
333 static walk_rc_t
334 api_dump_ip6_ra_itf_walk_fn (u32 sw_if_index, void *arg)
335 {
336   api_dump_ip6_ra_itf_walk_ctx_t *ctx = arg;
337
338   vec_add1 (ctx->sw_if_indices, sw_if_index);
339
340   return (WALK_CONTINUE);
341 }
342
343 static void
344 vl_api_sw_interface_ip6nd_ra_dump_t_handler (
345   vl_api_sw_interface_ip6nd_ra_dump_t *mp)
346 {
347   vl_api_registration_t *reg;
348   u32 sw_if_index;
349   ip6_ra_t *radv_info;
350
351   reg = vl_api_client_index_to_registration (mp->client_index);
352   if (!reg)
353     return;
354
355   sw_if_index = ntohl (mp->sw_if_index);
356
357   if (sw_if_index == INDEX_INVALID)
358     {
359       /* dump all interfaces */
360
361       api_dump_ip6_ra_itf_walk_ctx_t ctx = {
362         .sw_if_indices = NULL,
363       };
364       u32 *sw_if_i;
365
366       ip6_ra_itf_walk (api_dump_ip6_ra_itf_walk_fn, &ctx);
367
368       vec_foreach (sw_if_i, ctx.sw_if_indices)
369         {
370           radv_info = ip6_ra_get_itf (*sw_if_i);
371           if (radv_info != NULL)
372             {
373               send_sw_interface_ip6nd_ra_details (reg, mp->context, radv_info);
374             }
375         }
376
377       vec_free (ctx.sw_if_indices);
378     }
379   else
380     {
381       /* dump a single interface */
382
383       radv_info = ip6_ra_get_itf (sw_if_index);
384       if (radv_info != NULL)
385         {
386           send_sw_interface_ip6nd_ra_details (reg, mp->context, radv_info);
387         }
388     }
389 }
390
391 static void
392   vl_api_ip6nd_send_router_solicitation_t_handler
393   (vl_api_ip6nd_send_router_solicitation_t * mp)
394 {
395   vl_api_ip6nd_send_router_solicitation_reply_t *rmp;
396   icmp6_send_router_solicitation_params_t params;
397   vlib_main_t *vm = vlib_get_main ();
398   int rv = 0;
399
400   VALIDATE_SW_IF_INDEX (mp);
401
402   BAD_SW_IF_INDEX_LABEL;
403   REPLY_MACRO (VL_API_IP6ND_SEND_ROUTER_SOLICITATION_REPLY);
404
405   if (rv != 0)
406     return;
407
408   params.irt = ntohl (mp->irt);
409   params.mrt = ntohl (mp->mrt);
410   params.mrc = ntohl (mp->mrc);
411   params.mrd = ntohl (mp->mrd);
412
413   icmp6_send_router_solicitation (vm, ntohl (mp->sw_if_index), mp->stop,
414                                   &params);
415 }
416
417 static void
418 ip6_ra_handle_report (const ip6_ra_report_t * rap)
419 {
420   vpe_client_registration_t *rp;
421
422   pool_foreach (rp, vpe_api_main.ip6_ra_events_registrations)
423    {
424     vl_api_registration_t *vl_reg;
425
426     vl_reg = vl_api_client_index_to_registration (rp->client_index);
427
428     if (vl_reg && vl_api_can_send_msg (vl_reg))
429       {
430         vl_api_ip6_ra_prefix_info_t *prefix;
431         vl_api_ip6_ra_event_t *event;
432
433         u32 event_size = (sizeof (vl_api_ip6_ra_event_t) +
434                           vec_len (rap->prefixes) *
435                           sizeof (vl_api_ip6_ra_prefix_info_t));
436         event = vl_msg_api_alloc_zero (event_size);
437
438         event->_vl_msg_id = htons (VL_API_IP6_RA_EVENT + REPLY_MSG_ID_BASE);
439         event->client_index = rp->client_index;
440         event->pid = rp->client_pid;
441         event->sw_if_index = clib_host_to_net_u32 (rap->sw_if_index);
442
443         ip6_address_encode (&rap->router_address,
444                             event->router_addr);
445
446         event->current_hop_limit = rap->current_hop_limit;
447         event->flags = rap->flags;
448         event->router_lifetime_in_sec =
449           clib_host_to_net_u16 (rap->router_lifetime_in_sec);
450         event->neighbor_reachable_time_in_msec =
451           clib_host_to_net_u32 (rap->neighbor_reachable_time_in_msec);
452         event->time_in_msec_between_retransmitted_neighbor_solicitations =
453           clib_host_to_net_u32 (rap->time_in_msec_between_retransmitted_neighbor_solicitations);
454         event->n_prefixes = clib_host_to_net_u32 (vec_len (rap->prefixes));
455
456         prefix = event->prefixes;
457           // (typeof (prefix)) event->prefixes;
458         u32 j;
459         for (j = 0; j < vec_len (rap->prefixes); j++)
460           {
461             ra_report_prefix_info_t *info = &rap->prefixes[j];
462             ip_prefix_encode(&info->prefix, &prefix->prefix);
463             prefix->flags = info->flags;
464             prefix->valid_time = clib_host_to_net_u32 (info->valid_time);
465             prefix->preferred_time =
466               clib_host_to_net_u32 (info->preferred_time);
467             prefix++;
468           }
469
470         vl_api_send_msg (vl_reg, (u8 *) event);
471       }
472   }
473 }
474
475 static void
476 vl_api_want_ip6_ra_events_t_handler (vl_api_want_ip6_ra_events_t * mp)
477 {
478   vpe_api_main_t *am = &vpe_api_main;
479   vl_api_want_ip6_ra_events_reply_t *rmp;
480   int rv = 0, had_reg, have_reg;
481
482   had_reg = hash_elts (am->ip6_ra_events_registration_hash);
483   uword *p = hash_get (am->ip6_ra_events_registration_hash, mp->client_index);
484   vpe_client_registration_t *rp;
485   if (p)
486     {
487       if (mp->enable)
488         {
489           clib_warning ("pid %d: already enabled...", ntohl (mp->pid));
490           rv = VNET_API_ERROR_INVALID_REGISTRATION;
491           goto reply;
492         }
493       else
494         {
495           rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
496           pool_put (am->ip6_ra_events_registrations, rp);
497           hash_unset (am->ip6_ra_events_registration_hash, mp->client_index);
498           goto reply;
499         }
500     }
501   if (mp->enable == 0)
502     {
503       clib_warning ("pid %d: already disabled...", ntohl (mp->pid));
504       rv = VNET_API_ERROR_INVALID_REGISTRATION;
505       goto reply;
506     }
507   pool_get (am->ip6_ra_events_registrations, rp);
508   rp->client_index = mp->client_index;
509   rp->client_pid = ntohl (mp->pid);
510   hash_set (am->ip6_ra_events_registration_hash, rp->client_index,
511             rp - am->ip6_ra_events_registrations);
512
513 reply:
514   have_reg = hash_elts (am->ip6_ra_events_registration_hash);
515
516   if (!had_reg && have_reg)
517     ip6_ra_report_register (ip6_ra_handle_report);
518   else if (had_reg && !have_reg)
519     ip6_ra_report_unregister (ip6_ra_handle_report);
520
521   REPLY_MACRO (VL_API_WANT_IP6_RA_EVENTS_REPLY);
522 }
523
524 static clib_error_t *
525 want_ip6_ra_events_reaper (u32 client_index)
526 {
527   vpe_api_main_t *am = &vpe_api_main;
528   vpe_client_registration_t *rp;
529   uword *p;
530
531   p = hash_get (am->ip6_ra_events_registration_hash, client_index);
532
533   if (p)
534     {
535       rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
536       pool_put (am->ip6_ra_events_registrations, rp);
537       hash_unset (am->ip6_ra_events_registration_hash, client_index);
538     }
539   return (NULL);
540 }
541
542 VL_MSG_API_REAPER_FUNCTION (want_ip6_ra_events_reaper);
543
544 #include <vnet/ip6-nd/ip6_nd.api.c>
545
546 static clib_error_t *
547 ip6_nd_api_init (vlib_main_t * vm)
548 {
549   /* Ask for a correctly-sized block of API message decode slots */
550   ip6_nd_base_msg_id = setup_message_id_table ();
551
552   return 0;
553 }
554
555 VLIB_INIT_FUNCTION (ip6_nd_api_init);
556
557 /*
558  * fd.io coding-style-patch-verification: ON
559  *
560  * Local Variables:
561  * eval: (c-set-style "gnu")
562  * End:
563  */