]> git.proxmox.com Git - mirror_frr.git/blobdiff - vrrpd/vrrp_arp.c
Merge pull request #5237 from ton31337/fix/doc_bgp_redistribute_vpn
[mirror_frr.git] / vrrpd / vrrp_arp.c
index a67af4e10472ab271349688fa0ca3a11d47afca3..750050e8c33bd414921112101c121045d7711732 100644 (file)
@@ -1,10 +1,9 @@
 /*
- * VRRP ARP primitives.
- *
+ * VRRP ARP handling.
  * Copyright (C) 2001-2017 Alexandre Cassen
  * Portions:
- *     Copyright (C) 2018 Cumulus Networks
- *                        Quentin Young
+ *     Copyright (C) 2018-2019 Cumulus Networks, Inc.
+ *     Quentin Young
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * this program; see the file COPYING; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
-
 #include <zebra.h>
 
-#include <net/if_arp.h>
 #include <linux/if_packet.h>
+#include <net/if_arp.h>
 #include <netinet/if_ether.h>
 
 #include "lib/if.h"
@@ -35,6 +33,9 @@
 
 #include "vrrp.h"
 #include "vrrp_arp.h"
+#include "vrrp_debug.h"
+
+#define VRRP_LOGPFX "[ARP] "
 
 /*
  * The size of the garp packet buffer should be the large enough to hold the
@@ -49,7 +50,8 @@
 static int garp_fd = -1;
 
 /* Send the gratuitous ARP message */
-static ssize_t vrrp_send_garp(struct interface *ifp, uint8_t *buf, ssize_t pack_len)
+static ssize_t vrrp_send_garp(struct interface *ifp, uint8_t *buf,
+                             ssize_t pack_len)
 {
        struct sockaddr_ll sll;
        ssize_t len;
@@ -58,7 +60,7 @@ static ssize_t vrrp_send_garp(struct interface *ifp, uint8_t *buf, ssize_t pack_
        memset(&sll, 0, sizeof(sll));
        sll.sll_family = AF_PACKET;
        sll.sll_protocol = ETH_P_ARP;
-       sll.sll_ifindex = (int) ifp->ifindex;
+       sll.sll_ifindex = (int)ifp->ifindex;
        sll.sll_halen = ifp->hw_addr_len;
        memset(sll.sll_addr, 0xFF, ETH_ALEN);
 
@@ -79,40 +81,40 @@ static ssize_t vrrp_build_garp(uint8_t *buf, struct interface *ifp,
                return -1;
 
        /* Build Ethernet header */
-       struct ether_header *eth = (struct ether_header *) buf;
+       struct ether_header *eth = (struct ether_header *)buf;
 
        memset(eth->ether_dhost, 0xFF, ETH_ALEN);
        memcpy(eth->ether_shost, ifp->hw_addr, ETH_ALEN);
        eth->ether_type = htons(ETHERTYPE_ARP);
 
        /* Build ARP payload */
-       struct arphdr *arph = (struct arphdr *) (buf + ETHER_HDR_LEN);
+       struct arphdr *arph = (struct arphdr *)(buf + ETHER_HDR_LEN);
 
        arph->ar_hrd = htons(HWTYPE_ETHER);
        arph->ar_pro = htons(ETHERTYPE_IP);
        arph->ar_hln = ifp->hw_addr_len;
        arph->ar_pln = sizeof(struct in_addr);
        arph->ar_op = htons(ARPOP_REQUEST);
-       arp_ptr = (uint8_t *)(arph + sizeof(struct arphdr));
+       arp_ptr = (uint8_t *)(arph + 1);
        /* Source MAC: us */
        memcpy(arp_ptr, ifp->hw_addr, ifp->hw_addr_len);
        arp_ptr += ifp->hw_addr_len;
        /* Source IP: us */
-       memcpy(arp_ptr, &v4, sizeof(struct in_addr));
+       memcpy(arp_ptr, v4, sizeof(struct in_addr));
        arp_ptr += sizeof(struct in_addr);
        /* Dest MAC: broadcast */
        memset(arp_ptr, 0xFF, ETH_ALEN);
        arp_ptr += ifp->hw_addr_len;
        /* Dest IP: us */
-       memcpy(arp_ptr, &v4, sizeof(struct in_addr));
+       memcpy(arp_ptr, v4, sizeof(struct in_addr));
        arp_ptr += sizeof(struct in_addr);
 
        return arp_ptr - buf;
 }
 
-void vrrp_garp_send(struct vrrp_vrouter *vr, struct in_addr *v4)
+void vrrp_garp_send(struct vrrp_router *r, struct in_addr *v4)
 {
-       struct interface *ifp = vr->ifp;
+       struct interface *ifp = r->mvl_ifp;
        uint8_t garpbuf[GARP_BUFFER_SIZE];
        ssize_t garpbuf_len;
        ssize_t sent_len;
@@ -121,41 +123,63 @@ void vrrp_garp_send(struct vrrp_vrouter *vr, struct in_addr *v4)
        /* If the interface doesn't support ARP, don't try sending */
        if (ifp->flags & IFF_NOARP) {
                zlog_warn(
-                       "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
-                       ifp->name);
+                       VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
+                       "Unable to send gratuitous ARP on %s; has IFF_NOARP",
+                       r->vr->vrid, family2str(r->family), ifp->name);
                return;
        }
 
        /* Build garp */
        garpbuf_len = vrrp_build_garp(garpbuf, ifp, v4);
 
+       if (garpbuf_len < 0) {
+               zlog_warn(
+                       VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
+                       "Unable to send gratuitous ARP on %s; MAC address unknown",
+                       r->vr->vrid, family2str(r->family), ifp->name);
+               return;
+       };
+
        /* Send garp */
        inet_ntop(AF_INET, v4, astr, sizeof(astr));
-       zlog_info("Sending gratuitous ARP on %s for %s", ifp->name, astr);
+
+       DEBUGD(&vrrp_dbg_arp,
+              VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
+              "Sending gratuitous ARP on %s for %s",
+              r->vr->vrid, family2str(r->family), ifp->name, astr);
+       if (DEBUG_MODE_CHECK(&vrrp_dbg_arp, DEBUG_MODE_ALL))
+               zlog_hexdump(garpbuf, garpbuf_len);
+
        sent_len = vrrp_send_garp(ifp, garpbuf, garpbuf_len);
 
        if (sent_len < 0)
-               zlog_warn("Error sending gratuitous ARP on %s for %s",
-                         ifp->name, astr);
+               zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
+                         "Error sending gratuitous ARP on %s for %s",
+                         r->vr->vrid, family2str(r->family), ifp->name, astr);
+       else
+               ++r->stats.garp_tx_cnt;
 }
 
