]> git.proxmox.com Git - mirror_frr.git/blame - zebra/if_ioctl.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / zebra / if_ioctl.c
CommitLineData
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 30static 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 115end:
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 123static 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 130static 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 159static 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 258static 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 275void 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 */