Annotation of embedaddon/quagga/zebra/rt_socket.c, revision 1.1.1.2
1.1 misho 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:
1.1.1.2 ! misho 44: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
1.1 misho 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: }
1.1.1.2 ! misho 67: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
1.1 misho 68:
69: /* Interface between zebra message and rtm message. */
70: static int
1.1.1.2 ! misho 71: kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib)
1.1 misho 72:
73: {
74: struct sockaddr_in *mask = NULL;
75: struct sockaddr_in sin_dest, sin_mask, sin_gate;
1.1.1.2 ! misho 76: struct nexthop *nexthop, *tnexthop;
! 77: int recursing;
1.1 misho 78: int nexthop_num = 0;
1.1.1.2 ! misho 79: ifindex_t ifindex = 0;
1.1 misho 80: int gate = 0;
81: int error;
1.1.1.2 ! misho 82: char prefix_buf[PREFIX_STRLEN];
1.1 misho 83:
84: if (IS_ZEBRA_DEBUG_RIB)
1.1.1.2 ! misho 85: prefix2str (p, prefix_buf, sizeof(prefix_buf));
1.1 misho 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. */
1.1.1.2 ! misho 102: for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1.1 misho 103: {
1.1.1.2 ! misho 104: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 105: continue;
! 106:
1.1 misho 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: {
1.1.1.2 ! misho 121: if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
! 122: nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
1.1 misho 123: {
1.1.1.2 ! misho 124: sin_gate.sin_addr = nexthop->gate.ipv4;
! 125: gate = 1;
1.1 misho 126: }
1.1.1.2 ! misho 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)
1.1 misho 132: {
1.1.1.2 ! misho 133: struct in_addr loopback;
! 134: loopback.s_addr = htonl (INADDR_LOOPBACK);
! 135: sin_gate.sin_addr = loopback;
! 136: gate = 1;
1.1 misho 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: {
1.1.1.2 ! misho 163: zlog_debug ("%s: %s: attention! gate not found for rib %p",
! 164: __func__, prefix_buf, rib);
! 165: rib_dump (p, rib);
1.1 misho 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)
1.1.1.2 ! misho 177: zlog_debug ("%s: %s: successfully did NH %s",
! 178: __func__, prefix_buf, gate_buf);
1.1 misho 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:
1.1.1.2 ! misho 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));
1.1 misho 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);
1.1.1.2 ! misho 210: } /* for (ALL_NEXTHOPS_RO(...))*/
1.1 misho 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:
1.1.1.2 ! misho 221: #ifdef SIN6_LEN
1.1 misho 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
1.1.1.2 ! misho 248: kernel_rtm_ipv6 (int cmd, struct prefix *p, struct rib *rib)
1.1 misho 249: {
250: struct sockaddr_in6 *mask;
251: struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
1.1.1.2 ! misho 252: struct nexthop *nexthop, *tnexthop;
! 253: int recursing;
1.1 misho 254: int nexthop_num = 0;
1.1.1.2 ! misho 255: ifindex_t ifindex = 0;
1.1 misho 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. */
1.1.1.2 ! misho 275: for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1.1 misho 276: {
1.1.1.2 ! misho 277: if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
! 278: continue;
! 279:
1.1 misho 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: {
1.1.1.2 ! misho 290: if (nexthop->type == NEXTHOP_TYPE_IPV6
! 291: || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
! 292: || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
1.1 misho 293: {
1.1.1.2 ! misho 294: sin_gate.sin6_addr = nexthop->gate.ipv6;
! 295: gate = 1;
1.1 misho 296: }
1.1.1.2 ! misho 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;
1.1 misho 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: {
1.1.1.2 ! misho 343: zlog_info ("kernel_rtm_ipv6(): nexthop %d add error=%d.",
1.1 misho 344: nexthop_num, error);
345: }
1.1.1.2 ! misho 346: #else
! 347: (void)error;
1.1 misho 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)
1.1.1.2 ! misho 357: zlog_debug ("kernel_rtm_ipv6(): No useful nexthop.");
1.1 misho 358: return 0;
359: }
360:
361: return 0; /*XXX*/
362: }
363:
1.1.1.2 ! misho 364: #endif
1.1 misho 365:
1.1.1.2 ! misho 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;
1.1 misho 377: }
378:
379: int
1.1.1.2 ! misho 380: kernel_route_rib (struct prefix *p, struct rib *old, struct rib *new)
1.1 misho 381: {
1.1.1.2 ! misho 382: int route = 0;
1.1 misho 383:
384: if (zserv_privs.change(ZPRIVS_RAISE))
385: zlog (NULL, LOG_ERR, "Can't raise privileges");
386:
1.1.1.2 ! misho 387: if (old)
! 388: route |= kernel_rtm (RTM_DELETE, p, old);
1.1 misho 389:
1.1.1.2 ! misho 390: if (new)
! 391: route |= kernel_rtm (RTM_ADD, p, new);
1.1 misho 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>