blob: 5b2a5e716641430fe5ab357d0365ae2c34237c30 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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"
pauledd7c242003-06-04 13:59:38 +000030#include "privs.h"
paul718e3742002-12-13 20:15:29 +000031
32#include "zebra/debug.h"
33#include "zebra/rib.h"
34
pauledd7c242003-06-04 13:59:38 +000035extern struct zebra_privs_t zserv_privs;
36
paul718e3742002-12-13 20:15:29 +000037int
38rtm_write (int message,
39 union sockunion *dest,
40 union sockunion *mask,
41 union sockunion *gate,
42 unsigned int index,
43 int zebra_flags,
44 int metric);
45
46/* Adjust netmask socket length. Return value is a adjusted sin_len
47 value. */
48int
49sin_masklen (struct in_addr mask)
50{
51 char *p, *lim;
52 int len;
53 struct sockaddr_in sin;
54
55 if (mask.s_addr == 0)
56 return sizeof (long);
57
58 sin.sin_addr = mask;
59 len = sizeof (struct sockaddr_in);
60
61 lim = (char *) &sin.sin_addr;
62 p = lim + sizeof (sin.sin_addr);
63
64 while (*--p == 0 && p >= lim)
65 len--;
66 return len;
67}
68
69/* Interface between zebra message and rtm message. */
70int
71kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
72
73{
hassofa2b17e2004-03-04 17:45:00 +000074 struct sockaddr_in *mask = NULL;
paul718e3742002-12-13 20:15:29 +000075 struct sockaddr_in sin_dest, sin_mask, sin_gate;
76 struct nexthop *nexthop;
77 int nexthop_num = 0;
78 unsigned int ifindex = 0;
79 int gate = 0;
80 int error;
81
82 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
83 sin_dest.sin_family = AF_INET;
84#ifdef HAVE_SIN_LEN
85 sin_dest.sin_len = sizeof (struct sockaddr_in);
86#endif /* HAVE_SIN_LEN */
87 sin_dest.sin_addr = p->u.prefix4;
88
89 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
90
91 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
92 sin_gate.sin_family = AF_INET;
93#ifdef HAVE_SIN_LEN
94 sin_gate.sin_len = sizeof (struct sockaddr_in);
95#endif /* HAVE_SIN_LEN */
96
97 /* Make gateway. */
98 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
99 {
100 gate = 0;
101
102 if ((cmd == RTM_ADD
103 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
104 || (cmd == RTM_DELETE
105#if 0
106 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
107#endif
108 ))
109 {
110 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
111 {
112 if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
113 nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
114 {
115 sin_gate.sin_addr = nexthop->rgate.ipv4;
116 gate = 1;
117 }
118 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
119 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
120 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
121 ifindex = nexthop->rifindex;
122 }
123 else
124 {
125 if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
126 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
127 {
128 sin_gate.sin_addr = nexthop->gate.ipv4;
129 gate = 1;
130 }
131 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
132 || nexthop->type == NEXTHOP_TYPE_IFNAME
133 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
134 ifindex = nexthop->ifindex;
paul595db7f2003-05-25 21:35:06 +0000135 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
136 {
137 struct in_addr loopback;
138 loopback.s_addr = htonl (INADDR_LOOPBACK);
139 sin_gate.sin_addr = loopback;
140 gate = 1;
141 }
142 }
paul718e3742002-12-13 20:15:29 +0000143
144 if (cmd == RTM_ADD)
145 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
146
147 if (gate && p->prefixlen == 32)
148 mask = NULL;
149 else
150 {
151 masklen2ip (p->prefixlen, &sin_mask.sin_addr);
152 sin_mask.sin_family = AF_UNSPEC;
153#ifdef HAVE_SIN_LEN
154 sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
155#endif /* HAVE_SIN_LEN */
156 mask = &sin_mask;
157 }
158 }
159
160 error = rtm_write (cmd,
161 (union sockunion *)&sin_dest,
162 (union sockunion *)mask,
163 gate ? (union sockunion *)&sin_gate : NULL,
164 ifindex,
165 rib->flags,
166 rib->metric);
167
168#if 0
169 if (error)
170 {
171 zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
172 nexthop_num, error);
173 }
174#endif
175
176 nexthop_num++;
177 }
178
179 /* If there is no useful nexthop then return. */
180 if (nexthop_num == 0)
181 {
182 if (IS_ZEBRA_DEBUG_KERNEL)
183 zlog_info ("kernel_rtm_ipv4(): No useful nexthop.");
184 return 0;
185 }
186
187 return 0; /*XXX*/
188}
189
190int
191kernel_add_ipv4 (struct prefix *p, struct rib *rib)
192{
pauledd7c242003-06-04 13:59:38 +0000193 int route;
194
195 if (zserv_privs.change(ZPRIVS_RAISE))
196 zlog (NULL, LOG_ERR, "Can't raise privileges");
197 route = kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
198 if (zserv_privs.change(ZPRIVS_LOWER))
199 zlog (NULL, LOG_ERR, "Can't lower privileges");
200
201 return route;
paul718e3742002-12-13 20:15:29 +0000202}
203
204int
205kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
206{
pauledd7c242003-06-04 13:59:38 +0000207 int route;
208
209 if (zserv_privs.change(ZPRIVS_RAISE))
210 zlog (NULL, LOG_ERR, "Can't raise privileges");
211 route = kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
212 if (zserv_privs.change(ZPRIVS_LOWER))
213 zlog (NULL, LOG_ERR, "Can't lower privileges");
214
215 return route;
paul718e3742002-12-13 20:15:29 +0000216}
217
218#ifdef HAVE_IPV6
219
220/* Calculate sin6_len value for netmask socket value. */
221int
222sin6_masklen (struct in6_addr mask)
223{
224 struct sockaddr_in6 sin6;
225 char *p, *lim;
226 int len;
227
228#if defined (INRIA)
229 if (IN_ANYADDR6 (mask))
230 return sizeof (long);
231#else /* ! INRIA */
232 if (IN6_IS_ADDR_UNSPECIFIED (&mask))
233 return sizeof (long);
234#endif /* ! INRIA */
235
236 sin6.sin6_addr = mask;
237 len = sizeof (struct sockaddr_in6);
238
239 lim = (char *) & sin6.sin6_addr;
240 p = lim + sizeof (sin6.sin6_addr);
241
242 while (*--p == 0 && p >= lim)
243 len--;
244
245 return len;
246}
247
248/* Interface between zebra message and rtm message. */
249int
250kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
251 struct in6_addr *gate, int index, int flags)
252{
253 struct sockaddr_in6 *mask;
254 struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
255
256 memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
257 sin_dest.sin6_family = AF_INET6;
258#ifdef SIN6_LEN
259 sin_dest.sin6_len = sizeof (struct sockaddr_in6);
260#endif /* SIN6_LEN */
261
262 memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
263
264 memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
265 sin_gate.sin6_family = AF_INET6;
266#ifdef SIN6_LEN
267 sin_gate.sin6_len = sizeof (struct sockaddr_in6);
268#endif /* SIN6_LEN */
269
270 sin_dest.sin6_addr = dest->prefix;
271
272 if (gate)
273 memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
274
275 /* Under kame set interface index to link local address. */
276#ifdef KAME
277
278#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
279 do { \
280 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
281 (a).s6_addr[3] = (i) & 0xff; \
282 } while (0)
283
284 if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
285 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
286#endif /* KAME */
287
288 if (gate && dest->prefixlen == 128)
289 mask = NULL;
290 else
291 {
292 masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
293 sin_mask.sin6_family = AF_UNSPEC;
294#ifdef SIN6_LEN
295 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
296#endif /* SIN6_LEN */
297 mask = &sin_mask;
298 }
299
300 return rtm_write (message,
301 (union sockunion *) &sin_dest,
302 (union sockunion *) mask,
303 gate ? (union sockunion *)&sin_gate : NULL,
304 index,
305 flags,
306 0);
307}
308
309/* Interface between zebra message and rtm message. */
310int
311kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
312 int family)
313{
314 struct sockaddr_in6 *mask;
315 struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
316 struct nexthop *nexthop;
317 int nexthop_num = 0;
318 unsigned int ifindex = 0;
319 int gate = 0;
320 int error;
321
322 memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
323 sin_dest.sin6_family = AF_INET6;
324#ifdef SIN6_LEN
325 sin_dest.sin6_len = sizeof (struct sockaddr_in6);
326#endif /* SIN6_LEN */
327 sin_dest.sin6_addr = p->u.prefix6;
328
329 memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
330
331 memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
332 sin_gate.sin6_family = AF_INET6;
333#ifdef HAVE_SIN_LEN
334 sin_gate.sin6_len = sizeof (struct sockaddr_in6);
335#endif /* HAVE_SIN_LEN */
336
337 /* Make gateway. */
338 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
339 {
340 gate = 0;
341
342 if ((cmd == RTM_ADD
343 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
344 || (cmd == RTM_DELETE
345#if 0
346 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
347#endif
348 ))
349 {
350 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
351 {
352 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
353 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
354 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
355 {
356 sin_gate.sin6_addr = nexthop->rgate.ipv6;
357 gate = 1;
358 }
359 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
360 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
361 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
362 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
363 ifindex = nexthop->rifindex;
364 }
365 else
366 {
367 if (nexthop->type == NEXTHOP_TYPE_IPV6
368 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
369 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
370 {
371 sin_gate.sin6_addr = nexthop->gate.ipv6;
372 gate = 1;
373 }
374 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
375 || nexthop->type == NEXTHOP_TYPE_IFNAME
376 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
377 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
378 ifindex = nexthop->ifindex;
379 }
380
381 if (cmd == RTM_ADD)
382 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
383 }
384
385 /* Under kame set interface index to link local address. */
386#ifdef KAME
387
388#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
389 do { \
390 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
391 (a).s6_addr[3] = (i) & 0xff; \
392 } while (0)
393
394 if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
395 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
396#endif /* KAME */
397
398 if (gate && p->prefixlen == 128)
399 mask = NULL;
400 else
401 {
402 masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
403 sin_mask.sin6_family = AF_UNSPEC;
404#ifdef SIN6_LEN
405 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
406#endif /* SIN6_LEN */
407 mask = &sin_mask;
408 }
409
410 error = rtm_write (cmd,
411 (union sockunion *) &sin_dest,
412 (union sockunion *) mask,
413 gate ? (union sockunion *)&sin_gate : NULL,
414 ifindex,
415 rib->flags,
416 rib->metric);
417
418#if 0
419 if (error)
420 {
421 zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
422 nexthop_num, error);
423 }
424#endif
425
426 nexthop_num++;
427 }
428
429 /* If there is no useful nexthop then return. */
430 if (nexthop_num == 0)
431 {
432 if (IS_ZEBRA_DEBUG_KERNEL)
433 zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
434 return 0;
435 }
436
437 return 0; /*XXX*/
438}
439
440int
441kernel_add_ipv6 (struct prefix *p, struct rib *rib)
442{
pauledd7c242003-06-04 13:59:38 +0000443 int route;
444
445 if (zserv_privs.change(ZPRIVS_RAISE))
446 zlog (NULL, LOG_ERR, "Can't raise privileges");
447 route = kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
448 if (zserv_privs.change(ZPRIVS_LOWER))
449 zlog (NULL, LOG_ERR, "Can't lower privileges");
450
451 return route;
paul718e3742002-12-13 20:15:29 +0000452}
453
454int
455kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
456{
pauledd7c242003-06-04 13:59:38 +0000457 int route;
458
459 if (zserv_privs.change(ZPRIVS_RAISE))
460 zlog (NULL, LOG_ERR, "Can't raise privileges");
461 route = kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
462 if (zserv_privs.change(ZPRIVS_LOWER))
463 zlog (NULL, LOG_ERR, "Can't lower privileges");
464
465 return route;
paul718e3742002-12-13 20:15:29 +0000466}
467
468/* Delete IPv6 route from the kernel. */
469int
470kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
471 int index, int flags, int table)
472{
pauledd7c242003-06-04 13:59:38 +0000473 int route;
474
475 if (zserv_privs.change(ZPRIVS_RAISE))
476 zlog (NULL, LOG_ERR, "Can't raise privileges");
477 route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
478 if (zserv_privs.change(ZPRIVS_LOWER))
479 zlog (NULL, LOG_ERR, "Can't lower privileges");
480
481 return route;
paul718e3742002-12-13 20:15:29 +0000482}
483#endif /* HAVE_IPV6 */