ip6-nd: add ip6-nd proxy
[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   /* *INDENT-OFF* */
99   pool_foreach_index (fib_index, im6->fibs)
100     {
101       fib_table_walk (fib_index, FIB_PROTOCOL_IP6,
102                       api_ip6nd_proxy_fib_table_walk, &ctx);
103     }
104   /* *INDENT-ON* */
105
106   vec_sort_with_function (ctx.indices, fib_entry_cmp_for_sort);
107
108   vec_foreach (feip, ctx.indices)
109   {
110     pfx = fib_entry_get_prefix (*feip);
111
112     send_ip6nd_proxy_details (reg,
113                               mp->context,
114                               &pfx->fp_addr,
115                               fib_entry_get_resolving_interface (*feip));
116   }
117
118   vec_free (ctx.indices);
119 }
120
121 static void
122 vl_api_ip6nd_proxy_enable_disable_t_handler (
123   vl_api_ip6nd_proxy_enable_disable_t *mp)
124 {
125   vl_api_ip6nd_proxy_enable_disable_reply_t *rmp;
126   int rv = 0;
127
128   VALIDATE_SW_IF_INDEX (mp);
129
130   if (mp->is_enable)
131     rv = ip6_nd_proxy_enable_disable (ntohl (mp->sw_if_index), 1);
132   else
133     rv = ip6_nd_proxy_enable_disable (ntohl (mp->sw_if_index), 0);
134
135   BAD_SW_IF_INDEX_LABEL;
136   REPLY_MACRO (VL_API_IP6ND_PROXY_ENABLE_DISABLE_REPLY);
137 }
138
139 static void
140 vl_api_ip6nd_proxy_add_del_t_handler (vl_api_ip6nd_proxy_add_del_t * mp)
141 {
142   vl_api_ip6nd_proxy_add_del_reply_t *rmp;
143   ip6_address_t ip6;
144   int rv = 0;
145
146   VALIDATE_SW_IF_INDEX (mp);
147
148   ip6_address_decode (mp->ip, &ip6);
149   if (mp->is_add)
150     rv = ip6_nd_proxy_add (ntohl (mp->sw_if_index), &ip6);
151   else
152     rv = ip6_nd_proxy_del (ntohl (mp->sw_if_index), &ip6);
153
154   BAD_SW_IF_INDEX_LABEL;
155   REPLY_MACRO (VL_API_IP6ND_PROXY_ADD_DEL_REPLY);
156 }
157
158 static void
159   vl_api_sw_interface_ip6nd_ra_config_t_handler
160   (vl_api_sw_interface_ip6nd_ra_config_t * mp)
161 {
162   vl_api_sw_interface_ip6nd_ra_config_reply_t *rmp;
163   vlib_main_t *vm = vlib_get_main ();
164   int rv = 0;
165   u8 is_no, suppress, managed, other, ll_option, send_unicast, cease,
166     default_router;
167
168   is_no = mp->is_no == 1;
169   suppress = mp->suppress == 1;
170   managed = mp->managed == 1;
171   other = mp->other == 1;
172   ll_option = mp->ll_option == 1;
173   send_unicast = mp->send_unicast == 1;
174   cease = mp->cease == 1;
175   default_router = mp->default_router == 1;
176
177   VALIDATE_SW_IF_INDEX (mp);
178
179   rv = ip6_ra_config (vm, ntohl (mp->sw_if_index),
180                       suppress, managed, other,
181                       ll_option, send_unicast, cease,
182                       default_router, ntohl (mp->lifetime),
183                       ntohl (mp->initial_count),
184                       ntohl (mp->initial_interval),
185                       ntohl (mp->max_interval),
186                       ntohl (mp->min_interval), is_no);
187
188   BAD_SW_IF_INDEX_LABEL;
189
190   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_CONFIG_REPLY);
191 }
192
193 static void
194   vl_api_sw_interface_ip6nd_ra_prefix_t_handler
195   (vl_api_sw_interface_ip6nd_ra_prefix_t * mp)
196 {
197   vlib_main_t *vm = vlib_get_main ();
198   vl_api_sw_interface_ip6nd_ra_prefix_reply_t *rmp;
199   fib_prefix_t pfx;
200   int rv = 0;
201   u8 is_no, use_default, no_advertise, off_link, no_autoconfig, no_onlink;
202
203   VALIDATE_SW_IF_INDEX (mp);
204
205   ip_prefix_decode (&mp->prefix, &pfx);
206   is_no = mp->is_no == 1;
207   use_default = mp->use_default == 1;
208   no_advertise = mp->no_advertise == 1;
209   off_link = mp->off_link == 1;
210   no_autoconfig = mp->no_autoconfig == 1;
211   no_onlink = mp->no_onlink == 1;
212
213   rv = ip6_ra_prefix (vm, ntohl (mp->sw_if_index),
214                       &pfx.fp_addr.ip6,
215                       pfx.fp_len, use_default,
216                       ntohl (mp->val_lifetime),
217                       ntohl (mp->pref_lifetime), no_advertise,
218                       off_link, no_autoconfig, no_onlink, is_no);
219
220   BAD_SW_IF_INDEX_LABEL;
221   REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY);
222 }
223
224 static void
225   vl_api_ip6nd_send_router_solicitation_t_handler
226   (vl_api_ip6nd_send_router_solicitation_t * mp)
227 {
228   vl_api_ip6nd_send_router_solicitation_reply_t *rmp;
229   icmp6_send_router_solicitation_params_t params;
230   vlib_main_t *vm = vlib_get_main ();
231   int rv = 0;
232
233   VALIDATE_SW_IF_INDEX (mp);
234
235   BAD_SW_IF_INDEX_LABEL;
236   REPLY_MACRO (VL_API_IP6ND_SEND_ROUTER_SOLICITATION_REPLY);
237
238   if (rv != 0)
239     return;
240
241   params.irt = ntohl (mp->irt);
242   params.mrt = ntohl (mp->mrt);
243   params.mrc = ntohl (mp->mrc);
244   params.mrd = ntohl (mp->mrd);
245
246   icmp6_send_router_solicitation (vm, ntohl (mp->sw_if_index), mp->stop,
247                                   &params);
248 }
249
250 static void
251 ip6_ra_handle_report (const ip6_ra_report_t * rap)
252 {
253   /* *INDENT-OFF* */
254   vpe_client_registration_t *rp;
255
256   pool_foreach (rp, vpe_api_main.ip6_ra_events_registrations)
257    {
258     vl_api_registration_t *vl_reg;
259
260     vl_reg = vl_api_client_index_to_registration (rp->client_index);
261
262     if (vl_reg && vl_api_can_send_msg (vl_reg))
263       {
264         vl_api_ip6_ra_prefix_info_t *prefix;
265         vl_api_ip6_ra_event_t *event;
266
267         u32 event_size = (sizeof (vl_api_ip6_ra_event_t) +
268                           vec_len (rap->prefixes) *
269                           sizeof (vl_api_ip6_ra_prefix_info_t));
270         event = vl_msg_api_alloc_zero (event_size);
271
272         event->_vl_msg_id = htons (VL_API_IP6_RA_EVENT + REPLY_MSG_ID_BASE);
273         event->client_index = rp->client_index;
274         event->pid = rp->client_pid;
275         event->sw_if_index = clib_host_to_net_u32 (rap->sw_if_index);
276
277         ip6_address_encode (&rap->router_address,
278                             event->router_addr);
279
280         event->current_hop_limit = rap->current_hop_limit;
281         event->flags = rap->flags;
282         event->router_lifetime_in_sec =
283           clib_host_to_net_u16 (rap->router_lifetime_in_sec);
284         event->neighbor_reachable_time_in_msec =
285           clib_host_to_net_u32 (rap->neighbor_reachable_time_in_msec);
286         event->time_in_msec_between_retransmitted_neighbor_solicitations =
287           clib_host_to_net_u32 (rap->time_in_msec_between_retransmitted_neighbor_solicitations);
288         event->n_prefixes = clib_host_to_net_u32 (vec_len (rap->prefixes));
289
290         prefix = event->prefixes;
291           // (typeof (prefix)) event->prefixes;
292         u32 j;
293         for (j = 0; j < vec_len (rap->prefixes); j++)
294           {
295             ra_report_prefix_info_t *info = &rap->prefixes[j];
296             ip_prefix_encode(&info->prefix, &prefix->prefix);
297             prefix->flags = info->flags;
298             prefix->valid_time = clib_host_to_net_u32 (info->valid_time);
299             prefix->preferred_time =
300               clib_host_to_net_u32 (info->preferred_time);
301             prefix++;
302           }
303
304         vl_api_send_msg (vl_reg, (u8 *) event);
305       }
306   }
307   /* *INDENT-ON* */
308 }
309
310 static void
311 vl_api_want_ip6_ra_events_t_handler (vl_api_want_ip6_ra_events_t * mp)
312 {
313   vpe_api_main_t *am = &vpe_api_main;
314   vl_api_want_ip6_ra_events_reply_t *rmp;
315   int rv = 0, had_reg, have_reg;
316
317   had_reg = hash_elts (am->ip6_ra_events_registration_hash);
318   uword *p = hash_get (am->ip6_ra_events_registration_hash, mp->client_index);
319   vpe_client_registration_t *rp;
320   if (p)
321     {
322       if (mp->enable)
323         {
324           clib_warning ("pid %d: already enabled...", ntohl (mp->pid));
325           rv = VNET_API_ERROR_INVALID_REGISTRATION;
326           goto reply;
327         }
328       else
329         {
330           rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
331           pool_put (am->ip6_ra_events_registrations, rp);
332           hash_unset (am->ip6_ra_events_registration_hash, mp->client_index);
333           goto reply;
334         }
335     }
336   if (mp->enable == 0)
337     {
338       clib_warning ("pid %d: already disabled...", ntohl (mp->pid));
339       rv = VNET_API_ERROR_INVALID_REGISTRATION;
340       goto reply;
341     }
342   pool_get (am->ip6_ra_events_registrations, rp);
343   rp->client_index = mp->client_index;
344   rp->client_pid = ntohl (mp->pid);
345   hash_set (am->ip6_ra_events_registration_hash, rp->client_index,
346             rp - am->ip6_ra_events_registrations);
347
348 reply:
349   have_reg = hash_elts (am->ip6_ra_events_registration_hash);
350
351   if (!had_reg && have_reg)
352     ip6_ra_report_register (ip6_ra_handle_report);
353   else if (had_reg && !have_reg)
354     ip6_ra_report_unregister (ip6_ra_handle_report);
355
356   REPLY_MACRO (VL_API_WANT_IP6_RA_EVENTS_REPLY);
357 }
358
359 static clib_error_t *
360 want_ip6_ra_events_reaper (u32 client_index)
361 {
362   vpe_api_main_t *am = &vpe_api_main;
363   vpe_client_registration_t *rp;
364   uword *p;
365
366   p = hash_get (am->ip6_ra_events_registration_hash, client_index);
367
368   if (p)
369     {
370       rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
371       pool_put (am->ip6_ra_events_registrations, rp);
372       hash_unset (am->ip6_ra_events_registration_hash, client_index);
373     }
374   return (NULL);
375 }
376
377 VL_MSG_API_REAPER_FUNCTION (want_ip6_ra_events_reaper);
378
379 #include <vnet/ip6-nd/ip6_nd.api.c>
380
381 static clib_error_t *
382 ip6_nd_api_init (vlib_main_t * vm)
383 {
384   /* Ask for a correctly-sized block of API message decode slots */
385   ip6_nd_base_msg_id = setup_message_id_table ();
386
387   return 0;
388 }
389
390 VLIB_INIT_FUNCTION (ip6_nd_api_init);
391
392 /*
393  * fd.io coding-style-patch-verification: ON
394  *
395  * Local Variables:
396  * eval: (c-set-style "gnu")
397  * End:
398  */