Annotation of embedaddon/quagga/zebra/rt_ioctl.c, revision 1.1.1.1
1.1 misho 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:
29: #include "zebra/zserv.h"
30: #include "zebra/rib.h"
31: #include "zebra/debug.h"
32: #include "zebra/rt.h"
33:
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)
38: {
39: return;
40: }
41:
42: /* Dummy function of routing socket. */
43: static void
44: kernel_read (int sock)
45: {
46: return;
47: }
48:
49: #if 0
50: /* Initialization prototype of struct sockaddr_in. */
51: static struct sockaddr_in sin_proto =
52: {
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}
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. */
66: int
67: kernel_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_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;
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_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;
94: }
95:
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);
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);
156: zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
157: return 1;
158: }
159: close (sock);
160:
161: return ret;
162: }
163:
164: /* Interface to ioctl route message. */
165: static int
166: kernel_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_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;
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_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;
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_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;
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)
264: zlog_debug ("netlink_route_multipath(): No useful nexthop.");
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_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);
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);
331: zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
332: return ret;
333: }
334: close (sock);
335:
336: return ret;
337: }
338:
339: int
340: kernel_add_ipv4 (struct prefix *p, struct rib *rib)
341: {
342: return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
343: }
344:
345: int
346: kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
347: {
348: return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
349: }
350:
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:
365: static int
366: kernel_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",
416: safe_strerror(errno));
417: ret = errno;
418: close (sock);
419: return ret;
420: }
421: close (sock);
422:
423: return ret;
424: }
425:
426: static int
427: kernel_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)
514: zlog_debug ("netlink_route_multipath(): No useful nexthop.");
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",
531: safe_strerror(errno));
532: ret = errno;
533: close (sock);
534: return ret;
535: }
536: close (sock);
537:
538: return ret;
539: }
540:
541: int
542: kernel_add_ipv6 (struct prefix *p, struct rib *rib)
543: {
544: return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
545: }
546:
547: int
548: kernel_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. */
554: int
555: kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
556: unsigned int index, int flags, int table)
557: {
558: return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
559: }
560: #endif /* HAVE_IPV6 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>