]> git.proxmox.com Git - mirror_frr.git/blame - zebra/if_ioctl.c
build: convert zebra/ to non-recursive build
[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
24#include "if.h"
25#include "sockunion.h"
26#include "prefix.h"
27#include "ioctl.h"
28#include "connected.h"
29#include "memory.h"
4a1ab8e4 30#include "zebra_memory.h"
718e3744 31#include "log.h"
8f7d9fc0 32#include "vrf.h"
82283592 33#include "vty.h"
718e3744 34
35#include "zebra/interface.h"
8f7d9fc0 36#include "zebra/rib.h"
718e3744 37
24f5e2fc
DL
38#include <ifaddrs.h>
39
718e3744 40/* Interface looking up using infamous SIOCGIFCONF. */
d62a17ae 41static int interface_list_ioctl(void)
718e3744 42{
d62a17ae 43 int ret;
44 int sock;
718e3744 45#define IFNUM_BASE 32
d62a17ae 46 int ifnum;
47 struct ifreq *ifreq;
48 struct ifconf ifconf;
49 struct interface *ifp;
50 int n;
51 int lastlen;
52
53 /* Normally SIOCGIFCONF works with AF_INET socket. */
54 sock = socket(AF_INET, SOCK_DGRAM, 0);
55 if (sock < 0) {
56 zlog_warn("Can't make AF_INET socket stream: %s",
57 safe_strerror(errno));
58 return -1;
59 }
60
61/* Set initial ifreq count. This will be double when SIOCGIFCONF
62 fail. Solaris has SIOCGIFNUM. */
718e3744 63#ifdef SIOCGIFNUM
d62a17ae 64 ret = ioctl(sock, SIOCGIFNUM, &ifnum);
65 if (ret < 0)
66 ifnum = IFNUM_BASE;
67 else
68 ifnum++;
718e3744 69#else
d62a17ae 70 ifnum = IFNUM_BASE;
718e3744 71#endif /* SIOCGIFNUM */
72
d62a17ae 73 ifconf.ifc_buf = NULL;
74
75 lastlen = 0;
76 /* Loop until SIOCGIFCONF success. */
77 for (;;) {
78 ifconf.ifc_len = sizeof(struct ifreq) * ifnum;
79 ifconf.ifc_buf =
80 XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
81
82 ret = ioctl(sock, SIOCGIFCONF, &ifconf);
83
84 if (ret < 0) {
85 zlog_warn("SIOCGIFCONF: %s", safe_strerror(errno));
86 goto end;
87 }
88 /* Repeatedly get info til buffer fails to grow. */
89 if (ifconf.ifc_len > lastlen) {
90 lastlen = ifconf.ifc_len;
91 ifnum += 10;
92 continue;
93 }
94 /* Success. */
95 break;
718e3744 96 }
718e3744 97
d62a17ae 98 /* Allocate interface. */
99 ifreq = ifconf.ifc_req;
718e3744 100
101#ifdef OPEN_BSD
d62a17ae 102 for (n = 0; n < ifconf.ifc_len;) {
103 unsigned int size;
104
105 ifreq = (struct ifreq *)((caddr_t)ifconf.ifc_req + n);
106 ifp = if_get_by_name_len(
107 ifreq->ifr_name,
108 strnlen(ifreq->ifr_name, sizeof(ifreq->ifr_name)),
109 VRF_DEFAULT, 0);
110 if_add_update(ifp);
111 size = ifreq->ifr_addr.sa_len;
112 if (size < sizeof(ifreq->ifr_addr))
113 size = sizeof(ifreq->ifr_addr);
114 size += sizeof(ifreq->ifr_name);
115 n += size;
116 }
718e3744 117#else
d62a17ae 118 for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) {
119 ifp = if_get_by_name_len(
120 ifreq->ifr_name,
121 strnlen(ifreq->ifr_name, sizeof(ifreq->ifr_name)),
122 VRF_DEFAULT, 0);
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{
d62a17ae 138 ifp->ifindex = if_nametoindex(ifp->name);
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
149 strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ);
150 ifreq.ifr_addr.sa_family = AF_INET;
151
152 /* Fetch Hardware address if available. */
153 ret = if_ioctl(SIOCGIFHWADDR, (caddr_t)&ifreq);
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) {
182 zlog_err("getifaddrs(): %s", safe_strerror(errno));
183 return -1;
718e3744 184 }
185
d62a17ae 186 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) {
187 if (ifap->ifa_addr == NULL) {
188 zlog_err(
189 "%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
190 __func__,
191 (ifap->ifa_name ? ifap->ifa_name : "(null)"));
192 continue;
193 }
194
195 ifp = if_lookup_by_name(ifap->ifa_name, VRF_DEFAULT);
196 if (ifp == NULL) {
197 zlog_err("if_getaddrs(): Can't lookup interface %s\n",
198 ifap->ifa_name);
199 continue;
200 }
201
202 if (ifap->ifa_addr->sa_family == AF_INET) {
203 struct sockaddr_in *addr;
204 struct sockaddr_in *mask;
205 struct sockaddr_in *dest;
206 struct in_addr *dest_pnt;
207 int flags = 0;
208
209 addr = (struct sockaddr_in *)ifap->ifa_addr;
210 mask = (struct sockaddr_in *)ifap->ifa_netmask;
211 prefixlen = ip_masklen(mask->sin_addr);
212
213 dest_pnt = NULL;
214
215 if (ifap->ifa_dstaddr
216 && !IPV4_ADDR_SAME(&addr->sin_addr,
217 &((struct sockaddr_in *)
218 ifap->ifa_dstaddr)
219 ->sin_addr)) {
220 dest = (struct sockaddr_in *)ifap->ifa_dstaddr;
221 dest_pnt = &dest->sin_addr;
222 flags = ZEBRA_IFA_PEER;
223 } else if (ifap->ifa_broadaddr
224 && !IPV4_ADDR_SAME(
225 &addr->sin_addr,
226 &((struct sockaddr_in *)
227 ifap->ifa_broadaddr)
228 ->sin_addr)) {
229 dest = (struct sockaddr_in *)
230 ifap->ifa_broadaddr;
231 dest_pnt = &dest->sin_addr;
232 }
233
234 connected_add_ipv4(ifp, flags, &addr->sin_addr,
235 prefixlen, dest_pnt, NULL);
236 }
237 if (ifap->ifa_addr->sa_family == AF_INET6) {
238 struct sockaddr_in6 *addr;
239 struct sockaddr_in6 *mask;
240 struct sockaddr_in6 *dest;
241 struct in6_addr *dest_pnt;
242 int flags = 0;
243
244 addr = (struct sockaddr_in6 *)ifap->ifa_addr;
245 mask = (struct sockaddr_in6 *)ifap->ifa_netmask;
246 prefixlen = ip6_masklen(mask->sin6_addr);
247
248 dest_pnt = NULL;
249
250 if (ifap->ifa_dstaddr
251 && !IPV6_ADDR_SAME(&addr->sin6_addr,
252 &((struct sockaddr_in6 *)
253 ifap->ifa_dstaddr)
254 ->sin6_addr)) {
255 dest = (struct sockaddr_in6 *)ifap->ifa_dstaddr;
256 dest_pnt = &dest->sin6_addr;
257 flags = ZEBRA_IFA_PEER;
258 } else if (ifap->ifa_broadaddr
259 && !IPV6_ADDR_SAME(
260 &addr->sin6_addr,
261 &((struct sockaddr_in6 *)
262 ifap->ifa_broadaddr)
263 ->sin6_addr)) {
264 dest = (struct sockaddr_in6 *)
265 ifap->ifa_broadaddr;
266 dest_pnt = &dest->sin6_addr;
267 }
718e3744 268
ab836aab 269#if defined(KAME)
d62a17ae 270 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
271 addr->sin6_scope_id =
272 ntohs(*(u_int16_t *)&addr->sin6_addr
273 .s6_addr[2]);
274 addr->sin6_addr.s6_addr[2] =
275 addr->sin6_addr.s6_addr[3] = 0;
276 }
277#endif
278
279 connected_add_ipv6(ifp, flags, &addr->sin6_addr,
280 prefixlen, dest_pnt, NULL);
281 }
718e3744 282 }
718e3744 283
d62a17ae 284 freeifaddrs(ifapfree);
718e3744 285
d62a17ae 286 return 0;
718e3744 287}
718e3744 288
289/* Fetch interface information via ioctl(). */
d62a17ae 290static void interface_info_ioctl()
718e3744 291{
d62a17ae 292 struct listnode *node, *nnode;
293 struct interface *ifp;
294
295 for (ALL_LIST_ELEMENTS(vrf_iflist(VRF_DEFAULT), node, nnode, ifp)) {
296 if_get_index(ifp);
718e3744 297#ifdef SIOCGIFHWADDR
d62a17ae 298 if_get_hwaddr(ifp);
718e3744 299#endif /* SIOCGIFHWADDR */
d62a17ae 300 if_get_flags(ifp);
301 if_get_mtu(ifp);
302 if_get_metric(ifp);
303 }
718e3744 304}
305
306/* Lookup all interface information. */
d62a17ae 307void interface_list(struct zebra_ns *zns)
718e3744 308{
12f6fb97 309
d62a17ae 310 zlog_info("interface_list: NS %u", zns->ns_id);
12f6fb97 311
d62a17ae 312/* Linux can do both proc & ioctl, ioctl is the only way to get
313 interface aliases in 2.2 series kernels. */
718e3744 314#ifdef HAVE_PROC_NET_DEV
d62a17ae 315 interface_list_proc();
718e3744 316#endif /* HAVE_PROC_NET_DEV */
d62a17ae 317 interface_list_ioctl();
718e3744 318
d62a17ae 319 /* After listing is done, get index, address, flags and other
320 interface's information. */
321 interface_info_ioctl();
718e3744 322
d62a17ae 323 if_getaddrs();
718e3744 324
56c1f7d8 325#if defined(HAVE_PROC_NET_IF_INET6)
d62a17ae 326 /* Linux provides interface's IPv6 address via
327 /proc/net/if_inet6. */
328 ifaddr_proc_ipv6();
56c1f7d8 329#endif /* HAVE_PROC_NET_IF_INET6 */
718e3744 330}