]>
Commit | Line | Data |
---|---|---|
41ee5442 QY |
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 | ||
4ec94408 QY |
39 | #define VRRP_LOGPFX "[ARP] " |
40 | ||
41ee5442 QY |
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); | |
c23edd74 | 98 | arp_ptr = (uint8_t *)(arph + 1); |
41ee5442 QY |
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 */ | |
c23edd74 | 103 | memcpy(arp_ptr, v4, sizeof(struct in_addr)); |
41ee5442 QY |
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 */ | |
c23edd74 | 109 | memcpy(arp_ptr, v4, sizeof(struct in_addr)); |
41ee5442 QY |
110 | arp_ptr += sizeof(struct in_addr); |
111 | ||
112 | return arp_ptr - buf; | |
113 | } | |
114 | ||
862f2f37 | 115 | void vrrp_garp_send(struct vrrp_router *r, struct in_addr *v4) |
41ee5442 | 116 | { |
dad18a2f | 117 | struct interface *ifp = r->mvl_ifp; |
41ee5442 QY |
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( | |
4ec94408 | 126 | VRRP_LOGPFX VRRP_LOGPFX_VRID |
41ee5442 | 127 | "Unable to send gratuitous ARP on %s; has IFF_NOARP\n", |
862f2f37 | 128 | r->vr->vrid, ifp->name); |
41ee5442 QY |
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)); | |
4ec94408 QY |
137 | zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID |
138 | "Sending gratuitous ARP on %s for %s", | |
862f2f37 | 139 | r->vr->vrid, ifp->name, astr); |
41ee5442 QY |
140 | sent_len = vrrp_send_garp(ifp, garpbuf, garpbuf_len); |
141 | ||
142 | if (sent_len < 0) | |
4ec94408 QY |
143 | zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID |
144 | "Error sending gratuitous ARP on %s for %s", | |
862f2f37 | 145 | r->vr->vrid, ifp->name, astr); |
41ee5442 QY |
146 | } |
147 | ||
862f2f37 | 148 | void vrrp_garp_send_all(struct vrrp_router *r) |
41ee5442 | 149 | { |
862f2f37 QY |
150 | assert(r->family == AF_INET); |
151 | ||
dad18a2f | 152 | struct interface *ifp = r->mvl_ifp; |
41ee5442 QY |
153 | |
154 | /* If the interface doesn't support ARP, don't try sending */ | |
155 | if (ifp->flags & IFF_NOARP) { | |
156 | zlog_warn( | |
4ec94408 | 157 | VRRP_LOGPFX VRRP_LOGPFX_VRID |
41ee5442 | 158 | "Unable to send gratuitous ARP on %s; has IFF_NOARP\n", |
862f2f37 | 159 | r->vr->vrid, ifp->name); |
41ee5442 QY |
160 | return; |
161 | } | |
162 | ||
163 | struct listnode *ln; | |
862f2f37 | 164 | struct ipaddr *ip; |
41ee5442 | 165 | |
862f2f37 QY |
166 | for (ALL_LIST_ELEMENTS_RO(r->addrs, ln, ip)) |
167 | vrrp_garp_send(r, &ip->ipaddr_v4); | |
41ee5442 QY |
168 | } |
169 | ||
170 | ||
171 | void vrrp_garp_init(void) | |
172 | { | |
173 | /* Create the socket descriptor */ | |
174 | /* FIXME: why ETH_P_RARP? */ | |
40744000 QY |
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 | } | |
41ee5442 QY |
180 | |
181 | if (garp_fd > 0) | |
4ec94408 | 182 | zlog_info(VRRP_LOGPFX "Initialized gratuitous ARP socket"); |
41ee5442 | 183 | else { |
4ec94408 QY |
184 | zlog_err(VRRP_LOGPFX |
185 | "Error initializing gratuitous ARP socket"); | |
41ee5442 QY |
186 | return; |
187 | } | |
188 | } | |
189 | ||
190 | void vrrp_garp_fini(void) | |
191 | { | |
192 | close(garp_fd); | |
193 | garp_fd = -1; | |
194 | } | |
40744000 QY |
195 | |
196 | bool vrrp_garp_is_init(void) | |
197 | { | |
198 | return garp_fd > 0; | |
199 | } |