blob: cd2f26ca861b5333d27e1ead170e594d2c87d3ea [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;
paul718e3742002-12-13 20:15:29 +0000132 }
133
134 if (cmd == RTM_ADD)
135 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
136
137 if (gate && p->prefixlen == 32)
138 mask = NULL;
139 else
140 {
141 masklen2ip (p->prefixlen, &sin_mask.sin_addr);
142 sin_mask.sin_family = AF_UNSPEC;
143#ifdef HAVE_SIN_LEN
144 sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
145#endif /* HAVE_SIN_LEN */
146 mask = &sin_mask;
147 }
148 }
149
150 error = rtm_write (cmd,
151 (union sockunion *)&sin_dest,
152 (union sockunion *)mask,
153 gate ? (union sockunion *)&sin_gate : NULL,
154 ifindex,
155 rib->flags,
156 rib->metric);
157
158#if 0
159 if (error)
160 {
161 zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
162 nexthop_num, error);
163 }
164#endif
165
166 nexthop_num++;
167 }
168
169 /* If there is no useful nexthop then return. */
170 if (nexthop_num == 0)
171 {
172 if (IS_ZEBRA_DEBUG_KERNEL)
173 zlog_info ("kernel_rtm_ipv4(): No useful nexthop.");
174 return 0;
175 }
176
177 return 0; /*XXX*/
178}
179
180int
181kernel_add_ipv4 (struct prefix *p, struct rib *rib)
182{
183 return kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
184}
185
186int
187kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
188{
189 return kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
190}
191
192#ifdef HAVE_IPV6
193
194/* Calculate sin6_len value for netmask socket value. */
195int
196sin6_masklen (struct in6_addr mask)
197{
198 struct sockaddr_in6 sin6;
199 char *p, *lim;
200 int len;
201
202#if defined (INRIA)
203 if (IN_ANYADDR6 (mask))
204 return sizeof (long);
205#else /* ! INRIA */
206 if (IN6_IS_ADDR_UNSPECIFIED (&mask))
207 return sizeof (long);
208#endif /* ! INRIA */
209
210 sin6.sin6_addr = mask;
211 len = sizeof (struct sockaddr_in6);
212
213 lim = (char *) & sin6.sin6_addr;
214 p = lim + sizeof (sin6.sin6_addr);
215
216 while (*--p == 0 && p >= lim)
217 len--;
218
219 return len;
220}
221
222/* Interface between zebra message and rtm message. */
223int
224kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
225 struct in6_addr *gate, int index, int flags)
226{
227 struct sockaddr_in6 *mask;
228 struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
229
230 memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
231 sin_dest.sin6_family = AF_INET6;
232#ifdef SIN6_LEN
233 sin_dest.sin6_len = sizeof (struct sockaddr_in6);
234#endif /* SIN6_LEN */
235
236 memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
237
238 memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
239 sin_gate.sin6_family = AF_INET6;
240#ifdef SIN6_LEN
241 sin_gate.sin6_len = sizeof (struct sockaddr_in6);
242#endif /* SIN6_LEN */
243
244 sin_dest.sin6_addr = dest->prefix;
245
246 if (gate)
247 memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
248
249 /* Under kame set interface index to link local address. */
250#ifdef KAME
251
252#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
253 do { \
254 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
255 (a).s6_addr[3] = (i) & 0xff; \
256 } while (0)
257
258 if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
259 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
260#endif /* KAME */
261
262 if (gate && dest->prefixlen == 128)
263 mask = NULL;
264 else
265 {
266 masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
267 sin_mask.sin6_family = AF_UNSPEC;
268#ifdef SIN6_LEN
269 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
270#endif /* SIN6_LEN */
271 mask = &sin_mask;
272 }
273
274 return rtm_write (message,
275 (union sockunion *) &sin_dest,
276 (union sockunion *) mask,
277 gate ? (union sockunion *)&sin_gate : NULL,
278 index,
279 flags,
280 0);
281}
282
283/* Interface between zebra message and rtm message. */
284int
285kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
286 int family)
287{
288 struct sockaddr_in6 *mask;
289 struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
290 struct nexthop *nexthop;
291 int nexthop_num = 0;
292 unsigned int ifindex = 0;
293 int gate = 0;
294 int error;
295
296 memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
297 sin_dest.sin6_family = AF_INET6;
298#ifdef SIN6_LEN
299 sin_dest.sin6_len = sizeof (struct sockaddr_in6);
300#endif /* SIN6_LEN */
301 sin_dest.sin6_addr = p->u.prefix6;
302
303 memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
304
305 memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
306 sin_gate.sin6_family = AF_INET6;
307#ifdef HAVE_SIN_LEN
308 sin_gate.sin6_len = sizeof (struct sockaddr_in6);
309#endif /* HAVE_SIN_LEN */
310
311 /* Make gateway. */
312 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
313 {
314 gate = 0;
315
316 if ((cmd == RTM_ADD
317 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
318 || (cmd == RTM_DELETE
319#if 0
320 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
321#endif
322 ))
323 {
324 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
325 {
326 if (nexthop->rtype == NEXTHOP_TYPE_IPV6
327 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
328 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
329 {
330 sin_gate.sin6_addr = nexthop->rgate.ipv6;
331 gate = 1;
332 }
333 if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
334 || nexthop->rtype == NEXTHOP_TYPE_IFNAME
335 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
336 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
337 ifindex = nexthop->rifindex;
338 }
339 else
340 {
341 if (nexthop->type == NEXTHOP_TYPE_IPV6
342 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
343 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
344 {
345 sin_gate.sin6_addr = nexthop->gate.ipv6;
346 gate = 1;
347 }
348 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
349 || nexthop->type == NEXTHOP_TYPE_IFNAME
350 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
351 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
352 ifindex = nexthop->ifindex;
353 }
354
355 if (cmd == RTM_ADD)
356 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
357 }
358
359 /* Under kame set interface index to link local address. */
360#ifdef KAME
361
362#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
363 do { \
364 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
365 (a).s6_addr[3] = (i) & 0xff; \
366 } while (0)
367
368 if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
369 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
370#endif /* KAME */
371
372 if (gate && p->prefixlen == 128)
373 mask = NULL;
374 else
375 {
376 masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
377 sin_mask.sin6_family = AF_UNSPEC;
378#ifdef SIN6_LEN
379 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
380#endif /* SIN6_LEN */
381 mask = &sin_mask;
382 }
383
384 error = rtm_write (cmd,
385 (union sockunion *) &sin_dest,
386 (union sockunion *) mask,
387 gate ? (union sockunion *)&sin_gate : NULL,
388 ifindex,
389 rib->flags,
390 rib->metric);
391
392#if 0
393 if (error)
394 {
395 zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
396 nexthop_num, error);
397 }
398#endif
399
400 nexthop_num++;
401 }
402
403 /* If there is no useful nexthop then return. */
404 if (nexthop_num == 0)
405 {
406 if (IS_ZEBRA_DEBUG_KERNEL)
407 zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
408 return 0;
409 }
410
411 return 0; /*XXX*/
412}
413
414int
415kernel_add_ipv6 (struct prefix *p, struct rib *rib)
416{
417 return kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
418}
419
420int
421kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
422{
423 return kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
424}
425
426/* Delete IPv6 route from the kernel. */
427int
428kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
429 int index, int flags, int table)
430{
431 return kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
432}
433#endif /* HAVE_IPV6 */