]> git.proxmox.com Git - mirror_frr.git/commitdiff
nhrpd: redirect netlink gre with zebra
authorPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 20 Dec 2019 10:10:34 +0000 (11:10 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 30 Apr 2021 08:33:18 +0000 (10:33 +0200)
as zebra has a new api to get gre and set gre source commands,
netlink gre get and netlink gre source function calls are redirected to zebra
by using the zapi interface.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
nhrpd/nhrp_interface.c
nhrpd/nhrp_route.c
nhrpd/nhrpd.h

index 402ffe9a24239a3522e1071eb69add6e5307f757..12c86c3876d7e11d3aa4ceca20a010a726eb7ce1 100644 (file)
 #include "nhrpd.h"
 #include "os.h"
 #include "netlink.h"
+#include "hash.h"
 
 DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface");
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF_GRE, "NHRP GRE interface");
+
+struct hash *nhrp_gre_list;
+
+static unsigned int nhrp_gre_info_key(const void *data)
+{
+       const struct nhrp_gre_info *r = data;
+
+       return r->ifindex;
+}
+
+static bool nhrp_gre_info_cmp(const void *data, const void *key)
+{
+       const struct nhrp_gre_info *a = data, *b = key;
+
+       if (a->ifindex == b->ifindex)
+               return true;
+       return false;
+}
+
+static void *nhrp_interface_gre_alloc(void *data)
+{
+       struct nhrp_gre_info *a;
+       struct nhrp_gre_info *b = data;
+
+       a = XMALLOC(MTYPE_NHRP_IF_GRE, sizeof(struct nhrp_gre_info));
+       memcpy(a, b, sizeof(struct nhrp_gre_info));
+       return a;
+}
+
+struct nhrp_gre_info *nhrp_gre_info_alloc(struct nhrp_gre_info *p)
+{
+       struct nhrp_gre_info *a;
+
+       a = (struct nhrp_gre_info *)hash_get(nhrp_gre_list, p,
+                                            nhrp_interface_gre_alloc);
+       return a;
+}
 
 static void nhrp_interface_update_cache_config(struct interface *ifp,
                                               bool available,
@@ -74,6 +113,9 @@ void nhrp_interface_init(void)
 {
        hook_register_prio(if_add, 0, nhrp_if_new_hook);
        hook_register_prio(if_del, 0, nhrp_if_delete_hook);
+
+       nhrp_gre_list = hash_create(nhrp_gre_info_key, nhrp_gre_info_cmp,
+                                   "NHRP GRE list Hash");
 }
 
 void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi)
@@ -102,14 +144,16 @@ static void nhrp_interface_update_source(struct interface *ifp)
 {
        struct nhrp_interface *nifp = ifp->info;
 
-       if (!nifp->source || !nifp->nbmaifp
-           || (ifindex_t)nifp->linkidx == nifp->nbmaifp->ifindex)
+       if (!nifp->source || !nifp->nbmaifp ||
+           ((ifindex_t)nifp->link_idx == nifp->nbmaifp->ifindex &&
+            (nifp->link_vrf_id == nifp->nbmaifp->vrf_id)))
                return;
 
-       nifp->linkidx = nifp->nbmaifp->ifindex;
-       debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d", ifp->name,
-              nifp->linkidx);
-       netlink_gre_set_link(ifp->ifindex, nifp->linkidx);
+       nifp->link_idx = nifp->nbmaifp->ifindex;
+       nifp->link_vrf_id = nifp->nbmaifp->vrf_id;
+       debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d, vr %u",
+              ifp->name, nifp->link_idx, nifp->link_vrf_id);
+       nhrp_send_zebra_gre_source_set(ifp, nifp->link_idx, nifp->link_vrf_id);
 }
 
 static void nhrp_interface_interface_notifier(struct notifier_block *n,
@@ -136,7 +180,8 @@ static void nhrp_interface_interface_notifier(struct notifier_block *n,
        }
 }
 
