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