]> git.proxmox.com Git - mirror_frr.git/blob - zebra/if_ioctl.c
zebra: add packet length into pbr support
[mirror_frr.git] / zebra / if_ioctl.c
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 *
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
20 */
21
22 #include <zebra.h>
23
24 #ifdef OPEN_BSD
25
26 #include "if.h"
27 #include "sockunion.h"
28 #include "prefix.h"
29 #include "ioctl.h"
30 #include "connected.h"
31 #include "memory.h"
32 #include "zebra_memory.h"
33 #include "log.h"
34 #include "vrf.h"
35 #include "vty.h"
36
37 #include "zebra/interface.h"
38 #include "zebra/rib.h"
39
40 #include <ifaddrs.h>
41
42 /* Interface looking up using infamous SIOCGIFCONF. */
43 static int interface_list_ioctl(void)
44 {
45 int ret;
46 int sock;
47 #define IFNUM_BASE 32
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. */
65 #ifdef SIOCGIFNUM
66 ret = ioctl(sock, SIOCGIFNUM, &ifnum);
67 if (ret < 0)
68 ifnum = IFNUM_BASE;
69 else
70 ifnum++;
71 #else
72 ifnum = IFNUM_BASE;
73 #endif /* SIOCGIFNUM */
74
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;
98 }
99
100 /* Allocate interface. */
101 ifreq = ifconf.ifc_req;
102
103 #ifdef OPEN_BSD
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(ifreq->ifr_name, VRF_DEFAULT, 0);
109 if_add_update(ifp);
110 size = ifreq->ifr_addr.sa_len;
111 if (size < sizeof(ifreq->ifr_addr))
112 size = sizeof(ifreq->ifr_addr);
113 size += sizeof(ifreq->ifr_name);
114 n += size;
115 }
116 #else
117 for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) {
118 ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT, 0);
119 if_add_update(ifp);
120 ifreq++;
121 }
122 #endif /* OPEN_BSD */
123
124 end:
125 close(sock);
126 XFREE(MTYPE_TMP, ifconf.ifc_buf);
127
128 return ret;
129 }
130
131 /* Get interface's index by ioctl. */
132 static int if_get_index(struct interface *ifp)
133 {
134 if_set_index(ifp, if_nametoindex(ifp->name));
135 return ifp->ifindex;
136 }
137
138 #ifdef SIOCGIFHWADDR
139 static int if_get_hwaddr(struct interface *ifp)
140 {
141 int ret;
142 struct ifreq ifreq;
143 int i;
144
145 strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ);
146 ifreq.ifr_addr.sa_family = AF_INET;
147
148 /* Fetch Hardware address if available. */
149 ret = vrf_if_ioctl(SIOCGIFHWADDR, (caddr_t)&ifreq, ifp->vrf_id);
150 if (ret < 0)
151 ifp->hw_addr_len = 0;
152 else {
153 memcpy(ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
154
155 for (i = 0; i < 6; i++)
156 if (ifp->hw_addr[i] != 0)
157 break;
158
159 if (i == 6)
160 ifp->hw_addr_len = 0;
161 else
162 ifp->hw_addr_len = 6;
163 }
164 return 0;
165 }
166 #endif /* SIOCGIFHWADDR */
167
168 static int if_getaddrs(void)
169 {
170 int ret;
171 struct ifaddrs *ifap;
172 struct ifaddrs *ifapfree;
173 struct interface *ifp;
174 int prefixlen;
175
176 ret = getifaddrs(&ifap);
177 if (ret != 0) {
178 zlog_err("getifaddrs(): %s", safe_strerror(errno));
179 return -1;
180 }
181
182 for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) {
183 if (ifap->ifa_addr == NULL) {
184 zlog_err(
185 "%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
186 __func__,
187 (ifap->ifa_name ? ifap->ifa_name : "(null)"));
188 continue;
189 }
190
191 ifp = if_lookup_by_name(ifap->ifa_name, VRF_DEFAULT);
192 if (ifp == NULL) {
193 zlog_err("if_getaddrs(): Can't lookup interface %s\n",
194 ifap->ifa_name);
195 continue;
196 }
197
198 if (ifap->ifa_addr->sa_family == AF_INET) {
199 struct sockaddr_in *addr;
200 struct sockaddr_in *mask;
201 struct sockaddr_in *dest;
202 struct in_addr *dest_pnt;
203 int flags = 0;
204
205 addr = (struct sockaddr_in *)ifap->ifa_addr;
206 mask = (struct sockaddr_in *)ifap->ifa_netmask;
207 prefixlen = ip_masklen(mask->sin_addr);
208
209 dest_pnt = NULL;
210
211 if (if_is_pointopoint(ifp) && ifap->ifa_dstaddr
212 && !IPV4_ADDR_SAME(&addr->sin_addr,
213 &((struct sockaddr_in *)
214 ifap->ifa_dstaddr)
215 ->sin_addr)) {
216 dest = (struct sockaddr_in *)ifap->ifa_dstaddr;
217 dest_pnt = &dest->sin_addr;
218 flags = ZEBRA_IFA_PEER;
219 } else if (ifap->ifa_broadaddr
220 && !IPV4_ADDR_SAME(
221 &addr->sin_addr,
222 &((struct sockaddr_in *)
223 ifap->ifa_broadaddr)
224 ->sin_addr)) {
225 dest = (struct sockaddr_in *)
226 ifap->ifa_broadaddr;
227 dest_pnt = &dest->sin_addr;
228 }
229
230 connected_add_ipv4(ifp, flags, &addr->sin_addr,
231 prefixlen, dest_pnt, NULL);
232 }
233 if (ifap->ifa_addr->sa_family == AF_INET6) {
234 struct sockaddr_in6 *addr;
235 struct sockaddr_in6 *mask;
236 int flags = 0;
237
238 addr = (struct sockaddr_in6 *)ifap->ifa_addr;
239 mask = (struct sockaddr_in6 *)ifap->ifa_netmask;
240 prefixlen = ip6_masklen(mask->sin6_addr);
241
242 #if defined(KAME)
243 if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
244 addr->sin6_scope_id =
245 ntohs(*(uint16_t *)&addr->sin6_addr
246 .s6_addr[2]);
247 addr->sin6_addr.s6_addr[2] =
248 addr->sin6_addr.s6_addr[3] = 0;
249 }
250 #endif
251
252 connected_add_ipv6(ifp, flags, &addr->sin6_addr, NULL,
253 prefixlen, NULL);
254 }
255 }
256
257 freeifaddrs(ifapfree);
258
259 return 0;
260 }
261
262 /* Fetch interface information via ioctl(). */
263 static void interface_info_ioctl()
264 {
265 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
266 struct interface *ifp;
267
268 FOR_ALL_INTERFACES (vrf, ifp) {
269 if_get_index(ifp);
270 #ifdef SIOCGIFHWADDR
271 if_get_hwaddr(ifp);
272 #endif /* SIOCGIFHWADDR */
273 if_get_flags(ifp);
274 if_get_mtu(ifp);
275 if_get_metric(ifp);
276 }
277 }
278
279 /* Lookup all interface information. */
280 void interface_list(struct zebra_ns *zns)
281 {
282
283 zlog_info("interface_list: NS %u", zns->ns_id);
284
285 /* Linux can do both proc & ioctl, ioctl is the only way to get
286 interface aliases in 2.2 series kernels. */
287 #ifdef HAVE_PROC_NET_DEV
288 interface_list_proc();
289 #endif /* HAVE_PROC_NET_DEV */
290 interface_list_ioctl();
291
292 /* After listing is done, get index, address, flags and other
293 interface's information. */
294 interface_info_ioctl();
295
296 if_getaddrs();
297
298 #if defined(HAVE_PROC_NET_IF_INET6)
299 /* Linux provides interface's IPv6 address via
300 /proc/net/if_inet6. */
301 ifaddr_proc_ipv6();
302 #endif /* HAVE_PROC_NET_IF_INET6 */
303 }
304
305 #endif /* OPEN_BSD */