]> git.proxmox.com Git - mirror_frr.git/blob - zebra/rt_socket.c
Merge pull request #762 from bingen/mutiple_nh_recursive_levels
[mirror_frr.git] / zebra / rt_socket.c
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 along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <zebra.h>
23 #ifdef __OpenBSD__
24 #include <netmpls/mpls.h>
25 #endif
26
27 #include "if.h"
28 #include "prefix.h"
29 #include "sockunion.h"
30 #include "log.h"
31 #include "privs.h"
32
33 #include "zebra/debug.h"
34 #include "zebra/rib.h"
35 #include "zebra/rt.h"
36 #include "zebra/kernel_socket.h"
37 #include "zebra/zebra_mpls.h"
38
39 extern struct zebra_privs_t zserv_privs;
40
41 /* kernel socket export */
42 extern int rtm_write (int message, union sockunion *dest,
43 union sockunion *mask, union sockunion *gate,
44 union sockunion *mpls, unsigned int index,
45 int zebra_flags, int metric);
46
47 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
48 /* Adjust netmask socket length. Return value is a adjusted sin_len
49 value. */
50 static int
51 sin_masklen (struct in_addr mask)
52 {
53 char *p, *lim;
54 int len;
55 struct sockaddr_in sin;
56
57 if (mask.s_addr == 0)
58 return sizeof (long);
59
60 sin.sin_addr = mask;
61 len = sizeof (struct sockaddr_in);
62
63 lim = (char *) &sin.sin_addr;
64 p = lim + sizeof (sin.sin_addr);
65
66 while (*--p == 0 && p >= lim)
67 len--;
68 return len;
69 }
70 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
71
72 /* Interface between zebra message and rtm message. */
73 static int
74 kernel_rtm_ipv4 (int cmd, struct prefix *p, struct route_entry *re)
75
76 {
77 struct sockaddr_in *mask = NULL;
78 struct sockaddr_in sin_dest, sin_mask, sin_gate;
79 #ifdef __OpenBSD__
80 struct sockaddr_mpls smpls;
81 #endif
82 union sockunion *smplsp = NULL;
83 struct nexthop *nexthop;
84 int nexthop_num = 0;
85 ifindex_t ifindex = 0;
86 int gate = 0;
87 int error;
88 char prefix_buf[PREFIX_STRLEN];
89
90 if (IS_ZEBRA_DEBUG_RIB)
91 prefix2str (p, prefix_buf, sizeof(prefix_buf));
92 memset (&sin_dest, 0, sizeof (struct sockaddr_in));
93 sin_dest.sin_family = AF_INET;
94 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
95 sin_dest.sin_len = sizeof (struct sockaddr_in);
96 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
97 sin_dest.sin_addr = p->u.prefix4;
98
99 memset (&sin_mask, 0, sizeof (struct sockaddr_in));
100
101 memset (&sin_gate, 0, sizeof (struct sockaddr_in));
102 sin_gate.sin_family = AF_INET;
103 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
104 sin_gate.sin_len = sizeof (struct sockaddr_in);
105 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
106
107 /* Make gateway. */
108 for (ALL_NEXTHOPS(re->nexthop, nexthop))
109 {
110 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
111 continue;
112
113 gate = 0;
114 char gate_buf[INET_ADDRSTRLEN] = "NULL";
115
116 /*
117 * XXX We need to refrain from kernel operations in some cases,
118 * but this if statement seems overly cautious - what about
119 * other than ADD and DELETE?
120 */
121 if ((cmd == RTM_ADD
122 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
123 || (cmd == RTM_DELETE
124 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
125 ))
126 {
127 if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
128 nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
129 {
130 sin_gate.sin_addr = nexthop->gate.ipv4;
131 gate = 1;
132 }
133 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
134 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
135 ifindex = nexthop->ifindex;
136 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
137 {
138 struct in_addr loopback;
139 loopback.s_addr = htonl (INADDR_LOOPBACK);
140 sin_gate.sin_addr = loopback;
141 gate = 1;
142 }
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_INET;
150 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
151 sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
152 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
153 mask = &sin_mask;
154 }
155
156 #ifdef __OpenBSD__
157 if (nexthop->nh_label)
158 {
159 memset (&smpls, 0, sizeof (smpls));
160 smpls.smpls_len = sizeof (smpls);
161 smpls.smpls_family = AF_MPLS;
162 smpls.smpls_label =
163 htonl (nexthop->nh_label->label[0] << MPLS_LABEL_OFFSET);
164 smplsp = (union sockunion *)&smpls;
165 }
166 #endif
167
168 error = rtm_write (cmd,
169 (union sockunion *)&sin_dest,
170 (union sockunion *)mask,
171 gate ? (union sockunion *)&sin_gate : NULL,
172 smplsp,
173 ifindex,
174 re->flags,
175 re->metric);
176
177 if (IS_ZEBRA_DEBUG_RIB)
178 {
179 if (!gate)
180 {
181 zlog_debug ("%s: %s: attention! gate not found for re %p",
182 __func__, prefix_buf, re);
183 route_entry_dump (p, NULL, re);
184 }
185 else
186 inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN);
187 }
188
189 switch (error)
190 {
191 /* We only flag nexthops as being in FIB if rtm_write() did its work. */
192 case ZEBRA_ERR_NOERROR:
193 nexthop_num++;
194 if (IS_ZEBRA_DEBUG_RIB)
195 zlog_debug ("%s: %s: successfully did NH %s",
196 __func__, prefix_buf, gate_buf);
197 if (cmd == RTM_ADD)
198 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
199 break;
200
201 /* The only valid case for this error is kernel's failure to install
202 * a multipath route, which is common for FreeBSD. This should be
203 * ignored silently, but logged as an error otherwise.
204 */
205 case ZEBRA_ERR_RTEXIST:
206 if (cmd != RTM_ADD)
207 zlog_err ("%s: rtm_write() returned %d for command %d",
208 __func__, error, cmd);
209 continue;
210 break;
211
212 /* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't
213 * normal to get any other messages in ANY case.
214 */
215 case ZEBRA_ERR_RTNOEXIST:
216 case ZEBRA_ERR_RTUNREACH:
217 default:
218 zlog_err ("%s: %s: rtm_write() unexpectedly returned %d for command %s",
219 __func__, prefix2str(p, prefix_buf, sizeof(prefix_buf)),
220 error, lookup_msg(rtm_type_str, cmd, NULL));
221 break;
222 }
223 } /* if (cmd and flags make sense) */
224 else
225 if (IS_ZEBRA_DEBUG_RIB)
226 zlog_debug ("%s: odd command %s for flags %d",
227 __func__, lookup_msg(rtm_type_str, cmd, NULL), nexthop->flags);
228 } /* for (ALL_NEXTHOPS(...))*/
229
230 /* If there was no useful nexthop, then complain. */
231 if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL)
232 zlog_debug ("%s: No useful nexthops were found in RIB entry %p", __func__, re);
233
234 return 0; /*XXX*/
235 }
236
237 #ifdef SIN6_LEN
238 /* Calculate sin6_len value for netmask socket value. */
239 static int
240 sin6_masklen (struct in6_addr mask)
241 {
242 struct sockaddr_in6 sin6;
243 char *p, *lim;
244 int len;
245
246 if (IN6_IS_ADDR_UNSPECIFIED (&mask))
247 return sizeof (long);
248
249 sin6.sin6_addr = mask;
250 len = sizeof (struct sockaddr_in6);
251
252 lim = (char *) & sin6.sin6_addr;
253 p = lim + sizeof (sin6.sin6_addr);
254
255 while (*--p == 0 && p >= lim)
256 len--;
257
258 return len;
259 }
260 #endif /* SIN6_LEN */
261
262 /* Interface between zebra message and rtm message. */
263 static int
264 kernel_rtm_ipv6 (int cmd, struct prefix *p, struct route_entry *re)
265 {
266 struct sockaddr_in6 *mask;
267 struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
268 struct nexthop *nexthop;
269 int nexthop_num = 0;
270 ifindex_t ifindex = 0;
271 int gate = 0;
272 int error;
273
274 memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
275 sin_dest.sin6_family = AF_INET6;
276 #ifdef SIN6_LEN
277 sin_dest.sin6_len = sizeof (struct sockaddr_in6);
278 #endif /* SIN6_LEN */
279 sin_dest.sin6_addr = p->u.prefix6;
280
281 memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
282
283 memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
284 sin_gate.sin6_family = AF_INET6;
285 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
286 sin_gate.sin6_len = sizeof (struct sockaddr_in6);
287 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
288
289 /* Make gateway. */
290 for (ALL_NEXTHOPS(re->nexthop, nexthop))
291 {
292 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
293 continue;
294
295 gate = 0;
296
297 if ((cmd == RTM_ADD
298 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
299 || (cmd == RTM_DELETE
300 #if 0
301 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
302 #endif
303 ))
304 {
305 if (nexthop->type == NEXTHOP_TYPE_IPV6
306 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
307 {
308 sin_gate.sin6_addr = nexthop->gate.ipv6;
309 gate = 1;
310 }
311 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
312 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
313 ifindex = nexthop->ifindex;
314
315 if (cmd == RTM_ADD)
316 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
317 }
318
319 /* Under kame set interface index to link local address. */
320 #ifdef KAME
321
322 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
323 do { \
324 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
325 (a).s6_addr[3] = (i) & 0xff; \
326 } while (0)
327
328 if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
329 SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
330 #endif /* KAME */
331
332 if (gate && p->prefixlen == 128)
333 mask = NULL;
334 else
335 {
336 masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
337 sin_mask.sin6_family = AF_INET6;
338 #ifdef SIN6_LEN
339 sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
340 #endif /* SIN6_LEN */
341 mask = &sin_mask;
342 }
343
344 error = rtm_write (cmd,
345 (union sockunion *) &sin_dest,
346 (union sockunion *) mask,
347 gate ? (union sockunion *)&sin_gate : NULL,
348 NULL,
349 ifindex,
350 re->flags,
351 re->metric);
352
353 #if 0
354 if (error)
355 {
356 zlog_info ("kernel_rtm_ipv6(): nexthop %d add error=%d.",
357 nexthop_num, error);
358 }
359 #else
360 (void)error;
361 #endif
362
363 nexthop_num++;
364 }
365
366 /* If there is no useful nexthop then return. */
367 if (nexthop_num == 0)
368 {
369 if (IS_ZEBRA_DEBUG_KERNEL)
370 zlog_debug ("kernel_rtm_ipv6(): No useful nexthop.");
371 return 0;
372 }
373
374 return 0; /*XXX*/
375 }
376
377 static int
378 kernel_rtm (int cmd, struct prefix *p, struct route_entry *re)
379 {
380 switch (PREFIX_FAMILY(p))
381 {
382 case AF_INET:
383 return kernel_rtm_ipv4 (cmd, p, re);
384 case AF_INET6:
385 return kernel_rtm_ipv6 (cmd, p, re);
386 }
387 return 0;
388 }
389
390 int
391 kernel_route_rib (struct prefix *p, struct prefix *src_p,
392 struct route_entry *old, struct route_entry *new)
393 {
394 int route = 0;
395
396 if (src_p && src_p->prefixlen)
397 {
398 zlog_err ("route add: IPv6 sourcedest routes unsupported!");
399 return 1;
400 }
401
402 if (zserv_privs.change(ZPRIVS_RAISE))
403 zlog_err("Can't raise privileges");
404
405 if (old)
406 route |= kernel_rtm (RTM_DELETE, p, old);
407
408 if (new)
409 route |= kernel_rtm (RTM_ADD, p, new);
410
411 if (zserv_privs.change(ZPRIVS_LOWER))
412 zlog_err("Can't lower privileges");
413
414 return route;
415 }
416
417 int
418 kernel_neigh_update (int add, int ifindex, uint32_t addr, char *lla, int llalen)
419 {
420 /* TODO */
421 return 0;
422 }
423
424 extern int
425 kernel_get_ipmr_sg_stats (void *mroute)
426 {
427 return 0;
428 }