blob: 8df877dbaaa11226e008ee0f532d813c983a8c1e [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"
paul718e3742002-12-13 20:15:29 +000033
34#include "zebra/interface.h"
Feng Lu758fb8f2014-07-03 18:23:09 +080035#include "zebra/rib.h"
paul718e3742002-12-13 20:15:29 +000036
37/* Interface looking up using infamous SIOCGIFCONF. */
paula1ac18c2005-06-28 17:17:12 +000038static int
39interface_list_ioctl (void)
paul718e3742002-12-13 20:15:29 +000040{
41 int ret;
42 int sock;
43#define IFNUM_BASE 32
44 int ifnum;
45 struct ifreq *ifreq;
46 struct ifconf ifconf;
47 struct interface *ifp;
48 int n;
49 int lastlen;
50
51 /* Normally SIOCGIFCONF works with AF_INET socket. */
52 sock = socket (AF_INET, SOCK_DGRAM, 0);
53 if (sock < 0)
54 {
ajs6099b3b2004-11-20 02:06:59 +000055 zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +000056 return -1;
57 }
58
59 /* Set initial ifreq count. This will be double when SIOCGIFCONF
60 fail. Solaris has SIOCGIFNUM. */
61#ifdef SIOCGIFNUM
62 ret = ioctl (sock, SIOCGIFNUM, &ifnum);
63 if (ret < 0)
64 ifnum = IFNUM_BASE;
65 else
66 ifnum++;
67#else
68 ifnum = IFNUM_BASE;
69#endif /* SIOCGIFNUM */
70
71 ifconf.ifc_buf = NULL;
72
73 lastlen = 0;
74 /* Loop until SIOCGIFCONF success. */
75 for (;;)
76 {
77 ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
78 ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
79
80 ret = ioctl(sock, SIOCGIFCONF, &ifconf);
81
82 if (ret < 0)
83 {
ajs6099b3b2004-11-20 02:06:59 +000084 zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +000085 goto end;
86 }
87 /* Repeatedly get info til buffer fails to grow. */
88 if (ifconf.ifc_len > lastlen)
89 {
90 lastlen = ifconf.ifc_len;
91 ifnum += 10;
92 continue;
93 }
94 /* Success. */
95 break;
96 }
97
98 /* Allocate interface. */
99 ifreq = ifconf.ifc_req;
100
101#ifdef OPEN_BSD
102 for (n = 0; n < ifconf.ifc_len; )
103 {
104 int size;
105
106 ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
ajs08dbfb62005-04-03 03:40:52 +0000107 ifp = if_get_by_name_len(ifreq->ifr_name,
108 strnlen(ifreq->ifr_name,
109 sizeof(ifreq->ifr_name)));
paul718e3742002-12-13 20:15:29 +0000110 if_add_update (ifp);
111 size = ifreq->ifr_addr.sa_len;
112 if (size < sizeof (ifreq->ifr_addr))
113 size = sizeof (ifreq->ifr_addr);
114 size += sizeof (ifreq->ifr_name);
115 n += size;
116 }
117#else
118 for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
119 {
ajs08dbfb62005-04-03 03:40:52 +0000120 ifp = if_get_by_name_len(ifreq->ifr_name,
121 strnlen(ifreq->ifr_name,
122 sizeof(ifreq->ifr_name)));
paul718e3742002-12-13 20:15:29 +0000123 if_add_update (ifp);
124 ifreq++;
125 }
126#endif /* OPEN_BSD */
127
128 end:
129 close (sock);
130 XFREE (MTYPE_TMP, ifconf.ifc_buf);
131
132 return ret;
133}
134
135/* Get interface's index by ioctl. */
paula1ac18c2005-06-28 17:17:12 +0000136static int
paul718e3742002-12-13 20:15:29 +0000137if_get_index (struct interface *ifp)
138{
paulab836aa2002-12-13 21:19:02 +0000139#if defined(HAVE_IF_NAMETOINDEX)
140 /* Modern systems should have if_nametoindex(3). */
141 ifp->ifindex = if_nametoindex(ifp->name);
142#elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES)
143 /* Fall-back for older linuxes. */
paul718e3742002-12-13 20:15:29 +0000144 int ret;
145 struct ifreq ifreq;
paul53db0fe2003-07-11 17:42:09 +0000146 static int if_fake_index;
paul718e3742002-12-13 20:15:29 +0000147
148 ifreq_set_name (&ifreq, ifp);
149
150 ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
151 if (ret < 0)
152 {
153 /* Linux 2.0.X does not have interface index. */
154 ifp->ifindex = if_fake_index++;
155 return ifp->ifindex;
156 }
157
158 /* OK we got interface index. */
159#ifdef ifr_ifindex
160 ifp->ifindex = ifreq.ifr_ifindex;
161#else
162 ifp->ifindex = ifreq.ifr_index;
163#endif
paul718e3742002-12-13 20:15:29 +0000164
165#else
paulab836aa2002-12-13 21:19:02 +0000166/* Linux 2.2.X does not provide individual interface index
167 for aliases and we know it. For others issue a warning. */
168#if !defined(HAVE_BROKEN_ALIASES)
169#warning "Using if_fake_index. You may want to add appropriate"
170#warning "mapping from ifname to ifindex for your system..."
171#endif
172 /* This branch probably won't provide usable results, but anyway... */
173 static int if_fake_index = 1;
paul718e3742002-12-13 20:15:29 +0000174 ifp->ifindex = if_fake_index++;
paulab836aa2002-12-13 21:19:02 +0000175#endif
176
paul718e3742002-12-13 20:15:29 +0000177 return ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000178}
179
180#ifdef SIOCGIFHWADDR
paula1ac18c2005-06-28 17:17:12 +0000181static int
paul718e3742002-12-13 20:15:29 +0000182if_get_hwaddr (struct interface *ifp)
183{
184 int ret;
185 struct ifreq ifreq;
186 int i;
187
188 strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
189 ifreq.ifr_addr.sa_family = AF_INET;
190
191 /* Fetch Hardware address if available. */
192 ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
193 if (ret < 0)
194 ifp->hw_addr_len = 0;
195 else
196 {
197 memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
198
199 for (i = 0; i < 6; i++)
200 if (ifp->hw_addr[i] != 0)
201 break;
202
203 if (i == 6)
204 ifp->hw_addr_len = 0;
205 else
206 ifp->hw_addr_len = 6;
207 }
208 return 0;
209}
210#endif /* SIOCGIFHWADDR */
211
212#ifdef HAVE_GETIFADDRS
213#include <ifaddrs.h>
214
paula1ac18c2005-06-28 17:17:12 +0000215static int
216if_getaddrs (void)
paul718e3742002-12-13 20:15:29 +0000217{
218 int ret;
219 struct ifaddrs *ifap;
220 struct ifaddrs *ifapfree;
221 struct interface *ifp;
222 int prefixlen;
223
224 ret = getifaddrs (&ifap);
225 if (ret != 0)
226 {
ajs6099b3b2004-11-20 02:06:59 +0000227 zlog_err ("getifaddrs(): %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000228 return -1;
229 }
230
231 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
232 {
paul61f42ae2006-01-17 17:59:11 +0000233 if (ifap->ifa_addr == NULL)
234 {
235 zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
236 __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)"));
237 continue;
238 }
239
paul718e3742002-12-13 20:15:29 +0000240 ifp = if_lookup_by_name (ifap->ifa_name);
241 if (ifp == NULL)
242 {
243 zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
244 ifap->ifa_name);
245 continue;
246 }
247
248 if (ifap->ifa_addr->sa_family == AF_INET)
249 {
250 struct sockaddr_in *addr;
251 struct sockaddr_in *mask;
252 struct sockaddr_in *dest;
253 struct in_addr *dest_pnt;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000254 int flags = 0;
paul718e3742002-12-13 20:15:29 +0000255
256 addr = (struct sockaddr_in *) ifap->ifa_addr;
257 mask = (struct sockaddr_in *) ifap->ifa_netmask;
258 prefixlen = ip_masklen (mask->sin_addr);
259
260 dest_pnt = NULL;
261
Andrew J. Schorre4529632006-12-12 19:18:21 +0000262 if (ifap->ifa_dstaddr &&
263 !IPV4_ADDR_SAME(&addr->sin_addr,
264 &((struct sockaddr_in *)
265 ifap->ifa_dstaddr)->sin_addr))
paul718e3742002-12-13 20:15:29 +0000266 {
267 dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
268 dest_pnt = &dest->sin_addr;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000269 flags = ZEBRA_IFA_PEER;
paul718e3742002-12-13 20:15:29 +0000270 }
Andrew J. Schorre4529632006-12-12 19:18:21 +0000271 else if (ifap->ifa_broadaddr &&
272 !IPV4_ADDR_SAME(&addr->sin_addr,
273 &((struct sockaddr_in *)
274 ifap->ifa_broadaddr)->sin_addr))
paul718e3742002-12-13 20:15:29 +0000275 {
276 dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
277 dest_pnt = &dest->sin_addr;
278 }
279
Andrew J. Schorre4529632006-12-12 19:18:21 +0000280 connected_add_ipv4 (ifp, flags, &addr->sin_addr,
paul718e3742002-12-13 20:15:29 +0000281 prefixlen, dest_pnt, NULL);
282 }
283#ifdef HAVE_IPV6
284 if (ifap->ifa_addr->sa_family == AF_INET6)
285 {
286 struct sockaddr_in6 *addr;
287 struct sockaddr_in6 *mask;
288 struct sockaddr_in6 *dest;
289 struct in6_addr *dest_pnt;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000290 int flags = 0;
paul718e3742002-12-13 20:15:29 +0000291
292 addr = (struct sockaddr_in6 *) ifap->ifa_addr;
293 mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
294 prefixlen = ip6_masklen (mask->sin6_addr);
295
296 dest_pnt = NULL;
297
Andrew J. Schorre4529632006-12-12 19:18:21 +0000298 if (ifap->ifa_dstaddr &&
299 !IPV6_ADDR_SAME(&addr->sin6_addr,
300 &((struct sockaddr_in6 *)
301 ifap->ifa_dstaddr)->sin6_addr))
paul718e3742002-12-13 20:15:29 +0000302 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000303 dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
304 dest_pnt = &dest->sin6_addr;
305 flags = ZEBRA_IFA_PEER;
paul718e3742002-12-13 20:15:29 +0000306 }
Andrew J. Schorre4529632006-12-12 19:18:21 +0000307 else if (ifap->ifa_broadaddr &&
308 !IPV6_ADDR_SAME(&addr->sin6_addr,
309 &((struct sockaddr_in6 *)
310 ifap->ifa_broadaddr)->sin6_addr))
paul718e3742002-12-13 20:15:29 +0000311 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000312 dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
313 dest_pnt = &dest->sin6_addr;
paul718e3742002-12-13 20:15:29 +0000314 }
315
paulab836aa2002-12-13 21:19:02 +0000316#if defined(KAME)
317 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
318 {
319 addr->sin6_scope_id =
320 ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]);
321 addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
322 }
323#endif
324
Andrew J. Schorre4529632006-12-12 19:18:21 +0000325 connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen,
paul0752ef02005-11-03 12:35:21 +0000326 dest_pnt, NULL);
paul718e3742002-12-13 20:15:29 +0000327 }
328#endif /* HAVE_IPV6 */
329 }
330
331 freeifaddrs (ifapfree);
332
333 return 0;
334}
335#else /* HAVE_GETIFADDRS */
336/* Interface address lookup by ioctl. This function only looks up
337 IPv4 address. */
338int
339if_get_addr (struct interface *ifp)
340{
341 int ret;
342 struct ifreq ifreq;
343 struct sockaddr_in addr;
344 struct sockaddr_in mask;
345 struct sockaddr_in dest;
346 struct in_addr *dest_pnt;
347 u_char prefixlen;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000348 int flags = 0;
paul718e3742002-12-13 20:15:29 +0000349
350 /* Interface's name and address family. */
351 strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
352 ifreq.ifr_addr.sa_family = AF_INET;
353
354 /* Interface's address. */
355 ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
356 if (ret < 0)
357 {
358 if (errno != EADDRNOTAVAIL)
359 {
ajs6099b3b2004-11-20 02:06:59 +0000360 zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000361 return ret;
362 }
363 return 0;
364 }
365 memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
366
367 /* Interface's network mask. */
368 ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
369 if (ret < 0)
370 {
371 if (errno != EADDRNOTAVAIL)
372 {
ajs6099b3b2004-11-20 02:06:59 +0000373 zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000374 return ret;
375 }
376 return 0;
377 }
378#ifdef ifr_netmask
379 memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
380#else
381 memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
382#endif /* ifr_netmask */
383 prefixlen = ip_masklen (mask.sin_addr);
384
385 /* Point to point or borad cast address pointer init. */
386 dest_pnt = NULL;
387
Andrew J. Schorre4529632006-12-12 19:18:21 +0000388 ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
389 if (ret < 0)
paul718e3742002-12-13 20:15:29 +0000390 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000391 if (errno != EADDRNOTAVAIL)
392 zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno));
393 }
394 else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr))
395 {
paul718e3742002-12-13 20:15:29 +0000396 memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
397 dest_pnt = &dest.sin_addr;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000398 flags = ZEBRA_IFA_PEER;
paul718e3742002-12-13 20:15:29 +0000399 }
Andrew J. Schorre4529632006-12-12 19:18:21 +0000400 if (!dest_pnt)
paul718e3742002-12-13 20:15:29 +0000401 {
402 ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
403 if (ret < 0)
404 {
405 if (errno != EADDRNOTAVAIL)
Andrew J. Schorre4529632006-12-12 19:18:21 +0000406 zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000407 }
Andrew J. Schorre4529632006-12-12 19:18:21 +0000408 else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr))
409 {
410 memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
411 dest_pnt = &dest.sin_addr;
412 }
paul718e3742002-12-13 20:15:29 +0000413 }
414
415
416 /* Set address to the interface. */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000417 connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL);
paul718e3742002-12-13 20:15:29 +0000418
419 return 0;
420}
421#endif /* HAVE_GETIFADDRS */
422
423/* Fetch interface information via ioctl(). */
424static void
425interface_info_ioctl ()
426{
paul1eb8ef22005-04-07 07:30:20 +0000427 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000428 struct interface *ifp;
429
paula1ac18c2005-06-28 17:17:12 +0000430 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
paul718e3742002-12-13 20:15:29 +0000431 {
paul718e3742002-12-13 20:15:29 +0000432 if_get_index (ifp);
433#ifdef SIOCGIFHWADDR
434 if_get_hwaddr (ifp);
435#endif /* SIOCGIFHWADDR */
436 if_get_flags (ifp);
437#ifndef HAVE_GETIFADDRS
438 if_get_addr (ifp);
439#endif /* ! HAVE_GETIFADDRS */
440 if_get_mtu (ifp);
441 if_get_metric (ifp);
442 }
443}
444
445/* Lookup all interface information. */
446void
Feng Lu758fb8f2014-07-03 18:23:09 +0800447interface_list (struct zebra_vrf *zvrf)
paul718e3742002-12-13 20:15:29 +0000448{
Feng Lu758fb8f2014-07-03 18:23:09 +0800449 if (zvrf->vrf_id != VRF_DEFAULT)
450 {
451 zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
452 return;
453 }
paul718e3742002-12-13 20:15:29 +0000454 /* Linux can do both proc & ioctl, ioctl is the only way to get
455 interface aliases in 2.2 series kernels. */
456#ifdef HAVE_PROC_NET_DEV
457 interface_list_proc ();
458#endif /* HAVE_PROC_NET_DEV */
459 interface_list_ioctl ();
460
461 /* After listing is done, get index, address, flags and other
462 interface's information. */
463 interface_info_ioctl ();
464
465#ifdef HAVE_GETIFADDRS
466 if_getaddrs ();
467#endif /* HAVE_GETIFADDRS */
468
469#if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
470 /* Linux provides interface's IPv6 address via
471 /proc/net/if_inet6. */
472 ifaddr_proc_ipv6 ();
473#endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
474}