blob: 0cdb0aca2b8a1503752635b343f3ff094e43ac67 [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"
paul6621ca82005-11-23 13:02:08 +000034#include "zebra/rt.h"
paul718e3742002-12-13 20:15:29 +000035
pauledd7c242003-06-04 13:59:38 +000036extern struct zebra_privs_t zserv_privs;
37
paul6621ca82005-11-23 13:02:08 +000038/* kernel socket export */
39extern int rtm_write (int message, union sockunion *dest,
40 union sockunion *mask, union sockunion *gate,
41 unsigned int index, int zebra_flags, int metric);
paul718e3742002-12-13 20:15:29 +000042
43/* Adjust netmask socket length. Return value is a adjusted sin_len
44 value. */
paul6621ca82005-11-23 13:02:08 +000045static int
paul718e3742002-12-13 20:15:29 +000046sin_masklen (struct in_addr mask)
47{
48 char *p, *lim;
49 int len;
50 struct sockaddr_in sin;
51
52 if (mask.s_addr == 0)
53 return sizeof (long);
54
55 sin.sin_addr = mask;
56 len = sizeof (struct sockaddr_in);
57
58 lim = (char *) &sin.sin_addr;
59 p = lim + sizeof (sin.sin_addr);
60
61 while (*--p == 0 && p >= lim)
62 len--;
63 return len;
64}
65
66/* Interface between zebra message and rtm message. */
paul6621ca82005-11-23 13:02:08 +000067static int
paul718e3742002-12-13 20:15:29 +000068kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
69
70{
hassofa2b17e2004-03-04 17:45:00 +000071 struct sockaddr_in *mask = NULL;
paul718e3742002-12-13 20:15:29 +000072 struct sockaddr_in sin_dest, sin_mask, sin_gate;
73 struct nexthop *nexthop;
74 int nexthop_num = 0;
75 unsigned int ifindex = 0;
76 int gate = 0;
77 int error;
78
79 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
80 sin_dest.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +000081#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +000082 sin_dest.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +000083#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +000084 sin_dest.sin_addr = p->u.prefix4;
85
86 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
87
88 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
89 sin_gate.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +000090#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +000091 sin_gate.sin_len = sizeof (struct sockaddr_in);
Paul Jakma6f0e3f62007-05-10 02:38:51 +000092#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +000093
94 /* Make gateway. */
95 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
96 {
97 gate = 0;
98
99 if ((cmd == RTM_ADD
100 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
101 || (cmd == RTM_DELETE
paul718e3742002-12-13 20:15:29 +0000102 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
paul718e3742002-12-13 20:15:29 +0000103 ))
104 {
105 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
106 {
107 if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
108 nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
109 {
110 sin_gate.sin_addr = nexthop->rgate.ipv4;
111 gate = 1;
112 }
113 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
114 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
115 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
116 ifindex = nexthop->rifindex;
117 }
118 else
119 {
120 if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
121 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
122 {
123 sin_gate.sin_addr = nexthop->gate.ipv4;
124 gate = 1;
125 }
126 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
127 || nexthop->type == NEXTHOP_TYPE_IFNAME
128 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
129 ifindex = nexthop->ifindex;
paul595db7f2003-05-25 21:35:06 +0000130 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
131 {
132 struct in_addr loopback;
133 loopback.s_addr = htonl (INADDR_LOOPBACK);
134 sin_gate.sin_addr = loopback;
135 gate = 1;
136 }
137 }
paul718e3742002-12-13 20:15:29 +0000138
paul718e3742002-12-13 20:15:29 +0000139 if (gate && p->prefixlen == 32)
140 mask = NULL;
141 else
142 {
143 masklen2ip (p->prefixlen, &sin_mask.sin_addr);
gdt6083e1f2005-12-29 15:59:57 +0000144 sin_mask.sin_family = AF_INET;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000145#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +0000146 sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000147#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +0000148 mask = &sin_mask;
149 }
paul718e3742002-12-13 20:15:29 +0000150
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 0
160 if (error)
161 {
162 zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
163 nexthop_num, error);
164 }
165#endif
Greg Troxelf76594a2007-08-02 14:07:07 +0000166 if (error == 0)
167 {
168 nexthop_num++;
169 if (cmd == RTM_ADD)
170 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
171 }
172 }
paul718e3742002-12-13 20:15:29 +0000173 }
174
175 /* If there is no useful nexthop then return. */
176 if (nexthop_num == 0)
177 {
178 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000179 zlog_debug ("kernel_rtm_ipv4(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +0000180 return 0;
181 }
182
183 return 0; /*XXX*/
184}
185
186int
187kernel_add_ipv4 (struct prefix *p, struct rib *rib)
188{
pauledd7c242003-06-04 13:59:38 +0000189 int route;
190
191 if (zserv_privs.change(ZPRIVS_RAISE))
192 zlog (NULL, LOG_ERR, "Can't raise privileges");
193 route = kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
194 if (zserv_privs.change(ZPRIVS_LOWER))
195 zlog (NULL, LOG_ERR, "Can't lower privileges");
196
197 return route;
paul718e3742002-12-13 20:15:29 +0000198}
199
200int
201kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
202{
pauledd7c242003-06-04 13:59:38 +0000203 int route;
204
205 if (zserv_privs.change(ZPRIVS_RAISE))
206 zlog (NULL, LOG_ERR, "Can't raise privileges");
207 route = kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
208 if (zserv_privs.change(ZPRIVS_LOWER))
209 zlog (NULL, LOG_ERR, "Can't lower privileges");
210
211 return route;
paul718e3742002-12-13 20:15:29 +0000212}
213
214#ifdef HAVE_IPV6
215
216/* Calculate sin6_len value for netmask socket value. */
paul6621ca82005-11-23 13:02:08 +0000217static int
paul718e3742002-12-13 20:15:29 +0000218sin6_masklen (struct in6_addr mask)
219{
220 struct sockaddr_in6 sin6;
221 char *p, *lim;
222 int len;
223
224#if defined (INRIA)
225 if (IN_ANYADDR6 (mask))
226 return sizeof (long);
227#else /* ! INRIA */
228 if (IN6_IS_ADDR_UNSPECIFIED (&mask))
229 return sizeof (long);
230#endif /* ! INRIA */
231
232 sin6.sin6_addr = mask;
233 len = sizeof (struct sockaddr_in6);
234
235 lim = (char *) & sin6.sin6_addr;
236 p = lim + sizeof (sin6.sin6_addr);
237
238 while (*--p == 0 && p >= lim)
239 len--;
240
241 return len;
242}
243
244/* Interface between zebra message and rtm message. */
paul6621ca82005-11-23 13:02:08 +0000245static int
paul718e3742002-12-13 20:15:29 +0000246kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
247 struct in6_addr *gate, int index, int flags)
248{
249 struct sockaddr_in6 *mask;
250 struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
251
252 memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
253 sin_dest.sin6_family = AF_INET6;
254#ifdef SIN6_LEN
255 sin_dest.sin6_len = sizeof (struct sockaddr_in6);
256#endif /* SIN6_LEN */
257
258 memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
259
260 memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
261 sin_gate.sin6_family = AF_INET6;
262#ifdef SIN6_LEN
263 sin_gate.sin6_len = sizeof (struct sockaddr_in6);
264#endif /* SIN6_LEN */
265
266 sin_dest.sin6_addr = dest->prefix;
267
268 if (gate)
269 memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
270
271 /* Under kame set interface index to link local address. */
272#ifdef KAME
273
274#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
275 do { \
276 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
277 (a).s6_addr[3] = (i) & 0xff; \
278 } while (0)
279
280 if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
281 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
282#endif /* KAME */
283
284 if (gate && dest->prefixlen == 128)
285 mask = NULL;
286 else
287 {
288 masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
paul6fe70d12005-11-12 22:55:10 +0000289 sin_mask.sin6_family = AF_INET6;
paul718e3742002-12-13 20:15:29 +0000290#ifdef SIN6_LEN
291 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
292#endif /* SIN6_LEN */
293 mask = &sin_mask;
294 }
295
296 return rtm_write (message,
297 (union sockunion *) &sin_dest,
298 (union sockunion *) mask,
299 gate ? (union sockunion *)&sin_gate : NULL,
300 index,
301 flags,
302 0);
303}
304
305/* Interface between zebra message and rtm message. */
paul6621ca82005-11-23 13:02:08 +0000306static int
paul718e3742002-12-13 20:15:29 +0000307kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
308 int family)
309{
310 struct sockaddr_in6 *mask;
311 struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
312 struct nexthop *nexthop;
313 int nexthop_num = 0;
314 unsigned int ifindex = 0;
315 int gate = 0;
316 int error;
317
318 memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
319 sin_dest.sin6_family = AF_INET6;
320#ifdef SIN6_LEN
321 sin_dest.sin6_len = sizeof (struct sockaddr_in6);
322#endif /* SIN6_LEN */
323 sin_dest.sin6_addr = p->u.prefix6;
324
325 memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
326
327 memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
328 sin_gate.sin6_family = AF_INET6;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000329#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
paul718e3742002-12-13 20:15:29 +0000330 sin_gate.sin6_len = sizeof (struct sockaddr_in6);
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000331#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
paul718e3742002-12-13 20:15:29 +0000332
333 /* Make gateway. */
334 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
335 {
336 gate = 0;
337
338 if ((cmd == RTM_ADD
339 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
340 || (cmd == RTM_DELETE
341#if 0
342 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
343#endif
344 ))
345 {
346 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
347 {
348 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
349 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
350 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
351 {
352 sin_gate.sin6_addr = nexthop->rgate.ipv6;
353 gate = 1;
354 }
355 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
356 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
357 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
358 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
359 ifindex = nexthop->rifindex;
360 }
361 else
362 {
363 if (nexthop->type == NEXTHOP_TYPE_IPV6
364 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
365 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
366 {
367 sin_gate.sin6_addr = nexthop->gate.ipv6;
368 gate = 1;
369 }
370 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
371 || nexthop->type == NEXTHOP_TYPE_IFNAME
372 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
373 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
374 ifindex = nexthop->ifindex;
375 }
376
377 if (cmd == RTM_ADD)
378 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
379 }
380
381 /* Under kame set interface index to link local address. */
382#ifdef KAME
383
384#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
385 do { \
386 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
387 (a).s6_addr[3] = (i) & 0xff; \
388 } while (0)
389
390 if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
391 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
392#endif /* KAME */
393
394 if (gate && p->prefixlen == 128)
395 mask = NULL;
396 else
397 {
398 masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
paul6fe70d12005-11-12 22:55:10 +0000399 sin_mask.sin6_family = AF_INET6;
paul718e3742002-12-13 20:15:29 +0000400#ifdef SIN6_LEN
401 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
402#endif /* SIN6_LEN */
403 mask = &sin_mask;
404 }
405
406 error = rtm_write (cmd,
407 (union sockunion *) &sin_dest,
408 (union sockunion *) mask,
409 gate ? (union sockunion *)&sin_gate : NULL,
410 ifindex,
411 rib->flags,
412 rib->metric);
413
414#if 0
415 if (error)
416 {
417 zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
418 nexthop_num, error);
419 }
420#endif
421
422 nexthop_num++;
423 }
424
425 /* If there is no useful nexthop then return. */
426 if (nexthop_num == 0)
427 {
428 if (IS_ZEBRA_DEBUG_KERNEL)
ajsb6178002004-12-07 21:12:56 +0000429 zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
paul718e3742002-12-13 20:15:29 +0000430 return 0;
431 }
432
433 return 0; /*XXX*/
434}
435
436int
437kernel_add_ipv6 (struct prefix *p, struct rib *rib)
438{
pauledd7c242003-06-04 13:59:38 +0000439 int route;
440
441 if (zserv_privs.change(ZPRIVS_RAISE))
442 zlog (NULL, LOG_ERR, "Can't raise privileges");
443 route = kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
444 if (zserv_privs.change(ZPRIVS_LOWER))
445 zlog (NULL, LOG_ERR, "Can't lower privileges");
446
447 return route;
paul718e3742002-12-13 20:15:29 +0000448}
449
450int
451kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
452{
pauledd7c242003-06-04 13:59:38 +0000453 int route;
454
455 if (zserv_privs.change(ZPRIVS_RAISE))
456 zlog (NULL, LOG_ERR, "Can't raise privileges");
457 route = kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
458 if (zserv_privs.change(ZPRIVS_LOWER))
459 zlog (NULL, LOG_ERR, "Can't lower privileges");
460
461 return route;
paul718e3742002-12-13 20:15:29 +0000462}
463
464/* Delete IPv6 route from the kernel. */
465int
466kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
paul6621ca82005-11-23 13:02:08 +0000467 unsigned int index, int flags, int table)
paul718e3742002-12-13 20:15:29 +0000468{
pauledd7c242003-06-04 13:59:38 +0000469 int route;
470
471 if (zserv_privs.change(ZPRIVS_RAISE))
472 zlog (NULL, LOG_ERR, "Can't raise privileges");
473 route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
474 if (zserv_privs.change(ZPRIVS_LOWER))
475 zlog (NULL, LOG_ERR, "Can't lower privileges");
476
477 return route;
paul718e3742002-12-13 20:15:29 +0000478}
479#endif /* HAVE_IPV6 */