]> git.proxmox.com Git - mirror_frr.git/blame - vrrpd/vrrp_arp.c
vrrpd: allow configuring global defaults
[mirror_frr.git] / vrrpd / vrrp_arp.c
CommitLineData
41ee5442 1/*
63d4bd12 2 * VRRP ARP handling.
41ee5442
QY
3 * Copyright (C) 2001-2017 Alexandre Cassen
4 * Portions:
63d4bd12
QY
5 * Copyright (C) 2018-2019 Cumulus Networks, Inc.
6 * Quentin Young
41ee5442
QY
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
41ee5442
QY
22#include <zebra.h>
23
41ee5442 24#include <linux/if_packet.h>
63d4bd12 25#include <net/if_arp.h>
41ee5442
QY
26#include <netinet/if_ether.h>
27
28#include "lib/if.h"
29#include "lib/linklist.h"
30#include "lib/log.h"
31#include "lib/memory.h"
32#include "lib/prefix.h"
33
34#include "vrrp.h"
35#include "vrrp_arp.h"
b637bcd4 36#include "vrrp_debug.h"
41ee5442 37
4ec94408
QY
38#define VRRP_LOGPFX "[ARP] "
39
41ee5442
QY
40/*
41 * The size of the garp packet buffer should be the large enough to hold the
42 * largest arp packet to be sent + the size of the link layer header for the
43 * corresponding protocol. In this case we hardcode for Ethernet.
44 */
45#define GARP_BUFFER_SIZE \
46 sizeof(struct ether_header) + sizeof(struct arphdr) + 2 * ETH_ALEN \
47 + 2 * sizeof(struct in_addr)
48
49/* static vars */
50static int garp_fd = -1;
51
52/* Send the gratuitous ARP message */
53static ssize_t vrrp_send_garp(struct interface *ifp, uint8_t *buf, ssize_t pack_len)
54{
55 struct sockaddr_ll sll;
56 ssize_t len;
57
58 /* Build the dst device */
59 memset(&sll, 0, sizeof(sll));
60 sll.sll_family = AF_PACKET;
61 sll.sll_protocol = ETH_P_ARP;
62 sll.sll_ifindex = (int) ifp->ifindex;
63 sll.sll_halen = ifp->hw_addr_len;
64 memset(sll.sll_addr, 0xFF, ETH_ALEN);
65
66 /* Send packet */
67 len = sendto(garp_fd, buf, pack_len, 0, (struct sockaddr *)&sll,
68 sizeof(sll));
69
70 return len;
71}
72
73/* Build a gratuitous ARP message over a specific interface */
74static ssize_t vrrp_build_garp(uint8_t *buf, struct interface *ifp,
75 struct in_addr *v4)
76{
77 uint8_t *arp_ptr;
78
79 if (ifp->hw_addr_len == 0)
80 return -1;
81
82 /* Build Ethernet header */
83 struct ether_header *eth = (struct ether_header *) buf;
84
85 memset(eth->ether_dhost, 0xFF, ETH_ALEN);
86 memcpy(eth->ether_shost, ifp->hw_addr, ETH_ALEN);
87 eth->ether_type = htons(ETHERTYPE_ARP);
88
89 /* Build ARP payload */
90 struct arphdr *arph = (struct arphdr *) (buf + ETHER_HDR_LEN);
91
92 arph->ar_hrd = htons(HWTYPE_ETHER);
93 arph->ar_pro = htons(ETHERTYPE_IP);
94 arph->ar_hln = ifp->hw_addr_len;
95 arph->ar_pln = sizeof(struct in_addr);
96 arph->ar_op = htons(ARPOP_REQUEST);
c23edd74 97 arp_ptr = (uint8_t *)(arph + 1);
41ee5442
QY
98 /* Source MAC: us */
99 memcpy(arp_ptr, ifp->hw_addr, ifp->hw_addr_len);
100 arp_ptr += ifp->hw_addr_len;
101 /* Source IP: us */
c23edd74 102 memcpy(arp_ptr, v4, sizeof(struct in_addr));
41ee5442
QY
103 arp_ptr += sizeof(struct in_addr);
104 /* Dest MAC: broadcast */
105 memset(arp_ptr, 0xFF, ETH_ALEN);
106 arp_ptr += ifp->hw_addr_len;
107 /* Dest IP: us */
c23edd74 108 memcpy(arp_ptr, v4, sizeof(struct in_addr));
41ee5442
QY
109 arp_ptr += sizeof(struct in_addr);
110
111 return arp_ptr - buf;
112}
113
862f2f37 114void vrrp_garp_send(struct vrrp_router *r, struct in_addr *v4)
41ee5442 115{
dad18a2f 116 struct interface *ifp = r->mvl_ifp;
41ee5442
QY
117 uint8_t garpbuf[GARP_BUFFER_SIZE];
118 ssize_t garpbuf_len;
119 ssize_t sent_len;
120 char astr[INET_ADDRSTRLEN];
121
122 /* If the interface doesn't support ARP, don't try sending */
123 if (ifp->flags & IFF_NOARP) {
124 zlog_warn(
4ec94408 125 VRRP_LOGPFX VRRP_LOGPFX_VRID
41ee5442 126 "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
862f2f37 127 r->vr->vrid, ifp->name);
41ee5442
QY
128 return;
129 }
130
131 /* Build garp */
132 garpbuf_len = vrrp_build_garp(garpbuf, ifp, v4);
133
134 /* Send garp */
135 inet_ntop(AF_INET, v4, astr, sizeof(astr));
b637bcd4
QY
136
137 DEBUGD(&vrrp_dbg_arp,
138 VRRP_LOGPFX VRRP_LOGPFX_VRID
139 "Sending gratuitous ARP on %s for %s",
140 r->vr->vrid, ifp->name, astr);
141 if (DEBUG_MODE_CHECK(&vrrp_dbg_arp, DEBUG_MODE_ALL))
142 zlog_hexdump(garpbuf, garpbuf_len);
143
41ee5442
QY
144 sent_len = vrrp_send_garp(ifp, garpbuf, garpbuf_len);
145
146 if (sent_len < 0)
4ec94408
QY
147 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
148 "Error sending gratuitous ARP on %s for %s",
862f2f37 149 r->vr->vrid, ifp->name, astr);
6332c77f
QY
150 else
151 ++r->stats.garp_tx_cnt;
41ee5442
QY
152}
153
862f2f37 154void vrrp_garp_send_all(struct vrrp_router *r)
41ee5442 155{
862f2f37
QY
156 assert(r->family == AF_INET);
157
dad18a2f 158 struct interface *ifp = r->mvl_ifp;
41ee5442
QY
159
160 /* If the interface doesn't support ARP, don't try sending */
161 if (ifp->flags & IFF_NOARP) {
162 zlog_warn(
4ec94408 163 VRRP_LOGPFX VRRP_LOGPFX_VRID
41ee5442 164 "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
862f2f37 165 r->vr->vrid, ifp->name);
41ee5442
QY
166 return;
167 }
168
169 struct listnode *ln;
862f2f37 170 struct ipaddr *ip;
41ee5442 171
862f2f37
QY
172 for (ALL_LIST_ELEMENTS_RO(r->addrs, ln, ip))
173 vrrp_garp_send(r, &ip->ipaddr_v4);
41ee5442
QY
174}
175
176
177void vrrp_garp_init(void)
178{
179 /* Create the socket descriptor */
180 /* FIXME: why ETH_P_RARP? */
40744000
QY
181 errno = 0;
182 frr_elevate_privs(&vrrp_privs) {
183 garp_fd = socket(PF_PACKET, SOCK_RAW | SOCK_CLOEXEC,
184 htons(ETH_P_RARP));
185 }
41ee5442 186
b637bcd4
QY
187 if (garp_fd > 0) {
188 DEBUGD(&vrrp_dbg_sock,
189 VRRP_LOGPFX "Initialized gratuitous ARP socket");
190 DEBUGD(&vrrp_dbg_arp,
191 VRRP_LOGPFX "Initialized gratuitous ARP subsystem");
192 } else {
4ec94408 193 zlog_err(VRRP_LOGPFX
b637bcd4 194 "Error initializing gratuitous ARP subsystem");
41ee5442
QY
195 }
196}
197
198void vrrp_garp_fini(void)
199{
200 close(garp_fd);
201 garp_fd = -1;
b637bcd4
QY
202
203 DEBUGD(&vrrp_dbg_arp,
204 VRRP_LOGPFX "Deinitialized gratuitous ARP subsystem");
41ee5442 205}
40744000
QY
206
207bool vrrp_garp_is_init(void)
208{
209 return garp_fd > 0;
210}