blob: 404a7c696fa4560a4dc26c99d891a80a4333abeb [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
2 * kernel routing table update by ioctl().
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
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.
21 */
22
23#include <zebra.h>
24
25#include "prefix.h"
26#include "log.h"
27#include "if.h"
28
paula1ac18c2005-06-28 17:17:12 +000029#include "zebra/zserv.h"
paul718e3742002-12-13 20:15:29 +000030#include "zebra/rib.h"
31#include "zebra/debug.h"
paula1ac18c2005-06-28 17:17:12 +000032#include "zebra/rt.h"
paul718e3742002-12-13 20:15:29 +000033
34/* Initialize of kernel interface. There is no kernel communication
35 support under ioctl(). So this is dummy stub function. */
36void
paula1ac18c2005-06-28 17:17:12 +000037kernel_init (void)
paul718e3742002-12-13 20:15:29 +000038{
39 return;
40}
41
42/* Dummy function of routing socket. */
paula1ac18c2005-06-28 17:17:12 +000043static void
paul718e3742002-12-13 20:15:29 +000044kernel_read (int sock)
45{
46 return;
47}
48
49#if 0
50/* Initialization prototype of struct sockaddr_in. */
51static struct sockaddr_in sin_proto =
52{
Paul Jakma6f0e3f62007-05-10 02:38:51 +000053#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +000054 sizeof (struct sockaddr_in),
Paul Jakma6f0e3f62007-05-10 02:38:51 +000055#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +000056 AF_INET, 0, {0}, {0}
57};
58#endif /* 0 */
59
60/* Solaris has ortentry. */
61#ifdef HAVE_OLD_RTENTRY
62#define rtentry ortentry
63#endif /* HAVE_OLD_RTENTRY */
64
65/* Interface to ioctl route message. */
66int
67kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate,
68 int index, int flags)
69{
70 int ret;
71 int sock;
72 struct rtentry rtentry;
73 struct sockaddr_in sin_dest, sin_mask, sin_gate;
74
75 memset (&rtentry, 0, sizeof (struct rtentry));
76
77 /* Make destination. */
78 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
79 sin_dest.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +000080#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +000081 sin_dest.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +000082#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +000083 sin_dest.sin_addr = dest->prefix;
84
85 /* Make gateway. */
86 if (gate)
87 {
88 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
89 sin_gate.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +000090#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +000091 sin_gate.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +000092#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +000093 sin_gate.sin_addr = *gate;
94 }
95
96 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
97 sin_mask.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +000098#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +000099 sin_gate.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000100#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +0000101 masklen2ip (dest->prefixlen, &sin_mask.sin_addr);
102
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 */
110
111 /* Routing entry flag set. */
112 if (dest->prefixlen == 32)
113 rtentry.rt_flags |= RTF_HOST;
114
115 if (gate && gate->s_addr != INADDR_ANY)
116 rtentry.rt_flags |= RTF_GATEWAY;
117
118 rtentry.rt_flags |= RTF_UP;
119
120 /* Additional flags */
121 rtentry.rt_flags |= flags;
122
123
124 /* For tagging route. */
125 /* rtentry.rt_flags |= RTF_DYNAMIC; */
126
127 /* Open socket for ioctl. */
128 sock = socket (AF_INET, SOCK_DGRAM, 0);
129 if (sock < 0)
130 {
131 zlog_warn ("can't make socket\n");
132 return -1;
133 }
134
135 /* Send message by ioctl(). */
136 ret = ioctl (sock, SIOCADDRT, &rtentry);
137 if (ret < 0)
138 {
139 switch (errno)
140 {
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;
153 }
154
155 close (sock);
ajs6099b3b2004-11-20 02:06:59 +0000156 zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
paul718e3742002-12-13 20:15:29 +0000157 return 1;
158 }
159 close (sock);
160
161 return ret;
162}
163
164/* Interface to ioctl route message. */
paula1ac18c2005-06-28 17:17:12 +0000165static int
paul718e3742002-12-13 20:15:29 +0000166kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
167{
168 int ret;
169 int sock;
170 struct rtentry rtentry;
171 struct sockaddr_in sin_dest, sin_mask, sin_gate;
Christian Frankefa713d92013-07-05 15:35:37 +0000172 struct nexthop *nexthop, *tnexthop;
173 int recursing;
paul718e3742002-12-13 20:15:29 +0000174 int nexthop_num = 0;
175 struct interface *ifp;
176
177 memset (&rtentry, 0, sizeof (struct rtentry));
178
179 /* Make destination. */
180 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
181 sin_dest.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000182#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +0000183 sin_dest.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000184#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +0000185 sin_dest.sin_addr = p->u.prefix4;
186
187 if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
188 {
189 SET_FLAG (rtentry.rt_flags, RTF_REJECT);
190
191 if (cmd == SIOCADDRT)
Christian Frankefa713d92013-07-05 15:35:37 +0000192 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
193 {
194 /* We shouldn't encounter recursive nexthops on discard routes,
195 * but it is probably better to handle that case correctly anyway.
196 */
197 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
198 continue;
199 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
200 }
paul718e3742002-12-13 20:15:29 +0000201 goto skip;
202 }
203
204 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
205
206 /* Make gateway. */
Christian Frankefa713d92013-07-05 15:35:37 +0000207 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul718e3742002-12-13 20:15:29 +0000208 {
Christian Frankefa713d92013-07-05 15:35:37 +0000209 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
210 continue;
211
paul718e3742002-12-13 20:15:29 +0000212 if ((cmd == SIOCADDRT
213 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
214 || (cmd == SIOCDELRT
215 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
216 {
Christian Frankefa713d92013-07-05 15:35:37 +0000217 if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
218 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
paul718e3742002-12-13 20:15:29 +0000219 {
Christian Frankefa713d92013-07-05 15:35:37 +0000220 sin_gate.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000221#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
Christian Frankefa713d92013-07-05 15:35:37 +0000222 sin_gate.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000223#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
Christian Frankefa713d92013-07-05 15:35:37 +0000224 sin_gate.sin_addr = nexthop->gate.ipv4;
225 rtentry.rt_flags |= RTF_GATEWAY;
paul718e3742002-12-13 20:15:29 +0000226 }
Christian Frankefa713d92013-07-05 15:35:37 +0000227 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
228 || nexthop->type == NEXTHOP_TYPE_IFNAME)
paul718e3742002-12-13 20:15:29 +0000229 {
Christian Frankefa713d92013-07-05 15:35:37 +0000230 ifp = if_lookup_by_index (nexthop->ifindex);
231 if (ifp)
232 rtentry.rt_dev = ifp->name;
233 else
234 return -1;
paul718e3742002-12-13 20:15:29 +0000235 }
236
237 if (cmd == SIOCADDRT)
238 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
239
240 nexthop_num++;
241 break;
242 }
243 }
244
245 /* If there is no useful nexthop then return. */
246 if (nexthop_num == 0)
247 {
248 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000249 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +0000250 return 0;
251 }
252
253 skip:
254
255 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
256 sin_mask.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000257#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +0000258 sin_mask.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000259#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +0000260 masklen2ip (p->prefixlen, &sin_mask.sin_addr);
261
262 /* Set destination address, mask and gateway.*/
263 memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
264
265 if (rtentry.rt_flags & RTF_GATEWAY)
266 memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
267
268#ifndef SUNOS_5
269 memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
270#endif /* SUNOS_5 */
271
272 /* Metric. It seems metric minus one value is installed... */
273 rtentry.rt_metric = rib->metric;
274
275 /* Routing entry flag set. */
276 if (p->prefixlen == 32)
277 rtentry.rt_flags |= RTF_HOST;
278
279 rtentry.rt_flags |= RTF_UP;
280
281 /* Additional flags */
282 /* rtentry.rt_flags |= flags; */
283
284 /* For tagging route. */
285 /* rtentry.rt_flags |= RTF_DYNAMIC; */
286
287 /* Open socket for ioctl. */
288 sock = socket (AF_INET, SOCK_DGRAM, 0);
289 if (sock < 0)
290 {
291 zlog_warn ("can't make socket\n");
292 return -1;
293 }
294
295 /* Send message by ioctl(). */
296 ret = ioctl (sock, cmd, &rtentry);
297 if (ret < 0)
298 {
299 switch (errno)
300 {
301 case EEXIST:
302 close (sock);
303 return ZEBRA_ERR_RTEXIST;
304 break;
305 case ENETUNREACH:
306 close (sock);
307 return ZEBRA_ERR_RTUNREACH;
308 break;
309 case EPERM:
310 close (sock);
311 return ZEBRA_ERR_EPERM;
312 break;
313 }
314
315 close (sock);
ajs6099b3b2004-11-20 02:06:59 +0000316 zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
paul718e3742002-12-13 20:15:29 +0000317 return ret;
318 }
319 close (sock);
320
321 return ret;
322}
323
324int
325kernel_add_ipv4 (struct prefix *p, struct rib *rib)
326{
327 return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
328}
329
330int
331kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
332{
333 return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
334}
335
336#ifdef HAVE_IPV6
337
338/* Below is hack for GNU libc definition and Linux 2.1.X header. */
339#undef RTF_DEFAULT
340#undef RTF_ADDRCONF
341
342#include <asm/types.h>
343
344#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
345/* struct in6_rtmsg will be declared in net/route.h. */
346#else
347#include <linux/ipv6_route.h>
348#endif
349
paula1ac18c2005-06-28 17:17:12 +0000350static int
paul718e3742002-12-13 20:15:29 +0000351kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate,
352 int index, int flags)
353{
354 int ret;
355 int sock;
356 struct in6_rtmsg rtm;
357
358 memset (&rtm, 0, sizeof (struct in6_rtmsg));
359
360 rtm.rtmsg_flags |= RTF_UP;
361 rtm.rtmsg_metric = 1;
362 memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr));
363 rtm.rtmsg_dst_len = dest->prefixlen;
364
365 /* We need link local index. But this should be done caller...
366 if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
367 {
368 index = if_index_address (&rtm.rtmsg_gateway);
369 rtm.rtmsg_ifindex = index;
370 }
371 else
372 rtm.rtmsg_ifindex = 0;
373 */
374
375 rtm.rtmsg_flags |= RTF_GATEWAY;
376
377 /* For tagging route. */
378 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
379
380 memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr));
381
382 if (index)
383 rtm.rtmsg_ifindex = index;
384 else
385 rtm.rtmsg_ifindex = 0;
386
387 rtm.rtmsg_metric = 1;
388
389 sock = socket (AF_INET6, SOCK_DGRAM, 0);
390 if (sock < 0)
391 {
392 zlog_warn ("can't make socket\n");
393 return -1;
394 }
395
396 /* Send message via ioctl. */
397 ret = ioctl (sock, type, &rtm);
398 if (ret < 0)
399 {
400 zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete",
ajs6099b3b2004-11-20 02:06:59 +0000401 safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +0000402 ret = errno;
403 close (sock);
404 return ret;
405 }
406 close (sock);
407
408 return ret;
409}
410
paula1ac18c2005-06-28 17:17:12 +0000411static int
paul718e3742002-12-13 20:15:29 +0000412kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
413 int family)
414{
415 int ret;
416 int sock;
417 struct in6_rtmsg rtm;
Christian Frankefa713d92013-07-05 15:35:37 +0000418 struct nexthop *nexthop, *tnexthop;
419 int recursing;
paul718e3742002-12-13 20:15:29 +0000420 int nexthop_num = 0;
421
422 memset (&rtm, 0, sizeof (struct in6_rtmsg));
423
424 rtm.rtmsg_flags |= RTF_UP;
425 rtm.rtmsg_metric = rib->metric;
426 memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr));
427 rtm.rtmsg_dst_len = p->prefixlen;
428
429 /* We need link local index. But this should be done caller...
430 if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
431 {
432 index = if_index_address (&rtm.rtmsg_gateway);
433 rtm.rtmsg_ifindex = index;
434 }
435 else
436 rtm.rtmsg_ifindex = 0;
437 */
438
439 rtm.rtmsg_flags |= RTF_GATEWAY;
440
441 /* For tagging route. */
442 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
443
444 /* Make gateway. */
Christian Frankefa713d92013-07-05 15:35:37 +0000445 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
paul718e3742002-12-13 20:15:29 +0000446 {
Christian Frankefa713d92013-07-05 15:35:37 +0000447 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
448 continue;
449
paul718e3742002-12-13 20:15:29 +0000450 if ((cmd == SIOCADDRT
451 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
452 || (cmd == SIOCDELRT
453 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
454 {
Christian Frankefa713d92013-07-05 15:35:37 +0000455 if (nexthop->type == NEXTHOP_TYPE_IPV6
456 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
457 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
paul718e3742002-12-13 20:15:29 +0000458 {
Christian Frankefa713d92013-07-05 15:35:37 +0000459 memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
460 sizeof (struct in6_addr));
paul718e3742002-12-13 20:15:29 +0000461 }
Christian Frankefa713d92013-07-05 15:35:37 +0000462 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
463 || nexthop->type == NEXTHOP_TYPE_IFNAME
464 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
465 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
466 rtm.rtmsg_ifindex = nexthop->ifindex;
paul718e3742002-12-13 20:15:29 +0000467 else
Christian Frankefa713d92013-07-05 15:35:37 +0000468 rtm.rtmsg_ifindex = 0;
paul718e3742002-12-13 20:15:29 +0000469
470 if (cmd == SIOCADDRT)
471 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
472
473 nexthop_num++;
474 break;
475 }
476 }
477
478 /* If there is no useful nexthop then return. */
479 if (nexthop_num == 0)
480 {
481 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000482 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +0000483 return 0;
484 }
485
486 sock = socket (AF_INET6, SOCK_DGRAM, 0);
487 if (sock < 0)
488 {
489 zlog_warn ("can't make socket\n");
490 return -1;
491 }
492
493 /* Send message via ioctl. */
494 ret = ioctl (sock, cmd, &rtm);
495 if (ret < 0)
496 {
497 zlog_warn ("can't %s ipv6 route: %s\n",
498 cmd == SIOCADDRT ? "add" : "delete",
ajs6099b3b2004-11-20 02:06:59 +0000499 safe_strerror(errno));
paul718e3742002-12-13 20:15:29 +0000500 ret = errno;
501 close (sock);
502 return ret;
503 }
504 close (sock);
505
506 return ret;
507}
508
509int
510kernel_add_ipv6 (struct prefix *p, struct rib *rib)
511{
512 return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
513}
514
515int
516kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
517{
518 return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
519}
520
521/* Delete IPv6 route from the kernel. */
522int
523kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paula1ac18c2005-06-28 17:17:12 +0000524 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +0000525{
526 return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
527}
528#endif /* HAVE_IPV6 */