]> git.proxmox.com Git - mirror_frr.git/blob - zebra/if_ioctl.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / zebra / if_ioctl.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Interface looking up by ioctl ().
4 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 */
6
7 #include <zebra.h>
8
9 #ifdef OPEN_BSD
10
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"
18 #include "vrf.h"
19 #include "vty.h"
20 #include "lib_errors.h"
21
22 #include "zebra/interface.h"
23 #include "zebra/rib.h"
24 #include "zebra/rt.h"
25 #include "zebra/zebra_errors.h"
26
27 #include <ifaddrs.h>
28
29 /* Interface looking up using infamous SIOCGIFCONF. */
30 static int interface_list_ioctl(void)
31 {
32 int ret;
33 int sock;
34 #define IFNUM_BASE 32
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) {
45 flog_err_sys(EC_LIB_SOCKET,
46 "Can't make AF_INET socket stream: %s",
47 safe_strerror(errno));
48 return -1;
49 }
50
51 /* Set initial ifreq count. This will be double when SIOCGIFCONF
52 fail. Solaris has SIOCGIFNUM. */
53 #ifdef SIOCGIFNUM
54 ret = ioctl(sock, SIOCGIFNUM, &ifnum);
55 if (ret < 0)
56 ifnum = IFNUM_BASE;
57 else
58 ifnum++;
59 #else
60 ifnum = IFNUM_BASE;
61 #endif /* SIOCGIFNUM */
62
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) {
75 flog_err_sys(EC_LIB_SYSTEM_CALL, "SIOCGIFCONF: %s",
76 safe_strerror(errno));
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;
87 }
88
89 /* Allocate interface. */
90 ifreq = ifconf.ifc_req;
91
92 #ifdef OPEN_BSD
93 for (n = 0; n < ifconf.ifc_len;) {
94 unsigned int size;
95
96 ifreq = (struct ifreq *)((caddr_t)ifconf.ifc_req + n);
97 ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT,
98 VRF_DEFAULT_NAME);
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 }
106 #else
107 for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) {
108 ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT,
109 VRF_DEFAULT_NAME);
110 if_add_update(ifp);
111 ifreq++;
112 }
113 #endif /* OPEN_BSD */
114
115 end:
116 close(sock);
117 XFREE(MTYPE_TMP, ifconf.ifc_buf);
118
119 return ret;
120 }
121
122 /* Get interface's index by ioctl. */
123 static int if_get_index(struct interface *ifp)
124 {
125 if_set_index(ifp, if_nametoindex(ifp->name));
126 return ifp->ifindex;
127 }
128
129 #ifdef SIOCGIFHWADDR
130 static int if_get_hwaddr(struct interface *ifp)
131 {
132 int ret;
133 struct ifreq ifreq;
134 int i;
135
136 strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name));
137 ifreq.ifr_addr.sa_family = AF_INET;
138
139 /* Fetch Hardware address if available. */
140 ret = vrf_if_ioctl(SIOCGIFHWADDR, (caddr_t)&ifreq, ifp->vrf->vrf_id);
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;
156 }
157 #endif /* SIOCGIFHWADDR */
158
159 static int if_getaddrs(void)
160 {
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) {
169 flog_err_sys(EC_LIB_SYSTEM_CALL, "getifaddrs(): %s",
170 safe_strerror(errno));
171 return -1;
172 }
173
174 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) {
175 if (ifap->ifa_addr == NULL) {
176 flog_err(
177 EC_LIB_INTERFACE,
178 "%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
179 __func__,
180 (ifap->ifa_name ? ifap->ifa_name : "(null)"));
181 continue;
182 }
183
184 ifp = if_lookup_by_name(ifap->ifa_name, VRF_DEFAULT);
185 if (ifp == NULL) {
186 flog_err(EC_LIB_INTERFACE,
187 "%s: Can't lookup interface %s", __func__,
188 ifap->ifa_name);
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
205 if (if_is_pointopoint(ifp) && ifap->ifa_dstaddr
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,
225 prefixlen, dest_pnt, NULL,
226 METRIC_MAX);
227 }
228 if (ifap->ifa_addr->sa_family == AF_INET6) {
229 struct sockaddr_in6 *addr;
230 struct sockaddr_in6 *mask;
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
237 #if defined(KAME)
238 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
239 addr->sin6_scope_id =
240 ntohs(*(uint16_t *)&addr->sin6_addr
241 .s6_addr[2]);
242 addr->sin6_addr.s6_addr[2] =
243 addr->sin6_addr.s6_addr[3] = 0;
244 }
245 #endif
246
247 connected_add_ipv6(ifp, flags, &addr->sin6_addr, NULL,
248 prefixlen, NULL, METRIC_MAX);
249 }
250 }
251
252 freeifaddrs(ifapfree);
253
254 return 0;
255 }
256
257 /* Fetch interface information via ioctl(). */
258 static void interface_info_ioctl()
259 {
260 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
261 struct interface *ifp;
262
263 FOR_ALL_INTERFACES (vrf, ifp) {
264 if_get_index(ifp);
265 #ifdef SIOCGIFHWADDR
266 if_get_hwaddr(ifp);
267 #endif /* SIOCGIFHWADDR */
268 if_get_flags(ifp);
269 if_get_mtu(ifp);
270 if_get_metric(ifp);
271 }
272 }
273
274 /* Lookup all interface information. */
275 void interface_list(struct zebra_ns *zns)
276 {
277
278 zlog_info("%s: NS %u", __func__, zns->ns_id);
279
280 /* Linux can do both proc & ioctl, ioctl is the only way to get
281 interface aliases in 2.2 series kernels. */
282 #ifdef HAVE_PROC_NET_DEV
283 interface_list_proc();
284 #endif /* HAVE_PROC_NET_DEV */
285 interface_list_ioctl();
286
287 /* After listing is done, get index, address, flags and other
288 interface's information. */
289 interface_info_ioctl();
290
291 if_getaddrs();
292
293 #if defined(HAVE_PROC_NET_IF_INET6)
294 /* Linux provides interface's IPv6 address via
295 /proc/net/if_inet6. */
296 ifaddr_proc_ipv6();
297 #endif /* HAVE_PROC_NET_IF_INET6 */
298 }
299
300 #endif /* OPEN_BSD */