]>
git.proxmox.com Git - mirror_frr.git/blob - zebra/if_ioctl.c
2 * Interface looking up by ioctl ().
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
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
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.
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
26 #include "sockunion.h"
29 #include "connected.h"
31 #include "zebra_memory.h"
36 #include "zebra/interface.h"
37 #include "zebra/rib.h"
39 /* Interface looking up using infamous SIOCGIFCONF. */
41 interface_list_ioctl (void)
49 struct interface
*ifp
;
53 /* Normally SIOCGIFCONF works with AF_INET socket. */
54 sock
= socket (AF_INET
, SOCK_DGRAM
, 0);
57 zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno
));
61 /* Set initial ifreq count. This will be double when SIOCGIFCONF
62 fail. Solaris has SIOCGIFNUM. */
64 ret
= ioctl (sock
, SIOCGIFNUM
, &ifnum
);
71 #endif /* SIOCGIFNUM */
73 ifconf
.ifc_buf
= NULL
;
76 /* Loop until SIOCGIFCONF success. */
79 ifconf
.ifc_len
= sizeof (struct ifreq
) * ifnum
;
80 ifconf
.ifc_buf
= XREALLOC(MTYPE_TMP
, ifconf
.ifc_buf
, ifconf
.ifc_len
);
82 ret
= ioctl(sock
, SIOCGIFCONF
, &ifconf
);
86 zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno
));
89 /* Repeatedly get info til buffer fails to grow. */
90 if (ifconf
.ifc_len
> lastlen
)
92 lastlen
= ifconf
.ifc_len
;
100 /* Allocate interface. */
101 ifreq
= ifconf
.ifc_req
;
104 for (n
= 0; n
< ifconf
.ifc_len
; )
108 ifreq
= (struct ifreq
*)((caddr_t
) ifconf
.ifc_req
+ n
);
109 ifp
= if_get_by_name_len(ifreq
->ifr_name
,
110 strnlen(ifreq
->ifr_name
,
111 sizeof(ifreq
->ifr_name
)));
113 size
= ifreq
->ifr_addr
.sa_len
;
114 if (size
< sizeof (ifreq
->ifr_addr
))
115 size
= sizeof (ifreq
->ifr_addr
);
116 size
+= sizeof (ifreq
->ifr_name
);
120 for (n
= 0; n
< ifconf
.ifc_len
; n
+= sizeof(struct ifreq
))
122 ifp
= if_get_by_name_len(ifreq
->ifr_name
,
123 strnlen(ifreq
->ifr_name
,
124 sizeof(ifreq
->ifr_name
)));
128 #endif /* OPEN_BSD */
132 XFREE (MTYPE_TMP
, ifconf
.ifc_buf
);
137 /* Get interface's index by ioctl. */
139 if_get_index (struct interface
*ifp
)
141 #if defined(HAVE_IF_NAMETOINDEX)
142 /* Modern systems should have if_nametoindex(3). */
143 ifp
->ifindex
= if_nametoindex(ifp
->name
);
144 #elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES)
145 /* Fall-back for older linuxes. */
148 static int if_fake_index
;
150 ifreq_set_name (&ifreq
, ifp
);
152 ret
= if_ioctl (SIOCGIFINDEX
, (caddr_t
) &ifreq
);
155 /* Linux 2.0.X does not have interface index. */
156 ifp
->ifindex
= if_fake_index
++;
160 /* OK we got interface index. */
162 ifp
->ifindex
= ifreq
.ifr_ifindex
;
164 ifp
->ifindex
= ifreq
.ifr_index
;
168 /* Linux 2.2.X does not provide individual interface index
169 for aliases and we know it. For others issue a warning. */
170 #if !defined(HAVE_BROKEN_ALIASES)
171 #warning "Using if_fake_index. You may want to add appropriate"
172 #warning "mapping from ifname to ifindex for your system..."
174 /* This branch probably won't provide usable results, but anyway... */
175 static int if_fake_index
= 1;
176 ifp
->ifindex
= if_fake_index
++;
184 if_get_hwaddr (struct interface
*ifp
)
190 strncpy (ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
191 ifreq
.ifr_addr
.sa_family
= AF_INET
;
193 /* Fetch Hardware address if available. */
194 ret
= if_ioctl (SIOCGIFHWADDR
, (caddr_t
) &ifreq
);
196 ifp
->hw_addr_len
= 0;
199 memcpy (ifp
->hw_addr
, ifreq
.ifr_hwaddr
.sa_data
, 6);
201 for (i
= 0; i
< 6; i
++)
202 if (ifp
->hw_addr
[i
] != 0)
206 ifp
->hw_addr_len
= 0;
208 ifp
->hw_addr_len
= 6;
212 #endif /* SIOCGIFHWADDR */
214 #ifdef HAVE_GETIFADDRS
221 struct ifaddrs
*ifap
;
222 struct ifaddrs
*ifapfree
;
223 struct interface
*ifp
;
226 ret
= getifaddrs (&ifap
);
229 zlog_err ("getifaddrs(): %s", safe_strerror (errno
));
233 for (ifapfree
= ifap
; ifap
; ifap
= ifap
->ifa_next
)
235 if (ifap
->ifa_addr
== NULL
)
237 zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
238 __func__
, (ifap
->ifa_name
? ifap
->ifa_name
: "(null)"));
242 ifp
= if_lookup_by_name (ifap
->ifa_name
);
245 zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
250 if (ifap
->ifa_addr
->sa_family
== AF_INET
)
252 struct sockaddr_in
*addr
;
253 struct sockaddr_in
*mask
;
254 struct sockaddr_in
*dest
;
255 struct in_addr
*dest_pnt
;
258 addr
= (struct sockaddr_in
*) ifap
->ifa_addr
;
259 mask
= (struct sockaddr_in
*) ifap
->ifa_netmask
;
260 prefixlen
= ip_masklen (mask
->sin_addr
);
264 if (ifap
->ifa_dstaddr
&&
265 !IPV4_ADDR_SAME(&addr
->sin_addr
,
266 &((struct sockaddr_in
*)
267 ifap
->ifa_dstaddr
)->sin_addr
))
269 dest
= (struct sockaddr_in
*) ifap
->ifa_dstaddr
;
270 dest_pnt
= &dest
->sin_addr
;
271 flags
= ZEBRA_IFA_PEER
;
273 else if (ifap
->ifa_broadaddr
&&
274 !IPV4_ADDR_SAME(&addr
->sin_addr
,
275 &((struct sockaddr_in
*)
276 ifap
->ifa_broadaddr
)->sin_addr
))
278 dest
= (struct sockaddr_in
*) ifap
->ifa_broadaddr
;
279 dest_pnt
= &dest
->sin_addr
;
282 connected_add_ipv4 (ifp
, flags
, &addr
->sin_addr
,
283 prefixlen
, dest_pnt
, NULL
);
286 if (ifap
->ifa_addr
->sa_family
== AF_INET6
)
288 struct sockaddr_in6
*addr
;
289 struct sockaddr_in6
*mask
;
290 struct sockaddr_in6
*dest
;
291 struct in6_addr
*dest_pnt
;
294 addr
= (struct sockaddr_in6
*) ifap
->ifa_addr
;
295 mask
= (struct sockaddr_in6
*) ifap
->ifa_netmask
;
296 prefixlen
= ip6_masklen (mask
->sin6_addr
);
300 if (ifap
->ifa_dstaddr
&&
301 !IPV6_ADDR_SAME(&addr
->sin6_addr
,
302 &((struct sockaddr_in6
*)
303 ifap
->ifa_dstaddr
)->sin6_addr
))
305 dest
= (struct sockaddr_in6
*) ifap
->ifa_dstaddr
;
306 dest_pnt
= &dest
->sin6_addr
;
307 flags
= ZEBRA_IFA_PEER
;
309 else if (ifap
->ifa_broadaddr
&&
310 !IPV6_ADDR_SAME(&addr
->sin6_addr
,
311 &((struct sockaddr_in6
*)
312 ifap
->ifa_broadaddr
)->sin6_addr
))
314 dest
= (struct sockaddr_in6
*) ifap
->ifa_broadaddr
;
315 dest_pnt
= &dest
->sin6_addr
;
319 if (IN6_IS_ADDR_LINKLOCAL(&addr
->sin6_addr
))
321 addr
->sin6_scope_id
=
322 ntohs(*(u_int16_t
*)&addr
->sin6_addr
.s6_addr
[2]);
323 addr
->sin6_addr
.s6_addr
[2] = addr
->sin6_addr
.s6_addr
[3] = 0;
327 connected_add_ipv6 (ifp
, flags
, &addr
->sin6_addr
, prefixlen
,
330 #endif /* HAVE_IPV6 */
333 freeifaddrs (ifapfree
);
337 #else /* HAVE_GETIFADDRS */
338 /* Interface address lookup by ioctl. This function only looks up
341 if_get_addr (struct interface
*ifp
)
345 struct sockaddr_in addr
;
346 struct sockaddr_in mask
;
347 struct sockaddr_in dest
;
348 struct in_addr
*dest_pnt
;
352 /* Interface's name and address family. */
353 strncpy (ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
354 ifreq
.ifr_addr
.sa_family
= AF_INET
;
356 /* Interface's address. */
357 ret
= if_ioctl (SIOCGIFADDR
, (caddr_t
) &ifreq
);
360 if (errno
!= EADDRNOTAVAIL
)
362 zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno
));
367 memcpy (&addr
, &ifreq
.ifr_addr
, sizeof (struct sockaddr_in
));
369 /* Interface's network mask. */
370 ret
= if_ioctl (SIOCGIFNETMASK
, (caddr_t
) &ifreq
);
373 if (errno
!= EADDRNOTAVAIL
)
375 zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno
));
381 memcpy (&mask
, &ifreq
.ifr_netmask
, sizeof (struct sockaddr_in
));
383 memcpy (&mask
, &ifreq
.ifr_addr
, sizeof (struct sockaddr_in
));
384 #endif /* ifr_netmask */
385 prefixlen
= ip_masklen (mask
.sin_addr
);
387 /* Point to point or borad cast address pointer init. */
390 ret
= if_ioctl (SIOCGIFDSTADDR
, (caddr_t
) &ifreq
);
393 if (errno
!= EADDRNOTAVAIL
)
394 zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno
));
396 else if (!IPV4_ADDR_SAME(&addr
.sin_addr
, &ifreq
.ifr_dstaddr
.sin_addr
))
398 memcpy (&dest
, &ifreq
.ifr_dstaddr
, sizeof (struct sockaddr_in
));
399 dest_pnt
= &dest
.sin_addr
;
400 flags
= ZEBRA_IFA_PEER
;
404 ret
= if_ioctl (SIOCGIFBRDADDR
, (caddr_t
) &ifreq
);
407 if (errno
!= EADDRNOTAVAIL
)
408 zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno
));
410 else if (!IPV4_ADDR_SAME(&addr
.sin_addr
, &ifreq
.ifr_broadaddr
.sin_addr
))
412 memcpy (&dest
, &ifreq
.ifr_broadaddr
, sizeof (struct sockaddr_in
));
413 dest_pnt
= &dest
.sin_addr
;
418 /* Set address to the interface. */
419 connected_add_ipv4 (ifp
, flags
, &addr
.sin_addr
, prefixlen
, dest_pnt
, NULL
);
423 #endif /* HAVE_GETIFADDRS */
425 /* Fetch interface information via ioctl(). */
427 interface_info_ioctl ()
429 struct listnode
*node
, *nnode
;
430 struct interface
*ifp
;
432 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), node
, nnode
, ifp
))
437 #endif /* SIOCGIFHWADDR */
439 #ifndef HAVE_GETIFADDRS
441 #endif /* ! HAVE_GETIFADDRS */
447 /* Lookup all interface information. */
449 interface_list (struct zebra_ns
*zns
)
452 zlog_info ("interface_list: NS %u", zns
->ns_id
);
454 /* 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 ();
461 /* After listing is done, get index, address, flags and other
462 interface's information. */
463 interface_info_ioctl ();
465 #ifdef HAVE_GETIFADDRS
467 #endif /* HAVE_GETIFADDRS */
469 #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
470 /* Linux provides interface's IPv6 address via
471 /proc/net/if_inet6. */
473 #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */