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