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