]>
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"
34 #include "zebra/interface.h"
35 #include "zebra/rib.h"
37 /* Interface looking up using infamous SIOCGIFCONF. */
39 interface_list_ioctl (void)
47 struct interface
*ifp
;
51 /* Normally SIOCGIFCONF works with AF_INET socket. */
52 sock
= socket (AF_INET
, SOCK_DGRAM
, 0);
55 zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno
));
59 /* Set initial ifreq count. This will be double when SIOCGIFCONF
60 fail. Solaris has SIOCGIFNUM. */
62 ret
= ioctl (sock
, SIOCGIFNUM
, &ifnum
);
69 #endif /* SIOCGIFNUM */
71 ifconf
.ifc_buf
= NULL
;
74 /* Loop until SIOCGIFCONF success. */
77 ifconf
.ifc_len
= sizeof (struct ifreq
) * ifnum
;
78 ifconf
.ifc_buf
= XREALLOC(MTYPE_TMP
, ifconf
.ifc_buf
, ifconf
.ifc_len
);
80 ret
= ioctl(sock
, SIOCGIFCONF
, &ifconf
);
84 zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno
));
87 /* Repeatedly get info til buffer fails to grow. */
88 if (ifconf
.ifc_len
> lastlen
)
90 lastlen
= ifconf
.ifc_len
;
98 /* Allocate interface. */
99 ifreq
= ifconf
.ifc_req
;
102 for (n
= 0; n
< ifconf
.ifc_len
; )
106 ifreq
= (struct ifreq
*)((caddr_t
) ifconf
.ifc_req
+ n
);
107 ifp
= if_get_by_name_len(ifreq
->ifr_name
,
108 strnlen(ifreq
->ifr_name
,
109 sizeof(ifreq
->ifr_name
)));
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
);
118 for (n
= 0; n
< ifconf
.ifc_len
; n
+= sizeof(struct ifreq
))
120 ifp
= if_get_by_name_len(ifreq
->ifr_name
,
121 strnlen(ifreq
->ifr_name
,
122 sizeof(ifreq
->ifr_name
)));
126 #endif /* OPEN_BSD */
130 XFREE (MTYPE_TMP
, ifconf
.ifc_buf
);
135 /* Get interface's index by ioctl. */
137 if_get_index (struct interface
*ifp
)
139 #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. */
146 static int if_fake_index
;
148 ifreq_set_name (&ifreq
, ifp
);
150 ret
= if_ioctl (SIOCGIFINDEX
, (caddr_t
) &ifreq
);
153 /* Linux 2.0.X does not have interface index. */
154 ifp
->ifindex
= if_fake_index
++;
158 /* OK we got interface index. */
160 ifp
->ifindex
= ifreq
.ifr_ifindex
;
162 ifp
->ifindex
= ifreq
.ifr_index
;
166 /* 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..."
172 /* This branch probably won't provide usable results, but anyway... */
173 static int if_fake_index
= 1;
174 ifp
->ifindex
= if_fake_index
++;
182 if_get_hwaddr (struct interface
*ifp
)
188 strncpy (ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
189 ifreq
.ifr_addr
.sa_family
= AF_INET
;
191 /* Fetch Hardware address if available. */
192 ret
= if_ioctl (SIOCGIFHWADDR
, (caddr_t
) &ifreq
);
194 ifp
->hw_addr_len
= 0;
197 memcpy (ifp
->hw_addr
, ifreq
.ifr_hwaddr
.sa_data
, 6);
199 for (i
= 0; i
< 6; i
++)
200 if (ifp
->hw_addr
[i
] != 0)
204 ifp
->hw_addr_len
= 0;
206 ifp
->hw_addr_len
= 6;
210 #endif /* SIOCGIFHWADDR */
212 #ifdef HAVE_GETIFADDRS
219 struct ifaddrs
*ifap
;
220 struct ifaddrs
*ifapfree
;
221 struct interface
*ifp
;
224 ret
= getifaddrs (&ifap
);
227 zlog_err ("getifaddrs(): %s", safe_strerror (errno
));
231 for (ifapfree
= ifap
; ifap
; ifap
= ifap
->ifa_next
)
233 if (ifap
->ifa_addr
== NULL
)
235 zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
236 __func__
, (ifap
->ifa_name
? ifap
->ifa_name
: "(null)"));
240 ifp
= if_lookup_by_name (ifap
->ifa_name
);
243 zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
248 if (ifap
->ifa_addr
->sa_family
== AF_INET
)
250 struct sockaddr_in
*addr
;
251 struct sockaddr_in
*mask
;
252 struct sockaddr_in
*dest
;
253 struct in_addr
*dest_pnt
;
256 addr
= (struct sockaddr_in
*) ifap
->ifa_addr
;
257 mask
= (struct sockaddr_in
*) ifap
->ifa_netmask
;
258 prefixlen
= ip_masklen (mask
->sin_addr
);
262 if (ifap
->ifa_dstaddr
&&
263 !IPV4_ADDR_SAME(&addr
->sin_addr
,
264 &((struct sockaddr_in
*)
265 ifap
->ifa_dstaddr
)->sin_addr
))
267 dest
= (struct sockaddr_in
*) ifap
->ifa_dstaddr
;
268 dest_pnt
= &dest
->sin_addr
;
269 flags
= ZEBRA_IFA_PEER
;
271 else if (ifap
->ifa_broadaddr
&&
272 !IPV4_ADDR_SAME(&addr
->sin_addr
,
273 &((struct sockaddr_in
*)
274 ifap
->ifa_broadaddr
)->sin_addr
))
276 dest
= (struct sockaddr_in
*) ifap
->ifa_broadaddr
;
277 dest_pnt
= &dest
->sin_addr
;
280 connected_add_ipv4 (ifp
, flags
, &addr
->sin_addr
,
281 prefixlen
, dest_pnt
, NULL
);
284 if (ifap
->ifa_addr
->sa_family
== AF_INET6
)
286 struct sockaddr_in6
*addr
;
287 struct sockaddr_in6
*mask
;
288 struct sockaddr_in6
*dest
;
289 struct in6_addr
*dest_pnt
;
292 addr
= (struct sockaddr_in6
*) ifap
->ifa_addr
;
293 mask
= (struct sockaddr_in6
*) ifap
->ifa_netmask
;
294 prefixlen
= ip6_masklen (mask
->sin6_addr
);
298 if (ifap
->ifa_dstaddr
&&
299 !IPV6_ADDR_SAME(&addr
->sin6_addr
,
300 &((struct sockaddr_in6
*)
301 ifap
->ifa_dstaddr
)->sin6_addr
))
303 dest
= (struct sockaddr_in6
*) ifap
->ifa_dstaddr
;
304 dest_pnt
= &dest
->sin6_addr
;
305 flags
= ZEBRA_IFA_PEER
;
307 else if (ifap
->ifa_broadaddr
&&
308 !IPV6_ADDR_SAME(&addr
->sin6_addr
,
309 &((struct sockaddr_in6
*)
310 ifap
->ifa_broadaddr
)->sin6_addr
))
312 dest
= (struct sockaddr_in6
*) ifap
->ifa_broadaddr
;
313 dest_pnt
= &dest
->sin6_addr
;
317 if (IN6_IS_ADDR_LINKLOCAL(&addr
->sin6_addr
))
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;
325 connected_add_ipv6 (ifp
, flags
, &addr
->sin6_addr
, prefixlen
,
328 #endif /* HAVE_IPV6 */
331 freeifaddrs (ifapfree
);
335 #else /* HAVE_GETIFADDRS */
336 /* Interface address lookup by ioctl. This function only looks up
339 if_get_addr (struct interface
*ifp
)
343 struct sockaddr_in addr
;
344 struct sockaddr_in mask
;
345 struct sockaddr_in dest
;
346 struct in_addr
*dest_pnt
;
350 /* Interface's name and address family. */
351 strncpy (ifreq
.ifr_name
, ifp
->name
, IFNAMSIZ
);
352 ifreq
.ifr_addr
.sa_family
= AF_INET
;
354 /* Interface's address. */
355 ret
= if_ioctl (SIOCGIFADDR
, (caddr_t
) &ifreq
);
358 if (errno
!= EADDRNOTAVAIL
)
360 zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno
));
365 memcpy (&addr
, &ifreq
.ifr_addr
, sizeof (struct sockaddr_in
));
367 /* Interface's network mask. */
368 ret
= if_ioctl (SIOCGIFNETMASK
, (caddr_t
) &ifreq
);
371 if (errno
!= EADDRNOTAVAIL
)
373 zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno
));
379 memcpy (&mask
, &ifreq
.ifr_netmask
, sizeof (struct sockaddr_in
));
381 memcpy (&mask
, &ifreq
.ifr_addr
, sizeof (struct sockaddr_in
));
382 #endif /* ifr_netmask */
383 prefixlen
= ip_masklen (mask
.sin_addr
);
385 /* Point to point or borad cast address pointer init. */
388 ret
= if_ioctl (SIOCGIFDSTADDR
, (caddr_t
) &ifreq
);
391 if (errno
!= EADDRNOTAVAIL
)
392 zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno
));
394 else if (!IPV4_ADDR_SAME(&addr
.sin_addr
, &ifreq
.ifr_dstaddr
.sin_addr
))
396 memcpy (&dest
, &ifreq
.ifr_dstaddr
, sizeof (struct sockaddr_in
));
397 dest_pnt
= &dest
.sin_addr
;
398 flags
= ZEBRA_IFA_PEER
;
402 ret
= if_ioctl (SIOCGIFBRDADDR
, (caddr_t
) &ifreq
);
405 if (errno
!= EADDRNOTAVAIL
)
406 zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno
));
408 else if (!IPV4_ADDR_SAME(&addr
.sin_addr
, &ifreq
.ifr_broadaddr
.sin_addr
))
410 memcpy (&dest
, &ifreq
.ifr_broadaddr
, sizeof (struct sockaddr_in
));
411 dest_pnt
= &dest
.sin_addr
;
416 /* Set address to the interface. */
417 connected_add_ipv4 (ifp
, flags
, &addr
.sin_addr
, prefixlen
, dest_pnt
, NULL
);
421 #endif /* HAVE_GETIFADDRS */
423 /* Fetch interface information via ioctl(). */
425 interface_info_ioctl ()
427 struct listnode
*node
, *nnode
;
428 struct interface
*ifp
;
430 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), node
, nnode
, ifp
))
435 #endif /* SIOCGIFHWADDR */
437 #ifndef HAVE_GETIFADDRS
439 #endif /* ! HAVE_GETIFADDRS */
445 /* Lookup all interface information. */
447 interface_list (struct zebra_ns
*zns
)
450 zlog_info ("interface_list: NS %u", zns
->ns_id
);
452 /* Linux can do both proc & ioctl, ioctl is the only way to get
453 interface aliases in 2.2 series kernels. */
454 #ifdef HAVE_PROC_NET_DEV
455 interface_list_proc ();
456 #endif /* HAVE_PROC_NET_DEV */
457 interface_list_ioctl ();
459 /* After listing is done, get index, address, flags and other
460 interface's information. */
461 interface_info_ioctl ();
463 #ifdef HAVE_GETIFADDRS
465 #endif /* HAVE_GETIFADDRS */
467 #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
468 /* Linux provides interface's IPv6 address via
469 /proc/net/if_inet6. */
471 #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */