1: /*
2: * Kernel routing table updates by routing socket.
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 "if.h"
26: #include "prefix.h"
27: #include "sockunion.h"
28: #include "log.h"
29: #include "str.h"
30: #include "privs.h"
31:
32: #include "zebra/debug.h"
33: #include "zebra/rib.h"
34: #include "zebra/rt.h"
35: #include "zebra/kernel_socket.h"
36:
37: extern struct zebra_privs_t zserv_privs;
38:
39: /* kernel socket export */
40: extern int rtm_write (int message, union sockunion *dest,
41: union sockunion *mask, union sockunion *gate,
42: unsigned int index, int zebra_flags, int metric);
43:
44: /* Adjust netmask socket length. Return value is a adjusted sin_len
45: value. */
46: static int
47: sin_masklen (struct in_addr mask)
48: {
49: char *p, *lim;
50: int len;
51: struct sockaddr_in sin;
52:
53: if (mask.s_addr == 0)
54: return sizeof (long);
55:
56: sin.sin_addr = mask;
57: len = sizeof (struct sockaddr_in);
58:
59: lim = (char *) &sin.sin_addr;
60: p = lim + sizeof (sin.sin_addr);
61:
62: while (*--p == 0 && p >= lim)
63: len--;
64: return len;
65: }
66:
67: /* Interface between zebra message and rtm message. */
68: static int
69: kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
70:
71: {
72: struct sockaddr_in *mask = NULL;
73: struct sockaddr_in sin_dest, sin_mask, sin_gate;
74: struct nexthop *nexthop;
75: int nexthop_num = 0;
76: unsigned int ifindex = 0;
77: int gate = 0;
78: int error;
79: char prefix_buf[INET_ADDRSTRLEN];
80:
81: if (IS_ZEBRA_DEBUG_RIB)
82: inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN);
83: memset (&sin_dest, 0, sizeof (struct sockaddr_in));
84: sin_dest.sin_family = AF_INET;
85: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
86: sin_dest.sin_len = sizeof (struct sockaddr_in);
87: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
88: sin_dest.sin_addr = p->u.prefix4;
89:
90: memset (&sin_mask, 0, sizeof (struct sockaddr_in));
91:
92: memset (&sin_gate, 0, sizeof (struct sockaddr_in));
93: sin_gate.sin_family = AF_INET;
94: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
95: sin_gate.sin_len = sizeof (struct sockaddr_in);
96: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
97:
98: /* Make gateway. */
99: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
100: {
101: gate = 0;
102: char gate_buf[INET_ADDRSTRLEN] = "NULL";
103:
104: /*
105: * XXX We need to refrain from kernel operations in some cases,
106: * but this if statement seems overly cautious - what about
107: * other than ADD and DELETE?
108: */
109: if ((cmd == RTM_ADD
110: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
111: || (cmd == RTM_DELETE
112: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
113: ))
114: {
115: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
116: {
117: if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
118: nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
119: {
120: sin_gate.sin_addr = nexthop->rgate.ipv4;
121: gate = 1;
122: }
123: if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
124: || nexthop->rtype == NEXTHOP_TYPE_IFNAME
125: || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
126: ifindex = nexthop->rifindex;
127: }
128: else
129: {
130: if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
131: nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
132: {
133: sin_gate.sin_addr = nexthop->gate.ipv4;
134: gate = 1;
135: }
136: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
137: || nexthop->type == NEXTHOP_TYPE_IFNAME
138: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
139: ifindex = nexthop->ifindex;
140: if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
141: {
142: struct in_addr loopback;
143: loopback.s_addr = htonl (INADDR_LOOPBACK);
144: sin_gate.sin_addr = loopback;
145: gate = 1;
146: }
147: }
148:
149: if (gate && p->prefixlen == 32)
150: mask = NULL;
151: else
152: {
153: masklen2ip (p->prefixlen, &sin_mask.sin_addr);
154: sin_mask.sin_family = AF_INET;
155: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
156: sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
157: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
158: mask = &sin_mask;
159: }
160:
161: error = rtm_write (cmd,
162: (union sockunion *)&sin_dest,
163: (union sockunion *)mask,
164: gate ? (union sockunion *)&sin_gate : NULL,
165: ifindex,
166: rib->flags,
167: rib->metric);
168:
169: if (IS_ZEBRA_DEBUG_RIB)
170: {
171: if (!gate)
172: {
173: zlog_debug ("%s: %s/%d: attention! gate not found for rib %p",
174: __func__, prefix_buf, p->prefixlen, rib);
175: rib_dump (__func__, (struct prefix_ipv4 *)p, rib);
176: }
177: else
178: inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN);
179: }
180:
181: switch (error)
182: {
183: /* We only flag nexthops as being in FIB if rtm_write() did its work. */
184: case ZEBRA_ERR_NOERROR:
185: nexthop_num++;
186: if (IS_ZEBRA_DEBUG_RIB)
187: zlog_debug ("%s: %s/%d: successfully did NH %s",
188: __func__, prefix_buf, p->prefixlen, gate_buf);
189: if (cmd == RTM_ADD)
190: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
191: break;
192:
193: /* The only valid case for this error is kernel's failure to install
194: * a multipath route, which is common for FreeBSD. This should be
195: * ignored silently, but logged as an error otherwise.
196: */
197: case ZEBRA_ERR_RTEXIST:
198: if (cmd != RTM_ADD)
199: zlog_err ("%s: rtm_write() returned %d for command %d",
200: __func__, error, cmd);
201: continue;
202: break;
203:
204: /* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't
205: * normal to get any other messages in ANY case.
206: */
207: case ZEBRA_ERR_RTNOEXIST:
208: case ZEBRA_ERR_RTUNREACH:
209: default:
210: /* This point is reachable regardless of debugging mode. */
211: if (!IS_ZEBRA_DEBUG_RIB)
212: inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN);
213: zlog_err ("%s: %s/%d: rtm_write() unexpectedly returned %d for command %s",
214: __func__, prefix_buf, p->prefixlen, error, lookup (rtm_type_str, cmd));
215: break;
216: }
217: } /* if (cmd and flags make sense) */
218: else
219: if (IS_ZEBRA_DEBUG_RIB)
220: zlog_debug ("%s: odd command %s for flags %d",
221: __func__, lookup (rtm_type_str, cmd), nexthop->flags);
222: } /* for (nexthop = ... */
223:
224: /* If there was no useful nexthop, then complain. */
225: if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL)
226: zlog_debug ("%s: No useful nexthops were found in RIB entry %p", __func__, rib);
227:
228: return 0; /*XXX*/
229: }
230:
231: int
232: kernel_add_ipv4 (struct prefix *p, struct rib *rib)
233: {
234: int route;
235:
236: if (zserv_privs.change(ZPRIVS_RAISE))
237: zlog (NULL, LOG_ERR, "Can't raise privileges");
238: route = kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
239: if (zserv_privs.change(ZPRIVS_LOWER))
240: zlog (NULL, LOG_ERR, "Can't lower privileges");
241:
242: return route;
243: }
244:
245: int
246: kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
247: {
248: int route;
249:
250: if (zserv_privs.change(ZPRIVS_RAISE))
251: zlog (NULL, LOG_ERR, "Can't raise privileges");
252: route = kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
253: if (zserv_privs.change(ZPRIVS_LOWER))
254: zlog (NULL, LOG_ERR, "Can't lower privileges");
255:
256: return route;
257: }
258:
259: #ifdef HAVE_IPV6
260:
261: /* Calculate sin6_len value for netmask socket value. */
262: static int
263: sin6_masklen (struct in6_addr mask)
264: {
265: struct sockaddr_in6 sin6;
266: char *p, *lim;
267: int len;
268:
269: #if defined (INRIA)
270: if (IN_ANYADDR6 (mask))
271: return sizeof (long);
272: #else /* ! INRIA */
273: if (IN6_IS_ADDR_UNSPECIFIED (&mask))
274: return sizeof (long);
275: #endif /* ! INRIA */
276:
277: sin6.sin6_addr = mask;
278: len = sizeof (struct sockaddr_in6);
279:
280: lim = (char *) & sin6.sin6_addr;
281: p = lim + sizeof (sin6.sin6_addr);
282:
283: while (*--p == 0 && p >= lim)
284: len--;
285:
286: return len;
287: }
288:
289: /* Interface between zebra message and rtm message. */
290: static int
291: kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
292: struct in6_addr *gate, int index, int flags)
293: {
294: struct sockaddr_in6 *mask;
295: struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
296:
297: memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
298: sin_dest.sin6_family = AF_INET6;
299: #ifdef SIN6_LEN
300: sin_dest.sin6_len = sizeof (struct sockaddr_in6);
301: #endif /* SIN6_LEN */
302:
303: memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
304:
305: memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
306: sin_gate.sin6_family = AF_INET6;
307: #ifdef SIN6_LEN
308: sin_gate.sin6_len = sizeof (struct sockaddr_in6);
309: #endif /* SIN6_LEN */
310:
311: sin_dest.sin6_addr = dest->prefix;
312:
313: if (gate)
314: memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
315:
316: /* Under kame set interface index to link local address. */
317: #ifdef KAME
318:
319: #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
320: do { \
321: (a).s6_addr[2] = ((i) >> 8) & 0xff; \
322: (a).s6_addr[3] = (i) & 0xff; \
323: } while (0)
324:
325: if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
326: SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
327: #endif /* KAME */
328:
329: if (gate && dest->prefixlen == 128)
330: mask = NULL;
331: else
332: {
333: masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
334: sin_mask.sin6_family = AF_INET6;
335: #ifdef SIN6_LEN
336: sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
337: #endif /* SIN6_LEN */
338: mask = &sin_mask;
339: }
340:
341: return rtm_write (message,
342: (union sockunion *) &sin_dest,
343: (union sockunion *) mask,
344: gate ? (union sockunion *)&sin_gate : NULL,
345: index,
346: flags,
347: 0);
348: }
349:
350: /* Interface between zebra message and rtm message. */
351: static int
352: kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
353: int family)
354: {
355: struct sockaddr_in6 *mask;
356: struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
357: struct nexthop *nexthop;
358: int nexthop_num = 0;
359: unsigned int ifindex = 0;
360: int gate = 0;
361: int error;
362:
363: memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
364: sin_dest.sin6_family = AF_INET6;
365: #ifdef SIN6_LEN
366: sin_dest.sin6_len = sizeof (struct sockaddr_in6);
367: #endif /* SIN6_LEN */
368: sin_dest.sin6_addr = p->u.prefix6;
369:
370: memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
371:
372: memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
373: sin_gate.sin6_family = AF_INET6;
374: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
375: sin_gate.sin6_len = sizeof (struct sockaddr_in6);
376: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
377:
378: /* Make gateway. */
379: for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
380: {
381: gate = 0;
382:
383: if ((cmd == RTM_ADD
384: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
385: || (cmd == RTM_DELETE
386: #if 0
387: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
388: #endif
389: ))
390: {
391: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
392: {
393: if (nexthop->rtype == NEXTHOP_TYPE_IPV6
394: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
395: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
396: {
397: sin_gate.sin6_addr = nexthop->rgate.ipv6;
398: gate = 1;
399: }
400: if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
401: || nexthop->rtype == NEXTHOP_TYPE_IFNAME
402: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
403: || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
404: ifindex = nexthop->rifindex;
405: }
406: else
407: {
408: if (nexthop->type == NEXTHOP_TYPE_IPV6
409: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
410: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
411: {
412: sin_gate.sin6_addr = nexthop->gate.ipv6;
413: gate = 1;
414: }
415: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
416: || nexthop->type == NEXTHOP_TYPE_IFNAME
417: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
418: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
419: ifindex = nexthop->ifindex;
420: }
421:
422: if (cmd == RTM_ADD)
423: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
424: }
425:
426: /* Under kame set interface index to link local address. */
427: #ifdef KAME
428:
429: #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
430: do { \
431: (a).s6_addr[2] = ((i) >> 8) & 0xff; \
432: (a).s6_addr[3] = (i) & 0xff; \
433: } while (0)
434:
435: if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
436: SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
437: #endif /* KAME */
438:
439: if (gate && p->prefixlen == 128)
440: mask = NULL;
441: else
442: {
443: masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
444: sin_mask.sin6_family = AF_INET6;
445: #ifdef SIN6_LEN
446: sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
447: #endif /* SIN6_LEN */
448: mask = &sin_mask;
449: }
450:
451: error = rtm_write (cmd,
452: (union sockunion *) &sin_dest,
453: (union sockunion *) mask,
454: gate ? (union sockunion *)&sin_gate : NULL,
455: ifindex,
456: rib->flags,
457: rib->metric);
458:
459: #if 0
460: if (error)
461: {
462: zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
463: nexthop_num, error);
464: }
465: #endif
466:
467: nexthop_num++;
468: }
469:
470: /* If there is no useful nexthop then return. */
471: if (nexthop_num == 0)
472: {
473: if (IS_ZEBRA_DEBUG_KERNEL)
474: zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
475: return 0;
476: }
477:
478: return 0; /*XXX*/
479: }
480:
481: int
482: kernel_add_ipv6 (struct prefix *p, struct rib *rib)
483: {
484: int route;
485:
486: if (zserv_privs.change(ZPRIVS_RAISE))
487: zlog (NULL, LOG_ERR, "Can't raise privileges");
488: route = kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
489: if (zserv_privs.change(ZPRIVS_LOWER))
490: zlog (NULL, LOG_ERR, "Can't lower privileges");
491:
492: return route;
493: }
494:
495: int
496: kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
497: {
498: int route;
499:
500: if (zserv_privs.change(ZPRIVS_RAISE))
501: zlog (NULL, LOG_ERR, "Can't raise privileges");
502: route = kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
503: if (zserv_privs.change(ZPRIVS_LOWER))
504: zlog (NULL, LOG_ERR, "Can't lower privileges");
505:
506: return route;
507: }
508:
509: /* Delete IPv6 route from the kernel. */
510: int
511: kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
512: unsigned int index, int flags, int table)
513: {
514: int route;
515:
516: if (zserv_privs.change(ZPRIVS_RAISE))
517: zlog (NULL, LOG_ERR, "Can't raise privileges");
518: route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
519: if (zserv_privs.change(ZPRIVS_LOWER))
520: zlog (NULL, LOG_ERR, "Can't lower privileges");
521:
522: return route;
523: }
524: #endif /* HAVE_IPV6 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>