]> git.proxmox.com Git - mirror_frr.git/blob - zebra/ioctl.c
*: change interface structure, from vrf_id to vrf
[mirror_frr.git] / zebra / ioctl.c
1 /*
2 * Common ioctl functions.
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 #include "linklist.h"
25 #include "if.h"
26 #include "prefix.h"
27 #include "ioctl.h"
28 #include "log.h"
29 #include "privs.h"
30 #include "lib_errors.h"
31
32 #include "vty.h"
33 #include "zebra/rib.h"
34 #include "zebra/rt.h"
35 #include "zebra/interface.h"
36 #include "zebra/zebra_errors.h"
37 #include "zebra/debug.h"
38
39 #ifndef SUNOS_5
40
41 #ifdef HAVE_BSD_LINK_DETECT
42 #include <net/if_media.h>
43 #endif /* HAVE_BSD_LINK_DETECT*/
44
45 extern struct zebra_privs_t zserv_privs;
46
47 /* clear and set interface name string */
48 void ifreq_set_name(struct ifreq *ifreq, struct interface *ifp)
49 {
50 strlcpy(ifreq->ifr_name, ifp->name, sizeof(ifreq->ifr_name));
51 }
52
53 /* call ioctl system call */
54 int if_ioctl(unsigned long request, caddr_t buffer)
55 {
56 int sock;
57 int ret;
58 int err = 0;
59
60 frr_elevate_privs(&zserv_privs) {
61 sock = socket(AF_INET, SOCK_DGRAM, 0);
62 if (sock < 0) {
63 zlog_err("Cannot create UDP socket: %s",
64 safe_strerror(errno));
65 exit(1);
66 }
67 if ((ret = ioctl(sock, request, buffer)) < 0)
68 err = errno;
69 }
70 close(sock);
71
72 if (ret < 0) {
73 errno = err;
74 return ret;
75 }
76 return 0;
77 }
78
79 /* call ioctl system call */
80 int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id)
81 {
82 int sock;
83 int ret;
84 int err = 0;
85
86 frr_elevate_privs(&zserv_privs) {
87 sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
88 if (sock < 0) {
89 zlog_err("Cannot create UDP socket: %s",
90 safe_strerror(errno));
91 exit(1);
92 }
93 ret = vrf_ioctl(vrf_id, sock, request, buffer);
94 if (ret < 0)
95 err = errno;
96 }
97 close(sock);
98
99 if (ret < 0) {
100 errno = err;
101 return ret;
102 }
103 return 0;
104 }
105
106 #ifndef HAVE_NETLINK
107 static int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
108 {
109 int sock;
110 int ret;
111 int err = 0;
112
113 frr_elevate_privs(&zserv_privs) {
114 sock = socket(AF_INET6, SOCK_DGRAM, 0);
115 if (sock < 0) {
116 zlog_err("Cannot create IPv6 datagram socket: %s",
117 safe_strerror(errno));
118 exit(1);
119 }
120
121 if ((ret = ioctl(sock, request, buffer)) < 0)
122 err = errno;
123 }
124 close(sock);
125
126 if (ret < 0) {
127 errno = err;
128 return ret;
129 }
130 return 0;
131 }
132 #endif /* ! HAVE_NETLINK */
133
134 /*
135 * get interface metric
136 * -- if value is not avaliable set -1
137 */
138 void if_get_metric(struct interface *ifp)
139 {
140 #ifdef SIOCGIFMETRIC
141 struct ifreq ifreq;
142
143 ifreq_set_name(&ifreq, ifp);
144
145 if (vrf_if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq,
146 vrf_to_id(ifp->vrf)) < 0)
147 return;
148 ifp->metric = ifreq.ifr_metric;
149 if (ifp->metric == 0)
150 ifp->metric = 1;
151 #else /* SIOCGIFMETRIC */
152 ifp->metric = -1;
153 #endif /* SIOCGIFMETRIC */
154 }
155
156 /* get interface MTU */
157 void if_get_mtu(struct interface *ifp)
158 {
159 struct ifreq ifreq;
160
161 ifreq_set_name(&ifreq, ifp);
162
163 #if defined(SIOCGIFMTU)
164 if (vrf_if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq,
165 vrf_to_id(ifp->vrf)) < 0) {
166 zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)");
167 ifp->mtu6 = ifp->mtu = -1;
168 return;
169 }
170
171 #ifdef SUNOS_5
172 ifp->mtu6 = ifp->mtu = ifreq.ifr_metric;
173 #else
174 ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu;
175 #endif /* SUNOS_5 */
176
177 /* propogate */
178 zebra_interface_up_update(ifp);
179
180 #else
181 zlog_info("Can't lookup mtu on this system");
182 ifp->mtu6 = ifp->mtu = -1;
183 #endif
184 }
185
186 /*
187 * Handler for interface address programming via the zebra dplane,
188 * for non-netlink platforms. This handler dispatches to per-platform
189 * helpers, based on the operation requested.
190 */
191 #ifndef HAVE_NETLINK
192
193 /* Prototypes: these are placed in this block so that they're only seen
194 * on non-netlink platforms.
195 */
196 static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx);
197 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx);
198 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
199 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
200
201 enum zebra_dplane_result kernel_address_update_ctx(
202 struct zebra_dplane_ctx *ctx)
203 {
204 int ret = -1;
205 const struct prefix *p;
206
207 p = dplane_ctx_get_intf_addr(ctx);
208
209 if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) {
210 if (p->family == AF_INET)
211 ret = if_set_prefix_ctx(ctx);
212 else
213 ret = if_set_prefix6_ctx(ctx);
214 } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_UNINSTALL) {
215 if (p->family == AF_INET)
216 ret = if_unset_prefix_ctx(ctx);
217 else
218 ret = if_unset_prefix6_ctx(ctx);
219 } else {
220 if (IS_ZEBRA_DEBUG_DPLANE)
221 zlog_debug("Invalid op in interface-addr install");
222 }
223
224 return (ret == 0 ?
225 ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
226 }
227
228 #endif /* !HAVE_NETLINK */
229
230 #ifdef HAVE_NETLINK
231
232 /* TODO -- remove; no use of these apis with netlink any longer */
233
234 #else /* ! HAVE_NETLINK */
235 #ifdef HAVE_STRUCT_IFALIASREQ
236
237 /*
238 * Helper for interface-addr install, non-netlink
239 */
240 static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
241 {
242 int ret;
243 struct ifaliasreq addreq;
244 struct sockaddr_in addr, mask, peer;
245 struct prefix_ipv4 *p;
246
247 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
248
249 memset(&addreq, 0, sizeof(addreq));
250 strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
251 sizeof(addreq.ifra_name));
252
253 memset(&addr, 0, sizeof(struct sockaddr_in));
254 addr.sin_addr = p->prefix;
255 addr.sin_family = p->family;
256 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
257 addr.sin_len = sizeof(struct sockaddr_in);
258 #endif
259 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
260
261 if (dplane_ctx_intf_is_connected(ctx)) {
262 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx);
263 memset(&mask, 0, sizeof(struct sockaddr_in));
264 peer.sin_addr = p->prefix;
265 peer.sin_family = p->family;
266 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
267 peer.sin_len = sizeof(struct sockaddr_in);
268 #endif
269 memcpy(&addreq.ifra_broadaddr, &peer,
270 sizeof(struct sockaddr_in));
271 }
272
273 memset(&mask, 0, sizeof(struct sockaddr_in));
274 masklen2ip(p->prefixlen, &mask.sin_addr);
275 mask.sin_family = p->family;
276 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
277 mask.sin_len = sizeof(struct sockaddr_in);
278 #endif
279 memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in));
280
281 ret = if_ioctl(SIOCAIFADDR, (caddr_t)&addreq);
282 if (ret < 0)
283 return ret;
284 return 0;
285
286 }
287
288 /*
289 * Helper for interface-addr un-install, non-netlink
290 */
291 static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
292 {
293 int ret;
294 struct ifaliasreq addreq;
295 struct sockaddr_in addr, mask, peer;
296 struct prefix_ipv4 *p;
297
298 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
299
300 memset(&addreq, 0, sizeof(addreq));
301 strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
302 sizeof(addreq.ifra_name));
303
304 memset(&addr, 0, sizeof(struct sockaddr_in));
305 addr.sin_addr = p->prefix;
306 addr.sin_family = p->family;
307 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
308 addr.sin_len = sizeof(struct sockaddr_in);
309 #endif
310 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
311
312 if (dplane_ctx_intf_is_connected(ctx)) {
313 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx);
314 memset(&mask, 0, sizeof(struct sockaddr_in));
315 peer.sin_addr = p->prefix;
316 peer.sin_family = p->family;
317 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
318 peer.sin_len = sizeof(struct sockaddr_in);
319 #endif
320 memcpy(&addreq.ifra_broadaddr, &peer,
321 sizeof(struct sockaddr_in));
322 }
323
324 memset(&mask, 0, sizeof(struct sockaddr_in));
325 masklen2ip(p->prefixlen, &mask.sin_addr);
326 mask.sin_family = p->family;
327 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
328 mask.sin_len = sizeof(struct sockaddr_in);
329 #endif
330 memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in));
331
332 ret = if_ioctl(SIOCDIFADDR, (caddr_t)&addreq);
333 if (ret < 0)
334 return ret;
335 return 0;
336 }
337 #else
338 /* Set up interface's address, netmask (and broadcas? ). Linux or
339 Solaris uses ifname:number semantics to set IP address aliases. */
340 int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
341 {
342 int ret;
343 struct ifreq ifreq;
344 struct sockaddr_in addr;
345 struct sockaddr_in broad;
346 struct sockaddr_in mask;
347 struct prefix_ipv4 ifaddr;
348 struct prefix_ipv4 *p;
349
350 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
351
352 ifaddr = *p;
353
354 strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
355 sizeof(ifreq.ifr_name));
356
357 addr.sin_addr = p->prefix;
358 addr.sin_family = p->family;
359 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
360 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
361 if (ret < 0)
362 return ret;
363
364 /* We need mask for make broadcast addr. */
365 masklen2ip(p->prefixlen, &mask.sin_addr);
366
367 if (dplane_ctx_intf_is_broadcast(ctx)) {
368 apply_mask_ipv4(&ifaddr);
369 addr.sin_addr = ifaddr.prefix;
370
371 broad.sin_addr.s_addr =
372 (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
373 broad.sin_family = p->family;
374
375 memcpy(&ifreq.ifr_broadaddr, &broad,
376 sizeof(struct sockaddr_in));
377 ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq);
378 if (ret < 0)
379 return ret;
380 }
381
382 mask.sin_family = p->family;
383 #ifdef SUNOS_5
384 memcpy(&mask, &ifreq.ifr_addr, sizeof(mask));
385 #else
386 memcpy(&ifreq.ifr_addr, &mask, sizeof(struct sockaddr_in));
387 #endif /* SUNOS5 */
388 ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq);
389 if (ret < 0)
390 return ret;
391
392 return 0;
393 }
394
395 /* Set up interface's address, netmask (and broadcas? ). Linux or
396 Solaris uses ifname:number semantics to set IP address aliases. */
397 int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
398 {
399 int ret;
400 struct ifreq ifreq;
401 struct sockaddr_in addr;
402 struct prefix_ipv4 *p;
403
404 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
405
406 strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
407 sizeof(ifreq.ifr_name));
408
409 memset(&addr, 0, sizeof(struct sockaddr_in));
410 addr.sin_family = p->family;
411 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
412 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
413 if (ret < 0)
414 return ret;
415
416 return 0;
417 }
418 #endif /* HAVE_STRUCT_IFALIASREQ */
419 #endif /* HAVE_NETLINK */
420
421 /* get interface flags */
422 void if_get_flags(struct interface *ifp)
423 {
424 int ret;
425 struct ifreq ifreq;
426 #ifdef HAVE_BSD_LINK_DETECT
427 struct ifmediareq ifmr;
428 #endif /* HAVE_BSD_LINK_DETECT */
429
430 ifreq_set_name(&ifreq, ifp);
431
432 ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq, vrf_to_id(ifp->vrf));
433 if (ret < 0) {
434 flog_err_sys(EC_LIB_SYSTEM_CALL,
435 "vrf_if_ioctl(SIOCGIFFLAGS) failed: %s",
436 safe_strerror(errno));
437 return;
438 }
439 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
440
441 /* Per-default, IFF_RUNNING is held high, unless link-detect says
442 * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
443 * following practice on Linux and Solaris kernels
444 */
445 SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
446
447 if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) {
448 (void)memset(&ifmr, 0, sizeof(ifmr));
449 strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name));
450
451 /* Seems not all interfaces implement this ioctl */
452 if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1 &&
453 errno != EINVAL)
454 flog_err_sys(EC_LIB_SYSTEM_CALL,
455 "if_ioctl(SIOCGIFMEDIA) failed: %s",
456 safe_strerror(errno));
457 else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */
458 {
459 if (ifmr.ifm_status & IFM_ACTIVE)
460 SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
461 else
462 UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
463 }
464 }
465 #endif /* HAVE_BSD_LINK_DETECT */
466
467 if_flags_update(ifp, (ifreq.ifr_flags & 0x0000ffff));
468 }
469
470 /* Set interface flags */
471 int if_set_flags(struct interface *ifp, uint64_t flags)
472 {
473 int ret;
474 struct ifreq ifreq;
475
476 memset(&ifreq, 0, sizeof(struct ifreq));
477 ifreq_set_name(&ifreq, ifp);
478
479 ifreq.ifr_flags = ifp->flags;
480 ifreq.ifr_flags |= flags;
481
482 ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, vrf_to_id(ifp->vrf));
483
484 if (ret < 0) {
485 zlog_info("can't set interface flags");
486 return ret;
487 }
488 return 0;
489 }
490
491 /* Unset interface's flag. */
492 int if_unset_flags(struct interface *ifp, uint64_t flags)
493 {
494 int ret;
495 struct ifreq ifreq;
496
497 memset(&ifreq, 0, sizeof(struct ifreq));
498 ifreq_set_name(&ifreq, ifp);
499
500 ifreq.ifr_flags = ifp->flags;
501 ifreq.ifr_flags &= ~flags;
502
503 ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, vrf_to_id(ifp->vrf));
504
505 if (ret < 0) {
506 zlog_info("can't unset interface flags");
507 return ret;
508 }
509 return 0;
510 }
511
512 #ifndef LINUX_IPV6 /* Netlink has its own code */
513
514 #ifdef HAVE_STRUCT_IN6_ALIASREQ
515 #ifndef ND6_INFINITE_LIFETIME
516 #define ND6_INFINITE_LIFETIME 0xffffffffL
517 #endif /* ND6_INFINITE_LIFETIME */
518
519 /*
520 * Helper for interface-addr install, non-netlink
521 */
522 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
523 {
524 int ret;
525 struct in6_aliasreq addreq;
526 struct sockaddr_in6 addr;
527 struct sockaddr_in6 mask;
528 struct prefix_ipv6 *p;
529
530 p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx);
531
532 memset(&addreq, 0, sizeof(addreq));
533 strlcpy((char *)&addreq.ifra_name,
534 dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
535
536 memset(&addr, 0, sizeof(struct sockaddr_in6));
537 addr.sin6_addr = p->prefix;
538 addr.sin6_family = p->family;
539 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
540 addr.sin6_len = sizeof(struct sockaddr_in6);
541 #endif
542 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6));
543
544 memset(&mask, 0, sizeof(struct sockaddr_in6));
545 masklen2ip6(p->prefixlen, &mask.sin6_addr);
546 mask.sin6_family = p->family;
547 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
548 mask.sin6_len = sizeof(struct sockaddr_in6);
549 #endif
550 memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6));
551
552 addreq.ifra_lifetime.ia6t_vltime = 0xffffffff;
553 addreq.ifra_lifetime.ia6t_pltime = 0xffffffff;
554
555 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
556 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
557 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
558 #endif
559
560 ret = if_ioctl_ipv6(SIOCAIFADDR_IN6, (caddr_t)&addreq);
561 if (ret < 0)
562 return ret;
563 return 0;
564 }
565
566 /*
567 * Helper for interface-addr un-install, non-netlink
568 */
569 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
570 {
571 int ret;
572 struct in6_aliasreq addreq;
573 struct sockaddr_in6 addr;
574 struct sockaddr_in6 mask;
575 struct prefix_ipv6 *p;
576
577 p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx);
578
579 memset(&addreq, 0, sizeof(addreq));
580 strlcpy((char *)&addreq.ifra_name,
581 dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
582
583 memset(&addr, 0, sizeof(struct sockaddr_in6));
584 addr.sin6_addr = p->prefix;
585 addr.sin6_family = p->family;
586 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
587 addr.sin6_len = sizeof(struct sockaddr_in6);
588 #endif
589 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6));
590
591 memset(&mask, 0, sizeof(struct sockaddr_in6));
592 masklen2ip6(p->prefixlen, &mask.sin6_addr);
593 mask.sin6_family = p->family;
594 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
595 mask.sin6_len = sizeof(struct sockaddr_in6);
596 #endif
597 memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6));
598
599 #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
600 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
601 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
602 #endif
603
604 ret = if_ioctl_ipv6(SIOCDIFADDR_IN6, (caddr_t)&addreq);
605 if (ret < 0)
606 return ret;
607 return 0;
608 }
609 #else
610 /* The old, pre-dataplane code here just returned, so we're retaining that
611 * choice.
612 */
613 static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
614 {
615 return 0;
616 }
617
618 static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
619 {
620 return 0;
621 }
622 #endif /* HAVE_STRUCT_IN6_ALIASREQ */
623
624 #endif /* LINUX_IPV6 */
625
626 #endif /* !SUNOS_5 */