]>
git.proxmox.com Git - mirror_frr.git/blob - zebra/if_ioctl.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Interface looking up by ioctl ().
4 * Copyright (C) 1997, 98 Kunihiro Ishiguro
12 #include "sockunion.h"
15 #include "connected.h"
20 #include "lib_errors.h"
22 #include "zebra/interface.h"
23 #include "zebra/rib.h"
25 #include "zebra/zebra_errors.h"
29 /* Interface looking up using infamous SIOCGIFCONF. */
30 static int interface_list_ioctl(void)
38 struct interface
*ifp
;
42 /* Normally SIOCGIFCONF works with AF_INET socket. */
43 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
45 flog_err_sys(EC_LIB_SOCKET
,
46 "Can't make AF_INET socket stream: %s",
47 safe_strerror(errno
));
51 /* Set initial ifreq count. This will be double when SIOCGIFCONF
52 fail. Solaris has SIOCGIFNUM. */
54 ret
= ioctl(sock
, SIOCGIFNUM
, &ifnum
);
61 #endif /* SIOCGIFNUM */
63 ifconf
.ifc_buf
= NULL
;
66 /* Loop until SIOCGIFCONF success. */
68 ifconf
.ifc_len
= sizeof(struct ifreq
) * ifnum
;
70 XREALLOC(MTYPE_TMP
, ifconf
.ifc_buf
, ifconf
.ifc_len
);
72 ret
= ioctl(sock
, SIOCGIFCONF
, &ifconf
);
75 flog_err_sys(EC_LIB_SYSTEM_CALL
, "SIOCGIFCONF: %s",
76 safe_strerror(errno
));
79 /* Repeatedly get info til buffer fails to grow. */
80 if (ifconf
.ifc_len
> lastlen
) {
81 lastlen
= ifconf
.ifc_len
;
89 /* Allocate interface. */
90 ifreq
= ifconf
.ifc_req
;
93 for (n
= 0; n
< ifconf
.ifc_len
;) {
96 ifreq
= (struct ifreq
*)((caddr_t
)ifconf
.ifc_req
+ n
);
97 ifp
= if_get_by_name(ifreq
->ifr_name
, VRF_DEFAULT
,
100 size
= ifreq
->ifr_addr
.sa_len
;
101 if (size
< sizeof(ifreq
->ifr_addr
))
102 size
= sizeof(ifreq
->ifr_addr
);
103 size
+= sizeof(ifreq
->ifr_name
);
107 for (n
= 0; n
< ifconf
.ifc_len
; n
+= sizeof(struct ifreq
)) {
108 ifp
= if_get_by_name(ifreq
->ifr_name
, VRF_DEFAULT
,
113 #endif /* OPEN_BSD */
117 XFREE(MTYPE_TMP
, ifconf
.ifc_buf
);
122 /* Get interface's index by ioctl. */
123 static int if_get_index(struct interface
*ifp
)
125 if_set_index(ifp
, if_nametoindex(ifp
->name
));
130 static int if_get_hwaddr(struct interface
*ifp
)
136 strlcpy(ifreq
.ifr_name
, ifp
->name
, sizeof(ifreq
.ifr_name
));
137 ifreq
.ifr_addr
.sa_family
= AF_INET
;
139 /* Fetch Hardware address if available. */
140 ret
= vrf_if_ioctl(SIOCGIFHWADDR
, (caddr_t
)&ifreq
, ifp
->vrf
->vrf_id
);
142 ifp
->hw_addr_len
= 0;
144 memcpy(ifp
->hw_addr
, ifreq
.ifr_hwaddr
.sa_data
, 6);
146 for (i
= 0; i
< 6; i
++)
147 if (ifp
->hw_addr
[i
] != 0)
151 ifp
->hw_addr_len
= 0;
153 ifp
->hw_addr_len
= 6;
157 #endif /* SIOCGIFHWADDR */
159 static int if_getaddrs(void)
162 struct ifaddrs
*ifap
;
163 struct ifaddrs
*ifapfree
;
164 struct interface
*ifp
;
167 ret
= getifaddrs(&ifap
);
169 flog_err_sys(EC_LIB_SYSTEM_CALL
, "getifaddrs(): %s",
170 safe_strerror(errno
));
174 for (ifapfree
= ifap
; ifap
; ifap
= ifap
->ifa_next
) {
175 if (ifap
->ifa_addr
== NULL
) {
178 "%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
180 (ifap
->ifa_name
? ifap
->ifa_name
: "(null)"));
184 ifp
= if_lookup_by_name(ifap
->ifa_name
, VRF_DEFAULT
);
186 flog_err(EC_LIB_INTERFACE
,
187 "%s: Can't lookup interface %s", __func__
,
192 if (ifap
->ifa_addr
->sa_family
== AF_INET
) {
193 struct sockaddr_in
*addr
;
194 struct sockaddr_in
*mask
;
195 struct sockaddr_in
*dest
;
196 struct in_addr
*dest_pnt
;
199 addr
= (struct sockaddr_in
*)ifap
->ifa_addr
;
200 mask
= (struct sockaddr_in
*)ifap
->ifa_netmask
;
201 prefixlen
= ip_masklen(mask
->sin_addr
);
205 if (if_is_pointopoint(ifp
) && ifap
->ifa_dstaddr
206 && !IPV4_ADDR_SAME(&addr
->sin_addr
,
207 &((struct sockaddr_in
*)
210 dest
= (struct sockaddr_in
*)ifap
->ifa_dstaddr
;
211 dest_pnt
= &dest
->sin_addr
;
212 flags
= ZEBRA_IFA_PEER
;
213 } else if (ifap
->ifa_broadaddr
216 &((struct sockaddr_in
*)
219 dest
= (struct sockaddr_in
*)
221 dest_pnt
= &dest
->sin_addr
;
224 connected_add_ipv4(ifp
, flags
, &addr
->sin_addr
,
225 prefixlen
, dest_pnt
, NULL
,
228 if (ifap
->ifa_addr
->sa_family
== AF_INET6
) {
229 struct sockaddr_in6
*addr
;
230 struct sockaddr_in6
*mask
;
233 addr
= (struct sockaddr_in6
*)ifap
->ifa_addr
;
234 mask
= (struct sockaddr_in6
*)ifap
->ifa_netmask
;
235 prefixlen
= ip6_masklen(mask
->sin6_addr
);
238 if (IN6_IS_ADDR_LINKLOCAL(&addr
->sin6_addr
)) {
239 addr
->sin6_scope_id
=
240 ntohs(*(uint16_t *)&addr
->sin6_addr
242 addr
->sin6_addr
.s6_addr
[2] =
243 addr
->sin6_addr
.s6_addr
[3] = 0;
247 connected_add_ipv6(ifp
, flags
, &addr
->sin6_addr
, NULL
,
248 prefixlen
, NULL
, METRIC_MAX
);
252 freeifaddrs(ifapfree
);
257 /* Fetch interface information via ioctl(). */
258 static void interface_info_ioctl()
260 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
261 struct interface
*ifp
;
263 FOR_ALL_INTERFACES (vrf
, ifp
) {
267 #endif /* SIOCGIFHWADDR */
274 /* Lookup all interface information. */
275 void interface_list(struct zebra_ns
*zns
)
278 zlog_info("%s: NS %u", __func__
, zns
->ns_id
);
280 /* Linux can do both proc & ioctl, ioctl is the only way to get
281 interface aliases in 2.2 series kernels. */
282 #ifdef HAVE_PROC_NET_DEV
283 interface_list_proc();
284 #endif /* HAVE_PROC_NET_DEV */
285 interface_list_ioctl();
287 /* After listing is done, get index, address, flags and other
288 interface's information. */
289 interface_info_ioctl();
293 #if defined(HAVE_PROC_NET_IF_INET6)
294 /* Linux provides interface's IPv6 address via
295 /proc/net/if_inet6. */
297 #endif /* HAVE_PROC_NET_IF_INET6 */
300 #endif /* OPEN_BSD */