ip-neighbor: Replace feature for the ip-neighbor data-base
[vpp.git] / src / vnet / ip-neighbor / ip_neighbor_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/ip-neighbor/ip_neighbor.h>
23 #include <vnet/ip-neighbor/ip_neighbor_watch.h>
24 #include <vnet/ip/ip_types_api.h>
25 #include <vnet/ethernet/ethernet_types_api.h>
26
27 #include <vlibapi/api.h>
28 #include <vlibmemory/api.h>
29
30 #include <vnet/ip-neighbor/ip_neighbor.api_enum.h>
31 #include <vnet/ip-neighbor/ip_neighbor.api_types.h>
32
33 static u16 msg_id_base;
34 #define REPLY_MSG_ID_BASE msg_id_base
35
36 #include <vlibapi/api_helper_macros.h>
37
38 #include <vnet/format_fns.h>
39
40
41 static ip46_type_t
42 ip46_type_from_af (ip_address_family_t af)
43 {
44   return (AF_IP4 == af ? IP46_TYPE_IP4 : IP46_TYPE_IP6);
45 }
46
47 static vl_api_ip_neighbor_flags_t
48 ip_neighbor_flags_encode (ip_neighbor_flags_t f)
49 {
50   vl_api_ip_neighbor_flags_t v = IP_API_NEIGHBOR_FLAG_NONE;
51
52   if (f & IP_NEIGHBOR_FLAG_STATIC)
53     v |= IP_API_NEIGHBOR_FLAG_STATIC;
54   if (f & IP_NEIGHBOR_FLAG_NO_FIB_ENTRY)
55     v |= IP_API_NEIGHBOR_FLAG_NO_FIB_ENTRY;
56
57   return (v);
58 }
59
60 static void
61 ip_neighbor_encode (vl_api_ip_neighbor_t * api, const ip_neighbor_t * ipn)
62 {
63   api->sw_if_index = htonl (ipn->ipn_key->ipnk_sw_if_index);
64   api->flags = ip_neighbor_flags_encode (ipn->ipn_flags);
65
66   ip_address_encode (&ipn->ipn_key->ipnk_ip,
67                      ipn->ipn_key->ipnk_type, &api->ip_address);
68   mac_address_encode (&ipn->ipn_mac, api->mac_address);
69 }
70
71 void
72 ip_neighbor_handle_event (const ip_neighbor_event_t * ipne)
73 {
74   vl_api_ip_neighbor_event_t *mp;
75   vl_api_registration_t *reg;
76   const ip_neighbor_t *ipn;
77
78   ipn = ip_neighbor_get (ipne->ipne_index);
79
80   if (NULL == ipn)
81     /* Client can cancel, die, etc. */
82     return;
83
84   /* Customer(s) requesting event for this neighbor */
85   reg = vl_api_client_index_to_registration (ipne->ipne_watch.ipw_client);
86   if (!reg)
87     return;
88
89   if (vl_api_can_send_msg (reg))
90     {
91       mp = vl_msg_api_alloc (sizeof (*mp));
92       clib_memset (mp, 0, sizeof (*mp));
93       mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_EVENT + REPLY_MSG_ID_BASE);
94       mp->client_index = ipne->ipne_watch.ipw_client;
95       mp->pid = ipne->ipne_watch.ipw_pid;
96
97       ip_neighbor_encode (&mp->neighbor, ipn);
98
99       vl_api_send_msg (reg, (u8 *) mp);
100     }
101   else
102     {
103       static f64 last_time;
104       /*
105        * Throttle syslog msgs.
106        * It's pretty tempting to just revoke the registration...
107        */
108       if (vlib_time_now (vlib_get_main ()) > last_time + 10.0)
109         {
110           clib_warning ("ip6 nd event for %U to pid %d: queue stuffed!",
111                         format_ip46_address, &ipn->ipn_key->ipnk_ip,
112                         IP46_TYPE_ANY, ipne->ipne_watch.ipw_pid);
113           last_time = vlib_time_now (vlib_get_main ());
114         }
115     }
116 }
117
118 typedef struct ip_neighbor_dump_ctx_t_
119 {
120   vl_api_registration_t *reg;
121   u32 context;
122 } ip_neighbor_dump_ctx_t;
123
124 static walk_rc_t
125 send_ip_neighbor_details (index_t ipni, void *arg)
126 {
127   ip_neighbor_dump_ctx_t *ctx = arg;
128   vl_api_ip_neighbor_details_t *mp;
129   ip_neighbor_t *ipn;
130
131   ipn = ip_neighbor_get (ipni);
132   mp = vl_msg_api_alloc (sizeof (*mp));
133   clib_memset (mp, 0, sizeof (*mp));
134   mp->_vl_msg_id = ntohs (VL_API_IP_NEIGHBOR_DETAILS + REPLY_MSG_ID_BASE);
135   mp->context = ctx->context;
136   mp->age =
137     clib_host_to_net_f64 ((vlib_time_now (vlib_get_main ()) -
138                            ipn->ipn_time_last_updated));
139   ip_neighbor_encode (&mp->neighbor, ipn);
140
141   vl_api_send_msg (ctx->reg, (u8 *) mp);
142
143   return (WALK_CONTINUE);
144 }
145
146 static void
147 vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp)
148 {
149   vl_api_registration_t *reg;
150   ip_address_family_t af;
151   int rv;
152
153   reg = vl_api_client_index_to_registration (mp->client_index);
154   if (!reg)
155     return;
156
157   u32 sw_if_index = ntohl (mp->sw_if_index);
158
159   rv = ip_address_family_decode (mp->af, &af);
160
161   if (rv)
162     return;
163
164   ip_neighbor_dump_ctx_t ctx = {
165     .reg = reg,
166     .context = mp->context,
167   };
168
169   // walk all neighbours on all interfaces
170   ip_neighbor_walk ((af == AF_IP4 ?
171                      IP46_TYPE_IP4 :
172                      IP46_TYPE_IP6),
173                     sw_if_index, send_ip_neighbor_details, &ctx);
174 }
175
176 static ip_neighbor_flags_t
177 ip_neighbor_flags_decode (vl_api_ip_neighbor_flags_t v)
178 {
179   ip_neighbor_flags_t f = IP_NEIGHBOR_FLAG_NONE;
180
181   if (v & IP_API_NEIGHBOR_FLAG_STATIC)
182     f |= IP_NEIGHBOR_FLAG_STATIC;
183   if (v & IP_API_NEIGHBOR_FLAG_NO_FIB_ENTRY)
184     f |= IP_NEIGHBOR_FLAG_NO_FIB_ENTRY;
185
186   return (f);
187 }
188
189 static void
190 vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
191                                       vlib_main_t * vm)
192 {
193   vl_api_ip_neighbor_add_del_reply_t *rmp;
194   ip_neighbor_flags_t flags;
195   u32 stats_index = ~0;
196   ip46_address_t ip = ip46_address_initializer;
197   mac_address_t mac;
198   ip46_type_t type;
199   int rv;
200
201   VALIDATE_SW_IF_INDEX ((&mp->neighbor));
202
203   flags = ip_neighbor_flags_decode (mp->neighbor.flags);
204   type = ip_address_decode (&mp->neighbor.ip_address, &ip);
205   mac_address_decode (mp->neighbor.mac_address, &mac);
206
207   /* must be static or dynamic, default to dynamic */
208   if (!(flags & IP_NEIGHBOR_FLAG_STATIC) &&
209       !(flags & IP_NEIGHBOR_FLAG_DYNAMIC))
210     flags |= IP_NEIGHBOR_FLAG_DYNAMIC;
211
212   /*
213    * there's no validation here of the ND/ARP entry being added.
214    * The expectation is that the FIB will ensure that nothing bad
215    * will come of adding bogus entries.
216    */
217   if (mp->is_add)
218     rv = ip_neighbor_add (&ip, type, &mac,
219                           ntohl (mp->neighbor.sw_if_index),
220                           flags, &stats_index);
221   else
222     rv = ip_neighbor_del (&ip, type, ntohl (mp->neighbor.sw_if_index));
223
224   BAD_SW_IF_INDEX_LABEL;
225
226   /* *INDENT-OFF* */
227   REPLY_MACRO2 (VL_API_IP_NEIGHBOR_ADD_DEL_REPLY,
228   ({
229     rmp->stats_index = htonl (stats_index);
230   }));
231   /* *INDENT-ON* */
232 }
233
234 static void
235 vl_api_want_ip_neighbor_events_t_handler (vl_api_want_ip_neighbor_events_t *
236                                           mp)
237 {
238   vl_api_want_ip_neighbor_events_reply_t *rmp;
239   ip46_address_t ip;
240   ip46_type_t itype;
241   int rv = 0;
242
243   if (mp->sw_if_index != ~0)
244     VALIDATE_SW_IF_INDEX (mp);
245   itype = ip_address_decode (&mp->ip, &ip);
246
247   ip_neighbor_watcher_t watch = {
248     .ipw_client = mp->client_index,
249     .ipw_pid = mp->pid,
250   };
251
252   if (mp->enable)
253     ip_neighbor_watch (&ip, itype, ntohl (mp->sw_if_index), &watch);
254   else
255     ip_neighbor_unwatch (&ip, itype, ntohl (mp->sw_if_index), &watch);
256
257   BAD_SW_IF_INDEX_LABEL;
258   REPLY_MACRO (VL_API_WANT_IP_NEIGHBOR_EVENTS_REPLY);
259 }
260
261 static void
262 vl_api_ip_neighbor_config_t_handler (vl_api_ip_neighbor_config_t * mp)
263 {
264   vl_api_ip_neighbor_config_reply_t *rmp;
265   ip_address_family_t af;
266   int rv;
267
268   rv = ip_address_family_decode (mp->af, &af);
269
270   if (!rv)
271     rv = ip_neighbor_config (ip46_type_from_af (af),
272                              ntohl (mp->max_number),
273                              ntohl (mp->max_age), mp->recycle);
274
275   REPLY_MACRO (VL_API_IP_NEIGHBOR_CONFIG_REPLY);
276 }
277
278 static void
279 vl_api_ip_neighbor_replace_begin_t_handler (vl_api_ip_neighbor_replace_begin_t
280                                             * mp)
281 {
282   vl_api_ip_neighbor_replace_begin_reply_t *rmp;
283   int rv = 0;
284
285   ip_neighbor_mark (IP46_TYPE_IP4);
286   ip_neighbor_mark (IP46_TYPE_IP6);
287
288   REPLY_MACRO (VL_API_IP_NEIGHBOR_REPLACE_BEGIN_REPLY);
289 }
290
291 static void
292 vl_api_ip_neighbor_replace_end_t_handler (vl_api_ip_neighbor_replace_end_t *
293                                           mp)
294 {
295   vl_api_ip_neighbor_replace_end_reply_t *rmp;
296   int rv = 0;
297
298   ip_neighbor_sweep (IP46_TYPE_IP4);
299   ip_neighbor_sweep (IP46_TYPE_IP6);
300
301   REPLY_MACRO (VL_API_IP_NEIGHBOR_REPLACE_END_REPLY);
302 }
303
304 #define vl_msg_name_crc_list
305 #include <vnet/ip-neighbor/ip_neighbor.api.h>
306 #undef vl_msg_name_crc_list
307
308 #include <vnet/ip-neighbor/ip_neighbor.api.c>
309
310 static clib_error_t *
311 ip_neighbor_api_init (vlib_main_t * vm)
312 {
313   /* Ask for a correctly-sized block of API message decode slots */
314   msg_id_base = setup_message_id_table ();
315
316   return 0;
317 }
318
319 VLIB_API_INIT_FUNCTION (ip_neighbor_api_init);
320
321 /*
322  * fd.io coding-style-patch-verification: ON
323  *
324  * Local Variables:
325  * eval: (c-set-style "gnu")
326  * End:
327  */