+ note the meta-queue in NEWS
[jleu-quagga.git] / zebra / rt_ioctl.c
bloba5d588c7f915edbd450691a87c00157465b3fe07
1 /*
2 * kernel routing table update by ioctl().
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
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.
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.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
23 #include <zebra.h>
25 #include "prefix.h"
26 #include "log.h"
27 #include "if.h"
29 #include "zebra/zserv.h"
30 #include "zebra/rib.h"
31 #include "zebra/debug.h"
32 #include "zebra/rt.h"
34 /* Initialize of kernel interface. There is no kernel communication
35 support under ioctl(). So this is dummy stub function. */
36 void
37 kernel_init (void)
39 return;
42 /* Dummy function of routing socket. */
43 static void
44 kernel_read (int sock)
46 return;
49 #if 0
50 /* Initialization prototype of struct sockaddr_in. */
51 static struct sockaddr_in sin_proto =
53 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
54 sizeof (struct sockaddr_in),
55 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
56 AF_INET, 0, {0}, {0}
58 #endif /* 0 */
60 /* Solaris has ortentry. */
61 #ifdef HAVE_OLD_RTENTRY
62 #define rtentry ortentry
63 #endif /* HAVE_OLD_RTENTRY */
65 /* Interface to ioctl route message. */
66 int
67 kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate,
68 int index, int flags)
70 int ret;
71 int sock;
72 struct rtentry rtentry;
73 struct sockaddr_in sin_dest, sin_mask, sin_gate;
75 memset (&rtentry, 0, sizeof (struct rtentry));
77 /* Make destination. */
78 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
79 sin_dest.sin_family = AF_INET;
80 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
81 sin_dest.sin_len = sizeof (struct sockaddr_in);
82 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
83 sin_dest.sin_addr = dest->prefix;
85 /* Make gateway. */
86 if (gate)
88 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
89 sin_gate.sin_family = AF_INET;
90 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
91 sin_gate.sin_len = sizeof (struct sockaddr_in);
92 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
93 sin_gate.sin_addr = *gate;
96 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
97 sin_mask.sin_family = AF_INET;
98 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
99 sin_gate.sin_len = sizeof (struct sockaddr_in);
100 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
101 masklen2ip (dest->prefixlen, &sin_mask.sin_addr);
103 /* Set destination address, mask and gateway.*/
104 memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
105 if (gate)
106 memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
107 #ifndef SUNOS_5
108 memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
109 #endif /* SUNOS_5 */
111 /* Routing entry flag set. */
112 if (dest->prefixlen == 32)
113 rtentry.rt_flags |= RTF_HOST;
115 if (gate && gate->s_addr != INADDR_ANY)
116 rtentry.rt_flags |= RTF_GATEWAY;
118 rtentry.rt_flags |= RTF_UP;
120 /* Additional flags */
121 rtentry.rt_flags |= flags;
124 /* For tagging route. */
125 /* rtentry.rt_flags |= RTF_DYNAMIC; */
127 /* Open socket for ioctl. */
128 sock = socket (AF_INET, SOCK_DGRAM, 0);
129 if (sock < 0)
131 zlog_warn ("can't make socket\n");
132 return -1;
135 /* Send message by ioctl(). */
136 ret = ioctl (sock, SIOCADDRT, &rtentry);
137 if (ret < 0)
139 switch (errno)
141 case EEXIST:
142 close (sock);
143 return ZEBRA_ERR_RTEXIST;
144 break;
145 case ENETUNREACH:
146 close (sock);
147 return ZEBRA_ERR_RTUNREACH;
148 break;
149 case EPERM:
150 close (sock);
151 return ZEBRA_ERR_EPERM;
152 break;
155 close (sock);
156 zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
157 return 1;
159 close (sock);
161 return ret;
164 /* Interface to ioctl route message. */
165 static int
166 kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
168 int ret;
169 int sock;
170 struct rtentry rtentry;
171 struct sockaddr_in sin_dest, sin_mask, sin_gate;
172 struct nexthop *nexthop;
173 int nexthop_num = 0;
174 struct interface *ifp;
176 memset (&rtentry, 0, sizeof (struct rtentry));
178 /* Make destination. */
179 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
180 sin_dest.sin_family = AF_INET;
181 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
182 sin_dest.sin_len = sizeof (struct sockaddr_in);
183 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
184 sin_dest.sin_addr = p->u.prefix4;
186 if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
188 SET_FLAG (rtentry.rt_flags, RTF_REJECT);
190 if (cmd == SIOCADDRT)
191 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
192 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
194 goto skip;
197 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
199 /* Make gateway. */
200 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
202 if ((cmd == SIOCADDRT
203 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
204 || (cmd == SIOCDELRT
205 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
207 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
209 if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
210 nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
212 sin_gate.sin_family = AF_INET;
213 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
214 sin_gate.sin_len = sizeof (struct sockaddr_in);
215 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
216 sin_gate.sin_addr = nexthop->rgate.ipv4;
217 rtentry.rt_flags |= RTF_GATEWAY;
219 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
220 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
222 ifp = if_lookup_by_index (nexthop->rifindex);
223 if (ifp)
224 rtentry.rt_dev = ifp->name;
225 else
226 return -1;
229 else
231 if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
232 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
234 sin_gate.sin_family = AF_INET;
235 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
236 sin_gate.sin_len = sizeof (struct sockaddr_in);
237 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
238 sin_gate.sin_addr = nexthop->gate.ipv4;
239 rtentry.rt_flags |= RTF_GATEWAY;
241 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
242 || nexthop->type == NEXTHOP_TYPE_IFNAME)
244 ifp = if_lookup_by_index (nexthop->ifindex);
245 if (ifp)
246 rtentry.rt_dev = ifp->name;
247 else
248 return -1;
252 if (cmd == SIOCADDRT)
253 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
255 nexthop_num++;
256 break;
260 /* If there is no useful nexthop then return. */
261 if (nexthop_num == 0)
263 if (IS_ZEBRA_DEBUG_KERNEL)
264 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
265 return 0;
268 skip:
270 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
271 sin_mask.sin_family = AF_INET;
272 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
273 sin_mask.sin_len = sizeof (struct sockaddr_in);
274 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
275 masklen2ip (p->prefixlen, &sin_mask.sin_addr);
277 /* Set destination address, mask and gateway.*/
278 memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
280 if (rtentry.rt_flags & RTF_GATEWAY)
281 memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
283 #ifndef SUNOS_5
284 memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
285 #endif /* SUNOS_5 */
287 /* Metric. It seems metric minus one value is installed... */
288 rtentry.rt_metric = rib->metric;
290 /* Routing entry flag set. */
291 if (p->prefixlen == 32)
292 rtentry.rt_flags |= RTF_HOST;
294 rtentry.rt_flags |= RTF_UP;
296 /* Additional flags */
297 /* rtentry.rt_flags |= flags; */
299 /* For tagging route. */
300 /* rtentry.rt_flags |= RTF_DYNAMIC; */
302 /* Open socket for ioctl. */
303 sock = socket (AF_INET, SOCK_DGRAM, 0);
304 if (sock < 0)
306 zlog_warn ("can't make socket\n");
307 return -1;
310 /* Send message by ioctl(). */
311 ret = ioctl (sock, cmd, &rtentry);
312 if (ret < 0)
314 switch (errno)
316 case EEXIST:
317 close (sock);
318 return ZEBRA_ERR_RTEXIST;
319 break;
320 case ENETUNREACH:
321 close (sock);
322 return ZEBRA_ERR_RTUNREACH;
323 break;
324 case EPERM:
325 close (sock);
326 return ZEBRA_ERR_EPERM;
327 break;
330 close (sock);
331 zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
332 return ret;
334 close (sock);
336 return ret;
340 kernel_add_ipv4 (struct prefix *p, struct rib *rib)
342 return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
346 kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
348 return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
351 #ifdef HAVE_IPV6
353 /* Below is hack for GNU libc definition and Linux 2.1.X header. */
354 #undef RTF_DEFAULT
355 #undef RTF_ADDRCONF
357 #include <asm/types.h>
359 #if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
360 /* struct in6_rtmsg will be declared in net/route.h. */
361 #else
362 #include <linux/ipv6_route.h>
363 #endif
365 static int
366 kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate,
367 int index, int flags)
369 int ret;
370 int sock;
371 struct in6_rtmsg rtm;
373 memset (&rtm, 0, sizeof (struct in6_rtmsg));
375 rtm.rtmsg_flags |= RTF_UP;
376 rtm.rtmsg_metric = 1;
377 memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr));
378 rtm.rtmsg_dst_len = dest->prefixlen;
380 /* We need link local index. But this should be done caller...
381 if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
383 index = if_index_address (&rtm.rtmsg_gateway);
384 rtm.rtmsg_ifindex = index;
386 else
387 rtm.rtmsg_ifindex = 0;
390 rtm.rtmsg_flags |= RTF_GATEWAY;
392 /* For tagging route. */
393 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
395 memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr));
397 if (index)
398 rtm.rtmsg_ifindex = index;
399 else
400 rtm.rtmsg_ifindex = 0;
402 rtm.rtmsg_metric = 1;
404 sock = socket (AF_INET6, SOCK_DGRAM, 0);
405 if (sock < 0)
407 zlog_warn ("can't make socket\n");
408 return -1;
411 /* Send message via ioctl. */
412 ret = ioctl (sock, type, &rtm);
413 if (ret < 0)
415 zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete",
416 safe_strerror(errno));
417 ret = errno;
418 close (sock);
419 return ret;
421 close (sock);
423 return ret;
426 static int
427 kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
428 int family)
430 int ret;
431 int sock;
432 struct in6_rtmsg rtm;
433 struct nexthop *nexthop;
434 int nexthop_num = 0;
436 memset (&rtm, 0, sizeof (struct in6_rtmsg));
438 rtm.rtmsg_flags |= RTF_UP;
439 rtm.rtmsg_metric = rib->metric;
440 memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr));
441 rtm.rtmsg_dst_len = p->prefixlen;
443 /* We need link local index. But this should be done caller...
444 if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
446 index = if_index_address (&rtm.rtmsg_gateway);
447 rtm.rtmsg_ifindex = index;
449 else
450 rtm.rtmsg_ifindex = 0;
453 rtm.rtmsg_flags |= RTF_GATEWAY;
455 /* For tagging route. */
456 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
458 /* Make gateway. */
459 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
461 if ((cmd == SIOCADDRT
462 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
463 || (cmd == SIOCDELRT
464 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
466 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
468 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
469 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
470 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
472 memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6,
473 sizeof (struct in6_addr));
475 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
476 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
477 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
478 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
479 rtm.rtmsg_ifindex = nexthop->rifindex;
480 else
481 rtm.rtmsg_ifindex = 0;
484 else
486 if (nexthop->type == NEXTHOP_TYPE_IPV6
487 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
488 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
490 memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
491 sizeof (struct in6_addr));
493 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
494 || nexthop->type == NEXTHOP_TYPE_IFNAME
495 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
496 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
497 rtm.rtmsg_ifindex = nexthop->ifindex;
498 else
499 rtm.rtmsg_ifindex = 0;
502 if (cmd == SIOCADDRT)
503 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
505 nexthop_num++;
506 break;
510 /* If there is no useful nexthop then return. */
511 if (nexthop_num == 0)
513 if (IS_ZEBRA_DEBUG_KERNEL)
514 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
515 return 0;
518 sock = socket (AF_INET6, SOCK_DGRAM, 0);
519 if (sock < 0)
521 zlog_warn ("can't make socket\n");
522 return -1;
525 /* Send message via ioctl. */
526 ret = ioctl (sock, cmd, &rtm);
527 if (ret < 0)
529 zlog_warn ("can't %s ipv6 route: %s\n",
530 cmd == SIOCADDRT ? "add" : "delete",
531 safe_strerror(errno));
532 ret = errno;
533 close (sock);
534 return ret;
536 close (sock);
538 return ret;
542 kernel_add_ipv6 (struct prefix *p, struct rib *rib)
544 return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
548 kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
550 return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
553 /* Delete IPv6 route from the kernel. */
555 kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
556 unsigned int index, int flags, int table)
558 return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
560 #endif /* HAVE_IPV6 */