X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=staticd%2Fstatic_zebra.c;h=1e23f597b0384eb4f30ff2e98b4c1617e011c59f;hb=ca2c70bde099e9e9e40d5151388d1e9ba849df0d;hp=9802aa548af93046469f42d17d29793cf02229a6;hpb=8d5cbee91d0a926dcc8dd114ebebf01950cfd110;p=mirror_frr.git diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 9802aa548..1e23f597b 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -34,6 +34,8 @@ #include "log.h" #include "nexthop.h" #include "nexthop_group.h" +#include "hash.h" +#include "jhash.h" #include "static_vrf.h" #include "static_routes.h" @@ -43,6 +45,7 @@ /* Zebra structure to hold current status. */ struct zclient *zclient; +static struct hash *static_nht_hash; static struct interface *zebra_interface_if_lookup(struct stream *s) { @@ -119,11 +122,17 @@ static int interface_state_up(int command, struct zclient *zclient, ifp = zebra_interface_if_lookup(zclient->ibuf); - if (if_is_vrf(ifp)) { - struct static_vrf *svrf = static_vrf_lookup_by_id(vrf_id); + if (ifp) { + if (if_is_vrf(ifp)) { + struct static_vrf *svrf = + static_vrf_lookup_by_id(vrf_id); - static_fixup_vrf_ids(svrf); - static_config_install_delayed_routes(svrf); + static_fixup_vrf_ids(svrf); + static_config_install_delayed_routes(svrf); + } + + /* Install any static reliant on this interface coming up */ + static_install_intf_nh(ifp); } return 0; @@ -176,10 +185,19 @@ static void zebra_connected(struct zclient *zclient) zclient_send_reg_requests(zclient, VRF_DEFAULT); } +struct static_nht_data { + struct prefix *nh; + + vrf_id_t nh_vrf_id; + + uint32_t refcount; + uint8_t nh_num; +}; static int static_zebra_nexthop_update(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct static_nht_data *nhtd, lookup; struct zapi_route nhr; afi_t afi = AFI_IP; @@ -191,7 +209,20 @@ static int static_zebra_nexthop_update(int command, struct zclient *zclient, if (nhr.prefix.family == AF_INET6) afi = AFI_IP6; - static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, vrf_id); + memset(&lookup, 0, sizeof(lookup)); + lookup.nh = &nhr.prefix; + lookup.nh_vrf_id = vrf_id; + + nhtd = hash_lookup(static_nht_hash, &lookup); + + if (nhtd) { + nhtd->nh_num = nhr.nexthop_num; + + static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, + nhtd->nh_vrf_id); + } else + zlog_err("No nhtd?"); + return 1; } @@ -200,10 +231,56 @@ static void static_zebra_capabilities(struct zclient_capabilities *cap) mpls_enabled = cap->mpls_enabled; } +static unsigned int static_nht_hash_key(void *data) +{ + struct static_nht_data *nhtd = data; + unsigned int key = 0; + + key = prefix_hash_key(nhtd->nh); + return jhash_1word(nhtd->nh_vrf_id, key); +} + +static bool static_nht_hash_cmp(const void *d1, const void *d2) +{ + const struct static_nht_data *nhtd1 = d1; + const struct static_nht_data *nhtd2 = d2; + + if (nhtd1->nh_vrf_id != nhtd2->nh_vrf_id) + return false; + + return prefix_same(nhtd1->nh, nhtd2->nh); +} + +static void *static_nht_hash_alloc(void *data) +{ + struct static_nht_data *copy = data; + struct static_nht_data *new; + + new = XMALLOC(MTYPE_TMP, sizeof(*new)); + + new->nh = prefix_new(); + prefix_copy(new->nh, copy->nh); + new->refcount = 0; + new->nh_num = 0; + new->nh_vrf_id = copy->nh_vrf_id; + + return new; +} + +static void static_nht_hash_free(void *data) +{ + struct static_nht_data *nhtd = data; + + prefix_free(nhtd->nh); + XFREE(MTYPE_TMP, nhtd); +} + void static_zebra_nht_register(struct static_route *si, bool reg) { + struct static_nht_data *nhtd, lookup; uint32_t cmd; struct prefix p; + afi_t afi = AFI_IP; cmd = (reg) ? ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER; @@ -224,24 +301,54 @@ void static_zebra_nht_register(struct static_route *si, bool reg) p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = si->addr.ipv4; + afi = AFI_IP; break; case STATIC_IPV6_GATEWAY: case STATIC_IPV6_GATEWAY_IFNAME: p.family = AF_INET6; p.prefixlen = IPV6_MAX_BITLEN; p.u.prefix6 = si->addr.ipv6; + afi = AFI_IP6; break; } + memset(&lookup, 0, sizeof(lookup)); + lookup.nh = &p; + lookup.nh_vrf_id = si->nh_vrf_id; + + si->nh_registered = reg; + + if (reg) { + nhtd = hash_get(static_nht_hash, &lookup, + static_nht_hash_alloc); + nhtd->refcount++; + + if (nhtd->refcount > 1) { + static_nht_update(nhtd->nh, nhtd->nh_num, + afi, si->nh_vrf_id); + return; + } + } else { + nhtd = hash_lookup(static_nht_hash, &lookup); + if (!nhtd) + return; + + nhtd->refcount--; + if (nhtd->refcount >= 1) + return; + + hash_release(static_nht_hash, nhtd); + static_nht_hash_free(nhtd); + } + if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0) zlog_warn("%s: Failure to send nexthop to zebra", __PRETTY_FUNCTION__); - - si->nh_registered = reg; } -extern void static_zebra_route_add(struct route_node *rn, vrf_id_t vrf_id, - safi_t safi, bool install) +extern void static_zebra_route_add(struct route_node *rn, + struct static_route *si_changed, + vrf_id_t vrf_id, safi_t safi, bool install) { struct static_route *si = rn->info; const struct prefix *p, *src_pp; @@ -262,29 +369,32 @@ extern void static_zebra_route_add(struct route_node *rn, vrf_id_t vrf_id, SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX); memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix)); } - + SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE); + if (si_changed->onlink) + SET_FLAG(api.flags, ZEBRA_FLAG_ONLINK); SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - + if (si_changed->distance) { + SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = si_changed->distance; + } + if (si_changed->tag) { + SET_FLAG(api.message, ZAPI_MESSAGE_TAG); + api.tag = si_changed->tag; + } + if (si_changed->table_id != 0) { + SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); + api.tableid = si_changed->table_id; + } for (/*loaded above*/; si; si = si->next) { api_nh = &api.nexthops[nh_num]; if (si->nh_vrf_id == VRF_UNKNOWN) continue; - /* - * If we create a ecmp static route the - * last distance and tag entered wins. Why because - * this cli choosen sucks - */ - if (si->distance) { - SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); - api.distance = si->distance; - } - if (si->tag) { - SET_FLAG(api.message, ZAPI_MESSAGE_TAG); - api.tag = si->tag; - } + if (si->distance != si_changed->distance) + continue; - api.tableid = si->table_id; + if (si->table_id != si_changed->table_id) + continue; api_nh->vrf_id = si->nh_vrf_id; switch (si->type) { @@ -361,7 +471,7 @@ void static_zebra_init(void) { struct zclient_options opt = { .receive_notify = true }; - zclient = zclient_new_notify(master, &opt); + zclient = zclient_new(master, &opt); zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs); zclient->zebra_capabilities = static_zebra_capabilities; @@ -374,4 +484,8 @@ void static_zebra_init(void) zclient->interface_address_delete = interface_address_delete; zclient->route_notify_owner = route_notify_owner; zclient->nexthop_update = static_zebra_nexthop_update; + + static_nht_hash = hash_create(static_nht_hash_key, + static_nht_hash_cmp, + "Static Nexthop Tracking hash"); }