1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2001-2017 Alexandre Cassen
6 * Copyright (C) 2018-2019 Cumulus Networks, Inc.
11 #include <linux/if_packet.h>
12 #include <net/if_arp.h>
13 #include <netinet/if_ether.h>
16 #include "lib/linklist.h"
18 #include "lib/memory.h"
19 #include "lib/prefix.h"
23 #include "vrrp_debug.h"
25 #define VRRP_LOGPFX "[ARP] "
28 * The size of the garp packet buffer should be the large enough to hold the
29 * largest arp packet to be sent + the size of the link layer header for the
30 * corresponding protocol. In this case we hardcode for Ethernet.
32 #define GARP_BUFFER_SIZE \
33 sizeof(struct ether_header) + sizeof(struct arphdr) + 2 * ETH_ALEN \
34 + 2 * sizeof(struct in_addr)
37 static int garp_fd
= -1;
39 /* Send the gratuitous ARP message */
40 static ssize_t
vrrp_send_garp(struct interface
*ifp
, uint8_t *buf
,
43 struct sockaddr_ll sll
;
46 /* Build the dst device */
47 memset(&sll
, 0, sizeof(sll
));
48 sll
.sll_family
= AF_PACKET
;
49 sll
.sll_protocol
= ETH_P_ARP
;
50 sll
.sll_ifindex
= (int)ifp
->ifindex
;
51 sll
.sll_halen
= ifp
->hw_addr_len
;
52 memset(sll
.sll_addr
, 0xFF, ETH_ALEN
);
55 len
= sendto(garp_fd
, buf
, pack_len
, 0, (struct sockaddr
*)&sll
,
61 /* Build a gratuitous ARP message over a specific interface */
62 static ssize_t
vrrp_build_garp(uint8_t *buf
, struct interface
*ifp
,
67 if (ifp
->hw_addr_len
== 0)
70 /* Build Ethernet header */
71 struct ether_header
*eth
= (struct ether_header
*)buf
;
73 memset(eth
->ether_dhost
, 0xFF, ETH_ALEN
);
74 memcpy(eth
->ether_shost
, ifp
->hw_addr
, ETH_ALEN
);
75 eth
->ether_type
= htons(ETHERTYPE_ARP
);
77 /* Build ARP payload */
78 struct arphdr
*arph
= (struct arphdr
*)(buf
+ ETHER_HDR_LEN
);
80 arph
->ar_hrd
= htons(HWTYPE_ETHER
);
81 arph
->ar_pro
= htons(ETHERTYPE_IP
);
82 arph
->ar_hln
= ifp
->hw_addr_len
;
83 arph
->ar_pln
= sizeof(struct in_addr
);
84 arph
->ar_op
= htons(ARPOP_REQUEST
);
85 arp_ptr
= (uint8_t *)(arph
+ 1);
87 memcpy(arp_ptr
, ifp
->hw_addr
, ifp
->hw_addr_len
);
88 arp_ptr
+= ifp
->hw_addr_len
;
90 memcpy(arp_ptr
, v4
, sizeof(struct in_addr
));
91 arp_ptr
+= sizeof(struct in_addr
);
92 /* Dest MAC: broadcast */
93 memset(arp_ptr
, 0xFF, ETH_ALEN
);
94 arp_ptr
+= ifp
->hw_addr_len
;
96 memcpy(arp_ptr
, v4
, sizeof(struct in_addr
));
97 arp_ptr
+= sizeof(struct in_addr
);
102 void vrrp_garp_send(struct vrrp_router
*r
, struct in_addr
*v4
)
104 struct interface
*ifp
= r
->mvl_ifp
;
105 uint8_t garpbuf
[GARP_BUFFER_SIZE
];
108 char astr
[INET_ADDRSTRLEN
];
110 /* If the interface doesn't support ARP, don't try sending */
111 if (ifp
->flags
& IFF_NOARP
) {
113 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
114 "Unable to send gratuitous ARP on %s; has IFF_NOARP",
115 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
);
120 garpbuf_len
= vrrp_build_garp(garpbuf
, ifp
, v4
);
122 if (garpbuf_len
< 0) {
124 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
125 "Unable to send gratuitous ARP on %s; MAC address unknown",
126 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
);
131 inet_ntop(AF_INET
, v4
, astr
, sizeof(astr
));
133 DEBUGD(&vrrp_dbg_arp
,
134 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
135 "Sending gratuitous ARP on %s for %s",
136 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
, astr
);
137 if (DEBUG_MODE_CHECK(&vrrp_dbg_arp
, DEBUG_MODE_ALL
))
138 zlog_hexdump(garpbuf
, garpbuf_len
);
140 sent_len
= vrrp_send_garp(ifp
, garpbuf
, garpbuf_len
);
143 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
144 "Error sending gratuitous ARP on %s for %s",
145 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
, astr
);
147 ++r
->stats
.garp_tx_cnt
;
150 void vrrp_garp_send_all(struct vrrp_router
*r
)
152 assert(r
->family
== AF_INET
);
154 struct interface
*ifp
= r
->mvl_ifp
;
156 /* If the interface doesn't support ARP, don't try sending */
157 if (ifp
->flags
& IFF_NOARP
) {
159 VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
160 "Unable to send gratuitous ARP on %s; has IFF_NOARP",
161 r
->vr
->vrid
, family2str(r
->family
), ifp
->name
);
168 for (ALL_LIST_ELEMENTS_RO(r
->addrs
, ln
, ip
))
169 vrrp_garp_send(r
, &ip
->ipaddr_v4
);
173 void vrrp_garp_init(void)
175 /* Create the socket descriptor */
176 /* FIXME: why ETH_P_RARP? */
178 frr_with_privs(&vrrp_privs
) {
179 garp_fd
= socket(PF_PACKET
, SOCK_RAW
| SOCK_CLOEXEC
,
184 DEBUGD(&vrrp_dbg_sock
,
185 VRRP_LOGPFX
"Initialized gratuitous ARP socket");
186 DEBUGD(&vrrp_dbg_arp
,
187 VRRP_LOGPFX
"Initialized gratuitous ARP subsystem");
190 "Error initializing gratuitous ARP subsystem");
194 void vrrp_garp_fini(void)
199 DEBUGD(&vrrp_dbg_arp
,
200 VRRP_LOGPFX
"Deinitialized gratuitous ARP subsystem");
203 bool vrrp_garp_is_init(void)