blob: 99328a1d2a628a8bb87e2f1b6e92fa09abb9752a [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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 "log.h"
Feng Lu758fb8f2014-07-03 18:23:09 +080032#include "vrf.h"
Donald Sharp4f847372015-12-22 15:24:25 -050033#include "vty.h"
paul718e3742002-12-13 20:15:29 +000034
35#include "zebra/interface.h"
Feng Lu758fb8f2014-07-03 18:23:09 +080036#include "zebra/rib.h"
paul718e3742002-12-13 20:15:29 +000037
38/* Interface looking up using infamous SIOCGIFCONF. */
paula1ac18c2005-06-28 17:17:12 +000039static int
40interface_list_ioctl (void)
paul718e3742002-12-13 20:15:29 +000041{
42 int ret;
43 int sock;
44#define IFNUM_BASE 32
45 int ifnum;
46 struct ifreq *ifreq;
47 struct ifconf ifconf;
48 struct interface *ifp;
49 int n;
50 int lastlen;
51
52 /* Normally SIOCGIFCONF works with AF_INET socket. */
53 sock = socket (AF_INET, SOCK_DGRAM, 0);
54 if (sock < 0)
55 {
ajs6099b3b2004-11-20 02:06:59 +000056 zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +000057 return -1;
58 }
59
60 /* Set initial ifreq count. This will be double when SIOCGIFCONF
61 fail. Solaris has SIOCGIFNUM. */
62#ifdef SIOCGIFNUM
63 ret = ioctl (sock, SIOCGIFNUM, &ifnum);
64 if (ret < 0)
65 ifnum = IFNUM_BASE;
66 else
67 ifnum++;
68#else
69 ifnum = IFNUM_BASE;
70#endif /* SIOCGIFNUM */
71
72 ifconf.ifc_buf = NULL;
73
74 lastlen = 0;
75 /* Loop until SIOCGIFCONF success. */
76 for (;;)
77 {
78 ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
79 ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
80
81 ret = ioctl(sock, SIOCGIFCONF, &ifconf);
82
83 if (ret < 0)
84 {
ajs6099b3b2004-11-20 02:06:59 +000085 zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +000086 goto end;
87 }
88 /* Repeatedly get info til buffer fails to grow. */
89 if (ifconf.ifc_len > lastlen)
90 {
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 {
105 int size;
106
107 ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
ajs08dbfb62005-04-03 03:40:52 +0000108 ifp = if_get_by_name_len(ifreq->ifr_name,
109 strnlen(ifreq->ifr_name,
110 sizeof(ifreq->ifr_name)));
paul718e3742002-12-13 20:15:29 +0000111 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 {
ajs08dbfb62005-04-03 03:40:52 +0000121 ifp = if_get_by_name_len(ifreq->ifr_name,
122 strnlen(ifreq->ifr_name,
123 sizeof(ifreq->ifr_name)));
paul718e3742002-12-13 20:15:29 +0000124 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. */
paula1ac18c2005-06-28 17:17:12 +0000137static int
paul718e3742002-12-13 20:15:29 +0000138if_get_index (struct interface *ifp)
139{
paulab836aa2002-12-13 21:19:02 +0000140#if defined(HAVE_IF_NAMETOINDEX)
141 /* Modern systems should have if_nametoindex(3). */
142 ifp->ifindex = if_nametoindex(ifp->name);
143#elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES)
144 /* Fall-back for older linuxes. */
paul718e3742002-12-13 20:15:29 +0000145 int ret;
146 struct ifreq ifreq;
paul53db0fe2003-07-11 17:42:09 +0000147 static int if_fake_index;
paul718e3742002-12-13 20:15:29 +0000148
149 ifreq_set_name (&ifreq, ifp);
150
151 ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
152 if (ret < 0)
153 {
154 /* Linux 2.0.X does not have interface index. */
155 ifp->ifindex = if_fake_index++;
156 return ifp->ifindex;
157 }
158
159 /* OK we got interface index. */
160#ifdef ifr_ifindex
161 ifp->ifindex = ifreq.ifr_ifindex;
162#else
163 ifp->ifindex = ifreq.ifr_index;
164#endif
paul718e3742002-12-13 20:15:29 +0000165
166#else
paulab836aa2002-12-13 21:19:02 +0000167/* Linux 2.2.X does not provide individual interface index
168 for aliases and we know it. For others issue a warning. */
169#if !defined(HAVE_BROKEN_ALIASES)
170#warning "Using if_fake_index. You may want to add appropriate"
171#warning "mapping from ifname to ifindex for your system..."
172#endif
173 /* This branch probably won't provide usable results, but anyway... */
174 static int if_fake_index = 1;
paul718e3742002-12-13 20:15:29 +0000175 ifp->ifindex = if_fake_index++;
paulab836aa2002-12-13 21:19:02 +0000176#endif
177
paul718e3742002-12-13 20:15:29 +0000178 return ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000179}
180
181#ifdef SIOCGIFHWADDR
paula1ac18c2005-06-28 17:17:12 +0000182static int
paul718e3742002-12-13 20:15:29 +0000183if_get_hwaddr (struct interface *ifp)
184{
185 int ret;
186 struct ifreq ifreq;
187 int i;
188
189 strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
190 ifreq.ifr_addr.sa_family = AF_INET;
191
192 /* Fetch Hardware address if available. */
193 ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
194 if (ret < 0)
195 ifp->hw_addr_len = 0;
196 else
197 {
198 memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
199
200 for (i = 0; i < 6; i++)
201 if (ifp->hw_addr[i] != 0)
202 break;
203
204 if (i == 6)
205 ifp->hw_addr_len = 0;
206 else
207 ifp->hw_addr_len = 6;
208 }
209 return 0;
210}
211#endif /* SIOCGIFHWADDR */
212
213#ifdef HAVE_GETIFADDRS
214#include <ifaddrs.h>
215
paula1ac18c2005-06-28 17:17:12 +0000216static int
217if_getaddrs (void)
paul718e3742002-12-13 20:15:29 +0000218{
219 int ret;
220 struct ifaddrs *ifap;
221 struct ifaddrs *ifapfree;
222 struct interface *ifp;
223 int prefixlen;
224
225 ret = getifaddrs (&ifap);
226 if (ret != 0)
227 {
ajs6099b3b2004-11-20 02:06:59 +0000228 zlog_err ("getifaddrs(): %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000229 return -1;
230 }
231
232 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
233 {
paul61f42ae2006-01-17 17:59:11 +0000234 if (ifap->ifa_addr == NULL)
235 {
236 zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
237 __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)"));
238 continue;
239 }
240
paul718e3742002-12-13 20:15:29 +0000241 ifp = if_lookup_by_name (ifap->ifa_name);
242 if (ifp == NULL)
243 {
244 zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
245 ifap->ifa_name);
246 continue;
247 }
248
249 if (ifap->ifa_addr->sa_family == AF_INET)
250 {
251 struct sockaddr_in *addr;
252 struct sockaddr_in *mask;
253 struct sockaddr_in *dest;
254 struct in_addr *dest_pnt;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000255 int flags = 0;
paul718e3742002-12-13 20:15:29 +0000256
257 addr = (struct sockaddr_in *) ifap->ifa_addr;
258 mask = (struct sockaddr_in *) ifap->ifa_netmask;
259 prefixlen = ip_masklen (mask->sin_addr);
260
261 dest_pnt = NULL;
262
Andrew J. Schorre4529632006-12-12 19:18:21 +0000263 if (ifap->ifa_dstaddr &&
264 !IPV4_ADDR_SAME(&addr->sin_addr,
265 &((struct sockaddr_in *)
266 ifap->ifa_dstaddr)->sin_addr))
paul718e3742002-12-13 20:15:29 +0000267 {
268 dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
269 dest_pnt = &dest->sin_addr;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000270 flags = ZEBRA_IFA_PEER;
paul718e3742002-12-13 20:15:29 +0000271 }
Andrew J. Schorre4529632006-12-12 19:18:21 +0000272 else if (ifap->ifa_broadaddr &&
273 !IPV4_ADDR_SAME(&addr->sin_addr,
274 &((struct sockaddr_in *)
275 ifap->ifa_broadaddr)->sin_addr))
paul718e3742002-12-13 20:15:29 +0000276 {
277 dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
278 dest_pnt = &dest->sin_addr;
279 }
280
Andrew J. Schorre4529632006-12-12 19:18:21 +0000281 connected_add_ipv4 (ifp, flags, &addr->sin_addr,
paul718e3742002-12-13 20:15:29 +0000282 prefixlen, dest_pnt, NULL);
283 }
284#ifdef HAVE_IPV6
285 if (ifap->ifa_addr->sa_family == AF_INET6)
286 {
287 struct sockaddr_in6 *addr;
288 struct sockaddr_in6 *mask;
289 struct sockaddr_in6 *dest;
290 struct in6_addr *dest_pnt;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000291 int flags = 0;
paul718e3742002-12-13 20:15:29 +0000292
293 addr = (struct sockaddr_in6 *) ifap->ifa_addr;
294 mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
295 prefixlen = ip6_masklen (mask->sin6_addr);
296
297 dest_pnt = NULL;
298
Andrew J. Schorre4529632006-12-12 19:18:21 +0000299 if (ifap->ifa_dstaddr &&
300 !IPV6_ADDR_SAME(&addr->sin6_addr,
301 &((struct sockaddr_in6 *)
302 ifap->ifa_dstaddr)->sin6_addr))
paul718e3742002-12-13 20:15:29 +0000303 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000304 dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
305 dest_pnt = &dest->sin6_addr;
306 flags = ZEBRA_IFA_PEER;
paul718e3742002-12-13 20:15:29 +0000307 }
Andrew J. Schorre4529632006-12-12 19:18:21 +0000308 else if (ifap->ifa_broadaddr &&
309 !IPV6_ADDR_SAME(&addr->sin6_addr,
310 &((struct sockaddr_in6 *)
311 ifap->ifa_broadaddr)->sin6_addr))
paul718e3742002-12-13 20:15:29 +0000312 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000313 dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
314 dest_pnt = &dest->sin6_addr;
paul718e3742002-12-13 20:15:29 +0000315 }
316
paulab836aa2002-12-13 21:19:02 +0000317#if defined(KAME)
318 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
319 {
320 addr->sin6_scope_id =
321 ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]);
322 addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
323 }
324#endif
325
Andrew J. Schorre4529632006-12-12 19:18:21 +0000326 connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen,
paul0752ef02005-11-03 12:35:21 +0000327 dest_pnt, NULL);
paul718e3742002-12-13 20:15:29 +0000328 }
329#endif /* HAVE_IPV6 */
330 }
331
332 freeifaddrs (ifapfree);
333
334 return 0;
335}
336#else /* HAVE_GETIFADDRS */
337/* Interface address lookup by ioctl. This function only looks up
338 IPv4 address. */
339int
340if_get_addr (struct interface *ifp)
341{
342 int ret;
343 struct ifreq ifreq;
344 struct sockaddr_in addr;
345 struct sockaddr_in mask;
346 struct sockaddr_in dest;
347 struct in_addr *dest_pnt;
348 u_char prefixlen;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000349 int flags = 0;
paul718e3742002-12-13 20:15:29 +0000350
351 /* Interface's name and address family. */
352 strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
353 ifreq.ifr_addr.sa_family = AF_INET;
354
355 /* Interface's address. */
356 ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
357 if (ret < 0)
358 {
359 if (errno != EADDRNOTAVAIL)
360 {
ajs6099b3b2004-11-20 02:06:59 +0000361 zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000362 return ret;
363 }
364 return 0;
365 }
366 memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
367
368 /* Interface's network mask. */
369 ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
370 if (ret < 0)
371 {
372 if (errno != EADDRNOTAVAIL)
373 {
ajs6099b3b2004-11-20 02:06:59 +0000374 zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000375 return ret;
376 }
377 return 0;
378 }
379#ifdef ifr_netmask
380 memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
381#else
382 memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
383#endif /* ifr_netmask */
384 prefixlen = ip_masklen (mask.sin_addr);
385
386 /* Point to point or borad cast address pointer init. */
387 dest_pnt = NULL;
388
Andrew J. Schorre4529632006-12-12 19:18:21 +0000389 ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
390 if (ret < 0)
paul718e3742002-12-13 20:15:29 +0000391 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000392 if (errno != EADDRNOTAVAIL)
393 zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno));
394 }
395 else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr))
396 {
paul718e3742002-12-13 20:15:29 +0000397 memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
398 dest_pnt = &dest.sin_addr;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000399 flags = ZEBRA_IFA_PEER;
paul718e3742002-12-13 20:15:29 +0000400 }
Andrew J. Schorre4529632006-12-12 19:18:21 +0000401 if (!dest_pnt)
paul718e3742002-12-13 20:15:29 +0000402 {
403 ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
404 if (ret < 0)
405 {
406 if (errno != EADDRNOTAVAIL)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000407 zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000408 }
Andrew J. Schorre4529632006-12-12 19:18:21 +0000409 else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr))
410 {
411 memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
412 dest_pnt = &dest.sin_addr;
413 }
paul718e3742002-12-13 20:15:29 +0000414 }
415
416
417 /* Set address to the interface. */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000418 connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL);
paul718e3742002-12-13 20:15:29 +0000419
420 return 0;
421}
422#endif /* HAVE_GETIFADDRS */
423
424/* Fetch interface information via ioctl(). */
425static void
426interface_info_ioctl ()
427{
paul1eb8ef22005-04-07 07:30:20 +0000428 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000429 struct interface *ifp;
430
paula1ac18c2005-06-28 17:17:12 +0000431 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
paul718e3742002-12-13 20:15:29 +0000432 {
paul718e3742002-12-13 20:15:29 +0000433 if_get_index (ifp);
434#ifdef SIOCGIFHWADDR
435 if_get_hwaddr (ifp);
436#endif /* SIOCGIFHWADDR */
437 if_get_flags (ifp);
438#ifndef HAVE_GETIFADDRS
439 if_get_addr (ifp);
440#endif /* ! HAVE_GETIFADDRS */
441 if_get_mtu (ifp);
442 if_get_metric (ifp);
443 }
444}
445
446/* Lookup all interface information. */
447void
Feng Lu758fb8f2014-07-03 18:23:09 +0800448interface_list (struct zebra_vrf *zvrf)
paul718e3742002-12-13 20:15:29 +0000449{
Feng Lu758fb8f2014-07-03 18:23:09 +0800450 if (zvrf->vrf_id != VRF_DEFAULT)
451 {
452 zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
453 return;
454 }
paul718e3742002-12-13 20:15:29 +0000455 /* Linux can do both proc & ioctl, ioctl is the only way to get
456 interface aliases in 2.2 series kernels. */
457#ifdef HAVE_PROC_NET_DEV
458 interface_list_proc ();
459#endif /* HAVE_PROC_NET_DEV */
460 interface_list_ioctl ();
461
462 /* After listing is done, get index, address, flags and other
463 interface's information. */
464 interface_info_ioctl ();
465
466#ifdef HAVE_GETIFADDRS
467 if_getaddrs ();
468#endif /* HAVE_GETIFADDRS */
469
470#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
471 /* Linux provides interface's IPv6 address via
472 /proc/net/if_inet6. */
473 ifaddr_proc_ipv6 ();
474#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
475}