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 : * @brief
17 : * A Data-Path Object is an object that represents actions that are
18 : * applied to packets are they are switched through VPP's data-path.
19 : *
20 : * The DPO can be considered to be like is a base class that is specialised
21 : * by other objects to provide concreate actions
22 : *
23 : * The VLIB graph nodes are graph of DPO types, the DPO graph is a graph of
24 : * instances.
25 : */
26 :
27 : // clang-format off
28 :
29 : #ifndef __DPO_H__
30 : #define __DPO_H__
31 :
32 : #include <vnet/vnet.h>
33 :
34 : /**
35 : * @brief An index for adjacencies.
36 : * Alas 'C' is not typesafe enough to b0rk when a u32 is used instead of
37 : * an index_t. However, for us humans, we can glean much more intent
38 : * from the declaration
39 : * foo barindex_t t);
40 : * than we can from
41 : * foo bar(u32 t);
42 : */
43 : typedef u32 index_t;
44 :
45 : /**
46 : * @brief Invalid index - used when no index is known
47 : * blazoned capitals INVALID speak volumes where ~0 does not.
48 : */
49 : #define INDEX_INVALID ((index_t)(~0))
50 :
51 : /**
52 : * @brief Data path protocol.
53 : * Actions performed on packets in the data-plane can be described and represented
54 : * by protocol independent objects, i.e. ADJACENCY, but the spceifics actions
55 : * required during ADJACENCY processing can be protocol dependent. For example,
56 : * the adjacency rewrite node performs a ip4 checksum calculation, ip6 and MPLS
57 : * do not, all 3 perform a TTL decrement. The VLIB graph nodes are thus protocol
58 : * dependent, and thus each graph edge/arc is too.
59 : * When programming a DPO's next node arc from child to parent it is thus required
60 : * to know the parent's data-path protocol so the correct arc index can be used.
61 : */
62 : typedef enum dpo_proto_t_
63 : {
64 : DPO_PROTO_IP4 = 0,
65 : DPO_PROTO_IP6,
66 : DPO_PROTO_MPLS,
67 : DPO_PROTO_ETHERNET,
68 : DPO_PROTO_BIER,
69 : DPO_PROTO_NSH,
70 : } __attribute__((packed)) dpo_proto_t;
71 :
72 : #define DPO_PROTO_NUM ((dpo_proto_t)(DPO_PROTO_NSH+1))
73 : #define DPO_PROTO_NONE ((dpo_proto_t)(DPO_PROTO_NUM+1))
74 :
75 : #define DPO_PROTOS { \
76 : [DPO_PROTO_IP4] = "ip4", \
77 : [DPO_PROTO_IP6] = "ip6", \
78 : [DPO_PROTO_ETHERNET] = "ethernet", \
79 : [DPO_PROTO_MPLS] = "mpls", \
80 : [DPO_PROTO_NSH] = "nsh", \
81 : [DPO_PROTO_BIER] = "bier", \
82 : }
83 :
84 : #define FOR_EACH_DPO_PROTO(_proto) \
85 : for (_proto = DPO_PROTO_IP4; \
86 : _proto <= DPO_PROTO_NSH; \
87 : _proto++)
88 :
89 : /**
90 : * @brief Common types of data-path objects
91 : * New types can be dynamically added using dpo_register_new_type()
92 : */
93 : typedef enum dpo_type_t_ {
94 : /**
95 : * A non-zero value first so we can spot unitialisation errors
96 : */
97 : DPO_FIRST,
98 : DPO_DROP,
99 : DPO_IP_NULL,
100 : DPO_PUNT,
101 : /**
102 : * @brief load-balancing over a choice of [un]equal cost paths
103 : */
104 : DPO_LOAD_BALANCE,
105 : DPO_REPLICATE,
106 : DPO_ADJACENCY,
107 : DPO_ADJACENCY_INCOMPLETE,
108 : DPO_ADJACENCY_MIDCHAIN,
109 : DPO_ADJACENCY_GLEAN,
110 : DPO_ADJACENCY_MCAST,
111 : DPO_ADJACENCY_MCAST_MIDCHAIN,
112 : DPO_RECEIVE,
113 : DPO_LOOKUP,
114 : DPO_LISP_CP,
115 : DPO_CLASSIFY,
116 : DPO_MPLS_DISPOSITION_PIPE,
117 : DPO_MPLS_DISPOSITION_UNIFORM,
118 : DPO_MFIB_ENTRY,
119 : DPO_INTERFACE_RX,
120 : DPO_INTERFACE_TX,
121 : DPO_DVR,
122 : DPO_L3_PROXY,
123 : DPO_BIER_TABLE,
124 : DPO_BIER_FMASK,
125 : DPO_BIER_IMP,
126 : DPO_BIER_DISP_TABLE,
127 : DPO_BIER_DISP_ENTRY,
128 : DPO_IP6_LL,
129 : DPO_PW_CW,
130 : DPO_LAST,
131 : } __attribute__((packed)) dpo_type_t;
132 :
133 : #define DPO_TYPE_NUM DPO_LAST
134 :
135 : #define DPO_TYPES { \
136 : [DPO_FIRST] = "dpo-invalid", \
137 : [DPO_DROP] = "dpo-drop", \
138 : [DPO_IP_NULL] = "dpo-ip-null", \
139 : [DPO_PUNT] = "dpo-punt", \
140 : [DPO_ADJACENCY] = "dpo-adjacency", \
141 : [DPO_ADJACENCY_INCOMPLETE] = "dpo-adjacency-incomplete", \
142 : [DPO_ADJACENCY_MIDCHAIN] = "dpo-adjacency-midcahin", \
143 : [DPO_ADJACENCY_GLEAN] = "dpo-glean", \
144 : [DPO_ADJACENCY_MCAST] = "dpo-adj-mcast", \
145 : [DPO_ADJACENCY_MCAST_MIDCHAIN] = "dpo-adj-mcast-midchain", \
146 : [DPO_RECEIVE] = "dpo-receive", \
147 : [DPO_LOOKUP] = "dpo-lookup", \
148 : [DPO_LOAD_BALANCE] = "dpo-load-balance", \
149 : [DPO_REPLICATE] = "dpo-replicate", \
150 : [DPO_LISP_CP] = "dpo-lisp-cp", \
151 : [DPO_CLASSIFY] = "dpo-classify", \
152 : [DPO_MPLS_DISPOSITION_PIPE] = "dpo-mpls-diposition-pipe", \
153 : [DPO_MPLS_DISPOSITION_UNIFORM] = "dpo-mpls-diposition-uniform", \
154 : [DPO_MFIB_ENTRY] = "dpo-mfib-entry", \
155 : [DPO_INTERFACE_RX] = "dpo-interface-rx", \
156 : [DPO_INTERFACE_TX] = "dpo-interface-tx", \
157 : [DPO_DVR] = "dpo-dvr", \
158 : [DPO_L3_PROXY] = "dpo-l3-proxy", \
159 : [DPO_BIER_TABLE] = "bier-table", \
160 : [DPO_BIER_FMASK] = "bier-fmask", \
161 : [DPO_BIER_IMP] = "bier-imposition", \
162 : [DPO_BIER_DISP_ENTRY] = "bier-disp-entry", \
163 : [DPO_BIER_DISP_TABLE] = "bier-disp-table", \
164 : [DPO_IP6_LL] = "ip6-link-local", \
165 : [DPO_PW_CW] = "PW-CW", \
166 : }
167 :
168 : /**
169 : * @brief The identity of a DPO is a combination of its type and its
170 : * instance number/index of objects of that type
171 : */
172 : typedef struct dpo_id_t_ {
173 : union {
174 : struct {
175 : /**
176 : * the type
177 : */
178 : dpo_type_t dpoi_type;
179 : /**
180 : * the data-path protocol of the type.
181 : */
182 : dpo_proto_t dpoi_proto;
183 : /**
184 : * The next VLIB node to follow.
185 : */
186 : u16 dpoi_next_node;
187 : /**
188 : * the index of objects of that type
189 : */
190 : index_t dpoi_index;
191 : };
192 : u64 as_u64;
193 : };
194 : } dpo_id_t;
195 :
196 : STATIC_ASSERT(sizeof(dpo_id_t) <= sizeof(u64),
197 : "DPO ID is greater than sizeof u64 "
198 : "atomic updates need to be revisited");
199 :
200 : /**
201 : * @brief An initialiser for DPOs declared on the stack.
202 : * Thenext node is set to 0 since VLIB graph nodes should set 0 index to drop.
203 : */
204 : #define DPO_INVALID \
205 : { \
206 : .dpoi_type = DPO_FIRST, \
207 : .dpoi_proto = DPO_PROTO_NONE, \
208 : .dpoi_index = INDEX_INVALID, \
209 : .dpoi_next_node = 0, \
210 : }
211 :
212 : /**
213 : * @brief Return true if the DPO object is valid, i.e. has been initialised.
214 : */
215 : static inline int
216 12802354 : dpo_id_is_valid (const dpo_id_t *dpoi)
217 : {
218 20602696 : return (dpoi->dpoi_type != DPO_FIRST &&
219 7800282 : dpoi->dpoi_index != INDEX_INVALID);
220 : }
221 :
222 : extern dpo_proto_t vnet_link_to_dpo_proto(vnet_link_t linkt);
223 :
224 : /**
225 : * @brief
226 : * Take a reference counting lock on the DPO
227 : */
228 : extern void dpo_lock(dpo_id_t *dpo);
229 :
230 : /**
231 : * @brief
232 : * Release a reference counting lock on the DPO
233 : */
234 : extern void dpo_unlock(dpo_id_t *dpo);
235 :
236 : /**
237 : * @brief
238 : * Make an interpose DPO from an original
239 : */
240 : extern void dpo_mk_interpose(const dpo_id_t *original,
241 : const dpo_id_t *parent,
242 : dpo_id_t *clone);
243 :
244 : /**
245 : * @brief Set/create a DPO ID
246 : * The DPO will be locked.
247 : *
248 : * @param dpo
249 : * The DPO object to configure
250 : *
251 : * @param type
252 : * The dpo_type_t of the DPO
253 : *
254 : * @param proto
255 : * The dpo_proto_t of the DPO
256 : *
257 : * @param index
258 : * The type specific index of the DPO
259 : */
260 : extern void dpo_set(dpo_id_t *dpo,
261 : dpo_type_t type,
262 : dpo_proto_t proto,
263 : index_t index);
264 :
265 : /**
266 : * @brief reset a DPO ID
267 : * The DPO will be unlocked.
268 : *
269 : * @param dpo
270 : * The DPO object to reset
271 : */
272 : extern void dpo_reset(dpo_id_t *dpo);
273 :
274 : /**
275 : * @brief compare two DPOs for equality
276 : */
277 : extern int dpo_cmp(const dpo_id_t *dpo1,
278 : const dpo_id_t *dpo2);
279 :
280 : /**
281 : * @brief
282 : * atomic copy a data-plane object.
283 : * This is safe to use when the dst DPO is currently switching packets
284 : */
285 : extern void dpo_copy(dpo_id_t *dst,
286 : const dpo_id_t *src);
287 :
288 : /**
289 : * @brief Return TRUE is the DPO is any type of adjacency
290 : */
291 : extern int dpo_is_adj(const dpo_id_t *dpo);
292 :
293 : /**
294 : * @brief Format a DPO_id_t oject
295 : */
296 : extern u8 *format_dpo_id(u8 * s, va_list * args);
297 :
298 : /**
299 : * @brief format a DPO type
300 : */
301 : extern u8 *format_dpo_type(u8 * s, va_list * args);
302 :
303 : /**
304 : * @brief format a DPO protocol
305 : */
306 : extern u8 *format_dpo_proto(u8 * s, va_list * args);
307 :
308 : /**
309 : * @brief format a DPO protocol
310 : */
311 : extern vnet_link_t dpo_proto_to_link(dpo_proto_t dp);
312 :
313 : /**
314 : * @brief
315 : * Set and stack a DPO.
316 : * The DPO passed is set to the parent DPO and the necessary
317 : * VLIB graph arcs are created. The child_type and child_proto
318 : * are used to get the VLID nodes from which the arcs are added.
319 : *
320 : * @param child_type
321 : * Child DPO type.
322 : *
323 : * @param child_proto
324 : * Child DPO proto
325 : *
326 : * @parem dpo
327 : * This is the DPO to stack and set.
328 : *
329 : * @paren parent_dpo
330 : * The parent DPO to stack onto.
331 : */
332 : extern void dpo_stack(dpo_type_t child_type,
333 : dpo_proto_t child_proto,
334 : dpo_id_t *dpo,
335 : const dpo_id_t *parent_dpo);
336 :
337 : /**
338 : * @brief
339 : * Set and stack a DPO.
340 : * The DPO passed is set to the parent DPO and the necessary
341 : * VLIB graph arcs are created, from the child_node passed.
342 : *
343 : * @param child_node
344 : * The VLIB graph node index to create an arc from to the parent
345 : *
346 : * @param dpo
347 : * This is the DPO to stack and set.
348 : *
349 : * @param parent_dpo
350 : * The parent DPO to stack onto.
351 : */
352 : extern void dpo_stack_from_node(u32 child_node,
353 : dpo_id_t *dpo,
354 : const dpo_id_t *parent);
355 :
356 : /**
357 : * Get a uRPF interface for the DPO
358 : *
359 : * @param dpo
360 : * The DPO from which to get the uRPF interface
361 : *
362 : * @return valid SW interface index or ~0
363 : */
364 : extern u32 dpo_get_urpf(const dpo_id_t *dpo);
365 :
366 : /**
367 : * Get the MTU DPO
368 : *
369 : * @param dpo
370 : * The DPO from which to get the MTU
371 : *
372 : * @return MTU (0xffff if something more usefull was unavailable)
373 : */
374 : extern u16 dpo_get_mtu(const dpo_id_t *dpo);
375 :
376 : /**
377 : * @brief A lock function registered for a DPO type
378 : */
379 : typedef void (*dpo_lock_fn_t)(dpo_id_t *dpo);
380 :
381 : /**
382 : * @brief An unlock function registered for a DPO type
383 : */
384 : typedef void (*dpo_unlock_fn_t)(dpo_id_t *dpo);
385 :
386 : /**
387 : * @brief An memory usage show command
388 : */
389 : typedef void (*dpo_mem_show_t)(void);
390 :
391 : /**
392 : * @brief Given a DPO instance return a vector of node indices that
393 : * the type/instance will use.
394 : */
395 : typedef u32* (*dpo_get_next_node_t)(const dpo_id_t *dpo);
396 :
397 : /**
398 : * @brief Given a DPO instance return an interface that can
399 : * be used in an uRPF check
400 : */
401 : typedef u32 (*dpo_get_urpf_t)(const dpo_id_t *dpo);
402 :
403 : /**
404 : * @brief Given a DPO instance return the MTU
405 : */
406 : typedef u16 (*dpo_get_mtu_t)(const dpo_id_t *dpo);
407 :
408 : /**
409 : * @brief Called during FIB interposition when the originally
410 : * registered DPO is used to 'clone' an instance for interposition
411 : * at a particular location in the FIB graph.
412 : * The parent is the next DPO in the chain that the clone will
413 : * be used instead of. The clone may then choose to stack itself
414 : * on the parent.
415 : */
416 : typedef void (*dpo_mk_interpose_t)(const dpo_id_t *original,
417 : const dpo_id_t *parent,
418 : dpo_id_t *clone);
419 :
420 : /**
421 : * @brief A virtual function table regisitered for a DPO type
422 : */
423 : typedef struct dpo_vft_t_
424 : {
425 : /**
426 : * A reference counting lock function
427 : */
428 : dpo_lock_fn_t dv_lock;
429 : /**
430 : * A reference counting unlock function
431 : */
432 : dpo_lock_fn_t dv_unlock;
433 : /**
434 : * A format function
435 : */
436 : format_function_t *dv_format;
437 : /**
438 : * A show memory usage function
439 : */
440 : dpo_mem_show_t dv_mem_show;
441 : /**
442 : * A function to get the next VLIB node given an instance
443 : * of the DPO. If this is null, then the node's name MUST be
444 : * retreiveable from the nodes names array passed in the register
445 : * function
446 : */
447 : dpo_get_next_node_t dv_get_next_node;
448 : /**
449 : * Get uRPF interface
450 : */
451 : dpo_get_urpf_t dv_get_urpf;
452 : /**
453 : * Get MTU
454 : */
455 : dpo_get_mtu_t dv_get_mtu;
456 : /**
457 : * Signal on an interposed child that the parent has changed
458 : */
459 : dpo_mk_interpose_t dv_mk_interpose;
460 : } dpo_vft_t;
461 :
462 :
463 : /**
464 : * @brief For a given DPO type Register:
465 : * - a virtual function table
466 : * - a NULL terminated array of graph nodes from which that object type
467 : * will originate packets, i.e. the nodes in which the object type will be
468 : * the parent DPO in the DP graph. The ndoes are per-data-path protocol
469 : * (see above).
470 : *
471 : * @param type
472 : * The type being registered.
473 : *
474 : * @param vft
475 : * The virtual function table to register for the type.
476 : *
477 : * @param nodes
478 : * The string description of the per-protocol VLIB graph nodes.
479 : */
480 : extern void dpo_register(dpo_type_t type,
481 : const dpo_vft_t *vft,
482 : const char * const * const * nodes);
483 :
484 : /**
485 : * @brief Create and register a new DPO type.
486 : *
487 : * This can be used by plugins to create new DPO types that are not listed
488 : * in dpo_type_t enum
489 : *
490 : * @param vft
491 : * The virtual function table to register for the type.
492 : *
493 : * @param nodes
494 : * The string description of the per-protocol VLIB graph nodes.
495 : *
496 : * @return The new dpo_type_t
497 : */
498 : extern dpo_type_t dpo_register_new_type(const dpo_vft_t *vft,
499 : const char * const * const * nodes);
500 :
501 : /**
502 : * @brief Return already stacked up next node index for a given
503 : * child_type/child_proto and parent_type/patent_proto.
504 : * The VLIB graph arc used is taken from the parent and child types
505 : * passed.
506 : *
507 : * @param child_type
508 : * Child DPO type.
509 : *
510 : * @param child_proto
511 : * Child DPO proto
512 : *
513 : * @param parent_type
514 : * Parent DPO type.
515 : *
516 : * @param parent_proto
517 : * Parent DPO proto
518 : *
519 : * @return The VLIB Graph node index
520 : */
521 : extern u32
522 : dpo_get_next_node_by_type_and_proto (dpo_type_t child_type,
523 : dpo_proto_t child_proto,
524 : dpo_type_t parent_type,
525 : dpo_proto_t parent_proto);
526 :
527 :
528 : /**
529 : * @brief Barrier sync if a dpo pool is about to expand
530 : *
531 : * @param VM (output)
532 : * vlib_main_t *, invariably &vlib_global_main
533 : *
534 : * @param P
535 : * pool pointer
536 : *
537 : * @param YESNO (output)
538 : * typically a u8, 1 => expand will occur, worker barrier held
539 : * 0 => no expand, barrier not held
540 : *
541 : * @return YESNO set
542 : */
543 :
544 : #define dpo_pool_barrier_sync(VM,P,YESNO) \
545 : do { \
546 : YESNO = pool_get_will_expand (P); \
547 : \
548 : if (YESNO) \
549 : { \
550 : VM = vlib_get_main(); \
551 : ASSERT ((VM)->thread_index == 0); \
552 : vlib_worker_thread_barrier_sync((VM)); \
553 : } \
554 : } while(0);
555 :
556 : /**
557 : * @brief Release barrier sync after dpo pool expansion
558 : *
559 : * @param VM
560 : * vlib_main_t pointer, must be &vlib_global_main
561 : *
562 : * @param YESNO
563 : * typically a u8, 1 => release required
564 : * 0 => no release required
565 : * @return none
566 : */
567 :
568 : #define dpo_pool_barrier_release(VM,YESNO) \
569 : if ((YESNO)) vlib_worker_thread_barrier_release((VM));
570 :
571 : #endif
572 :
573 : // clang-format on
|