Line data Source code
1 : /*
2 : * Zebra dataplane layer.
3 : * Copyright (c) 2018 Volta Networks, Inc.
4 : *
5 : * This program is free software; you can redistribute it and/or modify
6 : * it under the terms of the GNU General Public License as published by
7 : * the Free Software Foundation; either version 2 of the License, or
8 : * (at your option) any later version.
9 : *
10 : * This program is distributed in the hope that it will be useful, but
11 : * WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU General Public License along
16 : * with this program; see the file COPYING; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 : */
19 :
20 : #ifdef HAVE_CONFIG_H
21 : #include "config.h"
22 : #endif
23 :
24 : #include "lib/libfrr.h"
25 : #include "lib/debug.h"
26 : #include "lib/frratomic.h"
27 : #include "lib/frr_pthread.h"
28 : #include "lib/memory.h"
29 : #include "lib/zebra.h"
30 : #include "zebra/netconf_netlink.h"
31 : #include "zebra/zebra_router.h"
32 : #include "zebra/zebra_dplane.h"
33 : #include "zebra/zebra_vxlan_private.h"
34 : #include "zebra/zebra_mpls.h"
35 : #include "zebra/rt.h"
36 : #include "zebra/debug.h"
37 : #include "zebra/zebra_pbr.h"
38 : #include "zebra/zebra_neigh.h"
39 : #include "zebra/zebra_tc.h"
40 : #include "printfrr.h"
41 :
42 : /* Memory types */
43 3 : DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx");
44 3 : DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf");
45 3 : DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider");
46 3 : DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object");
47 3 : DEFINE_MTYPE_STATIC(ZEBRA, DP_NS, "DPlane NSes");
48 :
49 : #ifndef AOK
50 : # define AOK 0
51 : #endif
52 :
53 : /* Control for collection of extra interface info with route updates; a plugin
54 : * can enable the extra info via a dplane api.
55 : */
56 : static bool dplane_collect_extra_intf_info;
57 :
58 : /* Enable test dataplane provider */
59 : /*#define DPLANE_TEST_PROVIDER 1 */
60 :
61 : /* Default value for max queued incoming updates */
62 : const uint32_t DPLANE_DEFAULT_MAX_QUEUED = 200;
63 :
64 : /* Default value for new work per cycle */
65 : const uint32_t DPLANE_DEFAULT_NEW_WORK = 100;
66 :
67 : /* Validation check macro for context blocks */
68 : /* #define DPLANE_DEBUG 1 */
69 :
70 : #ifdef DPLANE_DEBUG
71 :
72 : # define DPLANE_CTX_VALID(p) \
73 : assert((p) != NULL)
74 :
75 : #else
76 :
77 : # define DPLANE_CTX_VALID(p)
78 :
79 : #endif /* DPLANE_DEBUG */
80 :
81 : /*
82 : * Nexthop information captured for nexthop/nexthop group updates
83 : */
84 : struct dplane_nexthop_info {
85 : uint32_t id;
86 : uint32_t old_id;
87 : afi_t afi;
88 : vrf_id_t vrf_id;
89 : int type;
90 :
91 : struct nexthop_group ng;
92 : struct nh_grp nh_grp[MULTIPATH_NUM];
93 : uint8_t nh_grp_count;
94 : };
95 :
96 : /*
97 : * Optional extra info about interfaces used in route updates' nexthops.
98 : */
99 : struct dplane_intf_extra {
100 : vrf_id_t vrf_id;
101 : uint32_t ifindex;
102 : uint32_t flags;
103 : uint32_t status;
104 :
105 : struct dplane_intf_extra_list_item dlink;
106 : };
107 :
108 : /*
109 : * Route information captured for route updates.
110 : */
111 : struct dplane_route_info {
112 :
113 : /* Dest and (optional) source prefixes */
114 : struct prefix zd_dest;
115 : struct prefix zd_src;
116 :
117 : afi_t zd_afi;
118 : safi_t zd_safi;
119 :
120 : int zd_type;
121 : int zd_old_type;
122 :
123 : route_tag_t zd_tag;
124 : route_tag_t zd_old_tag;
125 : uint32_t zd_metric;
126 : uint32_t zd_old_metric;
127 :
128 : uint16_t zd_instance;
129 : uint16_t zd_old_instance;
130 :
131 : uint8_t zd_distance;
132 : uint8_t zd_old_distance;
133 :
134 : uint32_t zd_mtu;
135 : uint32_t zd_nexthop_mtu;
136 :
137 : uint32_t zd_flags;
138 :
139 : /* Nexthop hash entry info */
140 : struct dplane_nexthop_info nhe;
141 :
142 : /* Nexthops */
143 : uint32_t zd_nhg_id;
144 : struct nexthop_group zd_ng;
145 :
146 : /* Backup nexthops (if present) */
147 : struct nexthop_group backup_ng;
148 :
149 : /* "Previous" nexthops, used only in route updates without netlink */
150 : struct nexthop_group zd_old_ng;
151 : struct nexthop_group old_backup_ng;
152 :
153 : /* Optional list of extra interface info */
154 : struct dplane_intf_extra_list_head intf_extra_list;
155 : };
156 :
157 : /*
158 : * Pseudowire info for the dataplane
159 : */
160 : struct dplane_pw_info {
161 : int type;
162 : int af;
163 : int status;
164 : uint32_t flags;
165 : uint32_t nhg_id;
166 : union g_addr dest;
167 : mpls_label_t local_label;
168 : mpls_label_t remote_label;
169 :
170 : /* Nexthops that are valid and installed */
171 : struct nexthop_group fib_nhg;
172 :
173 : /* Primary and backup nexthop sets, copied from the resolving route. */
174 : struct nexthop_group primary_nhg;
175 : struct nexthop_group backup_nhg;
176 :
177 : union pw_protocol_fields fields;
178 : };
179 :
180 : /*
181 : * Bridge port info for the dataplane
182 : */
183 : struct dplane_br_port_info {
184 : uint32_t sph_filter_cnt;
185 : struct in_addr sph_filters[ES_VTEP_MAX_CNT];
186 : /* DPLANE_BR_PORT_XXX - see zebra_dplane.h*/
187 : uint32_t flags;
188 : uint32_t backup_nhg_id;
189 : };
190 :
191 : /*
192 : * Interface/prefix info for the dataplane
193 : */
194 : struct dplane_intf_info {
195 :
196 : uint32_t metric;
197 : uint32_t flags;
198 :
199 : bool protodown;
200 : bool pd_reason_val;
201 :
202 : #define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */
203 : #define DPLANE_INTF_SECONDARY (1 << 1)
204 : #define DPLANE_INTF_BROADCAST (1 << 2)
205 : #define DPLANE_INTF_HAS_DEST DPLANE_INTF_CONNECTED
206 : #define DPLANE_INTF_HAS_LABEL (1 << 4)
207 :
208 : /* Interface address/prefix */
209 : struct prefix prefix;
210 :
211 : /* Dest address, for p2p, or broadcast prefix */
212 : struct prefix dest_prefix;
213 :
214 : char *label;
215 : char label_buf[32];
216 : };
217 :
218 : /*
219 : * EVPN MAC address info for the dataplane.
220 : */
221 : struct dplane_mac_info {
222 : vlanid_t vid;
223 : ifindex_t br_ifindex;
224 : struct ethaddr mac;
225 : struct in_addr vtep_ip;
226 : bool is_sticky;
227 : uint32_t nhg_id;
228 : uint32_t update_flags;
229 : };
230 :
231 : /*
232 : * Neighbor info for the dataplane
233 : */
234 : struct dplane_neigh_info {
235 : struct ipaddr ip_addr;
236 : union {
237 : struct ethaddr mac;
238 : struct ipaddr ip_addr;
239 : } link;
240 : uint32_t flags;
241 : uint16_t state;
242 : uint32_t update_flags;
243 : };
244 :
245 : /*
246 : * Neighbor Table
247 : */
248 : struct dplane_neigh_table {
249 : uint8_t family;
250 : uint32_t app_probes;
251 : uint32_t ucast_probes;
252 : uint32_t mcast_probes;
253 : };
254 :
255 : /*
256 : * Policy based routing rule info for the dataplane
257 : */
258 : struct dplane_ctx_rule {
259 : uint32_t priority;
260 :
261 : /* The route table pointed by this rule */
262 : uint32_t table;
263 :
264 : /* Filter criteria */
265 : uint32_t filter_bm;
266 : uint32_t fwmark;
267 : uint8_t dsfield;
268 : struct prefix src_ip;
269 : struct prefix dst_ip;
270 : uint8_t ip_proto;
271 : uint16_t src_port;
272 : uint16_t dst_port;
273 :
274 : uint8_t action_pcp;
275 : uint16_t action_vlan_id;
276 : uint16_t action_vlan_flags;
277 :
278 : uint32_t action_queue_id;
279 :
280 : char ifname[INTERFACE_NAMSIZ + 1];
281 : struct ethaddr smac;
282 : struct ethaddr dmac;
283 : int out_ifindex;
284 : intptr_t dp_flow_ptr;
285 : };
286 :
287 : struct dplane_rule_info {
288 : /*
289 : * Originating zclient sock fd, so we can know who to send
290 : * back to.
291 : */
292 : int sock;
293 :
294 : int unique;
295 : int seq;
296 :
297 : struct dplane_ctx_rule new;
298 : struct dplane_ctx_rule old;
299 : };
300 :
301 : struct dplane_gre_ctx {
302 : uint32_t link_ifindex;
303 : unsigned int mtu;
304 : struct zebra_l2info_gre info;
305 : };
306 :
307 :
308 : /*
309 : * Network interface configuration info - aligned with netlink's NETCONF
310 : * info. The flags values are public, in the dplane.h file...
311 : */
312 : struct dplane_netconf_info {
313 : enum dplane_netconf_status_e mpls_val;
314 : enum dplane_netconf_status_e mcast_val;
315 : enum dplane_netconf_status_e linkdown_val;
316 : };
317 :
318 : struct dplane_tc_qdisc_info {
319 : enum tc_qdisc_kind kind;
320 : const char *kind_str;
321 : };
322 :
323 : struct dplane_tc_class_info {
324 : uint32_t handle;
325 : enum tc_qdisc_kind kind;
326 : const char *kind_str;
327 : uint64_t rate;
328 : uint64_t ceil;
329 : };
330 :
331 : struct dplane_tc_filter_info {
332 : uint32_t handle;
333 : uint16_t priority;
334 : enum tc_filter_kind kind;
335 : const char *kind_str;
336 : uint32_t filter_bm;
337 : uint16_t eth_proto;
338 : uint8_t ip_proto;
339 : struct prefix src_ip;
340 : struct prefix dst_ip;
341 : uint16_t src_port_min;
342 : uint16_t src_port_max;
343 : uint16_t dst_port_min;
344 : uint16_t dst_port_max;
345 : uint8_t dsfield;
346 : uint8_t dsfield_mask;
347 : uint32_t classid;
348 : };
349 :
350 : /*
351 : * The context block used to exchange info about route updates across
352 : * the boundary between the zebra main context (and pthread) and the
353 : * dataplane layer (and pthread).
354 : */
355 : struct zebra_dplane_ctx {
356 :
357 : /* Operation code */
358 : enum dplane_op_e zd_op;
359 :
360 : /* Status on return */
361 : enum zebra_dplane_result zd_status;
362 :
363 : /* Dplane provider id */
364 : uint32_t zd_provider;
365 :
366 : /* Flags - used by providers, e.g. */
367 : int zd_flags;
368 :
369 : bool zd_is_update;
370 :
371 : uint32_t zd_seq;
372 : uint32_t zd_old_seq;
373 :
374 : /* Some updates may be generated by notifications: allow the
375 : * plugin to notice and ignore results from its own notifications.
376 : */
377 : uint32_t zd_notif_provider;
378 :
379 : /* TODO -- internal/sub-operation status? */
380 : enum zebra_dplane_result zd_remote_status;
381 : enum zebra_dplane_result zd_kernel_status;
382 :
383 : vrf_id_t zd_vrf_id;
384 : uint32_t zd_table_id;
385 :
386 : char zd_ifname[INTERFACE_NAMSIZ];
387 : ifindex_t zd_ifindex;
388 :
389 : /* Support info for different kinds of updates */
390 : union {
391 : struct dplane_route_info rinfo;
392 : struct zebra_lsp lsp;
393 : struct dplane_pw_info pw;
394 : struct dplane_br_port_info br_port;
395 : struct dplane_intf_info intf;
396 : struct dplane_mac_info macinfo;
397 : struct dplane_neigh_info neigh;
398 : struct dplane_rule_info rule;
399 : struct dplane_tc_qdisc_info tc_qdisc;
400 : struct dplane_tc_class_info tc_class;
401 : struct dplane_tc_filter_info tc_filter;
402 : struct zebra_pbr_iptable iptable;
403 : struct zebra_pbr_ipset ipset;
404 : struct {
405 : struct zebra_pbr_ipset_entry entry;
406 : struct zebra_pbr_ipset_info info;
407 : } ipset_entry;
408 : struct dplane_neigh_table neightable;
409 : struct dplane_gre_ctx gre;
410 : struct dplane_netconf_info netconf;
411 : } u;
412 :
413 : /* Namespace info, used especially for netlink kernel communication */
414 : struct zebra_dplane_info zd_ns_info;
415 :
416 : /* Embedded list linkage */
417 : struct dplane_ctx_list_item zd_entries;
418 : };
419 :
420 : /* Flag that can be set by a pre-kernel provider as a signal that an update
421 : * should bypass the kernel.
422 : */
423 : #define DPLANE_CTX_FLAG_NO_KERNEL 0x01
424 :
425 : /* List types declared now that the structs involved are defined. */
426 803 : DECLARE_DLIST(dplane_ctx_list, struct zebra_dplane_ctx, zd_entries);
427 30 : DECLARE_DLIST(dplane_intf_extra_list, struct dplane_intf_extra, dlink);
428 :
429 : /* List for dplane plugins/providers */
430 : PREDECL_DLIST(dplane_prov_list);
431 :
432 : /*
433 : * Registration block for one dataplane provider.
434 : */
435 : struct zebra_dplane_provider {
436 : /* Name */
437 : char dp_name[DPLANE_PROVIDER_NAMELEN + 1];
438 :
439 : /* Priority, for ordering among providers */
440 : uint8_t dp_priority;
441 :
442 : /* Id value */
443 : uint32_t dp_id;
444 :
445 : /* Mutex */
446 : pthread_mutex_t dp_mutex;
447 :
448 : /* Plugin-provided extra data */
449 : void *dp_data;
450 :
451 : /* Flags */
452 : int dp_flags;
453 :
454 : int (*dp_start)(struct zebra_dplane_provider *prov);
455 :
456 : int (*dp_fp)(struct zebra_dplane_provider *prov);
457 :
458 : int (*dp_fini)(struct zebra_dplane_provider *prov, bool early_p);
459 :
460 : _Atomic uint32_t dp_in_counter;
461 : _Atomic uint32_t dp_in_queued;
462 : _Atomic uint32_t dp_in_max;
463 : _Atomic uint32_t dp_out_counter;
464 : _Atomic uint32_t dp_out_queued;
465 : _Atomic uint32_t dp_out_max;
466 : _Atomic uint32_t dp_error_counter;
467 :
468 : /* Queue of contexts inbound to the provider */
469 : struct dplane_ctx_list_head dp_ctx_in_list;
470 :
471 : /* Queue of completed contexts outbound from the provider back
472 : * towards the dataplane module.
473 : */
474 : struct dplane_ctx_list_head dp_ctx_out_list;
475 :
476 : /* Embedded list linkage for provider objects */
477 : struct dplane_prov_list_item dp_link;
478 : };
479 :
480 : /* Declare list of providers/plugins */
481 13 : DECLARE_DLIST(dplane_prov_list, struct zebra_dplane_provider, dp_link);
482 :
483 : /* Declare types for list of zns info objects */
484 : PREDECL_DLIST(zns_info_list);
485 :
486 : struct dplane_zns_info {
487 : struct zebra_dplane_info info;
488 :
489 : /* Request data from the OS */
490 : struct thread *t_request;
491 :
492 : /* Read event */
493 : struct thread *t_read;
494 :
495 : /* List linkage */
496 : struct zns_info_list_item link;
497 : };
498 :
499 : /*
500 : * Globals
501 : */
502 : static struct zebra_dplane_globals {
503 : /* Mutex to control access to dataplane components */
504 : pthread_mutex_t dg_mutex;
505 :
506 : /* Results callback registered by zebra 'core' */
507 : int (*dg_results_cb)(struct dplane_ctx_list_head *ctxlist);
508 :
509 : /* Sentinel for beginning of shutdown */
510 : volatile bool dg_is_shutdown;
511 :
512 : /* Sentinel for end of shutdown */
513 : volatile bool dg_run;
514 :
515 : /* Update context queue inbound to the dataplane */
516 : struct dplane_ctx_list_head dg_update_list;
517 :
518 : /* Ordered list of providers */
519 : struct dplane_prov_list_head dg_providers;
520 :
521 : /* List of info about each zns */
522 : struct zns_info_list_head dg_zns_list;
523 :
524 : /* Counter used to assign internal ids to providers */
525 : uint32_t dg_provider_id;
526 :
527 : /* Limit number of pending, unprocessed updates */
528 : _Atomic uint32_t dg_max_queued_updates;
529 :
530 : /* Control whether system route notifications should be produced. */
531 : bool dg_sys_route_notifs;
532 :
533 : /* Limit number of new updates dequeued at once, to pace an
534 : * incoming burst.
535 : */
536 : uint32_t dg_updates_per_cycle;
537 :
538 : _Atomic uint32_t dg_routes_in;
539 : _Atomic uint32_t dg_routes_queued;
540 : _Atomic uint32_t dg_routes_queued_max;
541 : _Atomic uint32_t dg_route_errors;
542 : _Atomic uint32_t dg_other_errors;
543 :
544 : _Atomic uint32_t dg_nexthops_in;
545 : _Atomic uint32_t dg_nexthop_errors;
546 :
547 : _Atomic uint32_t dg_lsps_in;
548 : _Atomic uint32_t dg_lsp_errors;
549 :
550 : _Atomic uint32_t dg_pws_in;
551 : _Atomic uint32_t dg_pw_errors;
552 :
553 : _Atomic uint32_t dg_br_port_in;
554 : _Atomic uint32_t dg_br_port_errors;
555 :
556 : _Atomic uint32_t dg_intf_addrs_in;
557 : _Atomic uint32_t dg_intf_addr_errors;
558 : _Atomic uint32_t dg_intf_changes;
559 : _Atomic uint32_t dg_intf_changes_errors;
560 :
561 : _Atomic uint32_t dg_macs_in;
562 : _Atomic uint32_t dg_mac_errors;
563 :
564 : _Atomic uint32_t dg_neighs_in;
565 : _Atomic uint32_t dg_neigh_errors;
566 :
567 : _Atomic uint32_t dg_rules_in;
568 : _Atomic uint32_t dg_rule_errors;
569 :
570 : _Atomic uint32_t dg_update_yields;
571 :
572 : _Atomic uint32_t dg_iptable_in;
573 : _Atomic uint32_t dg_iptable_errors;
574 :
575 : _Atomic uint32_t dg_ipset_in;
576 : _Atomic uint32_t dg_ipset_errors;
577 : _Atomic uint32_t dg_ipset_entry_in;
578 : _Atomic uint32_t dg_ipset_entry_errors;
579 :
580 : _Atomic uint32_t dg_neightable_in;
581 : _Atomic uint32_t dg_neightable_errors;
582 :
583 : _Atomic uint32_t dg_gre_set_in;
584 : _Atomic uint32_t dg_gre_set_errors;
585 :
586 : _Atomic uint32_t dg_intfs_in;
587 : _Atomic uint32_t dg_intf_errors;
588 :
589 : _Atomic uint32_t dg_tcs_in;
590 : _Atomic uint32_t dg_tcs_errors;
591 :
592 : /* Dataplane pthread */
593 : struct frr_pthread *dg_pthread;
594 :
595 : /* Event-delivery context 'master' for the dplane */
596 : struct thread_master *dg_master;
597 :
598 : /* Event/'thread' pointer for queued updates */
599 : struct thread *dg_t_update;
600 :
601 : /* Event pointer for pending shutdown check loop */
602 : struct thread *dg_t_shutdown_check;
603 :
604 : } zdplane_info;
605 :
606 : /* Instantiate zns list type */
607 2 : DECLARE_DLIST(zns_info_list, struct dplane_zns_info, link);
608 :
609 : /*
610 : * Lock and unlock for interactions with the zebra 'core' pthread
611 : */
612 : #define DPLANE_LOCK() pthread_mutex_lock(&zdplane_info.dg_mutex)
613 : #define DPLANE_UNLOCK() pthread_mutex_unlock(&zdplane_info.dg_mutex)
614 :
615 :
616 : /*
617 : * Lock and unlock for individual providers
618 : */
619 : #define DPLANE_PROV_LOCK(p) pthread_mutex_lock(&((p)->dp_mutex))
620 : #define DPLANE_PROV_UNLOCK(p) pthread_mutex_unlock(&((p)->dp_mutex))
621 :
622 : /* Prototypes */
623 : static void dplane_thread_loop(struct thread *event);
624 : static enum zebra_dplane_result lsp_update_internal(struct zebra_lsp *lsp,
625 : enum dplane_op_e op);
626 : static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
627 : enum dplane_op_e op);
628 : static enum zebra_dplane_result intf_addr_update_internal(
629 : const struct interface *ifp, const struct connected *ifc,
630 : enum dplane_op_e op);
631 : static enum zebra_dplane_result mac_update_common(
632 : enum dplane_op_e op, const struct interface *ifp,
633 : const struct interface *br_ifp,
634 : vlanid_t vid, const struct ethaddr *mac,
635 : struct in_addr vtep_ip, bool sticky, uint32_t nhg_id,
636 : uint32_t update_flags);
637 : static enum zebra_dplane_result
638 : neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
639 : const void *link, int link_family,
640 : const struct ipaddr *ip, uint32_t flags, uint16_t state,
641 : uint32_t update_flags, int protocol);
642 :
643 : /*
644 : * Public APIs
645 : */
646 :
647 : /* Obtain thread_master for dataplane thread */
648 0 : struct thread_master *dplane_get_thread_master(void)
649 : {
650 0 : return zdplane_info.dg_master;
651 : }
652 :
653 : /*
654 : * Allocate a dataplane update context
655 : */
656 51 : struct zebra_dplane_ctx *dplane_ctx_alloc(void)
657 : {
658 51 : struct zebra_dplane_ctx *p;
659 :
660 : /* TODO -- just alloc'ing memory, but would like to maintain
661 : * a pool
662 : */
663 26 : p = XCALLOC(MTYPE_DP_CTX, sizeof(struct zebra_dplane_ctx));
664 :
665 51 : return p;
666 : }
667 :
668 : /* Enable system route notifications */
669 0 : void dplane_enable_sys_route_notifs(void)
670 : {
671 0 : zdplane_info.dg_sys_route_notifs = true;
672 0 : }
673 :
674 : /*
675 : * Clean up dependent/internal allocations inside a context object
676 : */
677 51 : static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
678 : {
679 51 : struct dplane_intf_extra *if_extra;
680 :
681 : /*
682 : * Some internal allocations may need to be freed, depending on
683 : * the type of info captured in the ctx.
684 : */
685 51 : switch (ctx->zd_op) {
686 15 : case DPLANE_OP_ROUTE_INSTALL:
687 : case DPLANE_OP_ROUTE_UPDATE:
688 : case DPLANE_OP_ROUTE_DELETE:
689 : case DPLANE_OP_SYS_ROUTE_ADD:
690 : case DPLANE_OP_SYS_ROUTE_DELETE:
691 : case DPLANE_OP_ROUTE_NOTIFY:
692 :
693 : /* Free allocated nexthops */
694 15 : if (ctx->u.rinfo.zd_ng.nexthop) {
695 : /* This deals with recursive nexthops too */
696 15 : nexthops_free(ctx->u.rinfo.zd_ng.nexthop);
697 :
698 15 : ctx->u.rinfo.zd_ng.nexthop = NULL;
699 : }
700 :
701 : /* Free backup info also (if present) */
702 15 : if (ctx->u.rinfo.backup_ng.nexthop) {
703 : /* This deals with recursive nexthops too */
704 0 : nexthops_free(ctx->u.rinfo.backup_ng.nexthop);
705 :
706 0 : ctx->u.rinfo.backup_ng.nexthop = NULL;
707 : }
708 :
709 15 : if (ctx->u.rinfo.zd_old_ng.nexthop) {
710 : /* This deals with recursive nexthops too */
711 0 : nexthops_free(ctx->u.rinfo.zd_old_ng.nexthop);
712 :
713 0 : ctx->u.rinfo.zd_old_ng.nexthop = NULL;
714 : }
715 :
716 15 : if (ctx->u.rinfo.old_backup_ng.nexthop) {
717 : /* This deals with recursive nexthops too */
718 0 : nexthops_free(ctx->u.rinfo.old_backup_ng.nexthop);
719 :
720 0 : ctx->u.rinfo.old_backup_ng.nexthop = NULL;
721 : }
722 :
723 : /* Optional extra interface info */
724 15 : while ((if_extra = dplane_intf_extra_list_pop(
725 : &ctx->u.rinfo.intf_extra_list)))
726 15 : XFREE(MTYPE_DP_INTF, if_extra);
727 :
728 : break;
729 :
730 10 : case DPLANE_OP_NH_INSTALL:
731 : case DPLANE_OP_NH_UPDATE:
732 : case DPLANE_OP_NH_DELETE: {
733 10 : if (ctx->u.rinfo.nhe.ng.nexthop) {
734 : /* This deals with recursive nexthops too */
735 10 : nexthops_free(ctx->u.rinfo.nhe.ng.nexthop);
736 :
737 10 : ctx->u.rinfo.nhe.ng.nexthop = NULL;
738 : }
739 : break;
740 : }
741 :
742 0 : case DPLANE_OP_LSP_INSTALL:
743 : case DPLANE_OP_LSP_UPDATE:
744 : case DPLANE_OP_LSP_DELETE:
745 : case DPLANE_OP_LSP_NOTIFY:
746 : {
747 0 : struct zebra_nhlfe *nhlfe;
748 :
749 : /* Unlink and free allocated NHLFEs */
750 0 : frr_each_safe(nhlfe_list, &ctx->u.lsp.nhlfe_list, nhlfe) {
751 0 : nhlfe_list_del(&ctx->u.lsp.nhlfe_list, nhlfe);
752 0 : zebra_mpls_nhlfe_free(nhlfe);
753 : }
754 :
755 : /* Unlink and free allocated backup NHLFEs, if present */
756 0 : frr_each_safe(nhlfe_list,
757 : &(ctx->u.lsp.backup_nhlfe_list), nhlfe) {
758 0 : nhlfe_list_del(&ctx->u.lsp.backup_nhlfe_list,
759 : nhlfe);
760 0 : zebra_mpls_nhlfe_free(nhlfe);
761 : }
762 :
763 : /* Clear pointers in lsp struct, in case we're caching
764 : * free context structs.
765 : */
766 0 : nhlfe_list_init(&ctx->u.lsp.nhlfe_list);
767 0 : ctx->u.lsp.best_nhlfe = NULL;
768 0 : nhlfe_list_init(&ctx->u.lsp.backup_nhlfe_list);
769 :
770 0 : break;
771 : }
772 :
773 0 : case DPLANE_OP_PW_INSTALL:
774 : case DPLANE_OP_PW_UNINSTALL:
775 : /* Free allocated nexthops */
776 0 : if (ctx->u.pw.fib_nhg.nexthop) {
777 : /* This deals with recursive nexthops too */
778 0 : nexthops_free(ctx->u.pw.fib_nhg.nexthop);
779 :
780 0 : ctx->u.pw.fib_nhg.nexthop = NULL;
781 : }
782 0 : if (ctx->u.pw.primary_nhg.nexthop) {
783 0 : nexthops_free(ctx->u.pw.primary_nhg.nexthop);
784 :
785 0 : ctx->u.pw.primary_nhg.nexthop = NULL;
786 : }
787 0 : if (ctx->u.pw.backup_nhg.nexthop) {
788 0 : nexthops_free(ctx->u.pw.backup_nhg.nexthop);
789 :
790 0 : ctx->u.pw.backup_nhg.nexthop = NULL;
791 : }
792 : break;
793 :
794 2 : case DPLANE_OP_ADDR_INSTALL:
795 : case DPLANE_OP_ADDR_UNINSTALL:
796 : case DPLANE_OP_INTF_ADDR_ADD:
797 : case DPLANE_OP_INTF_ADDR_DEL:
798 : /* Maybe free label string, if allocated */
799 2 : if (ctx->u.intf.label != NULL &&
800 0 : ctx->u.intf.label != ctx->u.intf.label_buf) {
801 0 : XFREE(MTYPE_DP_CTX, ctx->u.intf.label);
802 0 : ctx->u.intf.label = NULL;
803 : }
804 : break;
805 :
806 : case DPLANE_OP_MAC_INSTALL:
807 : case DPLANE_OP_MAC_DELETE:
808 : case DPLANE_OP_NEIGH_INSTALL:
809 : case DPLANE_OP_NEIGH_UPDATE:
810 : case DPLANE_OP_NEIGH_DELETE:
811 : case DPLANE_OP_VTEP_ADD:
812 : case DPLANE_OP_VTEP_DELETE:
813 : case DPLANE_OP_RULE_ADD:
814 : case DPLANE_OP_RULE_DELETE:
815 : case DPLANE_OP_RULE_UPDATE:
816 : case DPLANE_OP_NEIGH_DISCOVER:
817 : case DPLANE_OP_BR_PORT_UPDATE:
818 : case DPLANE_OP_NEIGH_IP_INSTALL:
819 : case DPLANE_OP_NEIGH_IP_DELETE:
820 : case DPLANE_OP_NONE:
821 : case DPLANE_OP_IPSET_ADD:
822 : case DPLANE_OP_IPSET_DELETE:
823 : case DPLANE_OP_INTF_INSTALL:
824 : case DPLANE_OP_INTF_UPDATE:
825 : case DPLANE_OP_INTF_DELETE:
826 : case DPLANE_OP_TC_QDISC_INSTALL:
827 : case DPLANE_OP_TC_QDISC_UNINSTALL:
828 : case DPLANE_OP_TC_CLASS_ADD:
829 : case DPLANE_OP_TC_CLASS_DELETE:
830 : case DPLANE_OP_TC_CLASS_UPDATE:
831 : case DPLANE_OP_TC_FILTER_ADD:
832 : case DPLANE_OP_TC_FILTER_DELETE:
833 : case DPLANE_OP_TC_FILTER_UPDATE:
834 : break;
835 :
836 : case DPLANE_OP_IPSET_ENTRY_ADD:
837 : case DPLANE_OP_IPSET_ENTRY_DELETE:
838 : break;
839 : case DPLANE_OP_NEIGH_TABLE_UPDATE:
840 : break;
841 0 : case DPLANE_OP_IPTABLE_ADD:
842 : case DPLANE_OP_IPTABLE_DELETE:
843 0 : if (ctx->u.iptable.interface_name_list)
844 0 : list_delete(&ctx->u.iptable.interface_name_list);
845 : break;
846 : case DPLANE_OP_GRE_SET:
847 : case DPLANE_OP_INTF_NETCONFIG:
848 : break;
849 : }
850 51 : }
851 :
852 : /*
853 : * Free a dataplane results context.
854 : */
855 51 : static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
856 : {
857 51 : if (pctx == NULL)
858 : return;
859 :
860 51 : DPLANE_CTX_VALID(*pctx);
861 :
862 : /* TODO -- just freeing memory, but would like to maintain
863 : * a pool
864 : */
865 :
866 : /* Some internal allocations may need to be freed, depending on
867 : * the type of info captured in the ctx.
868 : */
869 51 : dplane_ctx_free_internal(*pctx);
870 :
871 51 : XFREE(MTYPE_DP_CTX, *pctx);
872 : }
873 :
874 : /*
875 : * Reset an allocated context object for re-use. All internal allocations are
876 : * freed and the context is memset.
877 : */
878 0 : void dplane_ctx_reset(struct zebra_dplane_ctx *ctx)
879 : {
880 0 : dplane_ctx_free_internal(ctx);
881 0 : memset(ctx, 0, sizeof(*ctx));
882 0 : }
883 :
884 : /*
885 : * Return a context block to the dplane module after processing
886 : */
887 51 : void dplane_ctx_fini(struct zebra_dplane_ctx **pctx)
888 : {
889 : /* TODO -- maintain pool; for now, just free */
890 51 : dplane_ctx_free(pctx);
891 0 : }
892 :
893 : /* Init a list of contexts */
894 65 : void dplane_ctx_q_init(struct dplane_ctx_list_head *q)
895 : {
896 65 : dplane_ctx_list_init(q);
897 65 : }
898 :
899 : /* Enqueue a context block */
900 50 : void dplane_ctx_enqueue_tail(struct dplane_ctx_list_head *list,
901 : const struct zebra_dplane_ctx *ctx)
902 : {
903 50 : dplane_ctx_list_add_tail(list, (struct zebra_dplane_ctx *)ctx);
904 50 : }
905 :
906 : /* Append a list of context blocks to another list */
907 82 : void dplane_ctx_list_append(struct dplane_ctx_list_head *to_list,
908 : struct dplane_ctx_list_head *from_list)
909 : {
910 82 : struct zebra_dplane_ctx *ctx;
911 :
912 291 : while ((ctx = dplane_ctx_list_pop(from_list)) != NULL)
913 336 : dplane_ctx_list_add_tail(to_list, ctx);
914 82 : }
915 :
916 6 : struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_list_head *q)
917 : {
918 6 : struct zebra_dplane_ctx *ctx = dplane_ctx_list_first(q);
919 :
920 6 : return ctx;
921 : }
922 :
923 : /* Dequeue a context block from the head of a list */
924 155 : struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_list_head *q)
925 : {
926 155 : struct zebra_dplane_ctx *ctx = dplane_ctx_list_pop(q);
927 :
928 155 : return ctx;
929 : }
930 :
931 : /*
932 : * Accessors for information from the context object
933 : */
934 90 : enum zebra_dplane_result dplane_ctx_get_status(
935 : const struct zebra_dplane_ctx *ctx)
936 : {
937 90 : DPLANE_CTX_VALID(ctx);
938 :
939 90 : return ctx->zd_status;
940 : }
941 :
942 27 : void dplane_ctx_set_status(struct zebra_dplane_ctx *ctx,
943 : enum zebra_dplane_result status)
944 : {
945 27 : DPLANE_CTX_VALID(ctx);
946 :
947 27 : ctx->zd_status = status;
948 27 : }
949 :
950 : /* Retrieve last/current provider id */
951 0 : uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx)
952 : {
953 0 : DPLANE_CTX_VALID(ctx);
954 0 : return ctx->zd_provider;
955 : }
956 :
957 : /* Providers run before the kernel can control whether a kernel
958 : * update should be done.
959 : */
960 0 : void dplane_ctx_set_skip_kernel(struct zebra_dplane_ctx *ctx)
961 : {
962 0 : DPLANE_CTX_VALID(ctx);
963 :
964 0 : SET_FLAG(ctx->zd_flags, DPLANE_CTX_FLAG_NO_KERNEL);
965 0 : }
966 :
967 25 : bool dplane_ctx_is_skip_kernel(const struct zebra_dplane_ctx *ctx)
968 : {
969 25 : DPLANE_CTX_VALID(ctx);
970 :
971 25 : return CHECK_FLAG(ctx->zd_flags, DPLANE_CTX_FLAG_NO_KERNEL);
972 : }
973 :
974 26 : void dplane_ctx_set_op(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
975 : {
976 26 : DPLANE_CTX_VALID(ctx);
977 26 : ctx->zd_op = op;
978 26 : }
979 :
980 214 : enum dplane_op_e dplane_ctx_get_op(const struct zebra_dplane_ctx *ctx)
981 : {
982 214 : DPLANE_CTX_VALID(ctx);
983 :
984 214 : return ctx->zd_op;
985 : }
986 :
987 0 : const char *dplane_op2str(enum dplane_op_e op)
988 : {
989 0 : const char *ret = "UNKNOWN";
990 :
991 0 : switch (op) {
992 0 : case DPLANE_OP_NONE:
993 0 : ret = "NONE";
994 0 : break;
995 :
996 : /* Route update */
997 0 : case DPLANE_OP_ROUTE_INSTALL:
998 0 : ret = "ROUTE_INSTALL";
999 0 : break;
1000 0 : case DPLANE_OP_ROUTE_UPDATE:
1001 0 : ret = "ROUTE_UPDATE";
1002 0 : break;
1003 0 : case DPLANE_OP_ROUTE_DELETE:
1004 0 : ret = "ROUTE_DELETE";
1005 0 : break;
1006 0 : case DPLANE_OP_ROUTE_NOTIFY:
1007 0 : ret = "ROUTE_NOTIFY";
1008 0 : break;
1009 :
1010 : /* Nexthop update */
1011 0 : case DPLANE_OP_NH_INSTALL:
1012 0 : ret = "NH_INSTALL";
1013 0 : break;
1014 0 : case DPLANE_OP_NH_UPDATE:
1015 0 : ret = "NH_UPDATE";
1016 0 : break;
1017 0 : case DPLANE_OP_NH_DELETE:
1018 0 : ret = "NH_DELETE";
1019 0 : break;
1020 :
1021 0 : case DPLANE_OP_LSP_INSTALL:
1022 0 : ret = "LSP_INSTALL";
1023 0 : break;
1024 0 : case DPLANE_OP_LSP_UPDATE:
1025 0 : ret = "LSP_UPDATE";
1026 0 : break;
1027 0 : case DPLANE_OP_LSP_DELETE:
1028 0 : ret = "LSP_DELETE";
1029 0 : break;
1030 0 : case DPLANE_OP_LSP_NOTIFY:
1031 0 : ret = "LSP_NOTIFY";
1032 0 : break;
1033 :
1034 0 : case DPLANE_OP_PW_INSTALL:
1035 0 : ret = "PW_INSTALL";
1036 0 : break;
1037 0 : case DPLANE_OP_PW_UNINSTALL:
1038 0 : ret = "PW_UNINSTALL";
1039 0 : break;
1040 :
1041 0 : case DPLANE_OP_SYS_ROUTE_ADD:
1042 0 : ret = "SYS_ROUTE_ADD";
1043 0 : break;
1044 0 : case DPLANE_OP_SYS_ROUTE_DELETE:
1045 0 : ret = "SYS_ROUTE_DEL";
1046 0 : break;
1047 :
1048 0 : case DPLANE_OP_BR_PORT_UPDATE:
1049 0 : ret = "BR_PORT_UPDATE";
1050 0 : break;
1051 :
1052 0 : case DPLANE_OP_ADDR_INSTALL:
1053 0 : ret = "ADDR_INSTALL";
1054 0 : break;
1055 0 : case DPLANE_OP_ADDR_UNINSTALL:
1056 0 : ret = "ADDR_UNINSTALL";
1057 0 : break;
1058 :
1059 0 : case DPLANE_OP_MAC_INSTALL:
1060 0 : ret = "MAC_INSTALL";
1061 0 : break;
1062 0 : case DPLANE_OP_MAC_DELETE:
1063 0 : ret = "MAC_DELETE";
1064 0 : break;
1065 :
1066 0 : case DPLANE_OP_NEIGH_INSTALL:
1067 0 : ret = "NEIGH_INSTALL";
1068 0 : break;
1069 0 : case DPLANE_OP_NEIGH_UPDATE:
1070 0 : ret = "NEIGH_UPDATE";
1071 0 : break;
1072 0 : case DPLANE_OP_NEIGH_DELETE:
1073 0 : ret = "NEIGH_DELETE";
1074 0 : break;
1075 0 : case DPLANE_OP_VTEP_ADD:
1076 0 : ret = "VTEP_ADD";
1077 0 : break;
1078 0 : case DPLANE_OP_VTEP_DELETE:
1079 0 : ret = "VTEP_DELETE";
1080 0 : break;
1081 :
1082 0 : case DPLANE_OP_RULE_ADD:
1083 0 : ret = "RULE_ADD";
1084 0 : break;
1085 0 : case DPLANE_OP_RULE_DELETE:
1086 0 : ret = "RULE_DELETE";
1087 0 : break;
1088 0 : case DPLANE_OP_RULE_UPDATE:
1089 0 : ret = "RULE_UPDATE";
1090 0 : break;
1091 :
1092 0 : case DPLANE_OP_NEIGH_DISCOVER:
1093 0 : ret = "NEIGH_DISCOVER";
1094 0 : break;
1095 :
1096 0 : case DPLANE_OP_IPTABLE_ADD:
1097 0 : ret = "IPTABLE_ADD";
1098 0 : break;
1099 0 : case DPLANE_OP_IPTABLE_DELETE:
1100 0 : ret = "IPTABLE_DELETE";
1101 0 : break;
1102 0 : case DPLANE_OP_IPSET_ADD:
1103 0 : ret = "IPSET_ADD";
1104 0 : break;
1105 0 : case DPLANE_OP_IPSET_DELETE:
1106 0 : ret = "IPSET_DELETE";
1107 0 : break;
1108 0 : case DPLANE_OP_IPSET_ENTRY_ADD:
1109 0 : ret = "IPSET_ENTRY_ADD";
1110 0 : break;
1111 0 : case DPLANE_OP_IPSET_ENTRY_DELETE:
1112 0 : ret = "IPSET_ENTRY_DELETE";
1113 0 : break;
1114 0 : case DPLANE_OP_NEIGH_IP_INSTALL:
1115 0 : ret = "NEIGH_IP_INSTALL";
1116 0 : break;
1117 0 : case DPLANE_OP_NEIGH_IP_DELETE:
1118 0 : ret = "NEIGH_IP_DELETE";
1119 0 : break;
1120 0 : case DPLANE_OP_NEIGH_TABLE_UPDATE:
1121 0 : ret = "NEIGH_TABLE_UPDATE";
1122 0 : break;
1123 :
1124 0 : case DPLANE_OP_GRE_SET:
1125 0 : ret = "GRE_SET";
1126 0 : break;
1127 :
1128 : case DPLANE_OP_INTF_ADDR_ADD:
1129 : return "INTF_ADDR_ADD";
1130 :
1131 0 : case DPLANE_OP_INTF_ADDR_DEL:
1132 0 : return "INTF_ADDR_DEL";
1133 :
1134 0 : case DPLANE_OP_INTF_NETCONFIG:
1135 0 : return "INTF_NETCONFIG";
1136 :
1137 0 : case DPLANE_OP_INTF_INSTALL:
1138 0 : ret = "INTF_INSTALL";
1139 0 : break;
1140 0 : case DPLANE_OP_INTF_UPDATE:
1141 0 : ret = "INTF_UPDATE";
1142 0 : break;
1143 0 : case DPLANE_OP_INTF_DELETE:
1144 0 : ret = "INTF_DELETE";
1145 0 : break;
1146 :
1147 0 : case DPLANE_OP_TC_QDISC_INSTALL:
1148 0 : ret = "TC_QDISC_INSTALL";
1149 0 : break;
1150 0 : case DPLANE_OP_TC_QDISC_UNINSTALL:
1151 0 : ret = "TC_QDISC_UNINSTALL";
1152 0 : break;
1153 0 : case DPLANE_OP_TC_CLASS_ADD:
1154 0 : ret = "TC_CLASS_ADD";
1155 0 : break;
1156 0 : case DPLANE_OP_TC_CLASS_DELETE:
1157 0 : ret = "TC_CLASS_DELETE";
1158 0 : break;
1159 0 : case DPLANE_OP_TC_CLASS_UPDATE:
1160 0 : ret = "TC_CLASS_UPDATE";
1161 0 : break;
1162 0 : case DPLANE_OP_TC_FILTER_ADD:
1163 0 : ret = "TC_FILTER_ADD";
1164 0 : break;
1165 0 : case DPLANE_OP_TC_FILTER_DELETE:
1166 0 : ret = "TC_FILTER_DELETE";
1167 0 : break;
1168 0 : case DPLANE_OP_TC_FILTER_UPDATE:
1169 0 : ret = "TC__FILTER_UPDATE";
1170 0 : break;
1171 : }
1172 :
1173 : return ret;
1174 : }
1175 :
1176 0 : const char *dplane_res2str(enum zebra_dplane_result res)
1177 : {
1178 0 : const char *ret = "<Unknown>";
1179 :
1180 0 : switch (res) {
1181 0 : case ZEBRA_DPLANE_REQUEST_FAILURE:
1182 0 : ret = "FAILURE";
1183 0 : break;
1184 0 : case ZEBRA_DPLANE_REQUEST_QUEUED:
1185 0 : ret = "QUEUED";
1186 0 : break;
1187 0 : case ZEBRA_DPLANE_REQUEST_SUCCESS:
1188 0 : ret = "SUCCESS";
1189 0 : break;
1190 : }
1191 :
1192 0 : return ret;
1193 : }
1194 :
1195 0 : void dplane_ctx_set_dest(struct zebra_dplane_ctx *ctx,
1196 : const struct prefix *dest)
1197 : {
1198 0 : DPLANE_CTX_VALID(ctx);
1199 :
1200 0 : prefix_copy(&(ctx->u.rinfo.zd_dest), dest);
1201 0 : }
1202 :
1203 31 : const struct prefix *dplane_ctx_get_dest(const struct zebra_dplane_ctx *ctx)
1204 : {
1205 31 : DPLANE_CTX_VALID(ctx);
1206 :
1207 31 : return &(ctx->u.rinfo.zd_dest);
1208 : }
1209 :
1210 0 : void dplane_ctx_set_src(struct zebra_dplane_ctx *ctx, const struct prefix *src)
1211 : {
1212 0 : DPLANE_CTX_VALID(ctx);
1213 :
1214 0 : if (src)
1215 0 : prefix_copy(&(ctx->u.rinfo.zd_src), src);
1216 : else
1217 0 : memset(&(ctx->u.rinfo.zd_src), 0, sizeof(struct prefix));
1218 0 : }
1219 :
1220 : /* Source prefix is a little special - return NULL for "no src prefix" */
1221 16 : const struct prefix *dplane_ctx_get_src(const struct zebra_dplane_ctx *ctx)
1222 : {
1223 16 : DPLANE_CTX_VALID(ctx);
1224 :
1225 16 : if (ctx->u.rinfo.zd_src.prefixlen == 0 &&
1226 16 : IN6_IS_ADDR_UNSPECIFIED(&(ctx->u.rinfo.zd_src.u.prefix6))) {
1227 : return NULL;
1228 : } else {
1229 0 : return &(ctx->u.rinfo.zd_src);
1230 : }
1231 : }
1232 :
1233 14 : bool dplane_ctx_is_update(const struct zebra_dplane_ctx *ctx)
1234 : {
1235 14 : DPLANE_CTX_VALID(ctx);
1236 :
1237 14 : return ctx->zd_is_update;
1238 : }
1239 :
1240 8 : uint32_t dplane_ctx_get_seq(const struct zebra_dplane_ctx *ctx)
1241 : {
1242 8 : DPLANE_CTX_VALID(ctx);
1243 :
1244 8 : return ctx->zd_seq;
1245 : }
1246 :
1247 0 : uint32_t dplane_ctx_get_old_seq(const struct zebra_dplane_ctx *ctx)
1248 : {
1249 0 : DPLANE_CTX_VALID(ctx);
1250 :
1251 0 : return ctx->zd_old_seq;
1252 : }
1253 :
1254 0 : void dplane_ctx_set_vrf(struct zebra_dplane_ctx *ctx, vrf_id_t vrf)
1255 : {
1256 0 : DPLANE_CTX_VALID(ctx);
1257 :
1258 0 : ctx->zd_vrf_id = vrf;
1259 0 : }
1260 :
1261 40 : vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx)
1262 : {
1263 40 : DPLANE_CTX_VALID(ctx);
1264 :
1265 40 : return ctx->zd_vrf_id;
1266 : }
1267 :
1268 : /* In some paths we have only a namespace id */
1269 26 : void dplane_ctx_set_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t nsid)
1270 : {
1271 26 : DPLANE_CTX_VALID(ctx);
1272 :
1273 26 : ctx->zd_ns_info.ns_id = nsid;
1274 26 : }
1275 :
1276 26 : ns_id_t dplane_ctx_get_ns_id(const struct zebra_dplane_ctx *ctx)
1277 : {
1278 26 : DPLANE_CTX_VALID(ctx);
1279 :
1280 26 : return ctx->zd_ns_info.ns_id;
1281 : }
1282 :
1283 0 : bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx)
1284 : {
1285 0 : DPLANE_CTX_VALID(ctx);
1286 :
1287 0 : return (ctx->zd_notif_provider != 0);
1288 : }
1289 :
1290 8 : uint32_t dplane_ctx_get_notif_provider(const struct zebra_dplane_ctx *ctx)
1291 : {
1292 8 : DPLANE_CTX_VALID(ctx);
1293 :
1294 8 : return ctx->zd_notif_provider;
1295 : }
1296 :
1297 0 : void dplane_ctx_set_notif_provider(struct zebra_dplane_ctx *ctx,
1298 : uint32_t id)
1299 : {
1300 0 : DPLANE_CTX_VALID(ctx);
1301 :
1302 0 : ctx->zd_notif_provider = id;
1303 0 : }
1304 :
1305 0 : const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx)
1306 : {
1307 0 : DPLANE_CTX_VALID(ctx);
1308 :
1309 0 : return ctx->zd_ifname;
1310 : }
1311 :
1312 0 : void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname)
1313 : {
1314 0 : DPLANE_CTX_VALID(ctx);
1315 :
1316 0 : if (!ifname)
1317 : return;
1318 :
1319 0 : strlcpy(ctx->zd_ifname, ifname, sizeof(ctx->zd_ifname));
1320 : }
1321 :
1322 26 : ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx)
1323 : {
1324 26 : DPLANE_CTX_VALID(ctx);
1325 :
1326 26 : return ctx->zd_ifindex;
1327 : }
1328 :
1329 26 : void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex)
1330 : {
1331 26 : DPLANE_CTX_VALID(ctx);
1332 :
1333 26 : ctx->zd_ifindex = ifindex;
1334 26 : }
1335 :
1336 0 : void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type)
1337 : {
1338 0 : DPLANE_CTX_VALID(ctx);
1339 :
1340 0 : ctx->u.rinfo.zd_type = type;
1341 0 : }
1342 :
1343 62 : int dplane_ctx_get_type(const struct zebra_dplane_ctx *ctx)
1344 : {
1345 62 : DPLANE_CTX_VALID(ctx);
1346 :
1347 62 : return ctx->u.rinfo.zd_type;
1348 : }
1349 :
1350 15 : int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx)
1351 : {
1352 15 : DPLANE_CTX_VALID(ctx);
1353 :
1354 15 : return ctx->u.rinfo.zd_old_type;
1355 : }
1356 :
1357 24 : void dplane_ctx_set_afi(struct zebra_dplane_ctx *ctx, afi_t afi)
1358 : {
1359 24 : DPLANE_CTX_VALID(ctx);
1360 :
1361 24 : ctx->u.rinfo.zd_afi = afi;
1362 24 : }
1363 :
1364 47 : afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx)
1365 : {
1366 47 : DPLANE_CTX_VALID(ctx);
1367 :
1368 47 : return ctx->u.rinfo.zd_afi;
1369 : }
1370 :
1371 0 : void dplane_ctx_set_safi(struct zebra_dplane_ctx *ctx, safi_t safi)
1372 : {
1373 0 : DPLANE_CTX_VALID(ctx);
1374 :
1375 0 : ctx->u.rinfo.zd_safi = safi;
1376 0 : }
1377 :
1378 24 : safi_t dplane_ctx_get_safi(const struct zebra_dplane_ctx *ctx)
1379 : {
1380 24 : DPLANE_CTX_VALID(ctx);
1381 :
1382 24 : return ctx->u.rinfo.zd_safi;
1383 : }
1384 :
1385 0 : void dplane_ctx_set_table(struct zebra_dplane_ctx *ctx, uint32_t table)
1386 : {
1387 0 : DPLANE_CTX_VALID(ctx);
1388 :
1389 0 : ctx->zd_table_id = table;
1390 0 : }
1391 :
1392 24 : uint32_t dplane_ctx_get_table(const struct zebra_dplane_ctx *ctx)
1393 : {
1394 24 : DPLANE_CTX_VALID(ctx);
1395 :
1396 24 : return ctx->zd_table_id;
1397 : }
1398 :
1399 0 : route_tag_t dplane_ctx_get_tag(const struct zebra_dplane_ctx *ctx)
1400 : {
1401 0 : DPLANE_CTX_VALID(ctx);
1402 :
1403 0 : return ctx->u.rinfo.zd_tag;
1404 : }
1405 :
1406 0 : void dplane_ctx_set_tag(struct zebra_dplane_ctx *ctx, route_tag_t tag)
1407 : {
1408 0 : DPLANE_CTX_VALID(ctx);
1409 :
1410 0 : ctx->u.rinfo.zd_tag = tag;
1411 0 : }
1412 :
1413 0 : route_tag_t dplane_ctx_get_old_tag(const struct zebra_dplane_ctx *ctx)
1414 : {
1415 0 : DPLANE_CTX_VALID(ctx);
1416 :
1417 0 : return ctx->u.rinfo.zd_old_tag;
1418 : }
1419 :
1420 17 : uint16_t dplane_ctx_get_instance(const struct zebra_dplane_ctx *ctx)
1421 : {
1422 17 : DPLANE_CTX_VALID(ctx);
1423 :
1424 17 : return ctx->u.rinfo.zd_instance;
1425 : }
1426 :
1427 0 : void dplane_ctx_set_instance(struct zebra_dplane_ctx *ctx, uint16_t instance)
1428 : {
1429 0 : DPLANE_CTX_VALID(ctx);
1430 :
1431 0 : ctx->u.rinfo.zd_instance = instance;
1432 0 : }
1433 :
1434 0 : uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx)
1435 : {
1436 0 : DPLANE_CTX_VALID(ctx);
1437 :
1438 0 : return ctx->u.rinfo.zd_old_instance;
1439 : }
1440 :
1441 0 : uint32_t dplane_ctx_get_flags(const struct zebra_dplane_ctx *ctx)
1442 : {
1443 0 : DPLANE_CTX_VALID(ctx);
1444 :
1445 0 : return ctx->u.rinfo.zd_flags;
1446 : }
1447 :
1448 0 : void dplane_ctx_set_flags(struct zebra_dplane_ctx *ctx, uint32_t flags)
1449 : {
1450 0 : DPLANE_CTX_VALID(ctx);
1451 :
1452 0 : ctx->u.rinfo.zd_flags = flags;
1453 0 : }
1454 :
1455 0 : uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx)
1456 : {
1457 0 : DPLANE_CTX_VALID(ctx);
1458 :
1459 0 : return ctx->u.rinfo.zd_metric;
1460 : }
1461 :
1462 0 : uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx)
1463 : {
1464 0 : DPLANE_CTX_VALID(ctx);
1465 :
1466 0 : return ctx->u.rinfo.zd_old_metric;
1467 : }
1468 :
1469 0 : uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx)
1470 : {
1471 0 : DPLANE_CTX_VALID(ctx);
1472 :
1473 0 : return ctx->u.rinfo.zd_mtu;
1474 : }
1475 :
1476 0 : uint32_t dplane_ctx_get_nh_mtu(const struct zebra_dplane_ctx *ctx)
1477 : {
1478 0 : DPLANE_CTX_VALID(ctx);
1479 :
1480 0 : return ctx->u.rinfo.zd_nexthop_mtu;
1481 : }
1482 :
1483 0 : uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx)
1484 : {
1485 0 : DPLANE_CTX_VALID(ctx);
1486 :
1487 0 : return ctx->u.rinfo.zd_distance;
1488 : }
1489 :
1490 0 : void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance)
1491 : {
1492 0 : DPLANE_CTX_VALID(ctx);
1493 :
1494 0 : ctx->u.rinfo.zd_distance = distance;
1495 0 : }
1496 :
1497 0 : uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx)
1498 : {
1499 0 : DPLANE_CTX_VALID(ctx);
1500 :
1501 0 : return ctx->u.rinfo.zd_old_distance;
1502 : }
1503 :
1504 0 : int dplane_ctx_tc_qdisc_get_kind(const struct zebra_dplane_ctx *ctx)
1505 : {
1506 0 : DPLANE_CTX_VALID(ctx);
1507 :
1508 0 : return ctx->u.tc_qdisc.kind;
1509 : }
1510 :
1511 0 : const char *dplane_ctx_tc_qdisc_get_kind_str(const struct zebra_dplane_ctx *ctx)
1512 : {
1513 0 : DPLANE_CTX_VALID(ctx);
1514 :
1515 0 : return ctx->u.tc_qdisc.kind_str;
1516 : }
1517 :
1518 0 : uint32_t dplane_ctx_tc_class_get_handle(const struct zebra_dplane_ctx *ctx)
1519 : {
1520 0 : DPLANE_CTX_VALID(ctx);
1521 :
1522 0 : return ctx->u.tc_class.handle;
1523 : }
1524 :
1525 0 : int dplane_ctx_tc_class_get_kind(const struct zebra_dplane_ctx *ctx)
1526 : {
1527 0 : DPLANE_CTX_VALID(ctx);
1528 :
1529 0 : return ctx->u.tc_class.kind;
1530 : }
1531 :
1532 0 : const char *dplane_ctx_tc_class_get_kind_str(const struct zebra_dplane_ctx *ctx)
1533 : {
1534 0 : DPLANE_CTX_VALID(ctx);
1535 :
1536 0 : return ctx->u.tc_class.kind_str;
1537 : }
1538 :
1539 0 : uint64_t dplane_ctx_tc_class_get_rate(const struct zebra_dplane_ctx *ctx)
1540 : {
1541 0 : DPLANE_CTX_VALID(ctx);
1542 :
1543 0 : return ctx->u.tc_class.rate;
1544 : }
1545 :
1546 0 : uint64_t dplane_ctx_tc_class_get_ceil(const struct zebra_dplane_ctx *ctx)
1547 : {
1548 0 : DPLANE_CTX_VALID(ctx);
1549 :
1550 0 : return ctx->u.tc_class.ceil;
1551 : }
1552 :
1553 0 : int dplane_ctx_tc_filter_get_kind(const struct zebra_dplane_ctx *ctx)
1554 : {
1555 0 : DPLANE_CTX_VALID(ctx);
1556 :
1557 0 : return ctx->u.tc_filter.kind;
1558 : }
1559 :
1560 : const char *
1561 0 : dplane_ctx_tc_filter_get_kind_str(const struct zebra_dplane_ctx *ctx)
1562 : {
1563 0 : DPLANE_CTX_VALID(ctx);
1564 :
1565 0 : return ctx->u.tc_filter.kind_str;
1566 : }
1567 :
1568 0 : uint32_t dplane_ctx_tc_filter_get_priority(const struct zebra_dplane_ctx *ctx)
1569 : {
1570 0 : DPLANE_CTX_VALID(ctx);
1571 :
1572 0 : return ctx->u.tc_filter.priority;
1573 : }
1574 :
1575 0 : uint32_t dplane_ctx_tc_filter_get_handle(const struct zebra_dplane_ctx *ctx)
1576 : {
1577 0 : DPLANE_CTX_VALID(ctx);
1578 :
1579 0 : return ctx->u.tc_filter.handle;
1580 : }
1581 :
1582 0 : uint16_t dplane_ctx_tc_filter_get_eth_proto(const struct zebra_dplane_ctx *ctx)
1583 : {
1584 0 : DPLANE_CTX_VALID(ctx);
1585 :
1586 0 : return ctx->u.tc_filter.eth_proto;
1587 : }
1588 :
1589 0 : uint32_t dplane_ctx_tc_filter_get_filter_bm(const struct zebra_dplane_ctx *ctx)
1590 : {
1591 0 : DPLANE_CTX_VALID(ctx);
1592 :
1593 0 : return ctx->u.tc_filter.filter_bm;
1594 : }
1595 :
1596 : const struct prefix *
1597 0 : dplane_ctx_tc_filter_get_src_ip(const struct zebra_dplane_ctx *ctx)
1598 : {
1599 0 : DPLANE_CTX_VALID(ctx);
1600 :
1601 0 : return &ctx->u.tc_filter.src_ip;
1602 : }
1603 :
1604 : uint16_t
1605 0 : dplane_ctx_tc_filter_get_src_port_min(const struct zebra_dplane_ctx *ctx)
1606 : {
1607 0 : DPLANE_CTX_VALID(ctx);
1608 :
1609 0 : return ctx->u.tc_filter.src_port_min;
1610 : }
1611 :
1612 :
1613 : uint16_t
1614 0 : dplane_ctx_tc_filter_get_src_port_max(const struct zebra_dplane_ctx *ctx)
1615 : {
1616 0 : DPLANE_CTX_VALID(ctx);
1617 :
1618 0 : return ctx->u.tc_filter.src_port_max;
1619 : }
1620 :
1621 : const struct prefix *
1622 0 : dplane_ctx_tc_filter_get_dst_ip(const struct zebra_dplane_ctx *ctx)
1623 : {
1624 0 : DPLANE_CTX_VALID(ctx);
1625 :
1626 0 : return &ctx->u.tc_filter.dst_ip;
1627 : }
1628 :
1629 : uint16_t
1630 0 : dplane_ctx_tc_filter_get_dst_port_min(const struct zebra_dplane_ctx *ctx)
1631 : {
1632 0 : DPLANE_CTX_VALID(ctx);
1633 :
1634 0 : return ctx->u.tc_filter.dst_port_min;
1635 : }
1636 :
1637 :
1638 : uint16_t
1639 0 : dplane_ctx_tc_filter_get_dst_port_max(const struct zebra_dplane_ctx *ctx)
1640 : {
1641 0 : DPLANE_CTX_VALID(ctx);
1642 :
1643 0 : return ctx->u.tc_filter.dst_port_max;
1644 : }
1645 :
1646 0 : uint8_t dplane_ctx_tc_filter_get_ip_proto(const struct zebra_dplane_ctx *ctx)
1647 : {
1648 0 : DPLANE_CTX_VALID(ctx);
1649 :
1650 0 : return ctx->u.tc_filter.ip_proto;
1651 : }
1652 :
1653 0 : uint8_t dplane_ctx_tc_filter_get_dsfield(const struct zebra_dplane_ctx *ctx)
1654 : {
1655 0 : DPLANE_CTX_VALID(ctx);
1656 :
1657 0 : return ctx->u.tc_filter.dsfield;
1658 : }
1659 :
1660 : uint8_t
1661 0 : dplane_ctx_tc_filter_get_dsfield_mask(const struct zebra_dplane_ctx *ctx)
1662 : {
1663 0 : DPLANE_CTX_VALID(ctx);
1664 :
1665 0 : return ctx->u.tc_filter.dsfield_mask;
1666 : }
1667 :
1668 0 : uint32_t dplane_ctx_tc_filter_get_classid(const struct zebra_dplane_ctx *ctx)
1669 : {
1670 0 : DPLANE_CTX_VALID(ctx);
1671 :
1672 0 : return ctx->u.tc_filter.classid;
1673 : }
1674 :
1675 : /*
1676 : * Set the nexthops associated with a context: note that processing code
1677 : * may well expect that nexthops are in canonical (sorted) order, so we
1678 : * will enforce that here.
1679 : */
1680 0 : void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh)
1681 : {
1682 0 : DPLANE_CTX_VALID(ctx);
1683 :
1684 0 : if (ctx->u.rinfo.zd_ng.nexthop) {
1685 0 : nexthops_free(ctx->u.rinfo.zd_ng.nexthop);
1686 0 : ctx->u.rinfo.zd_ng.nexthop = NULL;
1687 : }
1688 0 : nexthop_group_copy_nh_sorted(&(ctx->u.rinfo.zd_ng), nh);
1689 0 : }
1690 :
1691 : /*
1692 : * Set the list of backup nexthops; their ordering is preserved (they're not
1693 : * re-sorted.)
1694 : */
1695 0 : void dplane_ctx_set_backup_nhg(struct zebra_dplane_ctx *ctx,
1696 : const struct nexthop_group *nhg)
1697 : {
1698 0 : struct nexthop *nh, *last_nh, *nexthop;
1699 :
1700 0 : DPLANE_CTX_VALID(ctx);
1701 :
1702 0 : if (ctx->u.rinfo.backup_ng.nexthop) {
1703 0 : nexthops_free(ctx->u.rinfo.backup_ng.nexthop);
1704 0 : ctx->u.rinfo.backup_ng.nexthop = NULL;
1705 : }
1706 :
1707 0 : last_nh = NULL;
1708 :
1709 : /* Be careful to preserve the order of the backup list */
1710 0 : for (nh = nhg->nexthop; nh; nh = nh->next) {
1711 0 : nexthop = nexthop_dup(nh, NULL);
1712 :
1713 0 : if (last_nh)
1714 0 : NEXTHOP_APPEND(last_nh, nexthop);
1715 : else
1716 0 : ctx->u.rinfo.backup_ng.nexthop = nexthop;
1717 :
1718 0 : last_nh = nexthop;
1719 : }
1720 0 : }
1721 :
1722 0 : uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx)
1723 : {
1724 0 : DPLANE_CTX_VALID(ctx);
1725 0 : return ctx->u.rinfo.zd_nhg_id;
1726 : }
1727 :
1728 17 : const struct nexthop_group *dplane_ctx_get_ng(
1729 : const struct zebra_dplane_ctx *ctx)
1730 : {
1731 17 : DPLANE_CTX_VALID(ctx);
1732 :
1733 17 : return &(ctx->u.rinfo.zd_ng);
1734 : }
1735 :
1736 : const struct nexthop_group *
1737 0 : dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx)
1738 : {
1739 0 : DPLANE_CTX_VALID(ctx);
1740 :
1741 0 : return &(ctx->u.rinfo.backup_ng);
1742 : }
1743 :
1744 : const struct nexthop_group *
1745 0 : dplane_ctx_get_old_ng(const struct zebra_dplane_ctx *ctx)
1746 : {
1747 0 : DPLANE_CTX_VALID(ctx);
1748 :
1749 0 : return &(ctx->u.rinfo.zd_old_ng);
1750 : }
1751 :
1752 : const struct nexthop_group *
1753 0 : dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx)
1754 : {
1755 0 : DPLANE_CTX_VALID(ctx);
1756 :
1757 0 : return &(ctx->u.rinfo.old_backup_ng);
1758 : }
1759 :
1760 41 : const struct zebra_dplane_info *dplane_ctx_get_ns(
1761 : const struct zebra_dplane_ctx *ctx)
1762 : {
1763 41 : DPLANE_CTX_VALID(ctx);
1764 :
1765 41 : return &(ctx->zd_ns_info);
1766 : }
1767 :
1768 20 : int dplane_ctx_get_ns_sock(const struct zebra_dplane_ctx *ctx)
1769 : {
1770 20 : DPLANE_CTX_VALID(ctx);
1771 :
1772 : #ifdef HAVE_NETLINK
1773 20 : return ctx->zd_ns_info.sock;
1774 : #else
1775 : return -1;
1776 : #endif
1777 : }
1778 :
1779 : /* Accessors for nexthop information */
1780 31 : uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx)
1781 : {
1782 31 : DPLANE_CTX_VALID(ctx);
1783 31 : return ctx->u.rinfo.nhe.id;
1784 : }
1785 :
1786 15 : uint32_t dplane_ctx_get_old_nhe_id(const struct zebra_dplane_ctx *ctx)
1787 : {
1788 15 : DPLANE_CTX_VALID(ctx);
1789 15 : return ctx->u.rinfo.nhe.old_id;
1790 : }
1791 :
1792 6 : afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx)
1793 : {
1794 6 : DPLANE_CTX_VALID(ctx);
1795 6 : return ctx->u.rinfo.nhe.afi;
1796 : }
1797 :
1798 0 : vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx)
1799 : {
1800 0 : DPLANE_CTX_VALID(ctx);
1801 0 : return ctx->u.rinfo.nhe.vrf_id;
1802 : }
1803 :
1804 10 : int dplane_ctx_get_nhe_type(const struct zebra_dplane_ctx *ctx)
1805 : {
1806 10 : DPLANE_CTX_VALID(ctx);
1807 10 : return ctx->u.rinfo.nhe.type;
1808 : }
1809 :
1810 : const struct nexthop_group *
1811 6 : dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx)
1812 : {
1813 6 : DPLANE_CTX_VALID(ctx);
1814 6 : return &(ctx->u.rinfo.nhe.ng);
1815 : }
1816 :
1817 : const struct nh_grp *
1818 0 : dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx)
1819 : {
1820 0 : DPLANE_CTX_VALID(ctx);
1821 0 : return ctx->u.rinfo.nhe.nh_grp;
1822 : }
1823 :
1824 6 : uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx)
1825 : {
1826 6 : DPLANE_CTX_VALID(ctx);
1827 6 : return ctx->u.rinfo.nhe.nh_grp_count;
1828 : }
1829 :
1830 : /* Accessors for LSP information */
1831 :
1832 0 : mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx)
1833 : {
1834 0 : DPLANE_CTX_VALID(ctx);
1835 :
1836 0 : return ctx->u.lsp.ile.in_label;
1837 : }
1838 :
1839 0 : void dplane_ctx_set_in_label(struct zebra_dplane_ctx *ctx, mpls_label_t label)
1840 : {
1841 0 : DPLANE_CTX_VALID(ctx);
1842 :
1843 0 : ctx->u.lsp.ile.in_label = label;
1844 0 : }
1845 :
1846 0 : uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx)
1847 : {
1848 0 : DPLANE_CTX_VALID(ctx);
1849 :
1850 0 : return ctx->u.lsp.addr_family;
1851 : }
1852 :
1853 0 : void dplane_ctx_set_addr_family(struct zebra_dplane_ctx *ctx,
1854 : uint8_t family)
1855 : {
1856 0 : DPLANE_CTX_VALID(ctx);
1857 :
1858 0 : ctx->u.lsp.addr_family = family;
1859 0 : }
1860 :
1861 0 : uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx)
1862 : {
1863 0 : DPLANE_CTX_VALID(ctx);
1864 :
1865 0 : return ctx->u.lsp.flags;
1866 : }
1867 :
1868 0 : void dplane_ctx_set_lsp_flags(struct zebra_dplane_ctx *ctx,
1869 : uint32_t flags)
1870 : {
1871 0 : DPLANE_CTX_VALID(ctx);
1872 :
1873 0 : ctx->u.lsp.flags = flags;
1874 0 : }
1875 :
1876 0 : const struct nhlfe_list_head *dplane_ctx_get_nhlfe_list(
1877 : const struct zebra_dplane_ctx *ctx)
1878 : {
1879 0 : DPLANE_CTX_VALID(ctx);
1880 0 : return &(ctx->u.lsp.nhlfe_list);
1881 : }
1882 :
1883 0 : const struct nhlfe_list_head *dplane_ctx_get_backup_nhlfe_list(
1884 : const struct zebra_dplane_ctx *ctx)
1885 : {
1886 0 : DPLANE_CTX_VALID(ctx);
1887 0 : return &(ctx->u.lsp.backup_nhlfe_list);
1888 : }
1889 :
1890 0 : struct zebra_nhlfe *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx,
1891 : enum lsp_types_t lsp_type,
1892 : enum nexthop_types_t nh_type,
1893 : const union g_addr *gate,
1894 : ifindex_t ifindex, uint8_t num_labels,
1895 : mpls_label_t *out_labels)
1896 : {
1897 0 : struct zebra_nhlfe *nhlfe;
1898 :
1899 0 : DPLANE_CTX_VALID(ctx);
1900 :
1901 0 : nhlfe = zebra_mpls_lsp_add_nhlfe(&(ctx->u.lsp),
1902 : lsp_type, nh_type, gate,
1903 : ifindex, num_labels, out_labels);
1904 :
1905 0 : return nhlfe;
1906 : }
1907 :
1908 0 : struct zebra_nhlfe *dplane_ctx_add_backup_nhlfe(
1909 : struct zebra_dplane_ctx *ctx, enum lsp_types_t lsp_type,
1910 : enum nexthop_types_t nh_type, const union g_addr *gate,
1911 : ifindex_t ifindex, uint8_t num_labels, mpls_label_t *out_labels)
1912 : {
1913 0 : struct zebra_nhlfe *nhlfe;
1914 :
1915 0 : DPLANE_CTX_VALID(ctx);
1916 :
1917 0 : nhlfe = zebra_mpls_lsp_add_backup_nhlfe(&(ctx->u.lsp),
1918 : lsp_type, nh_type, gate,
1919 : ifindex, num_labels,
1920 : out_labels);
1921 :
1922 0 : return nhlfe;
1923 : }
1924 :
1925 : const struct zebra_nhlfe *
1926 0 : dplane_ctx_get_best_nhlfe(const struct zebra_dplane_ctx *ctx)
1927 : {
1928 0 : DPLANE_CTX_VALID(ctx);
1929 :
1930 0 : return ctx->u.lsp.best_nhlfe;
1931 : }
1932 :
1933 : const struct zebra_nhlfe *
1934 0 : dplane_ctx_set_best_nhlfe(struct zebra_dplane_ctx *ctx,
1935 : struct zebra_nhlfe *nhlfe)
1936 : {
1937 0 : DPLANE_CTX_VALID(ctx);
1938 :
1939 0 : ctx->u.lsp.best_nhlfe = nhlfe;
1940 0 : return ctx->u.lsp.best_nhlfe;
1941 : }
1942 :
1943 0 : uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx)
1944 : {
1945 0 : DPLANE_CTX_VALID(ctx);
1946 :
1947 0 : return ctx->u.lsp.num_ecmp;
1948 : }
1949 :
1950 0 : mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx)
1951 : {
1952 0 : DPLANE_CTX_VALID(ctx);
1953 :
1954 0 : return ctx->u.pw.local_label;
1955 : }
1956 :
1957 0 : mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx)
1958 : {
1959 0 : DPLANE_CTX_VALID(ctx);
1960 :
1961 0 : return ctx->u.pw.remote_label;
1962 : }
1963 :
1964 0 : int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx)
1965 : {
1966 0 : DPLANE_CTX_VALID(ctx);
1967 :
1968 0 : return ctx->u.pw.type;
1969 : }
1970 :
1971 0 : int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx)
1972 : {
1973 0 : DPLANE_CTX_VALID(ctx);
1974 :
1975 0 : return ctx->u.pw.af;
1976 : }
1977 :
1978 0 : uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx)
1979 : {
1980 0 : DPLANE_CTX_VALID(ctx);
1981 :
1982 0 : return ctx->u.pw.flags;
1983 : }
1984 :
1985 0 : int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx)
1986 : {
1987 0 : DPLANE_CTX_VALID(ctx);
1988 :
1989 0 : return ctx->u.pw.status;
1990 : }
1991 :
1992 0 : void dplane_ctx_set_pw_status(struct zebra_dplane_ctx *ctx, int status)
1993 : {
1994 0 : DPLANE_CTX_VALID(ctx);
1995 :
1996 0 : ctx->u.pw.status = status;
1997 0 : }
1998 :
1999 0 : const union g_addr *dplane_ctx_get_pw_dest(
2000 : const struct zebra_dplane_ctx *ctx)
2001 : {
2002 0 : DPLANE_CTX_VALID(ctx);
2003 :
2004 0 : return &(ctx->u.pw.dest);
2005 : }
2006 :
2007 0 : const union pw_protocol_fields *dplane_ctx_get_pw_proto(
2008 : const struct zebra_dplane_ctx *ctx)
2009 : {
2010 0 : DPLANE_CTX_VALID(ctx);
2011 :
2012 0 : return &(ctx->u.pw.fields);
2013 : }
2014 :
2015 : const struct nexthop_group *
2016 0 : dplane_ctx_get_pw_nhg(const struct zebra_dplane_ctx *ctx)
2017 : {
2018 0 : DPLANE_CTX_VALID(ctx);
2019 :
2020 0 : return &(ctx->u.pw.fib_nhg);
2021 : }
2022 :
2023 : const struct nexthop_group *
2024 0 : dplane_ctx_get_pw_primary_nhg(const struct zebra_dplane_ctx *ctx)
2025 : {
2026 0 : DPLANE_CTX_VALID(ctx);
2027 :
2028 0 : return &(ctx->u.pw.primary_nhg);
2029 : }
2030 :
2031 : const struct nexthop_group *
2032 0 : dplane_ctx_get_pw_backup_nhg(const struct zebra_dplane_ctx *ctx)
2033 : {
2034 0 : DPLANE_CTX_VALID(ctx);
2035 :
2036 0 : return &(ctx->u.pw.backup_nhg);
2037 : }
2038 :
2039 : /* Accessors for interface information */
2040 2 : uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx)
2041 : {
2042 2 : DPLANE_CTX_VALID(ctx);
2043 :
2044 2 : return ctx->u.intf.metric;
2045 : }
2046 :
2047 2 : void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric)
2048 : {
2049 2 : DPLANE_CTX_VALID(ctx);
2050 :
2051 2 : ctx->u.intf.metric = metric;
2052 2 : }
2053 :
2054 0 : uint32_t dplane_ctx_get_intf_pd_reason_val(const struct zebra_dplane_ctx *ctx)
2055 : {
2056 0 : DPLANE_CTX_VALID(ctx);
2057 :
2058 0 : return ctx->u.intf.pd_reason_val;
2059 : }
2060 :
2061 0 : void dplane_ctx_set_intf_pd_reason_val(struct zebra_dplane_ctx *ctx, bool val)
2062 : {
2063 0 : DPLANE_CTX_VALID(ctx);
2064 :
2065 0 : ctx->u.intf.pd_reason_val = val;
2066 0 : }
2067 :
2068 0 : bool dplane_ctx_intf_is_protodown(const struct zebra_dplane_ctx *ctx)
2069 : {
2070 0 : DPLANE_CTX_VALID(ctx);
2071 :
2072 0 : return ctx->u.intf.protodown;
2073 : }
2074 :
2075 : /* Is interface addr p2p? */
2076 2 : bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
2077 : {
2078 2 : DPLANE_CTX_VALID(ctx);
2079 :
2080 2 : return (ctx->u.intf.flags & DPLANE_INTF_CONNECTED);
2081 : }
2082 :
2083 2 : bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx)
2084 : {
2085 2 : DPLANE_CTX_VALID(ctx);
2086 :
2087 2 : return (ctx->u.intf.flags & DPLANE_INTF_SECONDARY);
2088 : }
2089 :
2090 0 : bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx)
2091 : {
2092 0 : DPLANE_CTX_VALID(ctx);
2093 :
2094 0 : return (ctx->u.intf.flags & DPLANE_INTF_BROADCAST);
2095 : }
2096 :
2097 0 : void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx)
2098 : {
2099 0 : DPLANE_CTX_VALID(ctx);
2100 :
2101 0 : ctx->u.intf.flags |= DPLANE_INTF_CONNECTED;
2102 0 : }
2103 :
2104 0 : void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx)
2105 : {
2106 0 : DPLANE_CTX_VALID(ctx);
2107 :
2108 0 : ctx->u.intf.flags |= DPLANE_INTF_SECONDARY;
2109 0 : }
2110 :
2111 0 : void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx)
2112 : {
2113 0 : DPLANE_CTX_VALID(ctx);
2114 :
2115 0 : ctx->u.intf.flags |= DPLANE_INTF_BROADCAST;
2116 0 : }
2117 :
2118 2 : const struct prefix *dplane_ctx_get_intf_addr(
2119 : const struct zebra_dplane_ctx *ctx)
2120 : {
2121 2 : DPLANE_CTX_VALID(ctx);
2122 :
2123 2 : return &(ctx->u.intf.prefix);
2124 : }
2125 :
2126 2 : void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx,
2127 : const struct prefix *p)
2128 : {
2129 2 : DPLANE_CTX_VALID(ctx);
2130 :
2131 2 : prefix_copy(&(ctx->u.intf.prefix), p);
2132 2 : }
2133 :
2134 0 : bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx)
2135 : {
2136 0 : DPLANE_CTX_VALID(ctx);
2137 :
2138 0 : return (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST);
2139 : }
2140 :
2141 2 : const struct prefix *dplane_ctx_get_intf_dest(
2142 : const struct zebra_dplane_ctx *ctx)
2143 : {
2144 2 : DPLANE_CTX_VALID(ctx);
2145 :
2146 2 : return &(ctx->u.intf.dest_prefix);
2147 : }
2148 :
2149 0 : void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx,
2150 : const struct prefix *p)
2151 : {
2152 0 : DPLANE_CTX_VALID(ctx);
2153 :
2154 0 : prefix_copy(&(ctx->u.intf.dest_prefix), p);
2155 0 : }
2156 :
2157 2 : bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx)
2158 : {
2159 2 : DPLANE_CTX_VALID(ctx);
2160 :
2161 2 : return (ctx->u.intf.flags & DPLANE_INTF_HAS_LABEL);
2162 : }
2163 :
2164 0 : const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx)
2165 : {
2166 0 : DPLANE_CTX_VALID(ctx);
2167 :
2168 0 : return ctx->u.intf.label;
2169 : }
2170 :
2171 0 : void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label)
2172 : {
2173 0 : size_t len;
2174 :
2175 0 : DPLANE_CTX_VALID(ctx);
2176 :
2177 0 : if (ctx->u.intf.label && ctx->u.intf.label != ctx->u.intf.label_buf)
2178 0 : XFREE(MTYPE_DP_CTX, ctx->u.intf.label);
2179 :
2180 0 : ctx->u.intf.label = NULL;
2181 :
2182 0 : if (label) {
2183 0 : ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL;
2184 :
2185 : /* Use embedded buffer if it's adequate; else allocate. */
2186 0 : len = strlen(label);
2187 :
2188 0 : if (len < sizeof(ctx->u.intf.label_buf)) {
2189 0 : strlcpy(ctx->u.intf.label_buf, label,
2190 : sizeof(ctx->u.intf.label_buf));
2191 0 : ctx->u.intf.label = ctx->u.intf.label_buf;
2192 : } else {
2193 0 : ctx->u.intf.label = XSTRDUP(MTYPE_DP_CTX, label);
2194 : }
2195 : } else {
2196 0 : ctx->u.intf.flags &= ~DPLANE_INTF_HAS_LABEL;
2197 : }
2198 0 : }
2199 :
2200 : /* Accessors for MAC information */
2201 0 : vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx)
2202 : {
2203 0 : DPLANE_CTX_VALID(ctx);
2204 0 : return ctx->u.macinfo.vid;
2205 : }
2206 :
2207 0 : bool dplane_ctx_mac_is_sticky(const struct zebra_dplane_ctx *ctx)
2208 : {
2209 0 : DPLANE_CTX_VALID(ctx);
2210 0 : return ctx->u.macinfo.is_sticky;
2211 : }
2212 :
2213 0 : uint32_t dplane_ctx_mac_get_nhg_id(const struct zebra_dplane_ctx *ctx)
2214 : {
2215 0 : DPLANE_CTX_VALID(ctx);
2216 0 : return ctx->u.macinfo.nhg_id;
2217 : }
2218 :
2219 0 : uint32_t dplane_ctx_mac_get_update_flags(const struct zebra_dplane_ctx *ctx)
2220 : {
2221 0 : DPLANE_CTX_VALID(ctx);
2222 0 : return ctx->u.macinfo.update_flags;
2223 : }
2224 :
2225 0 : const struct ethaddr *dplane_ctx_mac_get_addr(
2226 : const struct zebra_dplane_ctx *ctx)
2227 : {
2228 0 : DPLANE_CTX_VALID(ctx);
2229 0 : return &(ctx->u.macinfo.mac);
2230 : }
2231 :
2232 0 : const struct in_addr *dplane_ctx_mac_get_vtep_ip(
2233 : const struct zebra_dplane_ctx *ctx)
2234 : {
2235 0 : DPLANE_CTX_VALID(ctx);
2236 0 : return &(ctx->u.macinfo.vtep_ip);
2237 : }
2238 :
2239 0 : ifindex_t dplane_ctx_mac_get_br_ifindex(const struct zebra_dplane_ctx *ctx)
2240 : {
2241 0 : DPLANE_CTX_VALID(ctx);
2242 0 : return ctx->u.macinfo.br_ifindex;
2243 : }
2244 :
2245 : /* Accessors for neighbor information */
2246 0 : const struct ipaddr *dplane_ctx_neigh_get_ipaddr(
2247 : const struct zebra_dplane_ctx *ctx)
2248 : {
2249 0 : DPLANE_CTX_VALID(ctx);
2250 0 : return &(ctx->u.neigh.ip_addr);
2251 : }
2252 :
2253 : const struct ipaddr *
2254 0 : dplane_ctx_neigh_get_link_ip(const struct zebra_dplane_ctx *ctx)
2255 : {
2256 0 : DPLANE_CTX_VALID(ctx);
2257 0 : return &(ctx->u.neigh.link.ip_addr);
2258 : }
2259 :
2260 0 : const struct ethaddr *dplane_ctx_neigh_get_mac(
2261 : const struct zebra_dplane_ctx *ctx)
2262 : {
2263 0 : DPLANE_CTX_VALID(ctx);
2264 0 : return &(ctx->u.neigh.link.mac);
2265 : }
2266 :
2267 0 : uint32_t dplane_ctx_neigh_get_flags(const struct zebra_dplane_ctx *ctx)
2268 : {
2269 0 : DPLANE_CTX_VALID(ctx);
2270 0 : return ctx->u.neigh.flags;
2271 : }
2272 :
2273 0 : uint16_t dplane_ctx_neigh_get_state(const struct zebra_dplane_ctx *ctx)
2274 : {
2275 0 : DPLANE_CTX_VALID(ctx);
2276 0 : return ctx->u.neigh.state;
2277 : }
2278 :
2279 0 : uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx)
2280 : {
2281 0 : DPLANE_CTX_VALID(ctx);
2282 0 : return ctx->u.neigh.update_flags;
2283 : }
2284 :
2285 : /* Accessor for GRE set */
2286 : uint32_t
2287 0 : dplane_ctx_gre_get_link_ifindex(const struct zebra_dplane_ctx *ctx)
2288 : {
2289 0 : DPLANE_CTX_VALID(ctx);
2290 :
2291 0 : return ctx->u.gre.link_ifindex;
2292 : }
2293 :
2294 : unsigned int
2295 0 : dplane_ctx_gre_get_mtu(const struct zebra_dplane_ctx *ctx)
2296 : {
2297 0 : DPLANE_CTX_VALID(ctx);
2298 :
2299 0 : return ctx->u.gre.mtu;
2300 : }
2301 :
2302 : const struct zebra_l2info_gre *
2303 0 : dplane_ctx_gre_get_info(const struct zebra_dplane_ctx *ctx)
2304 : {
2305 0 : DPLANE_CTX_VALID(ctx);
2306 :
2307 0 : return &ctx->u.gre.info;
2308 : }
2309 :
2310 : /* Accessors for PBR rule information */
2311 0 : int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx)
2312 : {
2313 0 : DPLANE_CTX_VALID(ctx);
2314 :
2315 0 : return ctx->u.rule.sock;
2316 : }
2317 :
2318 0 : const char *dplane_ctx_rule_get_ifname(const struct zebra_dplane_ctx *ctx)
2319 : {
2320 0 : DPLANE_CTX_VALID(ctx);
2321 :
2322 0 : return ctx->u.rule.new.ifname;
2323 : }
2324 :
2325 0 : int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx)
2326 : {
2327 0 : DPLANE_CTX_VALID(ctx);
2328 :
2329 0 : return ctx->u.rule.unique;
2330 : }
2331 :
2332 0 : int dplane_ctx_rule_get_seq(const struct zebra_dplane_ctx *ctx)
2333 : {
2334 0 : DPLANE_CTX_VALID(ctx);
2335 :
2336 0 : return ctx->u.rule.seq;
2337 : }
2338 :
2339 0 : uint32_t dplane_ctx_rule_get_priority(const struct zebra_dplane_ctx *ctx)
2340 : {
2341 0 : DPLANE_CTX_VALID(ctx);
2342 :
2343 0 : return ctx->u.rule.new.priority;
2344 : }
2345 :
2346 0 : uint32_t dplane_ctx_rule_get_old_priority(const struct zebra_dplane_ctx *ctx)
2347 : {
2348 0 : DPLANE_CTX_VALID(ctx);
2349 :
2350 0 : return ctx->u.rule.old.priority;
2351 : }
2352 :
2353 0 : uint32_t dplane_ctx_rule_get_table(const struct zebra_dplane_ctx *ctx)
2354 : {
2355 0 : DPLANE_CTX_VALID(ctx);
2356 :
2357 0 : return ctx->u.rule.new.table;
2358 : }
2359 :
2360 0 : uint32_t dplane_ctx_rule_get_old_table(const struct zebra_dplane_ctx *ctx)
2361 : {
2362 0 : DPLANE_CTX_VALID(ctx);
2363 :
2364 0 : return ctx->u.rule.old.table;
2365 : }
2366 :
2367 0 : uint32_t dplane_ctx_rule_get_filter_bm(const struct zebra_dplane_ctx *ctx)
2368 : {
2369 0 : DPLANE_CTX_VALID(ctx);
2370 :
2371 0 : return ctx->u.rule.new.filter_bm;
2372 : }
2373 :
2374 0 : uint32_t dplane_ctx_rule_get_old_filter_bm(const struct zebra_dplane_ctx *ctx)
2375 : {
2376 0 : DPLANE_CTX_VALID(ctx);
2377 :
2378 0 : return ctx->u.rule.old.filter_bm;
2379 : }
2380 :
2381 0 : uint32_t dplane_ctx_rule_get_fwmark(const struct zebra_dplane_ctx *ctx)
2382 : {
2383 0 : DPLANE_CTX_VALID(ctx);
2384 :
2385 0 : return ctx->u.rule.new.fwmark;
2386 : }
2387 :
2388 0 : uint32_t dplane_ctx_rule_get_old_fwmark(const struct zebra_dplane_ctx *ctx)
2389 : {
2390 0 : DPLANE_CTX_VALID(ctx);
2391 :
2392 0 : return ctx->u.rule.old.fwmark;
2393 : }
2394 :
2395 0 : uint8_t dplane_ctx_rule_get_ipproto(const struct zebra_dplane_ctx *ctx)
2396 : {
2397 0 : DPLANE_CTX_VALID(ctx);
2398 :
2399 0 : return ctx->u.rule.new.ip_proto;
2400 : }
2401 :
2402 0 : uint8_t dplane_ctx_rule_get_old_ipproto(const struct zebra_dplane_ctx *ctx)
2403 : {
2404 0 : DPLANE_CTX_VALID(ctx);
2405 :
2406 0 : return ctx->u.rule.old.ip_proto;
2407 : }
2408 :
2409 0 : uint16_t dplane_ctx_rule_get_src_port(const struct zebra_dplane_ctx *ctx)
2410 : {
2411 0 : DPLANE_CTX_VALID(ctx);
2412 :
2413 0 : return ctx->u.rule.new.src_port;
2414 : }
2415 :
2416 0 : uint16_t dplane_ctx_rule_get_old_src_port(const struct zebra_dplane_ctx *ctx)
2417 : {
2418 0 : DPLANE_CTX_VALID(ctx);
2419 :
2420 0 : return ctx->u.rule.old.src_port;
2421 : }
2422 :
2423 0 : uint16_t dplane_ctx_rule_get_dst_port(const struct zebra_dplane_ctx *ctx)
2424 : {
2425 0 : DPLANE_CTX_VALID(ctx);
2426 :
2427 0 : return ctx->u.rule.new.dst_port;
2428 : }
2429 :
2430 0 : uint16_t dplane_ctx_rule_get_old_dst_port(const struct zebra_dplane_ctx *ctx)
2431 : {
2432 0 : DPLANE_CTX_VALID(ctx);
2433 :
2434 0 : return ctx->u.rule.old.dst_port;
2435 : }
2436 :
2437 0 : uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx)
2438 : {
2439 0 : DPLANE_CTX_VALID(ctx);
2440 :
2441 0 : return ctx->u.rule.new.dsfield;
2442 : }
2443 :
2444 0 : uint8_t dplane_ctx_rule_get_old_dsfield(const struct zebra_dplane_ctx *ctx)
2445 : {
2446 0 : DPLANE_CTX_VALID(ctx);
2447 :
2448 0 : return ctx->u.rule.old.dsfield;
2449 : }
2450 :
2451 : const struct prefix *
2452 0 : dplane_ctx_rule_get_src_ip(const struct zebra_dplane_ctx *ctx)
2453 : {
2454 0 : DPLANE_CTX_VALID(ctx);
2455 :
2456 0 : return &(ctx->u.rule.new.src_ip);
2457 : }
2458 :
2459 : const struct prefix *
2460 0 : dplane_ctx_rule_get_old_src_ip(const struct zebra_dplane_ctx *ctx)
2461 : {
2462 0 : DPLANE_CTX_VALID(ctx);
2463 :
2464 0 : return &(ctx->u.rule.old.src_ip);
2465 : }
2466 :
2467 : const struct prefix *
2468 0 : dplane_ctx_rule_get_dst_ip(const struct zebra_dplane_ctx *ctx)
2469 : {
2470 0 : DPLANE_CTX_VALID(ctx);
2471 :
2472 0 : return &(ctx->u.rule.new.dst_ip);
2473 : }
2474 :
2475 : const struct prefix *
2476 0 : dplane_ctx_rule_get_old_dst_ip(const struct zebra_dplane_ctx *ctx)
2477 : {
2478 0 : DPLANE_CTX_VALID(ctx);
2479 :
2480 0 : return &(ctx->u.rule.old.dst_ip);
2481 : }
2482 :
2483 0 : uint32_t dplane_ctx_get_br_port_flags(const struct zebra_dplane_ctx *ctx)
2484 : {
2485 0 : DPLANE_CTX_VALID(ctx);
2486 :
2487 0 : return ctx->u.br_port.flags;
2488 : }
2489 :
2490 : uint32_t
2491 0 : dplane_ctx_get_br_port_sph_filter_cnt(const struct zebra_dplane_ctx *ctx)
2492 : {
2493 0 : DPLANE_CTX_VALID(ctx);
2494 :
2495 0 : return ctx->u.br_port.sph_filter_cnt;
2496 : }
2497 :
2498 : const struct in_addr *
2499 0 : dplane_ctx_get_br_port_sph_filters(const struct zebra_dplane_ctx *ctx)
2500 : {
2501 0 : DPLANE_CTX_VALID(ctx);
2502 :
2503 0 : return ctx->u.br_port.sph_filters;
2504 : }
2505 :
2506 : uint32_t
2507 0 : dplane_ctx_get_br_port_backup_nhg_id(const struct zebra_dplane_ctx *ctx)
2508 : {
2509 0 : DPLANE_CTX_VALID(ctx);
2510 :
2511 0 : return ctx->u.br_port.backup_nhg_id;
2512 : }
2513 :
2514 : /* Accessors for PBR iptable information */
2515 0 : void dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx,
2516 : struct zebra_pbr_iptable *table)
2517 : {
2518 0 : DPLANE_CTX_VALID(ctx);
2519 :
2520 0 : memcpy(table, &ctx->u.iptable, sizeof(struct zebra_pbr_iptable));
2521 0 : }
2522 :
2523 0 : void dplane_ctx_get_pbr_ipset(const struct zebra_dplane_ctx *ctx,
2524 : struct zebra_pbr_ipset *ipset)
2525 : {
2526 0 : DPLANE_CTX_VALID(ctx);
2527 :
2528 0 : assert(ipset);
2529 :
2530 0 : if (ctx->zd_op == DPLANE_OP_IPSET_ENTRY_ADD ||
2531 : ctx->zd_op == DPLANE_OP_IPSET_ENTRY_DELETE) {
2532 0 : memset(ipset, 0, sizeof(struct zebra_pbr_ipset));
2533 0 : ipset->type = ctx->u.ipset_entry.info.type;
2534 0 : ipset->family = ctx->u.ipset_entry.info.family;
2535 0 : memcpy(&ipset->ipset_name, &ctx->u.ipset_entry.info.ipset_name,
2536 : ZEBRA_IPSET_NAME_SIZE);
2537 : } else
2538 0 : memcpy(ipset, &ctx->u.ipset, sizeof(struct zebra_pbr_ipset));
2539 0 : }
2540 :
2541 0 : void dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx,
2542 : struct zebra_pbr_ipset_entry *entry)
2543 : {
2544 0 : DPLANE_CTX_VALID(ctx);
2545 :
2546 0 : assert(entry);
2547 :
2548 0 : memcpy(entry, &ctx->u.ipset_entry.entry, sizeof(struct zebra_pbr_ipset_entry));
2549 0 : }
2550 :
2551 : const struct ethaddr *
2552 0 : dplane_ctx_rule_get_smac(const struct zebra_dplane_ctx *ctx)
2553 : {
2554 0 : DPLANE_CTX_VALID(ctx);
2555 :
2556 0 : return &(ctx->u.rule.new.smac);
2557 : }
2558 :
2559 : const struct ethaddr *
2560 0 : dplane_ctx_rule_get_dmac(const struct zebra_dplane_ctx *ctx)
2561 : {
2562 0 : DPLANE_CTX_VALID(ctx);
2563 :
2564 0 : return &(ctx->u.rule.new.dmac);
2565 : }
2566 :
2567 0 : int dplane_ctx_rule_get_out_ifindex(const struct zebra_dplane_ctx *ctx)
2568 : {
2569 0 : DPLANE_CTX_VALID(ctx);
2570 :
2571 0 : return ctx->u.rule.new.out_ifindex;
2572 : }
2573 :
2574 0 : intptr_t dplane_ctx_rule_get_old_dp_flow_ptr(const struct zebra_dplane_ctx *ctx)
2575 : {
2576 0 : DPLANE_CTX_VALID(ctx);
2577 :
2578 0 : return ctx->u.rule.old.dp_flow_ptr;
2579 : }
2580 :
2581 0 : intptr_t dplane_ctx_rule_get_dp_flow_ptr(const struct zebra_dplane_ctx *ctx)
2582 : {
2583 0 : DPLANE_CTX_VALID(ctx);
2584 :
2585 0 : return ctx->u.rule.new.dp_flow_ptr;
2586 : }
2587 :
2588 0 : void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx,
2589 : intptr_t dp_flow_ptr)
2590 : {
2591 0 : DPLANE_CTX_VALID(ctx);
2592 :
2593 0 : ctx->u.rule.new.dp_flow_ptr = dp_flow_ptr;
2594 0 : }
2595 :
2596 : /*
2597 : * End of dplane context accessors
2598 : */
2599 :
2600 : /* Optional extra info about interfaces in nexthops - a plugin must enable
2601 : * this extra info.
2602 : */
2603 : const struct dplane_intf_extra *
2604 0 : dplane_ctx_get_intf_extra(const struct zebra_dplane_ctx *ctx)
2605 : {
2606 0 : return dplane_intf_extra_list_const_first(
2607 : &ctx->u.rinfo.intf_extra_list);
2608 : }
2609 :
2610 : const struct dplane_intf_extra *
2611 0 : dplane_ctx_intf_extra_next(const struct zebra_dplane_ctx *ctx,
2612 : const struct dplane_intf_extra *ptr)
2613 : {
2614 0 : return dplane_intf_extra_list_const_next(&ctx->u.rinfo.intf_extra_list,
2615 : ptr);
2616 : }
2617 :
2618 0 : vrf_id_t dplane_intf_extra_get_vrfid(const struct dplane_intf_extra *ptr)
2619 : {
2620 0 : return ptr->vrf_id;
2621 : }
2622 :
2623 0 : uint32_t dplane_intf_extra_get_ifindex(const struct dplane_intf_extra *ptr)
2624 : {
2625 0 : return ptr->ifindex;
2626 : }
2627 :
2628 0 : uint32_t dplane_intf_extra_get_flags(const struct dplane_intf_extra *ptr)
2629 : {
2630 0 : return ptr->flags;
2631 : }
2632 :
2633 0 : uint32_t dplane_intf_extra_get_status(const struct dplane_intf_extra *ptr)
2634 : {
2635 0 : return ptr->status;
2636 : }
2637 :
2638 : /*
2639 : * End of interface extra info accessors
2640 : */
2641 :
2642 0 : uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx)
2643 : {
2644 0 : DPLANE_CTX_VALID(ctx);
2645 :
2646 0 : return ctx->u.neightable.family;
2647 : }
2648 :
2649 : uint32_t
2650 0 : dplane_ctx_neightable_get_app_probes(const struct zebra_dplane_ctx *ctx)
2651 : {
2652 0 : DPLANE_CTX_VALID(ctx);
2653 :
2654 0 : return ctx->u.neightable.app_probes;
2655 : }
2656 :
2657 : uint32_t
2658 0 : dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx)
2659 : {
2660 0 : DPLANE_CTX_VALID(ctx);
2661 :
2662 0 : return ctx->u.neightable.ucast_probes;
2663 : }
2664 :
2665 : uint32_t
2666 0 : dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx)
2667 : {
2668 0 : DPLANE_CTX_VALID(ctx);
2669 :
2670 0 : return ctx->u.neightable.mcast_probes;
2671 : }
2672 :
2673 : enum dplane_netconf_status_e
2674 23 : dplane_ctx_get_netconf_mpls(const struct zebra_dplane_ctx *ctx)
2675 : {
2676 23 : DPLANE_CTX_VALID(ctx);
2677 :
2678 23 : return ctx->u.netconf.mpls_val;
2679 : }
2680 :
2681 : enum dplane_netconf_status_e
2682 23 : dplane_ctx_get_netconf_mcast(const struct zebra_dplane_ctx *ctx)
2683 : {
2684 23 : DPLANE_CTX_VALID(ctx);
2685 :
2686 23 : return ctx->u.netconf.mcast_val;
2687 : }
2688 :
2689 : enum dplane_netconf_status_e
2690 23 : dplane_ctx_get_netconf_linkdown(const struct zebra_dplane_ctx *ctx)
2691 : {
2692 23 : DPLANE_CTX_VALID(ctx);
2693 :
2694 23 : return ctx->u.netconf.linkdown_val;
2695 : }
2696 :
2697 24 : void dplane_ctx_set_netconf_mpls(struct zebra_dplane_ctx *ctx,
2698 : enum dplane_netconf_status_e val)
2699 : {
2700 24 : DPLANE_CTX_VALID(ctx);
2701 :
2702 24 : ctx->u.netconf.mpls_val = val;
2703 24 : }
2704 :
2705 24 : void dplane_ctx_set_netconf_mcast(struct zebra_dplane_ctx *ctx,
2706 : enum dplane_netconf_status_e val)
2707 : {
2708 24 : DPLANE_CTX_VALID(ctx);
2709 :
2710 24 : ctx->u.netconf.mcast_val = val;
2711 24 : }
2712 :
2713 24 : void dplane_ctx_set_netconf_linkdown(struct zebra_dplane_ctx *ctx,
2714 : enum dplane_netconf_status_e val)
2715 : {
2716 24 : DPLANE_CTX_VALID(ctx);
2717 :
2718 24 : ctx->u.netconf.linkdown_val = val;
2719 24 : }
2720 :
2721 :
2722 : /*
2723 : * Retrieve the limit on the number of pending, unprocessed updates.
2724 : */
2725 32 : uint32_t dplane_get_in_queue_limit(void)
2726 : {
2727 32 : return atomic_load_explicit(&zdplane_info.dg_max_queued_updates,
2728 : memory_order_relaxed);
2729 : }
2730 :
2731 : /*
2732 : * Configure limit on the number of pending, queued updates.
2733 : */
2734 0 : void dplane_set_in_queue_limit(uint32_t limit, bool set)
2735 : {
2736 : /* Reset to default on 'unset' */
2737 0 : if (!set)
2738 0 : limit = DPLANE_DEFAULT_MAX_QUEUED;
2739 :
2740 0 : atomic_store_explicit(&zdplane_info.dg_max_queued_updates, limit,
2741 : memory_order_relaxed);
2742 0 : }
2743 :
2744 : /*
2745 : * Retrieve the current queue depth of incoming, unprocessed updates
2746 : */
2747 32 : uint32_t dplane_get_in_queue_len(void)
2748 : {
2749 32 : return atomic_load_explicit(&zdplane_info.dg_routes_queued,
2750 : memory_order_seq_cst);
2751 : }
2752 :
2753 : /*
2754 : * Internal helper that copies information from a zebra ns object; this is
2755 : * called in the zebra main pthread context as part of dplane ctx init.
2756 : */
2757 25 : static void ctx_info_from_zns(struct zebra_dplane_info *ns_info,
2758 : struct zebra_ns *zns)
2759 : {
2760 25 : ns_info->ns_id = zns->ns_id;
2761 :
2762 : #if defined(HAVE_NETLINK)
2763 25 : ns_info->is_cmd = true;
2764 25 : ns_info->sock = zns->netlink_dplane_out.sock;
2765 25 : ns_info->seq = zns->netlink_dplane_out.seq;
2766 : #endif /* NETLINK */
2767 : }
2768 :
2769 : /*
2770 : * Common dataplane context init with zebra namespace info.
2771 : */
2772 25 : static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
2773 : struct zebra_ns *zns,
2774 : bool is_update)
2775 : {
2776 25 : ctx_info_from_zns(&(ctx->zd_ns_info), zns); /* */
2777 :
2778 25 : ctx->zd_is_update = is_update;
2779 :
2780 : #if defined(HAVE_NETLINK)
2781 : /* Increment message counter after copying to context struct - may need
2782 : * two messages in some 'update' cases.
2783 : */
2784 25 : if (is_update)
2785 0 : zns->netlink_dplane_out.seq += 2;
2786 : else
2787 25 : zns->netlink_dplane_out.seq++;
2788 : #endif /* HAVE_NETLINK */
2789 :
2790 15 : return AOK;
2791 : }
2792 :
2793 15 : int dplane_ctx_route_init_basic(struct zebra_dplane_ctx *ctx,
2794 : enum dplane_op_e op, struct route_entry *re,
2795 : const struct prefix *p,
2796 : const struct prefix_ipv6 *src_p, afi_t afi,
2797 : safi_t safi)
2798 : {
2799 15 : int ret = EINVAL;
2800 :
2801 15 : if (!ctx || !re)
2802 : return ret;
2803 :
2804 15 : dplane_intf_extra_list_init(&ctx->u.rinfo.intf_extra_list);
2805 :
2806 15 : ctx->zd_op = op;
2807 15 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2808 :
2809 15 : ctx->u.rinfo.zd_type = re->type;
2810 15 : ctx->u.rinfo.zd_old_type = re->type;
2811 :
2812 15 : prefix_copy(&(ctx->u.rinfo.zd_dest), p);
2813 :
2814 15 : if (src_p)
2815 0 : prefix_copy(&(ctx->u.rinfo.zd_src), src_p);
2816 : else
2817 15 : memset(&(ctx->u.rinfo.zd_src), 0, sizeof(ctx->u.rinfo.zd_src));
2818 :
2819 15 : ctx->zd_table_id = re->table;
2820 :
2821 15 : ctx->u.rinfo.zd_flags = re->flags;
2822 15 : ctx->u.rinfo.zd_metric = re->metric;
2823 15 : ctx->u.rinfo.zd_old_metric = re->metric;
2824 15 : ctx->zd_vrf_id = re->vrf_id;
2825 15 : ctx->u.rinfo.zd_mtu = re->mtu;
2826 15 : ctx->u.rinfo.zd_nexthop_mtu = re->nexthop_mtu;
2827 15 : ctx->u.rinfo.zd_instance = re->instance;
2828 15 : ctx->u.rinfo.zd_tag = re->tag;
2829 15 : ctx->u.rinfo.zd_old_tag = re->tag;
2830 15 : ctx->u.rinfo.zd_distance = re->distance;
2831 :
2832 15 : ctx->u.rinfo.zd_afi = afi;
2833 15 : ctx->u.rinfo.zd_safi = safi;
2834 :
2835 15 : return AOK;
2836 : }
2837 :
2838 : /*
2839 : * Initialize a context block for a route update from zebra data structs.
2840 : */
2841 15 : int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
2842 : struct route_node *rn, struct route_entry *re)
2843 : {
2844 15 : int ret = EINVAL;
2845 15 : const struct route_table *table = NULL;
2846 15 : const struct rib_table_info *info;
2847 15 : const struct prefix *p;
2848 15 : const struct prefix_ipv6 *src_p;
2849 15 : struct zebra_ns *zns;
2850 15 : struct zebra_vrf *zvrf;
2851 15 : struct nexthop *nexthop;
2852 15 : struct zebra_l3vni *zl3vni;
2853 15 : const struct interface *ifp;
2854 15 : struct dplane_intf_extra *if_extra;
2855 :
2856 15 : if (!ctx || !rn || !re)
2857 : return ret;
2858 :
2859 : /*
2860 : * Let's grab the data from the route_node
2861 : * so that we can call a helper function
2862 : */
2863 :
2864 : /* Prefixes: dest, and optional source */
2865 15 : srcdest_rnode_prefixes(rn, &p, (const struct prefix **)&src_p);
2866 15 : table = srcdest_rnode_table(rn);
2867 15 : info = table->info;
2868 :
2869 15 : if (dplane_ctx_route_init_basic(ctx, op, re, p, src_p, info->afi,
2870 15 : info->safi) != AOK)
2871 : return ret;
2872 :
2873 : /* Copy nexthops; recursive info is included too */
2874 15 : copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop),
2875 15 : re->nhe->nhg.nexthop, NULL);
2876 15 : ctx->u.rinfo.zd_nhg_id = re->nhe->id;
2877 :
2878 : /* Copy backup nexthop info, if present */
2879 15 : if (re->nhe->backup_info && re->nhe->backup_info->nhe) {
2880 0 : copy_nexthops(&(ctx->u.rinfo.backup_ng.nexthop),
2881 0 : re->nhe->backup_info->nhe->nhg.nexthop, NULL);
2882 : }
2883 :
2884 : /*
2885 : * Ensure that the dplane nexthops' flags are clear and copy
2886 : * encapsulation information.
2887 : */
2888 30 : for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) {
2889 15 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
2890 :
2891 : /* Optionally capture extra interface info while we're in the
2892 : * main zebra pthread - a plugin has to ask for this info.
2893 : */
2894 15 : if (dplane_collect_extra_intf_info) {
2895 0 : ifp = if_lookup_by_index(nexthop->ifindex,
2896 : nexthop->vrf_id);
2897 :
2898 0 : if (ifp) {
2899 0 : if_extra = XCALLOC(
2900 : MTYPE_DP_INTF,
2901 : sizeof(struct dplane_intf_extra));
2902 0 : if_extra->vrf_id = nexthop->vrf_id;
2903 0 : if_extra->ifindex = nexthop->ifindex;
2904 0 : if_extra->flags = ifp->flags;
2905 0 : if_extra->status = ifp->status;
2906 :
2907 0 : dplane_intf_extra_list_add_tail(
2908 : &ctx->u.rinfo.intf_extra_list,
2909 : if_extra);
2910 : }
2911 : }
2912 :
2913 : /* Check for available evpn encapsulations. */
2914 15 : if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN))
2915 15 : continue;
2916 :
2917 0 : zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
2918 0 : if (zl3vni && is_l3vni_oper_up(zl3vni)) {
2919 0 : nexthop->nh_encap_type = NET_VXLAN;
2920 0 : nexthop->nh_encap.vni = zl3vni->vni;
2921 : }
2922 : }
2923 :
2924 : /* Don't need some info when capturing a system notification */
2925 15 : if (op == DPLANE_OP_SYS_ROUTE_ADD ||
2926 : op == DPLANE_OP_SYS_ROUTE_DELETE) {
2927 : return AOK;
2928 : }
2929 :
2930 : /* Extract ns info - can't use pointers to 'core' structs */
2931 15 : zvrf = vrf_info_lookup(re->vrf_id);
2932 15 : zns = zvrf->zns;
2933 15 : dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
2934 :
2935 : #ifdef HAVE_NETLINK
2936 : {
2937 15 : struct nhg_hash_entry *nhe = zebra_nhg_resolve(re->nhe);
2938 :
2939 15 : ctx->u.rinfo.nhe.id = nhe->id;
2940 15 : ctx->u.rinfo.nhe.old_id = 0;
2941 : /*
2942 : * Check if the nhe is installed/queued before doing anything
2943 : * with this route.
2944 : *
2945 : * If its a delete we only use the prefix anyway, so this only
2946 : * matters for INSTALL/UPDATE.
2947 : */
2948 15 : if (zebra_nhg_kernel_nexthops_enabled() &&
2949 15 : (((op == DPLANE_OP_ROUTE_INSTALL) ||
2950 : (op == DPLANE_OP_ROUTE_UPDATE)) &&
2951 8 : !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) &&
2952 : !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)))
2953 : return ENOENT;
2954 :
2955 15 : re->nhe_installed_id = nhe->id;
2956 : }
2957 : #endif /* HAVE_NETLINK */
2958 :
2959 : /* Trying out the sequence number idea, so we can try to detect
2960 : * when a result is stale.
2961 : */
2962 15 : re->dplane_sequence = zebra_router_get_next_sequence();
2963 15 : ctx->zd_seq = re->dplane_sequence;
2964 :
2965 15 : return AOK;
2966 : }
2967 :
2968 0 : static int dplane_ctx_tc_qdisc_init(struct zebra_dplane_ctx *ctx,
2969 : enum dplane_op_e op,
2970 : const struct zebra_tc_qdisc *qdisc)
2971 : {
2972 0 : int ret = EINVAL;
2973 :
2974 0 : struct zebra_ns *zns = NULL;
2975 :
2976 0 : ctx->zd_op = op;
2977 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
2978 0 : ctx->zd_ifindex = qdisc->qdisc.ifindex;
2979 0 : ctx->u.tc_qdisc.kind = qdisc->qdisc.kind;
2980 0 : ctx->u.tc_qdisc.kind_str = tc_qdisc_kind2str(qdisc->qdisc.kind);
2981 :
2982 : /* TODO: init traffic control qdisc */
2983 0 : zns = zebra_ns_lookup(NS_DEFAULT);
2984 :
2985 0 : dplane_ctx_ns_init(ctx, zns, true);
2986 :
2987 0 : ret = AOK;
2988 :
2989 0 : return ret;
2990 : }
2991 :
2992 0 : static int dplane_ctx_tc_class_init(struct zebra_dplane_ctx *ctx,
2993 : enum dplane_op_e op,
2994 : struct zebra_tc_class *class)
2995 : {
2996 0 : int ret = EINVAL;
2997 :
2998 0 : struct zebra_ns *zns = NULL;
2999 :
3000 0 : ctx->zd_op = op;
3001 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3002 0 : ctx->zd_ifindex = class->class.ifindex;
3003 :
3004 0 : ctx->u.tc_class.handle = class->class.handle;
3005 0 : ctx->u.tc_class.kind = class->class.kind;
3006 0 : ctx->u.tc_class.kind_str = tc_qdisc_kind2str(class->class.kind);
3007 0 : ctx->u.tc_class.rate = class->class.u.htb.rate;
3008 0 : ctx->u.tc_class.ceil = class->class.u.htb.ceil;
3009 :
3010 0 : zns = zebra_ns_lookup(NS_DEFAULT);
3011 :
3012 0 : dplane_ctx_ns_init(ctx, zns, true);
3013 :
3014 0 : ret = AOK;
3015 :
3016 0 : return ret;
3017 : }
3018 :
3019 0 : static int dplane_ctx_tc_filter_init(struct zebra_dplane_ctx *ctx,
3020 : enum dplane_op_e op,
3021 : struct zebra_tc_filter *filter)
3022 : {
3023 0 : int ret = EINVAL;
3024 :
3025 0 : struct zebra_ns *zns = NULL;
3026 :
3027 0 : ctx->zd_op = op;
3028 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3029 0 : ctx->zd_ifindex = filter->filter.ifindex;
3030 :
3031 0 : ctx->u.tc_filter.eth_proto = filter->filter.protocol;
3032 0 : ctx->u.tc_filter.ip_proto = filter->filter.u.flower.ip_proto;
3033 :
3034 0 : ctx->u.tc_filter.kind = filter->filter.kind;
3035 0 : ctx->u.tc_filter.kind_str = tc_filter_kind2str(filter->filter.kind);
3036 :
3037 0 : ctx->u.tc_filter.filter_bm = filter->filter.u.flower.filter_bm;
3038 0 : prefix_copy(&ctx->u.tc_filter.src_ip, &filter->filter.u.flower.src_ip);
3039 0 : ctx->u.tc_filter.src_port_min = filter->filter.u.flower.src_port_min;
3040 0 : ctx->u.tc_filter.src_port_max = filter->filter.u.flower.src_port_max;
3041 0 : prefix_copy(&ctx->u.tc_filter.dst_ip, &filter->filter.u.flower.dst_ip);
3042 0 : ctx->u.tc_filter.dst_port_min = filter->filter.u.flower.dst_port_min;
3043 0 : ctx->u.tc_filter.dst_port_max = filter->filter.u.flower.dst_port_max;
3044 0 : ctx->u.tc_filter.dsfield = filter->filter.u.flower.dsfield;
3045 0 : ctx->u.tc_filter.dsfield_mask = filter->filter.u.flower.dsfield_mask;
3046 0 : ctx->u.tc_filter.classid = filter->filter.u.flower.classid;
3047 :
3048 0 : ctx->u.tc_filter.priority = filter->filter.priority;
3049 0 : ctx->u.tc_filter.handle = filter->filter.handle;
3050 :
3051 0 : zns = zebra_ns_lookup(NS_DEFAULT);
3052 :
3053 0 : dplane_ctx_ns_init(ctx, zns, true);
3054 :
3055 0 : ret = AOK;
3056 :
3057 0 : return ret;
3058 : }
3059 :
3060 : /**
3061 : * dplane_ctx_nexthop_init() - Initialize a context block for a nexthop update
3062 : *
3063 : * @ctx: Dataplane context to init
3064 : * @op: Operation being performed
3065 : * @nhe: Nexthop group hash entry
3066 : *
3067 : * Return: Result status
3068 : */
3069 10 : int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
3070 : struct nhg_hash_entry *nhe)
3071 : {
3072 10 : struct zebra_vrf *zvrf = NULL;
3073 10 : struct zebra_ns *zns = NULL;
3074 10 : int ret = EINVAL;
3075 :
3076 10 : if (!ctx || !nhe)
3077 : return ret;
3078 :
3079 10 : ctx->zd_op = op;
3080 10 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3081 :
3082 : /* Copy over nhe info */
3083 10 : ctx->u.rinfo.nhe.id = nhe->id;
3084 10 : ctx->u.rinfo.nhe.afi = nhe->afi;
3085 10 : ctx->u.rinfo.nhe.vrf_id = nhe->vrf_id;
3086 10 : ctx->u.rinfo.nhe.type = nhe->type;
3087 :
3088 10 : nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), &(nhe->nhg));
3089 :
3090 : /* If this is a group, convert it to a grp array of ids */
3091 10 : if (!zebra_nhg_depends_is_empty(nhe)
3092 0 : && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE))
3093 0 : ctx->u.rinfo.nhe.nh_grp_count = zebra_nhg_nhe2grp(
3094 0 : ctx->u.rinfo.nhe.nh_grp, nhe, MULTIPATH_NUM);
3095 :
3096 10 : zvrf = vrf_info_lookup(nhe->vrf_id);
3097 :
3098 : /*
3099 : * Fallback to default namespace if the vrf got ripped out from under
3100 : * us.
3101 : */
3102 10 : zns = zvrf ? zvrf->zns : zebra_ns_lookup(NS_DEFAULT);
3103 :
3104 : /*
3105 : * TODO: Might not need to mark this as an update, since
3106 : * it probably won't require two messages
3107 : */
3108 10 : dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_NH_UPDATE));
3109 :
3110 10 : ret = AOK;
3111 :
3112 : return ret;
3113 : }
3114 :
3115 : /**
3116 : * dplane_ctx_intf_init() - Initialize a context block for a interface update
3117 : *
3118 : * @ctx: Dataplane context to init
3119 : * @op: Operation being performed
3120 : * @ifp: Interface
3121 : *
3122 : * Return: Result status
3123 : */
3124 0 : int dplane_ctx_intf_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
3125 : const struct interface *ifp)
3126 : {
3127 0 : struct zebra_ns *zns;
3128 0 : struct zebra_if *zif;
3129 0 : int ret = EINVAL;
3130 0 : bool set_pdown, unset_pdown;
3131 :
3132 0 : if (!ctx || !ifp)
3133 : return ret;
3134 :
3135 0 : ctx->zd_op = op;
3136 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3137 0 : ctx->zd_vrf_id = ifp->vrf->vrf_id;
3138 :
3139 0 : strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
3140 0 : ctx->zd_ifindex = ifp->ifindex;
3141 :
3142 0 : zns = zebra_ns_lookup(ifp->vrf->vrf_id);
3143 0 : dplane_ctx_ns_init(ctx, zns, false);
3144 :
3145 :
3146 : /* Copy over ifp info */
3147 0 : ctx->u.intf.metric = ifp->metric;
3148 0 : ctx->u.intf.flags = ifp->flags;
3149 :
3150 : /* Copy over extra zebra info, if available */
3151 0 : zif = (struct zebra_if *)ifp->info;
3152 :
3153 0 : if (zif) {
3154 0 : set_pdown = !!(zif->flags & ZIF_FLAG_SET_PROTODOWN);
3155 0 : unset_pdown = !!(zif->flags & ZIF_FLAG_UNSET_PROTODOWN);
3156 :
3157 0 : if (zif->protodown_rc &&
3158 : ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) == false)
3159 0 : ctx->u.intf.pd_reason_val = true;
3160 :
3161 : /*
3162 : * See if we have new protodown state to set, otherwise keep
3163 : * current state
3164 : */
3165 0 : if (set_pdown)
3166 0 : ctx->u.intf.protodown = true;
3167 0 : else if (unset_pdown)
3168 0 : ctx->u.intf.protodown = false;
3169 : else
3170 0 : ctx->u.intf.protodown = !!ZEBRA_IF_IS_PROTODOWN(zif);
3171 : }
3172 :
3173 0 : dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_INTF_UPDATE));
3174 0 : ctx->zd_is_update = (op == DPLANE_OP_INTF_UPDATE);
3175 :
3176 0 : ret = AOK;
3177 :
3178 0 : return ret;
3179 : }
3180 :
3181 : /*
3182 : * Capture information for an LSP update in a dplane context.
3183 : */
3184 0 : int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
3185 : struct zebra_lsp *lsp)
3186 : {
3187 0 : int ret = AOK;
3188 0 : struct zebra_nhlfe *nhlfe, *new_nhlfe;
3189 :
3190 0 : ctx->zd_op = op;
3191 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3192 :
3193 : /* Capture namespace info */
3194 0 : dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
3195 : (op == DPLANE_OP_LSP_UPDATE));
3196 :
3197 0 : memset(&ctx->u.lsp, 0, sizeof(ctx->u.lsp));
3198 :
3199 0 : nhlfe_list_init(&(ctx->u.lsp.nhlfe_list));
3200 0 : nhlfe_list_init(&(ctx->u.lsp.backup_nhlfe_list));
3201 :
3202 : /* This may be called to create/init a dplane context, not necessarily
3203 : * to copy an lsp object.
3204 : */
3205 0 : if (lsp == NULL)
3206 : return ret;
3207 :
3208 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3209 0 : zlog_debug("init dplane ctx %s: in-label %u ecmp# %d",
3210 : dplane_op2str(op), lsp->ile.in_label,
3211 : lsp->num_ecmp);
3212 :
3213 0 : ctx->u.lsp.ile = lsp->ile;
3214 0 : ctx->u.lsp.addr_family = lsp->addr_family;
3215 0 : ctx->u.lsp.num_ecmp = lsp->num_ecmp;
3216 0 : ctx->u.lsp.flags = lsp->flags;
3217 :
3218 : /* Copy source LSP's nhlfes, and capture 'best' nhlfe */
3219 0 : frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
3220 : /* Not sure if this is meaningful... */
3221 0 : if (nhlfe->nexthop == NULL)
3222 0 : continue;
3223 :
3224 0 : new_nhlfe = zebra_mpls_lsp_add_nh(&(ctx->u.lsp), nhlfe->type,
3225 : nhlfe->nexthop);
3226 0 : if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) {
3227 : ret = ENOMEM;
3228 : break;
3229 : }
3230 :
3231 : /* Need to copy flags and backup info too */
3232 0 : new_nhlfe->flags = nhlfe->flags;
3233 0 : new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
3234 :
3235 0 : if (CHECK_FLAG(new_nhlfe->nexthop->flags,
3236 : NEXTHOP_FLAG_HAS_BACKUP)) {
3237 0 : new_nhlfe->nexthop->backup_num =
3238 0 : nhlfe->nexthop->backup_num;
3239 0 : memcpy(new_nhlfe->nexthop->backup_idx,
3240 0 : nhlfe->nexthop->backup_idx,
3241 : new_nhlfe->nexthop->backup_num);
3242 : }
3243 :
3244 0 : if (nhlfe == lsp->best_nhlfe)
3245 0 : ctx->u.lsp.best_nhlfe = new_nhlfe;
3246 : }
3247 :
3248 0 : if (ret != AOK)
3249 : return ret;
3250 :
3251 : /* Capture backup nhlfes/nexthops */
3252 0 : frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
3253 : /* Not sure if this is meaningful... */
3254 0 : if (nhlfe->nexthop == NULL)
3255 0 : continue;
3256 :
3257 0 : new_nhlfe = zebra_mpls_lsp_add_backup_nh(&(ctx->u.lsp),
3258 : nhlfe->type,
3259 : nhlfe->nexthop);
3260 0 : if (new_nhlfe == NULL || new_nhlfe->nexthop == NULL) {
3261 : ret = ENOMEM;
3262 : break;
3263 : }
3264 :
3265 : /* Need to copy flags too */
3266 0 : new_nhlfe->flags = nhlfe->flags;
3267 0 : new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
3268 : }
3269 :
3270 : return ret;
3271 : }
3272 :
3273 : /*
3274 : * Capture information for an LSP update in a dplane context.
3275 : */
3276 0 : static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
3277 : enum dplane_op_e op,
3278 : struct zebra_pw *pw)
3279 : {
3280 0 : int ret = EINVAL;
3281 0 : struct prefix p;
3282 0 : afi_t afi;
3283 0 : struct route_table *table;
3284 0 : struct route_node *rn;
3285 0 : struct route_entry *re;
3286 0 : const struct nexthop_group *nhg;
3287 0 : struct nexthop *nh, *newnh, *last_nh;
3288 :
3289 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3290 0 : zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u",
3291 : dplane_op2str(op), pw->ifname, pw->local_label,
3292 : pw->remote_label);
3293 :
3294 0 : ctx->zd_op = op;
3295 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3296 :
3297 : /* Capture namespace info: no netlink support as of 12/18,
3298 : * but just in case...
3299 : */
3300 0 : dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
3301 :
3302 0 : memset(&ctx->u.pw, 0, sizeof(ctx->u.pw));
3303 :
3304 : /* This name appears to be c-string, so we use string copy. */
3305 0 : strlcpy(ctx->zd_ifname, pw->ifname, sizeof(ctx->zd_ifname));
3306 :
3307 0 : ctx->zd_vrf_id = pw->vrf_id;
3308 0 : ctx->zd_ifindex = pw->ifindex;
3309 0 : ctx->u.pw.type = pw->type;
3310 0 : ctx->u.pw.af = pw->af;
3311 0 : ctx->u.pw.local_label = pw->local_label;
3312 0 : ctx->u.pw.remote_label = pw->remote_label;
3313 0 : ctx->u.pw.flags = pw->flags;
3314 :
3315 0 : ctx->u.pw.dest = pw->nexthop;
3316 :
3317 0 : ctx->u.pw.fields = pw->data;
3318 :
3319 : /* Capture nexthop info for the pw destination. We need to look
3320 : * up and use zebra datastructs, but we're running in the zebra
3321 : * pthread here so that should be ok.
3322 : */
3323 0 : memcpy(&p.u, &pw->nexthop, sizeof(pw->nexthop));
3324 0 : p.family = pw->af;
3325 0 : p.prefixlen = ((pw->af == AF_INET) ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN);
3326 :
3327 0 : afi = (pw->af == AF_INET) ? AFI_IP : AFI_IP6;
3328 0 : table = zebra_vrf_table(afi, SAFI_UNICAST, pw->vrf_id);
3329 0 : if (table == NULL)
3330 : return ret;
3331 :
3332 0 : rn = route_node_match(table, &p);
3333 0 : if (rn == NULL)
3334 : return ret;
3335 :
3336 0 : re = NULL;
3337 0 : RNODE_FOREACH_RE(rn, re) {
3338 0 : if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
3339 : break;
3340 : }
3341 :
3342 0 : if (re) {
3343 : /* We'll capture a 'fib' list of nexthops that meet our
3344 : * criteria: installed, and labelled.
3345 : */
3346 0 : nhg = rib_get_fib_nhg(re);
3347 0 : last_nh = NULL;
3348 :
3349 0 : if (nhg && nhg->nexthop) {
3350 0 : for (ALL_NEXTHOPS_PTR(nhg, nh)) {
3351 0 : if (!CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)
3352 : || CHECK_FLAG(nh->flags,
3353 : NEXTHOP_FLAG_RECURSIVE)
3354 0 : || nh->nh_label == NULL)
3355 0 : continue;
3356 :
3357 0 : newnh = nexthop_dup(nh, NULL);
3358 :
3359 0 : if (last_nh)
3360 0 : NEXTHOP_APPEND(last_nh, newnh);
3361 : else
3362 0 : ctx->u.pw.fib_nhg.nexthop = newnh;
3363 : last_nh = newnh;
3364 : }
3365 : }
3366 :
3367 : /* Include any installed backup nexthops also. */
3368 0 : nhg = rib_get_fib_backup_nhg(re);
3369 0 : if (nhg && nhg->nexthop) {
3370 0 : for (ALL_NEXTHOPS_PTR(nhg, nh)) {
3371 0 : if (!CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)
3372 : || CHECK_FLAG(nh->flags,
3373 : NEXTHOP_FLAG_RECURSIVE)
3374 0 : || nh->nh_label == NULL)
3375 0 : continue;
3376 :
3377 0 : newnh = nexthop_dup(nh, NULL);
3378 :
3379 0 : if (last_nh)
3380 0 : NEXTHOP_APPEND(last_nh, newnh);
3381 : else
3382 0 : ctx->u.pw.fib_nhg.nexthop = newnh;
3383 : last_nh = newnh;
3384 : }
3385 : }
3386 :
3387 : /* Copy primary nexthops; recursive info is included too */
3388 0 : assert(re->nhe != NULL); /* SA warning */
3389 0 : copy_nexthops(&(ctx->u.pw.primary_nhg.nexthop),
3390 0 : re->nhe->nhg.nexthop, NULL);
3391 0 : ctx->u.pw.nhg_id = re->nhe->id;
3392 :
3393 : /* Copy backup nexthop info, if present */
3394 0 : if (re->nhe->backup_info && re->nhe->backup_info->nhe) {
3395 0 : copy_nexthops(&(ctx->u.pw.backup_nhg.nexthop),
3396 0 : re->nhe->backup_info->nhe->nhg.nexthop,
3397 : NULL);
3398 : }
3399 : }
3400 0 : route_unlock_node(rn);
3401 :
3402 0 : return AOK;
3403 : }
3404 :
3405 : /**
3406 : * dplane_ctx_rule_init_single() - Initialize a dataplane representation of a
3407 : * PBR rule.
3408 : *
3409 : * @dplane_rule: Dataplane internal representation of a rule
3410 : * @rule: PBR rule
3411 : */
3412 0 : static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,
3413 : struct zebra_pbr_rule *rule)
3414 : {
3415 0 : struct zebra_neigh_ent *n;
3416 :
3417 0 : dplane_rule->priority = rule->rule.priority;
3418 0 : dplane_rule->table = rule->rule.action.table;
3419 :
3420 0 : dplane_rule->filter_bm = rule->rule.filter.filter_bm;
3421 0 : dplane_rule->fwmark = rule->rule.filter.fwmark;
3422 0 : dplane_rule->dsfield = rule->rule.filter.dsfield;
3423 0 : dplane_rule->ip_proto = rule->rule.filter.ip_proto;
3424 0 : dplane_rule->src_port = rule->rule.filter.src_port;
3425 0 : dplane_rule->dst_port = rule->rule.filter.dst_port;
3426 0 : prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip);
3427 0 : prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip);
3428 :
3429 0 : dplane_rule->action_pcp = rule->rule.action.pcp;
3430 0 : dplane_rule->action_vlan_flags = rule->rule.action.vlan_flags;
3431 0 : dplane_rule->action_vlan_id = rule->rule.action.vlan_id;
3432 0 : dplane_rule->action_queue_id = rule->rule.action.queue_id;
3433 :
3434 0 : strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ);
3435 0 : dplane_rule->dp_flow_ptr = rule->action.dp_flow_ptr;
3436 0 : n = rule->action.neigh;
3437 0 : if (n && (n->flags & ZEBRA_NEIGH_ENT_ACTIVE)) {
3438 0 : struct interface *ifp = if_lookup_by_index_per_ns(
3439 0 : zebra_ns_lookup(NS_DEFAULT), n->ifindex);
3440 0 : if (ifp) {
3441 0 : dplane_rule->out_ifindex = n->ifindex;
3442 0 : memcpy(&dplane_rule->dmac, &n->mac, ETH_ALEN);
3443 0 : memcpy(&dplane_rule->smac, ifp->hw_addr, ETH_ALEN);
3444 : } else {
3445 0 : dplane_rule->out_ifindex = 0;
3446 : }
3447 : }
3448 0 : }
3449 :
3450 : /**
3451 : * dplane_ctx_rule_init() - Initialize a context block for a PBR rule update.
3452 : *
3453 : * @ctx: Dataplane context to init
3454 : * @op: Operation being performed
3455 : * @new_rule: PBR rule
3456 : *
3457 : * Return: Result status
3458 : */
3459 0 : static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx,
3460 : enum dplane_op_e op,
3461 : struct zebra_pbr_rule *new_rule,
3462 : struct zebra_pbr_rule *old_rule)
3463 : {
3464 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
3465 0 : zlog_debug(
3466 : "init dplane ctx %s: IF %s Prio %u Fwmark %u Src %pFX Dst %pFX Table %u",
3467 : dplane_op2str(op), new_rule->ifname,
3468 : new_rule->rule.priority, new_rule->rule.filter.fwmark,
3469 : &new_rule->rule.filter.src_ip,
3470 : &new_rule->rule.filter.dst_ip,
3471 : new_rule->rule.action.table);
3472 :
3473 0 : ctx->zd_op = op;
3474 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3475 :
3476 0 : dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
3477 : op == DPLANE_OP_RULE_UPDATE);
3478 :
3479 0 : ctx->zd_vrf_id = new_rule->vrf_id;
3480 0 : strlcpy(ctx->zd_ifname, new_rule->ifname, sizeof(ctx->zd_ifname));
3481 :
3482 0 : ctx->u.rule.sock = new_rule->sock;
3483 0 : ctx->u.rule.unique = new_rule->rule.unique;
3484 0 : ctx->u.rule.seq = new_rule->rule.seq;
3485 :
3486 0 : dplane_ctx_rule_init_single(&ctx->u.rule.new, new_rule);
3487 0 : if (op == DPLANE_OP_RULE_UPDATE) {
3488 0 : dplane_ctx_rule_init_single(&ctx->u.rule.old, old_rule);
3489 : /* clear the dp_flow_ptr in the old_rule - it is about to be
3490 : * deleted
3491 : */
3492 0 : old_rule->action.dp_flow_ptr = (intptr_t)NULL;
3493 : }
3494 :
3495 0 : return AOK;
3496 : }
3497 :
3498 0 : static void zebra_dplane_interface_name_list_deletion(void *data)
3499 : {
3500 0 : XFREE(MTYPE_DP_NETFILTER, data);
3501 0 : }
3502 :
3503 : /**
3504 : * dplane_ctx_iptable_init() - Initialize a context block for a PBR iptable
3505 : * update.
3506 : *
3507 : * @ctx: Dataplane context to init
3508 : * @op: Operation being performed
3509 : * @new_rule: PBR iptable
3510 : *
3511 : * Return: Result status
3512 : */
3513 0 : static int dplane_ctx_iptable_init(struct zebra_dplane_ctx *ctx,
3514 : enum dplane_op_e op,
3515 : struct zebra_pbr_iptable *iptable)
3516 : {
3517 0 : char *ifname;
3518 0 : struct listnode *node;
3519 :
3520 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
3521 0 : zlog_debug(
3522 : "init dplane ctx %s: Unique %u Fwmark %u Family %s Action %s",
3523 : dplane_op2str(op), iptable->unique, iptable->fwmark,
3524 : family2str(iptable->family),
3525 : iptable->action == ZEBRA_IPTABLES_DROP ? "Drop"
3526 : : "Forward");
3527 : }
3528 :
3529 0 : ctx->zd_op = op;
3530 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3531 :
3532 0 : dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
3533 :
3534 0 : ctx->zd_vrf_id = iptable->vrf_id;
3535 0 : memcpy(&ctx->u.iptable, iptable, sizeof(struct zebra_pbr_iptable));
3536 0 : if (iptable->nb_interface > 0) {
3537 0 : ctx->u.iptable.interface_name_list = list_new();
3538 0 : ctx->u.iptable.interface_name_list->del =
3539 : zebra_dplane_interface_name_list_deletion;
3540 0 : for (ALL_LIST_ELEMENTS_RO(iptable->interface_name_list, node,
3541 : ifname)) {
3542 0 : listnode_add(ctx->u.iptable.interface_name_list,
3543 : XSTRDUP(MTYPE_DP_NETFILTER, ifname));
3544 : }
3545 : }
3546 0 : return AOK;
3547 : }
3548 :
3549 : /**
3550 : * dplane_ctx_ipset_init() - Initialize a context block for a PBR ipset update.
3551 : *
3552 : * @ctx: Dataplane context to init
3553 : * @op: Operation being performed
3554 : * @new_rule: PBR ipset
3555 : *
3556 : * Return: Result status
3557 : */
3558 0 : static int dplane_ctx_ipset_init(struct zebra_dplane_ctx *ctx,
3559 : enum dplane_op_e op,
3560 : struct zebra_pbr_ipset *ipset)
3561 : {
3562 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
3563 0 : zlog_debug("init dplane ctx %s: %s Unique %u Family %s Type %s",
3564 : dplane_op2str(op), ipset->ipset_name, ipset->unique,
3565 : family2str(ipset->family),
3566 : zebra_pbr_ipset_type2str(ipset->type));
3567 : }
3568 :
3569 0 : ctx->zd_op = op;
3570 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3571 :
3572 0 : dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
3573 :
3574 0 : ctx->zd_vrf_id = ipset->vrf_id;
3575 :
3576 0 : memcpy(&ctx->u.ipset, ipset, sizeof(struct zebra_pbr_ipset));
3577 0 : return AOK;
3578 : }
3579 :
3580 : /**
3581 : * dplane_ctx_ipset_entry_init() - Initialize a context block for a PBR ipset
3582 : * update.
3583 : *
3584 : * @ctx: Dataplane context to init
3585 : * @op: Operation being performed
3586 : * @new_rule: PBR ipset
3587 : *
3588 : * Return: Result status
3589 : */
3590 : static int
3591 0 : dplane_ctx_ipset_entry_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
3592 : struct zebra_pbr_ipset_entry *ipset_entry)
3593 : {
3594 0 : struct zebra_pbr_ipset *ipset;
3595 :
3596 0 : ipset = ipset_entry->backpointer;
3597 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
3598 0 : zlog_debug("init dplane ctx %s: %s Unique %u filter %u",
3599 : dplane_op2str(op), ipset->ipset_name,
3600 : ipset_entry->unique, ipset_entry->filter_bm);
3601 : }
3602 :
3603 0 : ctx->zd_op = op;
3604 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
3605 :
3606 0 : dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
3607 :
3608 0 : ctx->zd_vrf_id = ipset->vrf_id;
3609 :
3610 0 : memcpy(&ctx->u.ipset_entry.entry, ipset_entry,
3611 : sizeof(struct zebra_pbr_ipset_entry));
3612 0 : ctx->u.ipset_entry.entry.backpointer = NULL;
3613 0 : ctx->u.ipset_entry.info.type = ipset->type;
3614 0 : ctx->u.ipset_entry.info.family = ipset->family;
3615 0 : memcpy(&ctx->u.ipset_entry.info.ipset_name, &ipset->ipset_name,
3616 : ZEBRA_IPSET_NAME_SIZE);
3617 :
3618 0 : return AOK;
3619 : }
3620 :
3621 :
3622 : /*
3623 : * Enqueue a new update,
3624 : * and ensure an event is active for the dataplane pthread.
3625 : */
3626 25 : static int dplane_update_enqueue(struct zebra_dplane_ctx *ctx)
3627 : {
3628 25 : int ret = EINVAL;
3629 25 : uint32_t high, curr;
3630 :
3631 : /* Enqueue for processing by the dataplane pthread */
3632 25 : DPLANE_LOCK();
3633 : {
3634 25 : dplane_ctx_list_add_tail(&zdplane_info.dg_update_list, ctx);
3635 : }
3636 25 : DPLANE_UNLOCK();
3637 :
3638 25 : curr = atomic_fetch_add_explicit(
3639 : &(zdplane_info.dg_routes_queued),
3640 : 1, memory_order_seq_cst);
3641 :
3642 25 : curr++; /* We got the pre-incremented value */
3643 :
3644 : /* Maybe update high-water counter also */
3645 25 : high = atomic_load_explicit(&zdplane_info.dg_routes_queued_max,
3646 : memory_order_seq_cst);
3647 25 : while (high < curr) {
3648 9 : if (atomic_compare_exchange_weak_explicit(
3649 : &zdplane_info.dg_routes_queued_max,
3650 : &high, curr,
3651 : memory_order_seq_cst,
3652 : memory_order_seq_cst))
3653 : break;
3654 : }
3655 :
3656 : /* Ensure that an event for the dataplane thread is active */
3657 25 : ret = dplane_provider_work_ready();
3658 :
3659 25 : return ret;
3660 : }
3661 :
3662 : /*
3663 : * Utility that prepares a route update and enqueues it for processing
3664 : */
3665 : static enum zebra_dplane_result
3666 15 : dplane_route_update_internal(struct route_node *rn,
3667 : struct route_entry *re,
3668 : struct route_entry *old_re,
3669 : enum dplane_op_e op)
3670 : {
3671 15 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3672 15 : int ret = EINVAL;
3673 15 : struct zebra_dplane_ctx *ctx = NULL;
3674 :
3675 : /* Obtain context block */
3676 15 : ctx = dplane_ctx_alloc();
3677 :
3678 : /* Init context with info from zebra data structs */
3679 15 : ret = dplane_ctx_route_init(ctx, op, rn, re);
3680 15 : if (ret == AOK) {
3681 : /* Capture some extra info for update case
3682 : * where there's a different 'old' route.
3683 : */
3684 15 : if ((op == DPLANE_OP_ROUTE_UPDATE) &&
3685 0 : old_re && (old_re != re)) {
3686 :
3687 0 : old_re->dplane_sequence =
3688 0 : zebra_router_get_next_sequence();
3689 0 : ctx->zd_old_seq = old_re->dplane_sequence;
3690 :
3691 0 : ctx->u.rinfo.zd_old_tag = old_re->tag;
3692 0 : ctx->u.rinfo.zd_old_type = old_re->type;
3693 0 : ctx->u.rinfo.zd_old_instance = old_re->instance;
3694 0 : ctx->u.rinfo.zd_old_distance = old_re->distance;
3695 0 : ctx->u.rinfo.zd_old_metric = old_re->metric;
3696 0 : ctx->u.rinfo.nhe.old_id = old_re->nhe->id;
3697 :
3698 : #ifndef HAVE_NETLINK
3699 : /* For bsd, capture previous re's nexthops too, sigh.
3700 : * We'll need these to do per-nexthop deletes.
3701 : */
3702 : copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop),
3703 : old_re->nhe->nhg.nexthop, NULL);
3704 :
3705 : if (zebra_nhg_get_backup_nhg(old_re->nhe) != NULL) {
3706 : struct nexthop_group *nhg;
3707 : struct nexthop **nh;
3708 :
3709 : nhg = zebra_nhg_get_backup_nhg(old_re->nhe);
3710 : nh = &(ctx->u.rinfo.old_backup_ng.nexthop);
3711 :
3712 : if (nhg->nexthop)
3713 : copy_nexthops(nh, nhg->nexthop, NULL);
3714 : }
3715 : #endif /* !HAVE_NETLINK */
3716 : }
3717 :
3718 : /*
3719 : * If the old and new context type, and nexthop group id
3720 : * are the same there is no need to send down a route replace
3721 : * as that we know we have sent a nexthop group replace
3722 : * or an upper level protocol has sent us the exact
3723 : * same route again.
3724 : */
3725 15 : if ((dplane_ctx_get_type(ctx) == dplane_ctx_get_old_type(ctx))
3726 15 : && (dplane_ctx_get_nhe_id(ctx)
3727 15 : == dplane_ctx_get_old_nhe_id(ctx))
3728 0 : && (dplane_ctx_get_nhe_id(ctx) >= ZEBRA_NHG_PROTO_LOWER)) {
3729 0 : struct nexthop *nexthop;
3730 :
3731 0 : if (IS_ZEBRA_DEBUG_DPLANE)
3732 0 : zlog_debug(
3733 : "%s: Ignoring Route exactly the same",
3734 : __func__);
3735 :
3736 0 : for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
3737 : nexthop)) {
3738 0 : if (CHECK_FLAG(nexthop->flags,
3739 : NEXTHOP_FLAG_RECURSIVE))
3740 0 : continue;
3741 :
3742 0 : if (CHECK_FLAG(nexthop->flags,
3743 : NEXTHOP_FLAG_ACTIVE))
3744 0 : SET_FLAG(nexthop->flags,
3745 : NEXTHOP_FLAG_FIB);
3746 : }
3747 :
3748 0 : dplane_ctx_free(&ctx);
3749 0 : return ZEBRA_DPLANE_REQUEST_SUCCESS;
3750 : }
3751 :
3752 : /* Enqueue context for processing */
3753 15 : ret = dplane_update_enqueue(ctx);
3754 : }
3755 :
3756 : /* Update counter */
3757 15 : atomic_fetch_add_explicit(&zdplane_info.dg_routes_in, 1,
3758 : memory_order_relaxed);
3759 :
3760 15 : if (ret == AOK)
3761 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
3762 : else {
3763 0 : atomic_fetch_add_explicit(&zdplane_info.dg_route_errors, 1,
3764 : memory_order_relaxed);
3765 0 : if (ctx)
3766 0 : dplane_ctx_free(&ctx);
3767 : }
3768 :
3769 : return result;
3770 : }
3771 :
3772 : static enum zebra_dplane_result
3773 0 : tc_qdisc_update_internal(enum dplane_op_e op,
3774 : const struct zebra_tc_qdisc *qdisc)
3775 : {
3776 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3777 0 : int ret;
3778 0 : struct zebra_dplane_ctx *ctx = NULL;
3779 :
3780 : /* Obtain context block */
3781 0 : ctx = dplane_ctx_alloc();
3782 :
3783 0 : if (!ctx) {
3784 : ret = ENOMEM;
3785 : goto done;
3786 : }
3787 :
3788 : /* Init context with info from zebra data structs */
3789 0 : ret = dplane_ctx_tc_qdisc_init(ctx, op, qdisc);
3790 :
3791 0 : if (ret == AOK)
3792 0 : ret = dplane_update_enqueue(ctx);
3793 :
3794 0 : done:
3795 : /* Update counter */
3796 0 : atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1,
3797 : memory_order_relaxed);
3798 0 : if (ret == AOK) {
3799 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
3800 : } else {
3801 0 : atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1,
3802 : memory_order_relaxed);
3803 0 : if (ctx)
3804 0 : dplane_ctx_free(&ctx);
3805 : }
3806 :
3807 0 : return result;
3808 : }
3809 :
3810 : static enum zebra_dplane_result
3811 0 : tc_class_update_internal(enum dplane_op_e op, struct zebra_tc_class *class)
3812 : {
3813 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3814 0 : int ret;
3815 0 : struct zebra_dplane_ctx *ctx = NULL;
3816 :
3817 : /* Obtain context block */
3818 0 : ctx = dplane_ctx_alloc();
3819 :
3820 0 : if (!ctx) {
3821 : ret = ENOMEM;
3822 : goto done;
3823 : }
3824 :
3825 : /* Init context with info from zebra data structs */
3826 0 : ret = dplane_ctx_tc_class_init(ctx, op, class);
3827 :
3828 0 : if (ret == AOK)
3829 0 : ret = dplane_update_enqueue(ctx);
3830 :
3831 0 : done:
3832 : /* Update counter */
3833 0 : atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1,
3834 : memory_order_relaxed);
3835 0 : if (ret == AOK) {
3836 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
3837 : } else {
3838 0 : atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1,
3839 : memory_order_relaxed);
3840 0 : if (ctx)
3841 0 : dplane_ctx_free(&ctx);
3842 : }
3843 :
3844 0 : return result;
3845 : }
3846 :
3847 : static enum zebra_dplane_result
3848 0 : tc_filter_update_internal(enum dplane_op_e op, struct zebra_tc_filter *filter)
3849 : {
3850 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3851 0 : int ret;
3852 0 : struct zebra_dplane_ctx *ctx = NULL;
3853 :
3854 : /* Obtain context block */
3855 0 : ctx = dplane_ctx_alloc();
3856 :
3857 0 : if (!ctx) {
3858 : ret = ENOMEM;
3859 : goto done;
3860 : }
3861 :
3862 : /* Init context with info from zebra data structs */
3863 0 : ret = dplane_ctx_tc_filter_init(ctx, op, filter);
3864 :
3865 0 : if (ret == AOK)
3866 0 : ret = dplane_update_enqueue(ctx);
3867 :
3868 0 : done:
3869 : /* Update counter */
3870 0 : atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1,
3871 : memory_order_relaxed);
3872 0 : if (ret == AOK) {
3873 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
3874 : } else {
3875 0 : atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1,
3876 : memory_order_relaxed);
3877 0 : if (ctx)
3878 0 : dplane_ctx_free(&ctx);
3879 : }
3880 :
3881 0 : return result;
3882 : }
3883 :
3884 0 : enum zebra_dplane_result dplane_tc_qdisc_install(struct zebra_tc_qdisc *qdisc)
3885 : {
3886 0 : return tc_qdisc_update_internal(DPLANE_OP_TC_QDISC_INSTALL, qdisc);
3887 : }
3888 :
3889 0 : enum zebra_dplane_result dplane_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc)
3890 : {
3891 0 : return tc_qdisc_update_internal(DPLANE_OP_TC_QDISC_UNINSTALL, qdisc);
3892 : }
3893 :
3894 0 : enum zebra_dplane_result dplane_tc_class_add(struct zebra_tc_class *class)
3895 : {
3896 0 : return tc_class_update_internal(DPLANE_OP_TC_CLASS_ADD, class);
3897 : }
3898 :
3899 0 : enum zebra_dplane_result dplane_tc_class_delete(struct zebra_tc_class *class)
3900 : {
3901 0 : return tc_class_update_internal(DPLANE_OP_TC_CLASS_DELETE, class);
3902 : }
3903 :
3904 0 : enum zebra_dplane_result dplane_tc_class_update(struct zebra_tc_class *class)
3905 : {
3906 0 : return tc_class_update_internal(DPLANE_OP_TC_CLASS_UPDATE, class);
3907 : }
3908 :
3909 0 : enum zebra_dplane_result dplane_tc_filter_add(struct zebra_tc_filter *filter)
3910 : {
3911 0 : return tc_filter_update_internal(DPLANE_OP_TC_FILTER_ADD, filter);
3912 : }
3913 :
3914 0 : enum zebra_dplane_result dplane_tc_filter_delete(struct zebra_tc_filter *filter)
3915 : {
3916 0 : return tc_filter_update_internal(DPLANE_OP_TC_FILTER_DELETE, filter);
3917 : }
3918 :
3919 0 : enum zebra_dplane_result dplane_tc_filter_update(struct zebra_tc_filter *filter)
3920 : {
3921 0 : return tc_filter_update_internal(DPLANE_OP_TC_FILTER_UPDATE, filter);
3922 : }
3923 :
3924 : /**
3925 : * dplane_nexthop_update_internal() - Helper for enqueuing nexthop changes
3926 : *
3927 : * @nhe: Nexthop group hash entry where the change occured
3928 : * @op: The operation to be enqued
3929 : *
3930 : * Return: Result of the change
3931 : */
3932 : static enum zebra_dplane_result
3933 10 : dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op)
3934 : {
3935 10 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
3936 10 : int ret;
3937 10 : struct zebra_dplane_ctx *ctx = NULL;
3938 :
3939 : /* Obtain context block */
3940 10 : ctx = dplane_ctx_alloc();
3941 10 : if (!ctx) {
3942 : ret = ENOMEM;
3943 : goto done;
3944 : }
3945 :
3946 10 : ret = dplane_ctx_nexthop_init(ctx, op, nhe);
3947 10 : if (ret == AOK)
3948 10 : ret = dplane_update_enqueue(ctx);
3949 :
3950 0 : done:
3951 : /* Update counter */
3952 10 : atomic_fetch_add_explicit(&zdplane_info.dg_nexthops_in, 1,
3953 : memory_order_relaxed);
3954 :
3955 10 : if (ret == AOK)
3956 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
3957 : else {
3958 0 : atomic_fetch_add_explicit(&zdplane_info.dg_nexthop_errors, 1,
3959 : memory_order_relaxed);
3960 0 : if (ctx)
3961 0 : dplane_ctx_free(&ctx);
3962 : }
3963 :
3964 10 : return result;
3965 : }
3966 :
3967 : /*
3968 : * Enqueue a route 'add' for the dataplane.
3969 : */
3970 8 : enum zebra_dplane_result dplane_route_add(struct route_node *rn,
3971 : struct route_entry *re)
3972 : {
3973 8 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
3974 :
3975 8 : if (rn == NULL || re == NULL)
3976 : return ret;
3977 :
3978 8 : ret = dplane_route_update_internal(rn, re, NULL,
3979 : DPLANE_OP_ROUTE_INSTALL);
3980 :
3981 8 : return ret;
3982 : }
3983 :
3984 : /*
3985 : * Enqueue a route update for the dataplane.
3986 : */
3987 0 : enum zebra_dplane_result dplane_route_update(struct route_node *rn,
3988 : struct route_entry *re,
3989 : struct route_entry *old_re)
3990 : {
3991 0 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
3992 :
3993 0 : if (rn == NULL || re == NULL)
3994 : return ret;
3995 :
3996 0 : ret = dplane_route_update_internal(rn, re, old_re,
3997 : DPLANE_OP_ROUTE_UPDATE);
3998 :
3999 0 : return ret;
4000 : }
4001 :
4002 : /*
4003 : * Enqueue a route removal for the dataplane.
4004 : */
4005 7 : enum zebra_dplane_result dplane_route_delete(struct route_node *rn,
4006 : struct route_entry *re)
4007 : {
4008 7 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
4009 :
4010 7 : if (rn == NULL || re == NULL)
4011 : return ret;
4012 :
4013 7 : ret = dplane_route_update_internal(rn, re, NULL,
4014 : DPLANE_OP_ROUTE_DELETE);
4015 :
4016 7 : return ret;
4017 : }
4018 :
4019 : /*
4020 : * Notify the dplane when system/connected routes change.
4021 : */
4022 16 : enum zebra_dplane_result dplane_sys_route_add(struct route_node *rn,
4023 : struct route_entry *re)
4024 : {
4025 16 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
4026 :
4027 : /* Ignore this event unless a provider plugin has requested it. */
4028 16 : if (!zdplane_info.dg_sys_route_notifs)
4029 : return ZEBRA_DPLANE_REQUEST_SUCCESS;
4030 :
4031 :
4032 0 : if (rn == NULL || re == NULL)
4033 : return ret;
4034 :
4035 0 : ret = dplane_route_update_internal(rn, re, NULL,
4036 : DPLANE_OP_SYS_ROUTE_ADD);
4037 :
4038 0 : return ret;
4039 : }
4040 :
4041 : /*
4042 : * Notify the dplane when system/connected routes are deleted.
4043 : */
4044 0 : enum zebra_dplane_result dplane_sys_route_del(struct route_node *rn,
4045 : struct route_entry *re)
4046 : {
4047 0 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
4048 :
4049 : /* Ignore this event unless a provider plugin has requested it. */
4050 0 : if (!zdplane_info.dg_sys_route_notifs)
4051 : return ZEBRA_DPLANE_REQUEST_SUCCESS;
4052 :
4053 0 : if (rn == NULL || re == NULL)
4054 : return ret;
4055 :
4056 0 : ret = dplane_route_update_internal(rn, re, NULL,
4057 : DPLANE_OP_SYS_ROUTE_DELETE);
4058 :
4059 0 : return ret;
4060 : }
4061 :
4062 : /*
4063 : * Update from an async notification, to bring other fibs up-to-date.
4064 : */
4065 : enum zebra_dplane_result
4066 0 : dplane_route_notif_update(struct route_node *rn,
4067 : struct route_entry *re,
4068 : enum dplane_op_e op,
4069 : struct zebra_dplane_ctx *ctx)
4070 : {
4071 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4072 0 : int ret = EINVAL;
4073 0 : struct zebra_dplane_ctx *new_ctx = NULL;
4074 0 : struct nexthop *nexthop;
4075 0 : struct nexthop_group *nhg;
4076 :
4077 0 : if (rn == NULL || re == NULL)
4078 0 : goto done;
4079 :
4080 0 : new_ctx = dplane_ctx_alloc();
4081 0 : if (new_ctx == NULL)
4082 : goto done;
4083 :
4084 : /* Init context with info from zebra data structs */
4085 0 : dplane_ctx_route_init(new_ctx, op, rn, re);
4086 :
4087 : /* For add/update, need to adjust the nexthops so that we match
4088 : * the notification state, which may not be the route-entry/RIB
4089 : * state.
4090 : */
4091 0 : if (op == DPLANE_OP_ROUTE_UPDATE ||
4092 : op == DPLANE_OP_ROUTE_INSTALL) {
4093 :
4094 0 : nexthops_free(new_ctx->u.rinfo.zd_ng.nexthop);
4095 0 : new_ctx->u.rinfo.zd_ng.nexthop = NULL;
4096 :
4097 0 : nhg = rib_get_fib_nhg(re);
4098 0 : if (nhg && nhg->nexthop)
4099 0 : copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
4100 : nhg->nexthop, NULL);
4101 :
4102 : /* Check for installed backup nexthops also */
4103 0 : nhg = rib_get_fib_backup_nhg(re);
4104 0 : if (nhg && nhg->nexthop) {
4105 0 : copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
4106 : nhg->nexthop, NULL);
4107 : }
4108 :
4109 0 : for (ALL_NEXTHOPS(new_ctx->u.rinfo.zd_ng, nexthop))
4110 0 : UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
4111 :
4112 : }
4113 :
4114 : /* Capture info about the source of the notification, in 'ctx' */
4115 0 : dplane_ctx_set_notif_provider(new_ctx,
4116 : dplane_ctx_get_notif_provider(ctx));
4117 :
4118 0 : ret = dplane_update_enqueue(new_ctx);
4119 :
4120 0 : done:
4121 0 : if (ret == AOK)
4122 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
4123 0 : else if (new_ctx)
4124 0 : dplane_ctx_free(&new_ctx);
4125 :
4126 0 : return result;
4127 : }
4128 :
4129 : /*
4130 : * Enqueue a nexthop add for the dataplane.
4131 : */
4132 6 : enum zebra_dplane_result dplane_nexthop_add(struct nhg_hash_entry *nhe)
4133 : {
4134 6 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
4135 :
4136 6 : if (nhe)
4137 6 : ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_INSTALL);
4138 6 : return ret;
4139 : }
4140 :
4141 : /*
4142 : * Enqueue a nexthop update for the dataplane.
4143 : *
4144 : * Might not need this func since zebra's nexthop objects should be immutable?
4145 : */
4146 0 : enum zebra_dplane_result dplane_nexthop_update(struct nhg_hash_entry *nhe)
4147 : {
4148 0 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
4149 :
4150 0 : if (nhe)
4151 0 : ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_UPDATE);
4152 0 : return ret;
4153 : }
4154 :
4155 : /*
4156 : * Enqueue a nexthop removal for the dataplane.
4157 : */
4158 4 : enum zebra_dplane_result dplane_nexthop_delete(struct nhg_hash_entry *nhe)
4159 : {
4160 4 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
4161 :
4162 4 : if (nhe)
4163 4 : ret = dplane_nexthop_update_internal(nhe, DPLANE_OP_NH_DELETE);
4164 :
4165 4 : return ret;
4166 : }
4167 :
4168 : /*
4169 : * Enqueue LSP add for the dataplane.
4170 : */
4171 0 : enum zebra_dplane_result dplane_lsp_add(struct zebra_lsp *lsp)
4172 : {
4173 0 : enum zebra_dplane_result ret =
4174 0 : lsp_update_internal(lsp, DPLANE_OP_LSP_INSTALL);
4175 :
4176 0 : return ret;
4177 : }
4178 :
4179 : /*
4180 : * Enqueue LSP update for the dataplane.
4181 : */
4182 0 : enum zebra_dplane_result dplane_lsp_update(struct zebra_lsp *lsp)
4183 : {
4184 0 : enum zebra_dplane_result ret =
4185 0 : lsp_update_internal(lsp, DPLANE_OP_LSP_UPDATE);
4186 :
4187 0 : return ret;
4188 : }
4189 :
4190 : /*
4191 : * Enqueue LSP delete for the dataplane.
4192 : */
4193 0 : enum zebra_dplane_result dplane_lsp_delete(struct zebra_lsp *lsp)
4194 : {
4195 0 : enum zebra_dplane_result ret =
4196 0 : lsp_update_internal(lsp, DPLANE_OP_LSP_DELETE);
4197 :
4198 0 : return ret;
4199 : }
4200 :
4201 : /* Update or un-install resulting from an async notification */
4202 : enum zebra_dplane_result
4203 0 : dplane_lsp_notif_update(struct zebra_lsp *lsp, enum dplane_op_e op,
4204 : struct zebra_dplane_ctx *notif_ctx)
4205 : {
4206 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4207 0 : int ret;
4208 0 : struct zebra_dplane_ctx *ctx = NULL;
4209 0 : struct nhlfe_list_head *head;
4210 0 : struct zebra_nhlfe *nhlfe, *new_nhlfe;
4211 :
4212 : /* Obtain context block */
4213 0 : ctx = dplane_ctx_alloc();
4214 0 : if (ctx == NULL) {
4215 : ret = ENOMEM;
4216 : goto done;
4217 : }
4218 :
4219 : /* Copy info from zebra LSP */
4220 0 : ret = dplane_ctx_lsp_init(ctx, op, lsp);
4221 0 : if (ret != AOK)
4222 0 : goto done;
4223 :
4224 : /* Add any installed backup nhlfes */
4225 0 : head = &(ctx->u.lsp.backup_nhlfe_list);
4226 0 : frr_each(nhlfe_list, head, nhlfe) {
4227 :
4228 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) &&
4229 0 : CHECK_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_FIB)) {
4230 0 : new_nhlfe = zebra_mpls_lsp_add_nh(&(ctx->u.lsp),
4231 : nhlfe->type,
4232 : nhlfe->nexthop);
4233 :
4234 : /* Need to copy flags too */
4235 0 : new_nhlfe->flags = nhlfe->flags;
4236 0 : new_nhlfe->nexthop->flags = nhlfe->nexthop->flags;
4237 : }
4238 : }
4239 :
4240 : /* Capture info about the source of the notification */
4241 0 : dplane_ctx_set_notif_provider(
4242 : ctx,
4243 : dplane_ctx_get_notif_provider(notif_ctx));
4244 :
4245 0 : ret = dplane_update_enqueue(ctx);
4246 :
4247 0 : done:
4248 : /* Update counter */
4249 0 : atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1,
4250 : memory_order_relaxed);
4251 :
4252 0 : if (ret == AOK)
4253 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
4254 : else {
4255 0 : atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
4256 : memory_order_relaxed);
4257 0 : if (ctx)
4258 0 : dplane_ctx_free(&ctx);
4259 : }
4260 0 : return result;
4261 : }
4262 :
4263 : /*
4264 : * Enqueue pseudowire install for the dataplane.
4265 : */
4266 0 : enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw)
4267 : {
4268 0 : return pw_update_internal(pw, DPLANE_OP_PW_INSTALL);
4269 : }
4270 :
4271 : /*
4272 : * Enqueue pseudowire un-install for the dataplane.
4273 : */
4274 0 : enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw)
4275 : {
4276 0 : return pw_update_internal(pw, DPLANE_OP_PW_UNINSTALL);
4277 : }
4278 :
4279 : /*
4280 : * Common internal LSP update utility
4281 : */
4282 0 : static enum zebra_dplane_result lsp_update_internal(struct zebra_lsp *lsp,
4283 : enum dplane_op_e op)
4284 : {
4285 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4286 0 : int ret = EINVAL;
4287 0 : struct zebra_dplane_ctx *ctx = NULL;
4288 :
4289 : /* Obtain context block */
4290 0 : ctx = dplane_ctx_alloc();
4291 :
4292 0 : ret = dplane_ctx_lsp_init(ctx, op, lsp);
4293 0 : if (ret != AOK)
4294 0 : goto done;
4295 :
4296 0 : ret = dplane_update_enqueue(ctx);
4297 :
4298 0 : done:
4299 : /* Update counter */
4300 0 : atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1,
4301 : memory_order_relaxed);
4302 :
4303 0 : if (ret == AOK)
4304 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
4305 : else {
4306 0 : atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
4307 : memory_order_relaxed);
4308 0 : dplane_ctx_free(&ctx);
4309 : }
4310 :
4311 0 : return result;
4312 : }
4313 :
4314 : /*
4315 : * Internal, common handler for pseudowire updates.
4316 : */
4317 0 : static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
4318 : enum dplane_op_e op)
4319 : {
4320 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4321 0 : int ret;
4322 0 : struct zebra_dplane_ctx *ctx = NULL;
4323 :
4324 0 : ctx = dplane_ctx_alloc();
4325 :
4326 0 : ret = dplane_ctx_pw_init(ctx, op, pw);
4327 0 : if (ret != AOK)
4328 0 : goto done;
4329 :
4330 0 : ret = dplane_update_enqueue(ctx);
4331 :
4332 0 : done:
4333 : /* Update counter */
4334 0 : atomic_fetch_add_explicit(&zdplane_info.dg_pws_in, 1,
4335 : memory_order_relaxed);
4336 :
4337 0 : if (ret == AOK)
4338 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
4339 : else {
4340 0 : atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
4341 : memory_order_relaxed);
4342 0 : dplane_ctx_free(&ctx);
4343 : }
4344 :
4345 0 : return result;
4346 : }
4347 :
4348 : /*
4349 : * Enqueue access br_port update.
4350 : */
4351 : enum zebra_dplane_result
4352 0 : dplane_br_port_update(const struct interface *ifp, bool non_df,
4353 : uint32_t sph_filter_cnt,
4354 : const struct in_addr *sph_filters, uint32_t backup_nhg_id)
4355 : {
4356 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4357 0 : uint32_t flags = 0;
4358 0 : int ret;
4359 0 : struct zebra_dplane_ctx *ctx = NULL;
4360 0 : struct zebra_ns *zns;
4361 0 : enum dplane_op_e op = DPLANE_OP_BR_PORT_UPDATE;
4362 :
4363 0 : if (non_df)
4364 0 : flags |= DPLANE_BR_PORT_NON_DF;
4365 :
4366 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_EVPN_MH_ES) {
4367 0 : uint32_t i;
4368 0 : char vtep_str[ES_VTEP_LIST_STR_SZ];
4369 :
4370 0 : vtep_str[0] = '\0';
4371 0 : for (i = 0; i < sph_filter_cnt; ++i) {
4372 0 : snprintfrr(vtep_str + strlen(vtep_str),
4373 0 : sizeof(vtep_str) - strlen(vtep_str), "%pI4 ",
4374 0 : &sph_filters[i]);
4375 : }
4376 0 : zlog_debug(
4377 : "init br_port ctx %s: ifp %s, flags 0x%x backup_nhg 0x%x sph %s",
4378 : dplane_op2str(op), ifp->name, flags, backup_nhg_id,
4379 : vtep_str);
4380 : }
4381 :
4382 0 : ctx = dplane_ctx_alloc();
4383 :
4384 0 : ctx->zd_op = op;
4385 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
4386 0 : ctx->zd_vrf_id = ifp->vrf->vrf_id;
4387 :
4388 0 : zns = zebra_ns_lookup(ifp->vrf->vrf_id);
4389 0 : dplane_ctx_ns_init(ctx, zns, false);
4390 :
4391 0 : ctx->zd_ifindex = ifp->ifindex;
4392 0 : strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
4393 :
4394 : /* Init the br-port-specific data area */
4395 0 : memset(&ctx->u.br_port, 0, sizeof(ctx->u.br_port));
4396 :
4397 0 : ctx->u.br_port.flags = flags;
4398 0 : ctx->u.br_port.backup_nhg_id = backup_nhg_id;
4399 0 : ctx->u.br_port.sph_filter_cnt = sph_filter_cnt;
4400 0 : memcpy(ctx->u.br_port.sph_filters, sph_filters,
4401 : sizeof(ctx->u.br_port.sph_filters[0]) * sph_filter_cnt);
4402 :
4403 : /* Enqueue for processing on the dplane pthread */
4404 0 : ret = dplane_update_enqueue(ctx);
4405 :
4406 : /* Increment counter */
4407 0 : atomic_fetch_add_explicit(&zdplane_info.dg_br_port_in, 1,
4408 : memory_order_relaxed);
4409 :
4410 0 : if (ret == AOK) {
4411 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
4412 : } else {
4413 : /* Error counter */
4414 0 : atomic_fetch_add_explicit(&zdplane_info.dg_br_port_errors, 1,
4415 : memory_order_relaxed);
4416 0 : dplane_ctx_free(&ctx);
4417 : }
4418 :
4419 0 : return result;
4420 : }
4421 :
4422 : enum zebra_dplane_result
4423 0 : dplane_intf_mpls_modify_state(const struct interface *ifp, bool set)
4424 : {
4425 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4426 0 : struct zebra_dplane_ctx *ctx;
4427 0 : struct zebra_ns *zns;
4428 0 : int ret = EINVAL;
4429 :
4430 0 : ctx = dplane_ctx_alloc();
4431 0 : ctx->zd_op = DPLANE_OP_INTF_NETCONFIG;
4432 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
4433 0 : ctx->zd_vrf_id = ifp->vrf->vrf_id;
4434 0 : strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
4435 :
4436 0 : zns = zebra_ns_lookup(ifp->vrf->vrf_id);
4437 0 : dplane_ctx_ns_init(ctx, zns, false);
4438 :
4439 0 : ctx->zd_ifindex = ifp->ifindex;
4440 0 : if (set)
4441 0 : dplane_ctx_set_netconf_mpls(ctx, DPLANE_NETCONF_STATUS_ENABLED);
4442 : else
4443 0 : dplane_ctx_set_netconf_mpls(ctx,
4444 : DPLANE_NETCONF_STATUS_DISABLED);
4445 : /* Increment counter */
4446 0 : atomic_fetch_add_explicit(&zdplane_info.dg_intf_changes, 1,
4447 : memory_order_relaxed);
4448 :
4449 0 : ret = dplane_update_enqueue(ctx);
4450 :
4451 0 : if (ret == AOK)
4452 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
4453 : else {
4454 : /* Error counter */
4455 0 : atomic_fetch_add_explicit(&zdplane_info.dg_intf_changes_errors,
4456 : 1, memory_order_relaxed);
4457 0 : dplane_ctx_free(&ctx);
4458 : }
4459 :
4460 0 : return result;
4461 : }
4462 :
4463 : /*
4464 : * Enqueue interface address add for the dataplane.
4465 : */
4466 0 : enum zebra_dplane_result dplane_intf_addr_set(const struct interface *ifp,
4467 : const struct connected *ifc)
4468 : {
4469 : #if !defined(HAVE_NETLINK) && defined(HAVE_STRUCT_IFALIASREQ)
4470 : /* Extra checks for this OS path. */
4471 :
4472 : /* Don't configure PtP addresses on broadcast ifs or reverse */
4473 : if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER(ifc)) {
4474 : if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_DPLANE)
4475 : zlog_debug("Failed to set intf addr: mismatch p2p and connected");
4476 :
4477 : return ZEBRA_DPLANE_REQUEST_FAILURE;
4478 : }
4479 : #endif
4480 :
4481 0 : return intf_addr_update_internal(ifp, ifc, DPLANE_OP_ADDR_INSTALL);
4482 : }
4483 :
4484 : /*
4485 : * Enqueue interface address remove/uninstall for the dataplane.
4486 : */
4487 0 : enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
4488 : const struct connected *ifc)
4489 : {
4490 0 : return intf_addr_update_internal(ifp, ifc, DPLANE_OP_ADDR_UNINSTALL);
4491 : }
4492 :
4493 0 : static enum zebra_dplane_result intf_addr_update_internal(
4494 : const struct interface *ifp, const struct connected *ifc,
4495 : enum dplane_op_e op)
4496 : {
4497 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4498 0 : int ret = EINVAL;
4499 0 : struct zebra_dplane_ctx *ctx = NULL;
4500 0 : struct zebra_ns *zns;
4501 :
4502 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
4503 0 : zlog_debug("init intf ctx %s: idx %d, addr %u:%pFX",
4504 : dplane_op2str(op), ifp->ifindex, ifp->vrf->vrf_id,
4505 : ifc->address);
4506 :
4507 0 : ctx = dplane_ctx_alloc();
4508 :
4509 0 : ctx->zd_op = op;
4510 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
4511 0 : ctx->zd_vrf_id = ifp->vrf->vrf_id;
4512 :
4513 0 : zns = zebra_ns_lookup(ifp->vrf->vrf_id);
4514 0 : dplane_ctx_ns_init(ctx, zns, false);
4515 :
4516 : /* Init the interface-addr-specific area */
4517 0 : memset(&ctx->u.intf, 0, sizeof(ctx->u.intf));
4518 :
4519 0 : strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
4520 0 : ctx->zd_ifindex = ifp->ifindex;
4521 0 : ctx->u.intf.prefix = *(ifc->address);
4522 :
4523 0 : if (if_is_broadcast(ifp))
4524 0 : ctx->u.intf.flags |= DPLANE_INTF_BROADCAST;
4525 :
4526 0 : if (CONNECTED_PEER(ifc)) {
4527 0 : ctx->u.intf.dest_prefix = *(ifc->destination);
4528 0 : ctx->u.intf.flags |=
4529 : (DPLANE_INTF_CONNECTED | DPLANE_INTF_HAS_DEST);
4530 : }
4531 :
4532 0 : if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
4533 0 : ctx->u.intf.flags |= DPLANE_INTF_SECONDARY;
4534 :
4535 0 : if (ifc->label) {
4536 0 : size_t len;
4537 :
4538 0 : ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL;
4539 :
4540 : /* Use embedded buffer if it's adequate; else allocate. */
4541 0 : len = strlen(ifc->label);
4542 :
4543 0 : if (len < sizeof(ctx->u.intf.label_buf)) {
4544 0 : strlcpy(ctx->u.intf.label_buf, ifc->label,
4545 : sizeof(ctx->u.intf.label_buf));
4546 0 : ctx->u.intf.label = ctx->u.intf.label_buf;
4547 : } else {
4548 0 : ctx->u.intf.label = XSTRDUP(MTYPE_DP_CTX, ifc->label);
4549 : }
4550 : }
4551 :
4552 0 : ret = dplane_update_enqueue(ctx);
4553 :
4554 : /* Increment counter */
4555 0 : atomic_fetch_add_explicit(&zdplane_info.dg_intf_addrs_in, 1,
4556 : memory_order_relaxed);
4557 :
4558 0 : if (ret == AOK)
4559 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
4560 : else {
4561 : /* Error counter */
4562 0 : atomic_fetch_add_explicit(&zdplane_info.dg_intf_addr_errors,
4563 : 1, memory_order_relaxed);
4564 0 : dplane_ctx_free(&ctx);
4565 : }
4566 :
4567 0 : return result;
4568 : }
4569 :
4570 : /**
4571 : * dplane_intf_update_internal() - Helper for enqueuing interface changes
4572 : *
4573 : * @ifp: Interface where the change occured
4574 : * @op: The operation to be enqued
4575 : *
4576 : * Return: Result of the change
4577 : */
4578 : static enum zebra_dplane_result
4579 0 : dplane_intf_update_internal(const struct interface *ifp, enum dplane_op_e op)
4580 : {
4581 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4582 0 : int ret;
4583 0 : struct zebra_dplane_ctx *ctx = NULL;
4584 :
4585 : /* Obtain context block */
4586 0 : ctx = dplane_ctx_alloc();
4587 0 : if (!ctx) {
4588 : ret = ENOMEM;
4589 : goto done;
4590 : }
4591 :
4592 0 : ret = dplane_ctx_intf_init(ctx, op, ifp);
4593 0 : if (ret == AOK)
4594 0 : ret = dplane_update_enqueue(ctx);
4595 :
4596 0 : done:
4597 : /* Update counter */
4598 0 : atomic_fetch_add_explicit(&zdplane_info.dg_intfs_in, 1,
4599 : memory_order_relaxed);
4600 :
4601 0 : if (ret == AOK)
4602 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
4603 : else {
4604 0 : atomic_fetch_add_explicit(&zdplane_info.dg_intf_errors, 1,
4605 : memory_order_relaxed);
4606 0 : if (ctx)
4607 0 : dplane_ctx_free(&ctx);
4608 : }
4609 :
4610 0 : return result;
4611 : }
4612 :
4613 : /*
4614 : * Enqueue a interface add for the dataplane.
4615 : */
4616 0 : enum zebra_dplane_result dplane_intf_add(const struct interface *ifp)
4617 : {
4618 0 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
4619 :
4620 0 : if (ifp)
4621 0 : ret = dplane_intf_update_internal(ifp, DPLANE_OP_INTF_INSTALL);
4622 0 : return ret;
4623 : }
4624 :
4625 : /*
4626 : * Enqueue a interface update for the dataplane.
4627 : */
4628 0 : enum zebra_dplane_result dplane_intf_update(const struct interface *ifp)
4629 : {
4630 0 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
4631 :
4632 0 : if (ifp)
4633 0 : ret = dplane_intf_update_internal(ifp, DPLANE_OP_INTF_UPDATE);
4634 0 : return ret;
4635 : }
4636 :
4637 : /*
4638 : * Enqueue a interface delete for the dataplane.
4639 : */
4640 0 : enum zebra_dplane_result dplane_intf_delete(const struct interface *ifp)
4641 : {
4642 0 : enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
4643 :
4644 0 : if (ifp)
4645 0 : ret = dplane_intf_update_internal(ifp, DPLANE_OP_INTF_DELETE);
4646 0 : return ret;
4647 : }
4648 :
4649 : /*
4650 : * Enqueue vxlan/evpn mac add (or update).
4651 : */
4652 0 : enum zebra_dplane_result dplane_rem_mac_add(const struct interface *ifp,
4653 : const struct interface *bridge_ifp,
4654 : vlanid_t vid,
4655 : const struct ethaddr *mac,
4656 : struct in_addr vtep_ip,
4657 : bool sticky,
4658 : uint32_t nhg_id,
4659 : bool was_static)
4660 : {
4661 0 : enum zebra_dplane_result result;
4662 0 : uint32_t update_flags = 0;
4663 :
4664 0 : update_flags |= DPLANE_MAC_REMOTE;
4665 0 : if (was_static)
4666 0 : update_flags |= DPLANE_MAC_WAS_STATIC;
4667 :
4668 : /* Use common helper api */
4669 0 : result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
4670 : vid, mac, vtep_ip, sticky, nhg_id, update_flags);
4671 0 : return result;
4672 : }
4673 :
4674 : /*
4675 : * Enqueue vxlan/evpn mac delete.
4676 : */
4677 0 : enum zebra_dplane_result dplane_rem_mac_del(const struct interface *ifp,
4678 : const struct interface *bridge_ifp,
4679 : vlanid_t vid,
4680 : const struct ethaddr *mac,
4681 : struct in_addr vtep_ip)
4682 : {
4683 0 : enum zebra_dplane_result result;
4684 0 : uint32_t update_flags = 0;
4685 :
4686 0 : update_flags |= DPLANE_MAC_REMOTE;
4687 :
4688 : /* Use common helper api */
4689 0 : result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp,
4690 : vid, mac, vtep_ip, false, 0, update_flags);
4691 0 : return result;
4692 : }
4693 :
4694 : /*
4695 : * API to configure link local with either MAC address or IP information
4696 : */
4697 0 : enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
4698 : const struct interface *ifp,
4699 : struct ipaddr *link_ip,
4700 : struct ipaddr *ip,
4701 : uint32_t ndm_state, int protocol)
4702 : {
4703 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4704 0 : uint16_t state = 0;
4705 0 : uint32_t update_flags;
4706 :
4707 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
4708 0 : zlog_debug("%s: init link ctx %s: ifp %s, link_ip %pIA ip %pIA",
4709 : __func__, dplane_op2str(op), ifp->name, link_ip, ip);
4710 :
4711 0 : if (ndm_state == ZEBRA_NEIGH_STATE_REACHABLE)
4712 : state = DPLANE_NUD_REACHABLE;
4713 0 : else if (ndm_state == ZEBRA_NEIGH_STATE_FAILED)
4714 0 : state = DPLANE_NUD_FAILED;
4715 :
4716 0 : update_flags = DPLANE_NEIGH_NO_EXTENSION;
4717 :
4718 0 : result = neigh_update_internal(op, ifp, (const void *)link_ip,
4719 : ipaddr_family(link_ip), ip, 0, state,
4720 : update_flags, protocol);
4721 :
4722 0 : return result;
4723 : }
4724 :
4725 : /*
4726 : * Enqueue local mac add (or update).
4727 : */
4728 0 : enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp,
4729 : const struct interface *bridge_ifp,
4730 : vlanid_t vid,
4731 : const struct ethaddr *mac,
4732 : bool sticky,
4733 : uint32_t set_static,
4734 : uint32_t set_inactive)
4735 : {
4736 0 : enum zebra_dplane_result result;
4737 0 : uint32_t update_flags = 0;
4738 0 : struct in_addr vtep_ip;
4739 :
4740 0 : if (set_static)
4741 0 : update_flags |= DPLANE_MAC_SET_STATIC;
4742 :
4743 0 : if (set_inactive)
4744 0 : update_flags |= DPLANE_MAC_SET_INACTIVE;
4745 :
4746 0 : vtep_ip.s_addr = 0;
4747 :
4748 : /* Use common helper api */
4749 0 : result = mac_update_common(DPLANE_OP_MAC_INSTALL, ifp, bridge_ifp,
4750 : vid, mac, vtep_ip, sticky, 0,
4751 : update_flags);
4752 0 : return result;
4753 : }
4754 :
4755 : /*
4756 : * Enqueue local mac del
4757 : */
4758 : enum zebra_dplane_result
4759 0 : dplane_local_mac_del(const struct interface *ifp,
4760 : const struct interface *bridge_ifp, vlanid_t vid,
4761 : const struct ethaddr *mac)
4762 : {
4763 0 : enum zebra_dplane_result result;
4764 0 : struct in_addr vtep_ip;
4765 :
4766 0 : vtep_ip.s_addr = 0;
4767 :
4768 : /* Use common helper api */
4769 0 : result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp, vid,
4770 : mac, vtep_ip, false, 0, 0);
4771 0 : return result;
4772 : }
4773 : /*
4774 : * Public api to init an empty context - either newly-allocated or
4775 : * reset/cleared - for a MAC update.
4776 : */
4777 0 : void dplane_mac_init(struct zebra_dplane_ctx *ctx,
4778 : const struct interface *ifp,
4779 : const struct interface *br_ifp,
4780 : vlanid_t vid,
4781 : const struct ethaddr *mac,
4782 : struct in_addr vtep_ip,
4783 : bool sticky,
4784 : uint32_t nhg_id,
4785 : uint32_t update_flags)
4786 : {
4787 0 : struct zebra_ns *zns;
4788 :
4789 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
4790 0 : ctx->zd_vrf_id = ifp->vrf->vrf_id;
4791 :
4792 0 : zns = zebra_ns_lookup(ifp->vrf->vrf_id);
4793 0 : dplane_ctx_ns_init(ctx, zns, false);
4794 :
4795 0 : strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
4796 0 : ctx->zd_ifindex = ifp->ifindex;
4797 :
4798 : /* Init the mac-specific data area */
4799 0 : memset(&ctx->u.macinfo, 0, sizeof(ctx->u.macinfo));
4800 :
4801 0 : ctx->u.macinfo.br_ifindex = br_ifp->ifindex;
4802 0 : ctx->u.macinfo.vtep_ip = vtep_ip;
4803 0 : ctx->u.macinfo.mac = *mac;
4804 0 : ctx->u.macinfo.vid = vid;
4805 0 : ctx->u.macinfo.is_sticky = sticky;
4806 0 : ctx->u.macinfo.nhg_id = nhg_id;
4807 0 : ctx->u.macinfo.update_flags = update_flags;
4808 0 : }
4809 :
4810 : /*
4811 : * Common helper api for MAC address/vxlan updates
4812 : */
4813 : static enum zebra_dplane_result
4814 0 : mac_update_common(enum dplane_op_e op,
4815 : const struct interface *ifp,
4816 : const struct interface *br_ifp,
4817 : vlanid_t vid,
4818 : const struct ethaddr *mac,
4819 : struct in_addr vtep_ip,
4820 : bool sticky,
4821 : uint32_t nhg_id,
4822 : uint32_t update_flags)
4823 : {
4824 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4825 0 : int ret;
4826 0 : struct zebra_dplane_ctx *ctx = NULL;
4827 :
4828 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
4829 0 : zlog_debug("init mac ctx %s: mac %pEA, ifp %s, vtep %pI4",
4830 : dplane_op2str(op), mac, ifp->name, &vtep_ip);
4831 :
4832 0 : ctx = dplane_ctx_alloc();
4833 0 : ctx->zd_op = op;
4834 :
4835 : /* Common init for the ctx */
4836 0 : dplane_mac_init(ctx, ifp, br_ifp, vid, mac, vtep_ip, sticky,
4837 : nhg_id, update_flags);
4838 :
4839 : /* Enqueue for processing on the dplane pthread */
4840 0 : ret = dplane_update_enqueue(ctx);
4841 :
4842 : /* Increment counter */
4843 0 : atomic_fetch_add_explicit(&zdplane_info.dg_macs_in, 1,
4844 : memory_order_relaxed);
4845 :
4846 0 : if (ret == AOK)
4847 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
4848 : else {
4849 : /* Error counter */
4850 0 : atomic_fetch_add_explicit(&zdplane_info.dg_mac_errors, 1,
4851 : memory_order_relaxed);
4852 0 : dplane_ctx_free(&ctx);
4853 : }
4854 :
4855 0 : return result;
4856 : }
4857 :
4858 : /*
4859 : * Enqueue evpn neighbor add for the dataplane.
4860 : */
4861 0 : enum zebra_dplane_result dplane_rem_neigh_add(const struct interface *ifp,
4862 : const struct ipaddr *ip,
4863 : const struct ethaddr *mac,
4864 : uint32_t flags, bool was_static)
4865 : {
4866 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4867 0 : uint32_t update_flags = 0;
4868 :
4869 0 : update_flags |= DPLANE_NEIGH_REMOTE;
4870 :
4871 0 : if (was_static)
4872 0 : update_flags |= DPLANE_NEIGH_WAS_STATIC;
4873 :
4874 0 : result = neigh_update_internal(
4875 : DPLANE_OP_NEIGH_INSTALL, ifp, (const void *)mac, AF_ETHERNET,
4876 : ip, flags, DPLANE_NUD_NOARP, update_flags, 0);
4877 :
4878 0 : return result;
4879 : }
4880 :
4881 : /*
4882 : * Enqueue local neighbor add for the dataplane.
4883 : */
4884 0 : enum zebra_dplane_result dplane_local_neigh_add(const struct interface *ifp,
4885 : const struct ipaddr *ip,
4886 : const struct ethaddr *mac,
4887 : bool set_router, bool set_static,
4888 : bool set_inactive)
4889 : {
4890 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
4891 0 : uint32_t update_flags = 0;
4892 0 : uint32_t ntf = 0;
4893 0 : uint16_t state;
4894 :
4895 0 : if (set_static)
4896 0 : update_flags |= DPLANE_NEIGH_SET_STATIC;
4897 :
4898 0 : if (set_inactive) {
4899 0 : update_flags |= DPLANE_NEIGH_SET_INACTIVE;
4900 0 : state = DPLANE_NUD_STALE;
4901 : } else {
4902 : state = DPLANE_NUD_REACHABLE;
4903 : }
4904 :
4905 0 : if (set_router)
4906 0 : ntf |= DPLANE_NTF_ROUTER;
4907 :
4908 0 : result = neigh_update_internal(DPLANE_OP_NEIGH_INSTALL, ifp,
4909 : (const void *)mac, AF_ETHERNET, ip, ntf,
4910 : state, update_flags, 0);
4911 :
4912 0 : return result;
4913 : }
4914 :
4915 : /*
4916 : * Enqueue evpn neighbor delete for the dataplane.
4917 : */
4918 0 : enum zebra_dplane_result dplane_rem_neigh_delete(const struct interface *ifp,
4919 : const struct ipaddr *ip)
4920 : {
4921 0 : enum zebra_dplane_result result;
4922 0 : uint32_t update_flags = 0;
4923 :
4924 0 : update_flags |= DPLANE_NEIGH_REMOTE;
4925 :
4926 0 : result = neigh_update_internal(DPLANE_OP_NEIGH_DELETE, ifp, NULL,
4927 : AF_ETHERNET, ip, 0, 0, update_flags, 0);
4928 :
4929 0 : return result;
4930 : }
4931 :
4932 : /*
4933 : * Enqueue evpn VTEP add for the dataplane.
4934 : */
4935 0 : enum zebra_dplane_result dplane_vtep_add(const struct interface *ifp,
4936 : const struct in_addr *ip,
4937 : vni_t vni)
4938 : {
4939 0 : enum zebra_dplane_result result;
4940 0 : struct ethaddr mac = { {0, 0, 0, 0, 0, 0} };
4941 0 : struct ipaddr addr;
4942 :
4943 0 : if (IS_ZEBRA_DEBUG_VXLAN)
4944 0 : zlog_debug("Install %pI4 into flood list for VNI %u intf %s(%u)",
4945 : ip, vni, ifp->name, ifp->ifindex);
4946 :
4947 0 : SET_IPADDR_V4(&addr);
4948 0 : addr.ipaddr_v4 = *ip;
4949 :
4950 0 : result = neigh_update_internal(DPLANE_OP_VTEP_ADD, ifp, &mac,
4951 : AF_ETHERNET, &addr, 0, 0, 0, 0);
4952 :
4953 0 : return result;
4954 : }
4955 :
4956 : /*
4957 : * Enqueue evpn VTEP add for the dataplane.
4958 : */
4959 0 : enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
4960 : const struct in_addr *ip,
4961 : vni_t vni)
4962 : {
4963 0 : enum zebra_dplane_result result;
4964 0 : struct ethaddr mac = { {0, 0, 0, 0, 0, 0} };
4965 0 : struct ipaddr addr;
4966 :
4967 0 : if (IS_ZEBRA_DEBUG_VXLAN)
4968 0 : zlog_debug(
4969 : "Uninstall %pI4 from flood list for VNI %u intf %s(%u)",
4970 : ip, vni, ifp->name, ifp->ifindex);
4971 :
4972 0 : SET_IPADDR_V4(&addr);
4973 0 : addr.ipaddr_v4 = *ip;
4974 :
4975 0 : result = neigh_update_internal(DPLANE_OP_VTEP_DELETE, ifp,
4976 : (const void *)&mac, AF_ETHERNET, &addr,
4977 : 0, 0, 0, 0);
4978 :
4979 0 : return result;
4980 : }
4981 :
4982 0 : enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp,
4983 : const struct ipaddr *ip)
4984 : {
4985 0 : enum zebra_dplane_result result;
4986 :
4987 0 : result = neigh_update_internal(DPLANE_OP_NEIGH_DISCOVER, ifp, NULL,
4988 : AF_ETHERNET, ip, DPLANE_NTF_USE,
4989 : DPLANE_NUD_INCOMPLETE, 0, 0);
4990 :
4991 0 : return result;
4992 : }
4993 :
4994 0 : enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp,
4995 : const uint8_t family,
4996 : const uint32_t app_probes,
4997 : const uint32_t ucast_probes,
4998 : const uint32_t mcast_probes)
4999 : {
5000 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
5001 0 : int ret;
5002 0 : struct zebra_dplane_ctx *ctx = NULL;
5003 0 : struct zebra_ns *zns;
5004 0 : enum dplane_op_e op = DPLANE_OP_NEIGH_TABLE_UPDATE;
5005 :
5006 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
5007 0 : zlog_debug("set neigh ctx %s: ifp %s, family %s",
5008 : dplane_op2str(op), ifp->name, family2str(family));
5009 : }
5010 :
5011 0 : ctx = dplane_ctx_alloc();
5012 :
5013 0 : ctx->zd_op = op;
5014 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
5015 0 : ctx->zd_vrf_id = ifp->vrf->vrf_id;
5016 :
5017 0 : zns = zebra_ns_lookup(ifp->vrf->vrf_id);
5018 0 : dplane_ctx_ns_init(ctx, zns, false);
5019 :
5020 0 : strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
5021 0 : ctx->zd_ifindex = ifp->ifindex;
5022 :
5023 : /* Init the neighbor-specific data area */
5024 0 : memset(&ctx->u.neightable, 0, sizeof(ctx->u.neightable));
5025 :
5026 0 : ctx->u.neightable.family = family;
5027 0 : ctx->u.neightable.app_probes = app_probes;
5028 0 : ctx->u.neightable.ucast_probes = ucast_probes;
5029 0 : ctx->u.neightable.mcast_probes = mcast_probes;
5030 :
5031 : /* Enqueue for processing on the dplane pthread */
5032 0 : ret = dplane_update_enqueue(ctx);
5033 :
5034 : /* Increment counter */
5035 0 : atomic_fetch_add_explicit(&zdplane_info.dg_neightable_in, 1,
5036 : memory_order_relaxed);
5037 :
5038 0 : if (ret == AOK)
5039 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
5040 : else {
5041 : /* Error counter */
5042 0 : atomic_fetch_add_explicit(&zdplane_info.dg_neightable_errors, 1,
5043 : memory_order_relaxed);
5044 0 : dplane_ctx_free(&ctx);
5045 : }
5046 :
5047 0 : return result;
5048 : }
5049 :
5050 : /*
5051 : * Common helper api for neighbor updates
5052 : */
5053 : static enum zebra_dplane_result
5054 0 : neigh_update_internal(enum dplane_op_e op, const struct interface *ifp,
5055 : const void *link, const int link_family,
5056 : const struct ipaddr *ip, uint32_t flags, uint16_t state,
5057 : uint32_t update_flags, int protocol)
5058 : {
5059 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
5060 0 : int ret;
5061 0 : struct zebra_dplane_ctx *ctx = NULL;
5062 0 : struct zebra_ns *zns;
5063 0 : const struct ethaddr *mac = NULL;
5064 0 : const struct ipaddr *link_ip = NULL;
5065 :
5066 0 : if (link_family == AF_ETHERNET)
5067 : mac = (const struct ethaddr *)link;
5068 : else
5069 0 : link_ip = (const struct ipaddr *)link;
5070 :
5071 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
5072 0 : char buf1[PREFIX_STRLEN];
5073 :
5074 0 : buf1[0] = '\0';
5075 0 : if (link_family == AF_ETHERNET)
5076 0 : prefix_mac2str(mac, buf1, sizeof(buf1));
5077 : else
5078 0 : ipaddr2str(link_ip, buf1, sizeof(buf1));
5079 0 : zlog_debug("init neigh ctx %s: ifp %s, %s %s, ip %pIA",
5080 : dplane_op2str(op), ifp->name,
5081 : link_family == AF_ETHERNET ? "mac" : "link", buf1,
5082 : ip);
5083 : }
5084 :
5085 0 : ctx = dplane_ctx_alloc();
5086 :
5087 0 : ctx->zd_op = op;
5088 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
5089 0 : ctx->zd_vrf_id = ifp->vrf->vrf_id;
5090 0 : dplane_ctx_set_type(ctx, protocol);
5091 :
5092 0 : zns = zebra_ns_lookup(ifp->vrf->vrf_id);
5093 0 : dplane_ctx_ns_init(ctx, zns, false);
5094 :
5095 0 : strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
5096 0 : ctx->zd_ifindex = ifp->ifindex;
5097 :
5098 : /* Init the neighbor-specific data area */
5099 0 : memset(&ctx->u.neigh, 0, sizeof(ctx->u.neigh));
5100 :
5101 0 : ctx->u.neigh.ip_addr = *ip;
5102 0 : if (mac)
5103 0 : ctx->u.neigh.link.mac = *mac;
5104 0 : else if (link_ip)
5105 0 : ctx->u.neigh.link.ip_addr = *link_ip;
5106 :
5107 0 : ctx->u.neigh.flags = flags;
5108 0 : ctx->u.neigh.state = state;
5109 0 : ctx->u.neigh.update_flags = update_flags;
5110 :
5111 : /* Enqueue for processing on the dplane pthread */
5112 0 : ret = dplane_update_enqueue(ctx);
5113 :
5114 : /* Increment counter */
5115 0 : atomic_fetch_add_explicit(&zdplane_info.dg_neighs_in, 1,
5116 : memory_order_relaxed);
5117 :
5118 0 : if (ret == AOK)
5119 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
5120 : else {
5121 : /* Error counter */
5122 0 : atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors, 1,
5123 : memory_order_relaxed);
5124 0 : dplane_ctx_free(&ctx);
5125 : }
5126 :
5127 0 : return result;
5128 : }
5129 :
5130 : /*
5131 : * Common helper api for PBR rule updates
5132 : */
5133 : static enum zebra_dplane_result
5134 0 : rule_update_internal(enum dplane_op_e op, struct zebra_pbr_rule *new_rule,
5135 : struct zebra_pbr_rule *old_rule)
5136 : {
5137 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
5138 0 : struct zebra_dplane_ctx *ctx;
5139 0 : int ret;
5140 :
5141 0 : ctx = dplane_ctx_alloc();
5142 :
5143 0 : ret = dplane_ctx_rule_init(ctx, op, new_rule, old_rule);
5144 0 : if (ret != AOK)
5145 0 : goto done;
5146 :
5147 0 : ret = dplane_update_enqueue(ctx);
5148 :
5149 0 : done:
5150 0 : atomic_fetch_add_explicit(&zdplane_info.dg_rules_in, 1,
5151 : memory_order_relaxed);
5152 :
5153 0 : if (ret == AOK)
5154 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
5155 : else {
5156 0 : atomic_fetch_add_explicit(&zdplane_info.dg_rule_errors, 1,
5157 : memory_order_relaxed);
5158 0 : dplane_ctx_free(&ctx);
5159 : }
5160 :
5161 0 : return result;
5162 : }
5163 :
5164 0 : enum zebra_dplane_result dplane_pbr_rule_add(struct zebra_pbr_rule *rule)
5165 : {
5166 0 : return rule_update_internal(DPLANE_OP_RULE_ADD, rule, NULL);
5167 : }
5168 :
5169 0 : enum zebra_dplane_result dplane_pbr_rule_delete(struct zebra_pbr_rule *rule)
5170 : {
5171 0 : return rule_update_internal(DPLANE_OP_RULE_DELETE, rule, NULL);
5172 : }
5173 :
5174 0 : enum zebra_dplane_result dplane_pbr_rule_update(struct zebra_pbr_rule *old_rule,
5175 : struct zebra_pbr_rule *new_rule)
5176 : {
5177 0 : return rule_update_internal(DPLANE_OP_RULE_UPDATE, new_rule, old_rule);
5178 : }
5179 : /*
5180 : * Common helper api for iptable updates
5181 : */
5182 : static enum zebra_dplane_result
5183 0 : iptable_update_internal(enum dplane_op_e op, struct zebra_pbr_iptable *iptable)
5184 : {
5185 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
5186 0 : struct zebra_dplane_ctx *ctx;
5187 0 : int ret;
5188 :
5189 0 : if ((op == DPLANE_OP_IPTABLE_ADD &&
5190 0 : CHECK_FLAG(iptable->internal_flags, IPTABLE_INSTALL_QUEUED)) ||
5191 0 : (op == DPLANE_OP_IPTABLE_DELETE &&
5192 0 : CHECK_FLAG(iptable->internal_flags, IPTABLE_UNINSTALL_QUEUED))) {
5193 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
5194 0 : zlog_debug(
5195 : "update dplane ctx %s: iptable %s already in progress",
5196 : dplane_op2str(op), iptable->ipset_name);
5197 0 : return result;
5198 : }
5199 :
5200 0 : ctx = dplane_ctx_alloc();
5201 :
5202 0 : ret = dplane_ctx_iptable_init(ctx, op, iptable);
5203 0 : if (ret != AOK)
5204 0 : goto done;
5205 :
5206 0 : ret = dplane_update_enqueue(ctx);
5207 :
5208 0 : done:
5209 0 : atomic_fetch_add_explicit(&zdplane_info.dg_iptable_in, 1,
5210 : memory_order_relaxed);
5211 :
5212 0 : if (ret == AOK) {
5213 0 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
5214 0 : if (op == DPLANE_OP_IPTABLE_ADD)
5215 0 : SET_FLAG(iptable->internal_flags,
5216 : IPTABLE_INSTALL_QUEUED);
5217 : else
5218 0 : SET_FLAG(iptable->internal_flags,
5219 : IPTABLE_UNINSTALL_QUEUED);
5220 : } else {
5221 0 : atomic_fetch_add_explicit(&zdplane_info.dg_iptable_errors, 1,
5222 : memory_order_relaxed);
5223 0 : dplane_ctx_free(&ctx);
5224 : }
5225 : return result;
5226 : }
5227 :
5228 : enum zebra_dplane_result
5229 0 : dplane_pbr_iptable_add(struct zebra_pbr_iptable *iptable)
5230 : {
5231 0 : return iptable_update_internal(DPLANE_OP_IPTABLE_ADD, iptable);
5232 : }
5233 :
5234 : enum zebra_dplane_result
5235 0 : dplane_pbr_iptable_delete(struct zebra_pbr_iptable *iptable)
5236 : {
5237 0 : return iptable_update_internal(DPLANE_OP_IPTABLE_DELETE, iptable);
5238 : }
5239 :
5240 : /*
5241 : * Common helper api for ipset updates
5242 : */
5243 : static enum zebra_dplane_result
5244 0 : ipset_update_internal(enum dplane_op_e op, struct zebra_pbr_ipset *ipset)
5245 : {
5246 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
5247 0 : struct zebra_dplane_ctx *ctx;
5248 0 : int ret;
5249 :
5250 0 : ctx = dplane_ctx_alloc();
5251 :
5252 0 : ret = dplane_ctx_ipset_init(ctx, op, ipset);
5253 0 : if (ret != AOK)
5254 0 : goto done;
5255 :
5256 0 : ret = dplane_update_enqueue(ctx);
5257 :
5258 0 : done:
5259 0 : atomic_fetch_add_explicit(&zdplane_info.dg_ipset_in, 1,
5260 : memory_order_relaxed);
5261 :
5262 0 : if (ret == AOK)
5263 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
5264 : else {
5265 0 : atomic_fetch_add_explicit(&zdplane_info.dg_ipset_errors, 1,
5266 : memory_order_relaxed);
5267 0 : dplane_ctx_free(&ctx);
5268 : }
5269 :
5270 0 : return result;
5271 : }
5272 :
5273 0 : enum zebra_dplane_result dplane_pbr_ipset_add(struct zebra_pbr_ipset *ipset)
5274 : {
5275 0 : return ipset_update_internal(DPLANE_OP_IPSET_ADD, ipset);
5276 : }
5277 :
5278 0 : enum zebra_dplane_result dplane_pbr_ipset_delete(struct zebra_pbr_ipset *ipset)
5279 : {
5280 0 : return ipset_update_internal(DPLANE_OP_IPSET_DELETE, ipset);
5281 : }
5282 :
5283 : /*
5284 : * Common helper api for ipset updates
5285 : */
5286 : static enum zebra_dplane_result
5287 0 : ipset_entry_update_internal(enum dplane_op_e op,
5288 : struct zebra_pbr_ipset_entry *ipset_entry)
5289 : {
5290 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
5291 0 : struct zebra_dplane_ctx *ctx;
5292 0 : int ret;
5293 :
5294 0 : ctx = dplane_ctx_alloc();
5295 :
5296 0 : ret = dplane_ctx_ipset_entry_init(ctx, op, ipset_entry);
5297 0 : if (ret != AOK)
5298 0 : goto done;
5299 :
5300 0 : ret = dplane_update_enqueue(ctx);
5301 :
5302 0 : done:
5303 0 : atomic_fetch_add_explicit(&zdplane_info.dg_ipset_entry_in, 1,
5304 : memory_order_relaxed);
5305 :
5306 0 : if (ret == AOK)
5307 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
5308 : else {
5309 0 : atomic_fetch_add_explicit(&zdplane_info.dg_ipset_entry_errors,
5310 : 1, memory_order_relaxed);
5311 0 : dplane_ctx_free(&ctx);
5312 : }
5313 :
5314 0 : return result;
5315 : }
5316 :
5317 : enum zebra_dplane_result
5318 0 : dplane_pbr_ipset_entry_add(struct zebra_pbr_ipset_entry *ipset)
5319 : {
5320 0 : return ipset_entry_update_internal(DPLANE_OP_IPSET_ENTRY_ADD, ipset);
5321 : }
5322 :
5323 : enum zebra_dplane_result
5324 0 : dplane_pbr_ipset_entry_delete(struct zebra_pbr_ipset_entry *ipset)
5325 : {
5326 0 : return ipset_entry_update_internal(DPLANE_OP_IPSET_ENTRY_DELETE, ipset);
5327 : }
5328 :
5329 : /*
5330 : * Common helper api for GRE set
5331 : */
5332 : enum zebra_dplane_result
5333 0 : dplane_gre_set(struct interface *ifp, struct interface *ifp_link,
5334 : unsigned int mtu, const struct zebra_l2info_gre *gre_info)
5335 : {
5336 0 : enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
5337 0 : struct zebra_dplane_ctx *ctx;
5338 0 : enum dplane_op_e op = DPLANE_OP_GRE_SET;
5339 0 : int ret;
5340 0 : struct zebra_ns *zns;
5341 :
5342 0 : ctx = dplane_ctx_alloc();
5343 :
5344 0 : if (!ifp)
5345 : return result;
5346 :
5347 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
5348 0 : zlog_debug("init dplane ctx %s: if %s link %s%s",
5349 : dplane_op2str(op), ifp->name,
5350 : ifp_link ? "set" : "unset", ifp_link ?
5351 : ifp_link->name : "");
5352 : }
5353 :
5354 0 : ctx->zd_op = op;
5355 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
5356 0 : zns = zebra_ns_lookup(ifp->vrf->vrf_id);
5357 0 : if (!zns)
5358 : return result;
5359 0 : dplane_ctx_ns_init(ctx, zns, false);
5360 :
5361 0 : dplane_ctx_set_ifname(ctx, ifp->name);
5362 0 : ctx->zd_vrf_id = ifp->vrf->vrf_id;
5363 0 : ctx->zd_ifindex = ifp->ifindex;
5364 0 : if (ifp_link)
5365 0 : ctx->u.gre.link_ifindex = ifp_link->ifindex;
5366 : else
5367 0 : ctx->u.gre.link_ifindex = 0;
5368 0 : if (gre_info)
5369 0 : memcpy(&ctx->u.gre.info, gre_info, sizeof(ctx->u.gre.info));
5370 0 : ctx->u.gre.mtu = mtu;
5371 :
5372 0 : ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
5373 :
5374 : /* Enqueue context for processing */
5375 0 : ret = dplane_update_enqueue(ctx);
5376 :
5377 : /* Update counter */
5378 0 : atomic_fetch_add_explicit(&zdplane_info.dg_gre_set_in, 1,
5379 : memory_order_relaxed);
5380 :
5381 0 : if (ret == AOK)
5382 : result = ZEBRA_DPLANE_REQUEST_QUEUED;
5383 : else {
5384 0 : atomic_fetch_add_explicit(
5385 : &zdplane_info.dg_gre_set_errors, 1,
5386 : memory_order_relaxed);
5387 0 : if (ctx)
5388 0 : dplane_ctx_free(&ctx);
5389 : result = ZEBRA_DPLANE_REQUEST_FAILURE;
5390 : }
5391 : return result;
5392 : }
5393 :
5394 : /*
5395 : * Handler for 'show dplane'
5396 : */
5397 0 : int dplane_show_helper(struct vty *vty, bool detailed)
5398 : {
5399 0 : uint64_t queued, queue_max, limit, errs, incoming, yields,
5400 : other_errs;
5401 :
5402 : /* Using atomics because counters are being changed in different
5403 : * pthread contexts.
5404 : */
5405 0 : incoming = atomic_load_explicit(&zdplane_info.dg_routes_in,
5406 : memory_order_relaxed);
5407 0 : limit = atomic_load_explicit(&zdplane_info.dg_max_queued_updates,
5408 : memory_order_relaxed);
5409 0 : queued = atomic_load_explicit(&zdplane_info.dg_routes_queued,
5410 : memory_order_relaxed);
5411 0 : queue_max = atomic_load_explicit(&zdplane_info.dg_routes_queued_max,
5412 : memory_order_relaxed);
5413 0 : errs = atomic_load_explicit(&zdplane_info.dg_route_errors,
5414 : memory_order_relaxed);
5415 0 : yields = atomic_load_explicit(&zdplane_info.dg_update_yields,
5416 : memory_order_relaxed);
5417 0 : other_errs = atomic_load_explicit(&zdplane_info.dg_other_errors,
5418 : memory_order_relaxed);
5419 :
5420 0 : vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n",
5421 : incoming);
5422 0 : vty_out(vty, "Route update errors: %"PRIu64"\n", errs);
5423 0 : vty_out(vty, "Other errors : %"PRIu64"\n", other_errs);
5424 0 : vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit);
5425 0 : vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued);
5426 0 : vty_out(vty, "Route update queue max: %"PRIu64"\n", queue_max);
5427 0 : vty_out(vty, "Dplane update yields: %"PRIu64"\n", yields);
5428 :
5429 0 : incoming = atomic_load_explicit(&zdplane_info.dg_lsps_in,
5430 : memory_order_relaxed);
5431 0 : errs = atomic_load_explicit(&zdplane_info.dg_lsp_errors,
5432 : memory_order_relaxed);
5433 0 : vty_out(vty, "LSP updates: %"PRIu64"\n", incoming);
5434 0 : vty_out(vty, "LSP update errors: %"PRIu64"\n", errs);
5435 :
5436 0 : incoming = atomic_load_explicit(&zdplane_info.dg_pws_in,
5437 : memory_order_relaxed);
5438 0 : errs = atomic_load_explicit(&zdplane_info.dg_pw_errors,
5439 : memory_order_relaxed);
5440 0 : vty_out(vty, "PW updates: %"PRIu64"\n", incoming);
5441 0 : vty_out(vty, "PW update errors: %"PRIu64"\n", errs);
5442 :
5443 0 : incoming = atomic_load_explicit(&zdplane_info.dg_intf_addrs_in,
5444 : memory_order_relaxed);
5445 0 : errs = atomic_load_explicit(&zdplane_info.dg_intf_addr_errors,
5446 : memory_order_relaxed);
5447 0 : vty_out(vty, "Intf addr updates: %"PRIu64"\n", incoming);
5448 0 : vty_out(vty, "Intf addr errors: %"PRIu64"\n", errs);
5449 :
5450 0 : incoming = atomic_load_explicit(&zdplane_info.dg_intf_changes,
5451 : memory_order_relaxed);
5452 0 : errs = atomic_load_explicit(&zdplane_info.dg_intf_changes_errors,
5453 : memory_order_relaxed);
5454 0 : vty_out(vty, "Intf change updates: %" PRIu64 "\n", incoming);
5455 0 : vty_out(vty, "Intf change errors: %" PRIu64 "\n", errs);
5456 :
5457 0 : incoming = atomic_load_explicit(&zdplane_info.dg_macs_in,
5458 : memory_order_relaxed);
5459 0 : errs = atomic_load_explicit(&zdplane_info.dg_mac_errors,
5460 : memory_order_relaxed);
5461 0 : vty_out(vty, "EVPN MAC updates: %"PRIu64"\n", incoming);
5462 0 : vty_out(vty, "EVPN MAC errors: %"PRIu64"\n", errs);
5463 :
5464 0 : incoming = atomic_load_explicit(&zdplane_info.dg_neighs_in,
5465 : memory_order_relaxed);
5466 0 : errs = atomic_load_explicit(&zdplane_info.dg_neigh_errors,
5467 : memory_order_relaxed);
5468 0 : vty_out(vty, "EVPN neigh updates: %"PRIu64"\n", incoming);
5469 0 : vty_out(vty, "EVPN neigh errors: %"PRIu64"\n", errs);
5470 :
5471 0 : incoming = atomic_load_explicit(&zdplane_info.dg_rules_in,
5472 : memory_order_relaxed);
5473 0 : errs = atomic_load_explicit(&zdplane_info.dg_rule_errors,
5474 : memory_order_relaxed);
5475 0 : vty_out(vty, "Rule updates: %" PRIu64 "\n", incoming);
5476 0 : vty_out(vty, "Rule errors: %" PRIu64 "\n", errs);
5477 :
5478 0 : incoming = atomic_load_explicit(&zdplane_info.dg_br_port_in,
5479 : memory_order_relaxed);
5480 0 : errs = atomic_load_explicit(&zdplane_info.dg_br_port_errors,
5481 : memory_order_relaxed);
5482 0 : vty_out(vty, "Bridge port updates: %" PRIu64 "\n", incoming);
5483 0 : vty_out(vty, "Bridge port errors: %" PRIu64 "\n", errs);
5484 :
5485 0 : incoming = atomic_load_explicit(&zdplane_info.dg_iptable_in,
5486 : memory_order_relaxed);
5487 0 : errs = atomic_load_explicit(&zdplane_info.dg_iptable_errors,
5488 : memory_order_relaxed);
5489 0 : vty_out(vty, "IPtable updates: %" PRIu64 "\n", incoming);
5490 0 : vty_out(vty, "IPtable errors: %" PRIu64 "\n", errs);
5491 0 : incoming = atomic_load_explicit(&zdplane_info.dg_ipset_in,
5492 : memory_order_relaxed);
5493 0 : errs = atomic_load_explicit(&zdplane_info.dg_ipset_errors,
5494 : memory_order_relaxed);
5495 0 : vty_out(vty, "IPset updates: %" PRIu64 "\n", incoming);
5496 0 : vty_out(vty, "IPset errors: %" PRIu64 "\n", errs);
5497 0 : incoming = atomic_load_explicit(&zdplane_info.dg_ipset_entry_in,
5498 : memory_order_relaxed);
5499 0 : errs = atomic_load_explicit(&zdplane_info.dg_ipset_entry_errors,
5500 : memory_order_relaxed);
5501 0 : vty_out(vty, "IPset entry updates: %" PRIu64 "\n", incoming);
5502 0 : vty_out(vty, "IPset entry errors: %" PRIu64 "\n", errs);
5503 :
5504 0 : incoming = atomic_load_explicit(&zdplane_info.dg_neightable_in,
5505 : memory_order_relaxed);
5506 0 : errs = atomic_load_explicit(&zdplane_info.dg_neightable_errors,
5507 : memory_order_relaxed);
5508 0 : vty_out(vty, "Neighbor Table updates: %"PRIu64"\n", incoming);
5509 0 : vty_out(vty, "Neighbor Table errors: %"PRIu64"\n", errs);
5510 :
5511 0 : incoming = atomic_load_explicit(&zdplane_info.dg_gre_set_in,
5512 : memory_order_relaxed);
5513 0 : errs = atomic_load_explicit(&zdplane_info.dg_gre_set_errors,
5514 : memory_order_relaxed);
5515 0 : vty_out(vty, "GRE set updates: %"PRIu64"\n", incoming);
5516 0 : vty_out(vty, "GRE set errors: %"PRIu64"\n", errs);
5517 0 : return CMD_SUCCESS;
5518 : }
5519 :
5520 : /*
5521 : * Handler for 'show dplane providers'
5522 : */
5523 0 : int dplane_show_provs_helper(struct vty *vty, bool detailed)
5524 : {
5525 0 : struct zebra_dplane_provider *prov;
5526 0 : uint64_t in, in_q, in_max, out, out_q, out_max;
5527 :
5528 0 : vty_out(vty, "Zebra dataplane providers:\n");
5529 :
5530 0 : DPLANE_LOCK();
5531 0 : prov = dplane_prov_list_first(&zdplane_info.dg_providers);
5532 0 : DPLANE_UNLOCK();
5533 :
5534 : /* Show counters, useful info from each registered provider */
5535 0 : while (prov) {
5536 :
5537 0 : in = atomic_load_explicit(&prov->dp_in_counter,
5538 : memory_order_relaxed);
5539 0 : in_q = atomic_load_explicit(&prov->dp_in_queued,
5540 : memory_order_relaxed);
5541 0 : in_max = atomic_load_explicit(&prov->dp_in_max,
5542 : memory_order_relaxed);
5543 0 : out = atomic_load_explicit(&prov->dp_out_counter,
5544 : memory_order_relaxed);
5545 0 : out_q = atomic_load_explicit(&prov->dp_out_queued,
5546 : memory_order_relaxed);
5547 0 : out_max = atomic_load_explicit(&prov->dp_out_max,
5548 : memory_order_relaxed);
5549 :
5550 0 : vty_out(vty, "%s (%u): in: %"PRIu64", q: %"PRIu64", q_max: %"PRIu64", out: %"PRIu64", q: %"PRIu64", q_max: %"PRIu64"\n",
5551 0 : prov->dp_name, prov->dp_id, in, in_q, in_max,
5552 : out, out_q, out_max);
5553 :
5554 0 : prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov);
5555 : }
5556 :
5557 0 : return CMD_SUCCESS;
5558 : }
5559 :
5560 : /*
5561 : * Helper for 'show run' etc.
5562 : */
5563 0 : int dplane_config_write_helper(struct vty *vty)
5564 : {
5565 0 : if (zdplane_info.dg_max_queued_updates != DPLANE_DEFAULT_MAX_QUEUED)
5566 0 : vty_out(vty, "zebra dplane limit %u\n",
5567 0 : zdplane_info.dg_max_queued_updates);
5568 :
5569 0 : return 0;
5570 : }
5571 :
5572 : /*
5573 : * Provider registration
5574 : */
5575 1 : int dplane_provider_register(const char *name,
5576 : enum dplane_provider_prio prio,
5577 : int flags,
5578 : int (*start_fp)(struct zebra_dplane_provider *),
5579 : int (*fp)(struct zebra_dplane_provider *),
5580 : int (*fini_fp)(struct zebra_dplane_provider *,
5581 : bool early),
5582 : void *data,
5583 : struct zebra_dplane_provider **prov_p)
5584 : {
5585 1 : int ret = 0;
5586 1 : struct zebra_dplane_provider *p = NULL, *last;
5587 :
5588 : /* Validate */
5589 1 : if (fp == NULL) {
5590 0 : ret = EINVAL;
5591 0 : goto done;
5592 : }
5593 :
5594 1 : if (prio <= DPLANE_PRIO_NONE ||
5595 : prio > DPLANE_PRIO_LAST) {
5596 0 : ret = EINVAL;
5597 0 : goto done;
5598 : }
5599 :
5600 : /* Allocate and init new provider struct */
5601 1 : p = XCALLOC(MTYPE_DP_PROV, sizeof(struct zebra_dplane_provider));
5602 :
5603 1 : pthread_mutex_init(&(p->dp_mutex), NULL);
5604 1 : dplane_ctx_list_init(&p->dp_ctx_in_list);
5605 1 : dplane_ctx_list_init(&p->dp_ctx_out_list);
5606 :
5607 1 : p->dp_flags = flags;
5608 1 : p->dp_priority = prio;
5609 1 : p->dp_fp = fp;
5610 1 : p->dp_start = start_fp;
5611 1 : p->dp_fini = fini_fp;
5612 1 : p->dp_data = data;
5613 :
5614 : /* Lock - the dplane pthread may be running */
5615 1 : DPLANE_LOCK();
5616 :
5617 1 : p->dp_id = ++zdplane_info.dg_provider_id;
5618 :
5619 1 : if (name)
5620 1 : strlcpy(p->dp_name, name, DPLANE_PROVIDER_NAMELEN);
5621 : else
5622 0 : snprintf(p->dp_name, DPLANE_PROVIDER_NAMELEN,
5623 : "provider-%u", p->dp_id);
5624 :
5625 : /* Insert into list ordered by priority */
5626 2 : frr_each (dplane_prov_list, &zdplane_info.dg_providers, last) {
5627 0 : if (last->dp_priority > p->dp_priority)
5628 : break;
5629 : }
5630 :
5631 1 : if (last)
5632 0 : dplane_prov_list_add_after(&zdplane_info.dg_providers, last, p);
5633 : else
5634 1 : dplane_prov_list_add_tail(&zdplane_info.dg_providers, p);
5635 :
5636 : /* And unlock */
5637 1 : DPLANE_UNLOCK();
5638 :
5639 1 : if (IS_ZEBRA_DEBUG_DPLANE)
5640 0 : zlog_debug("dplane: registered new provider '%s' (%u), prio %d",
5641 : p->dp_name, p->dp_id, p->dp_priority);
5642 :
5643 1 : done:
5644 1 : if (prov_p)
5645 0 : *prov_p = p;
5646 :
5647 1 : return ret;
5648 : }
5649 :
5650 : /* Accessors for provider attributes */
5651 0 : const char *dplane_provider_get_name(const struct zebra_dplane_provider *prov)
5652 : {
5653 0 : return prov->dp_name;
5654 : }
5655 :
5656 0 : uint32_t dplane_provider_get_id(const struct zebra_dplane_provider *prov)
5657 : {
5658 0 : return prov->dp_id;
5659 : }
5660 :
5661 0 : void *dplane_provider_get_data(const struct zebra_dplane_provider *prov)
5662 : {
5663 0 : return prov->dp_data;
5664 : }
5665 :
5666 8 : int dplane_provider_get_work_limit(const struct zebra_dplane_provider *prov)
5667 : {
5668 8 : return zdplane_info.dg_updates_per_cycle;
5669 : }
5670 :
5671 : /* Lock/unlock a provider's mutex - iff the provider was registered with
5672 : * the THREADED flag.
5673 : */
5674 75 : void dplane_provider_lock(struct zebra_dplane_provider *prov)
5675 : {
5676 75 : if (dplane_provider_is_threaded(prov))
5677 0 : DPLANE_PROV_LOCK(prov);
5678 0 : }
5679 :
5680 75 : void dplane_provider_unlock(struct zebra_dplane_provider *prov)
5681 : {
5682 75 : if (dplane_provider_is_threaded(prov))
5683 0 : DPLANE_PROV_UNLOCK(prov);
5684 0 : }
5685 :
5686 : /*
5687 : * Dequeue and maintain associated counter
5688 : */
5689 33 : struct zebra_dplane_ctx *dplane_provider_dequeue_in_ctx(
5690 : struct zebra_dplane_provider *prov)
5691 : {
5692 33 : struct zebra_dplane_ctx *ctx = NULL;
5693 :
5694 66 : dplane_provider_lock(prov);
5695 :
5696 33 : ctx = dplane_ctx_list_pop(&(prov->dp_ctx_in_list));
5697 33 : if (ctx) {
5698 25 : atomic_fetch_sub_explicit(&prov->dp_in_queued, 1,
5699 : memory_order_relaxed);
5700 : }
5701 :
5702 66 : dplane_provider_unlock(prov);
5703 :
5704 33 : return ctx;
5705 : }
5706 :
5707 : /*
5708 : * Dequeue work to a list, return count
5709 : */
5710 0 : int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov,
5711 : struct dplane_ctx_list_head *listp)
5712 : {
5713 0 : int limit, ret;
5714 0 : struct zebra_dplane_ctx *ctx;
5715 :
5716 0 : limit = zdplane_info.dg_updates_per_cycle;
5717 :
5718 0 : dplane_provider_lock(prov);
5719 :
5720 0 : for (ret = 0; ret < limit; ret++) {
5721 0 : ctx = dplane_ctx_list_pop(&(prov->dp_ctx_in_list));
5722 0 : if (ctx)
5723 0 : dplane_ctx_list_add_tail(listp, ctx);
5724 : else
5725 : break;
5726 : }
5727 :
5728 0 : if (ret > 0)
5729 0 : atomic_fetch_sub_explicit(&prov->dp_in_queued, ret,
5730 : memory_order_relaxed);
5731 :
5732 0 : dplane_provider_unlock(prov);
5733 :
5734 0 : return ret;
5735 : }
5736 :
5737 0 : uint32_t dplane_provider_out_ctx_queue_len(struct zebra_dplane_provider *prov)
5738 : {
5739 0 : return atomic_load_explicit(&(prov->dp_out_counter),
5740 : memory_order_relaxed);
5741 : }
5742 :
5743 : /*
5744 : * Enqueue and maintain associated counter
5745 : */
5746 25 : void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
5747 : struct zebra_dplane_ctx *ctx)
5748 : {
5749 25 : uint64_t curr, high;
5750 :
5751 50 : dplane_provider_lock(prov);
5752 :
5753 25 : dplane_ctx_list_add_tail(&(prov->dp_ctx_out_list), ctx);
5754 :
5755 : /* Maintain out-queue counters */
5756 25 : atomic_fetch_add_explicit(&(prov->dp_out_queued), 1,
5757 : memory_order_relaxed);
5758 25 : curr = atomic_load_explicit(&prov->dp_out_queued,
5759 : memory_order_relaxed);
5760 25 : high = atomic_load_explicit(&prov->dp_out_max,
5761 : memory_order_relaxed);
5762 25 : if (curr > high)
5763 25 : atomic_store_explicit(&prov->dp_out_max, curr,
5764 : memory_order_relaxed);
5765 :
5766 50 : dplane_provider_unlock(prov);
5767 :
5768 25 : atomic_fetch_add_explicit(&(prov->dp_out_counter), 1,
5769 : memory_order_relaxed);
5770 25 : }
5771 :
5772 : /*
5773 : * Accessor for provider object
5774 : */
5775 150 : bool dplane_provider_is_threaded(const struct zebra_dplane_provider *prov)
5776 : {
5777 116 : return (prov->dp_flags & DPLANE_PROV_FLAG_THREADED);
5778 : }
5779 :
5780 : #ifdef HAVE_NETLINK
5781 : /*
5782 : * Callback when an OS (netlink) incoming event read is ready. This runs
5783 : * in the dplane pthread.
5784 : */
5785 16 : static void dplane_incoming_read(struct thread *event)
5786 : {
5787 16 : struct dplane_zns_info *zi = THREAD_ARG(event);
5788 :
5789 16 : kernel_dplane_read(&zi->info);
5790 :
5791 : /* Re-start read task */
5792 16 : thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi,
5793 : zi->info.sock, &zi->t_read);
5794 16 : }
5795 :
5796 : /*
5797 : * Callback in the dataplane pthread that requests info from the OS and
5798 : * initiates netlink reads.
5799 : */
5800 1 : static void dplane_incoming_request(struct thread *event)
5801 : {
5802 1 : struct dplane_zns_info *zi = THREAD_ARG(event);
5803 :
5804 : /* Start read task */
5805 1 : thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi,
5806 : zi->info.sock, &zi->t_read);
5807 :
5808 : /* Send requests */
5809 1 : netlink_request_netconf(zi->info.sock);
5810 1 : }
5811 :
5812 : /*
5813 : * Initiate requests for existing info from the OS. This is called by the
5814 : * main pthread, but we want all activity on the dplane netlink socket to
5815 : * take place on the dplane pthread, so we schedule an event to accomplish
5816 : * that.
5817 : */
5818 2 : static void dplane_kernel_info_request(struct dplane_zns_info *zi)
5819 : {
5820 : /* If we happen to encounter an enabled zns before the dplane
5821 : * pthread is running, we'll initiate this later on.
5822 : */
5823 2 : if (zdplane_info.dg_master)
5824 1 : thread_add_event(zdplane_info.dg_master,
5825 : dplane_incoming_request, zi, 0,
5826 : &zi->t_request);
5827 2 : }
5828 :
5829 : #endif /* HAVE_NETLINK */
5830 :
5831 : /*
5832 : * Notify dplane when namespaces are enabled and disabled. The dplane
5833 : * needs to start and stop reading incoming events from the zns. In the
5834 : * common case where vrfs are _not_ namespaces, there will only be one
5835 : * of these.
5836 : *
5837 : * This is called in the main pthread.
5838 : */
5839 2 : void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled)
5840 : {
5841 2 : struct dplane_zns_info *zi;
5842 :
5843 2 : if (IS_ZEBRA_DEBUG_DPLANE)
5844 0 : zlog_debug("%s: %s for nsid %u", __func__,
5845 : (enabled ? "ENABLED" : "DISABLED"), zns->ns_id);
5846 :
5847 : /* Search for an existing zns info entry */
5848 4 : frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
5849 1 : if (zi->info.ns_id == zns->ns_id)
5850 : break;
5851 : }
5852 :
5853 2 : if (enabled) {
5854 : /* Create a new entry if necessary; start reading. */
5855 1 : if (zi == NULL) {
5856 1 : zi = XCALLOC(MTYPE_DP_NS, sizeof(*zi));
5857 :
5858 1 : zi->info.ns_id = zns->ns_id;
5859 :
5860 1 : zns_info_list_add_tail(&zdplane_info.dg_zns_list, zi);
5861 :
5862 1 : if (IS_ZEBRA_DEBUG_DPLANE)
5863 0 : zlog_debug("%s: nsid %u, new zi %p", __func__,
5864 : zns->ns_id, zi);
5865 : }
5866 :
5867 : /* Make sure we're up-to-date with the zns object */
5868 : #if defined(HAVE_NETLINK)
5869 1 : zi->info.is_cmd = false;
5870 1 : zi->info.sock = zns->netlink_dplane_in.sock;
5871 :
5872 : /* Initiate requests for existing info from the OS, and
5873 : * begin reading from the netlink socket.
5874 : */
5875 1 : dplane_kernel_info_request(zi);
5876 : #endif
5877 1 : } else if (zi) {
5878 1 : if (IS_ZEBRA_DEBUG_DPLANE)
5879 0 : zlog_debug("%s: nsid %u, deleting zi %p", __func__,
5880 : zns->ns_id, zi);
5881 :
5882 : /* Stop reading, free memory */
5883 1 : zns_info_list_del(&zdplane_info.dg_zns_list, zi);
5884 :
5885 : /* Stop any outstanding tasks */
5886 1 : if (zdplane_info.dg_master) {
5887 1 : thread_cancel_async(zdplane_info.dg_master,
5888 : &zi->t_request, NULL);
5889 :
5890 1 : thread_cancel_async(zdplane_info.dg_master, &zi->t_read,
5891 : NULL);
5892 : }
5893 :
5894 1 : XFREE(MTYPE_DP_NS, zi);
5895 : }
5896 2 : }
5897 :
5898 : /*
5899 : * Provider api to signal that work/events are available
5900 : * for the dataplane pthread.
5901 : */
5902 25 : int dplane_provider_work_ready(void)
5903 : {
5904 : /* Note that during zebra startup, we may be offered work before
5905 : * the dataplane pthread (and thread-master) are ready. We want to
5906 : * enqueue the work, but the event-scheduling machinery may not be
5907 : * available.
5908 : */
5909 25 : if (zdplane_info.dg_run) {
5910 25 : thread_add_event(zdplane_info.dg_master,
5911 : dplane_thread_loop, NULL, 0,
5912 : &zdplane_info.dg_t_update);
5913 : }
5914 :
5915 25 : return AOK;
5916 : }
5917 :
5918 : /*
5919 : * Enqueue a context directly to zebra main.
5920 : */
5921 26 : void dplane_provider_enqueue_to_zebra(struct zebra_dplane_ctx *ctx)
5922 : {
5923 26 : struct dplane_ctx_list_head temp_list;
5924 :
5925 : /* Zebra's api takes a list, so we need to use a temporary list */
5926 26 : dplane_ctx_list_init(&temp_list);
5927 :
5928 26 : dplane_ctx_list_add_tail(&temp_list, ctx);
5929 26 : (zdplane_info.dg_results_cb)(&temp_list);
5930 26 : }
5931 :
5932 : /*
5933 : * Kernel dataplane provider
5934 : */
5935 :
5936 0 : static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
5937 : {
5938 0 : char buf[PREFIX_STRLEN];
5939 :
5940 0 : switch (dplane_ctx_get_op(ctx)) {
5941 :
5942 : case DPLANE_OP_ROUTE_INSTALL:
5943 : case DPLANE_OP_ROUTE_UPDATE:
5944 : case DPLANE_OP_ROUTE_DELETE:
5945 0 : zlog_debug("%u:%pFX Dplane route update ctx %p op %s",
5946 : dplane_ctx_get_vrf(ctx), dplane_ctx_get_dest(ctx),
5947 : ctx, dplane_op2str(dplane_ctx_get_op(ctx)));
5948 0 : break;
5949 :
5950 : case DPLANE_OP_NH_INSTALL:
5951 : case DPLANE_OP_NH_UPDATE:
5952 : case DPLANE_OP_NH_DELETE:
5953 0 : zlog_debug("ID (%u) Dplane nexthop update ctx %p op %s",
5954 : dplane_ctx_get_nhe_id(ctx), ctx,
5955 : dplane_op2str(dplane_ctx_get_op(ctx)));
5956 0 : break;
5957 :
5958 : case DPLANE_OP_LSP_INSTALL:
5959 : case DPLANE_OP_LSP_UPDATE:
5960 : case DPLANE_OP_LSP_DELETE:
5961 : break;
5962 :
5963 : case DPLANE_OP_PW_INSTALL:
5964 : case DPLANE_OP_PW_UNINSTALL:
5965 0 : zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u",
5966 : dplane_ctx_get_ifname(ctx),
5967 : dplane_op2str(ctx->zd_op), dplane_ctx_get_pw_af(ctx),
5968 : dplane_ctx_get_pw_local_label(ctx),
5969 : dplane_ctx_get_pw_remote_label(ctx));
5970 0 : break;
5971 :
5972 : case DPLANE_OP_ADDR_INSTALL:
5973 : case DPLANE_OP_ADDR_UNINSTALL:
5974 0 : zlog_debug("Dplane intf %s, idx %u, addr %pFX",
5975 : dplane_op2str(dplane_ctx_get_op(ctx)),
5976 : dplane_ctx_get_ifindex(ctx),
5977 : dplane_ctx_get_intf_addr(ctx));
5978 0 : break;
5979 :
5980 : case DPLANE_OP_MAC_INSTALL:
5981 : case DPLANE_OP_MAC_DELETE:
5982 0 : prefix_mac2str(dplane_ctx_mac_get_addr(ctx), buf,
5983 : sizeof(buf));
5984 :
5985 0 : zlog_debug("Dplane %s, mac %s, ifindex %u",
5986 : dplane_op2str(dplane_ctx_get_op(ctx)),
5987 : buf, dplane_ctx_get_ifindex(ctx));
5988 0 : break;
5989 :
5990 : case DPLANE_OP_NEIGH_INSTALL:
5991 : case DPLANE_OP_NEIGH_UPDATE:
5992 : case DPLANE_OP_NEIGH_DELETE:
5993 : case DPLANE_OP_VTEP_ADD:
5994 : case DPLANE_OP_VTEP_DELETE:
5995 : case DPLANE_OP_NEIGH_DISCOVER:
5996 : case DPLANE_OP_NEIGH_IP_INSTALL:
5997 : case DPLANE_OP_NEIGH_IP_DELETE:
5998 0 : ipaddr2str(dplane_ctx_neigh_get_ipaddr(ctx), buf,
5999 : sizeof(buf));
6000 :
6001 0 : zlog_debug("Dplane %s, ip %s, ifindex %u",
6002 : dplane_op2str(dplane_ctx_get_op(ctx)),
6003 : buf, dplane_ctx_get_ifindex(ctx));
6004 0 : break;
6005 :
6006 : case DPLANE_OP_RULE_ADD:
6007 : case DPLANE_OP_RULE_DELETE:
6008 : case DPLANE_OP_RULE_UPDATE:
6009 0 : zlog_debug("Dplane rule update op %s, if %s(%u), ctx %p",
6010 : dplane_op2str(dplane_ctx_get_op(ctx)),
6011 : dplane_ctx_get_ifname(ctx),
6012 : dplane_ctx_get_ifindex(ctx), ctx);
6013 0 : break;
6014 :
6015 : case DPLANE_OP_SYS_ROUTE_ADD:
6016 : case DPLANE_OP_SYS_ROUTE_DELETE:
6017 : case DPLANE_OP_ROUTE_NOTIFY:
6018 : case DPLANE_OP_LSP_NOTIFY:
6019 : case DPLANE_OP_BR_PORT_UPDATE:
6020 :
6021 : case DPLANE_OP_NONE:
6022 : break;
6023 :
6024 : case DPLANE_OP_IPTABLE_ADD:
6025 : case DPLANE_OP_IPTABLE_DELETE: {
6026 0 : struct zebra_pbr_iptable ipt;
6027 :
6028 0 : dplane_ctx_get_pbr_iptable(ctx, &ipt);
6029 0 : zlog_debug("Dplane iptable update op %s, unique(%u), ctx %p",
6030 : dplane_op2str(dplane_ctx_get_op(ctx)), ipt.unique,
6031 : ctx);
6032 0 : } break;
6033 0 : case DPLANE_OP_IPSET_ADD:
6034 : case DPLANE_OP_IPSET_DELETE: {
6035 0 : struct zebra_pbr_ipset ipset;
6036 :
6037 0 : dplane_ctx_get_pbr_ipset(ctx, &ipset);
6038 0 : zlog_debug("Dplane ipset update op %s, unique(%u), ctx %p",
6039 : dplane_op2str(dplane_ctx_get_op(ctx)), ipset.unique,
6040 : ctx);
6041 0 : } break;
6042 0 : case DPLANE_OP_IPSET_ENTRY_ADD:
6043 : case DPLANE_OP_IPSET_ENTRY_DELETE: {
6044 0 : struct zebra_pbr_ipset_entry ipent;
6045 :
6046 0 : dplane_ctx_get_pbr_ipset_entry(ctx, &ipent);
6047 0 : zlog_debug(
6048 : "Dplane ipset entry update op %s, unique(%u), ctx %p",
6049 : dplane_op2str(dplane_ctx_get_op(ctx)), ipent.unique,
6050 : ctx);
6051 0 : } break;
6052 : case DPLANE_OP_NEIGH_TABLE_UPDATE:
6053 0 : zlog_debug("Dplane neigh table op %s, ifp %s, family %s",
6054 : dplane_op2str(dplane_ctx_get_op(ctx)),
6055 : dplane_ctx_get_ifname(ctx),
6056 : family2str(dplane_ctx_neightable_get_family(ctx)));
6057 0 : break;
6058 0 : case DPLANE_OP_GRE_SET:
6059 0 : zlog_debug("Dplane gre set op %s, ifp %s, link %u",
6060 : dplane_op2str(dplane_ctx_get_op(ctx)),
6061 : dplane_ctx_get_ifname(ctx),
6062 : ctx->u.gre.link_ifindex);
6063 0 : break;
6064 :
6065 : case DPLANE_OP_INTF_ADDR_ADD:
6066 : case DPLANE_OP_INTF_ADDR_DEL:
6067 0 : zlog_debug("Dplane incoming op %s, intf %s, addr %pFX",
6068 : dplane_op2str(dplane_ctx_get_op(ctx)),
6069 : dplane_ctx_get_ifname(ctx),
6070 : dplane_ctx_get_intf_addr(ctx));
6071 0 : break;
6072 :
6073 : case DPLANE_OP_INTF_NETCONFIG:
6074 0 : zlog_debug("%s: ifindex %d, mpls %d, mcast %d",
6075 : dplane_op2str(dplane_ctx_get_op(ctx)),
6076 : dplane_ctx_get_ifindex(ctx),
6077 : dplane_ctx_get_netconf_mpls(ctx),
6078 : dplane_ctx_get_netconf_mcast(ctx));
6079 0 : break;
6080 :
6081 : case DPLANE_OP_INTF_INSTALL:
6082 : case DPLANE_OP_INTF_UPDATE:
6083 : case DPLANE_OP_INTF_DELETE:
6084 0 : zlog_debug("Dplane intf %s, idx %u, protodown %d",
6085 : dplane_op2str(dplane_ctx_get_op(ctx)),
6086 : dplane_ctx_get_ifindex(ctx),
6087 : dplane_ctx_intf_is_protodown(ctx));
6088 0 : break;
6089 :
6090 : /* TODO: more detailed log */
6091 : case DPLANE_OP_TC_QDISC_INSTALL:
6092 : case DPLANE_OP_TC_QDISC_UNINSTALL:
6093 0 : zlog_debug("Dplane tc qdisc ifidx %u",
6094 : dplane_ctx_get_ifindex(ctx));
6095 0 : break;
6096 : case DPLANE_OP_TC_CLASS_ADD:
6097 : case DPLANE_OP_TC_CLASS_DELETE:
6098 : case DPLANE_OP_TC_CLASS_UPDATE:
6099 : break;
6100 : case DPLANE_OP_TC_FILTER_ADD:
6101 : case DPLANE_OP_TC_FILTER_DELETE:
6102 : case DPLANE_OP_TC_FILTER_UPDATE:
6103 : break;
6104 : }
6105 0 : }
6106 :
6107 25 : static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
6108 : {
6109 25 : enum zebra_dplane_result res = dplane_ctx_get_status(ctx);
6110 :
6111 25 : switch (dplane_ctx_get_op(ctx)) {
6112 :
6113 15 : case DPLANE_OP_ROUTE_INSTALL:
6114 : case DPLANE_OP_ROUTE_UPDATE:
6115 : case DPLANE_OP_ROUTE_DELETE:
6116 15 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6117 0 : atomic_fetch_add_explicit(&zdplane_info.dg_route_errors,
6118 : 1, memory_order_relaxed);
6119 :
6120 15 : if ((dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE)
6121 8 : && (res == ZEBRA_DPLANE_REQUEST_SUCCESS)) {
6122 8 : struct nexthop *nexthop;
6123 :
6124 : /* Update installed nexthops to signal which have been
6125 : * installed.
6126 : */
6127 16 : for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
6128 : nexthop)) {
6129 8 : if (CHECK_FLAG(nexthop->flags,
6130 : NEXTHOP_FLAG_RECURSIVE))
6131 0 : continue;
6132 :
6133 8 : if (CHECK_FLAG(nexthop->flags,
6134 : NEXTHOP_FLAG_ACTIVE)) {
6135 8 : SET_FLAG(nexthop->flags,
6136 : NEXTHOP_FLAG_FIB);
6137 : }
6138 : }
6139 : }
6140 : break;
6141 :
6142 10 : case DPLANE_OP_NH_INSTALL:
6143 : case DPLANE_OP_NH_UPDATE:
6144 : case DPLANE_OP_NH_DELETE:
6145 10 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6146 2 : atomic_fetch_add_explicit(
6147 : &zdplane_info.dg_nexthop_errors, 1,
6148 : memory_order_relaxed);
6149 : break;
6150 :
6151 0 : case DPLANE_OP_LSP_INSTALL:
6152 : case DPLANE_OP_LSP_UPDATE:
6153 : case DPLANE_OP_LSP_DELETE:
6154 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6155 0 : atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors,
6156 : 1, memory_order_relaxed);
6157 : break;
6158 :
6159 0 : case DPLANE_OP_PW_INSTALL:
6160 : case DPLANE_OP_PW_UNINSTALL:
6161 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6162 0 : atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
6163 : memory_order_relaxed);
6164 : break;
6165 :
6166 0 : case DPLANE_OP_ADDR_INSTALL:
6167 : case DPLANE_OP_ADDR_UNINSTALL:
6168 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6169 0 : atomic_fetch_add_explicit(
6170 : &zdplane_info.dg_intf_addr_errors, 1,
6171 : memory_order_relaxed);
6172 : break;
6173 :
6174 0 : case DPLANE_OP_MAC_INSTALL:
6175 : case DPLANE_OP_MAC_DELETE:
6176 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6177 0 : atomic_fetch_add_explicit(&zdplane_info.dg_mac_errors,
6178 : 1, memory_order_relaxed);
6179 : break;
6180 :
6181 0 : case DPLANE_OP_NEIGH_INSTALL:
6182 : case DPLANE_OP_NEIGH_UPDATE:
6183 : case DPLANE_OP_NEIGH_DELETE:
6184 : case DPLANE_OP_VTEP_ADD:
6185 : case DPLANE_OP_VTEP_DELETE:
6186 : case DPLANE_OP_NEIGH_DISCOVER:
6187 : case DPLANE_OP_NEIGH_IP_INSTALL:
6188 : case DPLANE_OP_NEIGH_IP_DELETE:
6189 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6190 0 : atomic_fetch_add_explicit(&zdplane_info.dg_neigh_errors,
6191 : 1, memory_order_relaxed);
6192 : break;
6193 :
6194 0 : case DPLANE_OP_RULE_ADD:
6195 : case DPLANE_OP_RULE_DELETE:
6196 : case DPLANE_OP_RULE_UPDATE:
6197 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6198 0 : atomic_fetch_add_explicit(&zdplane_info.dg_rule_errors,
6199 : 1, memory_order_relaxed);
6200 : break;
6201 :
6202 0 : case DPLANE_OP_IPTABLE_ADD:
6203 : case DPLANE_OP_IPTABLE_DELETE:
6204 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6205 0 : atomic_fetch_add_explicit(
6206 : &zdplane_info.dg_iptable_errors, 1,
6207 : memory_order_relaxed);
6208 : break;
6209 :
6210 0 : case DPLANE_OP_IPSET_ADD:
6211 : case DPLANE_OP_IPSET_DELETE:
6212 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6213 0 : atomic_fetch_add_explicit(&zdplane_info.dg_ipset_errors,
6214 : 1, memory_order_relaxed);
6215 : break;
6216 :
6217 0 : case DPLANE_OP_IPSET_ENTRY_ADD:
6218 : case DPLANE_OP_IPSET_ENTRY_DELETE:
6219 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6220 0 : atomic_fetch_add_explicit(
6221 : &zdplane_info.dg_ipset_entry_errors, 1,
6222 : memory_order_relaxed);
6223 : break;
6224 :
6225 0 : case DPLANE_OP_NEIGH_TABLE_UPDATE:
6226 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6227 0 : atomic_fetch_add_explicit(
6228 : &zdplane_info.dg_neightable_errors, 1,
6229 : memory_order_relaxed);
6230 : break;
6231 :
6232 0 : case DPLANE_OP_GRE_SET:
6233 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6234 0 : atomic_fetch_add_explicit(
6235 : &zdplane_info.dg_gre_set_errors, 1,
6236 : memory_order_relaxed);
6237 : break;
6238 :
6239 0 : case DPLANE_OP_INTF_INSTALL:
6240 : case DPLANE_OP_INTF_UPDATE:
6241 : case DPLANE_OP_INTF_DELETE:
6242 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6243 0 : atomic_fetch_add_explicit(&zdplane_info.dg_intf_errors,
6244 : 1, memory_order_relaxed);
6245 : break;
6246 :
6247 0 : case DPLANE_OP_TC_QDISC_INSTALL:
6248 : case DPLANE_OP_TC_QDISC_UNINSTALL:
6249 : case DPLANE_OP_TC_CLASS_ADD:
6250 : case DPLANE_OP_TC_CLASS_DELETE:
6251 : case DPLANE_OP_TC_CLASS_UPDATE:
6252 : case DPLANE_OP_TC_FILTER_ADD:
6253 : case DPLANE_OP_TC_FILTER_DELETE:
6254 : case DPLANE_OP_TC_FILTER_UPDATE:
6255 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6256 0 : atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors,
6257 : 1, memory_order_relaxed);
6258 : break;
6259 :
6260 : /* Ignore 'notifications' - no-op */
6261 : case DPLANE_OP_SYS_ROUTE_ADD:
6262 : case DPLANE_OP_SYS_ROUTE_DELETE:
6263 : case DPLANE_OP_ROUTE_NOTIFY:
6264 : case DPLANE_OP_LSP_NOTIFY:
6265 : case DPLANE_OP_BR_PORT_UPDATE:
6266 : break;
6267 :
6268 : /* TODO -- error counters for incoming events? */
6269 : case DPLANE_OP_INTF_ADDR_ADD:
6270 : case DPLANE_OP_INTF_ADDR_DEL:
6271 : case DPLANE_OP_INTF_NETCONFIG:
6272 : break;
6273 :
6274 0 : case DPLANE_OP_NONE:
6275 0 : if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
6276 0 : atomic_fetch_add_explicit(&zdplane_info.dg_other_errors,
6277 : 1, memory_order_relaxed);
6278 : break;
6279 : }
6280 25 : }
6281 :
6282 0 : static void kernel_dplane_process_iptable(struct zebra_dplane_provider *prov,
6283 : struct zebra_dplane_ctx *ctx)
6284 : {
6285 0 : zebra_pbr_process_iptable(ctx);
6286 0 : dplane_provider_enqueue_out_ctx(prov, ctx);
6287 0 : }
6288 :
6289 0 : static void kernel_dplane_process_ipset(struct zebra_dplane_provider *prov,
6290 : struct zebra_dplane_ctx *ctx)
6291 : {
6292 0 : zebra_pbr_process_ipset(ctx);
6293 0 : dplane_provider_enqueue_out_ctx(prov, ctx);
6294 0 : }
6295 :
6296 : static void
6297 0 : kernel_dplane_process_ipset_entry(struct zebra_dplane_provider *prov,
6298 : struct zebra_dplane_ctx *ctx)
6299 : {
6300 0 : zebra_pbr_process_ipset_entry(ctx);
6301 0 : dplane_provider_enqueue_out_ctx(prov, ctx);
6302 0 : }
6303 :
6304 0 : void dplane_rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
6305 : struct prefix_ipv6 *src_p, struct route_entry *re,
6306 : struct nexthop_group *ng, int startup,
6307 : struct zebra_dplane_ctx *ctx)
6308 : {
6309 0 : if (!ctx)
6310 0 : rib_add_multipath(afi, safi, p, src_p, re, ng, startup);
6311 : else {
6312 0 : dplane_ctx_route_init_basic(ctx, dplane_ctx_get_op(ctx), re, p,
6313 : src_p, afi, safi);
6314 0 : dplane_provider_enqueue_to_zebra(ctx);
6315 : }
6316 0 : }
6317 :
6318 : /*
6319 : * Kernel provider callback
6320 : */
6321 8 : static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
6322 : {
6323 8 : struct zebra_dplane_ctx *ctx;
6324 8 : struct dplane_ctx_list_head work_list;
6325 8 : int counter, limit;
6326 :
6327 8 : dplane_ctx_list_init(&work_list);
6328 :
6329 8 : limit = dplane_provider_get_work_limit(prov);
6330 :
6331 8 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
6332 0 : zlog_debug("dplane provider '%s': processing",
6333 : dplane_provider_get_name(prov));
6334 :
6335 33 : for (counter = 0; counter < limit; counter++) {
6336 33 : ctx = dplane_provider_dequeue_in_ctx(prov);
6337 33 : if (ctx == NULL)
6338 : break;
6339 25 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
6340 0 : kernel_dplane_log_detail(ctx);
6341 :
6342 25 : if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD
6343 25 : || dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_DELETE))
6344 0 : kernel_dplane_process_iptable(prov, ctx);
6345 25 : else if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ADD
6346 25 : || dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_DELETE))
6347 0 : kernel_dplane_process_ipset(prov, ctx);
6348 25 : else if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ENTRY_ADD
6349 25 : || dplane_ctx_get_op(ctx)
6350 : == DPLANE_OP_IPSET_ENTRY_DELETE))
6351 0 : kernel_dplane_process_ipset_entry(prov, ctx);
6352 : else
6353 50 : dplane_ctx_list_add_tail(&work_list, ctx);
6354 : }
6355 :
6356 8 : kernel_update_multi(&work_list);
6357 :
6358 33 : while ((ctx = dplane_ctx_list_pop(&work_list)) != NULL) {
6359 25 : kernel_dplane_handle_result(ctx);
6360 :
6361 25 : dplane_provider_enqueue_out_ctx(prov, ctx);
6362 : }
6363 :
6364 : /* Ensure that we'll run the work loop again if there's still
6365 : * more work to do.
6366 : */
6367 8 : if (counter >= limit) {
6368 0 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
6369 0 : zlog_debug("dplane provider '%s' reached max updates %d",
6370 : dplane_provider_get_name(prov), counter);
6371 :
6372 0 : atomic_fetch_add_explicit(&zdplane_info.dg_update_yields,
6373 : 1, memory_order_relaxed);
6374 :
6375 0 : dplane_provider_work_ready();
6376 : }
6377 :
6378 8 : return 0;
6379 : }
6380 :
6381 : #ifdef DPLANE_TEST_PROVIDER
6382 :
6383 : /*
6384 : * Test dataplane provider plugin
6385 : */
6386 :
6387 : /*
6388 : * Test provider process callback
6389 : */
6390 : static int test_dplane_process_func(struct zebra_dplane_provider *prov)
6391 : {
6392 : struct zebra_dplane_ctx *ctx;
6393 : int counter, limit;
6394 :
6395 : /* Just moving from 'in' queue to 'out' queue */
6396 :
6397 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
6398 : zlog_debug("dplane provider '%s': processing",
6399 : dplane_provider_get_name(prov));
6400 :
6401 : limit = dplane_provider_get_work_limit(prov);
6402 :
6403 : for (counter = 0; counter < limit; counter++) {
6404 : ctx = dplane_provider_dequeue_in_ctx(prov);
6405 : if (ctx == NULL)
6406 : break;
6407 :
6408 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
6409 : zlog_debug("dplane provider '%s': op %s",
6410 : dplane_provider_get_name(prov),
6411 : dplane_op2str(dplane_ctx_get_op(ctx)));
6412 :
6413 : dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
6414 :
6415 : dplane_provider_enqueue_out_ctx(prov, ctx);
6416 : }
6417 :
6418 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
6419 : zlog_debug("dplane provider '%s': processed %d",
6420 : dplane_provider_get_name(prov), counter);
6421 :
6422 : /* Ensure that we'll run the work loop again if there's still
6423 : * more work to do.
6424 : */
6425 : if (counter >= limit)
6426 : dplane_provider_work_ready();
6427 :
6428 : return 0;
6429 : }
6430 :
6431 : /*
6432 : * Test provider shutdown/fini callback
6433 : */
6434 : static int test_dplane_shutdown_func(struct zebra_dplane_provider *prov,
6435 : bool early)
6436 : {
6437 : if (IS_ZEBRA_DEBUG_DPLANE)
6438 : zlog_debug("dplane provider '%s': %sshutdown",
6439 : dplane_provider_get_name(prov),
6440 : early ? "early " : "");
6441 :
6442 : return 0;
6443 : }
6444 : #endif /* DPLANE_TEST_PROVIDER */
6445 :
6446 : /*
6447 : * Register default kernel provider
6448 : */
6449 1 : static void dplane_provider_init(void)
6450 : {
6451 1 : int ret;
6452 :
6453 1 : ret = dplane_provider_register("Kernel",
6454 : DPLANE_PRIO_KERNEL,
6455 : DPLANE_PROV_FLAGS_DEFAULT, NULL,
6456 : kernel_dplane_process_func,
6457 : NULL,
6458 : NULL, NULL);
6459 :
6460 1 : if (ret != AOK)
6461 0 : zlog_err("Unable to register kernel dplane provider: %d",
6462 : ret);
6463 :
6464 : #ifdef DPLANE_TEST_PROVIDER
6465 : /* Optional test provider ... */
6466 : ret = dplane_provider_register("Test",
6467 : DPLANE_PRIO_PRE_KERNEL,
6468 : DPLANE_PROV_FLAGS_DEFAULT, NULL,
6469 : test_dplane_process_func,
6470 : test_dplane_shutdown_func,
6471 : NULL /* data */, NULL);
6472 :
6473 : if (ret != AOK)
6474 : zlog_err("Unable to register test dplane provider: %d",
6475 : ret);
6476 : #endif /* DPLANE_TEST_PROVIDER */
6477 1 : }
6478 :
6479 : /*
6480 : * Allow zebra code to walk the queue of pending contexts, evaluate each one
6481 : * using a callback function. If the function returns 'true', the context
6482 : * will be dequeued and freed without being processed.
6483 : */
6484 0 : int dplane_clean_ctx_queue(bool (*context_cb)(struct zebra_dplane_ctx *ctx,
6485 : void *arg), void *val)
6486 : {
6487 0 : struct zebra_dplane_ctx *ctx;
6488 0 : struct dplane_ctx_list_head work_list;
6489 :
6490 0 : dplane_ctx_list_init(&work_list);
6491 :
6492 0 : if (context_cb == NULL)
6493 : return AOK;
6494 :
6495 : /* Walk the pending context queue under the dplane lock. */
6496 0 : DPLANE_LOCK();
6497 :
6498 0 : frr_each_safe (dplane_ctx_list, &zdplane_info.dg_update_list, ctx) {
6499 0 : if (context_cb(ctx, val)) {
6500 0 : dplane_ctx_list_del(&zdplane_info.dg_update_list, ctx);
6501 0 : dplane_ctx_list_add_tail(&work_list, ctx);
6502 : }
6503 : }
6504 :
6505 0 : DPLANE_UNLOCK();
6506 :
6507 : /* Now free any contexts selected by the caller, without holding
6508 : * the lock.
6509 : */
6510 0 : while ((ctx = dplane_ctx_list_pop(&work_list)) != NULL)
6511 0 : dplane_ctx_fini(&ctx);
6512 :
6513 : return AOK;
6514 : }
6515 :
6516 : /* Indicates zebra shutdown/exit is in progress. Some operations may be
6517 : * simplified or skipped during shutdown processing.
6518 : */
6519 0 : bool dplane_is_in_shutdown(void)
6520 : {
6521 0 : return zdplane_info.dg_is_shutdown;
6522 : }
6523 :
6524 : /*
6525 : * Enable collection of extra info about interfaces in route updates.
6526 : */
6527 0 : void dplane_enable_intf_extra_info(void)
6528 : {
6529 0 : dplane_collect_extra_intf_info = true;
6530 0 : }
6531 :
6532 : /*
6533 : * Early or pre-shutdown, de-init notification api. This runs pretty
6534 : * early during zebra shutdown, as a signal to stop new work and prepare
6535 : * for updates generated by shutdown/cleanup activity, as zebra tries to
6536 : * remove everything it's responsible for.
6537 : * NB: This runs in the main zebra pthread context.
6538 : */
6539 1 : void zebra_dplane_pre_finish(void)
6540 : {
6541 1 : struct zebra_dplane_provider *prov;
6542 :
6543 1 : if (IS_ZEBRA_DEBUG_DPLANE)
6544 0 : zlog_debug("Zebra dataplane pre-finish called");
6545 :
6546 1 : zdplane_info.dg_is_shutdown = true;
6547 :
6548 : /* Notify provider(s) of pending shutdown. */
6549 4 : frr_each (dplane_prov_list, &zdplane_info.dg_providers, prov) {
6550 1 : if (prov->dp_fini == NULL)
6551 1 : continue;
6552 :
6553 0 : prov->dp_fini(prov, true /* early */);
6554 : }
6555 1 : }
6556 :
6557 : /*
6558 : * Utility to determine whether work remains enqueued within the dplane;
6559 : * used during system shutdown processing.
6560 : */
6561 1 : static bool dplane_work_pending(void)
6562 : {
6563 1 : bool ret = false;
6564 1 : struct zebra_dplane_ctx *ctx;
6565 1 : struct zebra_dplane_provider *prov;
6566 :
6567 : /* TODO -- just checking incoming/pending work for now, must check
6568 : * providers
6569 : */
6570 1 : DPLANE_LOCK();
6571 : {
6572 1 : ctx = dplane_ctx_list_first(&zdplane_info.dg_update_list);
6573 1 : prov = dplane_prov_list_first(&zdplane_info.dg_providers);
6574 : }
6575 1 : DPLANE_UNLOCK();
6576 :
6577 1 : if (ctx != NULL)
6578 : return true;
6579 :
6580 2 : while (prov) {
6581 :
6582 1 : dplane_provider_lock(prov);
6583 :
6584 1 : ctx = dplane_ctx_list_first(&(prov->dp_ctx_in_list));
6585 0 : if (ctx == NULL)
6586 1 : ctx = dplane_ctx_list_first(&(prov->dp_ctx_out_list));
6587 :
6588 1 : dplane_provider_unlock(prov);
6589 :
6590 1 : if (ctx != NULL)
6591 : break;
6592 :
6593 3 : prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov);
6594 : }
6595 :
6596 1 : if (ctx != NULL)
6597 0 : ret = true;
6598 :
6599 : return ret;
6600 : }
6601 :
6602 : /*
6603 : * Shutdown-time intermediate callback, used to determine when all pending
6604 : * in-flight updates are done. If there's still work to do, reschedules itself.
6605 : * If all work is done, schedules an event to the main zebra thread for
6606 : * final zebra shutdown.
6607 : * This runs in the dplane pthread context.
6608 : */
6609 1 : static void dplane_check_shutdown_status(struct thread *event)
6610 : {
6611 1 : struct dplane_zns_info *zi;
6612 :
6613 1 : if (IS_ZEBRA_DEBUG_DPLANE)
6614 0 : zlog_debug("Zebra dataplane shutdown status check called");
6615 :
6616 : /* Remove any zns info entries as we stop the dplane pthread. */
6617 2 : frr_each_safe (zns_info_list, &zdplane_info.dg_zns_list, zi) {
6618 0 : zns_info_list_del(&zdplane_info.dg_zns_list, zi);
6619 :
6620 0 : if (zdplane_info.dg_master) {
6621 0 : THREAD_OFF(zi->t_read);
6622 0 : THREAD_OFF(zi->t_request);
6623 : }
6624 :
6625 0 : XFREE(MTYPE_DP_NS, zi);
6626 : }
6627 :
6628 1 : if (dplane_work_pending()) {
6629 : /* Reschedule dplane check on a short timer */
6630 0 : thread_add_timer_msec(zdplane_info.dg_master,
6631 : dplane_check_shutdown_status,
6632 : NULL, 100,
6633 : &zdplane_info.dg_t_shutdown_check);
6634 :
6635 : /* TODO - give up and stop waiting after a short time? */
6636 :
6637 : } else {
6638 : /* We appear to be done - schedule a final callback event
6639 : * for the zebra main pthread.
6640 : */
6641 1 : thread_add_event(zrouter.master, zebra_finalize, NULL, 0, NULL);
6642 : }
6643 1 : }
6644 :
6645 : /*
6646 : * Shutdown, de-init api. This runs pretty late during shutdown,
6647 : * after zebra has tried to free/remove/uninstall all routes during shutdown.
6648 : * At this point, dplane work may still remain to be done, so we can't just
6649 : * blindly terminate. If there's still work to do, we'll periodically check
6650 : * and when done, we'll enqueue a task to the zebra main thread for final
6651 : * termination processing.
6652 : *
6653 : * NB: This runs in the main zebra thread context.
6654 : */
6655 1 : void zebra_dplane_finish(void)
6656 : {
6657 1 : if (IS_ZEBRA_DEBUG_DPLANE)
6658 0 : zlog_debug("Zebra dataplane fini called");
6659 :
6660 1 : thread_add_event(zdplane_info.dg_master,
6661 : dplane_check_shutdown_status, NULL, 0,
6662 : &zdplane_info.dg_t_shutdown_check);
6663 1 : }
6664 :
6665 : /*
6666 : * Main dataplane pthread event loop. The thread takes new incoming work
6667 : * and offers it to the first provider. It then iterates through the
6668 : * providers, taking complete work from each one and offering it
6669 : * to the next in order. At each step, a limited number of updates are
6670 : * processed during a cycle in order to provide some fairness.
6671 : *
6672 : * This loop through the providers is only run once, so that the dataplane
6673 : * pthread can look for other pending work - such as i/o work on behalf of
6674 : * providers.
6675 : */
6676 8 : static void dplane_thread_loop(struct thread *event)
6677 : {
6678 8 : struct dplane_ctx_list_head work_list;
6679 8 : struct dplane_ctx_list_head error_list;
6680 8 : struct zebra_dplane_provider *prov;
6681 8 : struct zebra_dplane_ctx *ctx;
6682 8 : int limit, counter, error_counter;
6683 8 : uint64_t curr, high;
6684 8 : bool reschedule = false;
6685 :
6686 : /* Capture work limit per cycle */
6687 8 : limit = zdplane_info.dg_updates_per_cycle;
6688 :
6689 : /* Init temporary lists used to move contexts among providers */
6690 8 : dplane_ctx_list_init(&work_list);
6691 8 : dplane_ctx_list_init(&error_list);
6692 :
6693 8 : error_counter = 0;
6694 :
6695 : /* Check for zebra shutdown */
6696 8 : if (!zdplane_info.dg_run)
6697 0 : return;
6698 :
6699 : /* Dequeue some incoming work from zebra (if any) onto the temporary
6700 : * working list.
6701 : */
6702 8 : DPLANE_LOCK();
6703 :
6704 : /* Locate initial registered provider */
6705 8 : prov = dplane_prov_list_first(&zdplane_info.dg_providers);
6706 :
6707 : /* Move new work from incoming list to temp list */
6708 33 : for (counter = 0; counter < limit; counter++) {
6709 33 : ctx = dplane_ctx_list_pop(&zdplane_info.dg_update_list);
6710 33 : if (ctx) {
6711 25 : ctx->zd_provider = prov->dp_id;
6712 :
6713 25 : dplane_ctx_list_add_tail(&work_list, ctx);
6714 : } else {
6715 : break;
6716 : }
6717 : }
6718 :
6719 8 : DPLANE_UNLOCK();
6720 :
6721 8 : atomic_fetch_sub_explicit(&zdplane_info.dg_routes_queued, counter,
6722 : memory_order_relaxed);
6723 :
6724 8 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
6725 0 : zlog_debug("dplane: incoming new work counter: %d", counter);
6726 :
6727 : /* Iterate through the registered providers, offering new incoming
6728 : * work. If the provider has outgoing work in its queue, take that
6729 : * work for the next provider
6730 : */
6731 16 : while (prov) {
6732 :
6733 : /* At each iteration, the temporary work list has 'counter'
6734 : * items.
6735 : */
6736 8 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
6737 0 : zlog_debug("dplane enqueues %d new work to provider '%s'",
6738 : counter, dplane_provider_get_name(prov));
6739 :
6740 : /* Capture current provider id in each context; check for
6741 : * error status.
6742 : */
6743 66 : frr_each_safe (dplane_ctx_list, &work_list, ctx) {
6744 25 : if (dplane_ctx_get_status(ctx) ==
6745 : ZEBRA_DPLANE_REQUEST_SUCCESS) {
6746 25 : ctx->zd_provider = prov->dp_id;
6747 : } else {
6748 : /*
6749 : * TODO -- improve error-handling: recirc
6750 : * errors backwards so that providers can
6751 : * 'undo' their work (if they want to)
6752 : */
6753 :
6754 : /* Move to error list; will be returned
6755 : * zebra main.
6756 : */
6757 0 : dplane_ctx_list_del(&work_list, ctx);
6758 0 : dplane_ctx_list_add_tail(&error_list, ctx);
6759 0 : error_counter++;
6760 : }
6761 : }
6762 :
6763 : /* Enqueue new work to the provider */
6764 8 : dplane_provider_lock(prov);
6765 :
6766 33 : while ((ctx = dplane_ctx_list_pop(&work_list)) != NULL)
6767 58 : dplane_ctx_list_add_tail(&(prov->dp_ctx_in_list), ctx);
6768 :
6769 8 : atomic_fetch_add_explicit(&prov->dp_in_counter, counter,
6770 : memory_order_relaxed);
6771 8 : atomic_fetch_add_explicit(&prov->dp_in_queued, counter,
6772 : memory_order_relaxed);
6773 8 : curr = atomic_load_explicit(&prov->dp_in_queued,
6774 : memory_order_relaxed);
6775 8 : high = atomic_load_explicit(&prov->dp_in_max,
6776 : memory_order_relaxed);
6777 8 : if (curr > high)
6778 2 : atomic_store_explicit(&prov->dp_in_max, curr,
6779 : memory_order_relaxed);
6780 :
6781 8 : dplane_provider_unlock(prov);
6782 :
6783 : /* Reset the temp list (though the 'concat' may have done this
6784 : * already), and the counter
6785 : */
6786 8 : dplane_ctx_list_init(&work_list);
6787 8 : counter = 0;
6788 :
6789 : /* Call into the provider code. Note that this is
6790 : * unconditional: we offer to do work even if we don't enqueue
6791 : * any _new_ work.
6792 : */
6793 8 : (*prov->dp_fp)(prov);
6794 :
6795 : /* Check for zebra shutdown */
6796 8 : if (!zdplane_info.dg_run)
6797 : break;
6798 :
6799 : /* Dequeue completed work from the provider */
6800 8 : dplane_provider_lock(prov);
6801 :
6802 33 : while (counter < limit) {
6803 33 : ctx = dplane_ctx_list_pop(&(prov->dp_ctx_out_list));
6804 33 : if (ctx) {
6805 25 : dplane_ctx_list_add_tail(&work_list, ctx);
6806 25 : counter++;
6807 : } else
6808 : break;
6809 : }
6810 :
6811 8 : dplane_provider_unlock(prov);
6812 :
6813 8 : if (counter >= limit)
6814 0 : reschedule = true;
6815 :
6816 8 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
6817 0 : zlog_debug("dplane dequeues %d completed work from provider %s",
6818 : counter, dplane_provider_get_name(prov));
6819 :
6820 : /* Locate next provider */
6821 24 : prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov);
6822 : }
6823 :
6824 : /*
6825 : * We hit the work limit while processing at least one provider's
6826 : * output queue - ensure we come back and finish it.
6827 : */
6828 8 : if (reschedule)
6829 0 : dplane_provider_work_ready();
6830 :
6831 : /* After all providers have been serviced, enqueue any completed
6832 : * work and any errors back to zebra so it can process the results.
6833 : */
6834 8 : if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
6835 0 : zlog_debug("dplane has %d completed, %d errors, for zebra main",
6836 : counter, error_counter);
6837 :
6838 : /*
6839 : * Hand lists through the api to zebra main,
6840 : * to reduce the number of lock/unlock cycles
6841 : */
6842 :
6843 : /* Call through to zebra main */
6844 8 : (zdplane_info.dg_results_cb)(&error_list);
6845 :
6846 8 : dplane_ctx_list_init(&error_list);
6847 :
6848 : /* Call through to zebra main */
6849 8 : (zdplane_info.dg_results_cb)(&work_list);
6850 :
6851 8 : dplane_ctx_list_init(&work_list);
6852 : }
6853 :
6854 : /*
6855 : * Final phase of shutdown, after all work enqueued to dplane has been
6856 : * processed. This is called from the zebra main pthread context.
6857 : */
6858 1 : void zebra_dplane_shutdown(void)
6859 : {
6860 1 : struct zebra_dplane_provider *dp;
6861 :
6862 1 : if (IS_ZEBRA_DEBUG_DPLANE)
6863 0 : zlog_debug("Zebra dataplane shutdown called");
6864 :
6865 : /* Stop dplane thread, if it's running */
6866 :
6867 1 : zdplane_info.dg_run = false;
6868 :
6869 1 : if (zdplane_info.dg_t_update)
6870 0 : thread_cancel_async(zdplane_info.dg_t_update->master,
6871 : &zdplane_info.dg_t_update, NULL);
6872 :
6873 1 : frr_pthread_stop(zdplane_info.dg_pthread, NULL);
6874 :
6875 : /* Destroy pthread */
6876 1 : frr_pthread_destroy(zdplane_info.dg_pthread);
6877 1 : zdplane_info.dg_pthread = NULL;
6878 1 : zdplane_info.dg_master = NULL;
6879 :
6880 : /* Notify provider(s) of final shutdown.
6881 : * Note that this call is in the main pthread, so providers must
6882 : * be prepared for that.
6883 : */
6884 4 : frr_each (dplane_prov_list, &zdplane_info.dg_providers, dp) {
6885 1 : if (dp->dp_fini == NULL)
6886 1 : continue;
6887 :
6888 0 : dp->dp_fini(dp, false);
6889 : }
6890 :
6891 : /* TODO -- Clean-up provider objects */
6892 :
6893 : /* TODO -- Clean queue(s), free memory */
6894 1 : }
6895 :
6896 : /*
6897 : * Initialize the dataplane module during startup, internal/private version
6898 : */
6899 1 : static void zebra_dplane_init_internal(void)
6900 : {
6901 1 : memset(&zdplane_info, 0, sizeof(zdplane_info));
6902 :
6903 1 : pthread_mutex_init(&zdplane_info.dg_mutex, NULL);
6904 :
6905 1 : dplane_prov_list_init(&zdplane_info.dg_providers);
6906 :
6907 1 : dplane_ctx_list_init(&zdplane_info.dg_update_list);
6908 1 : zns_info_list_init(&zdplane_info.dg_zns_list);
6909 :
6910 1 : zdplane_info.dg_updates_per_cycle = DPLANE_DEFAULT_NEW_WORK;
6911 :
6912 1 : zdplane_info.dg_max_queued_updates = DPLANE_DEFAULT_MAX_QUEUED;
6913 :
6914 : /* Register default kernel 'provider' during init */
6915 1 : dplane_provider_init();
6916 1 : }
6917 :
6918 : /*
6919 : * Start the dataplane pthread. This step needs to be run later than the
6920 : * 'init' step, in case zebra has fork-ed.
6921 : */
6922 1 : void zebra_dplane_start(void)
6923 : {
6924 1 : struct dplane_zns_info *zi;
6925 1 : struct zebra_dplane_provider *prov;
6926 1 : struct frr_pthread_attr pattr = {
6927 1 : .start = frr_pthread_attr_default.start,
6928 1 : .stop = frr_pthread_attr_default.stop
6929 : };
6930 :
6931 : /* Start dataplane pthread */
6932 :
6933 1 : zdplane_info.dg_pthread = frr_pthread_new(&pattr, "Zebra dplane thread",
6934 : "zebra_dplane");
6935 :
6936 1 : zdplane_info.dg_master = zdplane_info.dg_pthread->master;
6937 :
6938 1 : zdplane_info.dg_run = true;
6939 :
6940 : /* Enqueue an initial event for the dataplane pthread */
6941 1 : thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0,
6942 : &zdplane_info.dg_t_update);
6943 :
6944 : /* Enqueue requests and reads if necessary */
6945 4 : frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
6946 : #if defined(HAVE_NETLINK)
6947 1 : thread_add_read(zdplane_info.dg_master, dplane_incoming_read,
6948 : zi, zi->info.sock, &zi->t_read);
6949 1 : dplane_kernel_info_request(zi);
6950 : #endif
6951 : }
6952 :
6953 : /* Call start callbacks for registered providers */
6954 :
6955 1 : DPLANE_LOCK();
6956 1 : prov = dplane_prov_list_first(&zdplane_info.dg_providers);
6957 1 : DPLANE_UNLOCK();
6958 :
6959 1 : while (prov) {
6960 :
6961 1 : if (prov->dp_start)
6962 0 : (prov->dp_start)(prov);
6963 :
6964 : /* Locate next provider */
6965 3 : prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov);
6966 : }
6967 :
6968 1 : frr_pthread_run(zdplane_info.dg_pthread, NULL);
6969 1 : }
6970 :
6971 : /*
6972 : * Initialize the dataplane module at startup; called by zebra rib_init()
6973 : */
6974 1 : void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_list_head *))
6975 : {
6976 1 : zebra_dplane_init_internal();
6977 1 : zdplane_info.dg_results_cb = results_fp;
6978 1 : }
|