]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: Notice when our neighbor entry is removed and fight back
authorDonald Sharp <sharpd@cumulusnetworks.com>
Mon, 9 Apr 2018 12:04:39 +0000 (08:04 -0400)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Mon, 9 Apr 2018 12:04:39 +0000 (08:04 -0400)
Notice when someone deletes a neighbor entry we've put in for
rfc-5549 gets deleted by some evil evil person.  When this happens
notice and push it back in, immediately.

Ticket: CM-18612
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
zebra/interface.c
zebra/interface.h
zebra/rt_netlink.c

index 4f761a5e99c253b5d2c28e9b9c4ff089073c5d7f..6f59a2d399632d551a8c9f4fda8935877c80cc0e 100644 (file)
@@ -825,6 +825,7 @@ void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp,
                                          struct in6_addr *address, int add)
 {
        struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
+       struct zebra_if *zif = ifp->info;
        char buf[16] = "169.254.0.1";
        struct in_addr ipv4_ll;
        char mac[6];
@@ -845,6 +846,16 @@ void if_nbr_ipv6ll_to_ipv4ll_neigh_update(struct interface *ifp,
 
        /* Add arp record */
        kernel_neigh_update(add, ifp->ifindex, ipv4_ll.s_addr, mac, 6, ns_id);
+
+       /*
+        * We need to note whether or not we originated a v6
+        * neighbor entry for this interface.  So that when
+        * someone unwisely accidently deletes this entry
+        * we can shove it back in.
+        */
+       zif->v6_2_v4_ll_neigh_entry = !!add;
+       memcpy(&zif->v6_2_v4_ll_addr6, address, sizeof(*address));
+
        zvrf->neigh_updates++;
 }
 
index fba3201c5c56b967f128b3935320414722bda9b1..9634bfdb3fb841688bfc346357088fa2fc83fab3 100644 (file)
@@ -272,6 +272,13 @@ struct zebra_if {
        struct interface *link;
 
        struct thread *speed_update;
+
+       /*
+        * Does this interface have a v6 to v4 ll neighbor entry
+        * for bgp unnumbered?
+        */
+       bool v6_2_v4_ll_neigh_entry;
+       struct in6_addr v6_2_v4_ll_addr6;
 };
 
 DECLARE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp),
index 3053c56d1e93839f47e60aa385c8fdf8999154ad..d1edea804aad33d35a000b2f17c6c09b5e76648f 100644 (file)
@@ -2112,21 +2112,53 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
 
        ndm = NLMSG_DATA(h);
 
-       /* We only process neigh notifications if EVPN is enabled */
-       if (!is_evpn_enabled())
-               return 0;
-
        /* The interface should exist. */
        ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
                                        ndm->ndm_ifindex);
        if (!ifp || !ifp->info)
                return 0;
 
-       /* Drop "permanent" entries. */
-       if (ndm->ndm_state & NUD_PERMANENT)
+       zif = (struct zebra_if *)ifp->info;
+
+       /* Parse attributes and extract fields of interest. */
+       memset(tb, 0, sizeof tb);
+       netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
+
+       if (!tb[NDA_DST]) {
+               zlog_warn("%s family %s IF %s(%u) - no DST",
+                         nl_msg_type_to_str(h->nlmsg_type),
+                         nl_family_to_str(ndm->ndm_family), ifp->name,
+                         ndm->ndm_ifindex);
                return 0;
+       }
+
+       memset(&ip, 0, sizeof(struct ipaddr));
+       ip.ipa_type = (ndm->ndm_family == AF_INET) ? IPADDR_V4 : IPADDR_V6;
+       memcpy(&ip.ip.addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
+
+       /* Drop some "permanent" entries. */
+       if (ndm->ndm_state & NUD_PERMANENT) {
+               char buf[16] = "169.254.0.1";
+               struct in_addr ipv4_ll;
+
+               if (ndm->ndm_family != AF_INET)
+                       return 0;
+
+               if (!zif->v6_2_v4_ll_neigh_entry)
+                       return 0;
+
+               if (h->nlmsg_type != RTM_DELNEIGH)
+                       return 0;
+
+               inet_pton(AF_INET, buf, &ipv4_ll);
+               if (ipv4_ll.s_addr != ip.ip._v4_addr.s_addr)
+                       return 0;
+
+               if_nbr_ipv6ll_to_ipv4ll_neigh_update(
+                       ifp, &zif->v6_2_v4_ll_addr6, true);
+               return 0;
+       }
 
-       zif = (struct zebra_if *)ifp->info;
        /* 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.
@@ -2148,22 +2180,7 @@ static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
        else
                return 0;
 
-       /* Parse attributes and extract fields of interest. */
-       memset(tb, 0, sizeof tb);
-       netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
-
-       if (!tb[NDA_DST]) {
-               zlog_warn("%s family %s IF %s(%u) - no DST",
-                         nl_msg_type_to_str(h->nlmsg_type),
-                         nl_family_to_str(ndm->ndm_family), ifp->name,
-                         ndm->ndm_ifindex);
-               return 0;
-       }
        memset(&mac, 0, sizeof(struct ethaddr));
-       memset(&ip, 0, sizeof(struct ipaddr));
-       ip.ipa_type = (ndm->ndm_family == AF_INET) ? IPADDR_V4 : IPADDR_V6;
-       memcpy(&ip.ip.addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
-
        if (h->nlmsg_type == RTM_NEWNEIGH) {
                if (tb[NDA_LLADDR]) {
                        if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {