]> git.proxmox.com Git - mirror_frr.git/blob - zebra/if_ioctl_solaris.c
zebra: print unknown rule family as number
[mirror_frr.git] / zebra / if_ioctl_solaris.c
1 /*
2 * Interface looking up by ioctl () on Solaris.
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 SUNOS_5
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 "privs.h"
35 #include "vrf.h"
36 #include "vty.h"
37 #include "lib_errors.h"
38
39 #include "zebra/interface.h"
40 #include "zebra/ioctl_solaris.h"
41 #include "zebra/rib.h"
42 #include "zebra/rt.h"
43 #include "zebra/zebra_errors.h"
44
45 static int if_get_addr(struct interface *, struct sockaddr *, const char *);
46 static void interface_info_ioctl(struct interface *);
47 extern struct zebra_privs_t zserv_privs;
48
49 static int interface_list_ioctl(int af)
50 {
51 int ret;
52 int sock;
53 #define IFNUM_BASE 32
54 struct lifnum lifn;
55 int ifnum;
56 struct lifreq *lifreq;
57 struct lifconf lifconf;
58 struct interface *ifp;
59 int n;
60 size_t needed, lastneeded = 0;
61 char *buf = NULL;
62
63 frr_with_privs(&zserv_privs) {
64 sock = socket(af, SOCK_DGRAM, 0);
65 }
66
67 if (sock < 0) {
68 flog_err_sys(EC_LIB_SOCKET, "Can't make %s socket stream: %s",
69 (af == AF_INET ? "AF_INET" : "AF_INET6"),
70 safe_strerror(errno));
71 return -1;
72 }
73
74 calculate_lifc_len:
75 frr_with_privs(&zserv_privs) {
76 lifn.lifn_family = af;
77 lifn.lifn_flags = LIFC_NOXMIT;
78 /* we want NOXMIT interfaces too */
79 ret = ioctl(sock, SIOCGLIFNUM, &lifn);
80 }
81
82 if (ret < 0) {
83 flog_err_sys(EC_LIB_SYSTEM_CALL,
84 "interface_list_ioctl: SIOCGLIFNUM failed %s",
85 safe_strerror(errno));
86 close(sock);
87 return -1;
88 }
89 ifnum = lifn.lifn_count;
90
91 /*
92 * When calculating the buffer size needed, add a small number
93 * of interfaces to those we counted. We do this to capture
94 * the interface status of potential interfaces which may have
95 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
96 */
97 needed = (ifnum + 4) * sizeof(struct lifreq);
98 if (needed > lastneeded || needed < lastneeded / 2) {
99 if (buf != NULL)
100 XFREE(MTYPE_TMP, buf);
101 buf = XMALLOC(MTYPE_TMP, needed);
102 }
103 lastneeded = needed;
104
105 lifconf.lifc_family = af;
106 lifconf.lifc_flags = LIFC_NOXMIT;
107 lifconf.lifc_len = needed;
108 lifconf.lifc_buf = buf;
109
110 frr_with_privs(&zserv_privs) {
111 ret = ioctl(sock, SIOCGLIFCONF, &lifconf);
112 }
113
114 if (ret < 0) {
115 if (errno == EINVAL)
116 goto calculate_lifc_len;
117
118 flog_err_sys(EC_LIB_SYSTEM_CALL, "SIOCGLIFCONF: %s",
119 safe_strerror(errno));
120 goto end;
121 }
122
123 /* Allocate interface. */
124 lifreq = lifconf.lifc_req;
125
126 for (n = 0; n < lifconf.lifc_len; n += sizeof(struct lifreq)) {
127 /* we treat Solaris logical interfaces as addresses, because
128 * that is
129 * how PF_ROUTE on Solaris treats them. Hence we can not
130 * directly use
131 * the lifreq_name to get the ifp. We need to normalise the
132 * name
133 * before attempting get.
134 *
135 * Solaris logical interface names are in the form of:
136 * <interface name>:<logical interface id>
137 */
138 unsigned int normallen = 0;
139 uint64_t lifflags;
140
141 /* We should exclude ~IFF_UP interfaces, as we'll find out about
142 * them
143 * coming up later through RTM_NEWADDR message on the route
144 * socket.
145 */
146 if (if_get_flags_direct(lifreq->lifr_name, &lifflags,
147 lifreq->lifr_addr.ss_family)
148 || !CHECK_FLAG(lifflags, IFF_UP)) {
149 lifreq++;
150 continue;
151 }
152
153 /* Find the normalised name */
154 while ((normallen < sizeof(lifreq->lifr_name))
155 && (*(lifreq->lifr_name + normallen) != '\0')
156 && (*(lifreq->lifr_name + normallen) != ':'))
157 normallen++;
158
159 ifp = if_get_by_name(lifreq->lifr_name, VRF_DEFAULT);
160
161 if (lifreq->lifr_addr.ss_family == AF_INET)
162 ifp->flags |= IFF_IPV4;
163
164 if (lifreq->lifr_addr.ss_family == AF_INET6) {
165 ifp->flags |= IFF_IPV6;
166 }
167
168 if_add_update(ifp);
169
170 interface_info_ioctl(ifp);
171
172 /* If a logical interface pass the full name so it can be
173 * as a label on the address
174 */
175 if (*(lifreq->lifr_name + normallen) != '\0')
176 if_get_addr(ifp, (struct sockaddr *)&lifreq->lifr_addr,
177 lifreq->lifr_name);
178 else
179 if_get_addr(ifp, (struct sockaddr *)&lifreq->lifr_addr,
180 NULL);
181
182 /* Poke the interface flags. Lets IFF_UP mangling kick in */
183 if_flags_update(ifp, ifp->flags);
184
185 lifreq++;
186 }
187
188 end:
189 close(sock);
190 XFREE(MTYPE_TMP, lifconf.lifc_buf);
191 return ret;
192 }
193
194 /* Get interface's index by ioctl. */
195 static int if_get_index(struct interface *ifp)
196 {
197 int ret;
198 struct lifreq lifreq;
199
200 lifreq_set_name(&lifreq, ifp->name);
201
202 if (ifp->flags & IFF_IPV4)
203 ret = AF_IOCTL(AF_INET, SIOCGLIFINDEX, (caddr_t)&lifreq);
204 else if (ifp->flags & IFF_IPV6)
205 ret = AF_IOCTL(AF_INET6, SIOCGLIFINDEX, (caddr_t)&lifreq);
206 else
207 ret = -1;
208
209 if (ret < 0) {
210 flog_err_sys(EC_LIB_SYSTEM_CALL, "SIOCGLIFINDEX(%s) failed",
211 ifp->name);
212 return ret;
213 }
214
215 /* OK we got interface index. */
216 #ifdef ifr_ifindex
217 if_set_index(ifp, lifreq.lifr_ifindex);
218 #else
219 if_set_index(ifp, lifreq.lifr_index);
220 #endif
221 return ifp->ifindex;
222 }
223
224
225 /* Interface address lookup by ioctl. This function only looks up
226 IPv4 address. */
227 #define ADDRLEN(sa) \
228 (((sa)->sa_family == AF_INET ? sizeof(struct sockaddr_in) \
229 : sizeof(struct sockaddr_in6)))
230
231 #define SIN(s) ((struct sockaddr_in *)(s))
232 #define SIN6(s) ((struct sockaddr_in6 *)(s))
233
234 /* Retrieve address information for the given ifp */
235 static int if_get_addr(struct interface *ifp, struct sockaddr *addr,
236 const char *label)
237 {
238 int ret;
239 struct lifreq lifreq;
240 struct sockaddr_storage mask, dest;
241 char *dest_pnt = NULL;
242 uint8_t prefixlen = 0;
243 afi_t af;
244 int flags = 0;
245
246 /* Interface's name and address family.
247 * We need to use the logical interface name / label, if we've been
248 * given one, in order to get the right address
249 */
250 strlcpy(lifreq.lifr_name, (label ? label : ifp->name),
251 sizeof(lifreq.lifr_name));
252
253 /* Interface's address. */
254 memcpy(&lifreq.lifr_addr, addr, ADDRLEN(addr));
255 af = addr->sa_family;
256
257 /* Point to point or broad cast address pointer init. */
258 dest_pnt = NULL;
259
260 if (AF_IOCTL(af, SIOCGLIFDSTADDR, (caddr_t)&lifreq) >= 0) {
261 memcpy(&dest, &lifreq.lifr_dstaddr, ADDRLEN(addr));
262 if (af == AF_INET)
263 dest_pnt = (char *)&(SIN(&dest)->sin_addr);
264 else
265 dest_pnt = (char *)&(SIN6(&dest)->sin6_addr);
266 flags = ZEBRA_IFA_PEER;
267 }
268
269 if (af == AF_INET) {
270 ret = if_ioctl(SIOCGLIFNETMASK, (caddr_t)&lifreq);
271
272 if (ret < 0) {
273 if (errno != EADDRNOTAVAIL) {
274 flog_err_sys(EC_LIB_SYSTEM_CALL,
275 "SIOCGLIFNETMASK (%s) fail: %s",
276 ifp->name, safe_strerror(errno));
277 return ret;
278 }
279 return 0;
280 }
281 memcpy(&mask, &lifreq.lifr_addr, ADDRLEN(addr));
282
283 prefixlen = ip_masklen(SIN(&mask)->sin_addr);
284 if (!dest_pnt
285 && (if_ioctl(SIOCGLIFBRDADDR, (caddr_t)&lifreq) >= 0)) {
286 memcpy(&dest, &lifreq.lifr_broadaddr,
287 sizeof(struct sockaddr_in));
288 dest_pnt = (char *)&SIN(&dest)->sin_addr;
289 }
290 } else if (af == AF_INET6) {
291 if (if_ioctl_ipv6(SIOCGLIFSUBNET, (caddr_t)&lifreq) < 0) {
292 if (ifp->flags & IFF_POINTOPOINT)
293 prefixlen = IPV6_MAX_BITLEN;
294 else
295 flog_err_sys(EC_LIB_SYSTEM_CALL,
296 "SIOCGLIFSUBNET (%s) fail: %s",
297 ifp->name, safe_strerror(errno));
298 } else {
299 prefixlen = lifreq.lifr_addrlen;
300 }
301 }
302
303 /* Set address to the interface. */
304 if (af == AF_INET)
305 connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen,
306 (struct in_addr *)dest_pnt, label,
307 METRIC_MAX);
308 else if (af == AF_INET6)
309 connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL,
310 prefixlen, label, METRIC_MAX);
311
312 return 0;
313 }
314
315 /* Fetch interface information via ioctl(). */
316 static void interface_info_ioctl(struct interface *ifp)
317 {
318 if_get_index(ifp);
319 if_get_flags(ifp);
320 if_get_mtu(ifp);
321 if_get_metric(ifp);
322 }
323
324 /* Lookup all interface information. */
325 void interface_list(struct zebra_ns *zns)
326 {
327 if (zns->ns_id != NS_DEFAULT) {
328 zlog_debug("interface_list: ignore NS %u", zns->ns_id);
329 return;
330 }
331 interface_list_ioctl(AF_INET);
332 interface_list_ioctl(AF_INET6);
333 interface_list_ioctl(AF_UNSPEC);
334 }
335
336 struct connected *if_lookup_linklocal(struct interface *ifp)
337 {
338 struct listnode *node;
339 struct connected *ifc;
340
341 if (ifp == NULL)
342 return NULL;
343
344 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
345 if ((ifc->address->family == AF_INET6)
346 && (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)))
347 return ifc;
348 }
349
350 return NULL;
351 }
352
353 #endif /* SUNOS_5 */