Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zebra, lib: use internal rbtree for per-NS tree of ifps #17297

Merged
merged 9 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions isisd/isis_route.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#ifndef _ZEBRA_ISIS_ROUTE_H
#define _ZEBRA_ISIS_ROUTE_H

#include "lib/table.h"
#include "lib/nexthop.h"

struct isis_nexthop {
Expand Down
6 changes: 0 additions & 6 deletions lib/if.c
Original file line number Diff line number Diff line change
Expand Up @@ -1002,12 +1002,6 @@ void if_terminate(struct vrf *vrf)

while (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) {
ifp = RB_ROOT(if_name_head, &vrf->ifaces_by_name);

if (ifp->node) {
ifp->node->info = NULL;
route_unlock_node(ifp->node);
ifp->node = NULL;
}
if_delete(&ifp);
}
}
Expand Down
2 changes: 0 additions & 2 deletions lib/if.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,6 @@ struct interface {
struct if_data stats;
#endif /* HAVE_NET_RT_IFLIST */

struct route_node *node;

struct vrf *vrf;

/*
Expand Down
66 changes: 42 additions & 24 deletions zebra/if_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1568,46 +1568,64 @@ static int netlink_request_tunneldump(struct zebra_ns *zns, int family,
return netlink_request(&zns->netlink_cmd, &req);
}

/* Prototype for tunneldump walker */
static int tunneldump_walk_cb(struct interface *ifp, void *arg);

struct tunneldump_ctx {
struct zebra_ns *zns;
struct zebra_dplane_info *dp_info;
int ret;
};

/*
* Currently we only ask for vxlan l3svd vni information.
* In the future this can be expanded.
*/
int netlink_tunneldump_read(struct zebra_ns *zns)
{
int ret = 0;
struct tunneldump_ctx ctx = {};
struct zebra_dplane_info dp_info;
struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct nlsock *netlink_cmd = &zns->netlink_cmd;

zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);

for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
if (!tmp_if)
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
continue;
/* Set up context and call iterator */
ctx.zns = zns;
ctx.dp_info = &dp_info;

ret = netlink_request_tunneldump(zns, PF_BRIDGE,
tmp_if->ifindex);
if (ret < 0) {
route_unlock_node(rn);
return ret;
}
zebra_ns_ifp_walk(zns, tunneldump_walk_cb, &ctx);

ret = netlink_parse_info(netlink_link_change, netlink_cmd,
&dp_info, 0, true);
ret = ctx.ret;

if (ret < 0) {
route_unlock_node(rn);
return ret;
}
return ret;
}

static int tunneldump_walk_cb(struct interface *ifp, void *arg)
{
int ret;
struct tunneldump_ctx *ctx = arg;
struct zebra_if *zif;

zif = ifp->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
goto done;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why goto here? Especially since we have other returns directly in the middle?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just an artifact of moving the code from the inline loop to the callback I guess. we need to be able to have "special" continue path for this clause, and then the "normal" continue path for non-error cases at the end of the callback?


ret = netlink_request_tunneldump(ctx->zns, PF_BRIDGE, ifp->ifindex);
if (ret < 0) {
ctx->ret = ret;
return NS_WALK_STOP;
}

return 0;
ret = netlink_parse_info(netlink_link_change, &(ctx->zns->netlink_cmd),
ctx->dp_info, 0, true);

if (ret < 0) {
ctx->ret = ret;
return NS_WALK_STOP;
}

done:
return NS_WALK_CONTINUE;
}

static uint8_t netlink_get_dplane_vlan_state(uint8_t state)
Expand Down
149 changes: 49 additions & 100 deletions zebra/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information");
DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp),
(vty, ifp));

DEFINE_MTYPE(ZEBRA, ZIF_DESC, "Intf desc");
DEFINE_MTYPE_STATIC(ZEBRA, ZIF_DESC, "Intf desc");

static void if_down_del_nbr_connected(struct interface *ifp);

Expand Down Expand Up @@ -215,6 +215,8 @@ static int if_zebra_delete_hook(struct interface *ifp)
if_nhg_dependents_release(ifp);
nhg_connected_tree_free(&zebra_if->nhg_dependents);

