]> git.proxmox.com Git - mirror_frr.git/blame - zebra/rt_socket.c
ospf6d: When removing a vertex free memory associated with it
[mirror_frr.git] / zebra / rt_socket.c
CommitLineData
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
ac4d0be5 20 * 02111-1307, USA.
718e3744 21 */
22
23#include <zebra.h>
fe6c7157 24#ifdef __OpenBSD__
d3e2c74a
RW
25#include <netmpls/mpls.h>
26#endif
718e3744 27
28#include "if.h"
29#include "prefix.h"
30#include "sockunion.h"
31#include "log.h"
edd7c245 32#include "privs.h"
718e3744 33
34#include "zebra/debug.h"
35#include "zebra/rib.h"
6621ca86 36#include "zebra/rt.h"
dc95824a 37#include "zebra/kernel_socket.h"
d3e2c74a 38#include "zebra/zebra_mpls.h"
718e3744 39
edd7c245 40extern struct zebra_privs_t zserv_privs;
41
6621ca86 42/* kernel socket export */
ac4d0be5 43extern 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);
718e3744 46
746c4f02 47#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
718e3744 48/* Adjust netmask socket length. Return value is a adjusted sin_len
49 value. */
ac4d0be5 50static int sin_masklen(struct in_addr mask)
718e3744 51{
ac4d0be5 52 char *p, *lim;
53 int len;
54 struct sockaddr_in sin;
718e3744 55
ac4d0be5 56 if (mask.s_addr == 0)
57 return sizeof(long);
718e3744 58
ac4d0be5 59 sin.sin_addr = mask;
60 len = sizeof(struct sockaddr_in);
718e3744 61
ac4d0be5 62 lim = (char *)&sin.sin_addr;
63 p = lim + sizeof(sin.sin_addr);
718e3744 64
ac4d0be5 65 while (*--p == 0 && p >= lim)
66 len--;
67 return len;
718e3744 68}
746c4f02 69#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
718e3744 70
71/* Interface between zebra message and rtm message. */
ac4d0be5 72static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct rib *rib)
718e3744 73
74{
ac4d0be5 75 struct sockaddr_in *mask = NULL;
76 struct sockaddr_in sin_dest, sin_mask, sin_gate;
fe6c7157 77#ifdef __OpenBSD__
ac4d0be5 78 struct sockaddr_mpls smpls;
d3e2c74a 79#endif
ac4d0be5 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;
6f0e3f6e 93#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
ac4d0be5 94 sin_dest.sin_len = sizeof(struct sockaddr_in);
6f0e3f6e 95#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
ac4d0be5 96 sin_dest.sin_addr = p->u.prefix4;
718e3744 97
ac4d0be5 98 memset(&sin_mask, 0, sizeof(struct sockaddr_in));
718e3744 99
ac4d0be5 100 memset(&sin_gate, 0, sizeof(struct sockaddr_in));
101 sin_gate.sin_family = AF_INET;
6f0e3f6e 102#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
ac4d0be5 103 sin_gate.sin_len = sizeof(struct sockaddr_in);
6f0e3f6e 104#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
718e3744 105
ac4d0be5 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;
6f0e3f6e 143#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
ac4d0be5 144 sin_mask.sin_len =
145 sin_masklen(sin_mask.sin_addr);
6f0e3f6e 146#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
ac4d0be5 147 mask = &sin_mask;
148 }
718e3744 149
fe6c7157 150#ifdef __OpenBSD__
ac4d0be5 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 }
d3e2c74a
RW
160#endif
161
ac4d0be5 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*/
718e3744 236}
237
746c4f02 238#ifdef SIN6_LEN
718e3744 239/* Calculate sin6_len value for netmask socket value. */
ac4d0be5 240static int sin6_masklen(struct in6_addr mask)
718e3744 241{
ac4d0be5 242 struct sockaddr_in6 sin6;
243 char *p, *lim;
244 int len;
718e3744 245
ac4d0be5 246 if (IN6_IS_ADDR_UNSPECIFIED(&mask))
247 return sizeof(long);
718e3744 248
ac4d0be5 249 sin6.sin6_addr = mask;
250 len = sizeof(struct sockaddr_in6);
718e3744 251
ac4d0be5 252 lim = (char *)&sin6.sin6_addr;
253 p = lim + sizeof(sin6.sin6_addr);
718e3744 254
ac4d0be5 255 while (*--p == 0 && p >= lim)
256 len--;
718e3744 257
ac4d0be5 258 return len;
718e3744 259}
746c4f02 260#endif /* SIN6_LEN */
718e3744 261
718e3744 262/* Interface between zebra message and rtm message. */
ac4d0be5 263static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct rib *rib)
718e3744 264{
ac4d0be5 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;
718e3744 276#ifdef SIN6_LEN
ac4d0be5 277 sin_dest.sin6_len = sizeof(struct sockaddr_in6);
718e3744 278#endif /* SIN6_LEN */
ac4d0be5 279 sin_dest.sin6_addr = p->u.prefix6;
718e3744 280
ac4d0be5 281 memset(&sin_mask, 0, sizeof(struct sockaddr_in6));
718e3744 282
ac4d0be5 283 memset(&sin_gate, 0, sizeof(struct sockaddr_in6));
284 sin_gate.sin6_family = AF_INET6;
6f0e3f6e 285#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
ac4d0be5 286 sin_gate.sin6_len = sizeof(struct sockaddr_in6);
6f0e3f6e 287#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
718e3744 288
ac4d0be5 289 /* Make gateway. */
290 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) {
291 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
292 continue;
fa713d9e 293
ac4d0be5 294 gate = 0;
718e3744 295
ac4d0be5 296 if ((cmd == RTM_ADD
297 && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
298 || (cmd == RTM_DELETE
718e3744 299#if 0
300 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
301#endif
ac4d0be5 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. */
718e3744 317#ifdef KAME
318
ac4d0be5 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)
718e3744 324
ac4d0be5 325 if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
326 SET_IN6_LINKLOCAL_IFINDEX(sin_gate.sin6_addr, ifindex);
718e3744 327#endif /* KAME */
328
ac4d0be5 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;
718e3744 334#ifdef SIN6_LEN
ac4d0be5 335 sin_mask.sin6_len = sin6_masklen(sin_mask.sin6_addr);
718e3744 336#endif /* SIN6_LEN */
ac4d0be5 337 mask = &sin_mask;
338 }
718e3744 339
ac4d0be5 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);
718e3744 344
345#if 0
346 if (error)
347 {
be717a0a 348 zlog_info ("kernel_rtm_ipv6(): nexthop %d add error=%d.",
718e3744 349 nexthop_num, error);
350 }
746c4f02 351#else
ac4d0be5 352 (void)error;
718e3744 353#endif
354
ac4d0be5 355 nexthop_num++;
356 }
718e3744 357
ac4d0be5 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 }
718e3744 364
ac4d0be5 365 return 0; /*XXX*/
718e3744 366}
367
ac4d0be5 368static int kernel_rtm(int cmd, struct prefix *p, struct rib *rib)
62ccf1e5 369{
ac4d0be5 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;
62ccf1e5
TT
377}
378
ac4d0be5 379int kernel_route_rib(struct prefix *p, struct prefix *src_p, struct rib *old,
380 struct rib *new)
718e3744 381{
ac4d0be5 382 int route = 0;
edd7c245 383
ac4d0be5 384 if (src_p && src_p->prefixlen) {
385 zlog_err("route add: IPv6 sourcedest routes unsupported!");
386 return 1;
387 }
05737783 388
ac4d0be5 389 if (zserv_privs.change(ZPRIVS_RAISE))
390 zlog_err("Can't raise privileges");
be717a0a 391
ac4d0be5 392 if (old)
393 route |= kernel_rtm(RTM_DELETE, p, old);
62ccf1e5 394
ac4d0be5 395 if (new)
396 route |= kernel_rtm(RTM_ADD, p, new);
be717a0a 397
ac4d0be5 398 if (zserv_privs.change(ZPRIVS_LOWER))
399 zlog_err("Can't lower privileges");
edd7c245 400
ac4d0be5 401 return route;
718e3744 402}
6b8a5694 403
ac4d0be5 404int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
405 int llalen)
6b8a5694 406{
ac4d0be5 407 /* TODO */
408 return 0;
6b8a5694 409}
1498c059 410
ac4d0be5 411extern int kernel_get_ipmr_sg_stats(void *mroute)
1498c059 412{
ac4d0be5 413 return 0;
1498c059 414}