]> git.proxmox.com Git - mirror_frr.git/blobdiff - staticd/static_zebra.c
zebra: Convert socket interface to use `union sockunion`
[mirror_frr.git] / staticd / static_zebra.c
index 9802aa548af93046469f42d17d29793cf02229a6..1e23f597b0384eb4f30ff2e98b4c1617e011c59f 100644 (file)
@@ -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");
 }