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