]> git.proxmox.com Git - mirror_frr.git/blob - zebra/ioctl_solaris.c
zebra: print unknown rule family as number
[mirror_frr.git] / zebra / ioctl_solaris.c
1 /*
2 * Common ioctl functions for 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 "linklist.h"
27 #include "if.h"
28 #include "prefix.h"
29 #include "ioctl.h"
30 #include "log.h"
31 #include "privs.h"
32 #include "vty.h"
33 #include "vrf.h"
34 #include "lib_errors.h"
35
36 #include "zebra/rib.h"
37 #include "zebra/rt.h"
38 #include "zebra/interface.h"
39 #include "zebra/ioctl_solaris.h"
40 #include "zebra/zebra_errors.h"
41 #include "zebra/debug.h"
42
43 extern struct zebra_privs_t zserv_privs;
44
45 /* Prototypes */
46 static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx);
47 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx);
48 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
49 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
50
51 /* clear and set interface name string */
52 void lifreq_set_name(struct lifreq *lifreq, const char *ifname)
53 {
54 strlcpy(lifreq->lifr_name, ifname, sizeof(lifreq->lifr_name));
55 }
56
57 int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id)
58 {
59 return if_ioctl(request, buffer);
60 }
61
62 /* call ioctl system call */
63 int if_ioctl(unsigned long request, caddr_t buffer)
64 {
65 int sock;
66 int ret;
67 int err;
68
69 frr_with_privs(&zserv_privs) {
70
71 sock = socket(AF_INET, SOCK_DGRAM, 0);
72 if (sock < 0) {
73 zlog_err("Cannot create UDP socket: %s",
74 safe_strerror(errno));
75 exit(1);
76 }
77
78 if ((ret = ioctl(sock, request, buffer)) < 0)
79 err = errno;
80
81 }
82
83 close(sock);
84
85 if (ret < 0) {
86 errno = err;
87 return ret;
88 }
89 return 0;
90 }
91
92
93 int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
94 {
95 int sock;
96 int ret;
97 int err;
98
99 frr_with_privs(&zserv_privs) {
100
101 sock = socket(AF_INET6, SOCK_DGRAM, 0);
102 if (sock < 0) {
103 zlog_err("Cannot create IPv6 datagram socket: %s",
104 safe_strerror(errno));
105 exit(1);
106 }
107
108 if ((ret = ioctl(sock, request, buffer)) < 0)
109 err = errno;
110
111 }
112
113 close(sock);
114
115 if (ret < 0) {
116 errno = err;
117 return ret;
118 }
119
120 return 0;
121 }
122
123 /*
124 * get interface metric
125 * -- if value is not avaliable set -1
126 */
127 void if_get_metric(struct interface *ifp)
128 {
129 struct lifreq lifreq;
130 int ret;
131
132 lifreq_set_name(&lifreq, ifp->name);
133
134 if (ifp->flags & IFF_IPV4)
135 ret = AF_IOCTL(AF_INET, SIOCGLIFMETRIC, (caddr_t)&lifreq);
136 #ifdef SOLARIS_IPV6
137 else if (ifp->flags & IFF_IPV6)
138 ret = AF_IOCTL(AF_INET6, SIOCGLIFMETRIC, (caddr_t)&lifreq);
139 #endif /* SOLARIS_IPV6 */
140 else
141 ret = -1;
142
143 if (ret < 0)
144 return;
145
146 ifp->metric = lifreq.lifr_metric;
147
148 if (ifp->metric == 0)
149 ifp->metric = 1;
150 }
151
152 /* get interface MTU */
153 void if_get_mtu(struct interface *ifp)
154 {
155 struct lifreq lifreq;
156 int ret;
157 uint8_t changed = 0;
158
159 if (ifp->flags & IFF_IPV4) {
160 lifreq_set_name(&lifreq, ifp->name);
161 ret = AF_IOCTL(AF_INET, SIOCGLIFMTU, (caddr_t)&lifreq);
162 if (ret < 0) {
163 zlog_info(
164 "Can't lookup mtu on %s by ioctl(SIOCGLIFMTU)",
165 ifp->name);
166 ifp->mtu = -1;
167 } else {
168 ifp->mtu = lifreq.lifr_metric;
169 changed = 1;
170 }
171 }
172
173 if (ifp->flags & IFF_IPV6) {
174 memset(&lifreq, 0, sizeof(lifreq));
175 lifreq_set_name(&lifreq, ifp->name);
176
177 ret = AF_IOCTL(AF_INET6, SIOCGLIFMTU, (caddr_t)&lifreq);
178 if (ret < 0) {
179 zlog_info(
180 "Can't lookup mtu6 on %s by ioctl(SIOCGIFMTU)",
181 ifp->name);
182 ifp->mtu6 = -1;
183 } else {
184 ifp->mtu6 = lifreq.lifr_metric;
185 changed = 1;
186 }
187 }
188
189 if (changed)
190 zebra_interface_up_update(ifp);
191 }
192
193 /*
194 *
195 */
196 enum zebra_dplane_result kernel_address_update_ctx(
197 struct zebra_dplane_ctx *ctx)
198 {
199 int ret = -1;
200 const struct prefix *p;
201
202 p = dplane_ctx_get_intf_addr(ctx);
203
204 if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) {
205 if (p->family == AF_INET)
206 ret = if_set_prefix_ctx(ctx);
207 else
208 ret = if_set_prefix6_ctx(ctx);
209 } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_UNINSTALL) {
210 if (p->family == AF_INET)
211 ret = if_unset_prefix_ctx(ctx);
212 else
213 ret = if_unset_prefix6_ctx(ctx);
214 } else {
215 if (IS_ZEBRA_DEBUG_DPLANE)
216 zlog_debug("Invalid op in interface-addr install");
217 }
218
219 return (ret == 0 ?
220 ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
221 }
222
223 /* Set up interface's address, netmask (and broadcast? ).
224 Solaris uses ifname:number semantics to set IP address aliases. */
225 static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
226 {
227 int ret;
228 struct ifreq ifreq;
229 struct sockaddr_in addr, broad, mask;
230 struct prefix_ipv4 ifaddr;
231 struct prefix_ipv4 *p;
232
233 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
234
235 ifaddr = *p;
236
237 strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
238 sizeof(ifreq.ifr_name));
239
240 addr.sin_addr = p->prefix;
241 addr.sin_family = p->family;
242 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
243
244 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
245
246 if (ret < 0)
247 return ret;
248
249 /* We need mask for make broadcast addr. */
250 masklen2ip(p->prefixlen, &mask.sin_addr);
251
252 if (dplane_ctx_intf_is_broadcast(ctx)) {
253 apply_mask_ipv4(&ifaddr);
254 addr.sin_addr = ifaddr.prefix;
255
256 broad.sin_addr.s_addr =
257 (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
258 broad.sin_family = p->family;
259
260 memcpy(&ifreq.ifr_broadaddr, &broad,
261 sizeof(struct sockaddr_in));
262 ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq);
263 if (ret < 0)
264 return ret;
265 }
266
267 mask.sin_family = p->family;
268 #ifdef SUNOS_5
269 memcpy(&mask, &ifreq.ifr_addr, sizeof(mask));
270 #else
271 memcpy(&ifreq.ifr_netmask, &mask, sizeof(struct sockaddr_in));
272 #endif /* SUNOS_5 */
273 ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq);
274
275 return ((ret < 0) ? ret : 0);
276 }
277
278 /* Set up interface's address, netmask (and broadcast).
279 Solaris uses ifname:number semantics to set IP address aliases. */
280 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
281 {
282 int ret;
283 struct ifreq ifreq;
284 struct sockaddr_in addr;
285 struct prefix_ipv4 *p;
286
287 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
288
289 strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
290 sizeof(ifreq.ifr_name));
291
292 memset(&addr, 0, sizeof(struct sockaddr_in));
293 addr.sin_family = p->family;
294 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
295
296 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
297
298 if (ret < 0)
299 return ret;
300
301 return 0;
302 }
303
304 /* Get just the flags for the given name.
305 * Used by the normal 'if_get_flags' function, as well
306 * as the bootup interface-list code, which has to peek at per-address
307 * flags in order to figure out which ones should be ignored..
308 */
309 int if_get_flags_direct(const char *ifname, uint64_t *flags, unsigned int af)
310 {
311 struct lifreq lifreq;
312 int ret;
313
314 lifreq_set_name(&lifreq, ifname);
315
316 ret = AF_IOCTL(af, SIOCGLIFFLAGS, (caddr_t)&lifreq);
317
318 if (ret)
319 zlog_debug("%s: ifname %s, error %s (%d)", __func__, ifname,
320 safe_strerror(errno), errno);
321
322 *flags = lifreq.lifr_flags;
323
324 return ret;
325 }
326
327 /* get interface flags */
328 void if_get_flags(struct interface *ifp)
329 {
330 int ret4 = 0, ret6 = 0;
331 uint64_t newflags = 0;
332 uint64_t tmpflags;
333
334 if (ifp->flags & IFF_IPV4) {
335 ret4 = if_get_flags_direct(ifp->name, &tmpflags, AF_INET);
336
337 if (!ret4)
338 newflags |= tmpflags;
339 else if (errno == ENXIO) {
340 /* it's gone */
341 UNSET_FLAG(ifp->flags, IFF_UP);
342 if_flags_update(ifp, ifp->flags);
343 }
344 }
345
346 if (ifp->flags & IFF_IPV6) {
347 ret6 = if_get_flags_direct(ifp->name, &tmpflags, AF_INET6);
348
349 if (!ret6)
350 newflags |= tmpflags;
351 else if (errno == ENXIO) {
352 /* it's gone */
353 UNSET_FLAG(ifp->flags, IFF_UP);
354 if_flags_update(ifp, ifp->flags);
355 }
356 }
357
358 /* only update flags if one of above succeeded */
359 if (!(ret4 && ret6))
360 if_flags_update(ifp, newflags);
361 }
362
363 /* Set interface flags */
364 int if_set_flags(struct interface *ifp, uint64_t flags)
365 {
366 int ret;
367 struct lifreq lifreq;
368
369 lifreq_set_name(&lifreq, ifp->name);
370
371 lifreq.lifr_flags = ifp->flags;
372 lifreq.lifr_flags |= flags;
373
374 if (ifp->flags & IFF_IPV4)
375 ret = AF_IOCTL(AF_INET, SIOCSLIFFLAGS, (caddr_t)&lifreq);
376 else if (ifp->flags & IFF_IPV6)
377 ret = AF_IOCTL(AF_INET6, SIOCSLIFFLAGS, (caddr_t)&lifreq);
378 else
379 ret = -1;
380
381 if (ret < 0)
382 zlog_info("can't set interface flags on %s: %s", ifp->name,
383 safe_strerror(errno));
384 else
385 ret = 0;
386
387 return ret;
388 }
389
390 /* Unset interface's flag. */
391 int if_unset_flags(struct interface *ifp, uint64_t flags)
392 {
393 int ret;
394 struct lifreq lifreq;
395
396 lifreq_set_name(&lifreq, ifp->name);
397
398 lifreq.lifr_flags = ifp->flags;
399 lifreq.lifr_flags &= ~flags;
400
401 if (ifp->flags & IFF_IPV4)
402 ret = AF_IOCTL(AF_INET, SIOCSLIFFLAGS, (caddr_t)&lifreq);
403 else if (ifp->flags & IFF_IPV6)
404 ret = AF_IOCTL(AF_INET6, SIOCSLIFFLAGS, (caddr_t)&lifreq);
405 else
406 ret = -1;
407
408 if (ret < 0)
409 zlog_info("can't unset interface flags");
410 else
411 ret = 0;
412
413 return ret;
414 }
415
416 /* Interface's address add/delete functions. */
417 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
418 {
419 char addrbuf[PREFIX_STRLEN];
420
421 prefix2str(dplane_ctx_get_intf_addr(ctx), addrbuf, sizeof(addrbuf));
422
423 flog_warn(EC_LIB_DEVELOPMENT, "Can't set %s on interface %s",
424 addrbuf, dplane_ctx_get_ifname(ctx));
425
426 return 0;
427 }
428
429 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
430 {
431 char addrbuf[PREFIX_STRLEN];
432
433 prefix2str(dplane_ctx_get_intf_addr(ctx), addrbuf, sizeof(addrbuf));
434
435 flog_warn(EC_LIB_DEVELOPMENT, "Can't delete %s on interface %s",
436 addrbuf, dplane_ctx_get_ifname(ctx));
437
438 return 0;
439 }
440
441 #endif /* SUNOS_5 */