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
)
70 struct sockaddr_in
*mask
= NULL
;
71 struct sockaddr_in sin_dest
, sin_mask
, sin_gate
;
72 struct nexthop
*nexthop
;
74 unsigned int ifindex
= 0;
78 memset (&sin_dest
, 0, sizeof (struct sockaddr_in
));
79 sin_dest
.sin_family
= AF_INET
;
81 sin_dest
.sin_len
= sizeof (struct sockaddr_in
);
82 #endif /* HAVE_SIN_LEN */
83 sin_dest
.sin_addr
= p
->u
.prefix4
;
85 memset (&sin_mask
, 0, sizeof (struct sockaddr_in
));
87 memset (&sin_gate
, 0, sizeof (struct sockaddr_in
));
88 sin_gate
.sin_family
= AF_INET
;
90 sin_gate
.sin_len
= sizeof (struct sockaddr_in
);
91 #endif /* HAVE_SIN_LEN */
94 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
99 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
100 || (cmd
== RTM_DELETE
102 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)
106 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
108 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV4
||
109 nexthop
->rtype
== NEXTHOP_TYPE_IPV4_IFINDEX
)
111 sin_gate
.sin_addr
= nexthop
->rgate
.ipv4
;
114 if (nexthop
->rtype
== NEXTHOP_TYPE_IFINDEX
115 || nexthop
->rtype
== NEXTHOP_TYPE_IFNAME
116 || nexthop
->rtype
== NEXTHOP_TYPE_IPV4_IFINDEX
)
117 ifindex
= nexthop
->rifindex
;
121 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
||
122 nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
124 sin_gate
.sin_addr
= nexthop
->gate
.ipv4
;
127 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
128 || nexthop
->type
== NEXTHOP_TYPE_IFNAME
129 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
130 ifindex
= nexthop
->ifindex
;
131 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
)
133 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_UNSPEC
;
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_info ("kernel_rtm_ipv4(): No useful nexthop.");
188 kernel_add_ipv4 (struct prefix
*p
, struct rib
*rib
)
190 return kernel_rtm_ipv4 (RTM_ADD
, p
, rib
, AF_INET
);
194 kernel_delete_ipv4 (struct prefix
*p
, struct rib
*rib
)
196 return kernel_rtm_ipv4 (RTM_DELETE
, p
, rib
, AF_INET
);
201 /* Calculate sin6_len value for netmask socket value. */
203 sin6_masklen (struct in6_addr mask
)
205 struct sockaddr_in6 sin6
;
210 if (IN_ANYADDR6 (mask
))
211 return sizeof (long);
213 if (IN6_IS_ADDR_UNSPECIFIED (&mask
))
214 return sizeof (long);
217 sin6
.sin6_addr
= mask
;
218 len
= sizeof (struct sockaddr_in6
);
220 lim
= (char *) & sin6
.sin6_addr
;
221 p
= lim
+ sizeof (sin6
.sin6_addr
);
223 while (*--p
== 0 && p
>= lim
)
229 /* Interface between zebra message and rtm message. */
231 kernel_rtm_ipv6 (int message
, struct prefix_ipv6
*dest
,
232 struct in6_addr
*gate
, int index
, int flags
)
234 struct sockaddr_in6
*mask
;
235 struct sockaddr_in6 sin_dest
, sin_mask
, sin_gate
;
237 memset (&sin_dest
, 0, sizeof (struct sockaddr_in6
));
238 sin_dest
.sin6_family
= AF_INET6
;
240 sin_dest
.sin6_len
= sizeof (struct sockaddr_in6
);
241 #endif /* SIN6_LEN */
243 memset (&sin_mask
, 0, sizeof (struct sockaddr_in6
));
245 memset (&sin_gate
, 0, sizeof (struct sockaddr_in6
));
246 sin_gate
.sin6_family
= AF_INET6
;
248 sin_gate
.sin6_len
= sizeof (struct sockaddr_in6
);
249 #endif /* SIN6_LEN */
251 sin_dest
.sin6_addr
= dest
->prefix
;
254 memcpy (&sin_gate
.sin6_addr
, gate
, sizeof (struct in6_addr
));
256 /* Under kame set interface index to link local address. */
259 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
261 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
262 (a).s6_addr[3] = (i) & 0xff; \
265 if (gate
&& IN6_IS_ADDR_LINKLOCAL(gate
))
266 SET_IN6_LINKLOCAL_IFINDEX (sin_gate
.sin6_addr
, index
);
269 if (gate
&& dest
->prefixlen
== 128)
273 masklen2ip6 (dest
->prefixlen
, &sin_mask
.sin6_addr
);
274 sin_mask
.sin6_family
= AF_UNSPEC
;
276 sin_mask
.sin6_len
= sin6_masklen (sin_mask
.sin6_addr
);
277 #endif /* SIN6_LEN */
281 return rtm_write (message
,
282 (union sockunion
*) &sin_dest
,
283 (union sockunion
*) mask
,
284 gate
? (union sockunion
*)&sin_gate
: NULL
,
290 /* Interface between zebra message and rtm message. */
292 kernel_rtm_ipv6_multipath (int cmd
, struct prefix
*p
, struct rib
*rib
,
295 struct sockaddr_in6
*mask
;
296 struct sockaddr_in6 sin_dest
, sin_mask
, sin_gate
;
297 struct nexthop
*nexthop
;
299 unsigned int ifindex
= 0;
303 memset (&sin_dest
, 0, sizeof (struct sockaddr_in6
));
304 sin_dest
.sin6_family
= AF_INET6
;
306 sin_dest
.sin6_len
= sizeof (struct sockaddr_in6
);
307 #endif /* SIN6_LEN */
308 sin_dest
.sin6_addr
= p
->u
.prefix6
;
310 memset (&sin_mask
, 0, sizeof (struct sockaddr_in6
));
312 memset (&sin_gate
, 0, sizeof (struct sockaddr_in6
));
313 sin_gate
.sin6_family
= AF_INET6
;
315 sin_gate
.sin6_len
= sizeof (struct sockaddr_in6
);
316 #endif /* HAVE_SIN_LEN */
319 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
324 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
325 || (cmd
== RTM_DELETE
327 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)
331 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
333 if (nexthop
->rtype
== NEXTHOP_TYPE_IPV6
334 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
335 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
337 sin_gate
.sin6_addr
= nexthop
->rgate
.ipv6
;
340 if (nexthop
->rtype
== NEXTHOP_TYPE_IFINDEX
341 || nexthop
->rtype
== NEXTHOP_TYPE_IFNAME
342 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFNAME
343 || nexthop
->rtype
== NEXTHOP_TYPE_IPV6_IFINDEX
)
344 ifindex
= nexthop
->rifindex
;
348 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
349 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
350 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
352 sin_gate
.sin6_addr
= nexthop
->gate
.ipv6
;
355 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
356 || nexthop
->type
== NEXTHOP_TYPE_IFNAME
357 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFNAME
358 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
359 ifindex
= nexthop
->ifindex
;
360 if (nexthop
->type
== NEXTHOP_TYPE_BLACKHOLE
)
362 #ifdef HAVE_IN6ADDR_GLOBAL
363 sin_gate
.sin6_addr
= in6addr_loopback
;
364 #else /*HAVE_IN6ADDR_GLOBAL*/
365 inet_pton (AF_INET6
, "::1", &sin_gate
.sin6_addr
);
366 #endif /*HAVE_IN6ADDR_GLOBAL*/
372 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
375 /* Under kame set interface index to link local address. */
378 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
380 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
381 (a).s6_addr[3] = (i) & 0xff; \
384 if (gate
&& IN6_IS_ADDR_LINKLOCAL(&sin_gate
.sin6_addr
))
385 SET_IN6_LINKLOCAL_IFINDEX (sin_gate
.sin6_addr
, ifindex
);
388 if (gate
&& p
->prefixlen
== 128)
392 masklen2ip6 (p
->prefixlen
, &sin_mask
.sin6_addr
);
393 sin_mask
.sin6_family
= AF_UNSPEC
;
395 sin_mask
.sin6_len
= sin6_masklen (sin_mask
.sin6_addr
);
396 #endif /* SIN6_LEN */
400 error
= rtm_write (cmd
,
401 (union sockunion
*) &sin_dest
,
402 (union sockunion
*) mask
,
403 gate
? (union sockunion
*)&sin_gate
: NULL
,
411 zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
419 /* If there is no useful nexthop then return. */
420 if (nexthop_num
== 0)
422 if (IS_ZEBRA_DEBUG_KERNEL
)
423 zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
431 kernel_add_ipv6 (struct prefix
*p
, struct rib
*rib
)
433 return kernel_rtm_ipv6_multipath (RTM_ADD
, p
, rib
, AF_INET6
);
437 kernel_delete_ipv6 (struct prefix
*p
, struct rib
*rib
)
439 return kernel_rtm_ipv6_multipath (RTM_DELETE
, p
, rib
, AF_INET6
);
442 /* Delete IPv6 route from the kernel. */
444 kernel_delete_ipv6_old (struct prefix_ipv6
*dest
, struct in6_addr
*gate
,
445 int index
, int flags
, int table
)
447 return kernel_rtm_ipv6 (RTM_DELETE
, dest
, gate
, index
, flags
);
449 #endif /* HAVE_IPV6 */