Line data Source code
1 : /*
2 : * ip_neighboor_watch.c; IP neighbor watching
3 : *
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:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
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.
16 : */
17 :
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>
22 :
23 : #include <vnet/ip-neighbor/ip_neighbor.api_enum.h>
24 : #include <vnet/ip-neighbor/ip_neighbor.api_types.h>
25 :
26 : #include <vlibmemory/api.h>
27 :
28 : /**
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.
32 : */
33 : typedef struct ip_neighbor_watch_db_t_
34 : {
35 : mhash_t ipnwdb_hash;
36 : } ip_neighbor_watch_db_t;
37 :
38 : static ip_neighbor_watch_db_t ipnw_db;
39 :
40 : static uword
41 559 : ip_neighbor_event_process (vlib_main_t * vm,
42 : vlib_node_runtime_t * rt, vlib_frame_t * f)
43 : {
44 559 : ip_neighbor_event_t *ipne, *ipnes = NULL;
45 559 : uword event_type = ~0;
46 :
47 : while (1)
48 : {
49 593 : vlib_process_wait_for_event (vm);
50 :
51 34 : ipnes = vlib_process_get_event_data (vm, &event_type);
52 :
53 34 : switch (event_type)
54 : {
55 34 : default:
56 80 : vec_foreach (ipne, ipnes) ip_neighbor_handle_event (ipne);
57 34 : break;
58 :
59 0 : case ~0:
60 : /* timeout - */
61 0 : break;
62 : }
63 :
64 34 : vec_reset_length (ipnes);
65 : }
66 : return 0;
67 : }
68 :
69 : /* *INDENT-OFF* */
70 178120 : 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",
74 : };
75 : /* *INDENT-ON* */
76 :
77 :
78 : static clib_error_t *
79 1207 : want_ip_neighbor_events_reaper (u32 client_index)
80 : {
81 1207 : ip_neighbor_key_t *key, *empty_keys = NULL;
82 : ip_neighbor_watcher_t *watchers;
83 : uword *v;
84 : i32 pos;
85 :
86 : /* walk the entire IP neighbour DB and removes the client's registrations */
87 : /* *INDENT-OFF* */
88 78457 : mhash_foreach(key, v, &ipnw_db.ipnwdb_hash,
89 : ({
90 : watchers = (ip_neighbor_watcher_t*) *v;
91 :
92 : vec_foreach_index_backwards (pos, watchers) {
93 : if (watchers[pos].ipw_client == client_index)
94 : vec_del1(watchers, pos);
95 : }
96 :
97 : if (vec_len(watchers) == 0)
98 : vec_add1 (empty_keys, *key);
99 : }));
100 : /* *INDENT-OFF* */
101 :
102 1208 : vec_foreach (key, empty_keys)
103 1 : mhash_unset (&ipnw_db.ipnwdb_hash, key, NULL);
104 1207 : vec_free (empty_keys);
105 1207 : return (NULL);
106 : }
107 :
108 559 : VL_MSG_API_REAPER_FUNCTION (want_ip_neighbor_events_reaper);
109 :
110 : static int
111 3 : ip_neighbor_watch_cmp (const ip_neighbor_watcher_t * w1,
112 : const ip_neighbor_watcher_t * w2)
113 : {
114 3 : return (0 == clib_memcmp (w1, w2, sizeof(*w1)));
115 : }
116 :
117 : void
118 4 : ip_neighbor_watch (const ip_address_t * ip,
119 : u32 sw_if_index,
120 : const ip_neighbor_watcher_t * watch)
121 : {
122 8 : ip_neighbor_key_t key = {
123 : .ipnk_ip = *ip,
124 4 : .ipnk_sw_if_index = (sw_if_index == 0 ? ~0 : sw_if_index),
125 : };
126 4 : ip_neighbor_watcher_t *ipws = NULL;
127 : uword *p;
128 :
129 4 : p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
130 :
131 4 : if (p)
132 : {
133 0 : ipws = (ip_neighbor_watcher_t*) p[0];
134 :
135 0 : if (~0 != vec_search_with_function (ipws, watch,
136 : ip_neighbor_watch_cmp))
137 : /* duplicate */
138 0 : return;
139 : }
140 :
141 4 : vec_add1 (ipws, *watch);
142 :
143 4 : mhash_set (&ipnw_db.ipnwdb_hash, &key, (uword) ipws, NULL);
144 : }
145 :
146 : void
147 3 : ip_neighbor_unwatch (const ip_address_t * ip,
148 : u32 sw_if_index,
149 : const ip_neighbor_watcher_t * watch)
150 : {
151 6 : ip_neighbor_key_t key = {
152 : .ipnk_ip = *ip,
153 3 : .ipnk_sw_if_index = (sw_if_index == 0 ? ~0 : sw_if_index),
154 : };
155 3 : ip_neighbor_watcher_t *ipws = NULL;
156 : uword *p;
157 : u32 pos;
158 :
159 3 : p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
160 :
161 3 : if (!p)
162 0 : return;
163 :
164 3 : ipws = (ip_neighbor_watcher_t*) p[0];
165 :
166 3 : pos = vec_search_with_function (ipws, watch, ip_neighbor_watch_cmp);
167 :
168 3 : if (~0 == pos)
169 0 : return;
170 :
171 3 : vec_del1 (ipws, pos);
172 :
173 3 : if (vec_len(ipws) == 0)
174 3 : mhash_unset (&ipnw_db.ipnwdb_hash, &key, NULL);
175 : }
176 :
177 : static void
178 46 : ip_neighbor_signal (ip_neighbor_watcher_t *watchers,
179 : index_t ipni,
180 : ip_neighbor_event_flags_t flags)
181 : {
182 : ip_neighbor_watcher_t *watcher;
183 :
184 92 : vec_foreach (watcher, watchers) {
185 : ip_neighbor_event_t *ipne;
186 :
187 46 : ipne = vlib_process_signal_event_data (vlib_get_main(),
188 46 : ip_neighbor_event_process_node.index,
189 : 0, 1, sizeof(*ipne));
190 46 : ipne->ipne_watch = *watcher;
191 46 : ipne->ipne_flags = flags;
192 46 : ip_neighbor_clone(ip_neighbor_get(ipni), &ipne->ipne_nbr);
193 : }
194 46 : }
195 :
196 : void
197 14781 : ip_neighbor_publish (index_t ipni,
198 : ip_neighbor_event_flags_t flags)
199 : {
200 : const ip_neighbor_t *ipn;
201 : ip_neighbor_key_t key;
202 : uword *p;
203 :
204 14781 : ipn = ip_neighbor_get (ipni);
205 :
206 14781 : clib_memcpy (&key, ipn->ipn_key, sizeof (key));
207 :
208 : /* Search the DB from longest to shortest key */
209 14781 : p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
210 :
211 14781 : if (p) {
212 1 : ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags);
213 : }
214 :
215 14781 : ip_address_reset (&key.ipnk_ip);
216 14781 : p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
217 :
218 14781 : if (p) {
219 2 : ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags);
220 : }
221 :
222 14781 : key.ipnk_sw_if_index = ~0;
223 14781 : p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
224 :
225 14781 : if (p) {
226 43 : ip_neighbor_signal ((ip_neighbor_watcher_t*) p[0], ipni, flags);
227 : }
228 14781 : }
229 :
230 : static clib_error_t *
231 2 : ip_neighbor_watchers_show (vlib_main_t * vm,
232 : unformat_input_t * input,
233 : vlib_cli_command_t * cmd)
234 : {
235 : ip_neighbor_watcher_t *watchers, *watcher;
236 : ip_neighbor_key_t *key;
237 : uword *v;
238 :
239 : /* *INDENT-OFF* */
240 142 : mhash_foreach(key, v, &ipnw_db.ipnwdb_hash,
241 : ({
242 : watchers = (ip_neighbor_watcher_t*) *v;
243 :
244 : ASSERT(vec_len(watchers));
245 : vlib_cli_output (vm, "Key: %U", format_ip_neighbor_key, key);
246 :
247 : vec_foreach (watcher, watchers)
248 : vlib_cli_output (vm, " %U", format_ip_neighbor_watcher, watcher);
249 : }));
250 : /* *INDENT-ON* */
251 2 : return (NULL);
252 : }
253 :
254 : /* *INDENT-OFF* */
255 272887 : VLIB_CLI_COMMAND (show_ip_neighbor_watchers_cmd_node, static) = {
256 : .path = "show ip neighbor-watcher",
257 : .function = ip_neighbor_watchers_show,
258 : .short_help = "show ip neighbors-watcher",
259 : };
260 : /* *INDENT-ON* */
261 :
262 : static clib_error_t *
263 559 : ip_neighbor_watch_init (vlib_main_t * vm)
264 : {
265 559 : mhash_init (&ipnw_db.ipnwdb_hash,
266 : sizeof (ip_neighbor_watcher_t *), sizeof (ip_neighbor_key_t));
267 559 : return (NULL);
268 : }
269 :
270 : /* *INDENT-OFF* */
271 47599 : VLIB_INIT_FUNCTION (ip_neighbor_watch_init) =
272 : {
273 : .runs_after = VLIB_INITS("ip_neighbor_init"),
274 : };
275 : /* *INDENT-ON* */
276 :
277 :
278 : /*
279 : * fd.io coding-style-patch-verification: ON
280 : *
281 : * Local Variables:
282 : * eval: (c-set-style "gnu")
283 : * End:
284 : */
|