]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: link layer config and notification, implementation in zebra
authorPhilippe Guibert <philippe.guibert@6wind.com>
Thu, 12 Dec 2019 15:06:59 +0000 (16:06 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 9 Apr 2021 16:29:58 +0000 (18:29 +0200)
zebra implements zebra api for configuring link layer information. that
can be an arp entry (for ipv4) or ipv6 neighbor discovery entry. This
can also be an ipv4/ipv6 entry associated to an underlay ipv4 address,
as it is used in gre point to multipoint interfaces.
this api will also be used as monitoring. an hash list is instantiated
into zebra (this is the vrf bitmap). each client interested in those entries
in a specific vrf, will listen for following messages: entries added, removed,
or who-has messages.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
lib/log.c
lib/zclient.h
zebra/rt.h
zebra/rt_netlink.c
zebra/rt_socket.c
zebra/zapi_msg.c
zebra/zapi_msg.h
zebra/zserv.c
zebra/zserv.h

index 9a8a91b004c6abcc75a40211d9fc785ef4cf85ca..6e8df99512b1032e5997ccf278e346d71bb0b09b 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -467,7 +467,9 @@ static const struct zebra_desc_table command_types[] = {
        DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_DEL),
        DESC_ENTRY(ZEBRA_NHRP_NEIGH_ADDED),
        DESC_ENTRY(ZEBRA_NHRP_NEIGH_REMOVED),
-       DESC_ENTRY(ZEBRA_NHRP_NEIGH_GET)};
+       DESC_ENTRY(ZEBRA_NHRP_NEIGH_GET),
+       DESC_ENTRY(ZEBRA_NHRP_NEIGH_REGISTER),
+       DESC_ENTRY(ZEBRA_NHRP_NEIGH_UNREGISTER)};
 
 #undef DESC_ENTRY
 
index a99f2eba168c737beccf325429df9caa4b05f4f2..d0d77f93c22a79dd1a6087e849e38520480e3747 100644 (file)
@@ -226,6 +226,8 @@ typedef enum {
        ZEBRA_NHRP_NEIGH_ADDED,
        ZEBRA_NHRP_NEIGH_REMOVED,
        ZEBRA_NHRP_NEIGH_GET,
+       ZEBRA_NHRP_NEIGH_REGISTER,
+       ZEBRA_NHRP_NEIGH_UNREGISTER,
 } zebra_message_types_t;
 
 enum zebra_error_types {
index 48f1df28685ef419d6980282f87a0b4473d79846..00ff378753d77cee5e50563c00618e655bdba538 100644 (file)
@@ -70,6 +70,8 @@ kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx);
 
 extern int kernel_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
                               int llalen, ns_id_t ns_id);
+extern int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client,
+                                bool reg);
 extern int kernel_interface_set_master(struct interface *master,
                                       struct interface *slave);
 
index 55e0775a8c49dffe30f87564a4b55d4d9bf08b0f..82ef78d299e568928b3ce823943d57f58fb510fc 100644 (file)
@@ -3307,6 +3307,8 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        bool local_inactive;
        uint32_t ext_flags = 0;
        bool dp_static = false;
+       int l2_len = 0;
+       int cmd;
 
        ndm = NLMSG_DATA(h);
 
@@ -3348,6 +3350,34 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
        if (h->nlmsg_type == RTM_NEWNEIGH && !(ndm->ndm_state & NUD_VALID))
                netlink_handle_5549(ndm, zif, ifp, &ip, true);
 
