4 * Copyright (C) 2001-2017 Alexandre Cassen
6 * Copyright (C) 2018 Cumulus Networks
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along with
20 * this program; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <net/if_arp.h>
27 #include <linux/if_packet.h>
28 #include <netinet/if_ether.h>
31 #include "lib/linklist.h"
33 #include "lib/memory.h"
34 #include "lib/prefix.h"
39 #define VRRP_LOGPFX "[ARP] "
42 * The size of the garp packet buffer should be the large enough to hold the
43 * largest arp packet to be sent + the size of the link layer header for the
44 * corresponding protocol. In this case we hardcode for Ethernet.
46 #define GARP_BUFFER_SIZE \
47 sizeof(struct ether_header) + sizeof(struct arphdr) + 2 * ETH_ALEN \
48 + 2 * sizeof(struct in_addr)
51 static int garp_fd
= -1;
53 /* Send the gratuitous ARP message */
54 static ssize_t
vrrp_send_garp(struct interface
*ifp
, uint8_t *buf
, ssize_t pack_len
)
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
->vr
->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
127 "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
128 r
->vr
->vrid
, ifp
->name
);
133 garpbuf_len
= vrrp_build_garp(garpbuf
, ifp
, v4
);
136 inet_ntop(AF_INET
, v4
, astr
, sizeof(astr
));
137 zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID
138 "Sending gratuitous ARP on %s for %s",
139 r
->vr
->vrid
, ifp
->name
, astr
);
140 sent_len
= vrrp_send_garp(ifp
, garpbuf
, garpbuf_len
);
143 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
144 "Error sending gratuitous ARP on %s for %s",
145 r
->vr
->vrid
, ifp
->name
, astr
);
148 void vrrp_garp_send_all(struct vrrp_router
*r
)
150 assert(r
->family
== AF_INET
);
152 struct interface
*ifp
= r
->vr
->ifp
;
154 /* If the interface doesn't support ARP, don't try sending */
155 if (ifp
->flags
& IFF_NOARP
) {
157 VRRP_LOGPFX VRRP_LOGPFX_VRID
158 "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
159 r
->vr
->vrid
, ifp
->name
);
166 for (ALL_LIST_ELEMENTS_RO(r
->addrs
, ln
, ip
))
167 vrrp_garp_send(r
, &ip
->ipaddr_v4
);
171 void vrrp_garp_init(void)
173 /* Create the socket descriptor */
174 /* FIXME: why ETH_P_RARP? */
176 frr_elevate_privs(&vrrp_privs
) {
177 garp_fd
= socket(PF_PACKET
, SOCK_RAW
| SOCK_CLOEXEC
,
182 zlog_info(VRRP_LOGPFX
"Initialized gratuitous ARP socket");
185 "Error initializing gratuitous ARP socket");
190 void vrrp_garp_fini(void)
196 bool vrrp_garp_is_init(void)