-static void nhrp_interface_update_nbma(struct interface *ifp)
+void nhrp_interface_update_nbma(struct interface *ifp,
+                               struct nhrp_gre_info *gre_info)
 {
        struct nhrp_interface *nifp = ifp->info, *nbmanifp = NULL;
        struct interface *nbmaifp = NULL;
@@ -145,21 +190,32 @@ static void nhrp_interface_update_nbma(struct interface *ifp)
        sockunion_family(&nbma) = AF_UNSPEC;
 
        if (nifp->source)
-               nbmaifp = if_lookup_by_name(nifp->source, VRF_DEFAULT);
+               nbmaifp = if_lookup_by_name(nifp->source, nifp->link_vrf_id);
 
        switch (ifp->ll_type) {
        case ZEBRA_LLT_IPGRE: {
                struct in_addr saddr = {0};
-               netlink_gre_get_info(ifp->ifindex, &nifp->grekey,
-                                    &nifp->linkidx, &saddr);
+
+               if (!gre_info) {
+                       nhrp_send_zebra_gre_request(ifp);
+                       return;
+               }
+               nifp->i_grekey = gre_info->ikey;
+               nifp->o_grekey = gre_info->okey;
+               nifp->link_idx = gre_info->ifindex_link;
+               nifp->link_vrf_id = gre_info->vrfid_link;
+               saddr.s_addr = gre_info->vtep_ip.s_addr;
+
                debugf(NHRP_DEBUG_IF, "%s: GRE: %x %x %x", ifp->name,
-                      nifp->grekey, nifp->linkidx, saddr.s_addr);
-               if (saddr.s_addr != INADDR_ANY)
-                       sockunion_set(&nbma, AF_INET, (uint8_t *)&saddr.s_addr,
+                      nifp->i_grekey, nifp->link_idx, saddr.s_addr);
+               if (saddr.s_addr)
+                       sockunion_set(&nbma, AF_INET,
+                                     (uint8_t *)&saddr.s_addr,
                                      sizeof(saddr.s_addr));
-               else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL)
+               else if (!nbmaifp && nifp->link_idx != IFINDEX_INTERNAL)
                        nbmaifp =
-                               if_lookup_by_index(nifp->linkidx, VRF_DEFAULT);
+                               if_lookup_by_index(nifp->link_idx,
+                                                  nifp->link_vrf_id);
        } break;
        default:
                break;
@@ -322,7 +378,7 @@ int nhrp_ifp_create(struct interface *ifp)
               ifp->name, ifp->ifindex, ifp->ll_type,
               if_link_type_str(ifp->ll_type));
 
-       nhrp_interface_update_nbma(ifp);
+       nhrp_interface_update_nbma(ifp, NULL);
 
        return 0;
 }
@@ -402,7 +458,7 @@ static void nhrp_interface_update_cache_config(struct interface *ifp, bool avail
 int nhrp_ifp_up(struct interface *ifp)
 {
        debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name);
-       nhrp_interface_update_nbma(ifp);
+       nhrp_interface_update_nbma(ifp, NULL);
 
        return 0;
 }
@@ -493,5 +549,5 @@ void nhrp_interface_set_source(struct interface *ifp, const char *ifname)
                free(nifp->source);
        nifp->source = ifname ? strdup(ifname) : NULL;
 
-       nhrp_interface_update_nbma(ifp);
+       nhrp_interface_update_nbma(ifp, NULL);
 }
index 23fa0771eff84f6b553f810236a237933b86214d..1f513b7c0ec17bd74e264c04a5375f425c306477 100644 (file)
@@ -380,6 +380,7 @@ void nhrp_zebra_init(void)
        zclient->neighbor_added = nhrp_neighbor_operation;
        zclient->neighbor_removed = nhrp_neighbor_operation;
        zclient->neighbor_get = nhrp_neighbor_operation;
+       zclient->gre_update = nhrp_gre_update;
        zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs);
 }
 
@@ -412,6 +413,32 @@ void nhrp_send_zebra_configure_arp(struct interface *ifp, int family)
        zclient_send_message(zclient);
 }
 
+void nhrp_send_zebra_gre_source_set(struct interface *ifp,
+                                   unsigned int link_idx,
+                                   vrf_id_t link_vrf_id)
+{
+       struct stream *s;
+
+       if (!zclient || zclient->sock < 0) {
+               zlog_err("%s : zclient not ready", __func__);
+               return;
+       }
+       if (link_idx == IFINDEX_INTERNAL || link_vrf_id == VRF_UNKNOWN) {
+               /* silently ignore */
+               return;
+       }
+       s = zclient->obuf;
+       stream_reset(s);
+       zclient_create_header(s,
+                             ZEBRA_GRE_SOURCE_SET,
+                             ifp->vrf_id);
+       stream_putl(s, ifp->ifindex);
+       stream_putl(s, link_idx);
+       stream_putl(s, link_vrf_id);
+       stream_putw_at(s, 0, stream_get_endp(s));
+       zclient_send_message(zclient);
+}
+
 void nhrp_send_zebra_nbr(union sockunion *in,
                         union sockunion *out,
                         struct interface *ifp)
@@ -429,6 +456,11 @@ void nhrp_send_zebra_nbr(union sockunion *in,
        zclient_send_message(zclient);
 }
 
+int nhrp_send_zebra_gre_request(struct interface *ifp)
+{
+       return zclient_send_zebra_gre_request(zclient, ifp);
+}
+
 void nhrp_zebra_terminate(void)
 {
        nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false);
@@ -441,3 +473,48 @@ void nhrp_zebra_terminate(void)
        route_table_finish(zebra_rib[AFI_IP]);
        route_table_finish(zebra_rib[AFI_IP6]);
 }