+       /* we send link layer information to client:
+        * - nlmsg_type = RTM_DELNEIGH|NEWNEIGH|GETNEIGH
+        * - struct ipaddr ( for DEL and GET)
+        * - struct ethaddr mac; (for NEW)
+        */
+       if (h->nlmsg_type == RTM_NEWNEIGH)
+               cmd = ZEBRA_NHRP_NEIGH_ADDED;
+       else if (h->nlmsg_type == RTM_GETNEIGH)
+               cmd = ZEBRA_NHRP_NEIGH_GET;
+       else if (h->nlmsg_type == RTM_DELNEIGH)
+               cmd = ZEBRA_NHRP_NEIGH_REMOVED;
+       else {
+               zlog_debug("%s(): unknown nlmsg type %u", __func__,
+                          h->nlmsg_type);
+               return 0;
+       }
+       if (tb[NDA_LLADDR]) {
+               /* copy LLADDR information */
+               l2_len = RTA_PAYLOAD(tb[NDA_LLADDR]);
+               memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), l2_len);
+       }
+       if (l2_len == IPV4_MAX_BYTELEN || l2_len == 0)
+               zsend_nhrp_neighbor_notify(cmd, ifp, &ip, ndm->ndm_state,
+                                          &mac, l2_len);
+
+       if (h->nlmsg_type == RTM_GETNEIGH)
+               return 0;
+
        /* The neighbor is present on an SVI. From this, we locate the
         * underlying
         * bridge because we're only interested in neighbors on a VxLAN bridge.
@@ -3615,7 +3645,8 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
        int len;
        struct ndmsg *ndm;
 
-       if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH))
+       if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH
+             || h->nlmsg_type == RTM_GETNEIGH))
                return 0;
 
        /* Length validity. */
index a0f401c33469fb4b66f503e1fcbc7a83c3bc12b2..5fdf589624cc5528fecf312115973dd34b4b78db 100644 (file)
@@ -362,6 +362,12 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
        return ZEBRA_DPLANE_REQUEST_SUCCESS;
 }
 
+int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client, bool reg)
+{
+       /* TODO */
+       return 0;
+}
+
 int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
                        int llalen, ns_id_t ns_id)
 {
index b482914418f9b1c5b6d053a129f1149cc39556ea..304a6a03f1fed4becee047420e15455d403eee4f 100644 (file)
@@ -974,6 +974,52 @@ void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx,
        zserv_send_message(client, s);
 }
 
+void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp,
+                               struct ipaddr *ipaddr, int ndm_state,
+                               void *mac, int macsize)
+{
+       struct stream *s;
+       struct listnode *node, *nnode;
+       struct zserv *client;
+       afi_t afi;
+
+       if (IS_ZEBRA_DEBUG_PACKET)
+               zlog_debug("%s: Notifying Neighbor entry (%u)",
+                          __PRETTY_FUNCTION__, cmd);
+
+       if (ipaddr->ipa_type == IPADDR_V4)
+               afi = AFI_IP;
+       else if (ipaddr->ipa_type == IPADDR_V6)
+               afi = AFI_IP6;
+       else
+               return;
+       for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+               if (!vrf_bitmap_check(client->nhrp_neighinfo[afi], ifp->vrf_id))
+                       continue;
+
+               s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+               zclient_create_header(s, cmd, ifp->vrf_id);
+               stream_putl(s, ifp->ifindex);
+               if (ipaddr->ipa_type == IPADDR_V4) {
+                       stream_putw(s, AF_INET);
+                       stream_put(s, &ipaddr->ip._v4_addr, IPV4_MAX_BYTELEN);
+               } else if (ipaddr->ipa_type == IPADDR_V6) {
+                       stream_putw(s, AF_INET6);
+                       stream_put(s, &ipaddr->ip._v6_addr, IPV6_MAX_BYTELEN);
+               } else
+                       return;
+               stream_putl(s, ndm_state);
+               stream_putl(s, macsize);
+               if (mac)
+                       stream_put(s, mac, macsize);
+               stream_putw_at(s, 0, stream_get_endp(s));
+
+               zserv_send_message(client, s);
+       }
+}
+
+
 /* Router-id is updated. Send ZEBRA_ROUTER_ID_UPDATE to client. */
 int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p,
                           vrf_id_t vrf_id)
@@ -2277,6 +2323,7 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS)
                        vrf_bitmap_unset(client->redist[afi][i], zvrf_id(zvrf));
                vrf_bitmap_unset(client->redist_default[afi], zvrf_id(zvrf));
                vrf_bitmap_unset(client->ridinfo[afi], zvrf_id(zvrf));
