diff options
Diffstat (limited to 'lib/if.c')
| -rw-r--r-- | lib/if.c | 62 |
1 files changed, 40 insertions, 22 deletions
@@ -48,6 +48,7 @@ DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters"); static void if_set_name(struct interface *ifp, const char *name); static struct interface *if_lookup_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); +static struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex); static int if_cmp_func(const struct interface *, const struct interface *); static int if_cmp_index_func(const struct interface *ifp1, const struct interface *ifp2); @@ -302,9 +303,6 @@ void if_delete(struct interface **ifp) if (ptr->ifindex != IFINDEX_INTERNAL) IFINDEX_RB_REMOVE(vrf, ptr); - if (!vrf_is_enabled(vrf)) - vrf_delete(vrf); - if_delete_retain(ptr); list_delete(&ptr->connected); @@ -440,7 +438,7 @@ static struct interface *if_lookup_by_name_all_vrf(const char *name) return NULL; } -struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex) +static struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex) { struct vrf *vrf; struct interface *ifp; @@ -457,36 +455,51 @@ struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex) return NULL; } -/* Lookup interface by IP address. */ -struct interface *if_lookup_exact_address(const void *src, int family, +/* Lookup interface by IP address. + * + * supersedes if_lookup_exact_address(), which didn't care about up/down + * state. but all users we have either only care if the address is local + * (=> use if_address_is_local() please), or care about UP interfaces before + * anything else + * + * to accept only UP interfaces, check if_is_up() on the returned ifp. + */ +struct interface *if_lookup_address_local(const void *src, int family, vrf_id_t vrf_id) { struct vrf *vrf = vrf_lookup_by_id(vrf_id); struct listnode *cnode; - struct interface *ifp; + struct interface *ifp, *best_down = NULL; struct prefix *p; struct connected *c; + if (family != AF_INET && family != AF_INET6) + return NULL; + FOR_ALL_INTERFACES (vrf, ifp) { for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { p = c->address; - if (p && (p->family == family)) { - if (family == AF_INET) { - if (IPV4_ADDR_SAME( - &p->u.prefix4, + if (!p || p->family != family) + continue; + + if (family == AF_INET) { + if (!IPV4_ADDR_SAME(&p->u.prefix4, (struct in_addr *)src)) - return ifp; - } else if (family == AF_INET6) { - if (IPV6_ADDR_SAME( - &p->u.prefix6, + continue; + } else if (family == AF_INET6) { + if (!IPV6_ADDR_SAME(&p->u.prefix6, (struct in6_addr *)src)) - return ifp; - } + continue; } + + if (if_is_up(ifp)) + return ifp; + if (!best_down) + best_down = ifp; } } - return NULL; + return best_down; } /* Lookup interface by IP address. */ @@ -700,7 +713,7 @@ int if_is_no_ptm_operative(const struct interface *ifp) } /* Is this loopback interface ? */ -int if_is_loopback(const struct interface *ifp) +int if_is_loopback_exact(const struct interface *ifp) { /* XXX: Do this better, eg what if IFF_WHATEVER means X on platform M * but Y on platform N? @@ -714,9 +727,10 @@ int if_is_vrf(const struct interface *ifp) return CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); } -bool if_is_loopback_or_vrf(const struct interface *ifp) +/* Should this interface be treated as a loopback? */ +bool if_is_loopback(const struct interface *ifp) { - if (if_is_loopback(ifp) || if_is_vrf(ifp)) + if (if_is_loopback_exact(ifp) || if_is_vrf(ifp)) return true; return false; @@ -1419,7 +1433,7 @@ static int lib_interface_create(struct nb_cb_create_args *args) static int lib_interface_destroy(struct nb_cb_destroy_args *args) { struct interface *ifp; - + struct vrf *vrf; switch (args->event) { case NB_EV_VALIDATE: @@ -1435,9 +1449,13 @@ static int lib_interface_destroy(struct nb_cb_destroy_args *args) break; case NB_EV_APPLY: ifp = nb_running_unset_entry(args->dnode); + vrf = ifp->vrf; ifp->configured = false; if_delete(&ifp); + + if (!vrf_is_enabled(vrf)) + vrf_delete(vrf); break; } |
