2 * ip_neighboor_watch.c; IP neighbor watching
4 * Copyright (c) 2019 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vnet/ip-neighbor/ip_neighbor.h>
19 #include <vnet/ip-neighbor/ip_neighbor_watch.h>
20 #include <vnet/ip/ip_types_api.h>
21 #include <vnet/ethernet/ethernet_types_api.h>
23 #include <vnet/ip-neighbor/ip_neighbor.api_enum.h>
24 #include <vnet/ip-neighbor/ip_neighbor.api_types.h>
26 #include <vlibmemory/api.h>
29 * Database of registered watchers
30 * The key for a watcher is {type, sw_if_index, addreess}
31 * interface=~0 / address=all-zeros imples any.
33 typedef struct ip_neighbor_watch_db_t_
36 } ip_neighbor_watch_db_t;
38 static ip_neighbor_watch_db_t ipnw_db;
41 ip_neighbor_event_process (vlib_main_t * vm,
42 vlib_node_runtime_t * rt, vlib_frame_t * f)
44 ip_neighbor_event_t *ipne, *ipnes = NULL;
45 uword event_type = ~0;
49 vlib_process_wait_for_event (vm);
51 ipnes = vlib_process_get_event_data (vm, &event_type);
56 vec_foreach (ipne, ipnes) ip_neighbor_handle_event (ipne);
64 vec_reset_length (ipnes);
70 VLIB_REGISTER_NODE (ip_neighbor_event_process_node) = {
71 .function = ip_neighbor_event_process,
72 .type = VLIB_NODE_TYPE_PROCESS,
73 .name = "ip-neighbor-event",
79 want_ip_neighbor_events_reaper (u32 client_index)
81 ip_neighbor_key_t *key, *empty_keys = NULL;
82 ip_neighbor_watcher_t *watchers;
86 /* walk the entire IP neighbour DB and removes the client's registrations */
88 mhash_foreach(key, v, &ipnw_db.ipnwdb_hash,
90 watchers = (ip_neighbor_watcher_t*) *v;
92 vec_foreach_index_backwards (pos, watchers) {
93 if (watchers[pos].ipw_client == client_index)
94 vec_del1(watchers, pos);
97 if (vec_len(watchers) == 0)
98 vec_add1 (empty_keys, *key);
102 vec_foreach (key, empty_keys)
103 mhash_unset (&ipnw_db.ipnwdb_hash, key, NULL);
104 vec_free (empty_keys);
108 VL_MSG_API_REAPER_FUNCTION (want_ip_neighbor_events_reaper);
111 ip_neighbor_watch_cmp (const ip_neighbor_watcher_t * w1,
112 const ip_neighbor_watcher_t * w2)
114 return (0 == clib_memcmp (w1, w2, sizeof(*w1)));
118 ip_neighbor_watch (const ip46_address_t * ip,
121 const ip_neighbor_watcher_t * watch)
123 ip_neighbor_key_t key = {
125 .ipnk_sw_if_index = (sw_if_index == 0 ? ~0 : sw_if_index),
128 ip_neighbor_watcher_t *ipws = NULL;
131 p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
135 ipws = (ip_neighbor_watcher_t*) p[0];
137 if (~0 != vec_search_with_function (ipws, watch,
138 ip_neighbor_watch_cmp))
143 vec_add1 (ipws, *watch);
145 mhash_set (&ipnw_db.ipnwdb_hash, &key, (uword) ipws, NULL);
149 ip_neighbor_unwatch (const ip46_address_t * ip,
152 const ip_neighbor_watcher_t * watch)
154 ip_neighbor_key_t key = {
156 .ipnk_sw_if_index = (sw_if_index == 0 ? ~0 : sw_if_index),
159 ip_neighbor_watcher_t *ipws = NULL;
163 p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
168 ipws = (ip_neighbor_watcher_t*) p[0];
170 pos = vec_search_with_function (ipws, watch, ip_neighbor_watch_cmp);
175 vec_del1 (ipws, pos);
177 if (vec_len(ipws) == 0)
178 mhash_unset (&ipnw_db.ipnwdb_hash, &key, NULL);
182 ip_neighbor_signal (ip_neighbor_watcher_t *watchers,
184 ip_neighbor_event_flags_t flags)
186 ip_neighbor_watcher_t *watcher;
188 vec_foreach (watcher, watchers) {
189 ip_neighbor_event_t *ipne;
191 ipne = vlib_process_signal_event_data (vlib_get_main(),
192 ip_neighbor_event_process_node.index,
193 0, 1, sizeof(*ipne));
194 ipne->ipne_watch = *watcher;
195 ipne->ipne_flags = flags;
196 ip_neighbor_clone(ip_neighbor_get(ipni), &ipne->ipne_nbr);
201 ip_neighbor_publish (index_t ipni,
202 ip_neighbor_event_flags_t flags)
204 const ip_neighbor_t *ipn;
205 ip_neighbor_key_t key;
208 ipn = ip_neighbor_get (ipni);
210 clib_memcpy (&key, ipn->ipn_key, sizeof (key));
212 /* Search the DB from longest to shortest key */
213 p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
216 ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags);
219 ip46_address_reset (&key.ipnk_ip);
220 p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
223 ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags);
226 key.ipnk_sw_if_index = ~0;
227 p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
230 ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags);
234 static clib_error_t *
235 ip_neighbor_watchers_show (vlib_main_t * vm,
236 unformat_input_t * input,
237 vlib_cli_command_t * cmd)
239 ip_neighbor_watcher_t *watchers, *watcher;
240 ip_neighbor_key_t *key;
244 mhash_foreach(key, v, &ipnw_db.ipnwdb_hash,
246 watchers = (ip_neighbor_watcher_t*) *v;
248 ASSERT(vec_len(watchers));
249 vlib_cli_output (vm, "Key: %U", format_ip_neighbor_key, key);
251 vec_foreach (watcher, watchers)
252 vlib_cli_output (vm, " %U", format_ip_neighbor_watcher, watcher);
259 VLIB_CLI_COMMAND (show_ip_neighbor_watchers_cmd_node, static) = {
260 .path = "show ip neighbor-watcher",
261 .function = ip_neighbor_watchers_show,
262 .short_help = "show ip neighbors-watcher",
266 static clib_error_t *
267 ip_neighbor_watch_init (vlib_main_t * vm)
269 mhash_init (&ipnw_db.ipnwdb_hash,
270 sizeof (ip_neighbor_watcher_t *), sizeof (ip_neighbor_key_t));
275 VLIB_INIT_FUNCTION (ip_neighbor_watch_init) =
277 .runs_after = VLIB_INITS("ip_neighbor_init"),
283 * fd.io coding-style-patch-verification: ON
286 * eval: (c-set-style "gnu")