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