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/rib.h"
30 #include "zebra/debug.h"
32 /* Initialize of kernel interface. There is no kernel communication
33 support under ioctl(). So this is dummy stub function. */
40 /* Dummy function of routing socket. */
42 kernel_read (int sock
)
48 /* Initialization prototype of struct sockaddr_in. */
49 static struct sockaddr_in sin_proto
=
52 sizeof (struct sockaddr_in
),
53 #endif /* HAVE_SIN_LEN */
58 /* Solaris has ortentry. */
59 #ifdef HAVE_OLD_RTENTRY
60 #define rtentry ortentry
61 #endif /* HAVE_OLD_RTENTRY */
63 /* Interface to ioctl route message. */
65 kernel_add_route (struct prefix_ipv4
*dest
, struct in_addr
*gate
,
70 struct rtentry rtentry
;
71 struct sockaddr_in sin_dest
, sin_mask
, sin_gate
;
73 memset (&rtentry
, 0, sizeof (struct rtentry
));
75 /* Make destination. */
76 memset (&sin_dest
, 0, sizeof (struct sockaddr_in
));
77 sin_dest
.sin_family
= AF_INET
;
79 sin_dest
.sin_len
= sizeof (struct sockaddr_in
);
80 #endif /* HAVE_SIN_LEN */
81 sin_dest
.sin_addr
= dest
->prefix
;
86 memset (&sin_gate
, 0, sizeof (struct sockaddr_in
));
87 sin_gate
.sin_family
= AF_INET
;
89 sin_gate
.sin_len
= sizeof (struct sockaddr_in
);
90 #endif /* HAVE_SIN_LEN */
91 sin_gate
.sin_addr
= *gate
;
94 memset (&sin_mask
, 0, sizeof (struct sockaddr_in
));
95 sin_mask
.sin_family
= AF_INET
;
97 sin_gate
.sin_len
= sizeof (struct sockaddr_in
);
98 #endif /* HAVE_SIN_LEN */
99 masklen2ip (dest
->prefixlen
, &sin_mask
.sin_addr
);
101 /* Set destination address, mask and gateway.*/
102 memcpy (&rtentry
.rt_dst
, &sin_dest
, sizeof (struct sockaddr_in
));
104 memcpy (&rtentry
.rt_gateway
, &sin_gate
, sizeof (struct sockaddr_in
));
106 memcpy (&rtentry
.rt_genmask
, &sin_mask
, sizeof (struct sockaddr_in
));
109 /* Routing entry flag set. */
110 if (dest
->prefixlen
== 32)
111 rtentry
.rt_flags
|= RTF_HOST
;
113 if (gate
&& gate
->s_addr
!= INADDR_ANY
)
114 rtentry
.rt_flags
|= RTF_GATEWAY
;
116 rtentry
.rt_flags
|= RTF_UP
;
118 /* Additional flags */
119 rtentry
.rt_flags
|= flags
;
122 /* For tagging route. */
123 /* rtentry.rt_flags |= RTF_DYNAMIC; */
125 /* Open socket for ioctl. */
126 sock
= socket (AF_INET
, SOCK_DGRAM
, 0);
129 zlog_warn ("can't make socket\n");
133 /* Send message by ioctl(). */
134 ret
= ioctl (sock
, SIOCADDRT
, &rtentry
);
141 return ZEBRA_ERR_RTEXIST
;
145 return ZEBRA_ERR_RTUNREACH
;
149 return ZEBRA_ERR_EPERM
;
154 zlog_warn ("write : %s (%d)", strerror (errno
), errno
);
162 /* Interface to ioctl route message. */
164 kernel_ioctl_ipv4 (u_long cmd
, struct prefix
*p
, struct rib
*rib
, int family
)
168 struct rtentry rtentry
;
169 struct sockaddr_in sin_dest
, sin_mask
, sin_gate
;
170 struct nexthop
*nexthop
;
172 struct interface
*ifp
;
174 memset (&rtentry
, 0, sizeof (struct rtentry
));
176 /* Make destination. */
177 memset (&sin_dest
, 0, sizeof (struct sockaddr_in
));
178 sin_dest
.sin_family
= AF_INET
;
180 sin_dest
.sin_len
= sizeof (struct sockaddr_in
);
181 #endif /* HAVE_SIN_LEN */
182 sin_dest
.sin_addr
= p
->u
.prefix4
;
184 if (CHECK_FLAG (rib
->flags
, ZEBRA_FLAG_BLACKHOLE
))
186 SET_FLAG (rtentry
.rt_flags
, RTF_REJECT
);
188 if (cmd
== SIOCADDRT
)
189 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
190 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
195 memset (&sin_gate
, 0, sizeof (struct sockaddr_in
));
198 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
200 if ((cmd
== SIOCADDRT
201 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
203 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)))
205 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
207 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV4
||
208 nexthop
->rtype
== NEXTHOP_TYPE_IPV4_IFINDEX
)
210 sin_gate
.sin_family
= AF_INET
;
212 sin_gate
.sin_len
= sizeof (struct sockaddr_in
);
213 #endif /* HAVE_SIN_LEN */
214 sin_gate
.sin_addr
= nexthop
->rgate
.ipv4
;
215 rtentry
.rt_flags
|= RTF_GATEWAY
;
217 if (nexthop
->rtype
== NEXTHOP_TYPE_IFINDEX
218 || nexthop
->rtype
== NEXTHOP_TYPE_IFNAME
)
220 ifp
= if_lookup_by_index (nexthop
->rifindex
);
222 rtentry
.rt_dev
= ifp
->name
;
229 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
||
230 nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
232 sin_gate
.sin_family
= AF_INET
;
234 sin_gate
.sin_len
= sizeof (struct sockaddr_in
);
235 #endif /* HAVE_SIN_LEN */
236 sin_gate
.sin_addr
= nexthop
->gate
.ipv4
;
237 rtentry
.rt_flags
|= RTF_GATEWAY
;
239 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
240 || nexthop
->type
== NEXTHOP_TYPE_IFNAME
)
242 ifp
= if_lookup_by_index (nexthop
->ifindex
);
244 rtentry
.rt_dev
= ifp
->name
;
250 if (cmd
== SIOCADDRT
)
251 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
258 /* If there is no useful nexthop then return. */
259 if (nexthop_num
== 0)
261 if (IS_ZEBRA_DEBUG_KERNEL
)
262 zlog_info ("kernel_ioctl_ipv4(): No useful nexthop.");
268 memset (&sin_mask
, 0, sizeof (struct sockaddr_in
));
269 sin_mask
.sin_family
= AF_INET
;
271 sin_mask
.sin_len
= sizeof (struct sockaddr_in
);
272 #endif /* HAVE_SIN_LEN */
273 masklen2ip (p
->prefixlen
, &sin_mask
.sin_addr
);
275 /* Set destination address, mask and gateway.*/
276 memcpy (&rtentry
.rt_dst
, &sin_dest
, sizeof (struct sockaddr_in
));
278 if (rtentry
.rt_flags
& RTF_GATEWAY
)
279 memcpy (&rtentry
.rt_gateway
, &sin_gate
, sizeof (struct sockaddr_in
));
282 memcpy (&rtentry
.rt_genmask
, &sin_mask
, sizeof (struct sockaddr_in
));
285 /* Metric. It seems metric minus one value is installed... */
286 rtentry
.rt_metric
= rib
->metric
;
288 /* Routing entry flag set. */
289 if (p
->prefixlen
== 32)
290 rtentry
.rt_flags
|= RTF_HOST
;
292 rtentry
.rt_flags
|= RTF_UP
;
294 /* Additional flags */
295 /* rtentry.rt_flags |= flags; */
297 /* For tagging route. */
298 /* rtentry.rt_flags |= RTF_DYNAMIC; */
300 /* Open socket for ioctl. */
301 sock
= socket (AF_INET
, SOCK_DGRAM
, 0);
304 zlog_warn ("can't make socket\n");
308 /* Send message by ioctl(). */
309 ret
= ioctl (sock
, cmd
, &rtentry
);
316 return ZEBRA_ERR_RTEXIST
;
320 return ZEBRA_ERR_RTUNREACH
;
324 return ZEBRA_ERR_EPERM
;
329 zlog_warn ("write : %s (%d)", strerror (errno
), errno
);
338 kernel_add_ipv4 (struct prefix
*p
, struct rib
*rib
)
340 return kernel_ioctl_ipv4 (SIOCADDRT
, p
, rib
, AF_INET
);
344 kernel_delete_ipv4 (struct prefix
*p
, struct rib
*rib
)
346 return kernel_ioctl_ipv4 (SIOCDELRT
, p
, rib
, AF_INET
);
351 /* Below is hack for GNU libc definition and Linux 2.1.X header. */
355 #include <asm/types.h>
357 #if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
358 /* struct in6_rtmsg will be declared in net/route.h. */
360 #include <linux/ipv6_route.h>
364 kernel_ioctl_ipv6 (u_long type
, struct prefix_ipv6
*dest
, struct in6_addr
*gate
,
365 int index
, int flags
)
369 struct in6_rtmsg rtm
;
371 memset (&rtm
, 0, sizeof (struct in6_rtmsg
));
373 rtm
.rtmsg_flags
|= RTF_UP
;
374 rtm
.rtmsg_metric
= 1;
375 memcpy (&rtm
.rtmsg_dst
, &dest
->prefix
, sizeof (struct in6_addr
));
376 rtm
.rtmsg_dst_len
= dest
->prefixlen
;
378 /* We need link local index. But this should be done caller...
379 if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
381 index = if_index_address (&rtm.rtmsg_gateway);
382 rtm.rtmsg_ifindex = index;
385 rtm.rtmsg_ifindex = 0;
388 rtm
.rtmsg_flags
|= RTF_GATEWAY
;
390 /* For tagging route. */
391 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
393 memcpy (&rtm
.rtmsg_gateway
, gate
, sizeof (struct in6_addr
));
396 rtm
.rtmsg_ifindex
= index
;
398 rtm
.rtmsg_ifindex
= 0;
400 rtm
.rtmsg_metric
= 1;
402 sock
= socket (AF_INET6
, SOCK_DGRAM
, 0);
405 zlog_warn ("can't make socket\n");
409 /* Send message via ioctl. */
410 ret
= ioctl (sock
, type
, &rtm
);
413 zlog_warn ("can't %s ipv6 route: %s\n", type
== SIOCADDRT
? "add" : "delete",
425 kernel_ioctl_ipv6_multipath (u_long cmd
, struct prefix
*p
, struct rib
*rib
,
430 struct in6_rtmsg rtm
;
431 struct nexthop
*nexthop
;
434 memset (&rtm
, 0, sizeof (struct in6_rtmsg
));
436 rtm
.rtmsg_flags
|= RTF_UP
;
437 rtm
.rtmsg_metric
= rib
->metric
;
438 memcpy (&rtm
.rtmsg_dst
, &p
->u
.prefix
, sizeof (struct in6_addr
));
439 rtm
.rtmsg_dst_len
= p
->prefixlen
;
441 /* We need link local index. But this should be done caller...
442 if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
444 index = if_index_address (&rtm.rtmsg_gateway);
445 rtm.rtmsg_ifindex = index;
448 rtm.rtmsg_ifindex = 0;
451 if (CHECK_FLAG (rib
->flags
, ZEBRA_FLAG_BLACKHOLE
))
452 SET_FLAG (rtm
.rtmsg_flags
, RTF_REJECT
);
454 rtm
.rtmsg_flags
|= RTF_GATEWAY
;
456 /* For tagging route. */
457 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
460 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
462 if ((cmd
== SIOCADDRT
463 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
465 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)))
467 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
469 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV6
470 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
471 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
473 memcpy (&rtm
.rtmsg_gateway
, &nexthop
->rgate
.ipv6
,
474 sizeof (struct in6_addr
));
476 if (nexthop
->rtype
== NEXTHOP_TYPE_IFINDEX
477 || nexthop
->rtype
== NEXTHOP_TYPE_IFNAME
478 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
479 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
480 rtm
.rtmsg_ifindex
= nexthop
->rifindex
;
482 rtm
.rtmsg_ifindex
= 0;
487 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
488 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
489 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
491 memcpy (&rtm
.rtmsg_gateway
, &nexthop
->gate
.ipv6
,
492 sizeof (struct in6_addr
));
494 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
495 || nexthop
->type
== NEXTHOP_TYPE_IFNAME
496 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
497 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
498 rtm
.rtmsg_ifindex
= nexthop
->ifindex
;
500 rtm
.rtmsg_ifindex
= 0;
501 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
)
503 #ifdef HAVE_IN6ADDR_GLOBAL
504 rtm
.rtmsg_gateway
= in6addr_loopback
;
505 #else /*HAVE_IN6ADDR_GLOBAL*/
506 inet_pton (AF_INET6
, "::1", &rtm
.rtmsg_gateway
);
507 #endif /*HAVE_IN6ADDR_GLOBAL*/
511 if (cmd
== SIOCADDRT
)
512 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
519 /* If there is no useful nexthop then return. */
520 if (nexthop_num
== 0)
522 if (IS_ZEBRA_DEBUG_KERNEL
)
523 zlog_info ("kernel_ioctl_ipv6_multipath(): No useful nexthop.");
527 sock
= socket (AF_INET6
, SOCK_DGRAM
, 0);
530 zlog_warn ("can't make socket\n");
534 /* Send message via ioctl. */
535 ret
= ioctl (sock
, cmd
, &rtm
);
538 zlog_warn ("can't %s ipv6 route: %s\n",
539 cmd
== SIOCADDRT
? "add" : "delete",
551 kernel_add_ipv6 (struct prefix
*p
, struct rib
*rib
)
553 return kernel_ioctl_ipv6_multipath (SIOCADDRT
, p
, rib
, AF_INET6
);
557 kernel_delete_ipv6 (struct prefix
*p
, struct rib
*rib
)
559 return kernel_ioctl_ipv6_multipath (SIOCDELRT
, p
, rib
, AF_INET6
);
562 /* Delete IPv6 route from the kernel. */
564 kernel_delete_ipv6_old (struct prefix_ipv6
*dest
, struct in6_addr
*gate
,
565 int index
, int flags
, int table
)
567 return kernel_ioctl_ipv6 (SIOCDELRT
, dest
, gate
, index
, flags
);
569 #endif /* HAVE_IPV6 */