]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
718e3744 | 2 | /* |
3 | * Interface looking up by ioctl (). | |
4 | * Copyright (C) 1997, 98 Kunihiro Ishiguro | |
718e3744 | 5 | */ |
6 | ||
7 | #include <zebra.h> | |
8 | ||
ddfeb486 DL |
9 | #ifdef OPEN_BSD |
10 | ||
718e3744 | 11 | #include "if.h" |
12 | #include "sockunion.h" | |
13 | #include "prefix.h" | |
14 | #include "ioctl.h" | |
15 | #include "connected.h" | |
16 | #include "memory.h" | |
17 | #include "log.h" | |
8f7d9fc0 | 18 | #include "vrf.h" |
82283592 | 19 | #include "vty.h" |
43e52561 | 20 | #include "lib_errors.h" |
718e3744 | 21 | |
22 | #include "zebra/interface.h" | |
8f7d9fc0 | 23 | #include "zebra/rib.h" |
f7dae312 | 24 | #include "zebra/rt.h" |
364fed6b | 25 | #include "zebra/zebra_errors.h" |
718e3744 | 26 | |
24f5e2fc DL |
27 | #include <ifaddrs.h> |
28 | ||
718e3744 | 29 | /* Interface looking up using infamous SIOCGIFCONF. */ |
d62a17ae | 30 | static int interface_list_ioctl(void) |
718e3744 | 31 | { |
d62a17ae | 32 | int ret; |
33 | int sock; | |
718e3744 | 34 | #define IFNUM_BASE 32 |
d62a17ae | 35 | int ifnum; |
36 | struct ifreq *ifreq; | |
37 | struct ifconf ifconf; | |
38 | struct interface *ifp; | |
39 | int n; | |
40 | int lastlen; | |
41 | ||
42 | /* Normally SIOCGIFCONF works with AF_INET socket. */ | |
43 | sock = socket(AF_INET, SOCK_DGRAM, 0); | |
44 | if (sock < 0) { | |
450971aa | 45 | flog_err_sys(EC_LIB_SOCKET, |
9df414fe QY |
46 | "Can't make AF_INET socket stream: %s", |
47 | safe_strerror(errno)); | |
d62a17ae | 48 | return -1; |
49 | } | |
50 | ||
51 | /* Set initial ifreq count. This will be double when SIOCGIFCONF | |
52 | fail. Solaris has SIOCGIFNUM. */ | |
718e3744 | 53 | #ifdef SIOCGIFNUM |
d62a17ae | 54 | ret = ioctl(sock, SIOCGIFNUM, &ifnum); |
55 | if (ret < 0) | |
56 | ifnum = IFNUM_BASE; | |
57 | else | |
58 | ifnum++; | |
718e3744 | 59 | #else |
d62a17ae | 60 | ifnum = IFNUM_BASE; |
718e3744 | 61 | #endif /* SIOCGIFNUM */ |
62 | ||
d62a17ae | 63 | ifconf.ifc_buf = NULL; |
64 | ||
65 | lastlen = 0; | |
66 | /* Loop until SIOCGIFCONF success. */ | |
67 | for (;;) { | |
68 | ifconf.ifc_len = sizeof(struct ifreq) * ifnum; | |
69 | ifconf.ifc_buf = | |
70 | XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len); | |
71 | ||
72 | ret = ioctl(sock, SIOCGIFCONF, &ifconf); | |
73 | ||
74 | if (ret < 0) { | |
450971aa | 75 | flog_err_sys(EC_LIB_SYSTEM_CALL, "SIOCGIFCONF: %s", |
9df414fe | 76 | safe_strerror(errno)); |
d62a17ae | 77 | goto end; |
78 | } | |
79 | /* Repeatedly get info til buffer fails to grow. */ | |
80 | if (ifconf.ifc_len > lastlen) { | |
81 | lastlen = ifconf.ifc_len; | |
82 | ifnum += 10; | |
83 | continue; | |
84 | } | |
85 | /* Success. */ | |
86 | break; | |
718e3744 | 87 | } |
718e3744 | 88 | |
d62a17ae | 89 | /* Allocate interface. */ |
90 | ifreq = ifconf.ifc_req; | |
718e3744 | 91 | |
92 | #ifdef OPEN_BSD | |
d62a17ae | 93 | for (n = 0; n < ifconf.ifc_len;) { |
94 | unsigned int size; | |
95 | ||
96 | ifreq = (struct ifreq *)((caddr_t)ifconf.ifc_req + n); | |
f60a1188 IR |
97 | ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT, |
98 | VRF_DEFAULT_NAME); | |
d62a17ae | 99 | if_add_update(ifp); |
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); | |
104 | n += size; | |
105 | } | |
718e3744 | 106 | #else |
d62a17ae | 107 | for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) { |
f60a1188 IR |
108 | ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT, |
109 | VRF_DEFAULT_NAME); | |
d62a17ae | 110 | if_add_update(ifp); |
111 | ifreq++; | |
112 | } | |
718e3744 | 113 | #endif /* OPEN_BSD */ |
114 | ||
d62a17ae | 115 | end: |
116 | close(sock); | |
117 | XFREE(MTYPE_TMP, ifconf.ifc_buf); | |
718e3744 | 118 | |
d62a17ae | 119 | return ret; |
718e3744 | 120 | } |
121 | ||
122 | /* Get interface's index by ioctl. */ | |
d62a17ae | 123 | static int if_get_index(struct interface *ifp) |
718e3744 | 124 | { |
ff880b78 | 125 | if_set_index(ifp, if_nametoindex(ifp->name)); |
d62a17ae | 126 | return ifp->ifindex; |
718e3744 | 127 | } |
128 | ||
129 | #ifdef SIOCGIFHWADDR | |
d62a17ae | 130 | static int if_get_hwaddr(struct interface *ifp) |
718e3744 | 131 | { |
d62a17ae | 132 | int ret; |
133 | struct ifreq ifreq; | |
134 | int i; | |
135 | ||
138a4965 | 136 | strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name)); |
d62a17ae | 137 | ifreq.ifr_addr.sa_family = AF_INET; |
138 | ||
139 | /* Fetch Hardware address if available. */ | |
096f7609 | 140 | ret = vrf_if_ioctl(SIOCGIFHWADDR, (caddr_t)&ifreq, ifp->vrf->vrf_id); |
d62a17ae | 141 | if (ret < 0) |
142 | ifp->hw_addr_len = 0; | |
143 | else { | |
144 | memcpy(ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6); | |
145 | ||
146 | for (i = 0; i < 6; i++) | |
147 | if (ifp->hw_addr[i] != 0) | |
148 | break; | |
149 | ||
150 | if (i == 6) | |
151 | ifp->hw_addr_len = 0; | |
152 | else | |
153 | ifp->hw_addr_len = 6; | |
154 | } | |
155 | return 0; | |
718e3744 | 156 | } |
157 | #endif /* SIOCGIFHWADDR */ | |
158 | ||
d62a17ae | 159 | static int if_getaddrs(void) |
718e3744 | 160 | { |
d62a17ae | 161 | int ret; |
162 | struct ifaddrs *ifap; | |
163 | struct ifaddrs *ifapfree; | |
164 | struct interface *ifp; | |
165 | int prefixlen; | |
166 | ||
167 | ret = getifaddrs(&ifap); | |
168 | if (ret != 0) { | |
450971aa | 169 | flog_err_sys(EC_LIB_SYSTEM_CALL, "getifaddrs(): %s", |
09c866e3 | 170 | safe_strerror(errno)); |
d62a17ae | 171 | return -1; |
718e3744 | 172 | } |
173 | ||
d62a17ae | 174 | for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) { |
175 | if (ifap->ifa_addr == NULL) { | |
af4c2728 | 176 | flog_err( |
450971aa | 177 | EC_LIB_INTERFACE, |
d62a17ae | 178 | "%s: nonsensical ifaddr with NULL ifa_addr, ifname %s", |
179 | __func__, | |
180 | (ifap->ifa_name ? ifap->ifa_name : "(null)")); | |
181 | continue; | |
182 | } | |
183 | ||
a36898e7 | 184 | ifp = if_lookup_by_name(ifap->ifa_name, VRF_DEFAULT); |
d62a17ae | 185 | if (ifp == NULL) { |
450971aa | 186 | flog_err(EC_LIB_INTERFACE, |
6751c0f3 | 187 | "%s: Can't lookup interface %s", __func__, |
1c50c1c0 | 188 | ifap->ifa_name); |
d62a17ae | 189 | continue; |
190 | } | |
191 | ||
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; | |
197 | int flags = 0; | |
198 | ||
199 | addr = (struct sockaddr_in *)ifap->ifa_addr; | |
200 | mask = (struct sockaddr_in *)ifap->ifa_netmask; | |
201 | prefixlen = ip_masklen(mask->sin_addr); | |
202 | ||
203 | dest_pnt = NULL; | |
204 | ||
608105a7 | 205 | if (if_is_pointopoint(ifp) && ifap->ifa_dstaddr |
d62a17ae | 206 | && !IPV4_ADDR_SAME(&addr->sin_addr, |
207 | &((struct sockaddr_in *) | |
208 | ifap->ifa_dstaddr) | |
209 | ->sin_addr)) { | |
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 | |
214 | && !IPV4_ADDR_SAME( | |
215 | &addr->sin_addr, | |
216 | &((struct sockaddr_in *) | |
217 | ifap->ifa_broadaddr) | |
218 | ->sin_addr)) { | |
219 | dest = (struct sockaddr_in *) | |
220 | ifap->ifa_broadaddr; | |
221 | dest_pnt = &dest->sin_addr; | |
222 | } | |
223 | ||
224 | connected_add_ipv4(ifp, flags, &addr->sin_addr, | |
cde1af84 AK |
225 | prefixlen, dest_pnt, NULL, |
226 | METRIC_MAX); | |
d62a17ae | 227 | } |
228 | if (ifap->ifa_addr->sa_family == AF_INET6) { | |
229 | struct sockaddr_in6 *addr; | |
230 | struct sockaddr_in6 *mask; | |
d62a17ae | 231 | int flags = 0; |
232 | ||
233 | addr = (struct sockaddr_in6 *)ifap->ifa_addr; | |
234 | mask = (struct sockaddr_in6 *)ifap->ifa_netmask; | |
235 | prefixlen = ip6_masklen(mask->sin6_addr); | |
236 | ||
ab836aab | 237 | #if defined(KAME) |
d62a17ae | 238 | if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { |
239 | addr->sin6_scope_id = | |
d7c0a89a | 240 | ntohs(*(uint16_t *)&addr->sin6_addr |
d62a17ae | 241 | .s6_addr[2]); |
242 | addr->sin6_addr.s6_addr[2] = | |
243 | addr->sin6_addr.s6_addr[3] = 0; | |
244 | } | |
245 | #endif | |
246 | ||
60c0687a | 247 | connected_add_ipv6(ifp, flags, &addr->sin6_addr, NULL, |
cde1af84 | 248 | prefixlen, NULL, METRIC_MAX); |
d62a17ae | 249 | } |
718e3744 | 250 | } |
718e3744 | 251 | |
d62a17ae | 252 | freeifaddrs(ifapfree); |
718e3744 | 253 | |
d62a17ae | 254 | return 0; |
718e3744 | 255 | } |
718e3744 | 256 | |
257 | /* Fetch interface information via ioctl(). */ | |
d62a17ae | 258 | static void interface_info_ioctl() |
718e3744 | 259 | { |
f4e14fdb | 260 | struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); |
d62a17ae | 261 | struct interface *ifp; |
262 | ||
451fda4f | 263 | FOR_ALL_INTERFACES (vrf, ifp) { |
d62a17ae | 264 | if_get_index(ifp); |
718e3744 | 265 | #ifdef SIOCGIFHWADDR |
d62a17ae | 266 | if_get_hwaddr(ifp); |
718e3744 | 267 | #endif /* SIOCGIFHWADDR */ |
d62a17ae | 268 | if_get_flags(ifp); |
269 | if_get_mtu(ifp); | |
270 | if_get_metric(ifp); | |
271 | } | |
718e3744 | 272 | } |
273 | ||
274 | /* Lookup all interface information. */ | |
d62a17ae | 275 | void interface_list(struct zebra_ns *zns) |
718e3744 | 276 | { |
12f6fb97 | 277 | |
6751c0f3 | 278 | zlog_info("%s: NS %u", __func__, zns->ns_id); |
12f6fb97 | 279 | |
d62a17ae | 280 | /* Linux can do both proc & ioctl, ioctl is the only way to get |
281 | interface aliases in 2.2 series kernels. */ | |
718e3744 | 282 | #ifdef HAVE_PROC_NET_DEV |
d62a17ae | 283 | interface_list_proc(); |
718e3744 | 284 | #endif /* HAVE_PROC_NET_DEV */ |
d62a17ae | 285 | interface_list_ioctl(); |
718e3744 | 286 | |
d62a17ae | 287 | /* After listing is done, get index, address, flags and other |
288 | interface's information. */ | |
289 | interface_info_ioctl(); | |
718e3744 | 290 | |
d62a17ae | 291 | if_getaddrs(); |
718e3744 | 292 | |
56c1f7d8 | 293 | #if defined(HAVE_PROC_NET_IF_INET6) |
d62a17ae | 294 | /* Linux provides interface's IPv6 address via |
295 | /proc/net/if_inet6. */ | |
296 | ifaddr_proc_ipv6(); | |
56c1f7d8 | 297 | #endif /* HAVE_PROC_NET_IF_INET6 */ |
718e3744 | 298 | } |
ddfeb486 DL |
299 | |
300 | #endif /* OPEN_BSD */ |