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"
36 extern struct zebra_privs_t zserv_privs
;
38 /* kernel socket export */
39 extern int rtm_write (int message
, union sockunion
*dest
,
40 union sockunion
*mask
, union sockunion
*gate
,
41 unsigned int index
, int zebra_flags
, int metric
);
43 /* Adjust netmask socket length. Return value is a adjusted sin_len
46 sin_masklen (struct in_addr mask
)
50 struct sockaddr_in sin
;
56 len
= sizeof (struct sockaddr_in
);
58 lim
= (char *) &sin
.sin_addr
;
59 p
= lim
+ sizeof (sin
.sin_addr
);
61 while (*--p
== 0 && p
>= lim
)
66 /* Interface between zebra message and rtm message. */
68 kernel_rtm_ipv4 (int cmd
, struct prefix
*p
, struct rib
*rib
, int family
)
71 struct sockaddr_in
*mask
= NULL
;
72 struct sockaddr_in sin_dest
, sin_mask
, sin_gate
;
73 struct nexthop
*nexthop
;
75 unsigned int ifindex
= 0;
79 memset (&sin_dest
, 0, sizeof (struct sockaddr_in
));
80 sin_dest
.sin_family
= AF_INET
;
82 sin_dest
.sin_len
= sizeof (struct sockaddr_in
);
83 #endif /* HAVE_SIN_LEN */
84 sin_dest
.sin_addr
= p
->u
.prefix4
;
86 memset (&sin_mask
, 0, sizeof (struct sockaddr_in
));
88 memset (&sin_gate
, 0, sizeof (struct sockaddr_in
));
89 sin_gate
.sin_family
= AF_INET
;
91 sin_gate
.sin_len
= sizeof (struct sockaddr_in
);
92 #endif /* HAVE_SIN_LEN */
95 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
100 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
101 || (cmd
== RTM_DELETE
103 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)
107 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
109 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV4
||
110 nexthop
->rtype
== NEXTHOP_TYPE_IPV4_IFINDEX
)
112 sin_gate
.sin_addr
= nexthop
->rgate
.ipv4
;
115 if (nexthop
->rtype
== NEXTHOP_TYPE_IFINDEX
116 || nexthop
->rtype
== NEXTHOP_TYPE_IFNAME
117 || nexthop
->rtype
== NEXTHOP_TYPE_IPV4_IFINDEX
)
118 ifindex
= nexthop
->rifindex
;
122 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
||
123 nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
125 sin_gate
.sin_addr
= nexthop
->gate
.ipv4
;
128 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
129 || nexthop
->type
== NEXTHOP_TYPE_IFNAME
130 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
131 ifindex
= nexthop
->ifindex
;
132 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
)
134 struct in_addr loopback
;
135 loopback
.s_addr
= htonl (INADDR_LOOPBACK
);
136 sin_gate
.sin_addr
= loopback
;
142 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
144 if (gate
&& p
->prefixlen
== 32)
148 masklen2ip (p
->prefixlen
, &sin_mask
.sin_addr
);
149 sin_mask
.sin_family
= AF_INET
;
151 sin_mask
.sin_len
= sin_masklen (sin_mask
.sin_addr
);
152 #endif /* HAVE_SIN_LEN */
157 error
= rtm_write (cmd
,
158 (union sockunion
*)&sin_dest
,
159 (union sockunion
*)mask
,
160 gate
? (union sockunion
*)&sin_gate
: NULL
,
168 zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
176 /* If there is no useful nexthop then return. */
177 if (nexthop_num
== 0)
179 if (IS_ZEBRA_DEBUG_KERNEL
)
180 zlog_debug ("kernel_rtm_ipv4(): No useful nexthop.");
188 kernel_add_ipv4 (struct prefix
*p
, struct rib
*rib
)
192 if (zserv_privs
.change(ZPRIVS_RAISE
))
193 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
194 route
= kernel_rtm_ipv4 (RTM_ADD
, p
, rib
, AF_INET
);
195 if (zserv_privs
.change(ZPRIVS_LOWER
))
196 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
202 kernel_delete_ipv4 (struct prefix
*p
, struct rib
*rib
)
206 if (zserv_privs
.change(ZPRIVS_RAISE
))
207 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
208 route
= kernel_rtm_ipv4 (RTM_DELETE
, p
, rib
, AF_INET
);
209 if (zserv_privs
.change(ZPRIVS_LOWER
))
210 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
217 /* Calculate sin6_len value for netmask socket value. */
219 sin6_masklen (struct in6_addr mask
)
221 struct sockaddr_in6 sin6
;
226 if (IN_ANYADDR6 (mask
))
227 return sizeof (long);
229 if (IN6_IS_ADDR_UNSPECIFIED (&mask
))
230 return sizeof (long);
233 sin6
.sin6_addr
= mask
;
234 len
= sizeof (struct sockaddr_in6
);
236 lim
= (char *) & sin6
.sin6_addr
;
237 p
= lim
+ sizeof (sin6
.sin6_addr
);
239 while (*--p
== 0 && p
>= lim
)
245 /* Interface between zebra message and rtm message. */
247 kernel_rtm_ipv6 (int message
, struct prefix_ipv6
*dest
,
248 struct in6_addr
*gate
, int index
, int flags
)
250 struct sockaddr_in6
*mask
;
251 struct sockaddr_in6 sin_dest
, sin_mask
, sin_gate
;
253 memset (&sin_dest
, 0, sizeof (struct sockaddr_in6
));
254 sin_dest
.sin6_family
= AF_INET6
;
256 sin_dest
.sin6_len
= sizeof (struct sockaddr_in6
);
257 #endif /* SIN6_LEN */
259 memset (&sin_mask
, 0, sizeof (struct sockaddr_in6
));
261 memset (&sin_gate
, 0, sizeof (struct sockaddr_in6
));
262 sin_gate
.sin6_family
= AF_INET6
;
264 sin_gate
.sin6_len
= sizeof (struct sockaddr_in6
);
265 #endif /* SIN6_LEN */
267 sin_dest
.sin6_addr
= dest
->prefix
;
270 memcpy (&sin_gate
.sin6_addr
, gate
, sizeof (struct in6_addr
));
272 /* Under kame set interface index to link local address. */
275 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
277 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
278 (a).s6_addr[3] = (i) & 0xff; \
281 if (gate
&& IN6_IS_ADDR_LINKLOCAL(gate
))
282 SET_IN6_LINKLOCAL_IFINDEX (sin_gate
.sin6_addr
, index
);
285 if (gate
&& dest
->prefixlen
== 128)
289 masklen2ip6 (dest
->prefixlen
, &sin_mask
.sin6_addr
);
290 sin_mask
.sin6_family
= AF_INET6
;
292 sin_mask
.sin6_len
= sin6_masklen (sin_mask
.sin6_addr
);
293 #endif /* SIN6_LEN */
297 return rtm_write (message
,
298 (union sockunion
*) &sin_dest
,
299 (union sockunion
*) mask
,
300 gate
? (union sockunion
*)&sin_gate
: NULL
,
306 /* Interface between zebra message and rtm message. */
308 kernel_rtm_ipv6_multipath (int cmd
, struct prefix
*p
, struct rib
*rib
,
311 struct sockaddr_in6
*mask
;
312 struct sockaddr_in6 sin_dest
, sin_mask
, sin_gate
;
313 struct nexthop
*nexthop
;
315 unsigned int ifindex
= 0;
319 memset (&sin_dest
, 0, sizeof (struct sockaddr_in6
));
320 sin_dest
.sin6_family
= AF_INET6
;
322 sin_dest
.sin6_len
= sizeof (struct sockaddr_in6
);
323 #endif /* SIN6_LEN */
324 sin_dest
.sin6_addr
= p
->u
.prefix6
;
326 memset (&sin_mask
, 0, sizeof (struct sockaddr_in6
));
328 memset (&sin_gate
, 0, sizeof (struct sockaddr_in6
));
329 sin_gate
.sin6_family
= AF_INET6
;
331 sin_gate
.sin6_len
= sizeof (struct sockaddr_in6
);
332 #endif /* HAVE_SIN_LEN */
335 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
340 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
341 || (cmd
== RTM_DELETE
343 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)
347 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
349 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV6
350 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
351 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
353 sin_gate
.sin6_addr
= nexthop
->rgate
.ipv6
;
356 if (nexthop
->rtype
== NEXTHOP_TYPE_IFINDEX
357 || nexthop
->rtype
== NEXTHOP_TYPE_IFNAME
358 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
359 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
360 ifindex
= nexthop
->rifindex
;
364 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
365 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
366 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
368 sin_gate
.sin6_addr
= nexthop
->gate
.ipv6
;
371 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
372 || nexthop
->type
== NEXTHOP_TYPE_IFNAME
373 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
374 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
375 ifindex
= nexthop
->ifindex
;
379 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
382 /* Under kame set interface index to link local address. */
385 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
387 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
388 (a).s6_addr[3] = (i) & 0xff; \
391 if (gate
&& IN6_IS_ADDR_LINKLOCAL(&sin_gate
.sin6_addr
))
392 SET_IN6_LINKLOCAL_IFINDEX (sin_gate
.sin6_addr
, ifindex
);
395 if (gate
&& p
->prefixlen
== 128)
399 masklen2ip6 (p
->prefixlen
, &sin_mask
.sin6_addr
);
400 sin_mask
.sin6_family
= AF_INET6
;
402 sin_mask
.sin6_len
= sin6_masklen (sin_mask
.sin6_addr
);
403 #endif /* SIN6_LEN */
407 error
= rtm_write (cmd
,
408 (union sockunion
*) &sin_dest
,
409 (union sockunion
*) mask
,
410 gate
? (union sockunion
*)&sin_gate
: NULL
,
418 zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
426 /* If there is no useful nexthop then return. */
427 if (nexthop_num
== 0)
429 if (IS_ZEBRA_DEBUG_KERNEL
)
430 zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
438 kernel_add_ipv6 (struct prefix
*p
, struct rib
*rib
)
442 if (zserv_privs
.change(ZPRIVS_RAISE
))
443 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
444 route
= kernel_rtm_ipv6_multipath (RTM_ADD
, p
, rib
, AF_INET6
);
445 if (zserv_privs
.change(ZPRIVS_LOWER
))
446 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
452 kernel_delete_ipv6 (struct prefix
*p
, struct rib
*rib
)
456 if (zserv_privs
.change(ZPRIVS_RAISE
))
457 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
458 route
= kernel_rtm_ipv6_multipath (RTM_DELETE
, p
, rib
, AF_INET6
);
459 if (zserv_privs
.change(ZPRIVS_LOWER
))
460 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
465 /* Delete IPv6 route from the kernel. */
467 kernel_delete_ipv6_old (struct prefix_ipv6
*dest
, struct in6_addr
*gate
,
468 unsigned int index
, int flags
, int table
)
472 if (zserv_privs
.change(ZPRIVS_RAISE
))
473 zlog (NULL
, LOG_ERR
, "Can't raise privileges");
474 route
= kernel_rtm_ipv6 (RTM_DELETE
, dest
, gate
, index
, flags
);
475 if (zserv_privs
.change(ZPRIVS_LOWER
))
476 zlog (NULL
, LOG_ERR
, "Can't lower privileges");
480 #endif /* HAVE_IPV6 */