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"
31 #include "zebra/debug.h"
32 #include "zebra/rib.h"
35 rtm_write (int message
,
36 union sockunion
*dest
,
37 union sockunion
*mask
,
38 union sockunion
*gate
,
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
;
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
;
136 loopback
.s_addr
= htonl (INADDR_LOOPBACK
);
137 sin_gate
.sin_addr
= loopback
;
143 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
145 if (gate
&& p
->prefixlen
== 32)
149 masklen2ip (p
->prefixlen
, &sin_mask
.sin_addr
);
150 sin_mask
.sin_family
= AF_UNSPEC
;
152 sin_mask
.sin_len
= sin_masklen (sin_mask
.sin_addr
);
153 #endif /* HAVE_SIN_LEN */
158 error
= rtm_write (cmd
,
159 (union sockunion
*)&sin_dest
,
160 (union sockunion
*)mask
,
161 gate
? (union sockunion
*)&sin_gate
: NULL
,
169 zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
177 /* If there is no useful nexthop then return. */
178 if (nexthop_num
== 0)
180 if (IS_ZEBRA_DEBUG_KERNEL
)
181 zlog_info ("kernel_rtm_ipv4(): No useful nexthop.");
189 kernel_add_ipv4 (struct prefix
*p
, struct rib
*rib
)
191 return kernel_rtm_ipv4 (RTM_ADD
, p
, rib
, AF_INET
);
195 kernel_delete_ipv4 (struct prefix
*p
, struct rib
*rib
)
197 return kernel_rtm_ipv4 (RTM_DELETE
, p
, rib
, AF_INET
);
202 /* Calculate sin6_len value for netmask socket value. */
204 sin6_masklen (struct in6_addr mask
)
206 struct sockaddr_in6 sin6
;
211 if (IN_ANYADDR6 (mask
))
212 return sizeof (long);
214 if (IN6_IS_ADDR_UNSPECIFIED (&mask
))
215 return sizeof (long);
218 sin6
.sin6_addr
= mask
;
219 len
= sizeof (struct sockaddr_in6
);
221 lim
= (char *) & sin6
.sin6_addr
;
222 p
= lim
+ sizeof (sin6
.sin6_addr
);
224 while (*--p
== 0 && p
>= lim
)
230 /* Interface between zebra message and rtm message. */
232 kernel_rtm_ipv6 (int message
, struct prefix_ipv6
*dest
,
233 struct in6_addr
*gate
, int index
, int flags
)
235 struct sockaddr_in6
*mask
;
236 struct sockaddr_in6 sin_dest
, sin_mask
, sin_gate
;
238 memset (&sin_dest
, 0, sizeof (struct sockaddr_in6
));
239 sin_dest
.sin6_family
= AF_INET6
;
241 sin_dest
.sin6_len
= sizeof (struct sockaddr_in6
);
242 #endif /* SIN6_LEN */
244 memset (&sin_mask
, 0, sizeof (struct sockaddr_in6
));
246 memset (&sin_gate
, 0, sizeof (struct sockaddr_in6
));
247 sin_gate
.sin6_family
= AF_INET6
;
249 sin_gate
.sin6_len
= sizeof (struct sockaddr_in6
);
250 #endif /* SIN6_LEN */
252 sin_dest
.sin6_addr
= dest
->prefix
;
255 memcpy (&sin_gate
.sin6_addr
, gate
, sizeof (struct in6_addr
));
257 /* Under kame set interface index to link local address. */
260 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
262 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
263 (a).s6_addr[3] = (i) & 0xff; \
266 if (gate
&& IN6_IS_ADDR_LINKLOCAL(gate
))
267 SET_IN6_LINKLOCAL_IFINDEX (sin_gate
.sin6_addr
, index
);
270 if (gate
&& dest
->prefixlen
== 128)
274 masklen2ip6 (dest
->prefixlen
, &sin_mask
.sin6_addr
);
275 sin_mask
.sin6_family
= AF_UNSPEC
;
277 sin_mask
.sin6_len
= sin6_masklen (sin_mask
.sin6_addr
);
278 #endif /* SIN6_LEN */
282 return rtm_write (message
,
283 (union sockunion
*) &sin_dest
,
284 (union sockunion
*) mask
,
285 gate
? (union sockunion
*)&sin_gate
: NULL
,
291 /* Interface between zebra message and rtm message. */
293 kernel_rtm_ipv6_multipath (int cmd
, struct prefix
*p
, struct rib
*rib
,
296 struct sockaddr_in6
*mask
;
297 struct sockaddr_in6 sin_dest
, sin_mask
, sin_gate
;
298 struct nexthop
*nexthop
;
300 unsigned int ifindex
= 0;
304 memset (&sin_dest
, 0, sizeof (struct sockaddr_in6
));
305 sin_dest
.sin6_family
= AF_INET6
;
307 sin_dest
.sin6_len
= sizeof (struct sockaddr_in6
);
308 #endif /* SIN6_LEN */
309 sin_dest
.sin6_addr
= p
->u
.prefix6
;
311 memset (&sin_mask
, 0, sizeof (struct sockaddr_in6
));
313 memset (&sin_gate
, 0, sizeof (struct sockaddr_in6
));
314 sin_gate
.sin6_family
= AF_INET6
;
316 sin_gate
.sin6_len
= sizeof (struct sockaddr_in6
);
317 #endif /* HAVE_SIN_LEN */
320 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
325 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
326 || (cmd
== RTM_DELETE
328 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)
332 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
334 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV6
335 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
336 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
338 sin_gate
.sin6_addr
= nexthop
->rgate
.ipv6
;
341 if (nexthop
->rtype
== NEXTHOP_TYPE_IFINDEX
342 || nexthop
->rtype
== NEXTHOP_TYPE_IFNAME
343 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
344 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
345 ifindex
= nexthop
->rifindex
;
349 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
350 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
351 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
353 sin_gate
.sin6_addr
= nexthop
->gate
.ipv6
;
356 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
357 || nexthop
->type
== NEXTHOP_TYPE_IFNAME
358 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
359 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
360 ifindex
= nexthop
->ifindex
;
364 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
367 /* Under kame set interface index to link local address. */
370 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
372 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
373 (a).s6_addr[3] = (i) & 0xff; \
376 if (gate
&& IN6_IS_ADDR_LINKLOCAL(&sin_gate
.sin6_addr
))
377 SET_IN6_LINKLOCAL_IFINDEX (sin_gate
.sin6_addr
, ifindex
);
380 if (gate
&& p
->prefixlen
== 128)
384 masklen2ip6 (p
->prefixlen
, &sin_mask
.sin6_addr
);
385 sin_mask
.sin6_family
= AF_UNSPEC
;
387 sin_mask
.sin6_len
= sin6_masklen (sin_mask
.sin6_addr
);
388 #endif /* SIN6_LEN */
392 error
= rtm_write (cmd
,
393 (union sockunion
*) &sin_dest
,
394 (union sockunion
*) mask
,
395 gate
? (union sockunion
*)&sin_gate
: NULL
,
403 zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
411 /* If there is no useful nexthop then return. */
412 if (nexthop_num
== 0)
414 if (IS_ZEBRA_DEBUG_KERNEL
)
415 zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
423 kernel_add_ipv6 (struct prefix
*p
, struct rib
*rib
)
425 return kernel_rtm_ipv6_multipath (RTM_ADD
, p
, rib
, AF_INET6
);
429 kernel_delete_ipv6 (struct prefix
*p
, struct rib
*rib
)
431 return kernel_rtm_ipv6_multipath (RTM_DELETE
, p
, rib
, AF_INET6
);
434 /* Delete IPv6 route from the kernel. */
436 kernel_delete_ipv6_old (struct prefix_ipv6
*dest
, struct in6_addr
*gate
,
437 int index
, int flags
, int table
)
439 return kernel_rtm_ipv6 (RTM_DELETE
, dest
, gate
, index
, flags
);
441 #endif /* HAVE_IPV6 */