]> git.proxmox.com Git - mirror_frr.git/commitdiff
vrrpd: implement gratuitous ARP
authorQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 30 Nov 2018 08:45:36 +0000 (08:45 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 17 May 2019 00:27:08 +0000 (00:27 +0000)
Implement gratuitous ARP functionality. Ethernet only.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
vrrpd/subdir.am
vrrpd/vrrp.c
vrrpd/vrrp.h
vrrpd/vrrp_arp.c [new file with mode: 0644]
vrrpd/vrrp_arp.h [new file with mode: 0644]

index 40dee9c1453eb96d8b1936274196bc64a00aaa1b..5c040932e6960313f015f0fe87cee4d4211f26e4 100644 (file)
@@ -11,18 +11,20 @@ man8 += $(MANBUILD)/vrrpd.8
 endif
 
 vrrpd_libvrrp_a_SOURCES = \
+       vrrpd/vrrp.c \
+       vrrpd/vrrp_arp.c \
        vrrpd/vrrp_memory.c \
-       vrrpd/vrrp_zebra.c \
-       vrrpd/vrrp_vty.c \
        vrrpd/vrrp_packet.c \
-       vrrpd/vrrp.c \
+       vrrpd/vrrp_vty.c \
+       vrrpd/vrrp_zebra.c \
        # end
 
 noinst_HEADERS += \
+       vrrpd/vrrp.h \
+       vrrpd/vrrp_arp.h \
        vrrpd/vrrp_memory.h \
-       vrrpd/vrrp_zebra.h \
        vrrpd/vrrp_vty.h \
-       vrrpd/vrrp.h \
+       vrrpd/vrrp_zebra.h \
        # end
 
 vrrpd/vrrp_vty_clippy.c: $(CLIPPY_DEPS)
index 2cc0896605e7f1f1fe085e893e3b7f58f7817054..f0a106ba0519282bd5ee47db24919e9b17b8ddb0 100644 (file)
@@ -17,6 +17,8 @@
  * with 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 "memory.h"
 #include "if.h"
 #include "linklist.h"
index 308e3a8e10e92451f78d1ed4270f62b950a6f0fc..95feeb4dfcaaa871bb0c94573891e1fac1d0d6fe 100644 (file)
@@ -17,8 +17,8 @@
  * with 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
  */
-#ifndef __VRRP_H__
-#define __VRRP_H_
+#ifndef _VRRP_H
+#define _VRRP_H
 
 #include <zebra.h>
 #include "linklist.h"
@@ -159,4 +159,4 @@ struct vrrp_vrouter *vrrp_lookup(uint8_t vrid);
  */
 void vrrp_event(struct vrrp_vrouter *vr, int event);
 
-#endif
+#endif /* _VRRP_H */
diff --git a/vrrpd/vrrp_arp.c b/vrrpd/vrrp_arp.c
new file mode 100644 (file)
index 0000000..cbea022
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * VRRP ARP primitives.
+ *
+ * Copyright (C) 2001-2017 Alexandre Cassen
+ * Portions:
+ *     Copyright (C) 2018 Cumulus Networks
+ *                        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
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * 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 <netinet/if_ether.h>
+
+#include "lib/if.h"
+#include "lib/linklist.h"
+#include "lib/log.h"
+#include "lib/memory.h"
+#include "lib/prefix.h"
+
+#include "vrrp.h"
+#include "vrrp_arp.h"
+
+/*
+ * The size of the garp packet buffer should be the large enough to hold the
+ * largest arp packet to be sent + the size of the link layer header for the
+ * corresponding protocol. In this case we hardcode for Ethernet.
+ */
+#define GARP_BUFFER_SIZE                                                       \
+       sizeof(struct ether_header) + sizeof(struct arphdr) + 2 * ETH_ALEN     \
+               + 2 * sizeof(struct in_addr)
+
+/* static vars */
+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)
+{
+       struct sockaddr_ll sll;
+       ssize_t len;
+
+       /* Build the dst device */
+       memset(&sll, 0, sizeof(sll));
+       sll.sll_family = AF_PACKET;
+       sll.sll_protocol = ETH_P_ARP;
+       sll.sll_ifindex = (int) ifp->ifindex;
+       sll.sll_halen = ifp->hw_addr_len;
+       memset(sll.sll_addr, 0xFF, ETH_ALEN);
+
+       /* Send packet */
+       len = sendto(garp_fd, buf, pack_len, 0, (struct sockaddr *)&sll,
+                    sizeof(sll));
+
+       return len;
+}
+
+/* Build a gratuitous ARP message over a specific interface */
+static ssize_t vrrp_build_garp(uint8_t *buf, struct interface *ifp,
+                              struct in_addr *v4)
+{
+       uint8_t *arp_ptr;
+
+       if (ifp->hw_addr_len == 0)
+               return -1;
+
+       /* Build Ethernet header */
+       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);
+
+       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));
+       /* 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));
+       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));
+       arp_ptr += sizeof(struct in_addr);
+
+       return arp_ptr - buf;
+}
+
+void vrrp_garp_send(struct vrrp_vrouter *vr, struct in_addr *v4)
+{
+       struct interface *ifp = vr->ifp;
+       uint8_t garpbuf[GARP_BUFFER_SIZE];
+       ssize_t garpbuf_len;
+       ssize_t sent_len;
+       char astr[INET_ADDRSTRLEN];
+
+       /* 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);
+               return;
+       }
+
+       /* Build garp */
+       garpbuf_len = vrrp_build_garp(garpbuf, ifp, v4);
+
+       /* Send garp */
+       inet_ntop(AF_INET, v4, astr, sizeof(astr));
+       zlog_info("Sending gratuitous ARP on %s for %s", ifp->name, astr);
+       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);
+}
+
+void vrrp_garp_send_all(struct vrrp_vrouter *vr)
+{
+       struct interface *ifp = vr->ifp;
+
+       /* 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);
+               return;
+       }
+
+       struct listnode *ln;
+       struct in_addr *v4;
+
+       for (ALL_LIST_ELEMENTS_RO(vr->v4, ln, v4))
+               vrrp_garp_send(vr, v4);
+}
+
+
+void vrrp_garp_init(void)
+{
+       /* Create the socket descriptor */
+       /* FIXME: why ETH_P_RARP? */
+       garp_fd = socket(PF_PACKET, SOCK_RAW | SOCK_CLOEXEC, htons(ETH_P_RARP));
+
+       if (garp_fd > 0)
+               zlog_info("Initialized gratuitous ARP socket");
+       else {
+               zlog_err("Error initializing gratuitous ARP socket");
+               return;
+       }
+}
+
+void vrrp_garp_fini(void)
+{
+       close(garp_fd);
+       garp_fd = -1;
+}
diff --git a/vrrpd/vrrp_arp.h b/vrrpd/vrrp_arp.h
new file mode 100644 (file)
index 0000000..d3c5651
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * VRRPD global definitions
+ * Copyright (C) 2018 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
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with 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
+ */
+#ifndef _VRRP_ARP_H
+#define _VRRP_ARP_H
+
+#include <zebra.h>
+
+#include "vrrp.h"
+
+/* FIXME: Use the kernel define for this */
+#define HWTYPE_ETHER 1
+
+/* prototypes */
+extern void vrrp_garp_init(void);
+extern void vrrp_garp_fini(void);
+extern void vrrp_garp_send(struct vrrp_vrouter *vr, struct in_addr *v4);
+extern void vrrp_garp_send_all(struct vrrp_vrouter *vr);
+#endif