+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * VRRP ARP primitives.
- *
+ * VRRP ARP handling.
* 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
+ * Copyright (C) 2018-2019 Cumulus Networks, Inc.
+ * Quentin Young
*/
-
#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"
#include "vrrp.h"
#include "vrrp_arp.h"
+#include "vrrp_debug.h"
#define VRRP_LOGPFX "[ARP] "
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;
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);
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);
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;
/* If the interface doesn't support ARP, don't try sending */
if (ifp->flags & IFF_NOARP) {
zlog_warn(
- VRRP_LOGPFX VRRP_LOGPFX_VRID
- "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
- vr->vrid, 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(VRRP_LOGPFX VRRP_LOGPFX_VRID
- "Sending gratuitous ARP on %s for %s",
- vr->vrid, 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(VRRP_LOGPFX VRRP_LOGPFX_VRID
+ zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
"Error sending gratuitous ARP on %s for %s",
- vr->vrid, ifp->name, astr);
+ 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
- "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
- vr->vrid, 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;
}
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);
}
/* 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(VRRP_LOGPFX "Initialized gratuitous ARP socket");
- else {
+ 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 socket");
- return;
+ "Error initializing gratuitous ARP subsystem");
}
}
{
close(garp_fd);
garp_fd = -1;
+
+ DEBUGD(&vrrp_dbg_arp,
+ VRRP_LOGPFX "Deinitialized gratuitous ARP subsystem");
}
bool vrrp_garp_is_init(void)