diff --git a/src/sonic-frr/patch/0009-ignore-route-from-default-table-and-prevent-po.patch b/src/sonic-frr/patch/0009-ignore-route-from-default-table-and-prevent-po.patch new file mode 100644 index 00000000000..3bf41909bd0 --- /dev/null +++ b/src/sonic-frr/patch/0009-ignore-route-from-default-table-and-prevent-po.patch @@ -0,0 +1,74 @@ +From 6e7761fd1e445b4dedecb3b90053fe5687ef285d Mon Sep 17 00:00:00 2001 +From: Vivek Reddy +Date: Fri, 19 May 2023 23:12:45 +0000 +Subject: [PATCH] From 12627632ce98ebb0e64495458d84b296df84af28 Mon Sep 17 + 00:00:00 2001 Subject: [PATCH] zebra: Ignore route from default table and + Prevent possible crashed from use after free + +a) Sonic has a host configuration process that places default routes into +the RT_TABLE_DEFAULT to allow for working without vrf's. Additionally +the sonic fpmsyncd has no idea of actual table ids are and the actual +vrf id's are passed down to it instead. As such the routes in table +RT_TABLE_DEFAULT would be passed down and cause issues in fpmsyncd +let's cut to the chase and stop this from happening. + +Long term this is a real problem in that FRR does allow the thought +of using any of the 4 billion tables available to it for doing routing. +See pbr( tables in the 10k range ), `ip import-table X` and the bgp +route-map command `table X`. For where this approach is going to fall +down. + +b) This patch also prevents the usage of data after it has already +been freed. Zebra on shutdown inititates through the router_shutdown +callback a table cleanup that stores on the zfpm_g->dest_q a list +of rib_dest_t's that needs to be removed from the fpm. This process +at the same time free's the dest->rnode, the dest->rnode->table +and the dest->rnode->info pointers. As such they cannot be used +when the zfpm_g->dest_q wakes up to gather data for sending +down the fpm pipe. Let's transform this problematic usage +of freed data to data we know that has not been freed yet. + +Signed-off-by: Donald Sharp +Signed-off-by: Vivek Reddy +--- + zebra/zebra_fpm_netlink.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c +index 34be9fb39..1339974e1 100644 +--- a/zebra/zebra_fpm_netlink.c ++++ b/zebra/zebra_fpm_netlink.c +@@ -279,17 +279,13 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd, + rib_dest_t *dest, struct route_entry *re) + { + struct nexthop *nexthop; +- struct rib_table_info *table_info = +- rib_table_info(rib_dest_table(dest)); +- struct zebra_vrf *zvrf = table_info->zvrf; + + memset(ri, 0, sizeof(*ri)); + + ri->prefix = rib_dest_prefix(dest); + ri->af = rib_dest_af(dest); + +- if (zvrf && zvrf->zns) +- ri->nlmsg_pid = zvrf->zns->netlink_dplane_out.snl.nl_pid; ++ ri->nlmsg_pid = pid; + + ri->nlmsg_type = cmd; + ri->rtm_table = zvrf_id(rib_dest_vrf(dest)); +@@ -307,6 +303,11 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd, + return 0; + } + ++ if (re->table == RT_TABLE_DEFAULT) { ++ zfpm_debug("%s: Discard RT_TABLE_DEFAULT route", __func__); ++ return 0; ++ } ++ + ri->rtm_protocol = netlink_proto_from_route_type(re->type); + ri->rtm_type = RTN_UNICAST; + ri->metric = &re->metric; +-- +2.17.1 + diff --git a/src/sonic-frr/patch/0009-ignore-route-from-default-table.patch b/src/sonic-frr/patch/0009-ignore-route-from-default-table.patch deleted file mode 100644 index ec41da74dad..00000000000 --- a/src/sonic-frr/patch/0009-ignore-route-from-default-table.patch +++ /dev/null @@ -1,30 +0,0 @@ -From bb3b003840959adf5b5be52e91bc798007c9857a Mon Sep 17 00:00:00 2001 -From: Ying Xie -Date: Thu, 8 Sep 2022 04:20:36 +0000 -Subject: [PATCH] From 776a29e8ab32c1364ee601a8730aabb773b0c86b Mon Sep 17 - 00:00:00 2001 Subject: [PATCH] ignore route from default table - -Signed-off-by: Ying Xie ---- - zebra/zebra_fpm_netlink.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c -index 34be9fb39..d6c875a7e 100644 ---- a/zebra/zebra_fpm_netlink.c -+++ b/zebra/zebra_fpm_netlink.c -@@ -283,6 +283,11 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd, - rib_table_info(rib_dest_table(dest)); - struct zebra_vrf *zvrf = table_info->zvrf; - -+ if (table_info->table_id == RT_TABLE_DEFAULT) { -+ zfpm_debug("%s: Discard default table route", __func__); -+ return 0; -+ } -+ - memset(ri, 0, sizeof(*ri)); - - ri->prefix = rib_dest_prefix(dest); --- -2.17.1 - diff --git a/src/sonic-frr/patch/0013-zebra-fix-use-after-deletion-event-in-freebsd.patch b/src/sonic-frr/patch/0013-zebra-fix-use-after-deletion-event-in-freebsd.patch new file mode 100644 index 00000000000..0b93c52db71 --- /dev/null +++ b/src/sonic-frr/patch/0013-zebra-fix-use-after-deletion-event-in-freebsd.patch @@ -0,0 +1,187 @@ +From ce67e8fd10f0250c187bab529808457c74fc4b0c Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Thu, 24 Mar 2022 20:02:33 -0400 +Subject: [PATCH] zebra: Fix use after deletion event in freebsd + +In the FreeBSD code if you delete the interface +and it has no configuration, the ifp pointer will +be deleted from the system *but* zebra continues +to dereference the just freed pointer. + +==58624== Invalid read of size 1 +==58624== at 0x48539F3: strlcpy (in /usr/local/libexec/valgrind/vgpreload_memcheck-amd64-freebsd.so) +==58624== by 0x2B0565: ifreq_set_name (ioctl.c:48) +==58624== by 0x2B0565: if_get_flags (ioctl.c:416) +==58624== by 0x2B2D9E: ifan_read (kernel_socket.c:455) +==58624== by 0x2B2D9E: kernel_read (kernel_socket.c:1403) +==58624== by 0x499F46E: thread_call (thread.c:2002) +==58624== by 0x495D2B7: frr_run (libfrr.c:1196) +==58624== by 0x2B40B8: main (main.c:471) +==58624== Address 0x6baa7f0 is 64 bytes inside a block of size 432 free'd +==58624== at 0x484ECDC: free (in /usr/local/libexec/valgrind/vgpreload_memcheck-amd64-freebsd.so) +==58624== by 0x4953A64: if_delete (if.c:283) +==58624== by 0x2A93C1: if_delete_update (interface.c:874) +==58624== by 0x2B2DF3: ifan_read (kernel_socket.c:453) +==58624== by 0x2B2DF3: kernel_read (kernel_socket.c:1403) +==58624== by 0x499F46E: thread_call (thread.c:2002) +==58624== by 0x495D2B7: frr_run (libfrr.c:1196) +==58624== by 0x2B40B8: main (main.c:471) +==58624== Block was alloc'd at +==58624== at 0x4851381: calloc (in /usr/local/libexec/valgrind/vgpreload_memcheck-amd64-freebsd.so) +==58624== by 0x496A022: qcalloc (memory.c:116) +==58624== by 0x49546BC: if_new (if.c:164) +==58624== by 0x49546BC: if_create_name (if.c:218) +==58624== by 0x49546BC: if_get_by_name (if.c:603) +==58624== by 0x2B1295: ifm_read (kernel_socket.c:628) +==58624== by 0x2A7FB6: interface_list (if_sysctl.c:129) +==58624== by 0x2E99C8: zebra_ns_enable (zebra_ns.c:127) +==58624== by 0x2E99C8: zebra_ns_init (zebra_ns.c:214) +==58624== by 0x2B3FF2: main (main.c:401) +==58624== + +Zebra needs to pass back whether or not the ifp pointer +was freed when if_delete_update is called and it should +then check in ifan_read as well as ifm_read that the +ifp pointer is still valid for use. + +Signed-off-by: Donald Sharp +(cherry picked from commit d0438da6b09333d2b77a9eac2e9fffbbae6e603b) +--- + zebra/if_netlink.c | 4 ++-- + zebra/interface.c | 5 +++-- + zebra/interface.h | 2 +- + zebra/kernel_socket.c | 27 +++++++++++++++------------ + zebra/zebra_netns_notify.c | 2 +- + 5 files changed, 22 insertions(+), 18 deletions(-) + +diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c +index 141e4074d56..5a2f6d33b18 100644 +--- a/zebra/if_netlink.c ++++ b/zebra/if_netlink.c +@@ -101,7 +101,7 @@ static void set_ifindex(struct interface *ifp, ifindex_t ifi_index, + EC_LIB_INTERFACE, + "interface rename detected on up interface: index %d was renamed from %s to %s, results are uncertain!", + ifi_index, oifp->name, ifp->name); +- if_delete_update(oifp); ++ if_delete_update(&oifp); + } + } + if_set_index(ifp, ifi_index); +@@ -2031,7 +2031,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) + else if (IS_ZEBRA_IF_VXLAN(ifp)) + zebra_l2_vxlanif_del(ifp); + +- if_delete_update(ifp); ++ if_delete_update(&ifp); + + /* If VRF, delete the VRF structure itself. */ + if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) +diff --git a/zebra/interface.c b/zebra/interface.c +index e4e80ec4e93..cb5dc83685c 100644 +--- a/zebra/interface.c ++++ b/zebra/interface.c +@@ -769,9 +769,10 @@ static void if_delete_connected(struct interface *ifp) + } + + /* Handle an interface delete event */ +-void if_delete_update(struct interface *ifp) ++void if_delete_update(struct interface **pifp) + { + struct zebra_if *zif; ++ struct interface *ifp = *pifp; + + if (if_is_up(ifp)) { + flog_err( +@@ -834,7 +835,7 @@ void if_delete_update(struct interface *ifp) + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("interface %s is being deleted from the system", + ifp->name); +- if_delete(&ifp); ++ if_delete(pifp); + } + } + +diff --git a/zebra/interface.h b/zebra/interface.h +index 771398b5476..571831f87da 100644 +--- a/zebra/interface.h ++++ b/zebra/interface.h +@@ -474,7 +474,7 @@ extern void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp, + struct in6_addr *address, + int add); + extern void if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(struct interface *ifp); +-extern void if_delete_update(struct interface *ifp); ++extern void if_delete_update(struct interface **ifp); + extern void if_add_update(struct interface *ifp); + extern void if_up(struct interface *); + extern void if_down(struct interface *); +diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c +index 573db4ae5d7..d6c43dbcb06 100644 +--- a/zebra/kernel_socket.c ++++ b/zebra/kernel_socket.c +@@ -450,12 +450,13 @@ static int ifan_read(struct if_announcemsghdr *ifan) + if_get_metric(ifp); + if_add_update(ifp); + } else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE) +- if_delete_update(ifp); +- +- if_get_flags(ifp); +- if_get_mtu(ifp); +- if_get_metric(ifp); ++ if_delete_update(&ifp); + ++ if (ifp) { ++ if_get_flags(ifp); ++ if_get_mtu(ifp); ++ if_get_metric(ifp); ++ } + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: interface %s index %d", __func__, + ifan->ifan_name, ifan->ifan_index); +@@ -722,10 +723,10 @@ int ifm_read(struct if_msghdr *ifm) + * will still behave correctly if run on a platform + * without + */ +- if_delete_update(ifp); ++ if_delete_update(&ifp); + } + #endif /* RTM_IFANNOUNCE */ +- if (if_is_up(ifp)) { ++ if (ifp && if_is_up(ifp)) { + #if defined(__bsdi__) + if_kvm_get_mtu(ifp); + #else +@@ -735,14 +736,16 @@ int ifm_read(struct if_msghdr *ifm) + } + } + ++ if (ifp) { + #ifdef HAVE_NET_RT_IFLIST +- ifp->stats = ifm->ifm_data; ++ ifp->stats = ifm->ifm_data; + #endif /* HAVE_NET_RT_IFLIST */ +- ifp->speed = ifm->ifm_data.ifi_baudrate / 1000000; ++ ifp->speed = ifm->ifm_data.ifi_baudrate / 1000000; + +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug("%s: interface %s index %d", __func__, ifp->name, +- ifp->ifindex); ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug("%s: interface %s index %d", __func__, ++ ifp->name, ifp->ifindex); ++ } + + return 0; + } +diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c +index 8cc7724f053..155079cfb41 100644 +--- a/zebra/zebra_netns_notify.c ++++ b/zebra/zebra_netns_notify.c +@@ -179,7 +179,7 @@ static int zebra_ns_delete(char *name) + } + + UNSET_FLAG(ifp->flags, IFF_UP); +- if_delete_update(ifp); ++ if_delete_update(&ifp); + } + + ns = (struct ns *)vrf->ns_ctxt; diff --git a/src/sonic-frr/patch/0014-zebra-Rename-vrf_lookup_by_tableid-to-zebra_vrf_lookup.patch b/src/sonic-frr/patch/0014-zebra-Rename-vrf_lookup_by_tableid-to-zebra_vrf_lookup.patch new file mode 100644 index 00000000000..c3973409124 --- /dev/null +++ b/src/sonic-frr/patch/0014-zebra-Rename-vrf_lookup_by_tableid-to-zebra_vrf_lookup.patch @@ -0,0 +1,151 @@ +From b0c68c92bb256a4d47644bcd734f9dc9e5f53567 Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Wed, 26 Apr 2023 23:25:27 -0400 +Subject: [PATCH] zebra: Rename vrf_lookup_by_tableid to zebra_vrf_lookup.. + +Rename the vrf_lookup_by_id function to zebra_vrf_lookup_by_id +and move to zebra_vrf.c where it nominally belongs, as that +we need zebra specific data to find this vrf_id and as such +it does not belong in vrf.c + +Signed-off-by: Donald Sharp +--- + zebra/if_netlink.c | 3 ++- + zebra/rt_netlink.c | 31 ++----------------------------- + zebra/rt_netlink.h | 1 - + zebra/zebra_vrf.c | 27 +++++++++++++++++++++++++++ + zebra/zebra_vrf.h | 1 + + 5 files changed, 32 insertions(+), 31 deletions(-) + +diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c +index 5a2f6d33b18..b3d74a2e462 100644 +--- a/zebra/if_netlink.c ++++ b/zebra/if_netlink.c +@@ -339,7 +339,8 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb, + if (!vrf_lookup_by_id((vrf_id_t)ifi->ifi_index)) { + vrf_id_t exist_id; + +- exist_id = vrf_lookup_by_table(nl_table_id, ns_id); ++ exist_id = ++ zebra_vrf_lookup_by_table(nl_table_id, ns_id); + if (exist_id != VRF_DEFAULT) { + vrf = vrf_lookup_by_id(exist_id); + +diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c +index 24c01b7f518..e4c1393bd19 100644 +--- a/zebra/rt_netlink.c ++++ b/zebra/rt_netlink.c +@@ -361,33 +361,6 @@ static inline int proto2zebra(int proto, int family, bool is_nexthop) + return proto; + } + +-/* +-Pending: create an efficient table_id (in a tree/hash) based lookup) +- */ +-vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id) +-{ +- struct vrf *vrf; +- struct zebra_vrf *zvrf; +- +- RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { +- zvrf = vrf->info; +- if (zvrf == NULL) +- continue; +- /* case vrf with netns : match the netnsid */ +- if (vrf_is_backend_netns()) { +- if (ns_id == zvrf_id(zvrf)) +- return zvrf_id(zvrf); +- } else { +- /* VRF is VRF_BACKEND_VRF_LITE */ +- if (zvrf->table_id != table_id) +- continue; +- return zvrf_id(zvrf); +- } +- } +- +- return VRF_DEFAULT; +-} +- + /** + * @parse_encap_mpls() - Parses encapsulated mpls attributes + * @tb: Pointer to rtattr to look for nested items in. +@@ -761,7 +734,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, + table = rtm->rtm_table; + + /* Map to VRF */ +- vrf_id = vrf_lookup_by_table(table, ns_id); ++ vrf_id = zebra_vrf_lookup_by_table(table, ns_id); + if (vrf_id == VRF_DEFAULT) { + if (!is_zebra_valid_kernel_table(table) + && !is_zebra_main_routing_table(table)) +@@ -1032,7 +1005,7 @@ static int netlink_route_change_read_multicast(struct nlmsghdr *h, + else + table = rtm->rtm_table; + +- vrf = vrf_lookup_by_table(table, ns_id); ++ vrf = zebra_vrf_lookup_by_table(table, ns_id); + + if (tb[RTA_IIF]) + iif = *(int *)RTA_DATA(tb[RTA_IIF]); +diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h +index 93c06e555b0..51c13574c70 100644 +--- a/zebra/rt_netlink.h ++++ b/zebra/rt_netlink.h +@@ -103,7 +103,6 @@ extern int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, + uint16_t vid); + extern int netlink_neigh_read_specific_ip(const struct ipaddr *ip, + struct interface *vlan_if); +-extern vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id); + + struct nl_batch; + extern enum netlink_msg_status +diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c +index f88a65d9520..5fee5a2db91 100644 +--- a/zebra/zebra_vrf.c ++++ b/zebra/zebra_vrf.c +@@ -393,6 +393,33 @@ struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf) + return zvrf; + } + ++/* ++Pending: create an efficient table_id (in a tree/hash) based lookup) ++ */ ++vrf_id_t zebra_vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id) ++{ ++ struct vrf *vrf; ++ struct zebra_vrf *zvrf; ++ ++ RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { ++ zvrf = vrf->info; ++ if (zvrf == NULL) ++ continue; ++ /* case vrf with netns : match the netnsid */ ++ if (vrf_is_backend_netns()) { ++ if (ns_id == zvrf_id(zvrf)) ++ return zvrf_id(zvrf); ++ } else { ++ /* VRF is VRF_BACKEND_VRF_LITE */ ++ if (zvrf->table_id != table_id) ++ continue; ++ return zvrf_id(zvrf); ++ } ++ } ++ ++ return VRF_DEFAULT; ++} ++ + /* Lookup VRF by identifier. */ + struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id) + { +diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h +index a24a008b761..031b80ebb0f 100644 +--- a/zebra/zebra_vrf.h ++++ b/zebra/zebra_vrf.h +@@ -257,6 +257,7 @@ extern struct route_table *zebra_vrf_get_table_with_table_id(afi_t afi, + extern void zebra_vrf_update_all(struct zserv *client); + extern struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id); + extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *); ++extern vrf_id_t zebra_vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id); + extern struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf); + extern struct route_table *zebra_vrf_table(afi_t, safi_t, vrf_id_t); + diff --git a/src/sonic-frr/patch/0015-zebra-Move-protodown_r_bit-to-a-better-spot.patch b/src/sonic-frr/patch/0015-zebra-Move-protodown_r_bit-to-a-better-spot.patch new file mode 100644 index 00000000000..e52eb0b0ccc --- /dev/null +++ b/src/sonic-frr/patch/0015-zebra-Move-protodown_r_bit-to-a-better-spot.patch @@ -0,0 +1,73 @@ +From 4f10f4df9635ed9afb0456f71213970c7e5fb5b8 Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Thu, 27 Apr 2023 07:37:58 -0400 +Subject: [PATCH] zebra: Move protodown_r_bit to a better spot + +Since we are moving some code handling out of the dataplane +and into zebra proper, lets move the protodown r bit as well. + +Signed-off-by: Donald Sharp +--- + zebra/zebra_router.c | 2 ++ + zebra/zebra_router.h | 28 ++++++++++++++++++++++++++++ + 2 files changed, 30 insertions(+) + +diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c +index 92a3b9424b3..ce0d9fc81a4 100644 +--- a/zebra/zebra_router.c ++++ b/zebra/zebra_router.c +@@ -273,6 +273,8 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) + { + zrouter.sequence_num = 0; + ++ zrouter.protodown_r_bit = FRR_PROTODOWN_REASON_DEFAULT_BIT; ++ + zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS; + + zebra_vxlan_init(); +diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h +index c0eab9cd6eb..b71fe757b89 100644 +--- a/zebra/zebra_router.h ++++ b/zebra/zebra_router.h +@@ -209,6 +209,8 @@ struct zebra_router { + */ + bool asic_offloaded; + bool notify_on_ack; ++ ++ uint8_t protodown_r_bit; + }; + + #define GRACEFUL_RESTART_TIME 60 +@@ -257,6 +259,32 @@ extern enum multicast_mode multicast_mode_ipv4_get(void); + + extern bool zebra_router_notify_on_ack(void); + ++#define FRR_PROTODOWN_REASON_DEFAULT_BIT 7 ++/* Protodown bit setter/getter ++ * ++ * Allow users to change the bit if it conflicts with another ++ * on their system. ++ */ ++static inline void if_netlink_set_frr_protodown_r_bit(uint8_t bit) ++{ ++ zrouter.protodown_r_bit = bit; ++} ++ ++static inline void if_netlink_unset_frr_protodown_r_bit(void) ++{ ++ zrouter.protodown_r_bit = FRR_PROTODOWN_REASON_DEFAULT_BIT; ++} ++ ++static inline bool if_netlink_frr_protodown_r_bit_is_set(void) ++{ ++ return (zrouter.protodown_r_bit != FRR_PROTODOWN_REASON_DEFAULT_BIT); ++} ++ ++static inline uint8_t if_netlink_get_frr_protodown_r_bit(void) ++{ ++ return zrouter.protodown_r_bit; ++} ++ + /* zebra_northbound.c */ + extern const struct frr_yang_module_info frr_zebra_info; + diff --git a/src/sonic-frr/patch/0016-zebra-Remove-unused-add-variable.patch b/src/sonic-frr/patch/0016-zebra-Remove-unused-add-variable.patch new file mode 100644 index 00000000000..ba3c0c50a58 --- /dev/null +++ b/src/sonic-frr/patch/0016-zebra-Remove-unused-add-variable.patch @@ -0,0 +1,55 @@ +From 0416333293fcfc23cad765c98fedb1f2c7aa141a Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Sat, 15 Apr 2023 08:04:51 -0400 +Subject: [PATCH] zebra: Remove unused add variable + +Function was not using the add variable. Remove it. + +Signed-off-by: Donald Sharp +--- + zebra/if_netlink.c | 2 +- + zebra/zebra_l2.c | 3 +-- + zebra/zebra_l2.h | 3 +-- + 3 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c +index b3d74a2e462..f0f3c58878f 100644 +--- a/zebra/if_netlink.c ++++ b/zebra/if_netlink.c +@@ -668,7 +668,7 @@ static void netlink_interface_update_l2info(struct interface *ifp, + struct zebra_l2info_bridge bridge_info; + + netlink_extract_bridge_info(link_data, &bridge_info); +- zebra_l2_bridge_add_update(ifp, &bridge_info, add); ++ zebra_l2_bridge_add_update(ifp, &bridge_info); + } else if (IS_ZEBRA_IF_VLAN(ifp)) { + struct zebra_l2info_vlan vlan_info; + +diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c +index 8a9f3dffe36..07bbc6e3bc4 100644 +--- a/zebra/zebra_l2.c ++++ b/zebra/zebra_l2.c +@@ -258,8 +258,7 @@ void zebra_l2if_update_bond(struct interface *ifp, bool add) + * map slaves (if any) to the bridge. + */ + void zebra_l2_bridge_add_update(struct interface *ifp, +- struct zebra_l2info_bridge *bridge_info, +- int add) ++ struct zebra_l2info_bridge *bridge_info) + { + struct zebra_if *zif; + +diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h +index 98744f3c1fb..48b022311f5 100644 +--- a/zebra/zebra_l2.h ++++ b/zebra/zebra_l2.h +@@ -108,8 +108,7 @@ extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave, + extern void + zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave); + extern void zebra_l2_bridge_add_update(struct interface *ifp, +- struct zebra_l2info_bridge *bridge_info, +- int add); ++ struct zebra_l2info_bridge *bridge_info); + extern void zebra_l2_bridge_del(struct interface *ifp); + extern void zebra_l2_vlanif_update(struct interface *ifp, + struct zebra_l2info_vlan *vlan_info); \ No newline at end of file diff --git a/src/sonic-frr/patch/0017-zebra-Remove-duplicate-function-for-netlink-interface.patch b/src/sonic-frr/patch/0017-zebra-Remove-duplicate-function-for-netlink-interface.patch new file mode 100644 index 00000000000..b5dc425a90b --- /dev/null +++ b/src/sonic-frr/patch/0017-zebra-Remove-duplicate-function-for-netlink-interface.patch @@ -0,0 +1,266 @@ +From 9bfcf42cda4b822034c5fb763bc4e51ef1d82019 Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Thu, 13 Apr 2023 16:43:27 -0400 +Subject: [PATCH] zebra: Remove duplicate function for netlink interface + changes + +Turns out FRR has 2 functions one specifically for startup +and one for normal day to day operations. There were only +a couple of minor differences from what I could tell, and +where they were different the after startup functionality should +have been updated too. I cannot figure out why we have 2. + +Non-startup handling of bonds appears to be incorrect +so let's fix that. Additionally the speed was not +properly being set in non-startup situations. + +Signed-off-by: Donald Sharp +--- + zebra/if_netlink.c | 192 +++++---------------------------------------- + 1 file changed, 19 insertions(+), 173 deletions(-) + +diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c +index f0f3c58878f..eb113797101 100644 +--- a/zebra/if_netlink.c ++++ b/zebra/if_netlink.c +@@ -858,176 +858,6 @@ static uint8_t netlink_parse_lacp_bypass(struct rtattr **linkinfo) + return bypass; + } + +-/* +- * Called from interface_lookup_netlink(). This function is only used +- * during bootstrap. +- */ +-static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) +-{ +- int len; +- struct ifinfomsg *ifi; +- struct rtattr *tb[IFLA_MAX + 1]; +- struct rtattr *linkinfo[IFLA_MAX + 1]; +- struct interface *ifp; +- char *name = NULL; +- char *kind = NULL; +- char *desc = NULL; +- char *slave_kind = NULL; +- struct zebra_ns *zns = NULL; +- vrf_id_t vrf_id = VRF_DEFAULT; +- enum zebra_iftype zif_type = ZEBRA_IF_OTHER; +- enum zebra_slave_iftype zif_slave_type = ZEBRA_IF_SLAVE_NONE; +- ifindex_t bridge_ifindex = IFINDEX_INTERNAL; +- ifindex_t link_ifindex = IFINDEX_INTERNAL; +- ifindex_t bond_ifindex = IFINDEX_INTERNAL; +- struct zebra_if *zif; +- ns_id_t link_nsid = ns_id; +- uint8_t bypass = 0; +- +- zns = zebra_ns_lookup(ns_id); +- ifi = NLMSG_DATA(h); +- +- if (h->nlmsg_type != RTM_NEWLINK) +- return 0; +- +- len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg)); +- if (len < 0) { +- zlog_err( +- "%s: Message received from netlink is of a broken size: %d %zu", +- __func__, h->nlmsg_len, +- (size_t)NLMSG_LENGTH(sizeof(struct ifinfomsg))); +- return -1; +- } +- +- /* We are interested in some AF_BRIDGE notifications. */ +- if (ifi->ifi_family == AF_BRIDGE) +- return netlink_bridge_interface(h, len, ns_id, startup); +- +- /* Looking up interface name. */ +- memset(linkinfo, 0, sizeof(linkinfo)); +- netlink_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); +- +- /* check for wireless messages to ignore */ +- if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) { +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug("%s: ignoring IFLA_WIRELESS message", +- __func__); +- return 0; +- } +- +- if (tb[IFLA_IFNAME] == NULL) +- return -1; +- name = (char *)RTA_DATA(tb[IFLA_IFNAME]); +- +- if (tb[IFLA_IFALIAS]) +- desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]); +- +- if (tb[IFLA_LINKINFO]) { +- netlink_parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, +- tb[IFLA_LINKINFO]); +- +- if (linkinfo[IFLA_INFO_KIND]) +- kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]); +- +- if (linkinfo[IFLA_INFO_SLAVE_KIND]) +- slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]); +- +- if ((slave_kind != NULL) && strcmp(slave_kind, "bond") == 0) +- netlink_determine_zebra_iftype("bond_slave", &zif_type); +- else +- netlink_determine_zebra_iftype(kind, &zif_type); +- } +- +- /* If VRF, create the VRF structure itself. */ +- if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) { +- netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); +- vrf_id = (vrf_id_t)ifi->ifi_index; +- } +- +- if (tb[IFLA_MASTER]) { +- if (slave_kind && (strcmp(slave_kind, "vrf") == 0) +- && !vrf_is_backend_netns()) { +- zif_slave_type = ZEBRA_IF_SLAVE_VRF; +- vrf_id = *(uint32_t *)RTA_DATA(tb[IFLA_MASTER]); +- } else if (slave_kind && (strcmp(slave_kind, "bridge") == 0)) { +- zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE; +- bridge_ifindex = +- *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]); +- } else if (slave_kind && (strcmp(slave_kind, "bond") == 0)) { +- zif_slave_type = ZEBRA_IF_SLAVE_BOND; +- bond_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]); +- bypass = netlink_parse_lacp_bypass(linkinfo); +- } else +- zif_slave_type = ZEBRA_IF_SLAVE_OTHER; +- } +- if (vrf_is_backend_netns()) +- vrf_id = (vrf_id_t)ns_id; +- +- /* If linking to another interface, note it. */ +- if (tb[IFLA_LINK]) +- link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]); +- +- if (tb[IFLA_LINK_NETNSID]) { +- link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]); +- link_nsid = ns_id_get_absolute(ns_id, link_nsid); +- } +- +- ifp = if_get_by_name(name, vrf_id, NULL); +- set_ifindex(ifp, ifi->ifi_index, zns); /* add it to ns struct */ +- +- ifp->flags = ifi->ifi_flags & 0x0000fffff; +- ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]); +- ifp->metric = 0; +- ifp->speed = get_iflink_speed(ifp, NULL); +- ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; +- +- /* Set zebra interface type */ +- zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); +- if (IS_ZEBRA_IF_VRF(ifp)) +- SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); +- +- /* +- * Just set the @link/lower-device ifindex. During nldump interfaces are +- * not ordered in any fashion so we may end up getting upper devices +- * before lower devices. We will setup the real linkage once the dump +- * is complete. +- */ +- zif = (struct zebra_if *)ifp->info; +- zif->link_ifindex = link_ifindex; +- +- if (desc) { +- XFREE(MTYPE_TMP, zif->desc); +- zif->desc = XSTRDUP(MTYPE_TMP, desc); +- } +- +- /* Hardware type and address. */ +- ifp->ll_type = netlink_to_zebra_link_type(ifi->ifi_type); +- netlink_interface_update_hw_addr(tb, ifp); +- +- if_add_update(ifp); +- +- /* Extract and save L2 interface information, take additional actions. +- */ +- netlink_interface_update_l2info(ifp, linkinfo[IFLA_INFO_DATA], +- 1, link_nsid); +- if (IS_ZEBRA_IF_BOND(ifp)) +- zebra_l2if_update_bond(ifp, true); +- if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) +- zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id, +- ZEBRA_BRIDGE_NO_ACTION); +- else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) +- zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); +- +- if (tb[IFLA_PROTO_DOWN]) { +- uint8_t protodown; +- +- protodown = *(uint8_t *)RTA_DATA(tb[IFLA_PROTO_DOWN]); +- netlink_proc_dplane_if_protodown(zif, !!protodown); +- } +- +- return 0; +-} +- + /* Request for specific interface or address information from the kernel */ + static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family, + int type, uint32_t filter_mask) +@@ -1080,7 +910,7 @@ int interface_lookup_netlink(struct zebra_ns *zns) + ret = netlink_request_intf_addr(netlink_cmd, AF_PACKET, RTM_GETLINK, 0); + if (ret < 0) + return ret; +- ret = netlink_parse_info(netlink_interface, netlink_cmd, &dp_info, 0, ++ ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, + true); + if (ret < 0) + return ret; +@@ -1090,7 +920,7 @@ int interface_lookup_netlink(struct zebra_ns *zns) + RTEXT_FILTER_BRVLAN); + if (ret < 0) + return ret; +- ret = netlink_parse_info(netlink_interface, netlink_cmd, &dp_info, 0, ++ ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, + true); + if (ret < 0) + return ret; +@@ -1747,7 +1577,10 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) + if (linkinfo[IFLA_INFO_SLAVE_KIND]) + slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]); + +- netlink_determine_zebra_iftype(kind, &zif_type); ++ if ((slave_kind != NULL) && strcmp(slave_kind, "bond") == 0) ++ netlink_determine_zebra_iftype("bond_slave", &zif_type); ++ else ++ netlink_determine_zebra_iftype(kind, &zif_type); + } + + /* If linking to another interface, note it. */ +@@ -1824,6 +1657,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) + } + ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); + ifp->metric = 0; ++ ifp->speed = get_iflink_speed(ifp, NULL); + ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; + + /* Set interface type */ +@@ -1835,6 +1669,16 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) + /* Update link. */ + zebra_if_update_link(ifp, link_ifindex, ns_id); + ++ /* ++ * Just set the @link/lower-device ifindex. During ++ * nldump interfaces are not ordered in any fashion so ++ * we may end up getting upper devices before lower ++ * devices. We will setup the real linkage once the dump ++ * is complete. ++ */ ++ zif = (struct zebra_if *)ifp->info; ++ zif->link_ifindex = link_ifindex; ++ + ifp->ll_type = + netlink_to_zebra_link_type(ifi->ifi_type); + netlink_interface_update_hw_addr(tb, ifp); +@@ -1847,6 +1691,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) + netlink_interface_update_l2info( + ifp, linkinfo[IFLA_INFO_DATA], + 1, link_nsid); ++ if (IS_ZEBRA_IF_BOND(ifp)) ++ zebra_l2if_update_bond(ifp, true); + if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) + zebra_l2if_update_bridge_slave( + ifp, bridge_ifindex, ns_id, diff --git a/src/sonic-frr/patch/0018-zebra-Add-code-to-get-set-interface-to-pass-up-from-dplane.patch b/src/sonic-frr/patch/0018-zebra-Add-code-to-get-set-interface-to-pass-up-from-dplane.patch new file mode 100644 index 00000000000..57bf8adbc7f --- /dev/null +++ b/src/sonic-frr/patch/0018-zebra-Add-code-to-get-set-interface-to-pass-up-from-dplane.patch @@ -0,0 +1,1295 @@ +From d4d825f933080d105a5b524e952bdcd9bd5f4cae Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Thu, 20 Apr 2023 08:51:42 -0400 +Subject: [PATCH] zebra: Add code to get/set interface to pass up from dplane + +1) Add a bunch of get/set functions and associated data +structure in zebra_dplane to allow the setting and retrieval +of interface netlink data up into the master pthread. + +2) Add a bit of code to breakup startup into stages. This is +because FRR currently has a mix of dplane and non dplane interactions +and the code needs to be paused before continuing on. + +Signed-off-by: Donald Sharp +--- + zebra/dplane_fpm_nl.c | 1 + + zebra/if_netlink.h | 4 + + zebra/interface.c | 128 +++++++-- + zebra/interface.h | 5 +- + zebra/kernel_netlink.c | 4 + + zebra/kernel_socket.c | 24 ++ + zebra/rt_netlink.c | 4 + + zebra/zebra_dplane.c | 527 ++++++++++++++++++++++++++++++++++++- + zebra/zebra_dplane.h | 121 +++++++++ + zebra/zebra_mpls.c | 4 + + zebra/zebra_mpls_openbsd.c | 111 ++++++++ + zebra/zebra_nhg.c | 4 + + zebra/zebra_rib.c | 10 +- + zebra/zebra_script.c | 4 + + 14 files changed, 919 insertions(+), 32 deletions(-) + +diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c +index 3b02128c900..b08b1e80dc0 100644 +--- a/zebra/dplane_fpm_nl.c ++++ b/zebra/dplane_fpm_nl.c +@@ -800,6 +800,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) + case DPLANE_OP_ROUTE_NOTIFY: + case DPLANE_OP_LSP_NOTIFY: + case DPLANE_OP_NONE: ++ case DPLANE_OP_STARTUP_STAGE: + break; + + default: +diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h +index a1ce7af8c78..78f7e3fd95b 100644 +--- a/zebra/if_netlink.h ++++ b/zebra/if_netlink.h +@@ -40,6 +40,10 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, + extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); + extern int interface_lookup_netlink(struct zebra_ns *zns); + ++extern ssize_t netlink_intf_msg_encode(uint16_t cmd, ++ const struct zebra_dplane_ctx *ctx, ++ void *buf, size_t buflen); ++ + extern enum netlink_msg_status + netlink_put_gre_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); + +diff --git a/zebra/interface.c b/zebra/interface.c +index cb5dc83685c..1ef1c843150 100644 +--- a/zebra/interface.c ++++ b/zebra/interface.c +@@ -1213,44 +1213,21 @@ void zebra_if_set_protodown(struct interface *ifp, bool down) + * This runs in the main pthread, using the info in the context object to + * modify an interface. + */ +-void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx) ++void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx, ++ struct interface *ifp) + { +- struct interface *ifp; + uint8_t flags = 0; + const char *label = NULL; +- ns_id_t ns_id; +- struct zebra_ns *zns; + uint32_t metric = METRIC_MAX; +- ifindex_t ifindex; + const struct prefix *addr, *dest = NULL; + enum dplane_op_e op; + + op = dplane_ctx_get_op(ctx); +- ns_id = dplane_ctx_get_ns_id(ctx); +- +- zns = zebra_ns_lookup(ns_id); +- if (zns == NULL) { +- /* No ns - deleted maybe? */ +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug("%s: can't find zns id %u", __func__, ns_id); +- goto done; +- } +- +- ifindex = dplane_ctx_get_ifindex(ctx); +- +- ifp = if_lookup_by_index_per_ns(zns, ifindex); +- if (ifp == NULL) { +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug("%s: can't find ifp at nsid %u index %d", +- __func__, ns_id, ifindex); +- goto done; +- } +- + addr = dplane_ctx_get_intf_addr(ctx); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s: ifindex %u, addr %pFX", __func__, +- dplane_op2str(op), ifindex, addr); ++ dplane_op2str(op), ifp->ifindex, addr); + + /* Is there a peer or broadcast address? */ + dest = dplane_ctx_get_intf_dest(ctx); +@@ -1305,10 +1282,103 @@ void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx) + */ + if (op != DPLANE_OP_INTF_ADDR_ADD) + rib_update(RIB_UPDATE_KERNEL); ++} ++ ++void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) ++{ ++ struct zebra_ns *zns; ++ struct interface *ifp; ++ ns_id_t ns_id; ++ enum dplane_op_e op; ++ enum zebra_dplane_result dp_res; ++ ifindex_t ifindex; ++ ++ ns_id = dplane_ctx_get_ns_id(ctx); ++ dp_res = dplane_ctx_get_status(ctx); ++ op = dplane_ctx_get_op(ctx); ++ ifindex = dplane_ctx_get_ifindex(ctx); ++ ++ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug("Intf dplane ctx %p, op %s, ifindex (%u), result %s", ++ ctx, dplane_op2str(op), ifindex, ++ dplane_res2str(dp_res)); ++ ++ zns = zebra_ns_lookup(ns_id); ++ if (zns == NULL) { ++ /* No ns - deleted maybe? */ ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug("%s: can't find zns id %u", __func__, ns_id); + +-done: +- /* We're responsible for the ctx object */ +- dplane_ctx_fini(&ctx); ++ return; ++ } ++ ++ ifp = if_lookup_by_index_per_ns(zns, ifindex); ++ if (ifp == NULL) { ++ if (ifindex != -1 && ifindex != -2) { ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "%s: can't find ifp at nsid %u index %d", ++ __func__, ns_id, ifindex); ++ ++ return; ++ } ++ } ++ ++ switch (op) { ++ case DPLANE_OP_INTF_ADDR_ADD: ++ case DPLANE_OP_INTF_ADDR_DEL: ++ zebra_if_addr_update_ctx(ctx, ifp); ++ break; ++ ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ break; ++ ++ ++ case DPLANE_OP_ROUTE_INSTALL: ++ case DPLANE_OP_ROUTE_UPDATE: ++ case DPLANE_OP_ROUTE_DELETE: ++ case DPLANE_OP_NH_DELETE: ++ case DPLANE_OP_NH_INSTALL: ++ case DPLANE_OP_NH_UPDATE: ++ case DPLANE_OP_ROUTE_NOTIFY: ++ case DPLANE_OP_LSP_INSTALL: ++ case DPLANE_OP_LSP_UPDATE: ++ case DPLANE_OP_LSP_DELETE: ++ case DPLANE_OP_LSP_NOTIFY: ++ case DPLANE_OP_PW_INSTALL: ++ case DPLANE_OP_PW_UNINSTALL: ++ case DPLANE_OP_SYS_ROUTE_ADD: ++ case DPLANE_OP_SYS_ROUTE_DELETE: ++ case DPLANE_OP_ADDR_INSTALL: ++ case DPLANE_OP_ADDR_UNINSTALL: ++ case DPLANE_OP_MAC_INSTALL: ++ case DPLANE_OP_MAC_DELETE: ++ case DPLANE_OP_NEIGH_INSTALL: ++ case DPLANE_OP_NEIGH_UPDATE: ++ case DPLANE_OP_NEIGH_DELETE: ++ case DPLANE_OP_NEIGH_IP_INSTALL: ++ case DPLANE_OP_NEIGH_IP_DELETE: ++ case DPLANE_OP_VTEP_ADD: ++ case DPLANE_OP_VTEP_DELETE: ++ case DPLANE_OP_RULE_ADD: ++ case DPLANE_OP_RULE_DELETE: ++ case DPLANE_OP_RULE_UPDATE: ++ case DPLANE_OP_NEIGH_DISCOVER: ++ case DPLANE_OP_BR_PORT_UPDATE: ++ case DPLANE_OP_NONE: ++ case DPLANE_OP_IPTABLE_ADD: ++ case DPLANE_OP_IPTABLE_DELETE: ++ case DPLANE_OP_IPSET_ADD: ++ case DPLANE_OP_IPSET_DELETE: ++ case DPLANE_OP_IPSET_ENTRY_ADD: ++ case DPLANE_OP_IPSET_ENTRY_DELETE: ++ case DPLANE_OP_NEIGH_TABLE_UPDATE: ++ case DPLANE_OP_GRE_SET: ++ case DPLANE_OP_STARTUP_STAGE: ++ break; /* should never hit here */ ++ } + } + + /* Dump if address information to vty. */ +diff --git a/zebra/interface.h b/zebra/interface.h +index 571831f87da..cc750b94b7a 100644 +--- a/zebra/interface.h ++++ b/zebra/interface.h +@@ -513,7 +513,10 @@ extern void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf); + extern void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif); + extern const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc, + char *pd_buf, uint32_t pd_buf_len); +-void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx); ++void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx, ++ struct interface *ifp); ++ ++void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx); + + #ifdef HAVE_PROC_NET_DEV + extern void ifstat_update_proc(void); +diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c +index ccafc8f0c02..40c9c25c37e 100644 +--- a/zebra/kernel_netlink.c ++++ b/zebra/kernel_netlink.c +@@ -1438,6 +1438,7 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: ++ case DPLANE_OP_STARTUP_STAGE: + return FRR_NETLINK_ERROR; + + case DPLANE_OP_GRE_SET: +@@ -1446,6 +1447,9 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_NONE: ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: + return FRR_NETLINK_ERROR; + } + +diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c +index d6c43dbcb06..8d5b65b0e4e 100644 +--- a/zebra/kernel_socket.c ++++ b/zebra/kernel_socket.c +@@ -1574,7 +1574,31 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list) + res = ZEBRA_DPLANE_REQUEST_SUCCESS; + break; + ++<<<<<<< HEAD + default: ++======= ++ case DPLANE_OP_INTF_NETCONFIG: ++ res = kernel_intf_netconf_update(ctx); ++ break; ++ ++ case DPLANE_OP_NONE: ++ case DPLANE_OP_BR_PORT_UPDATE: ++ case DPLANE_OP_IPTABLE_ADD: ++ case DPLANE_OP_IPTABLE_DELETE: ++ case DPLANE_OP_IPSET_ADD: ++ case DPLANE_OP_IPSET_DELETE: ++ case DPLANE_OP_IPSET_ENTRY_ADD: ++ case DPLANE_OP_IPSET_ENTRY_DELETE: ++ case DPLANE_OP_NEIGH_IP_INSTALL: ++ case DPLANE_OP_NEIGH_IP_DELETE: ++ case DPLANE_OP_NEIGH_TABLE_UPDATE: ++ case DPLANE_OP_GRE_SET: ++ case DPLANE_OP_INTF_ADDR_ADD: ++ case DPLANE_OP_INTF_ADDR_DEL: ++ case DPLANE_OP_STARTUP_STAGE: ++ zlog_err("Unhandled dplane data for %s", ++ dplane_op2str(dplane_ctx_get_op(ctx))); ++>>>>>>> 1b0778183a (zebra: Add code to get/set interface to pass up from dplane) + res = ZEBRA_DPLANE_REQUEST_FAILURE; + break; + } +diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c +index e4c1393bd19..5a43a6aac07 100644 +--- a/zebra/rt_netlink.c ++++ b/zebra/rt_netlink.c +@@ -4190,6 +4190,10 @@ static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx, + ret = netlink_neigh_table_update_ctx(ctx, buf, buflen); + break; + default: ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ case DPLANE_OP_STARTUP_STAGE: + ret = -1; + } + +diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c +index 656ebcf3b7f..f24c4bdaf50 100644 +--- a/zebra/zebra_dplane.c ++++ b/zebra/zebra_dplane.c +@@ -189,9 +189,44 @@ struct dplane_br_port_info { + */ + struct dplane_intf_info { + ++ enum zebra_iftype zif_type; ++ ifindex_t bond_ifindex; ++ ifindex_t link_ifindex; ++ int32_t mtu; ++ vrf_id_t vrf_id; ++ enum zebra_slave_iftype zif_slave_type; ++ ifindex_t master_ifindex; ++ ifindex_t bridge_ifindex; ++ ns_id_t link_nsid; ++ enum zebra_slave_iftype zslave_type; ++ uint8_t bypass; ++ enum zebra_link_type zltype; ++ bool startup; ++ uint8_t family; ++ struct zebra_vxlan_vni_array *vniarray; ++ struct zebra_dplane_bridge_vlan_info bvinfo; ++ struct zebra_dplane_bridge_vlan_info_array *bvarray; ++ ++ char desc[128]; ++ ++ int32_t hw_addr_len; ++ uint8_t hw_addr[INTERFACE_HWADDR_MAX]; ++ ++ uint32_t table_id; ++ ++ struct zebra_l2info_bridge binfo; ++ struct zebra_l2info_vlan vinfo; ++ struct zebra_l2info_vxlan vxinfo; ++ struct zebra_l2info_gre grinfo; ++ ++ uint32_t rc_bitfield; ++ + uint32_t metric; + uint32_t flags; + ++ bool protodown; ++ bool protodown_set; ++ + #define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */ + #define DPLANE_INTF_SECONDARY (1 << 1) + #define DPLANE_INTF_BROADCAST (1 << 2) +@@ -347,6 +382,7 @@ struct zebra_dplane_ctx { + } ipset_entry; + struct dplane_neigh_table neightable; + struct dplane_gre_ctx gre; ++ enum zebra_dplane_startup_notifications spot; + } u; + + /* Namespace info, used especially for netlink kernel communication */ +@@ -508,6 +544,9 @@ static struct zebra_dplane_globals { + _Atomic uint32_t dg_gre_set_in; + _Atomic uint32_t dg_gre_set_errors; + ++ _Atomic uint32_t dg_intfs_in; ++ _Atomic uint32_t dg_intf_errors; ++ + /* Dataplane pthread */ + struct frr_pthread *dg_pthread; + +@@ -745,7 +784,14 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + break; +- ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ if (ctx->u.intf.vniarray) ++ XFREE(MTYPE_TMP, ctx->u.intf.vniarray); ++ if (ctx->u.intf.bvarray) ++ XFREE(MTYPE_TMP, ctx->u.intf.bvarray); ++ break; ++ case DPLANE_OP_INTF_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: + break; +@@ -769,6 +815,7 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) + } + break; + case DPLANE_OP_GRE_SET: ++ case DPLANE_OP_STARTUP_STAGE: + break; + } + } +@@ -1053,6 +1100,19 @@ const char *dplane_op2str(enum dplane_op_e op) + + case DPLANE_OP_INTF_ADDR_DEL: + return "INTF_ADDR_DEL"; ++ ++ case DPLANE_OP_INTF_INSTALL: ++ ret = "INTF_INSTALL"; ++ break; ++ case DPLANE_OP_INTF_UPDATE: ++ ret = "INTF_UPDATE"; ++ break; ++ case DPLANE_OP_INTF_DELETE: ++ ret = "INTF_DELETE"; ++ break; ++ ++ case DPLANE_OP_STARTUP_STAGE: ++ ret = "STARTUP_STAGE"; + } + + return ret; +@@ -1194,6 +1254,422 @@ const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx) + return ctx->zd_ifname; + } + ++void dplane_ctx_set_ifp_bridge_vlan_info_array( ++ struct zebra_dplane_ctx *ctx, ++ struct zebra_dplane_bridge_vlan_info_array *bvarray) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.bvarray = bvarray; ++} ++ ++const struct zebra_dplane_bridge_vlan_info_array * ++dplane_ctx_get_ifp_bridge_vlan_info_array(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.bvarray; ++} ++ ++void dplane_ctx_set_ifp_vxlan_vni_array(struct zebra_dplane_ctx *ctx, ++ struct zebra_vxlan_vni_array *vniarray) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.vniarray = vniarray; ++} ++ ++const struct zebra_vxlan_vni_array * ++dplane_ctx_get_ifp_vxlan_vni_array(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.vniarray; ++} ++ ++void dplane_ctx_set_ifp_bridge_vlan_info( ++ struct zebra_dplane_ctx *ctx, ++ struct zebra_dplane_bridge_vlan_info *bvinfo) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.bvinfo = *bvinfo; ++} ++ ++const struct zebra_dplane_bridge_vlan_info * ++dplane_ctx_get_ifp_bridge_vlan_info(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return &ctx->u.intf.bvinfo; ++} ++ ++void dplane_ctx_set_ifp_family(struct zebra_dplane_ctx *ctx, uint8_t family) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.family = family; ++} ++ ++uint8_t dplane_ctx_get_ifp_family(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.family; ++} ++ ++void dplane_ctx_set_ifp_zltype(struct zebra_dplane_ctx *ctx, ++ enum zebra_link_type zltype) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.zltype = zltype; ++} ++ ++enum zebra_link_type ++dplane_ctx_get_ifp_zltype(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.zltype; ++} ++ ++void dplane_ctx_set_ifp_link_ifindex(struct zebra_dplane_ctx *ctx, ++ ifindex_t link_ifindex) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.link_ifindex = link_ifindex; ++} ++ ++ifindex_t dplane_ctx_get_ifp_link_ifindex(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.link_ifindex; ++} ++ ++void dplane_ctx_set_ifp_desc(struct zebra_dplane_ctx *ctx, const char *desc) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ strlcpy(ctx->u.intf.desc, desc, sizeof(ctx->u.intf.desc)); ++} ++ ++char *dplane_ctx_get_ifp_desc(struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.desc; ++} ++ ++void dplane_ctx_set_ifp_flags(struct zebra_dplane_ctx *ctx, uint64_t flags) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.flags = flags; ++} ++ ++uint64_t dplane_ctx_get_ifp_flags(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.flags; ++} ++ ++void dplane_ctx_set_ifp_bypass(struct zebra_dplane_ctx *ctx, uint8_t bypass) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.bypass = bypass; ++} ++ ++uint8_t dplane_ctx_get_ifp_bypass(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.bypass; ++} ++ ++void dplane_ctx_set_ifp_bridge_ifindex(struct zebra_dplane_ctx *ctx, ++ ifindex_t bridge_ifindex) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.bridge_ifindex = bridge_ifindex; ++} ++ ++ifindex_t dplane_ctx_get_ifp_bridge_ifindex(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.bridge_ifindex; ++} ++ ++void dplane_ctx_set_ifp_zif_slave_type(struct zebra_dplane_ctx *ctx, ++ enum zebra_slave_iftype zslave_type) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.zslave_type = zslave_type; ++} ++ ++enum zebra_slave_iftype ++dplane_ctx_get_ifp_zif_slave_type(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.zslave_type; ++} ++ ++void dplane_ctx_set_ifp_master_ifindex(struct zebra_dplane_ctx *ctx, ++ ifindex_t master_ifindex) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.master_ifindex = master_ifindex; ++} ++ ++ifindex_t dplane_ctx_get_ifp_master_ifindex(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.master_ifindex; ++} ++ ++void dplane_ctx_set_ifp_mtu(struct zebra_dplane_ctx *ctx, uint32_t mtu) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.mtu = mtu; ++} ++ ++uint32_t dplane_ctx_get_ifp_mtu(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.mtu; ++} ++ ++void dplane_ctx_set_ifp_vrf_id(struct zebra_dplane_ctx *ctx, vrf_id_t vrf_id) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.vrf_id = vrf_id; ++} ++ ++vrf_id_t dplane_ctx_get_ifp_vrf_id(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.vrf_id; ++} ++ ++void dplane_ctx_set_ifp_link_nsid(struct zebra_dplane_ctx *ctx, ++ ns_id_t link_nsid) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.link_nsid = link_nsid; ++} ++ ++ns_id_t dplane_ctx_get_ifp_link_nsid(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.link_nsid; ++} ++ ++void dplane_ctx_set_ifp_startup(struct zebra_dplane_ctx *ctx, bool startup) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.startup = startup; ++} ++ ++bool dplane_ctx_get_ifp_startup(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.startup; ++} ++ ++void dplane_ctx_set_ifp_protodown_set(struct zebra_dplane_ctx *ctx, bool set) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.protodown_set = set; ++} ++ ++bool dplane_ctx_get_ifp_protodown_set(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.protodown_set; ++} ++ ++void dplane_ctx_set_ifp_protodown(struct zebra_dplane_ctx *ctx, bool protodown) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.protodown = protodown; ++} ++ ++bool dplane_ctx_get_ifp_protodown(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.protodown; ++} ++ ++ifindex_t dplane_ctx_get_ifp_bond_ifindex(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.bond_ifindex; ++} ++ ++void dplane_ctx_set_ifp_rc_bitfield(struct zebra_dplane_ctx *ctx, ++ uint32_t rc_bitfield) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.rc_bitfield = rc_bitfield; ++} ++ ++uint32_t dplane_ctx_get_ifp_rc_bitfield(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.rc_bitfield; ++} ++ ++void dplane_ctx_set_ifp_gre_info(struct zebra_dplane_ctx *ctx, ++ struct zebra_l2info_gre *grinfo) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.grinfo = *grinfo; ++} ++ ++const struct zebra_l2info_gre * ++dplane_ctx_get_ifp_gre_info(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return &ctx->u.intf.grinfo; ++} ++ ++void dplane_ctx_set_ifp_vxlan_info(struct zebra_dplane_ctx *ctx, ++ struct zebra_l2info_vxlan *vxinfo) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.vxinfo = *vxinfo; ++} ++ ++const struct zebra_l2info_vxlan * ++dplane_ctx_get_ifp_vxlan_info(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return &ctx->u.intf.vxinfo; ++} ++ ++void dplane_ctx_set_ifp_vlan_info(struct zebra_dplane_ctx *ctx, ++ struct zebra_l2info_vlan *vinfo) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.vinfo = *vinfo; ++} ++ ++const struct zebra_l2info_vlan * ++dplane_ctx_get_ifp_vlan_info(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return &ctx->u.intf.vinfo; ++} ++ ++void dplane_ctx_set_ifp_bridge_info(struct zebra_dplane_ctx *ctx, ++ struct zebra_l2info_bridge *binfo) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.binfo = *binfo; ++} ++ ++const struct zebra_l2info_bridge * ++dplane_ctx_get_ifp_bridge_info(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return &ctx->u.intf.binfo; ++} ++ ++void dplane_ctx_set_ifp_table_id(struct zebra_dplane_ctx *ctx, ++ uint32_t table_id) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.table_id = table_id; ++} ++ ++uint32_t dplane_ctx_get_ifp_table_id(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.table_id; ++} ++ ++void dplane_ctx_set_ifp_hw_addr(struct zebra_dplane_ctx *ctx, ++ int32_t hw_addr_len, uint8_t *hw_addr) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.hw_addr_len = hw_addr_len; ++ memcpy(ctx->u.intf.hw_addr, hw_addr, hw_addr_len); ++} ++ ++int32_t dplane_ctx_get_ifp_hw_addr_len(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.hw_addr_len; ++} ++ ++const uint8_t *dplane_ctx_get_ifp_hw_addr(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.hw_addr; ++} ++ ++void dplane_ctx_set_ifp_bond_ifindex(struct zebra_dplane_ctx *ctx, ++ ifindex_t bond_ifindex) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.bond_ifindex = bond_ifindex; ++} ++ ++enum zebra_iftype ++dplane_ctx_get_ifp_zif_type(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.zif_type; ++} ++ ++void dplane_ctx_set_ifp_zif_type(struct zebra_dplane_ctx *ctx, ++ enum zebra_iftype zif_type) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ ctx->u.intf.zif_type = zif_type; ++} ++ + void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname) + { + DPLANE_CTX_VALID(ctx); +@@ -1740,6 +2216,13 @@ void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric) + ctx->u.intf.metric = metric; + } + ++bool dplane_ctx_intf_is_protodown(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.protodown; ++} ++ + /* Is interface addr p2p? */ + bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx) + { +@@ -5104,6 +5587,19 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) + dplane_ctx_get_ifname(ctx), + dplane_ctx_get_intf_addr(ctx)); + break; ++ ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ zlog_debug("Dplane intf %s, idx %u, protodown %d", ++ dplane_op2str(dplane_ctx_get_op(ctx)), ++ dplane_ctx_get_ifindex(ctx), ++ dplane_ctx_intf_is_protodown(ctx)); ++ break; ++ ++ /* TODO: more detailed log */ ++ case DPLANE_OP_STARTUP_STAGE: ++ break; + } + } + +@@ -5238,6 +5734,15 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) + &zdplane_info.dg_gre_set_errors, 1, + memory_order_relaxed); + break; ++ ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) ++ atomic_fetch_add_explicit(&zdplane_info.dg_intf_errors, ++ 1, memory_order_relaxed); ++ break; ++ + /* Ignore 'notifications' - no-op */ + case DPLANE_OP_SYS_ROUTE_ADD: + case DPLANE_OP_SYS_ROUTE_DELETE: +@@ -5252,6 +5757,7 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) + break; + + case DPLANE_OP_NONE: ++ case DPLANE_OP_STARTUP_STAGE: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit(&zdplane_info.dg_other_errors, + 1, memory_order_relaxed); +@@ -5959,6 +6465,25 @@ void zebra_dplane_start(void) + frr_pthread_run(zdplane_info.dg_pthread, NULL); + } + ++enum zebra_dplane_startup_notifications ++dplane_ctx_get_startup_spot(struct zebra_dplane_ctx *ctx) ++{ ++ return ctx->u.spot; ++} ++ ++void zebra_dplane_startup_stage(struct zebra_ns *zns, ++ enum zebra_dplane_startup_notifications spot) ++{ ++ struct zebra_dplane_ctx *ctx = dplane_ctx_alloc(); ++ ++ ctx->zd_op = DPLANE_OP_STARTUP_STAGE; ++ ctx->zd_status = ZEBRA_DPLANE_REQUEST_QUEUED; ++ ++ ctx->u.spot = spot; ++ dplane_ctx_set_ns_id(ctx, zns->ns_id); ++ ++ dplane_provider_enqueue_to_zebra(ctx); ++} + /* + * Initialize the dataplane module at startup; called by zebra rib_init() + */ +diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h +index 1d55181388e..381115269f7 100644 +--- a/zebra/zebra_dplane.h ++++ b/zebra/zebra_dplane.h +@@ -98,6 +98,11 @@ enum zebra_dplane_result { + ZEBRA_DPLANE_REQUEST_FAILURE, + }; + ++enum zebra_dplane_startup_notifications { ++ ZEBRA_DPLANE_INTERFACES_READ, ++ ZEBRA_DPLANE_TUNNELS_READ, ++ ZEBRA_DPLANE_ADDRESSES_READ, ++}; + /* + * API between the zebra dataplane system and the main zebra processing + * context. +@@ -182,6 +187,14 @@ enum dplane_op_e { + /* Incoming interface address events */ + DPLANE_OP_INTF_ADDR_ADD, + DPLANE_OP_INTF_ADDR_DEL, ++ ++ /* Interface update */ ++ DPLANE_OP_INTF_INSTALL, ++ DPLANE_OP_INTF_UPDATE, ++ DPLANE_OP_INTF_DELETE, ++ ++ /* Startup Control */ ++ DPLANE_OP_STARTUP_STAGE, + }; + + /* +@@ -296,6 +309,105 @@ const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx); + void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname); + ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx); + void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex); ++void dplane_ctx_set_ifp_bond_ifindex(struct zebra_dplane_ctx *ctx, ++ ifindex_t ifindex); ++ifindex_t dplane_ctx_get_ifp_bond_ifindex(const struct zebra_dplane_ctx *ctx); ++enum zebra_iftype ++dplane_ctx_get_ifp_zif_type(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_zif_type(struct zebra_dplane_ctx *ctx, ++ enum zebra_iftype zif_type); ++void dplane_ctx_set_ifp_table_id(struct zebra_dplane_ctx *ctx, ++ uint32_t table_id); ++uint32_t dplane_ctx_get_ifp_table_id(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_hw_addr(struct zebra_dplane_ctx *ctx, ++ int32_t hw_addr_len, uint8_t *hw_addr); ++int32_t dplane_ctx_get_ifp_hw_addr_len(const struct zebra_dplane_ctx *ctx); ++const uint8_t *dplane_ctx_get_ifp_hw_addr(const struct zebra_dplane_ctx *ctx); ++struct zebra_l2info_bridge; ++void dplane_ctx_set_ifp_bridge_info(struct zebra_dplane_ctx *ctx, ++ struct zebra_l2info_bridge *binfo); ++const struct zebra_l2info_bridge * ++dplane_ctx_get_ifp_bridge_info(const struct zebra_dplane_ctx *ctx); ++struct zebra_l2info_vlan; ++void dplane_ctx_set_ifp_vlan_info(struct zebra_dplane_ctx *ctx, ++ struct zebra_l2info_vlan *vinfo); ++const struct zebra_l2info_vlan * ++dplane_ctx_get_ifp_vlan_info(const struct zebra_dplane_ctx *ctx); ++struct zebra_l2info_vxlan; ++void dplane_ctx_set_ifp_vxlan_info(struct zebra_dplane_ctx *ctx, ++ struct zebra_l2info_vxlan *vxinfo); ++const struct zebra_l2info_vxlan * ++dplane_ctx_get_ifp_vxlan_info(const struct zebra_dplane_ctx *ctx); ++struct zebra_l2info_gre; ++void dplane_ctx_set_ifp_gre_info(struct zebra_dplane_ctx *ctx, ++ struct zebra_l2info_gre *greinfo); ++const struct zebra_l2info_gre * ++dplane_ctx_get_ifp_gre_info(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_zltype(struct zebra_dplane_ctx *ctx, ++ enum zebra_link_type zlt); ++enum zebra_link_type ++dplane_ctx_get_ifp_zltype(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_link_nsid(struct zebra_dplane_ctx *ctx, ns_id_t ns_id); ++ns_id_t dplane_ctx_get_ifp_link_nsid(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_desc(struct zebra_dplane_ctx *ctx, const char *desc); ++char *dplane_ctx_get_ifp_desc(struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_mtu(struct zebra_dplane_ctx *ctx, uint32_t mtu); ++uint32_t dplane_ctx_get_ifp_mtu(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_vrf_id(struct zebra_dplane_ctx *ctx, vrf_id_t vrf_id); ++vrf_id_t dplane_ctx_get_ifp_vrf_id(const struct zebra_dplane_ctx *ctx); ++enum zebra_slave_iftype; ++void dplane_ctx_set_ifp_zif_slave_type(struct zebra_dplane_ctx *ctx, ++ enum zebra_slave_iftype zslave_type); ++enum zebra_slave_iftype ++dplane_ctx_get_ifp_zif_slave_type(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_master_ifindex(struct zebra_dplane_ctx *ctx, ++ ifindex_t master_ifindex); ++ifindex_t dplane_ctx_get_ifp_master_ifindex(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_bridge_ifindex(struct zebra_dplane_ctx *ctx, ++ ifindex_t bridge_ifindex); ++ifindex_t dplane_ctx_get_ifp_bridge_ifindex(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_bypass(struct zebra_dplane_ctx *ctx, uint8_t bypass); ++uint8_t dplane_ctx_get_ifp_bypass(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_flags(struct zebra_dplane_ctx *ctx, uint64_t flags); ++uint64_t dplane_ctx_get_ifp_flags(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_protodown(struct zebra_dplane_ctx *ctx, bool protodown); ++bool dplane_ctx_get_ifp_protodown(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_startup(struct zebra_dplane_ctx *ctx, bool startup); ++bool dplane_ctx_get_ifp_startup(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_protodown_set(struct zebra_dplane_ctx *ctx, bool set); ++bool dplane_ctx_get_ifp_protodown_set(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_rc_bitfield(struct zebra_dplane_ctx *ctx, ++ uint32_t rc_bitfield); ++uint32_t dplane_ctx_get_ifp_rc_bitfield(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_link_ifindex(struct zebra_dplane_ctx *ctx, ++ ifindex_t link_ifindex); ++ifindex_t dplane_ctx_get_ifp_link_ifindex(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_ifp_family(struct zebra_dplane_ctx *ctx, uint8_t family); ++uint8_t dplane_ctx_get_ifp_family(const struct zebra_dplane_ctx *ctx); ++struct zebra_vxlan_vni_array; ++void dplane_ctx_set_ifp_vxlan_vni_array(struct zebra_dplane_ctx *ctx, ++ struct zebra_vxlan_vni_array *vniarray); ++const struct zebra_vxlan_vni_array * ++dplane_ctx_get_ifp_vxlan_vni_array(const struct zebra_dplane_ctx *ctx); ++struct zebra_dplane_bridge_vlan_info { ++ uint16_t flags; ++ uint16_t vid; ++}; ++void dplane_ctx_set_ifp_bridge_vlan_info( ++ struct zebra_dplane_ctx *ctx, ++ struct zebra_dplane_bridge_vlan_info *bvinfo); ++const struct zebra_dplane_bridge_vlan_info * ++dplane_ctx_get_ifp_bridge_vlan_info(const struct zebra_dplane_ctx *ctx); ++ ++struct zebra_dplane_bridge_vlan_info_array { ++ int count; ++ struct zebra_dplane_bridge_vlan_info array[0]; ++}; ++void dplane_ctx_set_ifp_bridge_vlan_info_array( ++ struct zebra_dplane_ctx *ctx, ++ struct zebra_dplane_bridge_vlan_info_array *bvarray); ++const struct zebra_dplane_bridge_vlan_info_array * ++dplane_ctx_get_ifp_bridge_vlan_info_array(const struct zebra_dplane_ctx *ctx); + + /* Retrieve last/current provider id */ + uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx); +@@ -458,6 +570,9 @@ dplane_ctx_get_pw_backup_nhg(const struct zebra_dplane_ctx *ctx); + /* Accessors for interface information */ + uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx); + void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric); ++uint32_t dplane_ctx_get_intf_pd_reason_val(const struct zebra_dplane_ctx *ctx); ++void dplane_ctx_set_intf_pd_reason_val(struct zebra_dplane_ctx *ctx, bool val); ++bool dplane_ctx_intf_is_protodown(const struct zebra_dplane_ctx *ctx); + /* Is interface addr p2p? */ + bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx); + void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx); +@@ -930,6 +1045,12 @@ void zebra_dplane_pre_finish(void); + void zebra_dplane_finish(void); + void zebra_dplane_shutdown(void); + ++void zebra_dplane_startup_stage(struct zebra_ns *zns, ++ enum zebra_dplane_startup_notifications spot); ++ ++enum zebra_dplane_startup_notifications ++dplane_ctx_get_startup_spot(struct zebra_dplane_ctx *ctx); ++ + #ifdef __cplusplus + } + #endif +diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c +index 924a43049be..fd8e31c0a70 100644 +--- a/zebra/zebra_mpls.c ++++ b/zebra/zebra_mpls.c +@@ -1854,6 +1854,10 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) + break; + + default: ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ case DPLANE_OP_STARTUP_STAGE: + break; + + } /* Switch */ +diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c +index cdf34936c0b..66ca629beaa 100644 +--- a/zebra/zebra_mpls_openbsd.c ++++ b/zebra/zebra_mpls_openbsd.c +@@ -255,7 +255,62 @@ static int kernel_lsp_cmd(struct zebra_dplane_ctx *ctx) + case DPLANE_OP_LSP_UPDATE: + action = RTM_CHANGE; + break; ++<<<<<<< HEAD + default: ++======= ++ case DPLANE_OP_NONE: ++ case DPLANE_OP_ROUTE_INSTALL: ++ case DPLANE_OP_ROUTE_UPDATE: ++ case DPLANE_OP_ROUTE_DELETE: ++ case DPLANE_OP_ROUTE_NOTIFY: ++ case DPLANE_OP_NH_INSTALL: ++ case DPLANE_OP_NH_UPDATE: ++ case DPLANE_OP_NH_DELETE: ++ case DPLANE_OP_LSP_NOTIFY: ++ case DPLANE_OP_PW_INSTALL: ++ case DPLANE_OP_PW_UNINSTALL: ++ case DPLANE_OP_SYS_ROUTE_ADD: ++ case DPLANE_OP_SYS_ROUTE_DELETE: ++ case DPLANE_OP_ADDR_INSTALL: ++ case DPLANE_OP_ADDR_UNINSTALL: ++ case DPLANE_OP_MAC_INSTALL: ++ case DPLANE_OP_MAC_DELETE: ++ case DPLANE_OP_NEIGH_INSTALL: ++ case DPLANE_OP_NEIGH_UPDATE: ++ case DPLANE_OP_NEIGH_DELETE: ++ case DPLANE_OP_VTEP_ADD: ++ case DPLANE_OP_VTEP_DELETE: ++ case DPLANE_OP_RULE_ADD: ++ case DPLANE_OP_RULE_DELETE: ++ case DPLANE_OP_RULE_UPDATE: ++ case DPLANE_OP_NEIGH_DISCOVER: ++ case DPLANE_OP_BR_PORT_UPDATE: ++ case DPLANE_OP_IPTABLE_ADD: ++ case DPLANE_OP_IPTABLE_DELETE: ++ case DPLANE_OP_IPSET_ADD: ++ case DPLANE_OP_IPSET_DELETE: ++ case DPLANE_OP_IPSET_ENTRY_ADD: ++ case DPLANE_OP_IPSET_ENTRY_DELETE: ++ case DPLANE_OP_NEIGH_IP_INSTALL: ++ case DPLANE_OP_NEIGH_IP_DELETE: ++ case DPLANE_OP_NEIGH_TABLE_UPDATE: ++ case DPLANE_OP_GRE_SET: ++ case DPLANE_OP_INTF_ADDR_ADD: ++ case DPLANE_OP_INTF_ADDR_DEL: ++ case DPLANE_OP_INTF_NETCONFIG: ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ case DPLANE_OP_TC_QDISC_INSTALL: ++ case DPLANE_OP_TC_QDISC_UNINSTALL: ++ case DPLANE_OP_TC_CLASS_ADD: ++ case DPLANE_OP_TC_CLASS_DELETE: ++ case DPLANE_OP_TC_CLASS_UPDATE: ++ case DPLANE_OP_TC_FILTER_ADD: ++ case DPLANE_OP_TC_FILTER_DELETE: ++ case DPLANE_OP_TC_FILTER_UPDATE: ++ case DPLANE_OP_STARTUP_STAGE: ++>>>>>>> 1b0778183a (zebra: Add code to get/set interface to pass up from dplane) + return -1; + } + +@@ -415,7 +470,63 @@ enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx) + case DPLANE_OP_PW_UNINSTALL: + result = kmpw_uninstall(ctx); + break; ++<<<<<<< HEAD + default: ++======= ++ case DPLANE_OP_NONE: ++ case DPLANE_OP_ROUTE_INSTALL: ++ case DPLANE_OP_ROUTE_UPDATE: ++ case DPLANE_OP_ROUTE_DELETE: ++ case DPLANE_OP_ROUTE_NOTIFY: ++ case DPLANE_OP_NH_INSTALL: ++ case DPLANE_OP_NH_UPDATE: ++ case DPLANE_OP_NH_DELETE: ++ case DPLANE_OP_LSP_INSTALL: ++ case DPLANE_OP_LSP_UPDATE: ++ case DPLANE_OP_LSP_DELETE: ++ case DPLANE_OP_LSP_NOTIFY: ++ case DPLANE_OP_SYS_ROUTE_ADD: ++ case DPLANE_OP_SYS_ROUTE_DELETE: ++ case DPLANE_OP_ADDR_INSTALL: ++ case DPLANE_OP_ADDR_UNINSTALL: ++ case DPLANE_OP_MAC_INSTALL: ++ case DPLANE_OP_MAC_DELETE: ++ case DPLANE_OP_NEIGH_INSTALL: ++ case DPLANE_OP_NEIGH_UPDATE: ++ case DPLANE_OP_NEIGH_DELETE: ++ case DPLANE_OP_VTEP_ADD: ++ case DPLANE_OP_VTEP_DELETE: ++ case DPLANE_OP_RULE_ADD: ++ case DPLANE_OP_RULE_DELETE: ++ case DPLANE_OP_RULE_UPDATE: ++ case DPLANE_OP_NEIGH_DISCOVER: ++ case DPLANE_OP_BR_PORT_UPDATE: ++ case DPLANE_OP_IPTABLE_ADD: ++ case DPLANE_OP_IPTABLE_DELETE: ++ case DPLANE_OP_IPSET_ADD: ++ case DPLANE_OP_IPSET_DELETE: ++ case DPLANE_OP_IPSET_ENTRY_ADD: ++ case DPLANE_OP_IPSET_ENTRY_DELETE: ++ case DPLANE_OP_NEIGH_IP_INSTALL: ++ case DPLANE_OP_NEIGH_IP_DELETE: ++ case DPLANE_OP_NEIGH_TABLE_UPDATE: ++ case DPLANE_OP_GRE_SET: ++ case DPLANE_OP_INTF_ADDR_ADD: ++ case DPLANE_OP_INTF_ADDR_DEL: ++ case DPLANE_OP_INTF_NETCONFIG: ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ case DPLANE_OP_TC_QDISC_INSTALL: ++ case DPLANE_OP_TC_QDISC_UNINSTALL: ++ case DPLANE_OP_TC_CLASS_ADD: ++ case DPLANE_OP_TC_CLASS_DELETE: ++ case DPLANE_OP_TC_CLASS_UPDATE: ++ case DPLANE_OP_TC_FILTER_ADD: ++ case DPLANE_OP_TC_FILTER_DELETE: ++ case DPLANE_OP_TC_FILTER_UPDATE: ++ case DPLANE_OP_STARTUP_STAGE: ++>>>>>>> 1b0778183a (zebra: Add code to get/set interface to pass up from dplane) + break; + } + +diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c +index 7d124307db5..40c69faf316 100644 +--- a/zebra/zebra_nhg.c ++++ b/zebra/zebra_nhg.c +@@ -2990,6 +2990,10 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) + case DPLANE_OP_GRE_SET: + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ case DPLANE_OP_STARTUP_STAGE: + break; + } + +diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c +index cf1baf077f7..377f9ce5a14 100644 +--- a/zebra/zebra_rib.c ++++ b/zebra/zebra_rib.c +@@ -2031,6 +2031,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) + zebra_rib_fixup_system(rn); + break; + default: ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ case DPLANE_OP_STARTUP_STAGE: + break; + } + +@@ -4298,7 +4302,10 @@ static int rib_process_dplane_results(struct thread *thread) + + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: +- zebra_if_addr_update_ctx(ctx); ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ zebra_if_dplane_result(ctx); + break; + + /* Some op codes not handled here */ +@@ -4316,6 +4323,7 @@ static int rib_process_dplane_results(struct thread *thread) + case DPLANE_OP_NEIGH_TABLE_UPDATE: + case DPLANE_OP_GRE_SET: + case DPLANE_OP_NONE: ++ case DPLANE_OP_STARTUP_STAGE: + /* Don't expect this: just return the struct? */ + dplane_ctx_fini(&ctx); + break; +diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c +index 0e19376abe2..b4ce9cf29fc 100644 +--- a/zebra/zebra_script.c ++++ b/zebra/zebra_script.c +@@ -413,6 +413,10 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) + } + lua_setfield(L, -2, "gre"); + case DPLANE_OP_NONE: ++ case DPLANE_OP_INTF_INSTALL: ++ case DPLANE_OP_INTF_UPDATE: ++ case DPLANE_OP_INTF_DELETE: ++ case DPLANE_OP_STARTUP_STAGE: + break; + } /* Dispatch by op code */ + } diff --git a/src/sonic-frr/patch/0019-zebra-Use-zebra-dplane-for-RTM-link-and-addr.patch b/src/sonic-frr/patch/0019-zebra-Use-zebra-dplane-for-RTM-link-and-addr.patch new file mode 100644 index 00000000000..af5ad25559f --- /dev/null +++ b/src/sonic-frr/patch/0019-zebra-Use-zebra-dplane-for-RTM-link-and-addr.patch @@ -0,0 +1,2175 @@ +From 7e479d22ca9d8317947f6c82187dd193cb8225cd Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Wed, 26 Apr 2023 23:02:09 -0400 +Subject: [PATCH] zebra: Use zebra dplane for RTM link and addr + +a) Move the reads of link and address information +into the dplane +b) Move the startup read of data into the dplane +as well. +c) Break up startup reading of the linux kernel data +into multiple phases. As that we have implied ordering +of data that must be read first and if the dplane has +taken over some data reading then we must delay initial +read-in of other data. + +Fixes: #13288 +Signed-off-by: Donald Sharp +--- + zebra/if_netlink.c | 764 ++++++++++++----------------------------- + zebra/interface.c | 702 ++++++++++++++++++++++++++++++++++++- + zebra/interface.h | 11 +- + zebra/kernel_netlink.c | 27 +- + zebra/kernel_socket.c | 4 + + zebra/rt.h | 1 + + zebra/rule_netlink.c | 1 + + zebra/zebra_dplane.c | 8 + + zebra/zebra_dplane.h | 14 +- + zebra/zebra_l2.c | 9 +- + zebra/zebra_l2.h | 63 +++- + zebra/zebra_ns.c | 28 +- + zebra/zebra_ns.h | 2 + + zebra/zebra_rib.c | 4 +- + 14 files changed, 1054 insertions(+), 584 deletions(-) + +diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c +index eb113797101..6f12e880c0a 100644 +--- a/zebra/if_netlink.c ++++ b/zebra/if_netlink.c +@@ -77,64 +77,21 @@ + + extern struct zebra_privs_t zserv_privs; + +-/* Note: on netlink systems, there should be a 1-to-1 mapping between interface +- names and ifindex values. */ +-static void set_ifindex(struct interface *ifp, ifindex_t ifi_index, +- struct zebra_ns *zns) +-{ +- struct interface *oifp; +- +- if (((oifp = if_lookup_by_index_per_ns(zns, ifi_index)) != NULL) +- && (oifp != ifp)) { +- if (ifi_index == IFINDEX_INTERNAL) +- flog_err( +- EC_LIB_INTERFACE, +- "Netlink is setting interface %s ifindex to reserved internal value %u", +- ifp->name, ifi_index); +- else { +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "interface index %d was renamed from %s to %s", +- ifi_index, oifp->name, ifp->name); +- if (if_is_up(oifp)) +- flog_err( +- EC_LIB_INTERFACE, +- "interface rename detected on up interface: index %d was renamed from %s to %s, results are uncertain!", +- ifi_index, oifp->name, ifp->name); +- if_delete_update(&oifp); +- } +- } +- if_set_index(ifp, ifi_index); +-} +- + /* Utility function to parse hardware link-layer address and update ifp */ + static void netlink_interface_update_hw_addr(struct rtattr **tb, +- struct interface *ifp) ++ struct zebra_dplane_ctx *ctx) + { +- int i; +- + if (tb[IFLA_ADDRESS]) { + int hw_addr_len; + + hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]); + + if (hw_addr_len > INTERFACE_HWADDR_MAX) +- zlog_debug("Hardware address is too large: %d", +- hw_addr_len); +- else { +- ifp->hw_addr_len = hw_addr_len; +- memcpy(ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), +- hw_addr_len); +- +- for (i = 0; i < hw_addr_len; i++) +- if (ifp->hw_addr[i] != 0) +- break; +- +- if (i == hw_addr_len) +- ifp->hw_addr_len = 0; +- else +- ifp->hw_addr_len = hw_addr_len; +- } ++ zlog_warn("Hardware address is too large: %d", ++ hw_addr_len); ++ else ++ dplane_ctx_set_ifp_hw_addr(ctx, hw_addr_len, ++ RTA_DATA(tb[IFLA_ADDRESS])); + } + } + +@@ -249,26 +206,6 @@ static enum zebra_link_type netlink_to_zebra_link_type(unsigned int hwt) + } + } + +-static inline void zebra_if_set_ziftype(struct interface *ifp, +- enum zebra_iftype zif_type, +- enum zebra_slave_iftype zif_slave_type) +-{ +- struct zebra_if *zif; +- +- zif = (struct zebra_if *)ifp->info; +- zif->zif_slave_type = zif_slave_type; +- +- if (zif->zif_type != zif_type) { +- zif->zif_type = zif_type; +- /* If the if_type has been set to bond initialize ES info +- * against it. XXX - note that we don't handle the case where +- * a zif changes from bond to non-bond; it is really +- * an unexpected/error condition. +- */ +- zebra_evpn_if_init(zif); +- } +-} +- + static void netlink_determine_zebra_iftype(const char *kind, + enum zebra_iftype *zif_type) + { +@@ -298,16 +235,11 @@ static void netlink_determine_zebra_iftype(const char *kind, + } + + static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb, +- uint32_t ns_id, const char *name) ++ uint32_t ns_id, const char *name, ++ struct zebra_dplane_ctx *ctx) + { +- struct ifinfomsg *ifi; + struct rtattr *linkinfo[IFLA_INFO_MAX + 1]; + struct rtattr *attr[IFLA_VRF_MAX + 1]; +- struct vrf *vrf = NULL; +- struct zebra_vrf *zvrf; +- uint32_t nl_table_id; +- +- ifi = NLMSG_DATA(h); + + netlink_parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb); + +@@ -329,75 +261,8 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb, + return; + } + +- nl_table_id = *(uint32_t *)RTA_DATA(attr[IFLA_VRF_TABLE]); +- +- if (h->nlmsg_type == RTM_NEWLINK) { +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug("RTM_NEWLINK for VRF %s(%u) table %u", name, +- ifi->ifi_index, nl_table_id); +- +- if (!vrf_lookup_by_id((vrf_id_t)ifi->ifi_index)) { +- vrf_id_t exist_id; +- +- exist_id = +- zebra_vrf_lookup_by_table(nl_table_id, ns_id); +- if (exist_id != VRF_DEFAULT) { +- vrf = vrf_lookup_by_id(exist_id); +- +- flog_err( +- EC_ZEBRA_VRF_MISCONFIGURED, +- "VRF %s id %u table id overlaps existing vrf %s, misconfiguration exiting", +- name, ifi->ifi_index, vrf->name); +- exit(-1); +- } +- } +- +- vrf = vrf_update((vrf_id_t)ifi->ifi_index, name); +- if (!vrf) { +- flog_err(EC_LIB_INTERFACE, "VRF %s id %u not created", +- name, ifi->ifi_index); +- return; +- } +- +- /* +- * This is the only place that we get the actual kernel table_id +- * being used. We need it to set the table_id of the routes +- * we are passing to the kernel.... And to throw some totally +- * awesome parties. that too. +- * +- * At this point we *must* have a zvrf because the vrf_create +- * callback creates one. We *must* set the table id +- * before the vrf_enable because of( at the very least ) +- * static routes being delayed for installation until +- * during the vrf_enable callbacks. +- */ +- zvrf = (struct zebra_vrf *)vrf->info; +- zvrf->table_id = nl_table_id; +- +- /* Enable the created VRF. */ +- if (!vrf_enable(vrf)) { +- flog_err(EC_LIB_INTERFACE, +- "Failed to enable VRF %s id %u", name, +- ifi->ifi_index); +- return; +- } +- +- } else // h->nlmsg_type == RTM_DELLINK +- { +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug("RTM_DELLINK for VRF %s(%u)", name, +- ifi->ifi_index); +- +- vrf = vrf_lookup_by_id((vrf_id_t)ifi->ifi_index); +- +- if (!vrf) { +- flog_warn(EC_ZEBRA_VRF_NOT_FOUND, "%s: vrf not found", +- __func__); +- return; +- } +- +- vrf_delete(vrf); +- } ++ dplane_ctx_set_ifp_table_id( ++ ctx, *(uint32_t *)RTA_DATA(attr[IFLA_VRF_TABLE])); + } + + static uint32_t get_iflink_speed(struct interface *interface, int *error) +@@ -657,58 +522,119 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data, + * bridge interface is added or updated, take further actions to map + * its members. Likewise, for VxLAN interface. + */ +-static void netlink_interface_update_l2info(struct interface *ifp, ++static void netlink_interface_update_l2info(struct zebra_dplane_ctx *ctx, ++ enum zebra_iftype zif_type, + struct rtattr *link_data, int add, + ns_id_t link_nsid) + { ++ struct zebra_l2info_bridge bridge_info; ++ struct zebra_l2info_vlan vlan_info; ++ struct zebra_l2info_vxlan vxlan_info; ++ struct zebra_l2info_gre gre_info; ++ + if (!link_data) + return; + +- if (IS_ZEBRA_IF_BRIDGE(ifp)) { +- struct zebra_l2info_bridge bridge_info; +- ++ switch (zif_type) { ++ case ZEBRA_IF_BRIDGE: + netlink_extract_bridge_info(link_data, &bridge_info); +- zebra_l2_bridge_add_update(ifp, &bridge_info); +- } else if (IS_ZEBRA_IF_VLAN(ifp)) { +- struct zebra_l2info_vlan vlan_info; +- ++ dplane_ctx_set_ifp_bridge_info(ctx, &bridge_info); ++ break; ++ case ZEBRA_IF_VLAN: + netlink_extract_vlan_info(link_data, &vlan_info); +- zebra_l2_vlanif_update(ifp, &vlan_info); +- zebra_evpn_acc_bd_svi_set(ifp->info, NULL, +- !!if_is_operative(ifp)); +- } else if (IS_ZEBRA_IF_VXLAN(ifp)) { +- struct zebra_l2info_vxlan vxlan_info; +- ++ dplane_ctx_set_ifp_vlan_info(ctx, &vlan_info); ++ break; ++ case ZEBRA_IF_VXLAN: + netlink_extract_vxlan_info(link_data, &vxlan_info); + vxlan_info.link_nsid = link_nsid; +- zebra_l2_vxlanif_add_update(ifp, &vxlan_info, add); +- if (link_nsid != NS_UNKNOWN && +- vxlan_info.ifindex_link) +- zebra_if_update_link(ifp, vxlan_info.ifindex_link, +- link_nsid); +- } else if (IS_ZEBRA_IF_GRE(ifp)) { +- struct zebra_l2info_gre gre_info; +- ++ dplane_ctx_set_ifp_vxlan_info(ctx, &vxlan_info); ++ break; ++ case ZEBRA_IF_GRE: + netlink_extract_gre_info(link_data, &gre_info); + gre_info.link_nsid = link_nsid; +- zebra_l2_greif_add_update(ifp, &gre_info, add); +- if (link_nsid != NS_UNKNOWN && +- gre_info.ifindex_link) +- zebra_if_update_link(ifp, gre_info.ifindex_link, +- link_nsid); ++ dplane_ctx_set_ifp_gre_info(ctx, &gre_info); ++ break; ++ case ZEBRA_IF_OTHER: ++ case ZEBRA_IF_VRF: ++ case ZEBRA_IF_MACVLAN: ++ case ZEBRA_IF_VETH: ++ case ZEBRA_IF_BOND: ++ case ZEBRA_IF_BOND_SLAVE: ++ break; ++ } ++} ++ ++static int ++netlink_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx, ++ struct rtattr *af_spec) ++{ ++ int rem; ++ uint16_t flags; ++ struct rtattr *i; ++ struct zebra_vxlan_vni_array *vniarray = NULL; ++ struct zebra_vxlan_vni vni_end; ++ struct zebra_vxlan_vni vni_start; ++ struct rtattr *aftb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1]; ++ int32_t count = 0; ++ ++ memset(&vni_start, 0, sizeof(vni_start)); ++ memset(&vni_end, 0, sizeof(vni_end)); ++ ++ for (i = RTA_DATA(af_spec), rem = RTA_PAYLOAD(af_spec); RTA_OK(i, rem); ++ i = RTA_NEXT(i, rem)) { ++ ++ if (i->rta_type != IFLA_BRIDGE_VLAN_TUNNEL_INFO) ++ continue; ++ ++ memset(aftb, 0, sizeof(aftb)); ++ netlink_parse_rtattr_nested(aftb, IFLA_BRIDGE_VLAN_TUNNEL_MAX, ++ i); ++ if (!aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID] || ++ !aftb[IFLA_BRIDGE_VLAN_TUNNEL_VID]) ++ /* vlan-vni info missing */ ++ return 0; ++ ++ count++; ++ flags = 0; ++ vniarray = XREALLOC( ++ MTYPE_TMP, vniarray, ++ sizeof(struct zebra_vxlan_vni_array) + ++ count * sizeof(struct zebra_vxlan_vni)); ++ ++ memset(&vniarray->vnis[count - 1], 0, ++ sizeof(struct zebra_vxlan_vni)); ++ ++ vniarray->vnis[count - 1].vni = ++ *(vni_t *)RTA_DATA(aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID]); ++ vniarray->vnis[count - 1].access_vlan = *(vlanid_t *)RTA_DATA( ++ aftb[IFLA_BRIDGE_VLAN_TUNNEL_VID]); ++ ++ if (aftb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]) ++ flags = *(uint16_t *)RTA_DATA( ++ aftb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]); ++ ++ vniarray->vnis[count - 1].flags = flags; + } ++ ++ if (count) { ++ vniarray->count = count; ++ dplane_ctx_set_ifp_vxlan_vni_array(ctx, vniarray); ++ } ++ return 0; + } + +-static int netlink_bridge_vxlan_update(struct interface *ifp, +- struct rtattr *af_spec) ++static int netlink_bridge_vxlan_update(struct zebra_dplane_ctx *ctx, ++ struct rtattr *af_spec) + { + struct rtattr *aftb[IFLA_BRIDGE_MAX + 1]; + struct bridge_vlan_info *vinfo; +- vlanid_t access_vlan; ++ struct zebra_dplane_bridge_vlan_info bvinfo; + + if (!af_spec) + return 0; + ++ netlink_bridge_vxlan_vlan_vni_map_update(ctx, af_spec); ++ + /* There is a 1-to-1 mapping of VLAN to VxLAN - hence + * only 1 access VLAN is accepted. + */ +@@ -717,131 +643,80 @@ static int netlink_bridge_vxlan_update(struct interface *ifp, + return 0; + + vinfo = RTA_DATA(aftb[IFLA_BRIDGE_VLAN_INFO]); +- if (!(vinfo->flags & BRIDGE_VLAN_INFO_PVID)) +- return 0; ++ bvinfo.flags = vinfo->flags; ++ bvinfo.vid = vinfo->vid; + +- access_vlan = (vlanid_t)vinfo->vid; +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug("Access VLAN %u for VxLAN IF %s(%u)", access_vlan, +- ifp->name, ifp->ifindex); +- zebra_l2_vxlanif_update_access_vlan(ifp, access_vlan); ++ dplane_ctx_set_ifp_bridge_vlan_info(ctx, &bvinfo); + return 0; + } + +-static void netlink_bridge_vlan_update(struct interface *ifp, +- struct rtattr *af_spec) ++static void netlink_bridge_vlan_update(struct zebra_dplane_ctx *ctx, ++ struct rtattr *af_spec) + { + struct rtattr *i; + int rem; +- uint16_t vid_range_start = 0; +- struct zebra_if *zif; +- bitfield_t old_vlan_bitmap; + struct bridge_vlan_info *vinfo; +- +- zif = (struct zebra_if *)ifp->info; +- +- /* cache the old bitmap addrs */ +- old_vlan_bitmap = zif->vlan_bitmap; +- /* create a new bitmap space for re-eval */ +- bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX); ++ struct zebra_dplane_bridge_vlan_info_array *bvarray = NULL; ++ int32_t count = 0; + + if (af_spec) { + for (i = RTA_DATA(af_spec), rem = RTA_PAYLOAD(af_spec); + RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { +- + if (i->rta_type != IFLA_BRIDGE_VLAN_INFO) + continue; + +- vinfo = RTA_DATA(i); +- +- if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { +- vid_range_start = vinfo->vid; +- continue; +- } ++ count++; ++ bvarray = XREALLOC( ++ MTYPE_TMP, bvarray, ++ sizeof(struct ++ zebra_dplane_bridge_vlan_info_array) + ++ count * sizeof(struct ++ zebra_dplane_bridge_vlan_info)); + +- if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) +- vid_range_start = vinfo->vid; +- +- zebra_vlan_bitmap_compute(ifp, vid_range_start, +- vinfo->vid); ++ vinfo = RTA_DATA(i); ++ bvarray->array[count - 1].flags = vinfo->flags; ++ bvarray->array[count - 1].vid = vinfo->vid; + } + } + +- zebra_vlan_mbr_re_eval(ifp, old_vlan_bitmap); +- +- bf_free(old_vlan_bitmap); ++ if (count) { ++ bvarray->count = count; ++ dplane_ctx_set_ifp_bridge_vlan_info_array(ctx, bvarray); ++ } + } + +-static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id, +- int startup) ++static int netlink_bridge_interface(struct zebra_dplane_ctx *ctx, ++ struct rtattr *af_spec, int startup) + { +- char *name = NULL; +- struct ifinfomsg *ifi; +- struct rtattr *tb[IFLA_MAX + 1]; +- struct interface *ifp; +- struct zebra_if *zif; +- struct rtattr *af_spec; + +- /* Fetch name and ifindex */ +- ifi = NLMSG_DATA(h); +- netlink_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); +- +- if (tb[IFLA_IFNAME] == NULL) +- return -1; +- name = (char *)RTA_DATA(tb[IFLA_IFNAME]); +- +- /* The interface should already be known, if not discard. */ +- ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), ifi->ifi_index); +- if (!ifp) { +- zlog_debug("Cannot find bridge IF %s(%u)", name, +- ifi->ifi_index); +- return 0; +- } +- +- /* We are only interested in the access VLAN i.e., AF_SPEC */ +- af_spec = tb[IFLA_AF_SPEC]; +- +- if (IS_ZEBRA_IF_VXLAN(ifp)) +- return netlink_bridge_vxlan_update(ifp, af_spec); ++ netlink_bridge_vxlan_update(ctx, af_spec); + + /* build vlan bitmap associated with this interface if that + * device type is interested in the vlans + */ +- zif = (struct zebra_if *)ifp->info; +- if (bf_is_inited(zif->vlan_bitmap)) +- netlink_bridge_vlan_update(ifp, af_spec); ++ netlink_bridge_vlan_update(ctx, af_spec); + ++ dplane_provider_enqueue_to_zebra(ctx); + return 0; + } + +-/* If the interface is an es bond member then it must follow EVPN's +- * protodown setting ++/* ++ * Process interface protodown dplane update. ++ * ++ * If the interface is an es bond member then it must follow EVPN's ++ * protodown setting. + */ +-static void netlink_proc_dplane_if_protodown(struct zebra_if *zif, +- bool protodown) ++static void netlink_proc_dplane_if_protodown(struct zebra_dplane_ctx *ctx, ++ struct rtattr **tb) + { +- bool zif_protodown; +- +- zif_protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN); +- if (protodown == zif_protodown) +- return; ++ bool protodown; ++ uint32_t rc_bitfield = 0; + +- if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug("interface %s dplane change, protdown %s", +- zif->ifp->name, protodown ? "on" : "off"); ++ protodown = !!*(uint8_t *)RTA_DATA(tb[IFLA_PROTO_DOWN]); + +- if (zebra_evpn_is_es_bond_member(zif->ifp)) { +- if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "bond mbr %s re-instate protdown %s in the dplane", +- zif->ifp->name, zif_protodown ? "on" : "off"); +- netlink_protodown(zif->ifp, zif_protodown); +- } else { +- if (protodown) +- zif->flags |= ZIF_FLAG_PROTODOWN; +- else +- zif->flags &= ~ZIF_FLAG_PROTODOWN; +- } ++ dplane_ctx_set_ifp_rc_bitfield(ctx, rc_bitfield); ++ dplane_ctx_set_ifp_protodown(ctx, protodown); ++ dplane_ctx_set_ifp_protodown_set(ctx, true); + } + + static uint8_t netlink_parse_lacp_bypass(struct rtattr **linkinfo) +@@ -901,7 +776,7 @@ int interface_lookup_netlink(struct zebra_ns *zns) + { + int ret; + struct zebra_dplane_info dp_info; +- struct nlsock *netlink_cmd = &zns->netlink_cmd; ++ struct nlsock *netlink_cmd = &zns->netlink_dplane_out; + + /* Capture key info from ns struct */ + zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/); +@@ -924,10 +799,7 @@ int interface_lookup_netlink(struct zebra_ns *zns) + true); + if (ret < 0) + return ret; +- +- /* fixup linkages */ +- zebra_if_update_all_links(zns); +- return 0; ++ return ret; + } + + /** +@@ -949,8 +821,8 @@ static int interface_addr_lookup_netlink(struct zebra_ns *zns) + ret = netlink_request_intf_addr(netlink_cmd, AF_INET, RTM_GETADDR, 0); + if (ret < 0) + return ret; +- ret = netlink_parse_info(netlink_interface_addr, netlink_cmd, &dp_info, +- 0, true); ++ ret = netlink_parse_info(netlink_interface_addr_dplane, netlink_cmd, ++ &dp_info, 0, true); + if (ret < 0) + return ret; + +@@ -958,8 +830,8 @@ static int interface_addr_lookup_netlink(struct zebra_ns *zns) + ret = netlink_request_intf_addr(netlink_cmd, AF_INET6, RTM_GETADDR, 0); + if (ret < 0) + return ret; +- ret = netlink_parse_info(netlink_interface_addr, netlink_cmd, &dp_info, +- 0, true); ++ ret = netlink_parse_info(netlink_interface_addr_dplane, netlink_cmd, ++ &dp_info, 0, true); + if (ret < 0) + return ret; + +@@ -1482,7 +1354,6 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, + + /* Enqueue ctx for main pthread to process */ + dplane_provider_enqueue_to_zebra(ctx); +- + return 0; + } + +@@ -1492,25 +1363,19 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) + struct ifinfomsg *ifi; + struct rtattr *tb[IFLA_MAX + 1]; + struct rtattr *linkinfo[IFLA_MAX + 1]; +- struct interface *ifp; + char *name = NULL; + char *kind = NULL; +- char *desc = NULL; + char *slave_kind = NULL; +- struct zebra_ns *zns; + vrf_id_t vrf_id = VRF_DEFAULT; + enum zebra_iftype zif_type = ZEBRA_IF_OTHER; + enum zebra_slave_iftype zif_slave_type = ZEBRA_IF_SLAVE_NONE; + ifindex_t bridge_ifindex = IFINDEX_INTERNAL; + ifindex_t bond_ifindex = IFINDEX_INTERNAL; + ifindex_t link_ifindex = IFINDEX_INTERNAL; +- uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; +- struct zebra_if *zif; + ns_id_t link_nsid = ns_id; + ifindex_t master_infindex = IFINDEX_INTERNAL; + uint8_t bypass = 0; + +- zns = zebra_ns_lookup(ns_id); + ifi = NLMSG_DATA(h); + + /* assume if not default zns, then new VRF */ +@@ -1539,10 +1404,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) + return -1; + } + +- /* We are interested in some AF_BRIDGE notifications. */ +- if (ifi->ifi_family == AF_BRIDGE) +- return netlink_bridge_interface(h, len, ns_id, startup); +- + /* Looking up interface name. */ + memset(linkinfo, 0, sizeof(linkinfo)); + netlink_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); +@@ -1591,18 +1452,47 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) + link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]); + link_nsid = ns_id_get_absolute(ns_id, link_nsid); + } +- if (tb[IFLA_IFALIAS]) { +- desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]); +- } + +- /* See if interface is present. */ +- ifp = if_lookup_by_name_per_ns(zns, name); ++ struct zebra_dplane_ctx *ctx = dplane_ctx_alloc(); ++ dplane_ctx_set_ns_id(ctx, ns_id); ++ dplane_ctx_set_ifp_link_nsid(ctx, link_nsid); ++ dplane_ctx_set_ifp_zif_type(ctx, zif_type); ++ dplane_ctx_set_ifindex(ctx, ifi->ifi_index); ++ dplane_ctx_set_ifname(ctx, name); ++ dplane_ctx_set_ifp_startup(ctx, startup); ++ dplane_ctx_set_ifp_family(ctx, ifi->ifi_family); ++ ++ /* We are interested in some AF_BRIDGE notifications. */ ++#ifndef AF_BRIDGE ++#define AF_BRIDGE 7 ++#endif ++ if (ifi->ifi_family == AF_BRIDGE) { ++ dplane_ctx_set_op(ctx, DPLANE_OP_INTF_INSTALL); ++ return netlink_bridge_interface(ctx, tb[IFLA_AF_SPEC], startup); ++ } + + if (h->nlmsg_type == RTM_NEWLINK) { ++ dplane_ctx_set_ifp_link_ifindex(ctx, link_ifindex); ++ dplane_ctx_set_op(ctx, DPLANE_OP_INTF_INSTALL); ++ dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_QUEUED); ++ if (tb[IFLA_IFALIAS]) { ++ dplane_ctx_set_ifp_desc(ctx, ++ RTA_DATA(tb[IFLA_IFALIAS])); ++ } ++ if (!tb[IFLA_MTU]) { ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "RTM_NEWLINK for interface %s(%u) without MTU set", ++ name, ifi->ifi_index); ++ return 0; ++ } ++ dplane_ctx_set_ifp_mtu(ctx, *(int *)RTA_DATA(tb[IFLA_MTU])); ++ + /* If VRF, create or update the VRF structure itself. */ + if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) { +- netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); +- vrf_id = (vrf_id_t)ifi->ifi_index; ++ netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name, ++ ctx); ++ vrf_id = ifi->ifi_index; + } + + if (tb[IFLA_MASTER]) { +@@ -1625,266 +1515,45 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) + } else + zif_slave_type = ZEBRA_IF_SLAVE_OTHER; + } ++ dplane_ctx_set_ifp_zif_slave_type(ctx, zif_slave_type); ++ dplane_ctx_set_ifp_vrf_id(ctx, vrf_id); ++ dplane_ctx_set_ifp_master_ifindex(ctx, master_infindex); ++ dplane_ctx_set_ifp_bridge_ifindex(ctx, bridge_ifindex); ++ dplane_ctx_set_ifp_bond_ifindex(ctx, bond_ifindex); ++ dplane_ctx_set_ifp_bypass(ctx, bypass); ++ dplane_ctx_set_ifp_zltype( ++ ctx, netlink_to_zebra_link_type(ifi->ifi_type)); ++ + if (vrf_is_backend_netns()) +- vrf_id = (vrf_id_t)ns_id; +- if (ifp == NULL +- || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { +- /* Add interface notification from kernel */ +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d sl_type %d master %u flags 0x%x", +- name, ifi->ifi_index, vrf_id, zif_type, +- zif_slave_type, master_infindex, +- ifi->ifi_flags); +- +- if (ifp == NULL) { +- /* unknown interface */ +- ifp = if_get_by_name(name, vrf_id, NULL); +- } else { +- /* pre-configured interface, learnt now */ +- if (ifp->vrf->vrf_id != vrf_id) +- if_update_to_new_vrf(ifp, vrf_id); +- } +- +- /* Update interface information. */ +- set_ifindex(ifp, ifi->ifi_index, zns); +- ifp->flags = ifi->ifi_flags & 0x0000fffff; +- if (!tb[IFLA_MTU]) { +- zlog_debug( +- "RTM_NEWLINK for interface %s(%u) without MTU set", +- name, ifi->ifi_index); +- return 0; +- } +- ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); +- ifp->metric = 0; +- ifp->speed = get_iflink_speed(ifp, NULL); +- ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; +- +- /* Set interface type */ +- zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); +- if (IS_ZEBRA_IF_VRF(ifp)) +- SET_FLAG(ifp->status, +- ZEBRA_INTERFACE_VRF_LOOPBACK); +- +- /* Update link. */ +- zebra_if_update_link(ifp, link_ifindex, ns_id); +- +- /* +- * Just set the @link/lower-device ifindex. During +- * nldump interfaces are not ordered in any fashion so +- * we may end up getting upper devices before lower +- * devices. We will setup the real linkage once the dump +- * is complete. +- */ +- zif = (struct zebra_if *)ifp->info; +- zif->link_ifindex = link_ifindex; +- +- ifp->ll_type = +- netlink_to_zebra_link_type(ifi->ifi_type); +- netlink_interface_update_hw_addr(tb, ifp); +- +- /* Inform clients, install any configured addresses. */ +- if_add_update(ifp); +- +- /* Extract and save L2 interface information, take +- * additional actions. */ +- netlink_interface_update_l2info( +- ifp, linkinfo[IFLA_INFO_DATA], +- 1, link_nsid); +- if (IS_ZEBRA_IF_BOND(ifp)) +- zebra_l2if_update_bond(ifp, true); +- if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) +- zebra_l2if_update_bridge_slave( +- ifp, bridge_ifindex, ns_id, +- ZEBRA_BRIDGE_NO_ACTION); +- else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) +- zebra_l2if_update_bond_slave(ifp, bond_ifindex, +- !!bypass); +- +- if (tb[IFLA_PROTO_DOWN]) { +- uint8_t protodown; +- +- protodown = *(uint8_t *)RTA_DATA( +- tb[IFLA_PROTO_DOWN]); +- netlink_proc_dplane_if_protodown(ifp->info, +- !!protodown); +- } +- } else if (ifp->vrf->vrf_id != vrf_id) { +- /* VRF change for an interface. */ +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "RTM_NEWLINK vrf-change for %s(%u) vrf_id %u -> %u flags 0x%x", +- name, ifp->ifindex, ifp->vrf->vrf_id, +- vrf_id, ifi->ifi_flags); ++ dplane_ctx_set_ifp_vrf_id(ctx, ns_id); + +- if_handle_vrf_change(ifp, vrf_id); +- } else { +- bool was_bridge_slave, was_bond_slave; +- uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION; ++ dplane_ctx_set_ifp_flags(ctx, ifi->ifi_flags & 0x0000fffff); + +- /* Interface update. */ +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "RTM_NEWLINK update for %s(%u) sl_type %d master %u flags 0x%x", +- name, ifp->ifindex, zif_slave_type, +- master_infindex, ifi->ifi_flags); ++ if (tb[IFLA_PROTO_DOWN]) { ++ dplane_ctx_set_ifp_protodown_set(ctx, true); ++ netlink_proc_dplane_if_protodown(ctx, tb); ++ } else ++ dplane_ctx_set_ifp_protodown_set(ctx, false); + +- set_ifindex(ifp, ifi->ifi_index, zns); +- if (!tb[IFLA_MTU]) { +- zlog_debug( +- "RTM_NEWLINK for interface %s(%u) without MTU set", +- name, ifi->ifi_index); +- return 0; +- } +- ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); +- ifp->metric = 0; +- +- /* Update interface type - NOTE: Only slave_type can +- * change. */ +- was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE(ifp); +- was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp); +- zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); +- +- memcpy(old_hw_addr, ifp->hw_addr, INTERFACE_HWADDR_MAX); +- +- /* Update link. */ +- zebra_if_update_link(ifp, link_ifindex, ns_id); +- +- ifp->ll_type = +- netlink_to_zebra_link_type(ifi->ifi_type); +- netlink_interface_update_hw_addr(tb, ifp); +- +- if (if_is_no_ptm_operative(ifp)) { +- ifp->flags = ifi->ifi_flags & 0x0000fffff; +- if (!if_is_no_ptm_operative(ifp)) { +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "Intf %s(%u) has gone DOWN", +- name, ifp->ifindex); +- if_down(ifp); +- rib_update(RIB_UPDATE_KERNEL); +- } else if (if_is_operative(ifp)) { +- bool mac_updated = false; +- +- /* Must notify client daemons of new +- * interface status. */ +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "Intf %s(%u) PTM up, notifying clients", +- name, ifp->ifindex); +- zebra_interface_up_update(ifp); +- +- /* Update EVPN VNI when SVI MAC change +- */ +- if (memcmp(old_hw_addr, ifp->hw_addr, +- INTERFACE_HWADDR_MAX)) +- mac_updated = true; +- if (IS_ZEBRA_IF_VLAN(ifp) +- && mac_updated) { +- struct interface *link_if; +- +- link_if = +- if_lookup_by_index_per_ns( +- zebra_ns_lookup(NS_DEFAULT), +- link_ifindex); +- if (link_if) +- zebra_vxlan_svi_up(ifp, +- link_if); +- } else if (mac_updated +- && IS_ZEBRA_IF_BRIDGE(ifp)) { +- zlog_debug( +- "Intf %s(%u) bridge changed MAC address", +- name, ifp->ifindex); +- chgflags = +- ZEBRA_BRIDGE_MASTER_MAC_CHANGE; +- } +- } +- } else { +- ifp->flags = ifi->ifi_flags & 0x0000fffff; +- if (if_is_operative(ifp)) { +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "Intf %s(%u) has come UP", +- name, ifp->ifindex); +- if_up(ifp); +- if (IS_ZEBRA_IF_BRIDGE(ifp)) +- chgflags = +- ZEBRA_BRIDGE_MASTER_UP; +- } else { +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "Intf %s(%u) has gone DOWN", +- name, ifp->ifindex); +- if_down(ifp); +- rib_update(RIB_UPDATE_KERNEL); +- } +- } +- +- /* Extract and save L2 interface information, take +- * additional actions. */ +- netlink_interface_update_l2info( +- ifp, linkinfo[IFLA_INFO_DATA], +- 0, link_nsid); +- if (IS_ZEBRA_IF_BRIDGE(ifp)) +- zebra_l2if_update_bridge(ifp, chgflags); +- if (IS_ZEBRA_IF_BOND(ifp)) +- zebra_l2if_update_bond(ifp, true); +- if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave) +- zebra_l2if_update_bridge_slave( +- ifp, bridge_ifindex, ns_id, chgflags); +- else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) +- zebra_l2if_update_bond_slave(ifp, bond_ifindex, +- !!bypass); +- +- if (tb[IFLA_PROTO_DOWN]) { +- uint8_t protodown; +- +- protodown = *(uint8_t *)RTA_DATA( +- tb[IFLA_PROTO_DOWN]); +- netlink_proc_dplane_if_protodown(ifp->info, +- !!protodown); +- } +- } ++ netlink_interface_update_hw_addr(tb, ctx); + +- zif = ifp->info; +- if (zif) { +- XFREE(MTYPE_TMP, zif->desc); +- if (desc) +- zif->desc = XSTRDUP(MTYPE_TMP, desc); +- } ++ /* Extract and save L2 interface information, take ++ * additional actions. */ ++ netlink_interface_update_l2info( ++ ctx, zif_type, linkinfo[IFLA_INFO_DATA], 1, link_nsid); + } else { +- /* Delete interface notification from kernel */ +- if (ifp == NULL) { +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "RTM_DELLINK for unknown interface %s(%u)", +- name, ifi->ifi_index); +- return 0; +- } +- + if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug("RTM_DELLINK for %s(%u)", name, +- ifp->ifindex); +- +- UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); +- +- if (IS_ZEBRA_IF_BOND(ifp)) +- zebra_l2if_update_bond(ifp, false); +- if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) +- zebra_l2if_update_bond_slave(ifp, bond_ifindex, false); +- /* Special handling for bridge or VxLAN interfaces. */ +- if (IS_ZEBRA_IF_BRIDGE(ifp)) +- zebra_l2_bridge_del(ifp); +- else if (IS_ZEBRA_IF_VXLAN(ifp)) +- zebra_l2_vxlanif_del(ifp); +- +- if_delete_update(&ifp); +- +- /* If VRF, delete the VRF structure itself. */ +- if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) +- netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); ++ zlog_debug("RTM_DELLINK for %s(%u), enqueuing to zebra", ++ name, ifi->ifi_index); ++ ++ dplane_ctx_set_op(ctx, DPLANE_OP_INTF_DELETE); ++ dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_QUEUED); ++ ++ dplane_ctx_set_ifp_bond_ifindex(ctx, bond_ifindex); + } + ++ dplane_provider_enqueue_to_zebra(ctx); ++ + return 0; + } + +@@ -1918,6 +1587,13 @@ int netlink_protodown(struct interface *ifp, bool down) + void interface_list(struct zebra_ns *zns) + { + interface_lookup_netlink(zns); ++ ++ zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_INTERFACES_READ); ++} ++ ++void interface_list_second(struct zebra_ns *zns) ++{ ++ zebra_if_update_all_links(zns); + /* We add routes for interface address, + * so we need to get the nexthop info + * from the kernel before we can do that +@@ -1925,6 +1601,8 @@ void interface_list(struct zebra_ns *zns) + netlink_nexthop_read(zns); + + interface_addr_lookup_netlink(zns); ++ ++ zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_ADDRESSES_READ); + } + + #endif /* GNU_LINUX */ +diff --git a/zebra/interface.c b/zebra/interface.c +index 1ef1c843150..667e3ac0dbf 100644 +--- a/zebra/interface.c ++++ b/zebra/interface.c +@@ -53,6 +53,7 @@ + #include "zebra/zebra_evpn_mh.h" + + DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information"); ++DEFINE_MTYPE_STATIC(ZEBRA, ZIF_DESC, "Zebra Interface Description"); + + #define ZEBRA_PTM_SUPPORT + +@@ -1222,6 +1223,9 @@ void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx, + const struct prefix *addr, *dest = NULL; + enum dplane_op_e op; + ++ if (!ifp) ++ return; ++ + op = dplane_ctx_get_op(ctx); + addr = dplane_ctx_get_intf_addr(ctx); + +@@ -1284,6 +1288,682 @@ void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx, + rib_update(RIB_UPDATE_KERNEL); + } + ++static void zebra_if_update_ctx(struct zebra_dplane_ctx *ctx, ++ struct interface *ifp) ++{ ++ enum zebra_dplane_result dp_res; ++ struct zebra_if *zif; ++ bool pd_reason_val; ++ bool down; ++ ++ dp_res = dplane_ctx_get_status(ctx); ++ pd_reason_val = dplane_ctx_get_intf_pd_reason_val(ctx); ++ down = dplane_ctx_intf_is_protodown(ctx); ++ ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug("%s: %s: if %s(%u) ctx-protodown %s ctx-reason %d", ++ __func__, dplane_op2str(dplane_ctx_get_op(ctx)), ++ ifp->name, ifp->ifindex, down ? "on" : "off", ++ pd_reason_val); ++ ++ zif = ifp->info; ++ if (!zif) { ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug("%s: if %s(%u) zebra info pointer is NULL", ++ __func__, ifp->name, ifp->ifindex); ++ return; ++ } ++ ++ if (dp_res != ZEBRA_DPLANE_REQUEST_SUCCESS) { ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug("%s: if %s(%u) dplane update failed", ++ __func__, ifp->name, ifp->ifindex); ++ return; ++ } ++ ++ /* Update our info */ ++ COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, down); ++} ++ ++static void interface_vrf_change(enum dplane_op_e op, ifindex_t ifindex, ++ const char *name, uint32_t tableid, ++ ns_id_t ns_id) ++{ ++ struct vrf *vrf; ++ struct zebra_vrf *zvrf = NULL; ++ ++ if (op == DPLANE_OP_INTF_DELETE) { ++ if (IS_ZEBRA_DEBUG_DPLANE) ++ zlog_debug("DPLANE_OP_INTF_DELETE for VRF %s(%u)", name, ++ ifindex); ++ ++ vrf = vrf_lookup_by_id((vrf_id_t)ifindex); ++ if (!vrf) { ++ flog_warn(EC_ZEBRA_VRF_NOT_FOUND, ++ "%s(%u): vrf not found", name, ifindex); ++ return; ++ } ++ ++ vrf_delete(vrf); ++ } else { ++ if (IS_ZEBRA_DEBUG_DPLANE) ++ zlog_debug( ++ "DPLANE_OP_INTF_UPDATE for VRF %s(%u) table %u", ++ name, ifindex, tableid); ++ ++ if (!vrf_lookup_by_id((vrf_id_t)ifindex)) { ++ vrf_id_t exist_id; ++ ++ exist_id = zebra_vrf_lookup_by_table(tableid, ns_id); ++ if (exist_id != VRF_DEFAULT) { ++ vrf = vrf_lookup_by_id(exist_id); ++ ++ flog_err( ++ EC_ZEBRA_VRF_MISCONFIGURED, ++ "VRF %s id %u table id overlaps existing vrf %s(%d), misconfiguration exiting", ++ name, ifindex, vrf->name, vrf->vrf_id); ++ exit(-1); ++ } ++ } ++ ++ vrf = vrf_update((vrf_id_t)ifindex, name); ++ if (!vrf) { ++ flog_err(EC_LIB_INTERFACE, "VRF %s id %u not created", ++ name, ifindex); ++ return; ++ } ++ ++ /* ++ * This is the only place that we get the actual kernel table_id ++ * being used. We need it to set the table_id of the routes ++ * we are passing to the kernel.... And to throw some totally ++ * awesome parties. that too. ++ * ++ * At this point we *must* have a zvrf because the vrf_create ++ * callback creates one. We *must* set the table id ++ * before the vrf_enable because of( at the very least ) ++ * static routes being delayed for installation until ++ * during the vrf_enable callbacks. ++ */ ++ zvrf = (struct zebra_vrf *)vrf->info; ++ zvrf->table_id = tableid; ++ ++ /* Enable the created VRF. */ ++ if (!vrf_enable(vrf)) { ++ flog_err(EC_LIB_INTERFACE, ++ "Failed to enable VRF %s id %u", name, ++ ifindex); ++ return; ++ } ++ } ++} ++ ++/* ++ * Note: on netlink systems, there should be a 1-to-1 mapping ++ * between interface names and ifindex values. ++ */ ++static void set_ifindex(struct interface *ifp, ifindex_t ifi_index, ++ struct zebra_ns *zns) ++{ ++ struct interface *oifp; ++ ++ oifp = if_lookup_by_index_per_ns(zns, ifi_index); ++ if ((oifp != NULL) && (oifp != ifp)) { ++ if (ifi_index == IFINDEX_INTERNAL) ++ flog_err( ++ EC_LIB_INTERFACE, ++ "Netlink is setting interface %s ifindex to reserved internal value %u", ++ ifp->name, ifi_index); ++ else { ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "interface index %d was renamed from %s to %s", ++ ifi_index, oifp->name, ifp->name); ++ if (if_is_up(oifp)) ++ flog_err( ++ EC_LIB_INTERFACE, ++ "interface rename detected on up interface: index %d was renamed from %s to %s, results are uncertain!", ++ ifi_index, oifp->name, ifp->name); ++ if_delete_update(&oifp); ++ } ++ } ++ if_set_index(ifp, ifi_index); ++} ++ ++static inline void zebra_if_set_ziftype(struct interface *ifp, ++ enum zebra_iftype zif_type, ++ enum zebra_slave_iftype zif_slave_type) ++{ ++ struct zebra_if *zif; ++ ++ zif = (struct zebra_if *)ifp->info; ++ zif->zif_slave_type = zif_slave_type; ++ ++ if (zif->zif_type != zif_type) { ++ zif->zif_type = zif_type; ++ /* If the if_type has been set to bond initialize ES info ++ * against it. XXX - note that we don't handle the case where ++ * a zif changes from bond to non-bond; it is really ++ * an unexpected/error condition. ++ */ ++ zebra_evpn_if_init(zif); ++ } ++} ++ ++static void interface_update_hw_addr(struct zebra_dplane_ctx *ctx, ++ struct interface *ifp) ++{ ++ int i; ++ ++ ifp->hw_addr_len = dplane_ctx_get_ifp_hw_addr_len(ctx); ++ memcpy(ifp->hw_addr, dplane_ctx_get_ifp_hw_addr(ctx), ifp->hw_addr_len); ++ ++ for (i = 0; i < ifp->hw_addr_len; i++) ++ if (ifp->hw_addr[i] != 0) ++ break; ++ ++ if (i == ifp->hw_addr_len) ++ ifp->hw_addr_len = 0; ++} ++ ++static void interface_update_l2info(struct zebra_dplane_ctx *ctx, ++ struct interface *ifp, ++ enum zebra_iftype zif_type, int add, ++ ns_id_t link_nsid) ++{ ++ const struct zebra_l2info_vxlan *vxlan_info; ++ const struct zebra_l2info_gre *gre_info; ++ ++ switch (zif_type) { ++ case ZEBRA_IF_BRIDGE: ++ zebra_l2_bridge_add_update(ifp, ++ dplane_ctx_get_ifp_bridge_info(ctx)); ++ break; ++ case ZEBRA_IF_VLAN: ++ zebra_l2_vlanif_update(ifp, dplane_ctx_get_ifp_vlan_info(ctx)); ++ zebra_evpn_acc_bd_svi_set(ifp->info, NULL, ++ !!if_is_operative(ifp)); ++ break; ++ case ZEBRA_IF_VXLAN: ++ vxlan_info = dplane_ctx_get_ifp_vxlan_info(ctx); ++ zebra_l2_vxlanif_add_update(ifp, vxlan_info, add); ++ if (link_nsid != NS_UNKNOWN && vxlan_info->ifindex_link) ++ zebra_if_update_link(ifp, vxlan_info->ifindex_link, ++ link_nsid); ++ break; ++ case ZEBRA_IF_GRE: ++ gre_info = dplane_ctx_get_ifp_gre_info(ctx); ++ zebra_l2_greif_add_update(ifp, gre_info, add); ++ if (link_nsid != NS_UNKNOWN && gre_info->ifindex_link) ++ zebra_if_update_link(ifp, gre_info->ifindex_link, ++ link_nsid); ++ break; ++ case ZEBRA_IF_OTHER: ++ case ZEBRA_IF_VRF: ++ case ZEBRA_IF_MACVLAN: ++ case ZEBRA_IF_VETH: ++ case ZEBRA_IF_BOND: ++ case ZEBRA_IF_BOND_SLAVE: ++ break; ++ } ++} ++ ++static void interface_if_protodown(struct interface *ifp, bool protodown, ++ uint32_t rc_bitfield) ++{ ++ struct zebra_if *zif = ifp->info; ++ bool old_protodown; ++ ++ old_protodown = !!ZEBRA_IF_IS_PROTODOWN(zif); ++ if (protodown == old_protodown) ++ return; ++ ++ if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_DPLANE) ++ zlog_debug("interface %s dplane change, protodown %s", ++ ifp->name, protodown ? "on" : "off"); ++ ++ /* Set protodown, respectively */ ++ COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, protodown); ++ ++ if (zebra_evpn_is_es_bond_member(ifp)) { ++ /* Check it's not already being sent to the dplane first */ ++ if (protodown && ++ CHECK_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN)) { ++ if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "bond mbr %s protodown on recv'd but already sent protodown on to the dplane", ++ ifp->name); ++ return; ++ } ++ ++ if (!protodown && ++ CHECK_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN)) { ++ if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "bond mbr %s protodown off recv'd but already sent protodown off to the dplane", ++ ifp->name); ++ return; ++ } ++ ++ if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "bond mbr %s reinstate protodown %s in the dplane", ++ ifp->name, old_protodown ? "on" : "off"); ++ ++ if (old_protodown) ++ SET_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN); ++ else ++ SET_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN); ++ } ++} ++ ++static void interface_bridge_vxlan_update(struct zebra_dplane_ctx *ctx, ++ struct interface *ifp) ++{ ++ const struct zebra_dplane_bridge_vlan_info *bvinfo; ++ ++ bvinfo = dplane_ctx_get_ifp_bridge_vlan_info(ctx); ++ ++ if (!(bvinfo->flags & DPLANE_BRIDGE_VLAN_INFO_PVID)) ++ return; ++ ++ if (IS_ZEBRA_DEBUG_DPLANE) ++ zlog_debug("Access VLAN %u for VxLAN IF %s(%u)", bvinfo->vid, ++ ifp->name, ifp->ifindex); ++ ++ zebra_l2_vxlanif_update_access_vlan(ifp, bvinfo->vid); ++} ++ ++static void interface_bridge_vlan_update(struct zebra_dplane_ctx *ctx, ++ struct interface *ifp) ++{ ++ struct zebra_if *zif = ifp->info; ++ const struct zebra_dplane_bridge_vlan_info_array *bvarray; ++ struct zebra_dplane_bridge_vlan_info bvinfo; ++ bitfield_t old_vlan_bitmap; ++ uint16_t vid_range_start = 0; ++ int32_t i; ++ ++ /* cache the old bitmap addrs */ ++ old_vlan_bitmap = zif->vlan_bitmap; ++ /* create a new bitmap space for re-eval */ ++ bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX); ++ ++ /* Could we have multiple bridge vlan infos? */ ++ bvarray = dplane_ctx_get_ifp_bridge_vlan_info_array(ctx); ++ if (!bvarray) ++ return; ++ ++ for (i = 0; i < bvarray->count; i++) { ++ bvinfo = bvarray->array[i]; ++ ++ if (bvinfo.flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_BEGIN) { ++ vid_range_start = bvinfo.vid; ++ continue; ++ } ++ ++ if (!(bvinfo.flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_END)) ++ vid_range_start = bvinfo.vid; ++ ++ zebra_vlan_bitmap_compute(ifp, vid_range_start, bvinfo.vid); ++ } ++ ++ zebra_vlan_mbr_re_eval(ifp, old_vlan_bitmap); ++ bf_free(old_vlan_bitmap); ++} ++ ++static void interface_bridge_handling(struct zebra_dplane_ctx *ctx, ++ struct interface *ifp, ++ enum zebra_iftype zif_type) ++{ ++ struct zebra_if *zif; ++ ++ if (!ifp) { ++ zlog_warn("Cannot find bridge if %s(%u)", ++ dplane_ctx_get_ifname(ctx), ++ dplane_ctx_get_ifindex(ctx)); ++ return; ++ } ++ ++ if (IS_ZEBRA_IF_VXLAN(ifp)) ++ return interface_bridge_vxlan_update(ctx, ifp); ++ ++ /* ++ * build vlan bitmap associated with this interface if that ++ * device type is interested in the vlans ++ */ ++ zif = ifp->info; ++ if (bf_is_inited(zif->vlan_bitmap)) ++ interface_bridge_vlan_update(ctx, ifp); ++} ++ ++static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) ++{ ++ enum dplane_op_e op = dplane_ctx_get_op(ctx); ++ const char *name = dplane_ctx_get_ifname(ctx); ++ ns_id_t ns_id = dplane_ctx_get_ns_id(ctx); ++ ifindex_t ifindex = dplane_ctx_get_ifindex(ctx); ++ ifindex_t bond_ifindex = dplane_ctx_get_ifp_bond_ifindex(ctx); ++ uint32_t tableid = dplane_ctx_get_ifp_table_id(ctx); ++ enum zebra_iftype zif_type = dplane_ctx_get_ifp_zif_type(ctx); ++ struct interface *ifp; ++ struct zebra_ns *zns; ++ ++ zns = zebra_ns_lookup(ns_id); ++ if (!zns) { ++ zlog_err("Where is our namespace?"); ++ return; ++ } ++ ++ if (IS_ZEBRA_DEBUG_DPLANE) ++ zlog_debug("%s for %s(%u)", dplane_op2str(op), name, ifindex); ++ ++ ifp = if_lookup_by_name_per_ns(zns, name); ++ if (op == DPLANE_OP_INTF_DELETE) { ++ /* Delete interface notification from kernel */ ++ if (ifp == NULL) { ++ if (IS_ZEBRA_DEBUG_EVENT) ++ zlog_debug( ++ "Delete LINK received for unknown interface %s(%u)", ++ name, ifindex); ++ return; ++ } ++ ++ UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); ++ ++ if (IS_ZEBRA_IF_BOND(ifp)) ++ zebra_l2if_update_bond(ifp, false); ++ if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) ++ zebra_l2if_update_bond_slave(ifp, bond_ifindex, false); ++ /* Special handling for bridge or VxLAN interfaces. */ ++ if (IS_ZEBRA_IF_BRIDGE(ifp)) ++ zebra_l2_bridge_del(ifp); ++ else if (IS_ZEBRA_IF_VXLAN(ifp)) ++ zebra_l2_vxlanif_del(ifp); ++ ++ if_delete_update(&ifp); ++ ++ if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) ++ interface_vrf_change(op, ifindex, name, tableid, ns_id); ++ } else { ++ ifindex_t master_ifindex, bridge_ifindex, bond_ifindex, ++ link_ifindex; ++ enum zebra_slave_iftype zif_slave_type; ++ uint8_t bypass; ++ uint64_t flags; ++ vrf_id_t vrf_id; ++ uint32_t mtu; ++ ns_id_t link_nsid; ++ struct zebra_if *zif; ++ bool protodown, protodown_set; ++ uint32_t rc_bitfield; ++ uint8_t old_hw_addr[INTERFACE_HWADDR_MAX]; ++ char *desc; ++ uint8_t family; ++ ++ /* If VRF, create or update the VRF structure itself. */ ++ if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) ++ interface_vrf_change(op, ifindex, name, tableid, ns_id); ++ ++ master_ifindex = dplane_ctx_get_ifp_master_ifindex(ctx); ++ zif_slave_type = dplane_ctx_get_ifp_zif_slave_type(ctx); ++ bridge_ifindex = dplane_ctx_get_ifp_bridge_ifindex(ctx); ++ bond_ifindex = dplane_ctx_get_ifp_bond_ifindex(ctx); ++ bypass = dplane_ctx_get_ifp_bypass(ctx); ++ flags = dplane_ctx_get_ifp_flags(ctx); ++ vrf_id = dplane_ctx_get_ifp_vrf_id(ctx); ++ mtu = dplane_ctx_get_ifp_mtu(ctx); ++ link_ifindex = dplane_ctx_get_ifp_link_ifindex(ctx); ++ link_nsid = dplane_ctx_get_ifp_link_nsid(ctx); ++ protodown_set = dplane_ctx_get_ifp_protodown_set(ctx); ++ protodown = dplane_ctx_get_ifp_protodown(ctx); ++ rc_bitfield = dplane_ctx_get_ifp_rc_bitfield(ctx); ++ desc = dplane_ctx_get_ifp_desc(ctx); ++ family = dplane_ctx_get_ifp_family(ctx); ++ ++#ifndef AF_BRIDGE ++ /* ++ * Work around to make free bsd happy at the moment ++ */ ++#define AF_BRIDGE 7 ++#endif ++ if (family == AF_BRIDGE) ++ return interface_bridge_handling(ctx, ifp, zif_type); ++ ++ if (ifp == NULL || ++ !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { ++ /* Add interface notification from kernel */ ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d sl_type %d master %u", ++ name, ifindex, vrf_id, zif_type, ++ zif_slave_type, master_ifindex); ++ ++ if (ifp == NULL) { ++ /* unknown interface */ ++ ifp = if_get_by_name(name, vrf_id, NULL); ++ } else { ++ /* pre-configured interface, learnt now */ ++ if (ifp->vrf->vrf_id != vrf_id) ++ if_update_to_new_vrf(ifp, vrf_id); ++ } ++ ++ /* Update interface information. */ ++ set_ifindex(ifp, ifindex, zns); ++ ifp->flags = flags; ++ ifp->mtu6 = ifp->mtu = mtu; ++ ifp->metric = 0; ++ ifp->speed = kernel_get_speed(ifp, NULL); ++ ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; ++ ++ /* Set interface type */ ++ zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); ++ if (IS_ZEBRA_IF_VRF(ifp)) ++ SET_FLAG(ifp->status, ++ ZEBRA_INTERFACE_VRF_LOOPBACK); ++ ++ /* Update link. */ ++ zebra_if_update_link(ifp, link_ifindex, link_nsid); ++ ++ /* ++ * Just set the @link/lower-device ifindex. During ++ * nldump interfaces are not ordered in any fashion so ++ * we may end up getting upper devices before lower ++ * devices. We will setup the real linkage once the dump ++ * is complete. ++ */ ++ zif = (struct zebra_if *)ifp->info; ++ zif->link_ifindex = link_ifindex; ++ ++ ifp->ll_type = dplane_ctx_get_ifp_zltype(ctx); ++ interface_update_hw_addr(ctx, ifp); ++ ++ /* Inform clients, install any configured addresses. */ ++ if_add_update(ifp); ++ ++ /* ++ * Extract and save L2 interface information, take ++ * additional actions. ++ */ ++ interface_update_l2info(ctx, ifp, zif_type, 1, ++ link_nsid); ++ if (IS_ZEBRA_IF_BOND(ifp)) ++ zebra_l2if_update_bond(ifp, true); ++ if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) ++ zebra_l2if_update_bridge_slave( ++ ifp, bridge_ifindex, ns_id, ++ ZEBRA_BRIDGE_NO_ACTION); ++ else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) ++ zebra_l2if_update_bond_slave(ifp, bond_ifindex, ++ !!bypass); ++ ++ if (protodown_set) { ++ interface_if_protodown(ifp, protodown, ++ rc_bitfield); ++ } ++ ++ if (IS_ZEBRA_IF_BRIDGE(ifp)) { ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "RTM_NEWLINK ADD for %s(%u), vlan-aware %d", ++ name, ifp->ifindex, ++ IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( ++ zif)); ++ } ++ } else if (ifp->vrf->vrf_id != vrf_id) { ++ /* VRF change for an interface. */ ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "RTM_NEWLINK vrf-change for %s(%u) vrf_id %u -> %u", ++ name, ifp->ifindex, ifp->vrf->vrf_id, ++ vrf_id); ++ ++ if_handle_vrf_change(ifp, vrf_id); ++ } else { ++ bool was_bridge_slave, was_bond_slave; ++ uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION; ++ ++ zif = ifp->info; ++ ++ /* Interface update. */ ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "RTM_NEWLINK update for %s(%u) sl_type %d master %u", ++ name, ifp->ifindex, zif_slave_type, ++ master_ifindex); ++ ++ set_ifindex(ifp, ifindex, zns); ++ ifp->mtu6 = ifp->mtu = mtu; ++ ifp->metric = 0; ++ ++ /* ++ * Update interface type - NOTE: Only slave_type can ++ * change. ++ */ ++ was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE(ifp); ++ was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp); ++ zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); ++ ++ memcpy(old_hw_addr, ifp->hw_addr, INTERFACE_HWADDR_MAX); ++ ++ /* Update link. */ ++ zebra_if_update_link(ifp, link_ifindex, link_nsid); ++ ++ ifp->ll_type = dplane_ctx_get_ifp_zltype(ctx); ++ interface_update_hw_addr(ctx, ifp); ++ ++ if (protodown_set) ++ interface_if_protodown(ifp, protodown, ++ rc_bitfield); ++ ++ if (if_is_no_ptm_operative(ifp)) { ++ ifp->flags = flags; ++ if (!if_is_no_ptm_operative(ifp) || ++ CHECK_FLAG(zif->flags, ++ ZIF_FLAG_PROTODOWN)) { ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "Intf %s(%u) has gone DOWN", ++ name, ifp->ifindex); ++ if_down(ifp); ++ rib_update(RIB_UPDATE_KERNEL); ++ } else if (if_is_operative(ifp)) { ++ bool mac_updated = false; ++ ++ /* ++ * Must notify client daemons of new ++ * interface status. ++ */ ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "Intf %s(%u) PTM up, notifying clients", ++ name, ifp->ifindex); ++ if_up(ifp); ++ ++ /* ++ * Update EVPN VNI when SVI MAC change ++ */ ++ if (memcmp(old_hw_addr, ifp->hw_addr, ++ INTERFACE_HWADDR_MAX)) ++ mac_updated = true; ++ if (IS_ZEBRA_IF_VLAN(ifp) && ++ mac_updated) { ++ struct interface *link_if; ++ ++ link_if = if_lookup_by_index_per_ns( ++ zebra_ns_lookup( ++ NS_DEFAULT), ++ link_ifindex); ++ if (link_if) ++ zebra_vxlan_svi_up( ++ ifp, link_if); ++ } else if (mac_updated && ++ IS_ZEBRA_IF_BRIDGE(ifp)) { ++ zlog_debug( ++ "Intf %s(%u) bridge changed MAC address", ++ name, ifp->ifindex); ++ chgflags = ++ ZEBRA_BRIDGE_MASTER_MAC_CHANGE; ++ } ++ } ++ } else { ++ ifp->flags = flags; ++ if (if_is_operative(ifp) && ++ !CHECK_FLAG(zif->flags, ++ ZIF_FLAG_PROTODOWN)) { ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "Intf %s(%u) has come UP", ++ name, ifp->ifindex); ++ if_up(ifp); ++ if (IS_ZEBRA_IF_BRIDGE(ifp)) ++ chgflags = ++ ZEBRA_BRIDGE_MASTER_UP; ++ } else { ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "Intf %s(%u) has gone DOWN", ++ name, ifp->ifindex); ++ if_down(ifp); ++ rib_update(RIB_UPDATE_KERNEL); ++ } ++ } ++ ++ /* ++ * Extract and save L2 interface information, take ++ * additional actions. ++ */ ++ interface_update_l2info(ctx, ifp, zif_type, 0, ++ link_nsid); ++ if (IS_ZEBRA_IF_BRIDGE(ifp)) ++ zebra_l2if_update_bridge(ifp, chgflags); ++ if (IS_ZEBRA_IF_BOND(ifp)) ++ zebra_l2if_update_bond(ifp, true); ++ if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave) ++ zebra_l2if_update_bridge_slave( ++ ifp, bridge_ifindex, ns_id, chgflags); ++ else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) ++ zebra_l2if_update_bond_slave(ifp, bond_ifindex, ++ !!bypass); ++ if (IS_ZEBRA_IF_BRIDGE(ifp)) { ++ if (IS_ZEBRA_DEBUG_KERNEL) ++ zlog_debug( ++ "RTM_NEWLINK update for %s(%u), vlan-aware %d", ++ name, ifp->ifindex, ++ IS_ZEBRA_IF_BRIDGE_VLAN_AWARE( ++ zif)); ++ } ++ } ++ ++ zif = ifp->info; ++ if (zif) { ++ XFREE(MTYPE_ZIF_DESC, zif->desc); ++ if (desc[0]) ++ zif->desc = XSTRDUP(MTYPE_ZIF_DESC, desc); ++ } ++ } ++} ++ + void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) + { + struct zebra_ns *zns; +@@ -1313,16 +1993,6 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) + } + + ifp = if_lookup_by_index_per_ns(zns, ifindex); +- if (ifp == NULL) { +- if (ifindex != -1 && ifindex != -2) { +- if (IS_ZEBRA_DEBUG_KERNEL) +- zlog_debug( +- "%s: can't find ifp at nsid %u index %d", +- __func__, ns_id, ifindex); +- +- return; +- } +- } + + switch (op) { + case DPLANE_OP_INTF_ADDR_ADD: +@@ -1333,9 +2003,17 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) + case DPLANE_OP_INTF_INSTALL: + case DPLANE_OP_INTF_UPDATE: + case DPLANE_OP_INTF_DELETE: ++ /* ++ * Queued from the dplane means it is something ++ * that we need to handle( create/delete the ++ * interface as needed ) ++ */ ++ if (dp_res == ZEBRA_DPLANE_REQUEST_QUEUED) ++ zebra_if_dplane_ifp_handling(ctx); ++ else ++ zebra_if_update_ctx(ctx, ifp); + break; + +- + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: +@@ -1379,6 +2057,8 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) + case DPLANE_OP_STARTUP_STAGE: + break; /* should never hit here */ + } ++ ++ dplane_ctx_fini(&ctx); + } + + /* Dump if address information to vty. */ +diff --git a/zebra/interface.h b/zebra/interface.h +index cc750b94b7a..c4264577c9f 100644 +--- a/zebra/interface.h ++++ b/zebra/interface.h +@@ -303,13 +303,22 @@ enum zebra_if_flags { + /* Dataplane protodown-on */ + ZIF_FLAG_PROTODOWN = (1 << 2), + ++ /* Dataplane protodown-on Queued to the dplane */ ++ ZIF_FLAG_SET_PROTODOWN = (1 << 3), ++ /* Dataplane protodown-off Queued to the dplane */ ++ ZIF_FLAG_UNSET_PROTODOWN = (1 << 4), ++ + /* LACP bypass state is set by the dataplane on a bond member + * and inherited by the bond (if one or more bond members are in + * a bypass state the bond is placed in a bypass state) + */ +- ZIF_FLAG_LACP_BYPASS = (1 << 3) ++ ZIF_FLAG_LACP_BYPASS = (1 << 5) + }; + ++#define ZEBRA_IF_IS_PROTODOWN(zif) ((zif)->flags & ZIF_FLAG_PROTODOWN) ++#define ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) \ ++ ((zif)->protodown_rc == ZEBRA_PROTODOWN_EXTERNAL) ++ + /* `zebra' daemon local interface structure. */ + struct zebra_if { + /* back pointer to the interface */ +diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c +index 40c9c25c37e..fbe41b427c8 100644 +--- a/zebra/kernel_netlink.c ++++ b/zebra/kernel_netlink.c +@@ -343,7 +343,7 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, + case RTM_NEWLINK: + return netlink_link_change(h, ns_id, startup); + case RTM_DELLINK: +- return netlink_link_change(h, ns_id, startup); ++ return 0; + case RTM_NEWNEIGH: + case RTM_DELNEIGH: + case RTM_GETNEIGH: +@@ -397,6 +397,7 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, + /* TODO */ + case RTM_NEWLINK: + case RTM_DELLINK: ++ return netlink_link_change(h, ns_id, startup); + + default: + break; +@@ -981,7 +982,6 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), + h->nlmsg_type, h->nlmsg_len, + h->nlmsg_seq, h->nlmsg_pid); + +- + /* + * Ignore messages that maybe sent from + * other actors besides the kernel +@@ -1502,7 +1502,7 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list) + netlink_socket (). */ + void kernel_init(struct zebra_ns *zns) + { +- uint32_t groups; ++ uint32_t groups, dplane_groups; + #if defined SOL_NETLINK + int one, ret; + #endif +@@ -1516,16 +1516,14 @@ void kernel_init(struct zebra_ns *zns) + * lead to confusion, so we need to convert the + * RTNLGRP_XXX to a bit position for ourself + */ +- groups = RTMGRP_LINK | +- RTMGRP_IPV4_ROUTE | +- RTMGRP_IPV4_IFADDR | +- RTMGRP_IPV6_ROUTE | +- RTMGRP_IPV6_IFADDR | +- RTMGRP_IPV4_MROUTE | +- RTMGRP_NEIGH | +- ((uint32_t) 1 << (RTNLGRP_IPV4_RULE - 1)) | +- ((uint32_t) 1 << (RTNLGRP_IPV6_RULE - 1)) | +- ((uint32_t) 1 << (RTNLGRP_NEXTHOP - 1)); ++ groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_IPV4_MROUTE | ++ RTMGRP_NEIGH | ((uint32_t)1 << (RTNLGRP_IPV4_RULE - 1)) | ++ ((uint32_t)1 << (RTNLGRP_IPV6_RULE - 1)) | ++ ((uint32_t)1 << (RTNLGRP_NEXTHOP - 1)); ++ ++ dplane_groups = (RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | ++ ((uint32_t)1 << (RTNLGRP_IPV4_NETCONF - 1)) | ++ ((uint32_t)1 << (RTNLGRP_IPV6_NETCONF - 1))); + + snprintf(zns->netlink.name, sizeof(zns->netlink.name), + "netlink-listen (NS %u)", zns->ns_id); +@@ -1561,7 +1559,8 @@ void kernel_init(struct zebra_ns *zns) + sizeof(zns->netlink_dplane_in.name), "netlink-dp-in (NS %u)", + zns->ns_id); + zns->netlink_dplane_in.sock = -1; +- if (netlink_socket(&zns->netlink_dplane_in, groups, zns->ns_id) < 0) { ++ if (netlink_socket(&zns->netlink_dplane_in, dplane_groups, zns->ns_id) < ++ 0) { + zlog_err("Failure to create %s socket", + zns->netlink_dplane_in.name); + exit(-1); +diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c +index 8d5b65b0e4e..6613cfce204 100644 +--- a/zebra/kernel_socket.c ++++ b/zebra/kernel_socket.c +@@ -1474,6 +1474,10 @@ static void routing_socket(struct zebra_ns *zns) + thread_add_read(zrouter.master, kernel_read, NULL, routing_sock, NULL); + } + ++void interface_list_second(struct zebra_ns *zns) ++{ ++} ++ + /* Exported interface function. This function simply calls + routing_socket (). */ + void kernel_init(struct zebra_ns *zns) +diff --git a/zebra/rt.h b/zebra/rt.h +index 90148d2c0d8..d75475e0408 100644 +--- a/zebra/rt.h ++++ b/zebra/rt.h +@@ -86,6 +86,7 @@ extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); + * state. + */ + extern void interface_list(struct zebra_ns *zns); ++extern void interface_list_second(struct zebra_ns *zns); + extern void kernel_init(struct zebra_ns *zns); + extern void kernel_terminate(struct zebra_ns *zns, bool complete); + extern void macfdb_read(struct zebra_ns *zns); +diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c +index fbf2620375f..dec8bbb155a 100644 +--- a/zebra/rule_netlink.c ++++ b/zebra/rule_netlink.c +@@ -413,6 +413,7 @@ int netlink_rules_read(struct zebra_ns *zns) + + ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd, + &dp_info, 0, true); ++ + return ret; + } + +diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c +index f24c4bdaf50..faa253f426b 100644 +--- a/zebra/zebra_dplane.c ++++ b/zebra/zebra_dplane.c +@@ -226,6 +226,7 @@ struct dplane_intf_info { + + bool protodown; + bool protodown_set; ++ bool pd_reason_val; + + #define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */ + #define DPLANE_INTF_SECONDARY (1 << 1) +@@ -2216,6 +2217,13 @@ void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric) + ctx->u.intf.metric = metric; + } + ++uint32_t dplane_ctx_get_intf_pd_reason_val(const struct zebra_dplane_ctx *ctx) ++{ ++ DPLANE_CTX_VALID(ctx); ++ ++ return ctx->u.intf.pd_reason_val; ++} ++ + bool dplane_ctx_intf_is_protodown(const struct zebra_dplane_ctx *ctx) + { + DPLANE_CTX_VALID(ctx); +diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h +index 381115269f7..9fec3e882ff 100644 +--- a/zebra/zebra_dplane.h ++++ b/zebra/zebra_dplane.h +@@ -100,7 +100,6 @@ enum zebra_dplane_result { + + enum zebra_dplane_startup_notifications { + ZEBRA_DPLANE_INTERFACES_READ, +- ZEBRA_DPLANE_TUNNELS_READ, + ZEBRA_DPLANE_ADDRESSES_READ, + }; + /* +@@ -387,6 +386,19 @@ uint8_t dplane_ctx_get_ifp_family(const struct zebra_dplane_ctx *ctx); + struct zebra_vxlan_vni_array; + void dplane_ctx_set_ifp_vxlan_vni_array(struct zebra_dplane_ctx *ctx, + struct zebra_vxlan_vni_array *vniarray); ++ ++/* ++ * These defines mirror the values for bridge values in linux ++ * at this point since we only have a linux implementation ++ * we don't need to do any type of translation. Let's just ++ * pass these through and use them ++ */ ++#define DPLANE_BRIDGE_VLAN_INFO_PVID \ ++ (1 << 1) /* VLAN is PVID, ingress untagged */ ++#define DPLANE_BRIDGE_VLAN_INFO_RANGE_BEGIN \ ++ (1 << 3) /* VLAN is start of vlan range */ ++#define DPLANE_BRIDGE_VLAN_INFO_RANGE_END \ ++ (1 << 4) /* VLAN is end of vlan range */ + const struct zebra_vxlan_vni_array * + dplane_ctx_get_ifp_vxlan_vni_array(const struct zebra_dplane_ctx *ctx); + struct zebra_dplane_bridge_vlan_info { +diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c +index 07bbc6e3bc4..4ad262a21da 100644 +--- a/zebra/zebra_l2.c ++++ b/zebra/zebra_l2.c +@@ -258,7 +258,7 @@ void zebra_l2if_update_bond(struct interface *ifp, bool add) + * map slaves (if any) to the bridge. + */ + void zebra_l2_bridge_add_update(struct interface *ifp, +- struct zebra_l2info_bridge *bridge_info) ++ const struct zebra_l2info_bridge *bridge_info) + { + struct zebra_if *zif; + +@@ -293,7 +293,7 @@ void zebra_l2if_update_bridge(struct interface *ifp, uint8_t chgflags) + * VLAN Id and this cannot change. + */ + void zebra_l2_vlanif_update(struct interface *ifp, +- struct zebra_l2info_vlan *vlan_info) ++ const struct zebra_l2info_vlan *vlan_info) + { + struct zebra_if *zif; + +@@ -310,7 +310,7 @@ void zebra_l2_vlanif_update(struct interface *ifp, + * clients about GRE information. + */ + void zebra_l2_greif_add_update(struct interface *ifp, +- struct zebra_l2info_gre *gre_info, int add) ++ const struct zebra_l2info_gre *gre_info, int add) + { + struct zebra_if *zif; + struct in_addr old_vtep_ip; +@@ -337,7 +337,8 @@ void zebra_l2_greif_add_update(struct interface *ifp, + * IP and VLAN mapping, but the latter is handled separately. + */ + void zebra_l2_vxlanif_add_update(struct interface *ifp, +- struct zebra_l2info_vxlan *vxlan_info, int add) ++ const struct zebra_l2info_vxlan *vxlan_info, ++ int add) + { + struct zebra_if *zif; + struct in_addr old_vtep_ip; +diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h +index 48b022311f5..b54253f1d9d 100644 +--- a/zebra/zebra_l2.h ++++ b/zebra/zebra_l2.h +@@ -70,6 +70,53 @@ struct zebra_l2info_gre { + ns_id_t link_nsid; + }; + ++struct zebra_vxlan_vni { ++ vni_t vni; /* VNI */ ++ vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */ ++ struct in_addr mcast_grp; ++ uint16_t flags; ++}; ++ ++struct zebra_vxlan_vni_array { ++ uint16_t count; ++ struct zebra_vxlan_vni vnis[0]; ++}; ++ ++enum { ZEBRA_VXLAN_IF_VNI = 0, /* per vni vxlan if */ ++ ZEBRA_VXLAN_IF_SVD /* single vxlan device */ ++}; ++ ++struct zebra_vxlan_if_vlan_ctx { ++ vlanid_t vid; ++ struct zebra_vxlan_vni *vni; ++}; ++ ++struct zebra_vxlan_if_update_ctx { ++ uint16_t chgflags; ++ struct in_addr old_vtep_ip; ++ struct zebra_vxlan_vni old_vni; ++ struct hash *old_vni_table; ++}; ++ ++struct zebra_vxlan_if_ctx { ++ /* input */ ++ struct zebra_if *zif; ++ int (*func)(struct zebra_if *zif, struct zebra_vxlan_vni *vni, ++ void *arg); ++ ++ /* input-output */ ++ void *arg; ++}; ++ ++struct zebra_vxlan_vni_info { ++ int iftype; ++ union { ++ struct zebra_vxlan_vni vni; /* per vni vxlan device vni info */ ++ struct hash ++ *vni_table; /* table of vni's assocated with this if */ ++ }; ++}; ++ + /* zebra L2 interface information - VXLAN interface */ + struct zebra_l2info_vxlan { + vni_t vni; /* VNI */ +@@ -107,17 +154,19 @@ extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave, + struct zebra_ns *zns); + extern void + zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave); +-extern void zebra_l2_bridge_add_update(struct interface *ifp, +- struct zebra_l2info_bridge *bridge_info); ++extern void ++zebra_l2_bridge_add_update(struct interface *ifp, ++ const struct zebra_l2info_bridge *bridge_info); + extern void zebra_l2_bridge_del(struct interface *ifp); + extern void zebra_l2_vlanif_update(struct interface *ifp, +- struct zebra_l2info_vlan *vlan_info); ++ const struct zebra_l2info_vlan *vlan_info); + extern void zebra_l2_greif_add_update(struct interface *ifp, +- struct zebra_l2info_gre *vxlan_info, ++ const struct zebra_l2info_gre *vxlan_info, + int add); +-extern void zebra_l2_vxlanif_add_update(struct interface *ifp, +- struct zebra_l2info_vxlan *vxlan_info, +- int add); ++extern void ++zebra_l2_vxlanif_add_update(struct interface *ifp, ++ const struct zebra_l2info_vxlan *vxlan_info, ++ int add); + extern void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp, + vlanid_t access_vlan); + extern void zebra_l2_greif_del(struct interface *ifp); +diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c +index 13fd9724993..01f7fbdfc52 100644 +--- a/zebra/zebra_ns.c ++++ b/zebra/zebra_ns.c +@@ -37,6 +37,7 @@ + #include "rib.h" + #include "table_manager.h" + #include "zebra_errors.h" ++#include "zebra_dplane.h" + + extern struct zebra_privs_t zserv_privs; + +@@ -115,6 +116,31 @@ int zebra_ns_disabled(struct ns *ns) + return zebra_ns_disable_internal(zns, true); + } + ++void zebra_ns_startup_continue(struct zebra_dplane_ctx *ctx) ++{ ++ struct zebra_ns *zns = zebra_ns_lookup(dplane_ctx_get_ns_id(ctx)); ++ enum zebra_dplane_startup_notifications spot; ++ ++ if (!zns) { ++ zlog_err("%s: No Namespace associated with %u", __func__, ++ dplane_ctx_get_ns_id(ctx)); ++ return; ++ } ++ ++ spot = dplane_ctx_get_startup_spot(ctx); ++ ++ switch (spot) { ++ case ZEBRA_DPLANE_INTERFACES_READ: ++ interface_list_second(zns); ++ break; ++ case ZEBRA_DPLANE_ADDRESSES_READ: ++ route_read(zns); ++ ++ kernel_read_pbr_rules(zns); ++ break; ++ } ++} ++ + /* Do global enable actions - open sockets, read kernel config etc. */ + int zebra_ns_enable(ns_id_t ns_id, void **info) + { +@@ -125,8 +151,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info) + kernel_init(zns); + zebra_dplane_ns_enable(zns, true); + interface_list(zns); +- route_read(zns); +- kernel_read_pbr_rules(zns); + + return 0; + } +diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h +index 0519e1d5b33..037097a4f0c 100644 +--- a/zebra/zebra_ns.h ++++ b/zebra/zebra_ns.h +@@ -80,6 +80,8 @@ int zebra_ns_final_shutdown(struct ns *ns, + void **param_out __attribute__((unused))); + int zebra_ns_config_write(struct vty *vty, struct ns *ns); + ++void zebra_ns_startup_continue(struct zebra_dplane_ctx *ctx); ++ + #ifdef __cplusplus + } + #endif +diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c +index 377f9ce5a14..8a63d29d1d2 100644 +--- a/zebra/zebra_rib.c ++++ b/zebra/zebra_rib.c +@@ -4323,10 +4323,12 @@ static int rib_process_dplane_results(struct thread *thread) + case DPLANE_OP_NEIGH_TABLE_UPDATE: + case DPLANE_OP_GRE_SET: + case DPLANE_OP_NONE: +- case DPLANE_OP_STARTUP_STAGE: + /* Don't expect this: just return the struct? */ + dplane_ctx_fini(&ctx); + break; ++ case DPLANE_OP_STARTUP_STAGE: ++ zebra_ns_startup_continue(ctx); ++ break; + + } /* Dispatch by op code */ + diff --git a/src/sonic-frr/patch/0020-zebra-Prevent-installation-of-connected-multiple-times.patch b/src/sonic-frr/patch/0020-zebra-Prevent-installation-of-connected-multiple-times.patch new file mode 100644 index 00000000000..b2566266088 --- /dev/null +++ b/src/sonic-frr/patch/0020-zebra-Prevent-installation-of-connected-multiple-times.patch @@ -0,0 +1,131 @@ +From 65da6c9ef51c945a0cc90688a6eab22b3ced8cad Mon Sep 17 00:00:00 2001 +From: Donald Sharp +Date: Fri, 2 Oct 2020 14:49:09 -0400 +Subject: [PATCH] zebra: Prevent installation of connected multiple times + +With recent changes to interface up mechanics in if_netlink.c +FRR was receiving as many as 4 up events for an interface +on ifdown/ifup events. This was causing timing issues +in FRR based upon some fun timings. Remove this from +happening. + +Ticket: CM-31623 +Signed-off-by: Donald Sharp +--- + zebra/interface.c | 15 +++++++++------ + zebra/interface.h | 2 +- + zebra/zebra_ptm.c | 6 +++--- + 3 files changed, 13 insertions(+), 10 deletions(-) + +diff --git a/zebra/interface.c b/zebra/interface.c +index 667e3ac0dbf..96e95bf677a 100644 +--- a/zebra/interface.c ++++ b/zebra/interface.c +@@ -492,7 +492,7 @@ void if_flags_update(struct interface *ifp, uint64_t newflags) + /* inoperative -> operative? */ + ifp->flags = newflags; + if (if_is_operative(ifp)) +- if_up(ifp); ++ if_up(ifp, true); + } + } + +@@ -1021,7 +1021,7 @@ bool if_nhg_dependents_is_empty(const struct interface *ifp) + } + + /* Interface is up. */ +-void if_up(struct interface *ifp) ++void if_up(struct interface *ifp, bool install_connected) + { + struct zebra_if *zif; + struct interface *link_if; +@@ -1053,7 +1053,8 @@ void if_up(struct interface *ifp) + #endif + + /* Install connected routes to the kernel. */ +- if_install_connected(ifp); ++ if (install_connected) ++ if_install_connected(ifp); + + /* Handle interface up for specific types for EVPN. Non-VxLAN interfaces + * are checked to see if (remote) neighbor entries need to be installed +@@ -1857,6 +1858,8 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) + rc_bitfield); + + if (if_is_no_ptm_operative(ifp)) { ++ bool is_up = if_is_operative(ifp); ++ + ifp->flags = flags; + if (!if_is_no_ptm_operative(ifp) || + CHECK_FLAG(zif->flags, +@@ -1878,7 +1881,7 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) + zlog_debug( + "Intf %s(%u) PTM up, notifying clients", + name, ifp->ifindex); +- if_up(ifp); ++ if_up(ifp, !is_up); + + /* + * Update EVPN VNI when SVI MAC change +@@ -1915,7 +1918,7 @@ static void zebra_if_dplane_ifp_handling(struct zebra_dplane_ctx *ctx) + zlog_debug( + "Intf %s(%u) has come UP", + name, ifp->ifindex); +- if_up(ifp); ++ if_up(ifp, true); + if (IS_ZEBRA_IF_BRIDGE(ifp)) + chgflags = + ZEBRA_BRIDGE_MASTER_UP; +@@ -3448,7 +3451,7 @@ int if_linkdetect(struct interface *ifp, bool detect) + + /* Interface may come up after disabling link detection */ + if (if_is_operative(ifp) && !if_was_operative) +- if_up(ifp); ++ if_up(ifp, true); + } + /* FIXME: Will defer status change forwarding if interface + does not come down! */ +diff --git a/zebra/interface.h b/zebra/interface.h +index c4264577c9f..92d756b772d 100644 +--- a/zebra/interface.h ++++ b/zebra/interface.h +@@ -485,7 +485,7 @@ extern void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp, + extern void if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(struct interface *ifp); + extern void if_delete_update(struct interface **ifp); + extern void if_add_update(struct interface *ifp); +-extern void if_up(struct interface *); ++extern void if_up(struct interface *ifp, bool install_connected); + extern void if_down(struct interface *); + extern void if_refresh(struct interface *); + extern void if_flags_update(struct interface *, uint64_t); +diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c +index 32edb78c7d7..b79e31ea5d1 100644 +--- a/zebra/zebra_ptm.c ++++ b/zebra/zebra_ptm.c +@@ -354,7 +354,7 @@ DEFUN (no_zebra_ptm_enable_if, + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("%s: Bringing up interface %s", + __func__, ifp->name); +- if_up(ifp); ++ if_up(ifp, true); + } + } + +@@ -557,7 +557,7 @@ static int zebra_ptm_handle_cbl_msg(void *arg, void *in_ctxt, + ifp->ptm_status = ZEBRA_PTM_STATUS_UP; + if (ifp->ptm_enable && if_is_no_ptm_operative(ifp) + && send_linkup) +- if_up(ifp); ++ if_up(ifp, true); + } else if (!strcmp(cbl_str, ZEBRA_PTM_FAIL_STR) + && (ifp->ptm_status != ZEBRA_PTM_STATUS_DOWN)) { + ifp->ptm_status = ZEBRA_PTM_STATUS_DOWN; +@@ -1169,7 +1169,7 @@ void zebra_ptm_reset_status(int ptm_disable) + zlog_debug( + "%s: Bringing up interface %s", + __func__, ifp->name); +- if_up(ifp); ++ if_up(ifp, true); + } + } + } diff --git a/src/sonic-frr/patch/series b/src/sonic-frr/patch/series index d7d7046ee6f..763d2c83776 100644 --- a/src/sonic-frr/patch/series +++ b/src/sonic-frr/patch/series @@ -8,7 +8,15 @@ 0008-Link-local-scope-was-not-set-while-binding-socket-for-bgp-ipv6-link-local-neighbors.patch Disable-ipv6-src-address-test-in-pceplib.patch cross-compile-changes.patch -0009-ignore-route-from-default-table.patch +0009-ignore-route-from-default-table-and-prevent-po.patch 0010-zebra-Note-when-the-netlink-DUMP-command-is-interrup.patch 0011-bgpd-enhanced-capability-is-always-turned-on-for-int.patch 0012-Ensure-ospf_apiclient_lsa_originate-cannot-accidently-write-into-stack.patch +0013-zebra-fix-use-after-deletion-event-in-freebsd.patch +0014-zebra-Rename-vrf_lookup_by_tableid-to-zebra_vrf_lookup.patch +0015-zebra-Move-protodown_r_bit-to-a-better-spot.patch +0016-zebra-Remove-unused-add-variable.patch +0017-zebra-Remove-duplicate-function-for-netlink-interface.patch +0018-zebra-Add-code-to-get-set-interface-to-pass-up-from-dplane.patch +0019-zebra-Use-zebra-dplane-for-RTM-link-and-addr.patch +0020-zebra-Prevent-installation-of-connected-multiple-times.patch