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
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
29 #include "zebra/zserv.h"
30 #include "zebra/rib.h"
31 #include "zebra/debug.h"
34 /* Initialize of kernel interface. There is no kernel communication
35 support under ioctl(). So this is dummy stub function. */
42 /* Dummy function of routing socket. */
44 kernel_read (int sock
)
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 */
60 /* Solaris has ortentry. */
61 #ifdef HAVE_OLD_RTENTRY
62 #define rtentry ortentry
63 #endif /* HAVE_OLD_RTENTRY */
65 /* Interface to ioctl route message. */
67 kernel_add_route (struct prefix_ipv4
*dest
, struct in_addr
*gate
,
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
;
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
));
106 memcpy (&rtentry
.rt_gateway
, &sin_gate
, sizeof (struct sockaddr_in
));
108 memcpy (&rtentry
.rt_genmask
, &sin_mask
, sizeof (struct sockaddr_in
));
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);
131 zlog_warn ("can't make socket\n");
135 /* Send message by ioctl(). */
136 ret
= ioctl (sock
, SIOCADDRT
, &rtentry
);
143 return ZEBRA_ERR_RTEXIST
;
147 return ZEBRA_ERR_RTUNREACH
;
151 return ZEBRA_ERR_EPERM
;
156 zlog_warn ("write : %s (%d)", safe_strerror (errno
), errno
);
164 /* Interface to ioctl route message. */
166 kernel_ioctl_ipv4 (u_long cmd
, struct prefix
*p
, struct rib
*rib
, int family
)
170 struct rtentry rtentry
;
171 struct sockaddr_in sin_dest
, sin_mask
, sin_gate
;
172 struct nexthop
*nexthop
;
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
);
197 memset (&sin_gate
, 0, sizeof (struct sockaddr_in
));
200 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
202 if ((cmd
== SIOCADDRT
203 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
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
);
224 rtentry
.rt_dev
= ifp
->name
;
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
);
246 rtentry
.rt_dev
= ifp
->name
;
252 if (cmd
== SIOCADDRT
)
253 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
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.");
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
));
284 memcpy (&rtentry
.rt_genmask
, &sin_mask
, sizeof (struct sockaddr_in
));
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);
306 zlog_warn ("can't make socket\n");
310 /* Send message by ioctl(). */
311 ret
= ioctl (sock
, cmd
, &rtentry
);
318 return ZEBRA_ERR_RTEXIST
;
322 return ZEBRA_ERR_RTUNREACH
;
326 return ZEBRA_ERR_EPERM
;
331 zlog_warn ("write : %s (%d)", safe_strerror (errno
), errno
);
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
);
353 /* Below is hack for GNU libc definition and Linux 2.1.X header. */
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. */
362 #include <linux/ipv6_route.h>
366 kernel_ioctl_ipv6 (u_long type
, struct prefix_ipv6
*dest
, struct in6_addr
*gate
,
367 int index
, int flags
)
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;
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
));
398 rtm
.rtmsg_ifindex
= index
;
400 rtm
.rtmsg_ifindex
= 0;
402 rtm
.rtmsg_metric
= 1;
404 sock
= socket (AF_INET6
, SOCK_DGRAM
, 0);
407 zlog_warn ("can't make socket\n");
411 /* Send message via ioctl. */
412 ret
= ioctl (sock
, type
, &rtm
);
415 zlog_warn ("can't %s ipv6 route: %s\n", type
== SIOCADDRT
? "add" : "delete",
416 safe_strerror(errno
));
427 kernel_ioctl_ipv6_multipath (u_long cmd
, struct prefix
*p
, struct rib
*rib
,
432 struct in6_rtmsg rtm
;
433 struct nexthop
*nexthop
;
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;
450 rtm.rtmsg_ifindex = 0;
453 rtm
.rtmsg_flags
|= RTF_GATEWAY
;
455 /* For tagging route. */
456 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
459 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
461 if ((cmd
== SIOCADDRT
462 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
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
;
481 rtm
.rtmsg_ifindex
= 0;
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
;
499 rtm
.rtmsg_ifindex
= 0;
502 if (cmd
== SIOCADDRT
)
503 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
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.");
518 sock
= socket (AF_INET6
, SOCK_DGRAM
, 0);
521 zlog_warn ("can't make socket\n");
525 /* Send message via ioctl. */
526 ret
= ioctl (sock
, cmd
, &rtm
);
529 zlog_warn ("can't %s ipv6 route: %s\n",
530 cmd
== SIOCADDRT
? "add" : "delete",
531 safe_strerror(errno
));
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 */