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 extern struct zebra_privs_t zserv_privs
;
38 rtm_write (int message
,
39 union sockunion
*dest
,
40 union sockunion
*mask
,
41 union sockunion
*gate
,
46 /* Adjust netmask socket length. Return value is a adjusted sin_len
49 sin_masklen (struct in_addr mask
)
53 struct sockaddr_in sin
;
59 len
= sizeof (struct sockaddr_in
);
61 lim
= (char *) &sin
.sin_addr
;
62 p
= lim
+ sizeof (sin
.sin_addr
);
64 while (*--p
== 0 && p
>= lim
)
69 /* Interface between zebra message and rtm message. */
71 kernel_rtm_ipv4 (int cmd
, struct prefix
*p
, struct rib
*rib
, int family
)
74 struct sockaddr_in
*mask
;
75 struct sockaddr_in sin_dest
, sin_mask
, sin_gate
;
76 struct nexthop
*nexthop
;
78 unsigned int ifindex
= 0;
82 memset (&sin_dest
, 0, sizeof (struct sockaddr_in
));
83 sin_dest
.sin_family
= AF_INET
;
85 sin_dest
.sin_len
= sizeof (struct sockaddr_in
);
86 #endif /* HAVE_SIN_LEN */
87 sin_dest
.sin_addr
= p
->u
.prefix4
;
89 memset (&sin_mask
, 0, sizeof (struct sockaddr_in
));
91 memset (&sin_gate
, 0, sizeof (struct sockaddr_in
));
92 sin_gate
.sin_family
= AF_INET
;
94 sin_gate
.sin_len
= sizeof (struct sockaddr_in
);
95 #endif /* HAVE_SIN_LEN */
98 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
103 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
104 || (cmd
== RTM_DELETE
106 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)
110 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
112 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV4
||
113 nexthop
->rtype
== NEXTHOP_TYPE_IPV4_IFINDEX
)
115 sin_gate
.sin_addr
= nexthop
->rgate
.ipv4
;
118 if (nexthop
->rtype
== NEXTHOP_TYPE_IFINDEX
119 || nexthop
->rtype
== NEXTHOP_TYPE_IFNAME
120 || nexthop
->rtype
== NEXTHOP_TYPE_IPV4_IFINDEX
)
121 ifindex
= nexthop
->rifindex
;
125 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
||
126 nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
128 sin_gate
.sin_addr
= nexthop
->gate
.ipv4
;
131 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
132 || nexthop
->type
== NEXTHOP_TYPE_IFNAME
133 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
134 ifindex
= nexthop
->ifindex
;
135 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
)
137 struct in_addr loopback
;
138 loopback
.s_addr
= htonl (INADDR_LOOPBACK
);
139 sin_gate
.sin_addr
= loopback
;
145 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
147 if (gate
&& p
->prefixlen
== 32)
151 masklen2ip (p
->prefixlen
, &sin_mask
.sin_addr
);
152 sin_mask
.sin_family
= AF_UNSPEC
;
154 sin_mask
.sin_len
= sin_masklen (sin_mask
.sin_addr
);
155 #endif /* HAVE_SIN_LEN */
160 error
= rtm_write (cmd
,
161 (union sockunion
*)&sin_dest
,
162 (union sockunion
*)mask
,
163 gate
? (union sockunion
*)&sin_gate
: NULL
,
171 zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
179 /* If there is no useful nexthop then return. */
180 if (nexthop_num
== 0)
182 if (IS_ZEBRA_DEBUG_KERNEL
)
183 zlog_info ("kernel_rtm_ipv4(): No useful nexthop.");
191 kernel_add_ipv4 (struct prefix
*p
, struct rib
*rib
)
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");
205 kernel_delete_ipv4 (struct prefix
*p
, struct rib
*rib
)
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");
220 /* Calculate sin6_len value for netmask socket value. */
222 sin6_masklen (struct in6_addr mask
)
224 struct sockaddr_in6 sin6
;
229 if (IN_ANYADDR6 (mask
))
230 return sizeof (long);
232 if (IN6_IS_ADDR_UNSPECIFIED (&mask
))
233 return sizeof (long);
236 sin6
.sin6_addr
= mask
;
237 len
= sizeof (struct sockaddr_in6
);
239 lim
= (char *) & sin6
.sin6_addr
;
240 p
= lim
+ sizeof (sin6
.sin6_addr
);
242 while (*--p
== 0 && p
>= lim
)
248 /* Interface between zebra message and rtm message. */
250 kernel_rtm_ipv6 (int message
, struct prefix_ipv6
*dest
,
251 struct in6_addr
*gate
, int index
, int flags
)
253 struct sockaddr_in6
*mask
;
254 struct sockaddr_in6 sin_dest
, sin_mask
, sin_gate
;
256 memset (&sin_dest
, 0, sizeof (struct sockaddr_in6
));
257 sin_dest
.sin6_family
= AF_INET6
;
259 sin_dest
.sin6_len
= sizeof (struct sockaddr_in6
);
260 #endif /* SIN6_LEN */
262 memset (&sin_mask
, 0, sizeof (struct sockaddr_in6
));
264 memset (&sin_gate
, 0, sizeof (struct sockaddr_in6
));
265 sin_gate
.sin6_family
= AF_INET6
;
267 sin_gate
.sin6_len
= sizeof (struct sockaddr_in6
);
268 #endif /* SIN6_LEN */
270 sin_dest
.sin6_addr
= dest
->prefix
;
273 memcpy (&sin_gate
.sin6_addr
, gate
, sizeof (struct in6_addr
));
275 /* Under kame set interface index to link local address. */
278 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
280 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
281 (a).s6_addr[3] = (i) & 0xff; \
284 if (gate
&& IN6_IS_ADDR_LINKLOCAL(gate
))
285 SET_IN6_LINKLOCAL_IFINDEX (sin_gate
.sin6_addr
, index
);
288 if (gate
&& dest
->prefixlen
== 128)
292 masklen2ip6 (dest
->prefixlen
, &sin_mask
.sin6_addr
);
293 sin_mask
.sin6_family
= AF_UNSPEC
;
295 sin_mask
.sin6_len
= sin6_masklen (sin_mask
.sin6_addr
);
296 #endif /* SIN6_LEN */
300 return rtm_write (message
,
301 (union sockunion
*) &sin_dest
,
302 (union sockunion
*) mask
,
303 gate
? (union sockunion
*)&sin_gate
: NULL
,
309 /* Interface between zebra message and rtm message. */
311 kernel_rtm_ipv6_multipath (int cmd
, struct prefix
*p
, struct rib
*rib
,
314 struct sockaddr_in6
*mask
;
315 struct sockaddr_in6 sin_dest
, sin_mask
, sin_gate
;
316 struct nexthop
*nexthop
;
318 unsigned int ifindex
= 0;
322 memset (&sin_dest
, 0, sizeof (struct sockaddr_in6
));
323 sin_dest
.sin6_family
= AF_INET6
;
325 sin_dest
.sin6_len
= sizeof (struct sockaddr_in6
);
326 #endif /* SIN6_LEN */
327 sin_dest
.sin6_addr
= p
->u
.prefix6
;
329 memset (&sin_mask
, 0, sizeof (struct sockaddr_in6
));
331 memset (&sin_gate
, 0, sizeof (struct sockaddr_in6
));
332 sin_gate
.sin6_family
= AF_INET6
;
334 sin_gate
.sin6_len
= sizeof (struct sockaddr_in6
);
335 #endif /* HAVE_SIN_LEN */
338 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
343 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
344 || (cmd
== RTM_DELETE
346 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)
350 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
352 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV6
353 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
354 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
356 sin_gate
.sin6_addr
= nexthop
->rgate
.ipv6
;
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
;
367 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
368 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
369 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
371 sin_gate
.sin6_addr
= nexthop
->gate
.ipv6
;
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
;
382 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
385 /* Under kame set interface index to link local address. */
388 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
390 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
391 (a).s6_addr[3] = (i) & 0xff; \
394 if (gate
&& IN6_IS_ADDR_LINKLOCAL(&sin_gate
.sin6_addr
))
395 SET_IN6_LINKLOCAL_IFINDEX (sin_gate
.sin6_addr
, ifindex
);
398 if (gate
&& p
->prefixlen
== 128)
402 masklen2ip6 (p
->prefixlen
, &sin_mask
.sin6_addr
);
403 sin_mask
.sin6_family
= AF_UNSPEC
;
405 sin_mask
.sin6_len
= sin6_masklen (sin_mask
.sin6_addr
);
406 #endif /* SIN6_LEN */
410 error
= rtm_write (cmd
,
411 (union sockunion
*) &sin_dest
,
412 (union sockunion
*) mask
,
413 gate
? (union sockunion
*)&sin_gate
: NULL
,
421 zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
429 /* If there is no useful nexthop then return. */
430 if (nexthop_num
== 0)
432 if (IS_ZEBRA_DEBUG_KERNEL
)
433 zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
441 kernel_add_ipv6 (struct prefix
*p
, struct rib
*rib
)
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");
455 kernel_delete_ipv6 (struct prefix
*p
, struct rib
*rib
)
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");
468 /* Delete IPv6 route from the kernel. */
470 kernel_delete_ipv6_old (struct prefix_ipv6
*dest
, struct in6_addr
*gate
,
471 int index
, int flags
, int table
)
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");
483 #endif /* HAVE_IPV6 */