diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2019-03-22 08:45:48 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-22 08:45:48 +0100 |
commit | 8d39ebf675a8a2fafde0dfa74ed927f364b3c6db (patch) | |
tree | f4e61cbdc17f60f34c1e7e510c0a98125bbf8d79 /pbrd | |
parent | Merge pull request #3972 from mjstapp/fix_privs_race (diff) | |
parent | lib, pbrd: fix indentation of a few commands (diff) | |
download | frr-8d39ebf675a8a2fafde0dfa74ed927f364b3c6db.tar.xz frr-8d39ebf675a8a2fafde0dfa74ed927f364b3c6db.zip |
Merge pull request #3776 from opensourcerouting/pbrd-interface-nexthops
pbrd: add support for interface nexthops
Diffstat (limited to 'pbrd')
-rw-r--r-- | pbrd/pbr_nht.c | 137 | ||||
-rw-r--r-- | pbrd/pbr_nht.h | 5 | ||||
-rw-r--r-- | pbrd/pbr_vty.c | 88 | ||||
-rw-r--r-- | pbrd/pbr_zebra.c | 6 |
4 files changed, 164 insertions, 72 deletions
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 6a025fd72..750475272 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -50,7 +50,7 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, static void pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, - enum nexthop_types_t nh_afi); + enum nexthop_types_t nh_type); /* * Nexthop refcount. @@ -157,7 +157,7 @@ static bool pbr_nh_hash_equal(const void *arg1, const void *arg2) switch (pbrnc1->nexthop->type) { case NEXTHOP_TYPE_IFINDEX: - return true; + return pbrnc1->nexthop->ifindex == pbrnc2->nexthop->ifindex; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: return pbrnc1->nexthop->gate.ipv4.s_addr @@ -264,6 +264,14 @@ void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); pbr_map_check_nh_group_change(nhgc->name); + + if (nhop->type == NEXTHOP_TYPE_IFINDEX) { + struct interface *ifp; + + ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id); + if (ifp) + pbr_nht_nexthop_interface_update(ifp); + } } void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, @@ -274,7 +282,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, struct pbr_nexthop_group_cache *pnhgc; struct pbr_nexthop_cache pnhc_find = {}; struct pbr_nexthop_cache *pnhc; - enum nexthop_types_t nh_afi = nhop->type; + enum nexthop_types_t nh_type = nhop->type; /* find pnhgc by name */ strlcpy(pnhgc_find.name, nhgc->name, sizeof(pnhgc_find.name)); @@ -296,7 +304,7 @@ void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, if (pnhgc->nhh->count) pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg); else - pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_afi); + pbr_nht_uninstall_nexthop_group(pnhgc, nhgc->nhg, nh_type); pbr_map_check_nh_group_change(nhgc->name); } @@ -372,39 +380,53 @@ void pbr_nht_route_removed_for_table(uint32_t table_id) * - AFI_MAX on error */ static afi_t pbr_nht_which_afi(struct nexthop_group nhg, - enum nexthop_types_t nh_afi) + enum nexthop_types_t nh_type) { struct nexthop *nexthop; afi_t install_afi = AFI_MAX; bool v6, v4, bh; + if (nh_type) { + switch (nh_type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + return AFI_IP; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + return AFI_IP6; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_BLACKHOLE: + return AFI_MAX; + } + } + v6 = v4 = bh = false; - if (!nh_afi) { - for (ALL_NEXTHOPS(nhg, nexthop)) { - nh_afi = nexthop->type; + for (ALL_NEXTHOPS(nhg, nexthop)) { + nh_type = nexthop->type; + + switch (nh_type) { + case NEXTHOP_TYPE_IFINDEX: + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + v6 = true; + install_afi = AFI_IP; + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + v4 = true; + install_afi = AFI_IP6; + break; + case NEXTHOP_TYPE_BLACKHOLE: + bh = true; break; } } - switch (nh_afi) { - case NEXTHOP_TYPE_IFINDEX: - break; - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - v6 = true; - install_afi = AFI_IP; - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - v4 = true; - install_afi = AFI_IP6; - break; - case NEXTHOP_TYPE_BLACKHOLE: - bh = true; + /* Interface and/or blackhole nexthops only. */ + if (!v4 && !v6) install_afi = AFI_MAX; - break; - } if (!bh && v6 && v4) DEBUGD(&pbr_dbg_nht, @@ -423,9 +445,9 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg) { afi_t install_afi; - enum nexthop_types_t nh_afi = 0; + enum nexthop_types_t nh_type = 0; - install_afi = pbr_nht_which_afi(nhg, nh_afi); + install_afi = pbr_nht_which_afi(nhg, nh_type); route_add(pnhgc, nhg, install_afi); } @@ -433,11 +455,11 @@ static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, static void pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, - enum nexthop_types_t nh_afi) + enum nexthop_types_t nh_type) { afi_t install_afi; - install_afi = pbr_nht_which_afi(nhg, nh_afi); + install_afi = pbr_nht_which_afi(nhg, nh_type); pnhgc->installed = false; pnhgc->valid = false; @@ -526,7 +548,7 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms) struct listnode *node; struct pbr_map_interface *pmi; struct nexthop *nh; - enum nexthop_types_t nh_afi = 0; + enum nexthop_types_t nh_type = 0; if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) @@ -542,13 +564,13 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms) pnhgc = hash_lookup(pbr_nhg_hash, &find); nh = pbrms->nhg->nexthop; - nh_afi = nh->type; + nh_type = nh->type; lup.nexthop = nh; pnhc = hash_lookup(pnhgc->nhh, &lup); pnhc->parent = NULL; hash_release(pnhgc->nhh, pnhc); pbr_nh_delete(&pnhc); - pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_afi); + pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg, nh_type); hash_release(pbr_nhg_hash, pnhgc); @@ -653,6 +675,7 @@ bool pbr_nht_nexthop_group_valid(const char *name) struct pbr_nht_individual { struct zapi_route *nhr; + struct interface *ifp; uint32_t valid; }; @@ -716,6 +739,56 @@ void pbr_nht_nexthop_update(struct zapi_route *nhr) hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr); } +static void +pbr_nht_individual_nexthop_interface_update_lookup(struct hash_backet *b, + void *data) +{ + struct pbr_nexthop_cache *pnhc = b->data; + struct pbr_nht_individual *pnhi = data; + bool old_valid; + + old_valid = pnhc->valid; + + if (pnhc->nexthop->type == NEXTHOP_TYPE_IFINDEX + && pnhc->nexthop->ifindex == pnhi->ifp->ifindex) + pnhc->valid = !!if_is_up(pnhi->ifp); + + DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d", pnhi->ifp->name, + old_valid, pnhc->valid); + + if (pnhc->valid) + pnhi->valid += 1; +} + +static void pbr_nht_nexthop_interface_update_lookup(struct hash_backet *b, + void *data) +{ + struct pbr_nexthop_group_cache *pnhgc = b->data; + struct pbr_nht_individual pnhi; + bool old_valid; + + old_valid = pnhgc->valid; + + pnhi.ifp = data; + pnhi.valid = 0; + hash_iterate(pnhgc->nhh, + pbr_nht_individual_nexthop_interface_update_lookup, &pnhi); + + /* + * If any of the specified nexthops are valid we are valid + */ + pnhgc->valid = !!pnhi.valid; + + if (old_valid != pnhgc->valid) + pbr_map_check_nh_group_change(pnhgc->name); +} + +void pbr_nht_nexthop_interface_update(struct interface *ifp) +{ + hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_interface_update_lookup, + ifp); +} + static uint32_t pbr_nhg_hash_key(void *arg) { struct pbr_nexthop_group_cache *nhgc = diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h index d37803fbe..4ef41cede 100644 --- a/pbrd/pbr_nht.h +++ b/pbrd/pbr_nht.h @@ -117,5 +117,10 @@ extern void pbr_nht_show_nexthop_group(struct vty *vty, const char *name); */ extern void pbr_nht_nexthop_update(struct zapi_route *nhr); +/* + * When we get a callback from zebra about an interface status update. + */ +extern void pbr_nht_nexthop_interface_update(struct interface *ifp); + extern void pbr_nht_init(void); #endif diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index f8232c958..067d5c01f 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -221,13 +221,19 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, } DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, - "[no] set nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]", + "[no] set nexthop\ + <\ + <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\ + |INTERFACE$intf\ + >\ + [nexthop-vrf NAME$name]", NO_STR "Set for the PBR-MAP\n" "Specify one of the nexthops in this map\n" "v4 Address\n" "v6 Address\n" "Interface to use\n" + "Interface to use\n" "If the nexthop is in a different vrf tell us\n" "The nexthop-vrf Name\n") { @@ -255,44 +261,38 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, memset(&nhop, 0, sizeof(nhop)); nhop.vrf_id = vrf->vrf_id; - /* - * Make SA happy. CLIPPY is not going to give us a NULL - * addr. - */ - assert(addr); - if (addr->sa.sa_family == AF_INET) { - nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; - if (intf) { - nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX; - nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); - if (nhop.ifindex == IFINDEX_INTERNAL) { - vty_out(vty, - "Specified Intf %s does not exist in vrf: %s\n", - intf, vrf->name); - return CMD_WARNING_CONFIG_FAILED; - } - } else - nhop.type = NEXTHOP_TYPE_IPV4; - } else { - memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16); - if (intf) { - nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX; - nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); - if (nhop.ifindex == IFINDEX_INTERNAL) { - vty_out(vty, - "Specified Intf %s does not exist in vrf: %s\n", - intf, vrf->name); - return CMD_WARNING_CONFIG_FAILED; - } + if (intf) { + nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id); + if (nhop.ifindex == IFINDEX_INTERNAL) { + vty_out(vty, + "Specified Intf %s does not exist in vrf: %s\n", + intf, vrf->name); + return CMD_WARNING_CONFIG_FAILED; + } + } + + if (addr) { + if (addr->sa.sa_family == AF_INET) { + nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr; + if (intf) + nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX; + else + nhop.type = NEXTHOP_TYPE_IPV4; } else { - if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { - vty_out(vty, - "Specified a v6 LL with no interface, rejecting\n"); - return CMD_WARNING_CONFIG_FAILED; + nhop.gate.ipv6 = addr->sin6.sin6_addr; + if (intf) + nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX; + else { + if (IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { + vty_out(vty, + "Specified a v6 LL with no interface, rejecting\n"); + return CMD_WARNING_CONFIG_FAILED; + } + nhop.type = NEXTHOP_TYPE_IPV6; } - nhop.type = NEXTHOP_TYPE_IPV6; } - } + } else + nhop.type = NEXTHOP_TYPE_IFINDEX; if (pbrms->nhg) nh = nexthop_exists(pbrms->nhg, &nhop); @@ -335,6 +335,14 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, pbr_map_check(pbrms); } + if (nhop.type == NEXTHOP_TYPE_IFINDEX) { + struct interface *ifp; + + ifp = if_lookup_by_index(nhop.ifindex, nhop.vrf_id); + if (ifp) + pbr_nht_nexthop_interface_update(ifp); + } + return CMD_SUCCESS; } @@ -616,18 +624,18 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty, vty_out(vty, "pbr-map %s seq %u\n", pbrm->name, pbrms->seqno); if (pbrms->src) - vty_out(vty, " match src-ip %s\n", + vty_out(vty, " match src-ip %s\n", prefix2str(pbrms->src, buff, sizeof(buff))); if (pbrms->dst) - vty_out(vty, " match dst-ip %s\n", + vty_out(vty, " match dst-ip %s\n", prefix2str(pbrms->dst, buff, sizeof(buff))); if (pbrms->nhgrp_name) - vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name); + vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name); if (pbrms->nhg) { - vty_out(vty, " set "); + vty_out(vty, " set "); nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop); } diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 558e63574..44c8daa97 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -75,6 +75,8 @@ static int interface_add(int command, struct zclient *zclient, if (!ifp->info) pbr_if_new(ifp); + pbr_nht_nexthop_interface_update(ifp); + return 0; } @@ -144,6 +146,8 @@ static int interface_state_up(int command, struct zclient *zclient, DEBUGD(&pbr_dbg_zebra, "%s: %s is up", __PRETTY_FUNCTION__, ifp->name); + pbr_nht_nexthop_interface_update(ifp); + return 0; } @@ -157,6 +161,8 @@ static int interface_state_down(int command, struct zclient *zclient, DEBUGD(&pbr_dbg_zebra, "%s: %s is down", __PRETTY_FUNCTION__, ifp->name); + pbr_nht_nexthop_interface_update(ifp); + return 0; } |