2 * Kernel routing table updates by routing socket.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
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
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.
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
27 #include "sockunion.h"
32 #include "zebra/debug.h"
33 #include "zebra/rib.h"
35 #include "zebra/kernel_socket.h"
37 extern struct zebra_privs_t zserv_privs
;
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
);
44 /* Adjust netmask socket length. Return value is a adjusted sin_len
47 sin_masklen (struct in_addr mask
)
51 struct sockaddr_in sin
;
57 len
= sizeof (struct sockaddr_in
);
59 lim
= (char *) &sin
.sin_addr
;
60 p
= lim
+ sizeof (sin
.sin_addr
);
62 while (*--p
== 0 && p
>= lim
)
67 /* Interface between zebra message and rtm message. */
69 kernel_rtm_ipv4 (int cmd
, struct prefix
*p
, struct rib
*rib
, int family
)
72 struct sockaddr_in
*mask
= NULL
;
73 struct sockaddr_in sin_dest
, sin_mask
, sin_gate
;
74 struct nexthop
*nexthop
;
76 unsigned int ifindex
= 0;
79 char prefix_buf
[INET_ADDRSTRLEN
];
81 if (IS_ZEBRA_DEBUG_RIB
)
82 inet_ntop (AF_INET
, &p
->u
.prefix
, prefix_buf
, INET_ADDRSTRLEN
);
83 memset (&sin_dest
, 0, sizeof (struct sockaddr_in
));
84 sin_dest
.sin_family
= AF_INET
;
85 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
86 sin_dest
.sin_len
= sizeof (struct sockaddr_in
);
87 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
88 sin_dest
.sin_addr
= p
->u
.prefix4
;
90 memset (&sin_mask
, 0, sizeof (struct sockaddr_in
));
92 memset (&sin_gate
, 0, sizeof (struct sockaddr_in
));
93 sin_gate
.sin_family
= AF_INET
;
94 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
95 sin_gate
.sin_len
= sizeof (struct sockaddr_in
);
96 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
99 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
102 char gate_buf
[INET_ADDRSTRLEN
] = "NULL";
105 * XXX We need to refrain from kernel operations in some cases,
106 * but this if statement seems overly cautious - what about
107 * other than ADD and DELETE?
110 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
111 || (cmd
== RTM_DELETE
112 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)
115 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
117 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV4
||
118 nexthop
->rtype
== NEXTHOP_TYPE_IPV4_IFINDEX
)
120 sin_gate
.sin_addr
= nexthop
->rgate
.ipv4
;
123 if (nexthop
->rtype
== NEXTHOP_TYPE_IFINDEX
124 || nexthop
->rtype
== NEXTHOP_TYPE_IFNAME
125 || nexthop
->rtype
== NEXTHOP_TYPE_IPV4_IFINDEX
)
126 ifindex
= nexthop
->rifindex
;
130 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
||
131 nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
133 sin_gate
.sin_addr
= nexthop
->gate
.ipv4
;
136 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
137 || nexthop
->type
== NEXTHOP_TYPE_IFNAME
138 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
139 ifindex
= nexthop
->ifindex
;
140 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
)
142 struct in_addr loopback
;
143 loopback
.s_addr
= htonl (INADDR_LOOPBACK
);
144 sin_gate
.sin_addr
= loopback
;
149 if (gate
&& p
->prefixlen
== 32)
153 masklen2ip (p
->prefixlen
, &sin_mask
.sin_addr
);
154 sin_mask
.sin_family
= AF_INET
;
155 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
156 sin_mask
.sin_len
= sin_masklen (sin_mask
.sin_addr
);
157 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
161 error
= rtm_write (cmd
,
162 (union sockunion
*)&sin_dest
,
163 (union sockunion
*)mask
,
164 gate
? (union sockunion
*)&sin_gate
: NULL
,
169 if (IS_ZEBRA_DEBUG_RIB
)
173 zlog_debug ("%s: %s/%d: attention! gate not found for rib %p",
174 __func__
, prefix_buf
, p
->prefixlen
, rib
);
175 rib_dump (__func__
, (struct prefix_ipv4
*)p
, rib
);
178 inet_ntop (AF_INET
, &sin_gate
.sin_addr
, gate_buf
, INET_ADDRSTRLEN
);
183 /* We only flag nexthops as being in FIB if rtm_write() did its work. */
184 case ZEBRA_ERR_NOERROR
:
186 if (IS_ZEBRA_DEBUG_RIB
)
187 zlog_debug ("%s: %s/%d: successfully did NH %s",
188 __func__
, prefix_buf
, p
->prefixlen
, gate_buf
);
190 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
193 /* The only valid case for this error is kernel's failure to install
194 * a multipath route, which is common for FreeBSD. This should be
195 * ignored silently, but logged as an error otherwise.
197 case ZEBRA_ERR_RTEXIST
:
199 zlog_err ("%s: rtm_write() returned %d for command %d",
200 __func__
, error
, cmd
);
204 /* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't
205 * normal to get any other messages in ANY case.
207 case ZEBRA_ERR_RTNOEXIST
:
208 case ZEBRA_ERR_RTUNREACH
:
210 /* This point is reachable regardless of debugging mode. */
211 if (!IS_ZEBRA_DEBUG_RIB
)
212 inet_ntop (AF_INET
, &p
->u
.prefix
, prefix_buf
, INET_ADDRSTRLEN
);
213 zlog_err ("%s: %s/%d: rtm_write() unexpectedly returned %d for command %s",
214 __func__
, prefix_buf
, p
->prefixlen
, error
, lookup (rtm_type_str
, cmd
));
217 } /* if (cmd and flags make sense) */
219 if (IS_ZEBRA_DEBUG_RIB
)
220 zlog_debug ("%s: odd command %s for flags %d",
221 __func__
, lookup (rtm_type_str
, cmd
), nexthop
->flags
);
222 } /* for (nexthop = ... */
224 /* If there was no useful nexthop, then complain. */
225 if (nexthop_num
== 0 && IS_ZEBRA_DEBUG_KERNEL
)
226 zlog_debug ("%s: No useful nexthops were found in RIB entry %p", __func__
, rib
);
232 kernel_add_ipv4 (struct prefix
*p
, struct rib
*rib
)
236 if (zserv_privs
.change(ZPRIVS_RAISE
))
237 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
238 route
= kernel_rtm_ipv4 (RTM_ADD
, p
, rib
, AF_INET
);
239 if (zserv_privs
.change(ZPRIVS_LOWER
))
240 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
246 kernel_delete_ipv4 (struct prefix
*p
, struct rib
*rib
)
250 if (zserv_privs
.change(ZPRIVS_RAISE
))
251 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
252 route
= kernel_rtm_ipv4 (RTM_DELETE
, p
, rib
, AF_INET
);
253 if (zserv_privs
.change(ZPRIVS_LOWER
))
254 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
261 /* Calculate sin6_len value for netmask socket value. */
263 sin6_masklen (struct in6_addr mask
)
265 struct sockaddr_in6 sin6
;
270 if (IN_ANYADDR6 (mask
))
271 return sizeof (long);
273 if (IN6_IS_ADDR_UNSPECIFIED (&mask
))
274 return sizeof (long);
277 sin6
.sin6_addr
= mask
;
278 len
= sizeof (struct sockaddr_in6
);
280 lim
= (char *) & sin6
.sin6_addr
;
281 p
= lim
+ sizeof (sin6
.sin6_addr
);
283 while (*--p
== 0 && p
>= lim
)
289 /* Interface between zebra message and rtm message. */
291 kernel_rtm_ipv6 (int message
, struct prefix_ipv6
*dest
,
292 struct in6_addr
*gate
, int index
, int flags
)
294 struct sockaddr_in6
*mask
;
295 struct sockaddr_in6 sin_dest
, sin_mask
, sin_gate
;
297 memset (&sin_dest
, 0, sizeof (struct sockaddr_in6
));
298 sin_dest
.sin6_family
= AF_INET6
;
300 sin_dest
.sin6_len
= sizeof (struct sockaddr_in6
);
301 #endif /* SIN6_LEN */
303 memset (&sin_mask
, 0, sizeof (struct sockaddr_in6
));
305 memset (&sin_gate
, 0, sizeof (struct sockaddr_in6
));
306 sin_gate
.sin6_family
= AF_INET6
;
308 sin_gate
.sin6_len
= sizeof (struct sockaddr_in6
);
309 #endif /* SIN6_LEN */
311 sin_dest
.sin6_addr
= dest
->prefix
;
314 memcpy (&sin_gate
.sin6_addr
, gate
, sizeof (struct in6_addr
));
316 /* Under kame set interface index to link local address. */
319 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
321 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
322 (a).s6_addr[3] = (i) & 0xff; \
325 if (gate
&& IN6_IS_ADDR_LINKLOCAL(gate
))
326 SET_IN6_LINKLOCAL_IFINDEX (sin_gate
.sin6_addr
, index
);
329 if (gate
&& dest
->prefixlen
== 128)
333 masklen2ip6 (dest
->prefixlen
, &sin_mask
.sin6_addr
);
334 sin_mask
.sin6_family
= AF_INET6
;
336 sin_mask
.sin6_len
= sin6_masklen (sin_mask
.sin6_addr
);
337 #endif /* SIN6_LEN */
341 return rtm_write (message
,
342 (union sockunion
*) &sin_dest
,
343 (union sockunion
*) mask
,
344 gate
? (union sockunion
*)&sin_gate
: NULL
,
350 /* Interface between zebra message and rtm message. */
352 kernel_rtm_ipv6_multipath (int cmd
, struct prefix
*p
, struct rib
*rib
,
355 struct sockaddr_in6
*mask
;
356 struct sockaddr_in6 sin_dest
, sin_mask
, sin_gate
;
357 struct nexthop
*nexthop
;
359 unsigned int ifindex
= 0;
363 memset (&sin_dest
, 0, sizeof (struct sockaddr_in6
));
364 sin_dest
.sin6_family
= AF_INET6
;
366 sin_dest
.sin6_len
= sizeof (struct sockaddr_in6
);
367 #endif /* SIN6_LEN */
368 sin_dest
.sin6_addr
= p
->u
.prefix6
;
370 memset (&sin_mask
, 0, sizeof (struct sockaddr_in6
));
372 memset (&sin_gate
, 0, sizeof (struct sockaddr_in6
));
373 sin_gate
.sin6_family
= AF_INET6
;
374 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
375 sin_gate
.sin6_len
= sizeof (struct sockaddr_in6
);
376 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
379 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
384 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
385 || (cmd
== RTM_DELETE
387 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)
391 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
393 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV6
394 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
395 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
397 sin_gate
.sin6_addr
= nexthop
->rgate
.ipv6
;
400 if (nexthop
->rtype
== NEXTHOP_TYPE_IFINDEX
401 || nexthop
->rtype
== NEXTHOP_TYPE_IFNAME
402 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
403 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
404 ifindex
= nexthop
->rifindex
;
408 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
409 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
410 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
412 sin_gate
.sin6_addr
= nexthop
->gate
.ipv6
;
415 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
416 || nexthop
->type
== NEXTHOP_TYPE_IFNAME
417 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
418 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
419 ifindex
= nexthop
->ifindex
;
423 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
426 /* Under kame set interface index to link local address. */
429 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
431 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
432 (a).s6_addr[3] = (i) & 0xff; \
435 if (gate
&& IN6_IS_ADDR_LINKLOCAL(&sin_gate
.sin6_addr
))
436 SET_IN6_LINKLOCAL_IFINDEX (sin_gate
.sin6_addr
, ifindex
);
439 if (gate
&& p
->prefixlen
== 128)
443 masklen2ip6 (p
->prefixlen
, &sin_mask
.sin6_addr
);
444 sin_mask
.sin6_family
= AF_INET6
;
446 sin_mask
.sin6_len
= sin6_masklen (sin_mask
.sin6_addr
);
447 #endif /* SIN6_LEN */
451 error
= rtm_write (cmd
,
452 (union sockunion
*) &sin_dest
,
453 (union sockunion
*) mask
,
454 gate
? (union sockunion
*)&sin_gate
: NULL
,
462 zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
470 /* If there is no useful nexthop then return. */
471 if (nexthop_num
== 0)
473 if (IS_ZEBRA_DEBUG_KERNEL
)
474 zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
482 kernel_add_ipv6 (struct prefix
*p
, struct rib
*rib
)
486 if (zserv_privs
.change(ZPRIVS_RAISE
))
487 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
488 route
= kernel_rtm_ipv6_multipath (RTM_ADD
, p
, rib
, AF_INET6
);
489 if (zserv_privs
.change(ZPRIVS_LOWER
))
490 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
496 kernel_delete_ipv6 (struct prefix
*p
, struct rib
*rib
)
500 if (zserv_privs
.change(ZPRIVS_RAISE
))
501 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
502 route
= kernel_rtm_ipv6_multipath (RTM_DELETE
, p
, rib
, AF_INET6
);
503 if (zserv_privs
.change(ZPRIVS_LOWER
))
504 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
509 /* Delete IPv6 route from the kernel. */
511 kernel_delete_ipv6_old (struct prefix_ipv6
*dest
, struct in6_addr
*gate
,
512 unsigned int index
, int flags
, int table
)
516 if (zserv_privs
.change(ZPRIVS_RAISE
))
517 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
518 route
= kernel_rtm_ipv6 (RTM_DELETE
, dest
, gate
, index
, flags
);
519 if (zserv_privs
.change(ZPRIVS_LOWER
))
520 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
524 #endif /* HAVE_IPV6 */