zebra_ns_unlink_ifp(ifp);

XFREE(MTYPE_ZIF_DESC, zebra_if->desc);

EVENT_OFF(zebra_if->speed_update);
Expand All @@ -225,81 +227,26 @@ static int if_zebra_delete_hook(struct interface *ifp)
return 0;
}

/* Build the table key */
static void if_build_key(uint32_t ifindex, struct prefix *p)
{
p->family = AF_INET;
p->prefixlen = IPV4_MAX_BITLEN;
p->u.prefix4.s_addr = ifindex;
}

/* Link an interface in a per NS interface tree */
struct interface *if_link_per_ns(struct zebra_ns *ns, struct interface *ifp)
{
struct prefix p;
struct route_node *rn;

if (ifp->ifindex == IFINDEX_INTERNAL)
return NULL;

if_build_key(ifp->ifindex, &p);
rn = route_node_get(ns->if_table, &p);
if (rn->info) {
ifp = (struct interface *)rn->info;
route_unlock_node(rn); /* get */
return ifp;
}

rn->info = ifp;
ifp->node = rn;

return ifp;
}

/* Delete a VRF. This is called in vrf_terminate(). */
void if_unlink_per_ns(struct interface *ifp)
{
if (!ifp->node)
return;

ifp->node->info = NULL;
route_unlock_node(ifp->node);
ifp->node = NULL;
}

/* Look up an interface by identifier within a NS */
struct interface *if_lookup_by_index_per_ns(struct zebra_ns *ns,
uint32_t ifindex)
{
struct prefix p;
struct route_node *rn;
struct interface *ifp = NULL;

if_build_key(ifindex, &p);
rn = route_node_lookup(ns->if_table, &p);
if (rn) {
ifp = (struct interface *)rn->info;
route_unlock_node(rn); /* lookup */
}
ifp = zebra_ns_lookup_ifp(ns, ifindex);

return ifp;
}

/* Look up an interface by name within a NS */
struct interface *if_lookup_by_name_per_ns(struct zebra_ns *ns,
const char *ifname)
{
struct route_node *rn;
struct interface *ifp;

for (rn = route_top(ns->if_table); rn; rn = route_next(rn)) {
ifp = (struct interface *)rn->info;
if (ifp && strcmp(ifp->name, ifname) == 0) {
route_unlock_node(rn);
return (ifp);
}
}
ifp = zebra_ns_lookup_ifp_name(ns, ifname);

return NULL;
return ifp;
}

struct interface *if_lookup_by_index_per_nsid(ns_id_t ns_id, uint32_t ifindex)
Expand Down Expand Up @@ -571,7 +518,8 @@ void if_add_update(struct interface *ifp)
zns = zvrf->zns;
else
zns = zebra_ns_lookup(NS_DEFAULT);
if_link_per_ns(zns, ifp);

zebra_ns_link_ifp(zns, ifp);
if_data = ifp->info;
assert(if_data);

Expand Down Expand Up @@ -776,15 +724,14 @@ void if_delete_update(struct interface **pifp)
/* Send out notification on interface delete. */
zebra_interface_delete_update(ifp);

if_unlink_per_ns(ifp);
zebra_ns_unlink_ifp(ifp);

/* Update ifindex after distributing the delete message. This is in
case any client needs to have the old value of ifindex available
while processing the deletion. Each client daemon is responsible
for setting ifindex to IFINDEX_INTERNAL after processing the
interface deletion message. */
if_set_index(ifp, IFINDEX_INTERNAL);
ifp->node = NULL;

UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);

Expand Down Expand Up @@ -1082,50 +1029,52 @@ void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex,
}

/*
* during initial link dump kernel does not order lower devices before
* upper devices so we need to fixup link dependencies at the end of dump
* Callback for per-ns link fixup iteration
*/
void zebra_if_update_all_links(struct zebra_ns *zns)
static int zif_link_fixup_cb(struct interface *ifp, void *arg)
{
struct route_node *rn;
struct interface *ifp;
struct zebra_if *zif;

if (IS_ZEBRA_DEBUG_KERNEL)
zlog_info("fixup link dependencies");
zif = ifp->info;
/* update bond-member to bond linkages */
if ((IS_ZEBRA_IF_BOND_SLAVE(ifp)) &&
(zif->bondslave_info.bond_ifindex != IFINDEX_INTERNAL) &&
!zif->bondslave_info.bond_if) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("bond mbr %s map to bond %d", zif->ifp->name,
zif->bondslave_info.bond_ifindex);
zebra_l2_map_slave_to_bond(zif, ifp->vrf->vrf_id);
}

