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