]> git.proxmox.com Git - mirror_frr.git/blame - zebra/rt_ioctl.c
* configure.ac, vtysh/Makefile.am: Only vtysh needs to be linked
[mirror_frr.git] / zebra / rt_ioctl.c
CommitLineData
718e3744 1/*
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
a1ac18c4 29#include "zebra/zserv.h"
718e3744 30#include "zebra/rib.h"
31#include "zebra/debug.h"
a1ac18c4 32#include "zebra/rt.h"
718e3744 33
34/* Initialize of kernel interface. There is no kernel communication
35 support under ioctl(). So this is dummy stub function. */
36void
a1ac18c4 37kernel_init (void)
718e3744 38{
39 return;
40}
41
42/* Dummy function of routing socket. */
a1ac18c4 43static void
718e3744 44kernel_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{
53#ifdef HAVE_SIN_LEN
54 sizeof (struct sockaddr_in),
55#endif /* HAVE_SIN_LEN */
56 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;
80#ifdef HAVE_SIN_LEN
81 sin_dest.sin_len = sizeof (struct sockaddr_in);
82#endif /* HAVE_SIN_LEN */
83 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;
90#ifdef HAVE_SIN_LEN
91 sin_gate.sin_len = sizeof (struct sockaddr_in);
92#endif /* HAVE_SIN_LEN */
93 sin_gate.sin_addr = *gate;
94 }
95
96 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
97 sin_mask.sin_family = AF_INET;
98#ifdef HAVE_SIN_LEN
99 sin_gate.sin_len = sizeof (struct sockaddr_in);
100#endif /* HAVE_SIN_LEN */
101 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);
6099b3b5 156 zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
718e3744 157 return 1;
158 }
159 close (sock);
160
161 return ret;
162}
163
164/* Interface to ioctl route message. */
a1ac18c4 165static int
718e3744 166kernel_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;
172 struct nexthop *nexthop;
173 int nexthop_num = 0;
174 struct interface *ifp;
175
176 memset (&rtentry, 0, sizeof (struct rtentry));
177
178 /* Make destination. */
179 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
180 sin_dest.sin_family = AF_INET;
181#ifdef HAVE_SIN_LEN
182 sin_dest.sin_len = sizeof (struct sockaddr_in);
183#endif /* HAVE_SIN_LEN */
184 sin_dest.sin_addr = p->u.prefix4;
185
186 if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
187 {
188 SET_FLAG (rtentry.rt_flags, RTF_REJECT);
189
190 if (cmd == SIOCADDRT)
191 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
192 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
193
194 goto skip;
195 }
196
197 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
198
199 /* Make gateway. */
200 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
201 {
202 if ((cmd == SIOCADDRT
203 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
204 || (cmd == SIOCDELRT
205 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
206 {
207 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
208 {
209 if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
210 nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
211 {
212 sin_gate.sin_family = AF_INET;
213#ifdef HAVE_SIN_LEN
214 sin_gate.sin_len = sizeof (struct sockaddr_in);
215#endif /* HAVE_SIN_LEN */
216 sin_gate.sin_addr = nexthop->rgate.ipv4;
217 rtentry.rt_flags |= RTF_GATEWAY;
218 }
219 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
220 || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
221 {
222 ifp = if_lookup_by_index (nexthop->rifindex);
223 if (ifp)
224 rtentry.rt_dev = ifp->name;
225 else
226 return -1;
227 }
228 }
229 else
230 {
231 if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
232 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
233 {
234 sin_gate.sin_family = AF_INET;
235#ifdef HAVE_SIN_LEN
236 sin_gate.sin_len = sizeof (struct sockaddr_in);
237#endif /* HAVE_SIN_LEN */
238 sin_gate.sin_addr = nexthop->gate.ipv4;
239 rtentry.rt_flags |= RTF_GATEWAY;
240 }
241 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
242 || nexthop->type == NEXTHOP_TYPE_IFNAME)
243 {
244 ifp = if_lookup_by_index (nexthop->ifindex);
245 if (ifp)
246 rtentry.rt_dev = ifp->name;
247 else
248 return -1;
249 }
250 }
251
252 if (cmd == SIOCADDRT)
253 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
254
255 nexthop_num++;
256 break;
257 }
258 }
259
260 /* If there is no useful nexthop then return. */
261 if (nexthop_num == 0)
262 {
263 if (IS_ZEBRA_DEBUG_KERNEL)
b6178002 264 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
718e3744 265 return 0;
266 }
267
268 skip:
269
270 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
271 sin_mask.sin_family = AF_INET;
272#ifdef HAVE_SIN_LEN
273 sin_mask.sin_len = sizeof (struct sockaddr_in);
274#endif /* HAVE_SIN_LEN */
275 masklen2ip (p->prefixlen, &sin_mask.sin_addr);
276
277 /* Set destination address, mask and gateway.*/
278 memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
279
280 if (rtentry.rt_flags & RTF_GATEWAY)
281 memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
282
283#ifndef SUNOS_5
284 memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
285#endif /* SUNOS_5 */
286
287 /* Metric. It seems metric minus one value is installed... */
288 rtentry.rt_metric = rib->metric;
289
290 /* Routing entry flag set. */
291 if (p->prefixlen == 32)
292 rtentry.rt_flags |= RTF_HOST;
293
294 rtentry.rt_flags |= RTF_UP;
295
296 /* Additional flags */
297 /* rtentry.rt_flags |= flags; */
298
299 /* For tagging route. */
300 /* rtentry.rt_flags |= RTF_DYNAMIC; */
301
302 /* Open socket for ioctl. */
303 sock = socket (AF_INET, SOCK_DGRAM, 0);
304 if (sock < 0)
305 {
306 zlog_warn ("can't make socket\n");
307 return -1;
308 }
309
310 /* Send message by ioctl(). */
311 ret = ioctl (sock, cmd, &rtentry);
312 if (ret < 0)
313 {
314 switch (errno)
315 {
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;
328 }
329
330 close (sock);
6099b3b5 331 zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
718e3744 332 return ret;
333 }
334 close (sock);
335
336 return ret;
337}
338
339int
340kernel_add_ipv4 (struct prefix *p, struct rib *rib)
341{
342 return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
343}
344
345int
346kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
347{
348 return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
349}
350\f
351#ifdef HAVE_IPV6
352
353/* Below is hack for GNU libc definition and Linux 2.1.X header. */
354#undef RTF_DEFAULT
355#undef RTF_ADDRCONF
356
357#include <asm/types.h>
358
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
364
a1ac18c4 365static int
718e3744 366kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate,
367 int index, int flags)
368{
369 int ret;
370 int sock;
371 struct in6_rtmsg rtm;
372
373 memset (&rtm, 0, sizeof (struct in6_rtmsg));
374
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;
379
380 /* We need link local index. But this should be done caller...
381 if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
382 {
383 index = if_index_address (&rtm.rtmsg_gateway);
384 rtm.rtmsg_ifindex = index;
385 }
386 else
387 rtm.rtmsg_ifindex = 0;
388 */
389
390 rtm.rtmsg_flags |= RTF_GATEWAY;
391
392 /* For tagging route. */
393 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
394
395 memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr));
396
397 if (index)
398 rtm.rtmsg_ifindex = index;
399 else
400 rtm.rtmsg_ifindex = 0;
401
402 rtm.rtmsg_metric = 1;
403
404 sock = socket (AF_INET6, SOCK_DGRAM, 0);
405 if (sock < 0)
406 {
407 zlog_warn ("can't make socket\n");
408 return -1;
409 }
410
411 /* Send message via ioctl. */
412 ret = ioctl (sock, type, &rtm);
413 if (ret < 0)
414 {
415 zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete",
6099b3b5 416 safe_strerror(errno));
718e3744 417 ret = errno;
418 close (sock);
419 return ret;
420 }
421 close (sock);
422
423 return ret;
424}
425
a1ac18c4 426static int
718e3744 427kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
428 int family)
429{
430 int ret;
431 int sock;
432 struct in6_rtmsg rtm;
433 struct nexthop *nexthop;
434 int nexthop_num = 0;
435
436 memset (&rtm, 0, sizeof (struct in6_rtmsg));
437
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;
442
443 /* We need link local index. But this should be done caller...
444 if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
445 {
446 index = if_index_address (&rtm.rtmsg_gateway);
447 rtm.rtmsg_ifindex = index;
448 }
449 else
450 rtm.rtmsg_ifindex = 0;
451 */
452
453 rtm.rtmsg_flags |= RTF_GATEWAY;
454
455 /* For tagging route. */
456 /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
457
458 /* Make gateway. */
459 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
460 {
461 if ((cmd == SIOCADDRT
462 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
463 || (cmd == SIOCDELRT
464 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
465 {
466 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
467 {
468 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
469 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
470 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
471 {
472 memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6,
473 sizeof (struct in6_addr));
474 }
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;
482
483 }
484 else
485 {
486 if (nexthop->type == NEXTHOP_TYPE_IPV6
487 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
488 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
489 {
490 memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
491 sizeof (struct in6_addr));
492 }
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;
500 }
501
502 if (cmd == SIOCADDRT)
503 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
504
505 nexthop_num++;
506 break;
507 }
508 }
509
510 /* If there is no useful nexthop then return. */
511 if (nexthop_num == 0)
512 {
513 if (IS_ZEBRA_DEBUG_KERNEL)
b6178002 514 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
718e3744 515 return 0;
516 }
517
518 sock = socket (AF_INET6, SOCK_DGRAM, 0);
519 if (sock < 0)
520 {
521 zlog_warn ("can't make socket\n");
522 return -1;
523 }
524
525 /* Send message via ioctl. */
526 ret = ioctl (sock, cmd, &rtm);
527 if (ret < 0)
528 {
529 zlog_warn ("can't %s ipv6 route: %s\n",
530 cmd == SIOCADDRT ? "add" : "delete",
6099b3b5 531 safe_strerror(errno));
718e3744 532 ret = errno;
533 close (sock);
534 return ret;
535 }
536 close (sock);
537
538 return ret;
539}
540
541int
542kernel_add_ipv6 (struct prefix *p, struct rib *rib)
543{
544 return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
545}
546
547int
548kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
549{
550 return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
551}
552
553/* Delete IPv6 route from the kernel. */
554int
555kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
a1ac18c4 556 unsigned int index, int flags, int table)
718e3744 557{
558 return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
559}
560#endif /* HAVE_IPV6 */