-void vrrp_garp_send_all(struct vrrp_vrouter *vr)
+void vrrp_garp_send_all(struct vrrp_router *r)
 {
-       struct interface *ifp = vr->ifp;
+       assert(r->family == AF_INET);
+
+       struct interface *ifp = r->mvl_ifp;
 
        /* If the interface doesn't support ARP, don't try sending */
        if (ifp->flags & IFF_NOARP) {
                zlog_warn(
+                       VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
                        "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
-                       ifp->name);
+                       r->vr->vrid, family2str(r->family), ifp->name);
                return;
        }
 
        struct listnode *ln;
-       struct in_addr *v4;
+       struct ipaddr *ip;
 
-       for (ALL_LIST_ELEMENTS_RO(vr->v4, ln, v4))
-               vrrp_garp_send(vr, v4);
+       for (ALL_LIST_ELEMENTS_RO(r->addrs, ln, ip))
+               vrrp_garp_send(r, &ip->ipaddr_v4);
 }
 
 
@@ -164,17 +188,19 @@ void vrrp_garp_init(void)
        /* Create the socket descriptor */
        /* FIXME: why ETH_P_RARP? */
        errno = 0;
-       frr_elevate_privs(&vrrp_privs) {
+       frr_with_privs(&vrrp_privs) {
                garp_fd = socket(PF_PACKET, SOCK_RAW | SOCK_CLOEXEC,
                                 htons(ETH_P_RARP));
        }
 
-       if (garp_fd > 0)
-               zlog_info("Initialized gratuitous ARP socket");
-       else {
-               perror("Error initializing gratuitous ARP socket");
-               zlog_err("Error initializing gratuitous ARP socket");
-               return;
+       if (garp_fd > 0) {
+               DEBUGD(&vrrp_dbg_sock,
+                      VRRP_LOGPFX "Initialized gratuitous ARP socket");
+               DEBUGD(&vrrp_dbg_arp,
+                      VRRP_LOGPFX "Initialized gratuitous ARP subsystem");
+       } else {
+               zlog_err(VRRP_LOGPFX
+                        "Error initializing gratuitous ARP subsystem");
        }
 }
 
@@ -182,6 +208,9 @@ void vrrp_garp_fini(void)
 {
        close(garp_fd);
        garp_fd = -1;
+
+       DEBUGD(&vrrp_dbg_arp,
+              VRRP_LOGPFX "Deinitialized gratuitous ARP subsystem");
 }
 
 bool vrrp_garp_is_init(void)