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