FD.io VPP  v20.05-21-gb1500e9ff
Vector Packet Processing
ip_neighbor_watch.c
Go to the documentation of this file.
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 
19 #include <vnet/ip/ip_types_api.h>
21 
22 #include <vnet/ip-neighbor/ip_neighbor.api_enum.h>
23 #include <vnet/ip-neighbor/ip_neighbor.api_types.h>
24 
25 #include <vlibmemory/api.h>
26 
27 /**
28  * Database of registered watchers
29  * The key for a watcher is {type, sw_if_index, addreess}
30  * interface=~0 / address=all-zeros imples any.
31  */
33 {
36 
38 
39 static uword
42 {
43  ip_neighbor_event_t *ipne, *ipnes = NULL;
44  uword event_type = ~0;
45 
46  while (1)
47  {
49 
50  ipnes = vlib_process_get_event_data (vm, &event_type);
51 
52  switch (event_type)
53  {
54  default:
55  vec_foreach (ipne, ipnes) ip_neighbor_handle_event (ipne);
56  break;
57 
58  case ~0:
59  /* timeout - */
60  break;
61  }
62 
63  vec_reset_length (ipnes);
64  }
65  return 0;
66 }
67 
68 /* *INDENT-OFF* */
70  .function = ip_neighbor_event_process,
71  .type = VLIB_NODE_TYPE_PROCESS,
72  .name = "ip-neighbor-event",
73 };
74 /* *INDENT-ON* */
75 
76 
77 static clib_error_t *
79 {
80  ip_neighbor_key_t *key, *empty_keys = NULL;
81  ip_neighbor_watcher_t *watchers;
82  uword *v;
83  i32 pos;
84 
85  /* walk the entire IP neighbour DB and removes the client's registrations */
86  /* *INDENT-OFF* */
87  mhash_foreach(key, v, &ipnw_db.ipnwdb_hash,
88  ({
89  watchers = (ip_neighbor_watcher_t*) *v;
90 
91  vec_foreach_index_backwards (pos, watchers) {
92  if (watchers[pos].ipw_client == client_index)
93  vec_del1(watchers, pos);
94  }
95 
96  if (vec_len(watchers) == 0)
97  vec_add1 (empty_keys, *key);
98  }));
99  /* *INDENT-OFF* */
100 
101  vec_foreach (key, empty_keys)
102  mhash_unset (&ipnw_db.ipnwdb_hash, key, NULL);
103  vec_free (empty_keys);
104  return (NULL);
105 }
106 
108 
109 static int
111  const ip_neighbor_watcher_t * w2)
112 {
113  return (0 == clib_memcmp (w1, w2, sizeof(*w1)));
114 }
115 
116 void
117 ip_neighbor_watch (const ip46_address_t * ip,
120  const ip_neighbor_watcher_t * watch)
121 {
123  .ipnk_ip = *ip,
124  .ipnk_sw_if_index = (sw_if_index == 0 ? ~0 : sw_if_index),
125  .ipnk_type = type,
126  };
127  ip_neighbor_watcher_t *ipws = NULL;
128  uword *p;
129 
130  p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
131 
132  if (p)
133  {
134  ipws = (ip_neighbor_watcher_t*) p[0];
135 
136  if (~0 != vec_search_with_function (ipws, watch,
138  /* duplicate */
139  return;
140  }
141 
142  vec_add1 (ipws, *watch);
143 
144  mhash_set (&ipnw_db.ipnwdb_hash, &key, (uword) ipws, NULL);
145 }
146 
147 void
148 ip_neighbor_unwatch (const ip46_address_t * ip,
151  const ip_neighbor_watcher_t * watch)
152 {
154  .ipnk_ip = *ip,
155  .ipnk_sw_if_index = (sw_if_index == 0 ? ~0 : sw_if_index),
156  .ipnk_type = type,
157  };
158  ip_neighbor_watcher_t *ipws = NULL;
159  uword *p;
160  u32 pos;
161 
162  p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
163 
164  if (!p)
165  return;
166 
167  ipws = (ip_neighbor_watcher_t*) p[0];
168 
169  pos = vec_search_with_function (ipws, watch, ip_neighbor_watch_cmp);
170 
171  if (~0 == pos)
172  return;
173 
174  vec_del1 (ipws, pos);
175 
176  if (vec_len(ipws) == 0)
177  mhash_unset (&ipnw_db.ipnwdb_hash, &key, NULL);
178 }
179 
180 static void
182 {
183  ip_neighbor_watcher_t *watcher;
184 
185  vec_foreach (watcher, watchers) {
186  ip_neighbor_event_t *ipne;
187 
190  0, 1, sizeof(*ipne));
191  ipne->ipne_watch = *watcher;
192  ipne->ipne_index = ipni;
193  }
194 }
195 
196 void
198 {
199  const ip_neighbor_t *ipn;
201  uword *p;
202 
203  ipn = ip_neighbor_get (ipni);
204 
205  clib_memcpy (&key, ipn->ipn_key, sizeof (key));
206 
207  /* Search the DB from longest to shortest key */
208  p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
209 
210  if (p) {
212  }
213 
215  p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
216 
217  if (p) {
219  }
220 
221  key.ipnk_sw_if_index = ~0;
222  p = mhash_get (&ipnw_db.ipnwdb_hash, &key);
223 
224  if (p) {
226  }
227 }
228 
229 static clib_error_t *
231  unformat_input_t * input,
232  vlib_cli_command_t * cmd)
233 {
234  ip_neighbor_watcher_t *watchers, *watcher;
236  uword *v;
237 
238  /* *INDENT-OFF* */
239  mhash_foreach(key, v, &ipnw_db.ipnwdb_hash,
240  ({
241  watchers = (ip_neighbor_watcher_t*) *v;
242 
243  ASSERT(vec_len(watchers));
244  vlib_cli_output (vm, "Key: %U", format_ip_neighbor_key, key);
245 
246  vec_foreach (watcher, watchers)
247  vlib_cli_output (vm, " %U", format_ip_neighbor_watcher, watcher);
248  }));
249  /* *INDENT-ON* */
250  return (NULL);
251 }
252 
253 /* *INDENT-OFF* */
254 VLIB_CLI_COMMAND (show_ip_neighbor_watchers_cmd_node, static) = {
255  .path = "show ip neighbor-watcher",
256  .function = ip_neighbor_watchers_show,
257  .short_help = "show ip neighbors-watcher",
258 };
259 /* *INDENT-ON* */
260 
261 static clib_error_t *
263 {
264  mhash_init (&ipnw_db.ipnwdb_hash,
265  sizeof (ip_neighbor_watcher_t *), sizeof (ip_neighbor_key_t));
266  return (NULL);
267 }
268 
269 /* *INDENT-OFF* */
271 {
272  .runs_after = VLIB_INITS("ip_neighbor_init"),
273 };
274 /* *INDENT-ON* */
275 
276 
277 /*
278  * fd.io coding-style-patch-verification: ON
279  *
280  * Local Variables:
281  * eval: (c-set-style "gnu")
282  * End:
283  */
static clib_error_t * want_ip_neighbor_events_reaper(u32 client_index)
static uword ip_neighbor_event_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: mhash.h:46
static int ip_neighbor_watch_cmp(const ip_neighbor_watcher_t *w1, const ip_neighbor_watcher_t *w2)
static clib_error_t * ip_neighbor_watch_init(vlib_main_t *vm)
vlib_node_registration_t ip_neighbor_event_process_node
(constructor) VLIB_REGISTER_NODE (ip_neighbor_event_process_node)
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
Definition: node_funcs.h:593
ip46_address_t ipnk_ip
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:346
struct ip_neighbor_watch_db_t_ ip_neighbor_watch_db_t
Database of registered watchers The key for a watcher is {type, sw_if_index, addreess} interface=~0 /...
#define mhash_foreach(k, v, mh, body)
Definition: mhash.h:159
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:590
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
#define clib_memcpy(d, s, n)
Definition: string.h:180
static void ip46_address_reset(ip46_address_t *ip46)
Definition: ip46_address.h:74
vl_api_interface_index_t sw_if_index
Definition: gre.api:53
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
void ip_neighbor_publish(index_t ipni)
A representation of an IP neighbour/peer.
unsigned int u32
Definition: types.h:88
VL_MSG_API_REAPER_FUNCTION(want_ip_neighbor_events_reaper)
void ip_neighbor_watch(const ip46_address_t *ip, ip46_type_t type, u32 sw_if_index, const ip_neighbor_watcher_t *watch)
static void ip_neighbor_signal(ip_neighbor_watcher_t *watchers, index_t ipni)
vl_api_fib_path_type_t type
Definition: fib_types.api:123
struct _unformat_input_t unformat_input_t
Database of registered watchers The key for a watcher is {type, sw_if_index, addreess} interface=~0 /...
static void * vlib_process_signal_event_data(vlib_main_t *vm, uword node_index, uword type_opaque, uword n_data_elts, uword n_data_elt_bytes)
Definition: node_funcs.h:828
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:873
void ip_neighbor_handle_event(const ip_neighbor_event_t *ipne)
From the watcher to the API to publish a new neighbor.
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
vlib_main_t * vm
Definition: in2out_ed.c:1599
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
#define clib_memcmp(s1, s2, m1)
Definition: string.h:737
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
static ip_neighbor_watch_db_t ipnw_db
#define vec_search_with_function(v, E, fn)
Search a vector for the index of the entry that matches.
Definition: vec.h:1031
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:152
signed int i32
Definition: types.h:77
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
ip_neighbor_key_t * ipn_key
The idempotent key.
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
typedef key
Definition: ipsec_types.api:85
static void * vlib_process_get_event_data(vlib_main_t *vm, uword *return_event_type_opaque)
Definition: node_funcs.h:463
vl_api_address_t ip
Definition: l2.api:501
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
ip_neighbor_t * ip_neighbor_get(index_t ipni)
Definition: ip_neighbor.c:88
#define vec_foreach(var, vec)
Vector iterator.
static clib_error_t * ip_neighbor_watchers_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define VLIB_INITS(...)
Definition: init.h:344
ip_neighbor_watcher_t ipne_watch
ip46_type_t
Definition: ip46_address.h:22
void ip_neighbor_unwatch(const ip46_address_t *ip, ip46_type_t type, u32 sw_if_index, const ip_neighbor_watcher_t *watch)