back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_dplane.c (source / functions) Hit Total Coverage
Test: test_bgp_minimum_holdtime.py::TestBGPMinimumHoldtime Lines: 653 2649 24.7 %
Date: 2023-02-24 18:37:25 Functions: 101 355 28.5 %

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

Generated by: LCOV version v1.16-topotato