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