Line data Source code
1 : /*
2 : * Copyright (c) 2016 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 : * An adjacency is a representation of an attached L3 peer.
17 : *
18 : * Adjacency Sub-types:
19 : * - neighbour: a representation of an attached L3 peer.
20 : * Key:{addr,interface,link/ether-type}
21 : * SHARED
22 : * - glean: used to drive ARP/ND for packets destined to a local sub-net.
23 : * 'glean' mean use the packet's destination address as the target
24 : * address in the ARP packet.
25 : * UNSHARED. Only one per-interface.
26 : * - midchain: a neighbour adj on a virtual/tunnel interface.
27 : *
28 : * The API to create and update the adjacency is very sub-type specific. This
29 : * is intentional as it encourages the user to carefully consider which adjacency
30 : * sub-type they are really using, and hence assign it data in the appropriate
31 : * sub-type space in the union of sub-types. This prevents the adj becoming a
32 : * disorganised dumping group for 'my features needs a u16 somewhere' data. It
33 : * is important to enforce this approach as space in the adjacency is a premium,
34 : * as we need it to fit in 1 cache line.
35 : *
36 : * the API is also based around an index to an adjacency not a raw pointer. This
37 : * is so the user doesn't suffer the same limp inducing firearm injuries that
38 : * the author suffered as the adjacencies can realloc.
39 : */
40 :
41 : #ifndef __ADJ_H__
42 : #define __ADJ_H__
43 :
44 : #include <vnet/adj/adj_types.h>
45 : #include <vnet/adj/adj_nbr.h>
46 : #include <vnet/adj/adj_glean.h>
47 : #include <vnet/adj/rewrite.h>
48 :
49 : /** @brief Common (IP4/IP6) next index stored in adjacency. */
50 : typedef enum
51 : {
52 : /** Adjacency to drop this packet. */
53 : IP_LOOKUP_NEXT_DROP,
54 : /** Adjacency to punt this packet. */
55 : IP_LOOKUP_NEXT_PUNT,
56 :
57 : /** This packet is for one of our own IP addresses. */
58 : IP_LOOKUP_NEXT_LOCAL,
59 :
60 : /** This packet matches an "incomplete adjacency" and packets
61 : need to be passed to ARP to find rewrite string for
62 : this destination. */
63 : IP_LOOKUP_NEXT_ARP,
64 :
65 : /** This packet matches an "interface route" and packets
66 : need to be passed to ARP to find rewrite string for
67 : this destination. */
68 : IP_LOOKUP_NEXT_GLEAN,
69 :
70 : /** This packet is to be rewritten and forwarded to the next
71 : processing node. This is typically the output interface but
72 : might be another node for further output processing. */
73 : IP_LOOKUP_NEXT_REWRITE,
74 :
75 : /** This packets follow a mid-chain adjacency */
76 : IP_LOOKUP_NEXT_MIDCHAIN,
77 :
78 : /** This packets needs to go to ICMP error */
79 : IP_LOOKUP_NEXT_ICMP_ERROR,
80 :
81 : /** Multicast Adjacency. */
82 : IP_LOOKUP_NEXT_MCAST,
83 :
84 : /** Broadcast Adjacency. */
85 : IP_LOOKUP_NEXT_BCAST,
86 :
87 : /** Multicast Midchain Adjacency. An Adjacency for sending multicast packets
88 : * on a tunnel/virtual interface */
89 : IP_LOOKUP_NEXT_MCAST_MIDCHAIN,
90 :
91 : IP_LOOKUP_N_NEXT,
92 : } __attribute__ ((packed)) ip_lookup_next_t;
93 :
94 : typedef enum
95 : {
96 : IP4_LOOKUP_N_NEXT = IP_LOOKUP_N_NEXT,
97 : } ip4_lookup_next_t;
98 :
99 : typedef enum
100 : {
101 : /* Hop-by-hop header handling */
102 : IP6_LOOKUP_NEXT_HOP_BY_HOP = IP_LOOKUP_N_NEXT,
103 : IP6_LOOKUP_NEXT_ADD_HOP_BY_HOP,
104 : IP6_LOOKUP_NEXT_POP_HOP_BY_HOP,
105 : IP6_LOOKUP_N_NEXT,
106 : } ip6_lookup_next_t;
107 :
108 : #define IP4_LOOKUP_NEXT_NODES { \
109 : [IP_LOOKUP_NEXT_DROP] = "ip4-drop", \
110 : [IP_LOOKUP_NEXT_PUNT] = "ip4-punt", \
111 : [IP_LOOKUP_NEXT_LOCAL] = "ip4-local", \
112 : [IP_LOOKUP_NEXT_ARP] = "ip4-arp", \
113 : [IP_LOOKUP_NEXT_GLEAN] = "ip4-glean", \
114 : [IP_LOOKUP_NEXT_REWRITE] = "ip4-rewrite", \
115 : [IP_LOOKUP_NEXT_MCAST] = "ip4-rewrite-mcast", \
116 : [IP_LOOKUP_NEXT_BCAST] = "ip4-rewrite-bcast", \
117 : [IP_LOOKUP_NEXT_MIDCHAIN] = "ip4-midchain", \
118 : [IP_LOOKUP_NEXT_MCAST_MIDCHAIN] = "ip4-mcast-midchain", \
119 : [IP_LOOKUP_NEXT_ICMP_ERROR] = "ip4-icmp-error", \
120 : }
121 :
122 : #define IP6_LOOKUP_NEXT_NODES { \
123 : [IP_LOOKUP_NEXT_DROP] = "ip6-drop", \
124 : [IP_LOOKUP_NEXT_PUNT] = "ip6-punt", \
125 : [IP_LOOKUP_NEXT_LOCAL] = "ip6-local", \
126 : [IP_LOOKUP_NEXT_ARP] = "ip6-discover-neighbor", \
127 : [IP_LOOKUP_NEXT_GLEAN] = "ip6-glean", \
128 : [IP_LOOKUP_NEXT_REWRITE] = "ip6-rewrite", \
129 : [IP_LOOKUP_NEXT_BCAST] = "ip6-rewrite-bcast", \
130 : [IP_LOOKUP_NEXT_MCAST] = "ip6-rewrite-mcast", \
131 : [IP_LOOKUP_NEXT_MIDCHAIN] = "ip6-midchain", \
132 : [IP_LOOKUP_NEXT_MCAST_MIDCHAIN] = "ip6-mcast-midchain", \
133 : [IP_LOOKUP_NEXT_ICMP_ERROR] = "ip6-icmp-error", \
134 : [IP6_LOOKUP_NEXT_HOP_BY_HOP] = "ip6-hop-by-hop", \
135 : [IP6_LOOKUP_NEXT_ADD_HOP_BY_HOP] = "ip6-add-hop-by-hop", \
136 : [IP6_LOOKUP_NEXT_POP_HOP_BY_HOP] = "ip6-pop-hop-by-hop", \
137 : }
138 :
139 : /**
140 : * The special broadcast address (to construct a broadcast adjacency
141 : */
142 : extern const ip46_address_t ADJ_BCAST_ADDR;
143 :
144 : /**
145 : * Forward declaration
146 : */
147 : struct ip_adjacency_t_;
148 :
149 : /**
150 : * @brief A function type for post-rewrite fixups on midchain adjacency
151 : */
152 : typedef void (*adj_midchain_fixup_t) (vlib_main_t * vm,
153 : const struct ip_adjacency_t_ * adj,
154 : vlib_buffer_t * b0,
155 : const void *data);
156 :
157 : /**
158 : * @brief Flags on an IP adjacency
159 : */
160 : typedef enum adj_attr_t_
161 : {
162 : /**
163 : * Currently a sync walk is active. Used to prevent re-entrant walking
164 : */
165 : ADJ_ATTR_SYNC_WALK_ACTIVE = 0,
166 :
167 : /**
168 : * When stacking midchains on a fib-entry extract the choice from the
169 : * load-balance returned based on an IP hash of the adj's rewrite
170 : */
171 : ADJ_ATTR_MIDCHAIN_IP_STACK,
172 : /**
173 : * If the midchain were to stack on its FIB entry a loop would form.
174 : */
175 : ADJ_ATTR_MIDCHAIN_LOOPED,
176 : /**
177 : * the fixup function is standard IP4o4 header
178 : */
179 : ADJ_ATTR_MIDCHAIN_FIXUP_IP4O4_HDR,
180 : /**
181 : * the fixup function performs the flow hash
182 : * this means the flow hash is performed on the inner
183 : * header, where the entropy is higher.
184 : */
185 : ADJ_ATTR_MIDCHAIN_FIXUP_FLOW_HASH,
186 : } adj_attr_t;
187 :
188 : #define ADJ_ATTR_NAMES { \
189 : [ADJ_ATTR_SYNC_WALK_ACTIVE] = "walk-active", \
190 : [ADJ_ATTR_MIDCHAIN_IP_STACK] = "midchain-ip-stack", \
191 : [ADJ_ATTR_MIDCHAIN_LOOPED] = "midchain-looped", \
192 : [ADJ_ATTR_MIDCHAIN_FIXUP_IP4O4_HDR] = "midchain-ip4o4-hdr-fixup", \
193 : [ADJ_ATTR_MIDCHAIN_FIXUP_FLOW_HASH] = "midchain-flow-hash", \
194 : }
195 :
196 : #define FOR_EACH_ADJ_ATTR(_attr) \
197 : for (_attr = ADJ_ATTR_SYNC_WALK_ACTIVE; \
198 : _attr <= ADJ_ATTR_MIDCHAIN_FIXUP_FLOW_HASH; \
199 : _attr++)
200 :
201 : /**
202 : * @brief Flags on an IP adjacency
203 : */
204 : typedef enum adj_flags_t_
205 : {
206 : ADJ_FLAG_NONE = 0,
207 : ADJ_FLAG_SYNC_WALK_ACTIVE = (1 << ADJ_ATTR_SYNC_WALK_ACTIVE),
208 : ADJ_FLAG_MIDCHAIN_IP_STACK = (1 << ADJ_ATTR_MIDCHAIN_IP_STACK),
209 : ADJ_FLAG_MIDCHAIN_LOOPED = (1 << ADJ_ATTR_MIDCHAIN_LOOPED),
210 : ADJ_FLAG_MIDCHAIN_FIXUP_IP4O4_HDR = (1 << ADJ_ATTR_MIDCHAIN_FIXUP_IP4O4_HDR),
211 : ADJ_FLAG_MIDCHAIN_FIXUP_FLOW_HASH = (1 << ADJ_ATTR_MIDCHAIN_FIXUP_FLOW_HASH),
212 : } __attribute__ ((packed)) adj_flags_t;
213 :
214 : /**
215 : * @brief Format adjacency flags
216 : */
217 : extern u8* format_adj_flags(u8 * s, va_list * args);
218 :
219 : /**
220 : * @brief IP unicast adjacency.
221 : * @note cache aligned.
222 : *
223 : * An adjacency is a representation of a peer on a particular link.
224 : */
225 : typedef struct ip_adjacency_t_
226 : {
227 : CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
228 :
229 : /**
230 : * Linkage into the FIB node graph. First member since this type
231 : * has 8 byte alignment requirements.
232 : */
233 : fib_node_t ia_node;
234 : /**
235 : * feature [arc] config index
236 : */
237 : u32 ia_cfg_index;
238 :
239 : union
240 : {
241 : /**
242 : * IP_LOOKUP_NEXT_ARP/IP_LOOKUP_NEXT_REWRITE
243 : *
244 : * neighbour adjacency sub-type;
245 : */
246 : struct
247 : {
248 : ip46_address_t next_hop;
249 : } nbr;
250 : /**
251 : * IP_LOOKUP_NEXT_MIDCHAIN
252 : *
253 : * A nbr adj that is also recursive. Think tunnels.
254 : * A nbr adj can transition to be of type MIDCHAIN
255 : * so be sure to leave the two structs with the next_hop
256 : * fields aligned.
257 : */
258 : struct
259 : {
260 : /**
261 : * The recursive next-hop.
262 : * This field MUST be at the same memory location as
263 : * sub_type.nbr.next_hop
264 : */
265 : ip46_address_t next_hop;
266 : /**
267 : * The next DPO to use
268 : */
269 : dpo_id_t next_dpo;
270 : /**
271 : * A function to perform the post-rewrite fixup
272 : */
273 : adj_midchain_fixup_t fixup_func;
274 : /**
275 : * Fixup data passed back to the client in the fixup function
276 : */
277 : const void *fixup_data;
278 : /**
279 : * the FIB entry this midchain resolves through. required for recursive
280 : * loop detection.
281 : */
282 : fib_node_index_t fei;
283 :
284 : /** spare space */
285 : u8 __ia_midchain_pad[4];
286 :
287 : } midchain;
288 : /**
289 : * IP_LOOKUP_NEXT_GLEAN
290 : *
291 : * Glean the address to ARP for from the packet's destination.
292 : * Technically these aren't adjacencies, i.e. they are not a
293 : * representation of a peer. One day we might untangle this coupling
294 : * and use a new Glean DPO.
295 : */
296 : struct
297 : {
298 : fib_prefix_t rx_pfx;
299 : } glean;
300 : } sub_type;
301 :
302 : CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
303 :
304 : /** Rewrite in second and third cache lines */
305 : VNET_DECLARE_REWRITE;
306 :
307 : /**
308 : * more control plane members that do not fit on the first cacheline
309 : */
310 : CLIB_CACHE_LINE_ALIGN_MARK (cacheline3);
311 :
312 : /**
313 : * A sorted vector of delegates
314 : */
315 : struct adj_delegate_t_ *ia_delegates;
316 :
317 : /**
318 : * The VLIB node in which this adj is used to forward packets
319 : */
320 : u32 ia_node_index;
321 :
322 : /**
323 : * Next hop after ip4-lookup.
324 : * This is not accessed in the rewrite nodes.
325 : * 1-bytes
326 : */
327 : ip_lookup_next_t lookup_next_index;
328 :
329 : /**
330 : * link/ether-type
331 : * 1 bytes
332 : */
333 : vnet_link_t ia_link;
334 :
335 : /**
336 : * The protocol of the neighbor/peer. i.e. the protocol with
337 : * which to interpret the 'next-hop' attributes of the sub-types.
338 : * 1-bytes
339 : */
340 : fib_protocol_t ia_nh_proto;
341 :
342 : /**
343 : * Flags on the adjacency
344 : * 1-bytes
345 : */
346 : adj_flags_t ia_flags;
347 :
348 : /**
349 : * Free space on the fourth cacheline (not used in the DP)
350 : */
351 : u8 __ia_pad[48];
352 : } ip_adjacency_t;
353 :
354 : STATIC_ASSERT ((STRUCT_OFFSET_OF (ip_adjacency_t, cacheline0) == 0),
355 : "IP adjacency cacheline 0 is not offset");
356 : STATIC_ASSERT ((STRUCT_OFFSET_OF (ip_adjacency_t, cacheline1) ==
357 : CLIB_CACHE_LINE_BYTES),
358 : "IP adjacency cacheline 1 is more than one cacheline size offset");
359 : #if defined __x86_64__
360 : STATIC_ASSERT ((STRUCT_OFFSET_OF (ip_adjacency_t, cacheline3) ==
361 : 3 * CLIB_CACHE_LINE_BYTES),
362 : "IP adjacency cacheline 3 is more than one cacheline size offset");
363 : /* An adj fits into 4 cachelines on your average machine */
364 : STATIC_ASSERT_SIZEOF (ip_adjacency_t, 4 * 64);
365 : #endif
366 : STATIC_ASSERT ((STRUCT_OFFSET_OF (ip_adjacency_t, sub_type.nbr.next_hop) ==
367 : STRUCT_OFFSET_OF (ip_adjacency_t, sub_type.midchain.next_hop)),
368 : "IP adjacency nbr and midchain offsets don't match");
369 :
370 : /**
371 : * @brief
372 : * Take a reference counting lock on the adjacency
373 : */
374 : extern void adj_lock(adj_index_t adj_index);
375 : /**
376 : * @brief
377 : * Release a reference counting lock on the adjacency
378 : */
379 : extern void adj_unlock(adj_index_t adj_index);
380 :
381 : /**
382 : * @brief
383 : * Add a child dependent to an adjacency. The child will
384 : * thus be informed via its registered back-walk function
385 : * when the adjacency state changes.
386 : */
387 : extern u32 adj_child_add(adj_index_t adj_index,
388 : fib_node_type_t type,
389 : fib_node_index_t child_index);
390 : /**
391 : * @brief
392 : * Remove a child dependent
393 : */
394 : extern void adj_child_remove(adj_index_t adj_index,
395 : u32 sibling_index);
396 :
397 : /**
398 : * @brief Walk the Adjacencies on a given interface
399 : */
400 : extern void adj_walk (u32 sw_if_index,
401 : adj_walk_cb_t cb,
402 : void *ctx);
403 :
404 : /**
405 : * @brief Return the link type of the adjacency
406 : */
407 : extern vnet_link_t adj_get_link_type (adj_index_t ai);
408 :
409 : /**
410 : * @brief Return the sw interface index of the adjacency.
411 : */
412 : extern u32 adj_get_sw_if_index (adj_index_t ai);
413 :
414 : /**
415 : * @brief Return true if the adjacency is 'UP', i.e. can be used for forwarding.
416 : * 0 is down, !0 is up.
417 : */
418 : extern int adj_is_up (adj_index_t ai);
419 :
420 : /**
421 : * @brief Return the link type of the adjacency
422 : */
423 : extern const u8* adj_get_rewrite (adj_index_t ai);
424 :
425 : /**
426 : * @brief descend the FIB graph looking for loops
427 : *
428 : * @param ai
429 : * The adj index to traverse
430 : *
431 : * @param entry_indicies)
432 : * A pointer to a vector of FIB entries already visited.
433 : */
434 : extern int adj_recursive_loop_detect (adj_index_t ai,
435 : fib_node_index_t **entry_indicies);
436 :
437 : /**
438 : * @brief
439 : * The global adjacency pool. Exposed for fast/inline data-plane access
440 : */
441 : extern ip_adjacency_t *adj_pool;
442 :
443 : /**
444 : * @brief
445 : * Adjacency packet counters
446 : */
447 : extern vlib_combined_counter_main_t adjacency_counters;
448 :
449 : /**
450 : * @brief Global Config for enabling per-adjacency counters
451 : * This is configurable because it comes with a non-negligible
452 : * performance cost. */
453 : extern int adj_per_adj_counters;
454 :
455 : /**
456 : * @brief
457 : * Get a pointer to an adjacency object from its index
458 : */
459 : static inline ip_adjacency_t *
460 19682239 : adj_get (adj_index_t adj_index)
461 : {
462 19682239 : return (pool_elt_at_index(adj_pool, adj_index));
463 : }
464 :
465 : static inline int
466 347048 : adj_is_valid(adj_index_t adj_index)
467 : {
468 347048 : return !(pool_is_free_index(adj_pool, adj_index));
469 : }
470 :
471 : /**
472 : * @brief Get the global configuration option for enabling per-adj counters
473 : */
474 : static inline int
475 441697 : adj_are_counters_enabled (void)
476 : {
477 441697 : return (adj_per_adj_counters);
478 : }
479 :
480 : #endif
|