]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
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" | |
edd7c245 | 30 | #include "privs.h" |
718e3744 | 31 | |
32 | #include "zebra/debug.h" | |
33 | #include "zebra/rib.h" | |
6621ca86 | 34 | #include "zebra/rt.h" |
718e3744 | 35 | |
edd7c245 | 36 | extern struct zebra_privs_t zserv_privs; |
37 | ||
6621ca86 | 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); | |
718e3744 | 42 | |
43 | /* Adjust netmask socket length. Return value is a adjusted sin_len | |
44 | value. */ | |
6621ca86 | 45 | static int |
718e3744 | 46 | sin_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. */ | |
6621ca86 | 67 | static int |
718e3744 | 68 | kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) |
69 | ||
70 | { | |
fa2b17e3 | 71 | struct sockaddr_in *mask = NULL; |
718e3744 | 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; | |
595db7f1 | 132 | if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) |
133 | { | |
134 | struct in_addr loopback; | |
135 | loopback.s_addr = htonl (INADDR_LOOPBACK); | |
136 | sin_gate.sin_addr = loopback; | |
137 | gate = 1; | |
138 | } | |
139 | } | |
718e3744 | 140 | |
141 | if (cmd == RTM_ADD) | |
142 | SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); | |
143 | ||
144 | if (gate && p->prefixlen == 32) | |
145 | mask = NULL; | |
146 | else | |
147 | { | |
148 | masklen2ip (p->prefixlen, &sin_mask.sin_addr); | |
149 | sin_mask.sin_family = AF_UNSPEC; | |
150 | #ifdef HAVE_SIN_LEN | |
151 | sin_mask.sin_len = sin_masklen (sin_mask.sin_addr); | |
152 | #endif /* HAVE_SIN_LEN */ | |
153 | mask = &sin_mask; | |
154 | } | |
155 | } | |
156 | ||
157 | error = rtm_write (cmd, | |
158 | (union sockunion *)&sin_dest, | |
159 | (union sockunion *)mask, | |
160 | gate ? (union sockunion *)&sin_gate : NULL, | |
161 | ifindex, | |
162 | rib->flags, | |
163 | rib->metric); | |
164 | ||
165 | #if 0 | |
166 | if (error) | |
167 | { | |
168 | zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.", | |
169 | nexthop_num, error); | |
170 | } | |
171 | #endif | |
172 | ||
173 | nexthop_num++; | |
174 | } | |
175 | ||
176 | /* If there is no useful nexthop then return. */ | |
177 | if (nexthop_num == 0) | |
178 | { | |
179 | if (IS_ZEBRA_DEBUG_KERNEL) | |
b6178002 | 180 | zlog_debug ("kernel_rtm_ipv4(): No useful nexthop."); |
718e3744 | 181 | return 0; |
182 | } | |
183 | ||
184 | return 0; /*XXX*/ | |
185 | } | |
186 | ||
187 | int | |
188 | kernel_add_ipv4 (struct prefix *p, struct rib *rib) | |
189 | { | |
edd7c245 | 190 | int route; |
191 | ||
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"); | |
197 | ||
198 | return route; | |
718e3744 | 199 | } |
200 | ||
201 | int | |
202 | kernel_delete_ipv4 (struct prefix *p, struct rib *rib) | |
203 | { | |
edd7c245 | 204 | int route; |
205 | ||
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"); | |
211 | ||
212 | return route; | |
718e3744 | 213 | } |
214 | ||
215 | #ifdef HAVE_IPV6 | |
216 | ||
217 | /* Calculate sin6_len value for netmask socket value. */ | |
6621ca86 | 218 | static int |
718e3744 | 219 | sin6_masklen (struct in6_addr mask) |
220 | { | |
221 | struct sockaddr_in6 sin6; | |
222 | char *p, *lim; | |
223 | int len; | |
224 | ||
225 | #if defined (INRIA) | |
226 | if (IN_ANYADDR6 (mask)) | |
227 | return sizeof (long); | |
228 | #else /* ! INRIA */ | |
229 | if (IN6_IS_ADDR_UNSPECIFIED (&mask)) | |
230 | return sizeof (long); | |
231 | #endif /* ! INRIA */ | |
232 | ||
233 | sin6.sin6_addr = mask; | |
234 | len = sizeof (struct sockaddr_in6); | |
235 | ||
236 | lim = (char *) & sin6.sin6_addr; | |
237 | p = lim + sizeof (sin6.sin6_addr); | |
238 | ||
239 | while (*--p == 0 && p >= lim) | |
240 | len--; | |
241 | ||
242 | return len; | |
243 | } | |
244 | ||
245 | /* Interface between zebra message and rtm message. */ | |
6621ca86 | 246 | static int |
718e3744 | 247 | kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest, |
248 | struct in6_addr *gate, int index, int flags) | |
249 | { | |
250 | struct sockaddr_in6 *mask; | |
251 | struct sockaddr_in6 sin_dest, sin_mask, sin_gate; | |
252 | ||
253 | memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); | |
254 | sin_dest.sin6_family = AF_INET6; | |
255 | #ifdef SIN6_LEN | |
256 | sin_dest.sin6_len = sizeof (struct sockaddr_in6); | |
257 | #endif /* SIN6_LEN */ | |
258 | ||
259 | memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); | |
260 | ||
261 | memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); | |
262 | sin_gate.sin6_family = AF_INET6; | |
263 | #ifdef SIN6_LEN | |
264 | sin_gate.sin6_len = sizeof (struct sockaddr_in6); | |
265 | #endif /* SIN6_LEN */ | |
266 | ||
267 | sin_dest.sin6_addr = dest->prefix; | |
268 | ||
269 | if (gate) | |
270 | memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr)); | |
271 | ||
272 | /* Under kame set interface index to link local address. */ | |
273 | #ifdef KAME | |
274 | ||
275 | #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ | |
276 | do { \ | |
277 | (a).s6_addr[2] = ((i) >> 8) & 0xff; \ | |
278 | (a).s6_addr[3] = (i) & 0xff; \ | |
279 | } while (0) | |
280 | ||
281 | if (gate && IN6_IS_ADDR_LINKLOCAL(gate)) | |
282 | SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index); | |
283 | #endif /* KAME */ | |
284 | ||
285 | if (gate && dest->prefixlen == 128) | |
286 | mask = NULL; | |
287 | else | |
288 | { | |
289 | masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr); | |
6fe70d1b | 290 | sin_mask.sin6_family = AF_INET6; |
718e3744 | 291 | #ifdef SIN6_LEN |
292 | sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr); | |
293 | #endif /* SIN6_LEN */ | |
294 | mask = &sin_mask; | |
295 | } | |
296 | ||
297 | return rtm_write (message, | |
298 | (union sockunion *) &sin_dest, | |
299 | (union sockunion *) mask, | |
300 | gate ? (union sockunion *)&sin_gate : NULL, | |
301 | index, | |
302 | flags, | |
303 | 0); | |
304 | } | |
305 | ||
306 | /* Interface between zebra message and rtm message. */ | |
6621ca86 | 307 | static int |
718e3744 | 308 | kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, |
309 | int family) | |
310 | { | |
311 | struct sockaddr_in6 *mask; | |
312 | struct sockaddr_in6 sin_dest, sin_mask, sin_gate; | |
313 | struct nexthop *nexthop; | |
314 | int nexthop_num = 0; | |
315 | unsigned int ifindex = 0; | |
316 | int gate = 0; | |
317 | int error; | |
318 | ||
319 | memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); | |
320 | sin_dest.sin6_family = AF_INET6; | |
321 | #ifdef SIN6_LEN | |
322 | sin_dest.sin6_len = sizeof (struct sockaddr_in6); | |
323 | #endif /* SIN6_LEN */ | |
324 | sin_dest.sin6_addr = p->u.prefix6; | |
325 | ||
326 | memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); | |
327 | ||
328 | memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); | |
329 | sin_gate.sin6_family = AF_INET6; | |
330 | #ifdef HAVE_SIN_LEN | |
331 | sin_gate.sin6_len = sizeof (struct sockaddr_in6); | |
332 | #endif /* HAVE_SIN_LEN */ | |
333 | ||
334 | /* Make gateway. */ | |
335 | for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) | |
336 | { | |
337 | gate = 0; | |
338 | ||
339 | if ((cmd == RTM_ADD | |
340 | && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) | |
341 | || (cmd == RTM_DELETE | |
342 | #if 0 | |
343 | && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) | |
344 | #endif | |
345 | )) | |
346 | { | |
347 | if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) | |
348 | { | |
349 | if (nexthop->rtype == NEXTHOP_TYPE_IPV6 | |
350 | || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME | |
351 | || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) | |
352 | { | |
353 | sin_gate.sin6_addr = nexthop->rgate.ipv6; | |
354 | gate = 1; | |
355 | } | |
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; | |
361 | } | |
362 | else | |
363 | { | |
364 | if (nexthop->type == NEXTHOP_TYPE_IPV6 | |
365 | || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME | |
366 | || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) | |
367 | { | |
368 | sin_gate.sin6_addr = nexthop->gate.ipv6; | |
369 | gate = 1; | |
370 | } | |
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; | |
376 | } | |
377 | ||
378 | if (cmd == RTM_ADD) | |
379 | SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); | |
380 | } | |
381 | ||
382 | /* Under kame set interface index to link local address. */ | |
383 | #ifdef KAME | |
384 | ||
385 | #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ | |
386 | do { \ | |
387 | (a).s6_addr[2] = ((i) >> 8) & 0xff; \ | |
388 | (a).s6_addr[3] = (i) & 0xff; \ | |
389 | } while (0) | |
390 | ||
391 | if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr)) | |
392 | SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex); | |
393 | #endif /* KAME */ | |
394 | ||
395 | if (gate && p->prefixlen == 128) | |
396 | mask = NULL; | |
397 | else | |
398 | { | |
399 | masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr); | |
6fe70d1b | 400 | sin_mask.sin6_family = AF_INET6; |
718e3744 | 401 | #ifdef SIN6_LEN |
402 | sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr); | |
403 | #endif /* SIN6_LEN */ | |
404 | mask = &sin_mask; | |
405 | } | |
406 | ||
407 | error = rtm_write (cmd, | |
408 | (union sockunion *) &sin_dest, | |
409 | (union sockunion *) mask, | |
410 | gate ? (union sockunion *)&sin_gate : NULL, | |
411 | ifindex, | |
412 | rib->flags, | |
413 | rib->metric); | |
414 | ||
415 | #if 0 | |
416 | if (error) | |
417 | { | |
418 | zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.", | |
419 | nexthop_num, error); | |
420 | } | |
421 | #endif | |
422 | ||
423 | nexthop_num++; | |
424 | } | |
425 | ||
426 | /* If there is no useful nexthop then return. */ | |
427 | if (nexthop_num == 0) | |
428 | { | |
429 | if (IS_ZEBRA_DEBUG_KERNEL) | |
b6178002 | 430 | zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop."); |
718e3744 | 431 | return 0; |
432 | } | |
433 | ||
434 | return 0; /*XXX*/ | |
435 | } | |
436 | ||
437 | int | |
438 | kernel_add_ipv6 (struct prefix *p, struct rib *rib) | |
439 | { | |
edd7c245 | 440 | int route; |
441 | ||
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"); | |
447 | ||
448 | return route; | |
718e3744 | 449 | } |
450 | ||
451 | int | |
452 | kernel_delete_ipv6 (struct prefix *p, struct rib *rib) | |
453 | { | |
edd7c245 | 454 | int route; |
455 | ||
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"); | |
461 | ||
462 | return route; | |
718e3744 | 463 | } |
464 | ||
465 | /* Delete IPv6 route from the kernel. */ | |
466 | int | |
467 | kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, | |
6621ca86 | 468 | unsigned int index, int flags, int table) |
718e3744 | 469 | { |
edd7c245 | 470 | int route; |
471 | ||
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"); | |
477 | ||
478 | return route; | |
718e3744 | 479 | } |
480 | #endif /* HAVE_IPV6 */ |