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: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
45: /* Adjust netmask socket length. Return value is a adjusted sin_len
46: value. */
47: static int
48: sin_masklen (struct in_addr mask)
49: {
50: char *p, *lim;
51: int len;
52: struct sockaddr_in sin;
53:
54: if (mask.s_addr == 0)
55: return sizeof (long);
56:
57: sin.sin_addr = mask;
58: len = sizeof (struct sockaddr_in);
59:
60: lim = (char *) &sin.sin_addr;
61: p = lim + sizeof (sin.sin_addr);
62:
63: while (*--p == 0 && p >= lim)
64: len--;
65: return len;
66: }
67: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
68:
69: /* Interface between zebra message and rtm message. */
70: static int
71: kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib)
72:
73: {
74: struct sockaddr_in *mask = NULL;
75: struct sockaddr_in sin_dest, sin_mask, sin_gate;
76: struct nexthop *nexthop, *tnexthop;
77: int recursing;
78: int nexthop_num = 0;
79: ifindex_t ifindex = 0;
80: int gate = 0;
81: int error;
82: char prefix_buf[PREFIX_STRLEN];
83:
84: if (IS_ZEBRA_DEBUG_RIB)
85: prefix2str (p, prefix_buf, sizeof(prefix_buf));
86: memset (&sin_dest, 0, sizeof (struct sockaddr_in));
87: sin_dest.sin_family = AF_INET;
88: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
89: sin_dest.sin_len = sizeof (struct sockaddr_in);
90: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
91: sin_dest.sin_addr = p->u.prefix4;
92:
93: memset (&sin_mask, 0, sizeof (struct sockaddr_in));
94:
95: memset (&sin_gate, 0, sizeof (struct sockaddr_in));
96: sin_gate.sin_family = AF_INET;
97: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
98: sin_gate.sin_len = sizeof (struct sockaddr_in);
99: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
100:
101: /* Make gateway. */
102: for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
103: {
104: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
105: continue;
106:
107: gate = 0;
108: char gate_buf[INET_ADDRSTRLEN] = "NULL";
109:
110: /*
111: * XXX We need to refrain from kernel operations in some cases,
112: * but this if statement seems overly cautious - what about
113: * other than ADD and DELETE?
114: */
115: if ((cmd == RTM_ADD
116: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
117: || (cmd == RTM_DELETE
118: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
119: ))
120: {
121: if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
122: nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
123: {
124: sin_gate.sin_addr = nexthop->gate.ipv4;
125: gate = 1;
126: }
127: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
128: || nexthop->type == NEXTHOP_TYPE_IFNAME
129: || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
130: ifindex = nexthop->ifindex;
131: if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
132: {
133: struct in_addr loopback;
134: loopback.s_addr = htonl (INADDR_LOOPBACK);
135: sin_gate.sin_addr = loopback;
136: gate = 1;
137: }
138:
139: if (gate && p->prefixlen == 32)
140: mask = NULL;
141: else
142: {
143: masklen2ip (p->prefixlen, &sin_mask.sin_addr);
144: sin_mask.sin_family = AF_INET;
145: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
146: sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
147: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
148: mask = &sin_mask;
149: }
150:
151: error = rtm_write (cmd,
152: (union sockunion *)&sin_dest,
153: (union sockunion *)mask,
154: gate ? (union sockunion *)&sin_gate : NULL,
155: ifindex,
156: rib->flags,
157: rib->metric);
158:
159: if (IS_ZEBRA_DEBUG_RIB)
160: {
161: if (!gate)
162: {
163: zlog_debug ("%s: %s: attention! gate not found for rib %p",
164: __func__, prefix_buf, rib);
165: rib_dump (p, rib);
166: }
167: else
168: inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN);
169: }
170:
171: switch (error)
172: {
173: /* We only flag nexthops as being in FIB if rtm_write() did its work. */
174: case ZEBRA_ERR_NOERROR:
175: nexthop_num++;
176: if (IS_ZEBRA_DEBUG_RIB)
177: zlog_debug ("%s: %s: successfully did NH %s",
178: __func__, prefix_buf, gate_buf);
179: if (cmd == RTM_ADD)
180: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
181: break;
182:
183: /* The only valid case for this error is kernel's failure to install
184: * a multipath route, which is common for FreeBSD. This should be
185: * ignored silently, but logged as an error otherwise.
186: */
187: case ZEBRA_ERR_RTEXIST:
188: if (cmd != RTM_ADD)
189: zlog_err ("%s: rtm_write() returned %d for command %d",
190: __func__, error, cmd);
191: continue;
192: break;
193:
194: /* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't
195: * normal to get any other messages in ANY case.
196: */
197: case ZEBRA_ERR_RTNOEXIST:
198: case ZEBRA_ERR_RTUNREACH:
199: default:
200: zlog_err ("%s: %s: rtm_write() unexpectedly returned %d for command %s",
201: __func__, prefix2str(p, prefix_buf, sizeof(prefix_buf)),
202: error, lookup (rtm_type_str, cmd));
203: break;
204: }
205: } /* if (cmd and flags make sense) */
206: else
207: if (IS_ZEBRA_DEBUG_RIB)
208: zlog_debug ("%s: odd command %s for flags %d",
209: __func__, lookup (rtm_type_str, cmd), nexthop->flags);
210: } /* for (ALL_NEXTHOPS_RO(...))*/
211:
212: /* If there was no useful nexthop, then complain. */
213: if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL)
214: zlog_debug ("%s: No useful nexthops were found in RIB entry %p", __func__, rib);
215:
216: return 0; /*XXX*/
217: }
218:
219: #ifdef HAVE_IPV6
220:
221: #ifdef SIN6_LEN
222: /* Calculate sin6_len value for netmask socket value. */
223: static int
224: sin6_masklen (struct in6_addr mask)
225: {
226: struct sockaddr_in6 sin6;
227: char *p, *lim;
228: int len;
229:
230: if (IN6_IS_ADDR_UNSPECIFIED (&mask))
231: return sizeof (long);
232:
233: sin6.sin6_addr = mask;
234: len = sizeof (struct sockaddr_in6);
235:
236: lim = (char *) & sin6.sin6_addr;
237: p = lim + sizeof (sin6.sin6_addr);
238:
239: while (*--p == 0 && p >= lim)
240: len--;
241:
242: return len;
243: }
244: #endif /* SIN6_LEN */
245:
246: /* Interface between zebra message and rtm message. */
247: static int
248: kernel_rtm_ipv6 (int cmd, struct prefix *p, struct rib *rib)
249: {
250: struct sockaddr_in6 *mask;
251: struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
252: struct nexthop *nexthop, *tnexthop;
253: int recursing;
254: int nexthop_num = 0;
255: ifindex_t ifindex = 0;
256: int gate = 0;
257: int error;
258:
259: memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
260: sin_dest.sin6_family = AF_INET6;
261: #ifdef SIN6_LEN
262: sin_dest.sin6_len = sizeof (struct sockaddr_in6);
263: #endif /* SIN6_LEN */
264: sin_dest.sin6_addr = p->u.prefix6;
265:
266: memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
267:
268: memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
269: sin_gate.sin6_family = AF_INET6;
270: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
271: sin_gate.sin6_len = sizeof (struct sockaddr_in6);
272: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
273:
274: /* Make gateway. */
275: for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
276: {
277: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
278: continue;
279:
280: gate = 0;
281:
282: if ((cmd == RTM_ADD
283: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
284: || (cmd == RTM_DELETE
285: #if 0
286: && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
287: #endif
288: ))
289: {
290: if (nexthop->type == NEXTHOP_TYPE_IPV6
291: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
292: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
293: {
294: sin_gate.sin6_addr = nexthop->gate.ipv6;
295: gate = 1;
296: }
297: if (nexthop->type == NEXTHOP_TYPE_IFINDEX
298: || nexthop->type == NEXTHOP_TYPE_IFNAME
299: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
300: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
301: ifindex = nexthop->ifindex;
302:
303: if (cmd == RTM_ADD)
304: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
305: }
306:
307: /* Under kame set interface index to link local address. */
308: #ifdef KAME
309:
310: #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
311: do { \
312: (a).s6_addr[2] = ((i) >> 8) & 0xff; \
313: (a).s6_addr[3] = (i) & 0xff; \
314: } while (0)
315:
316: if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
317: SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
318: #endif /* KAME */
319:
320: if (gate && p->prefixlen == 128)
321: mask = NULL;
322: else
323: {
324: masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
325: sin_mask.sin6_family = AF_INET6;
326: #ifdef SIN6_LEN
327: sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
328: #endif /* SIN6_LEN */
329: mask = &sin_mask;
330: }
331:
332: error = rtm_write (cmd,
333: (union sockunion *) &sin_dest,
334: (union sockunion *) mask,
335: gate ? (union sockunion *)&sin_gate : NULL,
336: ifindex,
337: rib->flags,
338: rib->metric);
339:
340: #if 0
341: if (error)
342: {
343: zlog_info ("kernel_rtm_ipv6(): nexthop %d add error=%d.",
344: nexthop_num, error);
345: }
346: #else
347: (void)error;
348: #endif
349:
350: nexthop_num++;
351: }
352:
353: /* If there is no useful nexthop then return. */
354: if (nexthop_num == 0)
355: {
356: if (IS_ZEBRA_DEBUG_KERNEL)
357: zlog_debug ("kernel_rtm_ipv6(): No useful nexthop.");
358: return 0;
359: }
360:
361: return 0; /*XXX*/
362: }
363:
364: #endif
365:
366: static int
367: kernel_rtm (int cmd, struct prefix *p, struct rib *rib)
368: {
369: switch (PREFIX_FAMILY(p))
370: {
371: case AF_INET:
372: return kernel_rtm_ipv4 (cmd, p, rib);
373: case AF_INET6:
374: return kernel_rtm_ipv6 (cmd, p, rib);
375: }
376: return 0;
377: }
378:
379: int
380: kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new)
381: {
382: int route = 0;
383:
384: if (zserv_privs.change(ZPRIVS_RAISE))
385: zlog (NULL, LOG_ERR, "Can't raise privileges");
386:
387: if (old)
388: route |= kernel_rtm (RTM_DELETE, p, old);
389:
390: if (new)
391: route |= kernel_rtm (RTM_ADD, p, new);
392:
393: if (zserv_privs.change(ZPRIVS_LOWER))
394: zlog (NULL, LOG_ERR, "Can't lower privileges");
395:
396: return route;
397: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>