diff options
Diffstat (limited to 'zebra/connected.c')
-rw-r--r-- | zebra/connected.c | 87 |
1 files changed, 63 insertions, 24 deletions
diff --git a/zebra/connected.c b/zebra/connected.c index ee0823f..404f892 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -48,7 +48,7 @@ static void connected_withdraw(struct connected *ifc) UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) { - listnode_delete(ifc->ifp->connected, ifc); + if_connected_del(ifc->ifp->connected, ifc); connected_free(&ifc); } } @@ -65,7 +65,7 @@ static void connected_announce(struct interface *ifp, struct connected *ifc) UNSET_FLAG(ifc->flags, ZEBRA_IFA_UNNUMBERED); } - listnode_add(ifp->connected, ifc); + if_connected_add_tail(ifp->connected, ifc); /* Update interface address information to protocol daemon. */ if (ifc->address->family == AF_INET) @@ -84,9 +84,8 @@ struct connected *connected_check(struct interface *ifp, { const struct prefix *p = pu.p; struct connected *ifc; - struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) + frr_each (if_connected, ifp->connected, ifc) if (prefix_same(ifc->address, p)) return ifc; @@ -101,9 +100,8 @@ struct connected *connected_check_ptp(struct interface *ifp, const struct prefix *p = pu.p; const struct prefix *d = du.p; struct connected *ifc; - struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { if (!prefix_same(ifc->address, p)) continue; if (!CONNECTED_PEER(ifc) && !d) @@ -182,7 +180,7 @@ static void connected_update(struct interface *ifp, struct connected *ifc) void connected_up(struct interface *ifp, struct connected *ifc) { afi_t afi; - struct prefix p; + struct prefix p, plocal; struct nexthop nh = { .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, @@ -192,8 +190,8 @@ void connected_up(struct interface *ifp, struct connected *ifc) uint32_t metric; uint32_t flags = 0; uint32_t count = 0; - struct listnode *cnode; struct connected *c; + bool install_local = true; zvrf = ifp->vrf->info; if (!zvrf) { @@ -210,6 +208,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) UNSET_FLAG(ifc->conf, ZEBRA_IFC_DOWN); prefix_copy(&p, CONNECTED_PREFIX(ifc)); + prefix_copy(&plocal, ifc->address); /* Apply mask to the network. */ apply_mask(&p); @@ -224,6 +223,8 @@ void connected_up(struct interface *ifp, struct connected *ifc) */ if (prefix_ipv4_any((struct prefix_ipv4 *)&p)) return; + + plocal.prefixlen = IPV4_MAX_BITLEN; break; case AFI_IP6: #ifndef GNU_LINUX @@ -231,6 +232,11 @@ void connected_up(struct interface *ifp, struct connected *ifc) if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6)) return; #endif + + if (IN6_IS_ADDR_LINKLOCAL(&plocal.u.prefix6)) + install_local = false; + + plocal.prefixlen = IPV6_MAX_BITLEN; break; case AFI_UNSPEC: case AFI_L2VPN: @@ -262,7 +268,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) * for all the addresses on an interface that * resolve to the same network and mask */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { struct prefix cp; prefix_copy(&cp, CONNECTED_PREFIX(c)); @@ -276,13 +282,24 @@ void connected_up(struct interface *ifp, struct connected *ifc) return; } - rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, - false); + if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, + zvrf->table_id, metric, 0, 0, 0, false); - rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, - false); + rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, + zvrf->table_id, metric, 0, 0, 0, false); + } + + if (install_local) { + rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_LOCAL, + 0, flags, &plocal, NULL, &nh, 0, zvrf->table_id, 0, 0, + 0, 0, false); + rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_LOCAL, 0, flags, &plocal, NULL, &nh, 0, + zvrf->table_id, 0, 0, 0, 0, false); + } /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { @@ -368,7 +385,7 @@ void connected_add_ipv4(struct interface *ifp, int flags, void connected_down(struct interface *ifp, struct connected *ifc) { afi_t afi; - struct prefix p; + struct prefix p, plocal; struct nexthop nh = { .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, @@ -376,8 +393,8 @@ void connected_down(struct interface *ifp, struct connected *ifc) }; struct zebra_vrf *zvrf; uint32_t count = 0; - struct listnode *cnode; struct connected *c; + bool remove_local = true; zvrf = ifp->vrf->info; if (!zvrf) { @@ -403,6 +420,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) } prefix_copy(&p, CONNECTED_PREFIX(ifc)); + prefix_copy(&plocal, ifc->address); /* Apply mask to the network. */ apply_mask(&p); @@ -417,10 +435,18 @@ void connected_down(struct interface *ifp, struct connected *ifc) */ if (prefix_ipv4_any((struct prefix_ipv4 *)&p)) return; + + plocal.prefixlen = IPV4_MAX_BITLEN; break; case AFI_IP6: if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6)) return; + + plocal.prefixlen = IPV6_MAX_BITLEN; + + if (IN6_IS_ADDR_LINKLOCAL(&plocal.u.prefix6)) + remove_local = false; + break; case AFI_UNSPEC: case AFI_L2VPN: @@ -439,7 +465,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) * allow the deletion when are removing the last * one. */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { struct prefix cp; prefix_copy(&cp, CONNECTED_PREFIX(c)); @@ -457,11 +483,25 @@ void connected_down(struct interface *ifp, struct connected *ifc) * Same logic as for connected_up(): push the changes into the * head. */ - rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); + if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); + + rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); + } + + if (remove_local) { + rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_LOCAL, 0, 0, &plocal, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); - rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, - 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); + rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_LOCAL, 0, 0, &plocal, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); + } /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { @@ -616,9 +656,8 @@ void connected_delete_ipv6(struct interface *ifp, int connected_is_unnumbered(struct interface *ifp) { struct connected *connected; - struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) && connected->address->family == AF_INET) return CHECK_FLAG(connected->flags, |