summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
Diffstat (limited to 'zebra')
-rw-r--r--zebra/if_netlink.c852
-rw-r--r--zebra/interface.c778
-rw-r--r--zebra/kernel_netlink.c20
-rw-r--r--zebra/kernel_socket.c8
-rw-r--r--zebra/rt.h2
-rw-r--r--zebra/rule_netlink.c1
-rw-r--r--zebra/zebra_dplane.h13
-rw-r--r--zebra/zebra_l2.c9
-rw-r--r--zebra/zebra_l2.h22
-rw-r--r--zebra/zebra_ns.c36
-rw-r--r--zebra/zebra_ns.h2
-rw-r--r--zebra/zebra_rib.c2
12 files changed, 1033 insertions, 712 deletions
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 55d63cc4e..8767b2622 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -64,64 +64,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]));
}
}
@@ -236,26 +193,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)
{
@@ -283,16 +220,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);
@@ -314,75 +246,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)
@@ -663,62 +528,59 @@ 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:
+ break;
}
}
-static int netlink_bridge_vxlan_vlan_vni_map_update(struct interface *ifp,
- struct rtattr *af_spec)
+static int
+netlink_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx,
+ struct rtattr *af_spec)
{
int rem;
- vni_t vni_id;
- vlanid_t vid;
uint16_t flags;
struct rtattr *i;
- struct zebra_vxlan_vni vni;
- struct zebra_vxlan_vni *vnip;
- struct hash *vni_table = NULL;
+ 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));
@@ -737,80 +599,46 @@ static int netlink_bridge_vxlan_vlan_vni_map_update(struct interface *ifp,
/* vlan-vni info missing */
return 0;
+ count++;
flags = 0;
- memset(&vni, 0, sizeof(vni));
+ 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));
- vni.vni = *(vni_t *)RTA_DATA(aftb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
- vni.access_vlan = *(vlanid_t *)RTA_DATA(
+ 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]);
- if (flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
- vni_start = vni;
- continue;
- }
-
- if (flags & BRIDGE_VLAN_INFO_RANGE_END)
- vni_end = vni;
-
- if (!(flags & BRIDGE_VLAN_INFO_RANGE_END)) {
- vni_start = vni;
- vni_end = vni;
- }
-
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "Vlan-Vni(%d:%d-%d:%d) update for VxLAN IF %s(%u)",
- vni_start.access_vlan, vni_end.access_vlan,
- vni_start.vni, vni_end.vni, ifp->name,
- ifp->ifindex);
-
- if (!vni_table) {
- vni_table = zebra_vxlan_vni_table_create();
- if (!vni_table)
- return 0;
- }
-
- for (vid = vni_start.access_vlan, vni_id = vni_start.vni;
- vid <= vni_end.access_vlan; vid++, vni_id++) {
-
- memset(&vni, 0, sizeof(vni));
- vni.vni = vni_id;
- vni.access_vlan = vid;
- vnip = hash_get(vni_table, &vni, zebra_vxlan_vni_alloc);
- if (!vnip)
- return 0;
- }
-
- memset(&vni_start, 0, sizeof(vni_start));
- memset(&vni_end, 0, sizeof(vni_end));
+ vniarray->vnis[count - 1].flags = flags;
}
- if (vni_table)
- zebra_vxlan_if_vni_table_add_update(ifp, vni_table);
-
+ 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;
- struct zebra_if *zif;
- vlanid_t access_vlan;
+ struct zebra_dplane_bridge_vlan_info bvinfo;
if (!af_spec)
return 0;
- zif = (struct zebra_if *)ifp->info;
-
- /* Single vxlan devices has vni-vlan range to update */
- if (IS_ZEBRA_VXLAN_IF_SVD(zif))
- return netlink_bridge_vxlan_vlan_vni_map_update(ifp, af_spec);
+ 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.
@@ -820,119 +648,73 @@ 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;
- }
-
- if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
- vid_range_start = vinfo->vid;
+ count++;
+ bvarray = XREALLOC(
+ MTYPE_TMP, bvarray,
+ sizeof(struct
+ zebra_dplane_bridge_vlan_info_array) +
+ count * sizeof(struct
+ zebra_dplane_bridge_vlan_info));
- 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;
}
-static bool is_if_protodown_reason_only_frr(uint32_t rc_bitfield)
-{
- return (rc_bitfield == (((uint32_t)1) << if_netlink_get_frr_protodown_r_bit()));
-}
-
/*
* 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,
+static void netlink_proc_dplane_if_protodown(struct zebra_dplane_ctx *ctx,
struct rtattr **tb)
{
bool protodown;
- bool old_protodown;
uint32_t rc_bitfield = 0;
struct rtattr *pd_reason_info[IFLA_MAX + 1];
@@ -947,59 +729,9 @@ static void netlink_proc_dplane_if_protodown(struct zebra_if *zif,
pd_reason_info[IFLA_PROTO_DOWN_REASON_VALUE]);
}
- /*
- * Set our reason code to note it wasn't us.
- * If the reason we got from the kernel is ONLY frr though, don't
- * set it.
- */
- COND_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_EXTERNAL,
- protodown && rc_bitfield &&
- !is_if_protodown_reason_only_frr(rc_bitfield));
-
-
- old_protodown = !!ZEBRA_IF_IS_PROTODOWN(zif);
- if (protodown == old_protodown)
- return;
-
- 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");
-
- /* Set protodown, respectively */
- COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, protodown);
-
- if (zebra_evpn_is_es_bond_member(zif->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",
- zif->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",
- zif->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",
- zif->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);
-
- dplane_intf_update(zif->ifp);
- }
+ 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)
@@ -1016,29 +748,6 @@ static uint8_t netlink_parse_lacp_bypass(struct rtattr **linkinfo)
return bypass;
}
-/*
- * Only called at startup to cleanup leftover protodown reasons we may
- * have not cleaned up. We leave protodown set though.
- */
-static void if_sweep_protodown(struct zebra_if *zif)
-{
- bool protodown;
-
- protodown = !!ZEBRA_IF_IS_PROTODOWN(zif);
-
- if (!protodown)
- return;
-
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("interface %s sweeping protodown %s reason 0x%x",
- zif->ifp->name, protodown ? "on" : "off",
- zif->protodown_rc);
-
- /* Only clear our reason codes, leave external if it was set */
- UNSET_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_ALL);
- dplane_intf_update(zif->ifp);
-}
-
/* 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)
@@ -1085,7 +794,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*/);
@@ -1109,6 +818,13 @@ int interface_lookup_netlink(struct zebra_ns *zns)
if (ret < 0)
return ret;
+ return ret;
+}
+
+void interface_list_tunneldump(struct zebra_ns *zns)
+{
+ int ret;
+
/*
* So netlink_tunneldump_read will initiate a request
* per tunnel to get data. If we are on a kernel that
@@ -1121,13 +837,12 @@ int interface_lookup_netlink(struct zebra_ns *zns)
*/
ret = netlink_tunneldump_read(zns);
if (ret < 0)
- return ret;
+ return;
- /* fixup linkages */
- zebra_if_update_all_links(zns);
- return 0;
+ zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_TUNNELS_READ);
}
+
/**
* interface_addr_lookup_netlink() - Look up interface addresses
*
@@ -1147,8 +862,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;
@@ -1156,8 +871,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;
@@ -1768,7 +1483,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;
}
@@ -1778,27 +1492,21 @@ 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;
frrtrace(3, frr_zebra, netlink_interface, h, ns_id, startup);
- zns = zebra_ns_lookup(ns_id);
ifi = NLMSG_DATA(h);
/* assume if not default zns, then new VRF */
@@ -1827,10 +1535,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_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len,
@@ -1877,18 +1581,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]) {
@@ -1911,277 +1644,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, 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 =
- 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]) {
- netlink_proc_dplane_if_protodown(ifp->info, tb);
- if (startup)
- if_sweep_protodown(zif);
- }
- 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 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;
- zif = ifp->info;
+ 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, link_nsid);
-
- ifp->ll_type =
- netlink_to_zebra_link_type(ifi->ifi_type);
- netlink_interface_update_hw_addr(tb, ifp);
-
- if (tb[IFLA_PROTO_DOWN])
- netlink_proc_dplane_if_protodown(ifp->info, tb);
-
- if (if_is_no_ptm_operative(ifp)) {
- bool is_up = if_is_operative(ifp);
- ifp->flags = ifi->ifi_flags & 0x0000fffff;
- 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, !is_up);
-
- /* 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) &&
- !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, true);
- 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 (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));
- }
- }
+ netlink_interface_update_hw_addr(tb, ctx);
- zif = ifp->info;
- if (zif) {
- XFREE(MTYPE_ZIF_DESC, zif->desc);
- if (desc)
- zif->desc = XSTRDUP(MTYPE_ZIF_DESC, 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);
-
- 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;
}
@@ -2258,6 +1759,13 @@ ssize_t netlink_intf_msg_encode(uint16_t cmd,
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
@@ -2265,6 +1773,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);
}
/**
diff --git a/zebra/interface.c b/zebra/interface.c
index 8cf934bf7..e923c0a18 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1294,6 +1294,9 @@ static 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);
@@ -1412,6 +1415,13 @@ static void zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx,
enum dplane_netconf_status_e mpls, mcast_on, linkdown;
bool *mcast_set, *linkdown_set;
+ if (!ifp && ifindex != -1 && ifindex != -2) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: Can't find ifp(%u)", __func__, ifindex);
+
+ return;
+ }
+
afi = dplane_ctx_get_afi(ctx);
mpls = dplane_ctx_get_netconf_mpls(ctx);
linkdown = dplane_ctx_get_netconf_linkdown(ctx);
@@ -1481,6 +1491,753 @@ static void zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx,
(*linkdown_set ? "ON" : "OFF"));
}
+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:
+ break;
+ }
+}
+
+static bool is_if_protodown_reason_only_frr(uint32_t rc_bitfield)
+{
+ uint8_t frr_protodown_r_bit = if_netlink_get_frr_protodown_r_bit();
+
+ return (rc_bitfield == (((uint32_t)1) << frr_protodown_r_bit));
+}
+
+static void interface_if_protodown(struct interface *ifp, bool protodown,
+ uint32_t rc_bitfield)
+{
+ struct zebra_if *zif = ifp->info;
+ bool old_protodown;
+
+ /*
+ * Set our reason code to note it wasn't us.
+ * If the reason we got from the kernel is ONLY frr though, don't
+ * set it.
+ */
+ COND_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_EXTERNAL,
+ protodown && rc_bitfield &&
+ !is_if_protodown_reason_only_frr(rc_bitfield));
+
+
+ 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);
+
+ dplane_intf_update(zif->ifp);
+ }
+}
+
+static void if_sweep_protodown(struct zebra_if *zif)
+{
+ bool protodown;
+
+ protodown = !!ZEBRA_IF_IS_PROTODOWN(zif);
+
+ if (!protodown)
+ return;
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("interface %s sweeping protodown %s reason 0x%x",
+ zif->ifp->name, protodown ? "on" : "off",
+ zif->protodown_rc);
+
+ /* Only clear our reason codes, leave external if it was set */
+ UNSET_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_ALL);
+ dplane_intf_update(zif->ifp);
+}
+
+static void
+interface_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx,
+ struct interface *ifp)
+{
+ const struct zebra_vxlan_vni_array *vniarray =
+ dplane_ctx_get_ifp_vxlan_vni_array(ctx);
+ struct zebra_vxlan_vni vni_start, vni_end;
+ struct hash *vni_table = NULL;
+ struct zebra_vxlan_vni vni, *vnip;
+ vni_t vni_id;
+ vlanid_t vid;
+ int i;
+
+ memset(&vni_start, 0, sizeof(vni_start));
+ memset(&vni_end, 0, sizeof(vni_end));
+
+ for (i = 0; i < vniarray->count; i++) {
+ uint16_t flags = vniarray->vnis[i].flags;
+
+ if (flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_BEGIN) {
+ vni_start = vniarray->vnis[i];
+ continue;
+ }
+
+ if (flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_END)
+ vni_end = vniarray->vnis[i];
+
+ if (!(flags & DPLANE_BRIDGE_VLAN_INFO_RANGE_END)) {
+ vni_start = vniarray->vnis[i];
+ vni_end = vniarray->vnis[i];
+ }
+
+ if (IS_ZEBRA_DEBUG_DPLANE)
+ zlog_debug(
+ "Vlan-Vni(%d:%d-%d:%d) update for VxLAN IF %s(%u)",
+ vni_start.access_vlan, vni_end.access_vlan,
+ vni_start.vni, vni_end.vni, ifp->name,
+ ifp->ifindex);
+
+ if (!vni_table) {
+ vni_table = zebra_vxlan_vni_table_create();
+ if (!vni_table)
+ return;
+ }
+
+ for (vid = vni_start.access_vlan, vni_id = vni_start.vni;
+ vid <= vni_end.access_vlan; vid++, vni_id++) {
+
+ memset(&vni, 0, sizeof(vni));
+ vni.vni = vni_id;
+ vni.access_vlan = vid;
+ vnip = hash_get(vni_table, &vni, zebra_vxlan_vni_alloc);
+ if (!vnip)
+ return;
+ }
+
+ memset(&vni_start, 0, sizeof(vni_start));
+ memset(&vni_end, 0, sizeof(vni_end));
+ }
+
+ if (vni_table)
+ zebra_vxlan_if_vni_table_add_update(ifp, vni_table);
+}
+
+static void interface_bridge_vxlan_update(struct zebra_dplane_ctx *ctx,
+ struct interface *ifp)
+{
+ struct zebra_if *zif = ifp->info;
+ const struct zebra_dplane_bridge_vlan_info *bvinfo;
+
+ if (IS_ZEBRA_VXLAN_IF_SVD(zif))
+ interface_bridge_vxlan_vlan_vni_map_update(ctx, ifp);
+
+ 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;
+ }
+
+ 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, startup;
+ 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);
+ startup = dplane_ctx_get_ifp_startup(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 (startup)
+ if_sweep_protodown(zif);
+ }
+
+ 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)) {
+ bool is_up = if_is_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, !is_up);
+
+ /*
+ * 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, true);
+ 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;
@@ -1510,17 +2267,6 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx)
}
ifp = if_lookup_by_index_per_ns(zns, ifindex);
- if (ifp == NULL) {
- if (op != DPLANE_OP_INTF_NETCONFIG ||
- (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:
@@ -1531,7 +2277,15 @@ 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:
- zebra_if_update_ctx(ctx, ifp);
+ /*
+ * 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_INTF_NETCONFIG:
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 2fab21ed9..f0d442768 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -398,7 +398,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:
@@ -474,6 +474,7 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
case RTM_NEWLINK:
case RTM_DELLINK:
+ return netlink_link_change(h, ns_id, startup);
default:
break;
@@ -1169,7 +1170,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
@@ -1778,17 +1778,11 @@ void kernel_init(struct zebra_ns *zns)
* groups are added further below after SOL_NETLINK is verified to
* exist.
*/
- 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)) |
- ((uint32_t) 1 << (RTNLGRP_TC - 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)) |
+ ((uint32_t)1 << (RTNLGRP_TC - 1));
dplane_groups = (RTMGRP_LINK |
RTMGRP_IPV4_IFADDR |
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index ccbe9b27c..fff3e6416 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -1468,6 +1468,14 @@ static void routing_socket(struct zebra_ns *zns)
event_add_read(zrouter.master, kernel_read, NULL, routing_sock, NULL);
}
+void interface_list_second(struct zebra_ns *zns)
+{
+}
+
+void interface_list_tunneldump(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 2e3495a03..af170a22a 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -84,6 +84,8 @@ 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_tunneldump(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 518c948c9..3bb4936b8 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -400,6 +400,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.h b/zebra/zebra_dplane.h
index be1811593..4be3f2887 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -409,6 +409,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 52ef7350f..39c1319f3 100644
--- a/zebra/zebra_l2.c
+++ b/zebra/zebra_l2.c
@@ -244,7 +244,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;
struct zebra_l2_bridge_if *br;
@@ -283,7 +283,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;
@@ -300,7 +300,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;
@@ -327,7 +327,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;
uint16_t chgflags = 0;
diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h
index c63310e27..588917f4c 100644
--- a/zebra/zebra_l2.h
+++ b/zebra/zebra_l2.h
@@ -80,6 +80,12 @@ 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 {
@@ -159,17 +165,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 6bb5e971e..ffdb9df53 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -23,6 +23,7 @@
#include "rib.h"
#include "table_manager.h"
#include "zebra_errors.h"
+#include "zebra_dplane.h"
extern struct zebra_privs_t zserv_privs;
@@ -101,6 +102,36 @@ 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_tunneldump(zns);
+ break;
+ case ZEBRA_DPLANE_TUNNELS_READ:
+ interface_list_second(zns);
+ break;
+ case ZEBRA_DPLANE_ADDRESSES_READ:
+ route_read(zns);
+
+ vlan_read(zns);
+ kernel_read_pbr_rules(zns);
+ kernel_read_tc_qdisc(zns);
+ break;
+ }
+}
+
/* Do global enable actions - open sockets, read kernel config etc. */
int zebra_ns_enable(ns_id_t ns_id, void **info)
{
@@ -111,11 +142,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);
-
- vlan_read(zns);
- kernel_read_pbr_rules(zns);
- kernel_read_tc_qdisc(zns);
return 0;
}
diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h
index e759d522f..edf261197 100644
--- a/zebra/zebra_ns.h
+++ b/zebra/zebra_ns.h
@@ -68,6 +68,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 18345b052..93b33c9ab 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -4862,7 +4862,9 @@ static void rib_process_dplane_results(struct event *thread)
case DPLANE_OP_NEIGH_TABLE_UPDATE:
case DPLANE_OP_GRE_SET:
case DPLANE_OP_NONE:
+ break;
case DPLANE_OP_STARTUP_STAGE:
+ zebra_ns_startup_continue(ctx);
break;
} /* Dispatch by op code */