3 * Copyright (C) 2001-2017 Alexandre Cassen
5 * Copyright (C) 2018-2019 Cumulus Networks, Inc.
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)
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
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
24 #include <linux/if_packet.h>
25 #include <net/if_arp.h>
26 #include <netinet/if_ether.h>
29 #include "lib/linklist.h"
31 #include "lib/memory.h"
32 #include "lib/prefix.h"
36 #include "vrrp_debug.h"
38 #define VRRP_LOGPFX "[ARP] "
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.
45 #define GARP_BUFFER_SIZE \
46 sizeof(struct ether_header) + sizeof(struct arphdr) + 2 * ETH_ALEN \
47 + 2 * sizeof(struct in_addr)
50 static int garp_fd
= -1;
52 /* Send the gratuitous ARP message */
53 static ssize_t
vrrp_send_garp(struct interface
*ifp
, uint8_t *buf
,
56 struct sockaddr_ll sll
;
59 /* Build the dst device */
60 memset(&sll
, 0, sizeof(sll
));
61 sll
.sll_family
= AF_PACKET
;
62 sll
.sll_protocol
= ETH_P_ARP
;
63 sll
.sll_ifindex
= (int)ifp
->ifindex
;
64 sll
.sll_halen
= ifp
->hw_addr_len
;
65 memset(sll
.sll_addr
, 0xFF, ETH_ALEN
);
68 len
= sendto(garp_fd
, buf
, pack_len
, 0, (struct sockaddr
*)&sll
,
74 /* Build a gratuitous ARP message over a specific interface */
75 static ssize_t
vrrp_build_garp(uint8_t *buf
, struct interface
*ifp
,
80 if (ifp
->hw_addr_len
== 0)
83 /* Build Ethernet header */
84 struct ether_header
*eth
= (struct ether_header
*)buf
;
86 memset(eth
->ether_dhost
, 0xFF, ETH_ALEN
);
87 memcpy(eth
->ether_shost
, ifp
->hw_addr
, ETH_ALEN
);
88 eth
->ether_type
= htons(ETHERTYPE_ARP
);
90 /* Build ARP payload */
91 struct arphdr
*arph
= (struct arphdr
*)(buf
+ ETHER_HDR_LEN
);
93 arph
->ar_hrd
= htons(HWTYPE_ETHER
);
94 arph
->ar_pro
= htons(ETHERTYPE_IP
);
95 arph
->ar_hln
= ifp
->hw_addr_len
;
96 arph
->ar_pln
= sizeof(struct in_addr
);
97 arph
->ar_op
= htons(ARPOP_REQUEST
);
98 arp_ptr
= (uint8_t *)(arph
+ 1);
100 memcpy(arp_ptr
, ifp
->hw_addr
, ifp
->hw_addr_len
);
101 arp_ptr
+= ifp
->hw_addr_len
;
103 memcpy(arp_ptr
, v4
, sizeof(struct in_addr
));
104 arp_ptr
+= sizeof(struct in_addr
);
105 /* Dest MAC: broadcast */
106 memset(arp_ptr
, 0xFF, ETH_ALEN
);
107 arp_ptr
+= ifp
->hw_addr_len
;
109 memcpy(arp_ptr
, v4
, sizeof(struct in_addr
));
110 arp_ptr
+= sizeof(struct in_addr
);
112 return arp_ptr
- buf
;
115 void vrrp_garp_send(struct vrrp_router
*r
, struct in_addr
*v4
)
117 struct interface
*ifp
= r
->mvl_ifp
;
118 uint8_t garpbuf
[GARP_BUFFER_SIZE
];
121 char astr
[INET_ADDRSTRLEN
];
123 /* If the interface doesn't support ARP, don't try sending */
124 if (ifp
->flags
& IFF_NOARP
) {
126 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
127 "Unable to send gratuitous ARP on %s; has IFF_NOARP",
128 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
);
133 garpbuf_len
= vrrp_build_garp(garpbuf
, ifp
, v4
);
135 if (garpbuf_len
< 0) {
137 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
138 "Unable to send gratuitous ARP on %s; MAC address unknown",
139 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
);
144 inet_ntop(AF_INET
, v4
, astr
, sizeof(astr
));
146 DEBUGD(&vrrp_dbg_arp
,
147 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
148 "Sending gratuitous ARP on %s for %s",
149 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
, astr
);
150 if (DEBUG_MODE_CHECK(&vrrp_dbg_arp
, DEBUG_MODE_ALL
))
151 zlog_hexdump(garpbuf
, garpbuf_len
);
153 sent_len
= vrrp_send_garp(ifp
, garpbuf
, garpbuf_len
);
156 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
157 "Error sending gratuitous ARP on %s for %s",
158 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
, astr
);
160 ++r
->stats
.garp_tx_cnt
;
163 void vrrp_garp_send_all(struct vrrp_router
*r
)
165 assert(r
->family
== AF_INET
);
167 struct interface
*ifp
= r
->mvl_ifp
;
169 /* If the interface doesn't support ARP, don't try sending */
170 if (ifp
->flags
& IFF_NOARP
) {
172 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
173 "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
174 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
);
181 for (ALL_LIST_ELEMENTS_RO(r
->addrs
, ln
, ip
))
182 vrrp_garp_send(r
, &ip
->ipaddr_v4
);
186 void vrrp_garp_init(void)
188 /* Create the socket descriptor */
189 /* FIXME: why ETH_P_RARP? */
191 frr_with_privs(&vrrp_privs
) {
192 garp_fd
= socket(PF_PACKET
, SOCK_RAW
| SOCK_CLOEXEC
,
197 DEBUGD(&vrrp_dbg_sock
,
198 VRRP_LOGPFX
"Initialized gratuitous ARP socket");
199 DEBUGD(&vrrp_dbg_arp
,
200 VRRP_LOGPFX
"Initialized gratuitous ARP subsystem");
203 "Error initializing gratuitous ARP subsystem");
207 void vrrp_garp_fini(void)
212 DEBUGD(&vrrp_dbg_arp
,
213 VRRP_LOGPFX
"Deinitialized gratuitous ARP subsystem");
216 bool vrrp_garp_is_init(void)