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