diff options
Diffstat (limited to 'zebra/interface.c')
| -rw-r--r-- | zebra/interface.c | 273 |
1 files changed, 214 insertions, 59 deletions
diff --git a/zebra/interface.c b/zebra/interface.c index a76f8741e0..d326109c19 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1229,58 +1229,73 @@ void zebra_if_update_all_links(struct zebra_ns *zns) } } -void zebra_if_set_protodown(struct interface *ifp, bool down) +int zebra_if_set_protodown(struct interface *ifp, bool new_down, + enum protodown_reasons new_reason) { + struct zebra_if *zif; + bool old_down; + uint32_t new_protodown_rc; + + zif = ifp->info; + + old_down = !!(zif->flags & ZIF_FLAG_PROTODOWN); + + if (new_down) + new_protodown_rc = zif->protodown_rc | new_reason; + else + new_protodown_rc = zif->protodown_rc & ~new_reason; + + /* Early return if already set down & reason bitfield matches */ + if ((new_down == old_down) && (new_protodown_rc == zif->protodown_rc)) { + + if (IS_ZEBRA_DEBUG_KERNEL) { + zlog_debug( + "Ignoring %s (%u): protodown %s already set reason: old 0x%x new 0x%x", + ifp->name, ifp->ifindex, + new_down ? "on" : "off", zif->protodown_rc, + new_protodown_rc); + return 1; + } + } + + zlog_info( + "Setting interface %s (%u): protodown %s reason: old 0x%x new 0x%x", + ifp->name, ifp->ifindex, new_down ? "on" : "off", + zif->protodown_rc, new_protodown_rc); + + zif->protodown_rc = new_protodown_rc; + #ifdef HAVE_NETLINK - netlink_protodown(ifp, down); + // TODO: remove this as separate commit + // netlink_protodown(ifp, new_down, zif->protodown_rc); + dplane_intf_update(ifp); #else zlog_warn("Protodown is not supported on this platform"); #endif + return 0; } /* - * Handle an interface addr event based on info in a dplane context object. + * Handle an interface events based on info in a dplane context object. * This runs in the main pthread, using the info in the context object to * modify an interface. */ -void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx) +static void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx, + struct interface *ifp) { - struct interface *ifp; uint8_t flags = 0; const char *label = NULL; - ns_id_t ns_id; - struct zebra_ns *zns; uint32_t metric = METRIC_MAX; - ifindex_t ifindex; const struct prefix *addr, *dest = NULL; enum dplane_op_e op; op = dplane_ctx_get_op(ctx); - ns_id = dplane_ctx_get_ns_id(ctx); - - zns = zebra_ns_lookup(ns_id); - if (zns == NULL) { - /* No ns - deleted maybe? */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: can't find zns id %u", __func__, ns_id); - goto done; - } - - ifindex = dplane_ctx_get_ifindex(ctx); - - ifp = if_lookup_by_index_per_ns(zns, ifindex); - if (ifp == NULL) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: can't find ifp at nsid %u index %d", - __func__, ns_id, ifindex); - goto done; - } - addr = dplane_ctx_get_intf_addr(ctx); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: %s: ifindex %u, addr %pFX", __func__, - dplane_op2str(op), ifindex, addr); + zlog_debug("%s: %s: ifindex %s(%u), addr %pFX", __func__, + dplane_op2str(dplane_ctx_get_op(ctx)), ifp->name, + ifp->ifindex, addr); /* Is there a peer or broadcast address? */ dest = dplane_ctx_get_intf_dest(ctx); @@ -1335,41 +1350,64 @@ void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx) */ if (op != DPLANE_OP_INTF_ADDR_ADD) rib_update(RIB_UPDATE_KERNEL); +} -done: - /* We're responsible for the ctx object */ - dplane_ctx_fini(&ctx); +static void zebra_if_update_ctx(struct zebra_dplane_ctx *ctx, + struct interface *ifp) +{ + enum zebra_dplane_result dp_res; + struct zebra_if *zif; + uint32_t r_bitfield; + bool down; + + dp_res = dplane_ctx_get_status(ctx); + r_bitfield = dplane_ctx_get_intf_r_bitfield(ctx); + down = dplane_ctx_intf_is_protodown(ctx); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s: if %s(%u) ctx-protodown %s ctx-reason 0x%x", + __func__, dplane_op2str(dplane_ctx_get_op(ctx)), + ifp->name, ifp->ifindex, down ? "on" : "off", + r_bitfield); + + zif = ifp->info; + if (!zif) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: if %s(%u) zebra info pointer is NULL", + __func__, ifp->name, ifp->ifindex); + return; + } + + if (dp_res != ZEBRA_DPLANE_REQUEST_SUCCESS) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: if %s(%u) dplane update failed", + __func__, ifp->name, ifp->ifindex); + return; + } + + /* Update our info */ + if (down) + zif->flags |= ZIF_FLAG_PROTODOWN; + else + zif->flags &= ~ZIF_FLAG_PROTODOWN; } /* * Handle netconf change from a dplane context object; runs in the main * pthread so it can update zebra data structs. */ -int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx) +static void zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx, + struct interface *ifp) { - struct zebra_ns *zns; - struct interface *ifp; struct zebra_if *zif; enum dplane_netconf_status_e mpls; - int ret = 0; - - zns = zebra_ns_lookup(dplane_ctx_get_netconf_ns_id(ctx)); - if (zns == NULL) { - ret = -1; - goto done; - } - - ifp = if_lookup_by_index_per_ns(zns, - dplane_ctx_get_netconf_ifindex(ctx)); - if (ifp == NULL) { - ret = -1; - goto done; - } zif = ifp->info; - if (zif == NULL) { - ret = -1; - goto done; + if (!zif) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: if %s(%u) zebra info pointer is NULL", + __func__, ifp->name, ifp->ifindex); + return; } mpls = dplane_ctx_get_netconf_mpls(ctx); @@ -1383,12 +1421,105 @@ int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx) zlog_debug("%s: if %s, ifindex %d, mpls %s", __func__, ifp->name, ifp->ifindex, (zif->mpls ? "ON" : "OFF")); +} + +void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) +{ + struct zebra_ns *zns; + struct interface *ifp; + ns_id_t ns_id; + enum dplane_op_e op; + enum zebra_dplane_result dp_res; + ifindex_t ifindex; + + ns_id = dplane_ctx_get_ns_id(ctx); + dp_res = dplane_ctx_get_status(ctx); + op = dplane_ctx_get_op(ctx); + ifindex = dplane_ctx_get_ifindex(ctx); + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Intf dplane ctx %p, op %s, ifindex (%u), result %s", + ctx, dplane_op2str(op), ifindex, + dplane_res2str(dp_res)); + + zns = zebra_ns_lookup(ns_id); + if (zns == NULL) { + /* No ns - deleted maybe? */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: can't find zns id %u", __func__, ns_id); + + goto done; + } + ifp = if_lookup_by_index_per_ns(zns, ifindex); + if (ifp == NULL) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: can't find ifp at nsid %u index %d", + __func__, ns_id, ifindex); + + goto done; + } + + switch (op) { + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: + zebra_if_addr_update_ctx(ctx, ifp); + break; + + case DPLANE_OP_INTF_INSTALL: + case DPLANE_OP_INTF_UPDATE: + case DPLANE_OP_INTF_DELETE: + zebra_if_update_ctx(ctx, ifp); + break; + + case DPLANE_OP_INTF_NETCONFIG: + zebra_if_netconf_update_ctx(ctx, ifp); + break; + + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: + case DPLANE_OP_NH_DELETE: + case DPLANE_OP_NH_INSTALL: + case DPLANE_OP_NH_UPDATE: + case DPLANE_OP_ROUTE_NOTIFY: + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + case DPLANE_OP_LSP_DELETE: + case DPLANE_OP_LSP_NOTIFY: + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + case DPLANE_OP_SYS_ROUTE_ADD: + case DPLANE_OP_SYS_ROUTE_DELETE: + case DPLANE_OP_ADDR_INSTALL: + case DPLANE_OP_ADDR_UNINSTALL: + case DPLANE_OP_MAC_INSTALL: + case DPLANE_OP_MAC_DELETE: + case DPLANE_OP_NEIGH_INSTALL: + case DPLANE_OP_NEIGH_UPDATE: + case DPLANE_OP_NEIGH_DELETE: + case DPLANE_OP_NEIGH_IP_INSTALL: + case DPLANE_OP_NEIGH_IP_DELETE: + case DPLANE_OP_VTEP_ADD: + case DPLANE_OP_VTEP_DELETE: + case DPLANE_OP_RULE_ADD: + case DPLANE_OP_RULE_DELETE: + case DPLANE_OP_RULE_UPDATE: + case DPLANE_OP_NEIGH_DISCOVER: + case DPLANE_OP_BR_PORT_UPDATE: + case DPLANE_OP_NONE: + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: + case DPLANE_OP_NEIGH_TABLE_UPDATE: + case DPLANE_OP_GRE_SET: + break; /* should never hit here */ + } done: - /* Free the context */ dplane_ctx_fini(&ctx); - - return ret; } /* Dump if address information to vty. */ @@ -1651,8 +1782,8 @@ static void ifs_dump_brief_vty_json(json_object *json, struct vrf *vrf) } } -const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc, - char *pd_buf, uint32_t pd_buf_len) +const char *zebra_protodown_rc_str(uint32_t protodown_rc, char *pd_buf, + uint32_t pd_buf_len) { bool first = true; @@ -1660,6 +1791,14 @@ const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc, strlcat(pd_buf, "(", pd_buf_len); + if (protodown_rc & ZEBRA_PROTODOWN_EXTERNAL) { + if (first) + first = false; + else + strlcat(pd_buf, ",", pd_buf_len); + strlcat(pd_buf, "external", pd_buf_len); + } + if (protodown_rc & ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY) { if (first) first = false; @@ -1669,11 +1808,27 @@ const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc, } if (protodown_rc & ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN) { - if (!first) + if (first) + first = false; + else strlcat(pd_buf, ",", pd_buf_len); strlcat(pd_buf, "uplinks-down", pd_buf_len); } + if (protodown_rc & ZEBRA_PROTODOWN_VRRP) { + if (first) + first = false; + else + strlcat(pd_buf, ",", pd_buf_len); + strlcat(pd_buf, "vrrp", pd_buf_len); + } + + if (protodown_rc & ZEBRA_PROTODOWN_SHARP) { + if (!first) + strlcat(pd_buf, ",", pd_buf_len); + strlcat(pd_buf, "sharp", pd_buf_len); + } + strlcat(pd_buf, ")", pd_buf_len); return pd_buf; |
