mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
Merge pull request #17297 from mjstapp/mjs_ifp_table
zebra, lib: use internal rbtree for per-NS tree of ifps
This commit is contained in:
commit
ac6314d380
|
@ -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 {
|
||||
|
|
6
lib/if.c
6
lib/if.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
2
lib/if.h
2
lib/if.h
|
@ -295,8 +295,6 @@ struct interface {
|
|||
struct if_data stats;
|
||||
#endif /* HAVE_NET_RT_IFLIST */
|
||||
|
||||
struct route_node *node;
|
||||
|
||||
struct vrf *vrf;
|
||||
|
||||
/*
|
||||
|
|
|
@ -1568,6 +1568,15 @@ 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.
|
||||
|
@ -1575,39 +1584,48 @@ static int netlink_request_tunneldump(struct zebra_ns *zns, int family,
|
|||
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;
|
||||
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -225,62 +227,14 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -288,18 +242,11 @@ struct interface *if_lookup_by_index_per_ns(struct zebra_ns *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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -776,7 +724,7 @@ 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
|
||||
|
@ -784,7 +732,6 @@ void if_delete_update(struct interface **pifp)
|
|||
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);
|
||||
|
||||
|
@ -1081,51 +1028,53 @@ void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex,
|
|||
link_ifindex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for per-ns link fixup iteration
|
||||
*/
|
||||
static int zif_link_fixup_cb(struct interface *ifp, void *arg)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
|
||||
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 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)
|
||||
{
|
||||
struct route_node *rn;
|
||||
struct interface *ifp;
|
||||
struct zebra_if *zif;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_info("fixup link dependencies");
|
||||
zlog_debug("fixup link dependencies");
|
||||
|
||||
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 VLAN<=>SVI map */
|
||||
if (IS_ZEBRA_IF_VLAN(ifp))
|
||||
zebra_evpn_acc_bd_svi_set(zif, NULL,
|
||||
!!if_is_operative(ifp));
|
||||
}
|
||||
zebra_ns_ifp_walk(zns, zif_link_fixup_cb, NULL);
|
||||
}
|
||||
|
||||
static bool if_ignore_set_protodown(const struct interface *ifp, bool new_down,
|
||||
|
|
|
@ -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 */
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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,
|
||||
|
|
|
@ -610,70 +610,47 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
|
|||
return;
|
||||
}
|
||||
|
||||
static int zebra_evpn_map_vlan_ns(struct ns *ns,
|
||||
void *_in_param,
|
||||
void **_p_zevpn)
|
||||
/* Callback for per-NS ifp walk */
|
||||
static int zebra_evpn_map_vlan_ns(struct interface *tmp_if, void *_in_param)
|
||||
{
|
||||
int found = 0;
|
||||
struct zebra_ns *zns = ns->info;
|
||||
struct route_node *rn;
|
||||
bool found = false;
|
||||
struct interface *br_if;
|
||||
struct zebra_evpn **p_zevpn = (struct zebra_evpn **)_p_zevpn;
|
||||
struct zebra_evpn *zevpn;
|
||||
struct interface *tmp_if = NULL;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_from_svi_param *in_param =
|
||||
(struct zebra_from_svi_param *)_in_param;
|
||||
vlanid_t vid;
|
||||
struct zebra_from_svi_param *in_param = _in_param;
|
||||
vni_t vni_id = 0;
|
||||
uint8_t bridge_vlan_aware;
|
||||
|
||||
assert(p_zevpn && in_param);
|
||||
assert(in_param);
|
||||
|
||||
br_if = in_param->br_if;
|
||||
assert(br_if);
|
||||
zif = in_param->zif;
|
||||
assert(zif);
|
||||
vid = in_param->vid;
|
||||
bridge_vlan_aware = in_param->bridge_vlan_aware;
|
||||
|
||||
if (bridge_vlan_aware) {
|
||||
vni_id = zebra_l2_bridge_if_vni_find(zif, vid);
|
||||
if (vni_id)
|
||||
found = 1;
|
||||
} else {
|
||||
/*
|
||||
* See if this interface (or interface plus VLAN Id) maps to a
|
||||
* VxLAN
|
||||
*/
|
||||
/* TODO: Optimize with a hash. */
|
||||
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;
|
||||
if (!if_is_operative(tmp_if))
|
||||
continue;
|
||||
/*
|
||||
* See if this interface (or interface plus VLAN Id) maps to a
|
||||
* VxLAN
|
||||
*/
|
||||
/* TODO: Optimize with a hash. */
|
||||
zif = tmp_if->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
||||
goto done;
|
||||
if (!if_is_operative(tmp_if))
|
||||
goto done;
|
||||
|
||||
if (zif->brslave_info.br_if != br_if)
|
||||
continue;
|
||||
if (zif->brslave_info.br_if != br_if)
|
||||
goto done;
|
||||
|
||||
vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
|
||||
if (vni_id) {
|
||||
found = 1;
|
||||
route_unlock_node(rn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
|
||||
if (vni_id)
|
||||
found = true;
|
||||
|
||||
done:
|
||||
if (!found)
|
||||
return NS_WALK_CONTINUE;
|
||||
|
||||
zevpn = zebra_evpn_lookup(vni_id);
|
||||
*p_zevpn = zevpn;
|
||||
in_param->zevpn = zevpn;
|
||||
return NS_WALK_STOP;
|
||||
}
|
||||
|
||||
|
@ -685,42 +662,39 @@ struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp,
|
|||
struct interface *br_if, vlanid_t vid)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
struct zebra_evpn **p_zevpn;
|
||||
struct zebra_evpn *zevpn = NULL;
|
||||
struct zebra_from_svi_param in_param;
|
||||
struct zebra_from_svi_param in_param = {};
|
||||
vni_t vni_id = 0;
|
||||
|
||||
/* Determine if bridge is VLAN-aware or not */
|
||||
zif = br_if->info;
|
||||
assert(zif);
|
||||
in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
|
||||
|
||||
/* Special case for vlan */
|
||||
if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif)) {
|
||||
vni_id = zebra_l2_bridge_if_vni_find(zif, vid);
|
||||
if (vni_id)
|
||||
return zebra_evpn_lookup(vni_id);
|
||||
}
|
||||
|
||||
in_param.vid = vid;
|
||||
in_param.br_if = br_if;
|
||||
in_param.zif = zif;
|
||||
p_zevpn = &zevpn;
|
||||
|
||||
ns_walk_func(zebra_evpn_map_vlan_ns, (void *)&in_param, (void **)p_zevpn);
|
||||
return zevpn;
|
||||
zebra_ns_ifp_walk_all(zebra_evpn_map_vlan_ns, &in_param);
|
||||
|
||||
return in_param.zevpn;
|
||||
}
|
||||
|
||||
static int zebra_evpn_from_svi_ns(struct ns *ns,
|
||||
void *_in_param,
|
||||
void **_p_zevpn)
|
||||
/* Callback for from_svi ifp walker */
|
||||
static int zebra_evpn_from_svi_ns(struct interface *tmp_if, void *_in_param)
|
||||
{
|
||||
struct zebra_ns *zns = ns->info;
|
||||
struct route_node *rn;
|
||||
struct interface *br_if;
|
||||
struct zebra_evpn **p_zevpn = (struct zebra_evpn **)_p_zevpn;
|
||||
struct zebra_evpn *zevpn;
|
||||
struct interface *tmp_if = NULL;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_if *br_zif;
|
||||
struct zebra_l2_bridge_vlan *bvlan;
|
||||
struct zebra_from_svi_param *in_param =
|
||||
(struct zebra_from_svi_param *)_in_param;
|
||||
int found = 0;
|
||||
struct zebra_from_svi_param *in_param = _in_param;
|
||||
bool found = false;
|
||||
vni_t vni_id = 0;
|
||||
vlanid_t vid = 0;
|
||||
uint8_t bridge_vlan_aware;
|
||||
|
||||
if (!in_param)
|
||||
return NS_WALK_STOP;
|
||||
|
@ -728,48 +702,30 @@ static int zebra_evpn_from_svi_ns(struct ns *ns,
|
|||
br_if = in_param->br_if;
|
||||
zif = in_param->zif;
|
||||
assert(zif);
|
||||
bridge_vlan_aware = in_param->bridge_vlan_aware;
|
||||
vid = in_param->vid;
|
||||
br_zif = br_if->info;
|
||||
assert(br_zif);
|
||||
|
||||
if (bridge_vlan_aware) {
|
||||
bvlan = zebra_l2_bridge_if_vlan_find(br_zif, vid);
|
||||
if (bvlan && bvlan->access_bd && bvlan->access_bd->vni) {
|
||||
found = 1;
|
||||
vni_id = bvlan->access_bd->vni;
|
||||
}
|
||||
} else {
|
||||
/* TODO: Optimize with a hash. */
|
||||
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;
|
||||
if (!if_is_operative(tmp_if))
|
||||
continue;
|
||||
if (!tmp_if)
|
||||
goto done;
|
||||
zif = tmp_if->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
||||
goto done;
|
||||
if (!if_is_operative(tmp_if))
|
||||
goto done;
|
||||
|
||||
if (zif->brslave_info.br_if != br_if)
|
||||
continue;
|
||||
if (zif->brslave_info.br_if != br_if)
|
||||
goto done;
|
||||
|
||||
vni_id =
|
||||
zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
|
||||
if (vni_id) {
|
||||
found = 1;
|
||||
route_unlock_node(rn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if);
|
||||
if (vni_id)
|
||||
found = true;
|
||||
|
||||
done:
|
||||
if (!found)
|
||||
return NS_WALK_CONTINUE;
|
||||
|
||||
zevpn = zebra_evpn_lookup(vni_id);
|
||||
if (p_zevpn)
|
||||
*p_zevpn = zevpn;
|
||||
in_param->zevpn = zevpn;
|
||||
return NS_WALK_STOP;
|
||||
}
|
||||
|
||||
|
@ -780,17 +736,21 @@ static int zebra_evpn_from_svi_ns(struct ns *ns,
|
|||
struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
|
||||
struct interface *br_if)
|
||||
{
|
||||
struct zebra_evpn *zevpn = NULL;
|
||||
struct zebra_evpn **p_zevpn;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_from_svi_param in_param;
|
||||
struct zebra_l2_bridge_vlan *bvlan;
|
||||
struct zebra_from_svi_param in_param = {};
|
||||
vni_t vni_id = 0;
|
||||
struct zebra_evpn *zevpn;
|
||||
struct zebra_l2info_vlan *vl;
|
||||
|
||||
if (!br_if)
|
||||
return NULL;
|
||||
|
||||
/* Make sure the linked interface is a bridge. */
|
||||
if (!IS_ZEBRA_IF_BRIDGE(br_if))
|
||||
if (!IS_ZEBRA_IF_BRIDGE(br_if)) {
|
||||
zlog_debug("%s: br_if NOT a bridge", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Determine if bridge is VLAN-aware or not */
|
||||
zif = br_if->info;
|
||||
|
@ -798,57 +758,60 @@ struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp,
|
|||
in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
|
||||
in_param.vid = 0;
|
||||
|
||||
/* Don't need to search in this case */
|
||||
if (in_param.bridge_vlan_aware) {
|
||||
struct zebra_l2info_vlan *vl;
|
||||
|
||||
if (!IS_ZEBRA_IF_VLAN(ifp))
|
||||
return NULL;
|
||||
|
||||
zevpn = NULL;
|
||||
|
||||
zif = ifp->info;
|
||||
assert(zif);
|
||||
vl = &zif->l2info.vl;
|
||||
in_param.vid = vl->vid;
|
||||
|
||||
bvlan = zebra_l2_bridge_if_vlan_find(br_if->info, vl->vid);
|
||||
if (bvlan && bvlan->access_bd && bvlan->access_bd->vni) {
|
||||
vni_id = bvlan->access_bd->vni;
|
||||
zevpn = zebra_evpn_lookup(vni_id);
|
||||
}
|
||||
|
||||
return zevpn;
|
||||
}
|
||||
|
||||
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN:
|
||||
* search all NSes
|
||||
*/
|
||||
in_param.br_if = br_if;
|
||||
in_param.zif = zif;
|
||||
p_zevpn = &zevpn;
|
||||
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
|
||||
ns_walk_func(zebra_evpn_from_svi_ns, (void *)&in_param,
|
||||
(void **)p_zevpn);
|
||||
return zevpn;
|
||||
zebra_ns_ifp_walk_all(zebra_evpn_from_svi_ns, &in_param);
|
||||
|
||||
return in_param.zevpn;
|
||||
}
|
||||
|
||||
static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp)
|
||||
static int zvni_map_to_macvlan_ns(struct interface *tmp_if, void *_in_param)
|
||||
{
|
||||
struct zebra_ns *zns = ns->info;
|
||||
struct zebra_from_svi_param *in_param =
|
||||
(struct zebra_from_svi_param *)_in_param;
|
||||
struct interface **p_ifp = (struct interface **)_p_ifp;
|
||||
struct route_node *rn;
|
||||
struct interface *tmp_if = NULL;
|
||||
struct zebra_from_svi_param *in_param = _in_param;
|
||||
struct zebra_if *zif;
|
||||
|
||||
assert(in_param && p_ifp);
|
||||
assert(in_param);
|
||||
|
||||
/* Identify corresponding VLAN interface. */
|
||||
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
||||
tmp_if = (struct interface *)rn->info;
|
||||
/* Check oper status of the SVI. */
|
||||
if (!tmp_if || !if_is_operative(tmp_if))
|
||||
continue;
|
||||
zif = tmp_if->info;
|
||||
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
|
||||
continue;
|
||||
/* Check oper status of the SVI. */
|
||||
if (!tmp_if || !if_is_operative(tmp_if))
|
||||
goto done;
|
||||
|
||||
if (zif->link == in_param->svi_if) {
|
||||
*p_ifp = tmp_if;
|
||||
route_unlock_node(rn);
|
||||
return NS_WALK_STOP;
|
||||
}
|
||||
zif = tmp_if->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
|
||||
goto done;
|
||||
|
||||
if (zif->link == in_param->svi_if) {
|
||||
in_param->ret_ifp = tmp_if;
|
||||
return NS_WALK_STOP;
|
||||
}
|
||||
|
||||
done:
|
||||
return NS_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -857,17 +820,16 @@ static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp)
|
|||
struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
|
||||
struct interface *svi_if)
|
||||
{
|
||||
struct interface *tmp_if = NULL;
|
||||
struct zebra_if *zif;
|
||||
struct interface **p_ifp;
|
||||
struct zebra_from_svi_param in_param;
|
||||
struct zebra_from_svi_param in_param = {};
|
||||
|
||||
/* Defensive check, caller expected to invoke only with valid bridge. */
|
||||
if (!br_if)
|
||||
return NULL;
|
||||
|
||||
if (!svi_if) {
|
||||
zlog_debug("svi_if is not passed.");
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("%s: svi_if is not passed.", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -879,11 +841,10 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
|
|||
in_param.br_if = br_if;
|
||||
in_param.zif = NULL;
|
||||
in_param.svi_if = svi_if;
|
||||
p_ifp = &tmp_if;
|
||||
|
||||
/* Identify corresponding VLAN interface. */
|
||||
ns_walk_func(zvni_map_to_macvlan_ns, (void *)&in_param, (void **)p_ifp);
|
||||
return tmp_if;
|
||||
zebra_ns_ifp_walk_all(zvni_map_to_macvlan_ns, &in_param);
|
||||
return in_param.ret_ifp;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -116,7 +116,10 @@ struct zebra_evpn {
|
|||
struct zebra_from_svi_param {
|
||||
struct interface *br_if;
|
||||
struct interface *svi_if;
|
||||
struct interface *ret_ifp;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_evpn *zevpn;
|
||||
struct zebra_l3vni *zl3vni;
|
||||
uint8_t bridge_vlan_aware;
|
||||
vlanid_t vid;
|
||||
};
|
||||
|
|
193
zebra/zebra_ns.c
193
zebra/zebra_ns.c
|
@ -28,9 +28,185 @@
|
|||
extern struct zebra_privs_t zserv_privs;
|
||||
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_NS, "Zebra Name Space");
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, ZNS_IFP, "Zebra NS Ifp");
|
||||
|
||||
static int ifp_tree_cmp(const struct ifp_tree_link *a, const struct ifp_tree_link *b);
|
||||
|
||||
DECLARE_RBTREE_UNIQ(ifp_tree, struct ifp_tree_link, link, ifp_tree_cmp);
|
||||
|
||||
static struct zebra_ns *dzns;
|
||||
|
||||
static int ifp_tree_cmp(const struct ifp_tree_link *a, const struct ifp_tree_link *b)
|
||||
{
|
||||
return (a->ifindex - b->ifindex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Link an ifp into its parent NS
|
||||
*/
|
||||
void zebra_ns_link_ifp(struct zebra_ns *zns, struct interface *ifp)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
struct ifp_tree_link *link, tlink = {};
|
||||
|
||||
zif = ifp->info;
|
||||
assert(zif != NULL);
|
||||
|
||||
if (zif->ns_tree_link) {
|
||||
assert(zif->ns_tree_link->zns == zns);
|
||||
assert(zif->ns_tree_link->ifp == ifp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Lookup first - already linked? */
|
||||
tlink.ifindex = ifp->ifindex;
|
||||
link = ifp_tree_find(&zns->ifp_tree, &tlink);
|
||||
if (link) {
|
||||
assert(link->ifp == ifp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate new linkage struct and add */
|
||||
link = XCALLOC(MTYPE_ZNS_IFP, sizeof(struct ifp_tree_link));
|
||||
link->ifp = ifp;
|
||||
link->ifindex = ifp->ifindex;
|
||||
link->zns = zns;
|
||||
|
||||
ifp_tree_add(&zns->ifp_tree, link);
|
||||
|
||||
zif->ns_tree_link = link;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlink an ifp from its parent NS (probably because the ifp is being deleted)
|
||||
*/
|
||||
void zebra_ns_unlink_ifp(struct interface *ifp)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
struct ifp_tree_link *link;
|
||||
struct zebra_ns *zns;
|
||||
|
||||
zif = ifp->info;
|
||||
if (zif && zif->ns_tree_link) {
|
||||
link = zif->ns_tree_link;
|
||||
zns = link->zns;
|
||||
|
||||
ifp_tree_del(&zns->ifp_tree, link);
|
||||
|
||||
zif->ns_tree_link = NULL;
|
||||
|
||||
XFREE(MTYPE_ZNS_IFP, link);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ifp lookup apis
|
||||
*/
|
||||
struct interface *zebra_ns_lookup_ifp(struct zebra_ns *zns, uint32_t ifindex)
|
||||
{
|
||||
struct interface *ifp = NULL;
|
||||
struct ifp_tree_link *link, tlink = {};
|
||||
|
||||
/* Init temp struct for lookup */
|
||||
tlink.ifindex = ifindex;
|
||||
|
||||
link = ifp_tree_find(&zns->ifp_tree, &tlink);
|
||||
if (link)
|
||||
ifp = link->ifp;
|
||||
|
||||
return ifp;
|
||||
}
|
||||
|
||||
static int lookup_ifp_name_cb(struct interface *ifp, void *arg);
|
||||
|
||||
struct ifp_name_ctx {
|
||||
const char *ifname;
|
||||
struct interface *ifp;
|
||||
};
|
||||
|
||||
struct interface *zebra_ns_lookup_ifp_name(struct zebra_ns *zns, const char *ifname)
|
||||
{
|
||||
struct ifp_name_ctx ctx = {};
|
||||
|
||||
/* Hand context struct into walker function for use in its callback */
|
||||
ctx.ifname = ifname;
|
||||
zebra_ns_ifp_walk(zns, lookup_ifp_name_cb, &ctx);
|
||||
|
||||
return ctx.ifp;
|
||||
}
|
||||
|
||||
static int lookup_ifp_name_cb(struct interface *ifp, void *arg)
|
||||
{
|
||||
struct ifp_name_ctx *pctx = arg;
|
||||
|
||||
if (strcmp(ifp->name, pctx->ifname) == 0) {
|
||||
pctx->ifp = ifp;
|
||||
return NS_WALK_STOP;
|
||||
}
|
||||
|
||||
return NS_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
/* Iterate collection of ifps, calling application's callback. Callback uses
|
||||
* return semantics from lib/ns.h: return NS_WALK_STOP to stop the iteration.
|
||||
* Caller's 'arg' is included in each callback.
|
||||
*/
|
||||
int zebra_ns_ifp_walk(struct zebra_ns *zns,
|
||||
int (*func)(struct interface *ifp, void *arg), void *arg)
|
||||
{
|
||||
struct ifp_tree_link *link;
|
||||
int ret = NS_WALK_CONTINUE;
|
||||
|
||||
frr_each (ifp_tree, &zns->ifp_tree, link) {
|
||||
ret = (func)(link->ifp, arg);
|
||||
if (ret == NS_WALK_STOP)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == NS_WALK_STOP)
|
||||
return NS_WALK_STOP;
|
||||
else
|
||||
return NS_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk all NSes, and all ifps for each NS.
|
||||
*/
|
||||
struct ns_ifp_walk_ctx {
|
||||
int (*func)(struct interface *ifp, void *arg);
|
||||
void *arg;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static int ns_ifp_walker(struct ns *ns, void *in_param, void **unused);
|
||||
|
||||
void zebra_ns_ifp_walk_all(int (*func)(struct interface *ifp, void *arg), void *arg)
|
||||
{
|
||||
struct ns_ifp_walk_ctx ctx = {};
|
||||
|
||||
ctx.func = func;
|
||||
ctx.arg = arg;
|
||||
|
||||
ns_walk_func(ns_ifp_walker, &ctx, NULL);
|
||||
}
|
||||
|
||||
static int ns_ifp_walker(struct ns *ns, void *in_param, void **unused)
|
||||
{
|
||||
struct zebra_ns *zns;
|
||||
struct ns_ifp_walk_ctx *ctx = in_param;
|
||||
int ret = NS_WALK_CONTINUE;
|
||||
|
||||
zns = ns->info;
|
||||
if (zns == NULL)
|
||||
goto done;
|
||||
|
||||
ret = zebra_ns_ifp_walk(zns, ctx->func, ctx->arg);
|
||||
|
||||
done:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete);
|
||||
|
||||
struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id)
|
||||
|
@ -58,7 +234,7 @@ static int zebra_ns_new(struct ns *ns)
|
|||
zns->ns_id = ns->ns_id;
|
||||
|
||||
/* Do any needed per-NS data structure allocation. */
|
||||
zns->if_table = route_table_init();
|
||||
ifp_tree_init(&zns->ifp_tree);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -66,11 +242,22 @@ static int zebra_ns_new(struct ns *ns)
|
|||
static int zebra_ns_delete(struct ns *ns)
|
||||
{
|
||||
struct zebra_ns *zns = (struct zebra_ns *)ns->info;
|
||||
struct zebra_if *zif;
|
||||
struct ifp_tree_link *link;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVENT)
|
||||
zlog_info("ZNS %s with id %u (deleted)", ns->name, ns->ns_id);
|
||||
if (!zns)
|
||||
return 0;
|
||||
|
||||
/* Clean up ifp tree */
|
||||
while ((link = ifp_tree_pop(&zns->ifp_tree)) != NULL) {
|
||||
zif = link->ifp->info;
|
||||
|
||||
zif->ns_tree_link = NULL;
|
||||
XFREE(MTYPE_ZNS_IFP, link);
|
||||
}
|
||||
|
||||
XFREE(MTYPE_ZEBRA_NS, ns->info);
|
||||
return 0;
|
||||
}
|
||||
|
@ -157,10 +344,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
|
|||
*/
|
||||
static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
|
||||
{
|
||||
if (zns->if_table)
|
||||
route_table_finish(zns->if_table);
|
||||
zns->if_table = NULL;
|
||||
|
||||
zebra_dplane_ns_enable(zns, false /*Disable*/);
|
||||
|
||||
kernel_terminate(zns, complete);
|
||||
|
|
|
@ -32,6 +32,20 @@ struct nlsock {
|
|||
};
|
||||
#endif
|
||||
|
||||
/* Tree of interfaces: external linkage struct, and rbtree */
|
||||
PREDECL_RBTREE_UNIQ(ifp_tree);
|
||||
|
||||
struct ifp_tree_link {
|
||||
struct ifp_tree_item link;
|
||||
|
||||
ifindex_t ifindex;
|
||||
|
||||
struct interface *ifp;
|
||||
|
||||
/* Backpointer */
|
||||
struct zebra_ns *zns;
|
||||
};
|
||||
|
||||
struct zebra_ns {
|
||||
/* net-ns name. */
|
||||
char name[VRF_NAMSIZ];
|
||||
|
@ -53,7 +67,8 @@ struct zebra_ns {
|
|||
struct nlsock ge_netlink_cmd; /* command channel for generic netlink */
|
||||
#endif
|
||||
|
||||
struct route_table *if_table;
|
||||
/* Tree of interfaces in this ns */
|
||||
struct ifp_tree_head ifp_tree;
|
||||
|
||||
/* Back pointer */
|
||||
struct ns *ns;
|
||||
|
@ -61,6 +76,23 @@ struct zebra_ns {
|
|||
|
||||
struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id);
|
||||
|
||||
/* Manage collection of ifps per-NS */
|
||||
void zebra_ns_link_ifp(struct zebra_ns *zns, struct interface *ifp);
|
||||
void zebra_ns_unlink_ifp(struct interface *ifp);
|
||||
struct interface *zebra_ns_lookup_ifp(struct zebra_ns *zns, uint32_t ifindex);
|
||||
struct interface *zebra_ns_lookup_ifp_name(struct zebra_ns *zns, const char *ifname);
|
||||
|
||||
/* Iterate collection of ifps, calling application's callback. Callback uses
|
||||
* return semantics from lib/ns.h: return NS_WALK_STOP to stop the iteration.
|
||||
* Caller's 'arg' is included in each callback.
|
||||
* The iterator returns STOP or CONTINUE also.
|
||||
*/
|
||||
int zebra_ns_ifp_walk(struct zebra_ns *zns,
|
||||
int (*func)(struct interface *ifp, void *arg), void *arg);
|
||||
|
||||
/* Walk all NSes, and all ifps for each NS. */
|
||||
void zebra_ns_ifp_walk_all(int (*func)(struct interface *ifp, void *arg), void *arg);
|
||||
|
||||
int zebra_ns_init(void);
|
||||
int zebra_ns_enable(ns_id_t ns_id, void **info);
|
||||
int zebra_ns_disabled(struct ns *ns);
|
||||
|
|
|
@ -859,39 +859,30 @@ static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
|
|||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
static int zvni_map_to_svi_ns(struct ns *ns,
|
||||
void *_in_param,
|
||||
void **_p_ifp)
|
||||
static int zvni_map_to_svi_ns(struct interface *tmp_if, void *_in_param)
|
||||
{
|
||||
struct zebra_ns *zns = ns->info;
|
||||
struct route_node *rn;
|
||||
struct zebra_from_svi_param *in_param =
|
||||
(struct zebra_from_svi_param *)_in_param;
|
||||
struct zebra_from_svi_param *in_param = _in_param;
|
||||
struct zebra_l2info_vlan *vl;
|
||||
struct interface *tmp_if = NULL;
|
||||
struct interface **p_ifp = (struct interface **)_p_ifp;
|
||||
struct zebra_if *zif;
|
||||
|
||||
assert(in_param && p_ifp);
|
||||
assert(in_param);
|
||||
|
||||
/* TODO: Optimize with a hash. */
|
||||
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
||||
tmp_if = (struct interface *)rn->info;
|
||||
/* Check oper status of the SVI. */
|
||||
if (!tmp_if || !if_is_operative(tmp_if))
|
||||
continue;
|
||||
zif = tmp_if->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VLAN
|
||||
|| zif->link != in_param->br_if)
|
||||
continue;
|
||||
vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
|
||||
|
||||
if (vl->vid == in_param->vid) {
|
||||
*p_ifp = tmp_if;
|
||||
route_unlock_node(rn);
|
||||
return NS_WALK_STOP;
|
||||
}
|
||||
/* Check oper status of the SVI. */
|
||||
if (!tmp_if || !if_is_operative(tmp_if))
|
||||
goto done;
|
||||
zif = tmp_if->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VLAN || zif->link != in_param->br_if)
|
||||
goto done;
|
||||
vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
|
||||
|
||||
if (vl->vid == in_param->vid) {
|
||||
in_param->ret_ifp = tmp_if;
|
||||
return NS_WALK_STOP;
|
||||
}
|
||||
|
||||
done:
|
||||
return NS_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -904,10 +895,9 @@ static int zvni_map_to_svi_ns(struct ns *ns,
|
|||
*/
|
||||
struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
|
||||
{
|
||||
struct interface *tmp_if = NULL;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_from_svi_param in_param;
|
||||
struct interface **p_ifp;
|
||||
struct zebra_from_svi_param in_param = {};
|
||||
|
||||
/* Defensive check, caller expected to invoke only with valid bridge. */
|
||||
if (!br_if)
|
||||
return NULL;
|
||||
|
@ -922,12 +912,11 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
|
|||
|
||||
in_param.vid = vid;
|
||||
in_param.br_if = br_if;
|
||||
in_param.zif = NULL;
|
||||
p_ifp = &tmp_if;
|
||||
|
||||
/* Identify corresponding VLAN interface. */
|
||||
ns_walk_func(zvni_map_to_svi_ns, (void *)&in_param,
|
||||
(void **)p_ifp);
|
||||
return tmp_if;
|
||||
zebra_ns_ifp_walk_all(zvni_map_to_svi_ns, &in_param);
|
||||
|
||||
return in_param.ret_ifp;
|
||||
}
|
||||
|
||||
int zebra_evpn_vxlan_del(struct zebra_evpn *zevpn)
|
||||
|
@ -1007,9 +996,9 @@ static int zevpn_build_vni_hash_table(struct zebra_if *zif,
|
|||
*/
|
||||
zevpn = zebra_evpn_lookup(vni);
|
||||
if (zevpn) {
|
||||
zlog_debug(
|
||||
"EVPN hash already present for IF %s(%u) L2-VNI %u",
|
||||
ifp->name, ifp->ifindex, vni);
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("EVPN hash already present for IF %s(%u) L2-VNI %u",
|
||||
ifp->name, ifp->ifindex, vni);
|
||||
|
||||
/*
|
||||
* Inform BGP if intf is up and mapped to
|
||||
|
@ -1072,48 +1061,32 @@ static int zevpn_build_vni_hash_table(struct zebra_if *zif,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int zevpn_build_hash_table_zns(struct ns *ns,
|
||||
void *param_in __attribute__((unused)),
|
||||
void **param_out __attribute__((unused)))
|
||||
static int zevpn_build_hash_table_zns(struct interface *ifp, void *arg)
|
||||
{
|
||||
struct zebra_ns *zns = ns->info;
|
||||
struct route_node *rn;
|
||||
struct interface *ifp;
|
||||
struct zebra_vrf *zvrf;
|
||||
struct zebra_vrf *zvrf = arg;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_l2info_vxlan *vxl;
|
||||
|
||||
zvrf = zebra_vrf_get_evpn();
|
||||
|
||||
/* Walk VxLAN interfaces and create EVPN hash. */
|
||||
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
||||
struct zebra_if *zif;
|
||||
struct zebra_l2info_vxlan *vxl;
|
||||
|
||||
ifp = (struct interface *)rn->info;
|
||||
if (!ifp)
|
||||
continue;
|
||||
zif = ifp->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
||||
continue;
|
||||
|
||||
vxl = &zif->l2info.vxl;
|
||||
/* link of VXLAN interface should be in zebra_evpn_vrf */
|
||||
if (zvrf->zns->ns_id != vxl->link_nsid) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"Intf %s(%u) link not in same "
|
||||
"namespace than BGP EVPN core instance ",
|
||||
ifp->name, ifp->ifindex);
|
||||
continue;
|
||||
}
|
||||
zif = ifp->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
||||
goto done;
|
||||
|
||||
vxl = &zif->l2info.vxl;
|
||||
/* link of VXLAN interface should be in zebra_evpn_vrf */
|
||||
if (zvrf->zns->ns_id != vxl->link_nsid) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("Building vni table for %s-if %s",
|
||||
IS_ZEBRA_VXLAN_IF_VNI(zif) ? "vni" : "svd",
|
||||
ifp->name);
|
||||
|
||||
zebra_vxlan_if_vni_iterate(zif, zevpn_build_vni_hash_table,
|
||||
NULL);
|
||||
zlog_debug("Intf %s(%u) link not in same namespace as BGP EVPN core instance",
|
||||
ifp->name, ifp->ifindex);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("Building vni table for %s-if %s",
|
||||
IS_ZEBRA_VXLAN_IF_VNI(zif) ? "vni" : "svd", ifp->name);
|
||||
|
||||
zebra_vxlan_if_vni_iterate(zif, zevpn_build_vni_hash_table, NULL);
|
||||
|
||||
done:
|
||||
return NS_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -1124,7 +1097,13 @@ static int zevpn_build_hash_table_zns(struct ns *ns,
|
|||
|
||||
static void zevpn_build_hash_table(void)
|
||||
{
|
||||
ns_walk_func(zevpn_build_hash_table_zns, NULL, NULL);
|
||||
struct zebra_vrf *zvrf;
|
||||
|
||||
zvrf = zebra_vrf_get_evpn();
|
||||
if (zvrf == NULL)
|
||||
return;
|
||||
|
||||
zebra_ns_ifp_walk_all(zevpn_build_hash_table_zns, zvrf);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1968,70 +1947,63 @@ static int zl3vni_del(struct zebra_l3vni *zl3vni)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
|
||||
void *_zl3vni,
|
||||
void **_pifp)
|
||||
{
|
||||
struct zebra_ns *zns = ns->info;
|
||||
struct zebra_l3vni *zl3vni = (struct zebra_l3vni *)_zl3vni;
|
||||
struct route_node *rn = NULL;
|
||||
struct interface *ifp = NULL;
|
||||
/* Context arg for zl3vni map iteration */
|
||||
struct zl3vni_map_arg {
|
||||
struct zebra_vrf *zvrf;
|
||||
struct zebra_l3vni *zl3vni;
|
||||
struct interface *ret_ifp;
|
||||
};
|
||||
|
||||
zvrf = zebra_vrf_get_evpn();
|
||||
static int zl3vni_map_to_vxlan_if_ns(struct interface *ifp, void *arg)
|
||||
{
|
||||
struct zl3vni_map_arg *ctx = arg;
|
||||
struct zebra_l3vni *zl3vni = ctx->zl3vni;
|
||||
struct zebra_vrf *zvrf = ctx->zvrf;
|
||||
struct zebra_if *zif = NULL;
|
||||
struct zebra_l2info_vxlan *vxl;
|
||||
struct zebra_vxlan_vni *vni = NULL;
|
||||
|
||||
assert(_pifp);
|
||||
/* look for vxlan-interface */
|
||||
|
||||
/* loop through all vxlan-interface */
|
||||
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
||||
zif = ifp->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
||||
goto done;
|
||||
|
||||
struct zebra_if *zif = NULL;
|
||||
struct zebra_l2info_vxlan *vxl;
|
||||
struct zebra_vxlan_vni *vni = NULL;
|
||||
vxl = &zif->l2info.vxl;
|
||||
vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
|
||||
if (!vni || vni->vni != zl3vni->vni)
|
||||
goto done;
|
||||
|
||||
ifp = (struct interface *)rn->info;
|
||||
if (!ifp)
|
||||
continue;
|
||||
|
||||
zif = ifp->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
||||
continue;
|
||||
|
||||
vxl = &zif->l2info.vxl;
|
||||
vni = zebra_vxlan_if_vni_find(zif, zl3vni->vni);
|
||||
if (!vni || vni->vni != zl3vni->vni)
|
||||
continue;
|
||||
|
||||
/* link of VXLAN interface should be in zebra_evpn_vrf */
|
||||
if (zvrf->zns->ns_id != vxl->link_nsid) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug(
|
||||
"Intf %s(%u) VNI %u, link not in same "
|
||||
"namespace than BGP EVPN core instance ",
|
||||
ifp->name, ifp->ifindex, vni->vni);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
zl3vni->local_vtep_ip = zif->l2info.vxl.vtep_ip;
|
||||
*_pifp = (void *)ifp;
|
||||
route_unlock_node(rn);
|
||||
return NS_WALK_STOP;
|
||||
/* link of VXLAN interface should be in zebra_evpn_vrf */
|
||||
if (zvrf->zns->ns_id != vxl->link_nsid) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("Intf %s(%u) VNI %u, link not in same namespace as BGP EVPN core instance",
|
||||
ifp->name, ifp->ifindex, vni->vni);
|
||||
goto done;
|
||||
}
|
||||
|
||||
zl3vni->local_vtep_ip = zif->l2info.vxl.vtep_ip;
|
||||
ctx->ret_ifp = ifp;
|
||||
|
||||
return NS_WALK_STOP;
|
||||
|
||||
done:
|
||||
return NS_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
struct interface *zl3vni_map_to_vxlan_if(struct zebra_l3vni *zl3vni)
|
||||
{
|
||||
struct interface **p_ifp;
|
||||
struct interface *ifp = NULL;
|
||||
struct zl3vni_map_arg arg = {};
|
||||
|
||||
p_ifp = &ifp;
|
||||
arg.zl3vni = zl3vni;
|
||||
arg.zvrf = zebra_vrf_get_evpn();
|
||||
|
||||
ns_walk_func(zl3vni_map_to_vxlan_if_ns,
|
||||
(void *)zl3vni, (void **)p_ifp);
|
||||
return ifp;
|
||||
if (arg.zvrf == NULL)
|
||||
return NULL;
|
||||
|
||||
zebra_ns_ifp_walk_all(zl3vni_map_to_vxlan_if_ns, &arg);
|
||||
|
||||
return arg.ret_ifp;
|
||||
}
|
||||
|
||||
struct interface *zl3vni_map_to_svi_if(struct zebra_l3vni *zl3vni)
|
||||
|
@ -2086,57 +2058,35 @@ struct zebra_l3vni *zl3vni_from_vrf(vrf_id_t vrf_id)
|
|||
return zl3vni_lookup(zvrf->l3vni);
|
||||
}
|
||||
|
||||
static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni)
|
||||
/* loop through all vxlan-interface */
|
||||
static int zl3vni_from_svi_ns(struct interface *tmp_if, void *_in_param)
|
||||
{
|
||||
int found = 0;
|
||||
vni_t vni_id = 0;
|
||||
struct zebra_ns *zns = ns->info;
|
||||
struct zebra_l3vni **p_zl3vni = (struct zebra_l3vni **)_p_zl3vni;
|
||||
struct zebra_from_svi_param *in_param =
|
||||
(struct zebra_from_svi_param *)_in_param;
|
||||
struct route_node *rn = NULL;
|
||||
struct interface *tmp_if = NULL;
|
||||
struct zebra_from_svi_param *in_param = _in_param;
|
||||
struct zebra_if *zif = NULL;
|
||||
struct zebra_if *br_zif = NULL;
|
||||
|
||||
assert(in_param && p_zl3vni);
|
||||
assert(in_param);
|
||||
|
||||
br_zif = in_param->br_if->info;
|
||||
assert(br_zif);
|
||||
zif = tmp_if->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
||||
goto done;
|
||||
if (!if_is_operative(tmp_if))
|
||||
goto done;
|
||||
|
||||
if (in_param->bridge_vlan_aware) {
|
||||
vni_id = zebra_l2_bridge_if_vni_find(br_zif, in_param->vid);
|
||||
if (vni_id)
|
||||
found = 1;
|
||||
} else {
|
||||
/* loop through all vxlan-interface */
|
||||
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;
|
||||
if (!if_is_operative(tmp_if))
|
||||
continue;
|
||||
if (zif->brslave_info.br_if != in_param->br_if)
|
||||
goto done;
|
||||
|
||||
if (zif->brslave_info.br_if != in_param->br_if)
|
||||
continue;
|
||||
|
||||
vni_id = zebra_vxlan_if_access_vlan_vni_find(
|
||||
zif, in_param->br_if);
|
||||
if (vni_id) {
|
||||
found = 1;
|
||||
route_unlock_node(rn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, in_param->br_if);
|
||||
if (vni_id) {
|
||||
in_param->zl3vni = zl3vni_lookup(vni_id);
|
||||
found = 1;
|
||||
}
|
||||
|
||||
done:
|
||||
if (!found)
|
||||
return NS_WALK_CONTINUE;
|
||||
|
||||
*p_zl3vni = zl3vni_lookup(vni_id);
|
||||
return NS_WALK_STOP;
|
||||
}
|
||||
|
||||
|
@ -2147,10 +2097,11 @@ static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni)
|
|||
static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
|
||||
struct interface *br_if)
|
||||
{
|
||||
struct zebra_l3vni *zl3vni = NULL;
|
||||
struct zebra_if *zif = NULL;
|
||||
vni_t vni_id = 0;
|
||||
struct zebra_if *br_zif = NULL;
|
||||
struct zebra_from_svi_param in_param = {};
|
||||
struct zebra_l3vni **p_zl3vni;
|
||||
struct zebra_l2info_vlan *vl;
|
||||
|
||||
if (!br_if)
|
||||
return NULL;
|
||||
|
@ -2158,15 +2109,15 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
|
|||
/* Make sure the linked interface is a bridge. */
|
||||
if (!IS_ZEBRA_IF_BRIDGE(br_if))
|
||||
return NULL;
|
||||
|
||||
in_param.br_if = br_if;
|
||||
|
||||
/* Determine if bridge is VLAN-aware or not */
|
||||
zif = br_if->info;
|
||||
assert(zif);
|
||||
in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif);
|
||||
if (in_param.bridge_vlan_aware) {
|
||||
struct zebra_l2info_vlan *vl;
|
||||
br_zif = br_if->info;
|
||||
assert(br_zif);
|
||||
|
||||
in_param.bridge_vlan_aware = IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif);
|
||||
if (in_param.bridge_vlan_aware) {
|
||||
if (!IS_ZEBRA_IF_VLAN(ifp))
|
||||
return NULL;
|
||||
|
||||
|
@ -2174,15 +2125,18 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
|
|||
assert(zif);
|
||||
vl = &zif->l2info.vl;
|
||||
in_param.vid = vl->vid;
|
||||
|
||||
vni_id = zebra_l2_bridge_if_vni_find(br_zif, in_param.vid);
|
||||
if (vni_id)
|
||||
return zl3vni_lookup(vni_id);
|
||||
}
|
||||
|
||||
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
|
||||
/* TODO: Optimize with a hash. */
|
||||
|
||||
p_zl3vni = &zl3vni;
|
||||
zebra_ns_ifp_walk_all(zl3vni_from_svi_ns, &in_param);
|
||||
|
||||
ns_walk_func(zl3vni_from_svi_ns, (void *)&in_param, (void **)p_zl3vni);
|
||||
return zl3vni;
|
||||
return in_param.zl3vni;
|
||||
}
|
||||
|
||||
vni_t vni_id_from_svi(struct interface *ifp, struct interface *br_if)
|
||||
|
@ -2336,6 +2290,36 @@ static void zevpn_add_to_l3vni_list(struct hash_bucket *bucket, void *ctxt)
|
|||
listnode_add_sort(zl3vni->l2vnis, zevpn);
|
||||
}
|
||||
|
||||
/* Helper for vni transition iterator */
|
||||
|
||||
struct vni_trans_ctx {
|
||||
vni_t vni;
|
||||
struct zebra_vxlan_vni *vnip;
|
||||
struct interface *ret_ifp;
|
||||
};
|
||||
|
||||
static int vni_trans_cb(struct interface *ifp, void *arg)
|
||||
{
|
||||
struct vni_trans_ctx *ctx = arg;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_vxlan_vni *vnip;
|
||||
|
||||
/* Find VxLAN interface for this VNI. */
|
||||
zif = ifp->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
||||
goto done;
|
||||
|
||||
vnip = zebra_vxlan_if_vni_find(zif, ctx->vni);
|
||||
if (vnip) {
|
||||
ctx->ret_ifp = ifp;
|
||||
ctx->vnip = vnip;
|
||||
return NS_WALK_STOP;
|
||||
}
|
||||
|
||||
done:
|
||||
return NS_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle transition of vni from l2 to l3 and vice versa.
|
||||
* This function handles only the L2VNI add/delete part of
|
||||
|
@ -2386,39 +2370,25 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
|
|||
return -1;
|
||||
}
|
||||
} else {
|
||||
struct zebra_ns *zns;
|
||||
struct route_node *rn;
|
||||
struct interface *ifp;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_vxlan_vni *vnip;
|
||||
struct zebra_l2info_vxlan *vxl;
|
||||
struct interface *vlan_if;
|
||||
bool found = false;
|
||||
struct zebra_if *zif;
|
||||
struct zebra_ns *zns;
|
||||
struct vni_trans_ctx ctx = {};
|
||||
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_debug("Adding L2-VNI %u - transition from L3-VNI",
|
||||
vni);
|
||||
|
||||
/* Find VxLAN interface for this VNI. */
|
||||
zns = zebra_ns_lookup(NS_DEFAULT);
|
||||
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
|
||||
ifp = (struct interface *)rn->info;
|
||||
if (!ifp)
|
||||
continue;
|
||||
zif = ifp->info;
|
||||
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
|
||||
continue;
|
||||
|
||||
vxl = &zif->l2info.vxl;
|
||||
vnip = zebra_vxlan_if_vni_find(zif, vni);
|
||||
if (vnip) {
|
||||
found = true;
|
||||
route_unlock_node(rn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx.vni = vni;
|
||||
|
||||
if (!found) {
|
||||
/* Find VxLAN interface for this VNI. */
|
||||
zebra_ns_ifp_walk(zns, vni_trans_cb, &ctx);
|
||||
|
||||
if (ctx.ret_ifp == NULL) {
|
||||
if (IS_ZEBRA_DEBUG_VXLAN)
|
||||
zlog_err(
|
||||
"Adding L2-VNI - Failed to find VxLAN interface for VNI %u",
|
||||
|
@ -2431,6 +2401,10 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
|
|||
if (zevpn)
|
||||
return 0;
|
||||
|
||||
zif = ctx.ret_ifp->info;
|
||||
vnip = ctx.vnip;
|
||||
vxl = &zif->l2info.vxl;
|
||||
|
||||
zevpn = zebra_evpn_add(vni);
|
||||
|
||||
/* Find bridge interface for the VNI */
|
||||
|
@ -2443,13 +2417,13 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
|
|||
listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
|
||||
}
|
||||
|
||||
zevpn->vxlan_if = ifp;
|
||||
zevpn->vxlan_if = ctx.ret_ifp;
|
||||
zevpn->local_vtep_ip = vxl->vtep_ip;
|
||||
|
||||
/* Inform BGP if the VNI is up and mapped to a bridge. */
|
||||
if (if_is_operative(ifp) && zif->brslave_info.br_if) {
|
||||
if (if_is_operative(ctx.ret_ifp) && zif->brslave_info.br_if) {
|
||||
zebra_evpn_send_add_to_client(zevpn);
|
||||
zebra_evpn_read_mac_neigh(zevpn, ifp);
|
||||
zebra_evpn_read_mac_neigh(zevpn, ctx.ret_ifp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue