Hybrid ICN (hICN) plugin  v21.06-rc0-4-g18fa668
mapme.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2020 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef __HICN_MAPME__
17 #define __HICN_MAPME__
18 
19 #include <vnet/dpo/load_balance.h>
20 #include <vnet/buffer.h>
21 #include <hicn/mapme.h>
22 
23 #include "hicn.h"
24 #include "route.h"
25 #include "strategy_dpo_ctx.h"
26 #include "strategy_dpo_manager.h" // dpo_is_hicn
27 
49 #define HICN_MAPME_ALLOW_LOCATORS 1
50 
51 //#define HICN_MAPME_NOTIFICATIONS 1
52 
53 #define NOT_A_NOTIFICATION false
54 #define TIMER_NO_REPEAT false
55 
56 #define INVALID_SEQ 0
57 
58 STATIC_ASSERT (sizeof (u32) == sizeof (seq_t), "seq_t is not 4 bytes");
59 
60 typedef struct hicn_mapme_conf_s
61 {
62  hicn_mapme_conf_t conf;
63  bool remove_dpo; // FIXME used ?
64 
65  vlib_main_t *vm;
66  vlib_log_class_t log_class;
68 
72 #define foreach_hicn_mapme_event \
73  _ (FACE_ADD) \
74  _ (FACE_DEL) \
75  _ (FACE_APP_ADD) \
76  _ (FACE_APP_DEL) \
77  _ (FACE_NH_SET) \
78  _ (FACE_NH_ADD) \
79  _ (FACE_PH_ADD) \
80  _ (FACE_PH_DEL)
81 
82 typedef enum
83 {
84 #define _(a) HICN_MAPME_EVENT_##a,
86 #undef _
87 } hicn_mapme_event_t;
88 
89 typedef hicn_dpo_ctx_t hicn_mapme_tfib_t;
90 
91 /*
92  * Ideally we might need to care about alignment, but this struct is only
93  * used for casting hicn_dpo_ctx_t.
94  *
95  * See otherwise vnet/dpo/dpo.h
96  */
97 
98 STATIC_ASSERT (sizeof (hicn_mapme_tfib_t) <= sizeof (hicn_dpo_ctx_t),
99  "hicn_mapme_tfib_t is greater than hicn_dpo_ctx_t");
100 
101 #define TFIB(dpo_ctx) ((hicn_mapme_tfib_t *) (dpo_ctx))
102 
103 static_always_inline int
104 hicn_mapme_nh_set (hicn_mapme_tfib_t *tfib, hicn_face_id_t face_id)
105 {
106  hicn_dpo_ctx_t *strategy_ctx = (hicn_dpo_ctx_t *) tfib;
107  const fib_prefix_t *prefix =
108  fib_entry_get_prefix (strategy_ctx->fib_entry_index);
109 
110  u32 n_entries = tfib->entry_count;
111  /* Remove all the existing next hops and set the new one */
112  for (int i = 0; i < n_entries; i++)
113  {
114  hicn_face_t *face = hicn_dpoi_get_from_idx (strategy_ctx->next_hops[0]);
115  ip_adjacency_t *adj = adj_get (face->dpo.dpoi_index);
116  ip_nh_del_helper (face->dpo.dpoi_proto, prefix,
117  &adj->sub_type.nbr.next_hop, face->sw_if);
118  }
119  hicn_face_t *face = hicn_dpoi_get_from_idx (face_id);
120  ip_nh_add_helper (face->dpo.dpoi_proto, prefix, &face->nat_addr,
121  face->sw_if);
122  return 0;
123 }
124 
128 static_always_inline int
129 hicn_mapme_nh_add (hicn_mapme_tfib_t *tfib, hicn_face_id_t face_id)
130 {
131  for (u8 pos = 0; pos < tfib->entry_count; pos++)
132  if (tfib->next_hops[pos] == face_id)
133  return 0;
134 
135  /* Add the next hop in the vrf 0 which will add it to the entry in the hICN
136  * vrf */
137  hicn_dpo_ctx_t *strategy_ctx = (hicn_dpo_ctx_t *) tfib;
138  const fib_prefix_t *prefix =
139  fib_entry_get_prefix (strategy_ctx->fib_entry_index);
140  hicn_face_t *face = hicn_dpoi_get_from_idx (face_id);
141  ip_nh_add_helper (face->dpo.dpoi_proto, prefix, &face->nat_addr,
142  face->sw_if);
143 
144  return 0;
145 }
146 
152 static_always_inline int
153 hicn_mapme_tfib_add (hicn_mapme_tfib_t *tfib, hicn_face_id_t face_id)
154 {
155  u8 pos = HICN_PARAM_FIB_ENTRY_NHOPS_MAX - tfib->tfib_entry_count;
156 
157  // XXX don 't add if it already exist
158  // eg.an old IU received on a face on which we are retransmitting
159  for (u8 pos2 = pos; pos2 < HICN_PARAM_FIB_ENTRY_NHOPS_MAX; pos2++)
160  if (tfib->next_hops[pos2] == face_id)
161  return 0;
162 
163  // Make sure we have enough room
164  if (pos <= tfib->entry_count)
165  return -1;
166 
167  tfib->next_hops[pos - 1] = face_id;
168  tfib->tfib_entry_count++;
169 
170  /*
171  * Take a lock on the face as if it will be removed from the next_hops a
172  * lock will be removed.
173  */
174  hicn_face_lock_with_id (face_id);
175 
176  return 0;
177 }
178 
179 static_always_inline int
180 hicn_mapme_tfib_clear (hicn_mapme_tfib_t *tfib)
181 {
182  hicn_face_id_t invalid = NEXT_HOP_INVALID;
183  /*
184  * We need to do a linear scan of TFIB entries to find the one to
185  * remove
186  */
187  u8 start_pos = HICN_PARAM_FIB_ENTRY_NHOPS_MAX - tfib->tfib_entry_count;
188  u8 pos = ~0;
189  for (pos = start_pos; pos < HICN_PARAM_FIB_ENTRY_NHOPS_MAX; pos++)
190  {
191  hicn_face_unlock_with_id (tfib->next_hops[pos]);
192  tfib->next_hops[pos] = invalid;
193  break;
194  }
195 
196  tfib->tfib_entry_count = 0;
197 
198  return 0;
199 }
200 
201 static_always_inline int
202 hicn_mapme_tfib_del (hicn_mapme_tfib_t *tfib, hicn_face_id_t face_id)
203 {
204  hicn_face_id_t invalid = NEXT_HOP_INVALID;
205  /*
206  * We need to do a linear scan of TFIB entries to find the one to
207  * remove
208  */
209  u8 start_pos = HICN_PARAM_FIB_ENTRY_NHOPS_MAX - tfib->tfib_entry_count;
210  u8 pos = ~0;
211  for (pos = start_pos; pos < HICN_PARAM_FIB_ENTRY_NHOPS_MAX; pos++)
212  if (tfib->next_hops[pos] == face_id)
213  {
214  hicn_face_unlock_with_id (tfib->next_hops[pos]);
215  tfib->next_hops[pos] = invalid;
216  break;
217  }
218  if (pos == HICN_PARAM_FIB_ENTRY_NHOPS_MAX)
219  /* Not found */
220  return -1;
221 
222  tfib->tfib_entry_count--;
223 
224  /* Likely we won't receive a new IU twice from the same face */
225  if (PREDICT_TRUE (pos > start_pos))
226  memmove (tfib->next_hops + start_pos + 1, tfib->next_hops + start_pos,
227  (pos - start_pos) * sizeof (hicn_face_id_t));
228 
229  return 0;
230 }
231 
236 static_always_inline dpo_id_t *
238 {
239  fib_prefix_t fib_pfx;
240  fib_node_index_t fib_entry_index;
241  u32 fib_index;
242  dpo_id_t *dpo_id;
243  load_balance_t *lb;
244 
245  const dpo_id_t *load_balance_dpo_id;
246 
247  /* At this point the face exists in the face table */
248  fib_prefix_from_ip46_addr (addr, &fib_pfx);
249  fib_pfx.fp_len = plen;
250 
251  /* Check if the route already exist in the fib : EPM */
252  fib_index = fib_table_find (fib_pfx.fp_proto, HICN_FIB_TABLE);
253 
254  fib_entry_index = fib_table_lookup_exact_match (fib_index, &fib_pfx);
255  if (fib_entry_index == FIB_NODE_INDEX_INVALID)
256  return NULL;
257 
258  load_balance_dpo_id = fib_entry_contribute_ip_forwarding (fib_entry_index);
259 
260  /* The dpo is not a load balance dpo as expected */
261  if (load_balance_dpo_id->dpoi_type != DPO_LOAD_BALANCE)
262  return NULL;
263 
264  /* former_dpo_id is a load_balance dpo */
265  lb = load_balance_get (load_balance_dpo_id->dpoi_index);
266 
267  /* Check if there is only one bucket */
268 
269  /*
270  * We now distinguish the case where we have an hICN route (the
271  * regular case), and the case where we have an IP route, to be able
272  * to apply MAP-Me mechanisms even to a locator IP address.
273  */
274 
275  for (int i = 0; i < lb->lb_n_buckets; i++)
276  {
277  /* un-const */
278  dpo_id = (dpo_id_t *) load_balance_get_bucket_i (lb, i);
279 
280  if (dpo_is_hicn (dpo_id))
281  return dpo_id;
282  }
283 
284  /* un-const */
285  return (dpo_id_t *) load_balance_dpo_id;
286 }
287 
288 /* DPO types */
289 
290 extern dpo_type_t hicn_face_udp_type;
291 extern dpo_type_t hicn_face_ip_type;
292 
293 /* VLIB EDGE IDs */
294 
295 /* in faces/ip/face_ip.c */
296 extern u32 strategy_face_ip4_vlib_edge;
297 extern u32 strategy_face_ip6_vlib_edge;
298 /* in faces/udp/face_udp.c */
299 extern u32 strategy_face_udp4_vlib_edge;
300 extern u32 strategy_face_udp6_vlib_edge;
301 
309 always_inline u32
311 {
312  if (dpo->dpoi_type == hicn_face_ip_type)
313  {
314  switch (dpo->dpoi_proto)
315  {
316  case DPO_PROTO_IP4:
317  return strategy_face_ip4_vlib_edge;
318  case DPO_PROTO_IP6:
319  return strategy_face_ip6_vlib_edge;
320  default:
321  return ~0;
322  }
323  }
324  else if (dpo->dpoi_type == hicn_face_udp_type)
325  {
326  switch (dpo->dpoi_proto)
327  {
328  case DPO_PROTO_IP4:
329  return strategy_face_udp4_vlib_edge;
330  case DPO_PROTO_IP6:
331  return strategy_face_udp6_vlib_edge;
332  default:
333  return ~0;
334  }
335  }
336  else
337  {
338  return ~0;
339  }
340 }
341 
345 always_inline char *
346 hicn_mapme_get_dpo_face_node (hicn_face_id_t face_id)
347 {
348  hicn_face_t *face = hicn_dpoi_get_from_idx (face_id);
349 
350  switch (face->dpo.dpoi_proto)
351  {
352  case DPO_PROTO_IP4:
353  return "hicn4-face-output";
354  case DPO_PROTO_IP6:
355  return "hicn6-face-output";
356  default:
357  return NULL;
358  }
359 }
360 
361 #define DEBUG(...) // vlib_log_debug(mapme_main.log_class, __VA_ARGS__)
362 #define WARN(...) // vlib_log_warn(mapme_main.log_class, __VA_ARGS__)
363 #define ERROR(...) // vlib_log_err(mapme_main.log_class, __VA_ARGS__)
364 
365 #endif /* __HICN_MAPME__ */
366 
367 /*
368  * fd.io coding-style-patch-verification: ON
369  *
370  * Local Variables: eval: (c-set-style "gnu") End:
371  */
route.h
dpo_is_hicn
u32 dpo_is_hicn(const dpo_id_t *dpo)
Check if the type of the dpo is among the list of hicn dpo types.
hicn_mapme_conf_t
MAP-Me configuration options.
Definition: mapme.h:33
hicn_mapme_get_dpo_face_node
always_inline char * hicn_mapme_get_dpo_face_node(hicn_face_id_t face_id)
Returns the next hop node on which we can send an Update packet.
Definition: mapme.h:346
hicn_mapme_get_dpo_vlib_edge
always_inline u32 hicn_mapme_get_dpo_vlib_edge(dpo_id_t *dpo)
Returns the next hop vlib edge on which we can send an Interest packet.
Definition: mapme.h:310
strategy_dpo_manager.h
hicn.h
fib_epm_lookup
static_always_inline dpo_id_t * fib_epm_lookup(ip46_address_t *addr, u8 plen)
Performs an Exact Prefix Match lookup on the FIB.
Definition: mapme.h:237
hicn_mapme_conf_s
Definition: mapme.h:60
strategy_dpo_ctx.h
hicn_dpoi_get_from_idx
always_inline hicn_face_t * hicn_dpoi_get_from_idx(hicn_face_id_t dpoi_index)
Return the face from the face id. Face id must be valid.
Definition: face.h:244
hicn_face_unlock_with_id
always_inline void hicn_face_unlock_with_id(hicn_face_id_t face_id)
Remove a lock to the face dpo. Deallocate the face id locks == 0.
Definition: face.h:278
hicn_mapme_nh_add
static_always_inline int hicn_mapme_nh_add(hicn_mapme_tfib_t *tfib, hicn_face_id_t face_id)
Add a next hop iif it is not already a next hops.
Definition: mapme.h:129
hicn_face_lock_with_id
always_inline void hicn_face_lock_with_id(hicn_face_id_t face_id)
Add a lock to the face dpo.
Definition: face.h:265
hicn_mapme_tfib_add
static_always_inline int hicn_mapme_tfib_add(hicn_mapme_tfib_t *tfib, hicn_face_id_t face_id)
Definition: mapme.h:153
ip_nh_del_helper
int ip_nh_del_helper(fib_protocol_t fib_proto, const fib_prefix_t *rpfx, ip46_address_t *nh, u32 sw_if)
ip_nh_add_helper
int ip_nh_add_helper(fib_protocol_t fib_proto, const fib_prefix_t *pfx, ip46_address_t *nh, u32 sw_if)
seq_t
u32 seq_t
MAP-Me update sequence number.
Definition: mapme.h:57
foreach_hicn_mapme_event
#define foreach_hicn_mapme_event
List of event to signat to the procesing node (eventmgr)
Definition: mapme.h:72
ip46_address_t
Definition: common.h:181