+
+void nhrp_gre_update(ZAPI_CALLBACK_ARGS)
+{
+       struct stream *s;
+       struct nhrp_gre_info gre_info, *val;
+       struct interface *ifp;
+
+       /* result */
+       s = zclient->ibuf;
+       if (vrf_id != VRF_DEFAULT)
+               return;
+
+       /* read GRE information */
+       STREAM_GETL(s, gre_info.ifindex);
+       STREAM_GETL(s, gre_info.ikey);
+       STREAM_GETL(s, gre_info.okey);
+       STREAM_GETL(s, gre_info.ifindex_link);
+       STREAM_GETL(s, gre_info.vrfid_link);
+       STREAM_GETL(s, gre_info.vtep_ip.s_addr);
+       STREAM_GETL(s, gre_info.vtep_ip_remote.s_addr);
+       if (gre_info.ifindex == IFINDEX_INTERNAL)
+               val = NULL;
+       else
+               val = hash_lookup(nhrp_gre_list, &gre_info);
+       if (val) {
+               if (gre_info.vtep_ip.s_addr != val->vtep_ip.s_addr ||
+                   gre_info.vrfid_link != val->vrfid_link ||
+                   gre_info.ifindex_link != val->ifindex_link ||
+                   gre_info.ikey != val->ikey ||
+                   gre_info.okey != val->okey) {
+                       /* update */
+                       memcpy(val, &gre_info, sizeof(struct nhrp_gre_info));
+               }
+       } else {
+               val = nhrp_gre_info_alloc(&gre_info);
+       }
+       ifp = if_lookup_by_index(gre_info.ifindex, vrf_id);
+       debugf(NHRP_DEBUG_EVENT, "%s: gre interface %d vr %d obtained from system",
+              ifp ? ifp->name : "<none>", gre_info.ifindex, vrf_id);
+       if (ifp)
+               nhrp_interface_update_nbma(ifp, val);
+       return;
+stream_failure:
+       zlog_err("%s(): error reading response ..", __func__);
+}
index 730f9b7d13e08e2427076fcd83bb9956456b637a..17abb04762aa021dcf8d362968b04aba99b3a4c7 100644 (file)
@@ -86,14 +86,22 @@ static inline int notifier_active(struct notifier_list *l)
        return !list_empty(&l->notifier_head);
 }
 
+extern struct hash *nhrp_gre_list;
+
 void nhrp_zebra_init(void);
 void nhrp_zebra_terminate(void);
 void nhrp_send_zebra_configure_arp(struct interface *ifp, int family);
 void nhrp_send_zebra_nbr(union sockunion *in,
                         union sockunion *out,
                         struct interface *ifp);
-void nhrp_send_zebra_configure_arp(struct interface *ifp,
-                                  int family);
+
+void nhrp_send_zebra_gre_source_set(struct interface *ifp,
+                                   unsigned int link_idx,
+                                   vrf_id_t link_vrf_id);
+
+extern int nhrp_send_zebra_gre_request(struct interface *ifp);
+extern struct nhrp_gre_info *nhrp_gre_info_alloc(struct nhrp_gre_info *p);
+
 struct zbuf;
 struct nhrp_vc;
 struct nhrp_cache;
@@ -300,8 +308,10 @@ struct nhrp_interface {
        char *ipsec_profile, *ipsec_fallback_profile, *source;
        union sockunion nbma;
        union sockunion nat_nbma;
-       unsigned int linkidx;
-       uint32_t grekey;
+       unsigned int link_idx;
+       unsigned int link_vrf_id;
+       uint32_t i_grekey;
+       uint32_t o_grekey;
 
        struct hash *peer_hash;
        struct hash *cache_config_hash;
@@ -325,6 +335,18 @@ struct nhrp_interface {
        } afi[AFI_MAX];
 };
 
+struct nhrp_gre_info {
+       ifindex_t ifindex;
+       struct in_addr vtep_ip; /* IFLA_GRE_LOCAL */
+       struct in_addr vtep_ip_remote; /* IFLA_GRE_REMOTE */
+       uint32_t ikey;
+       uint32_t okey;
+       ifindex_t ifindex_link; /* Interface index of interface
+                                * linked with GRE
+                                */
+       vrf_id_t vrfid_link;
+};
+
 extern struct zebra_privs_t nhrpd_privs;
 
 int sock_open_unix(const char *path);
@@ -332,6 +354,8 @@ int sock_open_unix(const char *path);
 void nhrp_interface_init(void);
 void nhrp_interface_update(struct interface *ifp);
 void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi);
+void nhrp_interface_update_nbma(struct interface *ifp,
+                               struct nhrp_gre_info *gre_info);
 
 int nhrp_interface_add(ZAPI_CALLBACK_ARGS);
 int nhrp_interface_delete(ZAPI_CALLBACK_ARGS);
@@ -340,6 +364,7 @@ int nhrp_interface_down(ZAPI_CALLBACK_ARGS);
 int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS);
 int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS);
 void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS);
+void nhrp_gre_update(ZAPI_CALLBACK_ARGS);
 
 void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n,
                               notifier_fn_t fn);