+               vrf_bitmap_unset(client->nhrp_neighinfo[afi], zvrf_id(zvrf));
        }
 }
 
@@ -3167,6 +3214,38 @@ stream_failure:
        return;
 }
 
+static inline void zebra_neigh_register(ZAPI_HANDLER_ARGS)
+{
+       afi_t afi;
+
+       STREAM_GETW(msg, afi);
+       if (afi <= AFI_UNSPEC || afi >= AFI_MAX) {
+               zlog_warn(
+                       "Invalid AFI %u while registering for neighbors notifications",
+                       afi);
+               goto stream_failure;
+       }
+       vrf_bitmap_set(client->nhrp_neighinfo[afi], zvrf_id(zvrf));
+stream_failure:
+       return;
+}
+
+static inline void zebra_neigh_unregister(ZAPI_HANDLER_ARGS)
+{
+       afi_t afi;
+
+       STREAM_GETW(msg, afi);
+       if (afi <= AFI_UNSPEC || afi >= AFI_MAX) {
+               zlog_warn(
+                       "Invalid AFI %u while unregistering from neighbor notifications",
+                       afi);
+               goto stream_failure;
+       }
+       vrf_bitmap_unset(client->nhrp_neighinfo[afi], zvrf_id(zvrf));
+stream_failure:
+       return;
+}
+
 static inline void zread_iptable(ZAPI_HANDLER_ARGS)
 {
        struct zebra_pbr_iptable *zpi =
@@ -3352,6 +3431,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
        [ZEBRA_ROUTE_NOTIFY_REQUEST] = zread_route_notify_request,
        [ZEBRA_EVPN_REMOTE_NH_ADD] = zebra_evpn_proc_remote_nh,
        [ZEBRA_EVPN_REMOTE_NH_DEL] = zebra_evpn_proc_remote_nh,
+       [ZEBRA_NHRP_NEIGH_REGISTER] = zebra_neigh_register,
+       [ZEBRA_NHRP_NEIGH_UNREGISTER] = zebra_neigh_unregister,
 };
 
 /*
index ca471f8d989bd1148c4a381805c15396739f38f1..2822619da99e02c93b1289fea135cfb993ae09ad 100644 (file)
@@ -104,6 +104,9 @@ extern int zsend_label_manager_connect_response(struct zserv *client,
 extern int zsend_sr_policy_notify_status(uint32_t color,
                                         struct ipaddr *endpoint, char *name,
                                         int status);
+extern void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp,
+                                      struct ipaddr *ipaddr, int ndm_state,
+                                      void *mac, int macsize);
 
 extern int zsend_client_close_notify(struct zserv *client,
                                     struct zserv *closed_client);
index 6c5eebe6fe696477b8a4983848586405db8dbc12..f89b6fe478313ebca5439705b35b3dace1a0af59 100644 (file)
@@ -638,6 +638,7 @@ static void zserv_client_free(struct zserv *client)
 
                vrf_bitmap_free(client->redist_default[afi]);
                vrf_bitmap_free(client->ridinfo[afi]);
+               vrf_bitmap_free(client->nhrp_neighinfo[afi]);
        }
 
        /*
@@ -760,6 +761,7 @@ static struct zserv *zserv_client_create(int sock)
                        client->redist[afi][i] = vrf_bitmap_init();
                client->redist_default[afi] = vrf_bitmap_init();
                client->ridinfo[afi] = vrf_bitmap_init();
+               client->nhrp_neighinfo[afi] = vrf_bitmap_init();
        }
 
        /* Add this client to linked list. */
index c60799b8ba8dff2f11632d1aa6c0fba85b36765f..203670ac1dd5186f33c376c1424aa62004cbb83c 100644 (file)
@@ -137,6 +137,9 @@ struct zserv {
        /* Router-id information. */
        vrf_bitmap_t ridinfo[AFI_MAX];
 
+       /* Router-id information. */
+       vrf_bitmap_t nhrp_neighinfo[AFI_MAX];
+
        bool notify_owner;
 
        /* Indicates if client is synchronous. */