for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
ifp = (struct interface *)rn->info;
if (!ifp)
continue;
zif = ifp->info;
/* update bond-member to bond linkages */
if ((IS_ZEBRA_IF_BOND_SLAVE(ifp))
&& (zif->bondslave_info.bond_ifindex != IFINDEX_INTERNAL)
&& !zif->bondslave_info.bond_if) {
if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("bond mbr %s map to bond %d",
zif->ifp->name,
zif->bondslave_info.bond_ifindex);
zebra_l2_map_slave_to_bond(zif, ifp->vrf->vrf_id);
}
/* update SVI linkages */
if ((zif->link_ifindex != IFINDEX_INTERNAL) && !zif->link) {
zif->link = if_lookup_by_index_per_nsid(zif->link_nsid,
zif->link_ifindex);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("interface %s/%d's lower fixup to %s/%d",
ifp->name, ifp->ifindex,
zif->link ? zif->link->name : "unk",
zif->link_ifindex);
}

/* update SVI linkages */
if ((zif->link_ifindex != IFINDEX_INTERNAL) && !zif->link) {
zif->link = if_lookup_by_index_per_nsid(
zif->link_nsid, zif->link_ifindex);
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("interface %s/%d's lower fixup to %s/%d",
ifp->name, ifp->ifindex,
zif->link?zif->link->name:"unk",
zif->link_ifindex);
}
/* Update VLAN<=>SVI map */
if (IS_ZEBRA_IF_VLAN(ifp))
zebra_evpn_acc_bd_svi_set(zif, NULL,
!!if_is_operative(ifp));

/* Update VLAN<=>SVI map */
if (IS_ZEBRA_IF_VLAN(ifp))
zebra_evpn_acc_bd_svi_set(zif, NULL,
!!if_is_operative(ifp));
}
return NS_WALK_CONTINUE;
}

/*
* during initial link dump kernel does not order lower devices before
* upper devices so we need to fixup link dependencies at the end of dump
*/
void zebra_if_update_all_links(struct zebra_ns *zns)
{
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("fixup link dependencies");

zebra_ns_ifp_walk(zns, zif_link_fixup_cb, NULL);
}

static bool if_ignore_set_protodown(const struct interface *ifp, bool new_down,
Expand Down
8 changes: 3 additions & 5 deletions zebra/interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,6 @@ enum zebra_if_flags {
#define ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) \
((zif)->protodown_rc == ZEBRA_PROTODOWN_EXTERNAL)

/* Mem type for zif desc */
DECLARE_MTYPE(ZIF_DESC);

/* `zebra' daemon local interface structure. */
struct zebra_if {
/* back pointer to the interface */
Expand Down Expand Up @@ -215,6 +212,9 @@ struct zebra_if {
char neigh_mac[6];
struct in6_addr v6_2_v4_ll_addr6;

/* Linkage for per-vrf/per-NS ifp container */
struct ifp_tree_link *ns_tree_link;

/* The description of the interface */
char *desc;
};
Expand Down Expand Up @@ -262,12 +262,10 @@ extern void zebra_if_init(void);
extern struct interface *if_lookup_by_index_per_ns(struct zebra_ns *, uint32_t);
extern struct interface *if_lookup_by_name_per_ns(struct zebra_ns *,
const char *);
extern struct interface *if_link_per_ns(struct zebra_ns *, struct interface *);
extern struct interface *if_lookup_by_index_per_nsid(ns_id_t nsid,
uint32_t ifindex);
extern const char *ifindex2ifname_per_ns(struct zebra_ns *, unsigned int);

extern void if_unlink_per_ns(struct interface *);
extern void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *fip,
char mac[6],
struct in6_addr *address,
Expand Down
Loading
Loading