summaryrefslogtreecommitdiffstats
path: root/zebra/interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/interface.c')
-rw-r--r--zebra/interface.c779
1 files changed, 767 insertions, 12 deletions
diff --git a/zebra/interface.c b/zebra/interface.c
index ae446988d..7df73e298 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1299,6 +1299,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);
@@ -1417,6 +1420,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);
@@ -1486,6 +1496,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;
@@ -1515,17 +2272,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:
@@ -1536,7 +2282,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:
@@ -1591,6 +2345,7 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_TC_FILTER_ADD:
case DPLANE_OP_TC_FILTER_DELETE:
case DPLANE_OP_TC_FILTER_UPDATE:
+ case DPLANE_OP_STARTUP_STAGE:
break; /* should never hit here */
}
}