]> git.proxmox.com Git - mirror_frr.git/blob - vrrpd/vrrp_arp.c
vrrpd: ipv6 support
[mirror_frr.git] / vrrpd / vrrp_arp.c
1 /*
2 * VRRP ARP primitives.
3 *
4 * Copyright (C) 2001-2017 Alexandre Cassen
5 * Portions:
6 * Copyright (C) 2018 Cumulus Networks
7 * Quentin Young
8 *
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)
12 * any later version.
13 *
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
17 * more details.
18 *
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
22 */
23
24 #include <zebra.h>
25
26 #include <net/if_arp.h>
27 #include <linux/if_packet.h>
28 #include <netinet/if_ether.h>
29
30 #include "lib/if.h"
31 #include "lib/linklist.h"
32 #include "lib/log.h"
33 #include "lib/memory.h"
34 #include "lib/prefix.h"
35
36 #include "vrrp.h"
37 #include "vrrp_arp.h"
38
39 #define VRRP_LOGPFX "[ARP] "
40
41 /*
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.
45 */
46 #define GARP_BUFFER_SIZE \
47 sizeof(struct ether_header) + sizeof(struct arphdr) + 2 * ETH_ALEN \
48 + 2 * sizeof(struct in_addr)
49
50 /* static vars */
51 static int garp_fd = -1;
52
53 /* Send the gratuitous ARP message */
54 static ssize_t vrrp_send_garp(struct interface *ifp, uint8_t *buf, ssize_t pack_len)
55 {
56 struct sockaddr_ll sll;
57 ssize_t len;
58
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);
66
67 /* Send packet */
68 len = sendto(garp_fd, buf, pack_len, 0, (struct sockaddr *)&sll,
69 sizeof(sll));
70
71 return len;
72 }
73
74 /* Build a gratuitous ARP message over a specific interface */
75 static ssize_t vrrp_build_garp(uint8_t *buf, struct interface *ifp,
76 struct in_addr *v4)
77 {
78 uint8_t *arp_ptr;
79
80 if (ifp->hw_addr_len == 0)
81 return -1;
82
83 /* Build Ethernet header */
84 struct ether_header *eth = (struct ether_header *) buf;
85
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);
89
90 /* Build ARP payload */
91 struct arphdr *arph = (struct arphdr *) (buf + ETHER_HDR_LEN);
92
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);
99 /* Source MAC: us */
100 memcpy(arp_ptr, ifp->hw_addr, ifp->hw_addr_len);
101 arp_ptr += ifp->hw_addr_len;
102 /* Source IP: us */
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;
108 /* Dest IP: us */
109 memcpy(arp_ptr, v4, sizeof(struct in_addr));
110 arp_ptr += sizeof(struct in_addr);
111
112 return arp_ptr - buf;
113 }
114
115 void vrrp_garp_send(struct vrrp_router *r, struct in_addr *v4)
116 {
117 struct interface *ifp = r->vr->ifp;
118 uint8_t garpbuf[GARP_BUFFER_SIZE];
119 ssize_t garpbuf_len;
120 ssize_t sent_len;
121 char astr[INET_ADDRSTRLEN];
122
123 /* If the interface doesn't support ARP, don't try sending */
124 if (ifp->flags & IFF_NOARP) {
125 zlog_warn(
126 VRRP_LOGPFX VRRP_LOGPFX_VRID
127 "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
128 r->vr->vrid, ifp->name);
129 return;
130 }
131
132 /* Build garp */
133 garpbuf_len = vrrp_build_garp(garpbuf, ifp, v4);
134
135 /* Send garp */
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);
141
142 if (sent_len < 0)
143 zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID
144 "Error sending gratuitous ARP on %s for %s",
145 r->vr->vrid, ifp->name, astr);
146 }
147
148 void vrrp_garp_send_all(struct vrrp_router *r)
149 {
150 assert(r->family == AF_INET);
151
152 struct interface *ifp = r->vr->ifp;
153
154 /* If the interface doesn't support ARP, don't try sending */
155 if (ifp->flags & IFF_NOARP) {
156 zlog_warn(
157 VRRP_LOGPFX VRRP_LOGPFX_VRID
158 "Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
159 r->vr->vrid, ifp->name);
160 return;
161 }
162
163 struct listnode *ln;
164 struct ipaddr *ip;
165
166 for (ALL_LIST_ELEMENTS_RO(r->addrs, ln, ip))
167 vrrp_garp_send(r, &ip->ipaddr_v4);
168 }
169
170
171 void vrrp_garp_init(void)
172 {
173 /* Create the socket descriptor */
174 /* FIXME: why ETH_P_RARP? */
175 errno = 0;
176 frr_elevate_privs(&vrrp_privs) {
177 garp_fd = socket(PF_PACKET, SOCK_RAW | SOCK_CLOEXEC,
178 htons(ETH_P_RARP));
179 }
180
181 if (garp_fd > 0)
182 zlog_info(VRRP_LOGPFX "Initialized gratuitous ARP socket");
183 else {
184 zlog_err(VRRP_LOGPFX
185 "Error initializing gratuitous ARP socket");
186 return;
187 }
188 }
189
190 void vrrp_garp_fini(void)
191 {
192 close(garp_fd);
193 garp_fd = -1;
194 }
195
196 bool vrrp_garp_is_init(void)
197 {
198 return garp_fd > 0;
199 }