]> git.proxmox.com Git - mirror_frr.git/blob - zebra/if_ioctl.c
release: FRR 3.0-rc1
[mirror_frr.git] / zebra / if_ioctl.c
1 /*
2 * Interface looking up by ioctl ().
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23 #include <zebra.h>
24
25 #include "if.h"
26 #include "sockunion.h"
27 #include "prefix.h"
28 #include "ioctl.h"
29 #include "connected.h"
30 #include "memory.h"
31 #include "zebra_memory.h"
32 #include "log.h"
33 #include "vrf.h"
34 #include "vty.h"
35
36 #include "zebra/interface.h"
37 #include "zebra/rib.h"
38
39 #include <ifaddrs.h>
40
41 /* Interface looking up using infamous SIOCGIFCONF. */
42 static int interface_list_ioctl(void)
43 {
44 int ret;
45 int sock;
46 #define IFNUM_BASE 32
47 int ifnum;
48 struct ifreq *ifreq;
49 struct ifconf ifconf;
50 struct interface *ifp;
51 int n;
52 int lastlen;
53
54 /* Normally SIOCGIFCONF works with AF_INET socket. */
55 sock = socket(AF_INET, SOCK_DGRAM, 0);
56 if (sock < 0) {
57 zlog_warn("Can't make AF_INET socket stream: %s",
58 safe_strerror(errno));
59 return -1;
60 }
61
62 /* Set initial ifreq count. This will be double when SIOCGIFCONF
63 fail. Solaris has SIOCGIFNUM. */
64 #ifdef SIOCGIFNUM
65 ret = ioctl(sock, SIOCGIFNUM, &ifnum);
66 if (ret < 0)
67 ifnum = IFNUM_BASE;
68 else
69 ifnum++;
70 #else
71 ifnum = IFNUM_BASE;
72 #endif /* SIOCGIFNUM */
73
74 ifconf.ifc_buf = NULL;
75
76 lastlen = 0;
77 /* Loop until SIOCGIFCONF success. */
78 for (;;) {
79 ifconf.ifc_len = sizeof(struct ifreq) * ifnum;
80 ifconf.ifc_buf =
81 XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
82
83 ret = ioctl(sock, SIOCGIFCONF, &ifconf);
84
85 if (ret < 0) {
86 zlog_warn("SIOCGIFCONF: %s", safe_strerror(errno));
87 goto end;
88 }
89 /* Repeatedly get info til buffer fails to grow. */
90 if (ifconf.ifc_len > lastlen) {
91 lastlen = ifconf.ifc_len;
92 ifnum += 10;
93 continue;
94 }
95 /* Success. */
96 break;
97 }
98
99 /* Allocate interface. */
100 ifreq = ifconf.ifc_req;
101
102 #ifdef OPEN_BSD
103 for (n = 0; n < ifconf.ifc_len;) {
104 unsigned int size;
105
106 ifreq = (struct ifreq *)((caddr_t)ifconf.ifc_req + n);
107 ifp = if_get_by_name_len(
108 ifreq->ifr_name,
109 strnlen(ifreq->ifr_name, sizeof(ifreq->ifr_name)),
110 VRF_DEFAULT, 0);
111 if_add_update(ifp);
112 size = ifreq->ifr_addr.sa_len;
113 if (size < sizeof(ifreq->ifr_addr))
114 size = sizeof(ifreq->ifr_addr);
115 size += sizeof(ifreq->ifr_name);
116 n += size;
117 }
118 #else
119 for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) {
120 ifp = if_get_by_name_len(
121 ifreq->ifr_name,
122 strnlen(ifreq->ifr_name, sizeof(ifreq->ifr_name)),
123 VRF_DEFAULT, 0);
124 if_add_update(ifp);
125 ifreq++;
126 }
127 #endif /* OPEN_BSD */
128
129 end:
130 close(sock);
131 XFREE(MTYPE_TMP, ifconf.ifc_buf);
132
133 return ret;
134 }
135
136 /* Get interface's index by ioctl. */
137 static int if_get_index(struct interface *ifp)
138 {
139 ifp->ifindex = if_nametoindex(ifp->name);
140 return ifp->ifindex;
141 }
142
143 #ifdef SIOCGIFHWADDR
144 static int if_get_hwaddr(struct interface *ifp)
145 {
146 int ret;
147 struct ifreq ifreq;
148 int i;
149
150 strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ);
151 ifreq.ifr_addr.sa_family = AF_INET;
152
153 /* Fetch Hardware address if available. */
154 ret = if_ioctl(SIOCGIFHWADDR, (caddr_t)&ifreq);
155 if (ret < 0)
156 ifp->hw_addr_len = 0;
157 else {
158 memcpy(ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
159
160 for (i = 0; i < 6; i++)
161 if (ifp->hw_addr[i] != 0)
162 break;
163
164 if (i == 6)
165 ifp->hw_addr_len = 0;
166 else
167 ifp->hw_addr_len = 6;
168 }
169 return 0;
170 }
171 #endif /* SIOCGIFHWADDR */
172
173 static int if_getaddrs(void)
174 {
175 int ret;
176 struct ifaddrs *ifap;
177 struct ifaddrs *ifapfree;
178 struct interface *ifp;
179 int prefixlen;
180
181 ret = getifaddrs(&ifap);
182 if (ret != 0) {
183 zlog_err("getifaddrs(): %s", safe_strerror(errno));
184 return -1;
185 }
186
187 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) {
188 if (ifap->ifa_addr == NULL) {
189 zlog_err(
190 "%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
191 __func__,
192 (ifap->ifa_name ? ifap->ifa_name : "(null)"));
193 continue;
194 }
195
196 ifp = if_lookup_by_name(ifap->ifa_name, VRF_DEFAULT);
197 if (ifp == NULL) {
198 zlog_err("if_getaddrs(): Can't lookup interface %s\n",
199 ifap->ifa_name);
200 continue;
201 }
202
203 if (ifap->ifa_addr->sa_family == AF_INET) {
204 struct sockaddr_in *addr;
205 struct sockaddr_in *mask;
206 struct sockaddr_in *dest;
207 struct in_addr *dest_pnt;
208 int flags = 0;
209
210 addr = (struct sockaddr_in *)ifap->ifa_addr;
211 mask = (struct sockaddr_in *)ifap->ifa_netmask;
212 prefixlen = ip_masklen(mask->sin_addr);
213
214 dest_pnt = NULL;
215
216 if (ifap->ifa_dstaddr
217 && !IPV4_ADDR_SAME(&addr->sin_addr,
218 &((struct sockaddr_in *)
219 ifap->ifa_dstaddr)
220 ->sin_addr)) {
221 dest = (struct sockaddr_in *)ifap->ifa_dstaddr;
222 dest_pnt = &dest->sin_addr;
223 flags = ZEBRA_IFA_PEER;
224 } else if (ifap->ifa_broadaddr
225 && !IPV4_ADDR_SAME(
226 &addr->sin_addr,
227 &((struct sockaddr_in *)
228 ifap->ifa_broadaddr)
229 ->sin_addr)) {
230 dest = (struct sockaddr_in *)
231 ifap->ifa_broadaddr;
232 dest_pnt = &dest->sin_addr;
233 }
234
235 connected_add_ipv4(ifp, flags, &addr->sin_addr,
236 prefixlen, dest_pnt, NULL);
237 }
238 if (ifap->ifa_addr->sa_family == AF_INET6) {
239 struct sockaddr_in6 *addr;
240 struct sockaddr_in6 *mask;
241 struct sockaddr_in6 *dest;
242 struct in6_addr *dest_pnt;
243 int flags = 0;
244
245 addr = (struct sockaddr_in6 *)ifap->ifa_addr;
246 mask = (struct sockaddr_in6 *)ifap->ifa_netmask;
247 prefixlen = ip6_masklen(mask->sin6_addr);
248
249 dest_pnt = NULL;
250
251 if (ifap->ifa_dstaddr
252 && !IPV6_ADDR_SAME(&addr->sin6_addr,
253 &((struct sockaddr_in6 *)
254 ifap->ifa_dstaddr)
255 ->sin6_addr)) {
256 dest = (struct sockaddr_in6 *)ifap->ifa_dstaddr;
257 dest_pnt = &dest->sin6_addr;
258 flags = ZEBRA_IFA_PEER;
259 } else if (ifap->ifa_broadaddr
260 && !IPV6_ADDR_SAME(
261 &addr->sin6_addr,
262 &((struct sockaddr_in6 *)
263 ifap->ifa_broadaddr)
264 ->sin6_addr)) {
265 dest = (struct sockaddr_in6 *)
266 ifap->ifa_broadaddr;
267 dest_pnt = &dest->sin6_addr;
268 }
269
270 #if defined(KAME)
271 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
272 addr->sin6_scope_id =
273 ntohs(*(u_int16_t *)&addr->sin6_addr
274 .s6_addr[2]);
275 addr->sin6_addr.s6_addr[2] =
276 addr->sin6_addr.s6_addr[3] = 0;
277 }
278 #endif
279
280 connected_add_ipv6(ifp, flags, &addr->sin6_addr,
281 prefixlen, dest_pnt, NULL);
282 }
283 }
284
285 freeifaddrs(ifapfree);
286
287 return 0;
288 }
289
290 /* Fetch interface information via ioctl(). */
291 static void interface_info_ioctl()
292 {
293 struct listnode *node, *nnode;
294 struct interface *ifp;
295
296 for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), node, nnode, ifp)) {
297 if_get_index(ifp);
298 #ifdef SIOCGIFHWADDR
299 if_get_hwaddr(ifp);
300 #endif /* SIOCGIFHWADDR */
301 if_get_flags(ifp);
302 if_get_mtu(ifp);
303 if_get_metric(ifp);
304 }
305 }
306
307 /* Lookup all interface information. */
308 void interface_list(struct zebra_ns *zns)
309 {
310
311 zlog_info("interface_list: NS %u", zns->ns_id);
312
313 /* Linux can do both proc & ioctl, ioctl is the only way to get
314 interface aliases in 2.2 series kernels. */
315 #ifdef HAVE_PROC_NET_DEV
316 interface_list_proc();
317 #endif /* HAVE_PROC_NET_DEV */
318 interface_list_ioctl();
319
320 /* After listing is done, get index, address, flags and other
321 interface's information. */
322 interface_info_ioctl();
323
324 if_getaddrs();
325
326 #if defined(HAVE_PROC_NET_IF_INET6)
327 /* Linux provides interface's IPv6 address via
328 /proc/net/if_inet6. */
329 ifaddr_proc_ipv6();
330 #endif /* HAVE_PROC_NET_IF_INET6 */
331 }