blob: fe88be814b4965a773074a8b5eb6bc940a7b3aed [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
2 * Kernel routing table updates by routing socket.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
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
10 * later version.
11 *
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.
16 *
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
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "if.h"
26#include "prefix.h"
27#include "sockunion.h"
28#include "log.h"
29#include "str.h"
30
31#include "zebra/debug.h"
32#include "zebra/rib.h"
33
34int
35rtm_write (int message,
36 union sockunion *dest,
37 union sockunion *mask,
38 union sockunion *gate,
39 unsigned int index,
40 int zebra_flags,
41 int metric);
42
43/* Adjust netmask socket length. Return value is a adjusted sin_len
44 value. */
45int
46sin_masklen (struct in_addr mask)
47{
48 char *p, *lim;
49 int len;
50 struct sockaddr_in sin;
51
52 if (mask.s_addr == 0)
53 return sizeof (long);
54
55 sin.sin_addr = mask;
56 len = sizeof (struct sockaddr_in);
57
58 lim = (char *) &sin.sin_addr;
59 p = lim + sizeof (sin.sin_addr);
60
61 while (*--p == 0 && p >= lim)
62 len--;
63 return len;
64}
65
66/* Interface between zebra message and rtm message. */
67int
68kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
69
70{
71 struct sockaddr_in *mask;
72 struct sockaddr_in sin_dest, sin_mask, sin_gate;
73 struct nexthop *nexthop;
74 int nexthop_num = 0;
75 unsigned int ifindex = 0;
76 int gate = 0;
77 int error;
78
79 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
80 sin_dest.sin_family = AF_INET;
81#ifdef HAVE_SIN_LEN
82 sin_dest.sin_len = sizeof (struct sockaddr_in);
83#endif /* HAVE_SIN_LEN */
84 sin_dest.sin_addr = p->u.prefix4;
85
86 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
87
88 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
89 sin_gate.sin_family = AF_INET;
90#ifdef HAVE_SIN_LEN
91 sin_gate.sin_len = sizeof (struct sockaddr_in);
92#endif /* HAVE_SIN_LEN */
93
94 /* Make gateway. */
95 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
96 {
97 gate = 0;
98
99 if ((cmd == RTM_ADD
100 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
101 || (cmd == RTM_DELETE
102#if 0
103 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
104#endif
105 ))
106 {
107 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
108 {
109 if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
110 nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
111 {
112 sin_gate.sin_addr = nexthop->rgate.ipv4;
113 gate = 1;
114 }
115 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
116 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
117 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
118 ifindex = nexthop->rifindex;
119 }
120 else
121 {
122 if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
123 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
124 {
125 sin_gate.sin_addr = nexthop->gate.ipv4;
126 gate = 1;
127 }
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)
133 {
134 struct in_addr loopback;
135
136 loopback.s_addr = htonl (INADDR_LOOPBACK);
137 sin_gate.sin_addr = loopback;
138 gate = 1;
139 }
140 }
141
142 if (cmd == RTM_ADD)
143 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
144
145 if (gate && p->prefixlen == 32)
146 mask = NULL;
147 else
148 {
149 masklen2ip (p->prefixlen, &sin_mask.sin_addr);
150 sin_mask.sin_family = AF_UNSPEC;
151#ifdef HAVE_SIN_LEN
152 sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
153#endif /* HAVE_SIN_LEN */
154 mask = &sin_mask;
155 }
156 }
157
158 error = rtm_write (cmd,
159 (union sockunion *)&sin_dest,
160 (union sockunion *)mask,
161 gate ? (union sockunion *)&sin_gate : NULL,
162 ifindex,
163 rib->flags,
164 rib->metric);
165
166#if 0
167 if (error)
168 {
169 zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
170 nexthop_num, error);
171 }
172#endif
173
174 nexthop_num++;
175 }
176
177 /* If there is no useful nexthop then return. */
178 if (nexthop_num == 0)
179 {
180 if (IS_ZEBRA_DEBUG_KERNEL)
181 zlog_info ("kernel_rtm_ipv4(): No useful nexthop.");
182 return 0;
183 }
184
185 return 0; /*XXX*/
186}
187
188int
189kernel_add_ipv4 (struct prefix *p, struct rib *rib)
190{
191 return kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
192}
193
194int
195kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
196{
197 return kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
198}
199
200#ifdef HAVE_IPV6
201
202/* Calculate sin6_len value for netmask socket value. */
203int
204sin6_masklen (struct in6_addr mask)
205{
206 struct sockaddr_in6 sin6;
207 char *p, *lim;
208 int len;
209
210#if defined (INRIA)
211 if (IN_ANYADDR6 (mask))
212 return sizeof (long);
213#else /* ! INRIA */
214 if (IN6_IS_ADDR_UNSPECIFIED (&mask))
215 return sizeof (long);
216#endif /* ! INRIA */
217
218 sin6.sin6_addr = mask;
219 len = sizeof (struct sockaddr_in6);
220
221 lim = (char *) & sin6.sin6_addr;
222 p = lim + sizeof (sin6.sin6_addr);
223
224 while (*--p == 0 && p >= lim)
225 len--;
226
227 return len;
228}
229
230/* Interface between zebra message and rtm message. */
231int
232kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
233 struct in6_addr *gate, int index, int flags)
234{
235 struct sockaddr_in6 *mask;
236 struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
237
238 memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
239 sin_dest.sin6_family = AF_INET6;
240#ifdef SIN6_LEN
241 sin_dest.sin6_len = sizeof (struct sockaddr_in6);
242#endif /* SIN6_LEN */
243
244 memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
245
246 memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
247 sin_gate.sin6_family = AF_INET6;
248#ifdef SIN6_LEN
249 sin_gate.sin6_len = sizeof (struct sockaddr_in6);
250#endif /* SIN6_LEN */
251
252 sin_dest.sin6_addr = dest->prefix;
253
254 if (gate)
255 memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
256
257 /* Under kame set interface index to link local address. */
258#ifdef KAME
259
260#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
261 do { \
262 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
263 (a).s6_addr[3] = (i) & 0xff; \
264 } while (0)
265
266 if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
267 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
268#endif /* KAME */
269
270 if (gate && dest->prefixlen == 128)
271 mask = NULL;
272 else
273 {
274 masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
275 sin_mask.sin6_family = AF_UNSPEC;
276#ifdef SIN6_LEN
277 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
278#endif /* SIN6_LEN */
279 mask = &sin_mask;
280 }
281
282 return rtm_write (message,
283 (union sockunion *) &sin_dest,
284 (union sockunion *) mask,
285 gate ? (union sockunion *)&sin_gate : NULL,
286 index,
287 flags,
288 0);
289}
290
291/* Interface between zebra message and rtm message. */
292int
293kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
294 int family)
295{
296 struct sockaddr_in6 *mask;
297 struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
298 struct nexthop *nexthop;
299 int nexthop_num = 0;
300 unsigned int ifindex = 0;
301 int gate = 0;
302 int error;
303
304 memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
305 sin_dest.sin6_family = AF_INET6;
306#ifdef SIN6_LEN
307 sin_dest.sin6_len = sizeof (struct sockaddr_in6);
308#endif /* SIN6_LEN */
309 sin_dest.sin6_addr = p->u.prefix6;
310
311 memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
312
313 memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
314 sin_gate.sin6_family = AF_INET6;
315#ifdef HAVE_SIN_LEN
316 sin_gate.sin6_len = sizeof (struct sockaddr_in6);
317#endif /* HAVE_SIN_LEN */
318
319 /* Make gateway. */
320 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
321 {
322 gate = 0;
323
324 if ((cmd == RTM_ADD
325 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
326 || (cmd == RTM_DELETE
327#if 0
328 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
329#endif
330 ))
331 {
332 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
333 {
334 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
335 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
336 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
337 {
338 sin_gate.sin6_addr = nexthop->rgate.ipv6;
339 gate = 1;
340 }
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;
346 }
347 else
348 {
349 if (nexthop->type == NEXTHOP_TYPE_IPV6
350 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
351 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
352 {
353 sin_gate.sin6_addr = nexthop->gate.ipv6;
354 gate = 1;
355 }
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;
361 }
362
363 if (cmd == RTM_ADD)
364 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
365 }
366
367 /* Under kame set interface index to link local address. */
368#ifdef KAME
369
370#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
371 do { \
372 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
373 (a).s6_addr[3] = (i) & 0xff; \
374 } while (0)
375
376 if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
377 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
378#endif /* KAME */
379
380 if (gate && p->prefixlen == 128)
381 mask = NULL;
382 else
383 {
384 masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
385 sin_mask.sin6_family = AF_UNSPEC;
386#ifdef SIN6_LEN
387 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
388#endif /* SIN6_LEN */
389 mask = &sin_mask;
390 }
391
392 error = rtm_write (cmd,
393 (union sockunion *) &sin_dest,
394 (union sockunion *) mask,
395 gate ? (union sockunion *)&sin_gate : NULL,
396 ifindex,
397 rib->flags,
398 rib->metric);
399
400#if 0
401 if (error)
402 {
403 zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
404 nexthop_num, error);
405 }
406#endif
407
408 nexthop_num++;
409 }
410
411 /* If there is no useful nexthop then return. */
412 if (nexthop_num == 0)
413 {
414 if (IS_ZEBRA_DEBUG_KERNEL)
415 zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
416 return 0;
417 }
418
419 return 0; /*XXX*/
420}
421
422int
423kernel_add_ipv6 (struct prefix *p, struct rib *rib)
424{
425 return kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
426}
427
428int
429kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
430{
431 return kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
432}
433
434/* Delete IPv6 route from the kernel. */
435int
436kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
437 int index, int flags, int table)
438{
439 return kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
440}
441#endif /* HAVE_IPV6 */