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