mpls_routes.c revision 1.23 1 1.23 kefren /* $NetBSD: mpls_routes.c,v 1.23 2013/10/12 18:55:40 kefren Exp $ */
2 1.1 kefren
3 1.1 kefren /*-
4 1.1 kefren * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 1.1 kefren * All rights reserved.
6 1.1 kefren *
7 1.1 kefren * This code is derived from software contributed to The NetBSD Foundation
8 1.1 kefren * by Mihai Chelaru <kefren (at) NetBSD.org>
9 1.1 kefren *
10 1.1 kefren * Redistribution and use in source and binary forms, with or without
11 1.1 kefren * modification, are permitted provided that the following conditions
12 1.1 kefren * are met:
13 1.1 kefren * 1. Redistributions of source code must retain the above copyright
14 1.1 kefren * notice, this list of conditions and the following disclaimer.
15 1.1 kefren * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 kefren * notice, this list of conditions and the following disclaimer in the
17 1.1 kefren * documentation and/or other materials provided with the distribution.
18 1.1 kefren *
19 1.1 kefren * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 kefren * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 kefren * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 kefren * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 kefren * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 kefren * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 kefren * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 kefren * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 kefren * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 kefren * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 kefren * POSSIBILITY OF SUCH DAMAGE.
30 1.1 kefren */
31 1.1 kefren
32 1.1 kefren #include <sys/types.h>
33 1.1 kefren #include <sys/socket.h>
34 1.1 kefren #include <sys/param.h>
35 1.1 kefren #include <sys/sysctl.h>
36 1.1 kefren #include <net/if.h>
37 1.1 kefren #include <net/route.h>
38 1.1 kefren #include <netinet/in.h>
39 1.1 kefren #include <netmpls/mpls.h>
40 1.1 kefren
41 1.1 kefren #include <arpa/inet.h>
42 1.1 kefren
43 1.1 kefren #include <assert.h>
44 1.1 kefren #include <stdlib.h>
45 1.1 kefren #include <errno.h>
46 1.17 kefren #include <poll.h>
47 1.1 kefren #include <stdio.h>
48 1.1 kefren #include <string.h>
49 1.1 kefren #include <unistd.h>
50 1.1 kefren
51 1.1 kefren #include "ldp.h"
52 1.1 kefren #include "ldp_errors.h"
53 1.1 kefren #include "ldp_peer.h"
54 1.1 kefren #include "mpls_interface.h"
55 1.1 kefren #include "tlv_stack.h"
56 1.1 kefren #include "label.h"
57 1.1 kefren #include "mpls_routes.h"
58 1.13 kefren #include "socketops.h"
59 1.1 kefren
60 1.1 kefren extern int route_socket;
61 1.17 kefren int rt_seq = 200;
62 1.1 kefren int dont_catch = 0;
63 1.6 kefren extern int no_default_route;
64 1.7 kefren extern int debug_f, warn_f;
65 1.21 kefren static int my_pid = 0;
66 1.1 kefren
67 1.1 kefren struct rt_msg replay_rt[REPLAY_MAX];
68 1.1 kefren int replay_index = 0;
69 1.1 kefren
70 1.18 kefren #if 0
71 1.7 kefren static int read_route_socket(char *, int);
72 1.18 kefren #endif
73 1.1 kefren void mask_addr(union sockunion *);
74 1.12 kefren int compare_sockunion(const union sockunion *, const union sockunion *);
75 1.14 kefren static int check_if_addr_updown(struct rt_msg *, uint);
76 1.1 kefren
77 1.1 kefren extern struct sockaddr mplssockaddr;
78 1.1 kefren
79 1.1 kefren /* Many lines inspired or shamelessly stolen from sbin/route/route.c */
80 1.1 kefren
81 1.1 kefren #define NEXTADDR(u) \
82 1.14 kefren do { l = RT_ROUNDUP(u->sa.sa_len); memcpy(cp, u, l); cp += l;} while(0);
83 1.1 kefren #define NEXTADDR2(u) \
84 1.4 kefren do { l = RT_ROUNDUP(u.sa_len); memcpy(cp, &u, l); cp += l; } while(0);
85 1.15 kefren
86 1.15 kefren #define CHECK_LEN(sunion) \
87 1.15 kefren if (size_cp + sunion->sa.sa_len > rlen) \
88 1.15 kefren return LDP_E_ROUTE_ERROR; \
89 1.15 kefren else \
90 1.15 kefren size_cp += sunion->sa.sa_len;
91 1.15 kefren
92 1.15 kefren #define CHECK_MINSA \
93 1.15 kefren if (size_cp + sizeof(sa_family_t) + sizeof(uint8_t) > rlen) \
94 1.15 kefren return LDP_E_ROUTE_ERROR;
95 1.15 kefren
96 1.15 kefren #define GETNEXT(dstunion, origunion) \
97 1.15 kefren do { \
98 1.15 kefren CHECK_MINSA \
99 1.15 kefren dstunion = (union sockunion *) ((char *) (origunion) + \
100 1.15 kefren RT_ROUNDUP((origunion)->sa.sa_len)); \
101 1.15 kefren CHECK_LEN(dstunion) \
102 1.15 kefren } while (0);
103 1.15 kefren
104 1.18 kefren #if 0
105 1.7 kefren static int
106 1.1 kefren read_route_socket(char *s, int max)
107 1.1 kefren {
108 1.1 kefren int rv, to_read;
109 1.1 kefren struct rt_msghdr *rhdr;
110 1.17 kefren struct pollfd pfd;
111 1.1 kefren
112 1.17 kefren pfd.fd = route_socket;
113 1.17 kefren pfd.events = POLLRDNORM;
114 1.17 kefren pfd.revents = 0;
115 1.1 kefren
116 1.1 kefren errno = 0;
117 1.1 kefren
118 1.1 kefren do {
119 1.17 kefren rv = poll(&pfd, 1, 100);
120 1.17 kefren } while (rv == -1 && errno == EINTR);
121 1.1 kefren
122 1.1 kefren if (rv < 1) {
123 1.1 kefren if (rv == 0) {
124 1.17 kefren fatalp("read_route_socket: poll timeout\n");
125 1.1 kefren } else
126 1.17 kefren fatalp("read_route_socket: poll: %s",
127 1.1 kefren strerror(errno));
128 1.1 kefren return 0;
129 1.1 kefren }
130 1.1 kefren
131 1.1 kefren do {
132 1.1 kefren rv = recv(route_socket, s, max, MSG_PEEK);
133 1.17 kefren } while(rv == -1 && errno == EINTR);
134 1.1 kefren
135 1.1 kefren if (rv < 1) {
136 1.1 kefren debugp("read_route_socket: recv error\n");
137 1.1 kefren return 0;
138 1.1 kefren }
139 1.1 kefren if (rv > max) {
140 1.1 kefren rv = max;
141 1.1 kefren debugp("read_route_socket: rv > max\n");
142 1.1 kefren }
143 1.1 kefren
144 1.1 kefren rhdr = (struct rt_msghdr *)s;
145 1.1 kefren to_read = rhdr->rtm_msglen > max ? max : rhdr->rtm_msglen;
146 1.1 kefren rv = 0;
147 1.1 kefren
148 1.1 kefren do {
149 1.1 kefren rv += recv(route_socket, s, to_read - rv, 0);
150 1.1 kefren } while (rv != to_read);
151 1.1 kefren
152 1.1 kefren return rv;
153 1.1 kefren }
154 1.18 kefren #endif /* 0 */
155 1.1 kefren
156 1.1 kefren /* Recalculate length */
157 1.1 kefren void
158 1.1 kefren mask_addr(union sockunion * su)
159 1.1 kefren {
160 1.1 kefren /*
161 1.1 kefren int olen = su->sa.sa_len;
162 1.1 kefren char *cp1 = olen + (char *) su;
163 1.1 kefren
164 1.1 kefren for (su->sa.sa_len = 0; cp1 > (char *) su;)
165 1.1 kefren if (*--cp1 != 0) {
166 1.1 kefren su->sa.sa_len = 1 + cp1 - (char *) su;
167 1.1 kefren break;
168 1.1 kefren }
169 1.1 kefren */
170 1.1 kefren /* Let's use INET only version for the moment */
171 1.1 kefren su->sa.sa_len = 4 + from_union_to_cidr(su) / 8 +
172 1.1 kefren ( from_union_to_cidr(su) % 8 ? 1 : 0 );
173 1.1 kefren }
174 1.1 kefren
175 1.1 kefren /* creates a sockunion from an IP address */
176 1.1 kefren union sockunion *
177 1.10 kefren make_inet_union(const char *s)
178 1.1 kefren {
179 1.1 kefren union sockunion *so_inet;
180 1.1 kefren
181 1.2 christos so_inet = calloc(1, sizeof(*so_inet));
182 1.1 kefren
183 1.1 kefren if (!so_inet) {
184 1.1 kefren fatalp("make_inet_union: malloc problem\n");
185 1.1 kefren return NULL;
186 1.2 christos }
187 1.1 kefren
188 1.1 kefren so_inet->sin.sin_len = sizeof(struct sockaddr_in);
189 1.1 kefren so_inet->sin.sin_family = AF_INET;
190 1.1 kefren inet_aton(s, &so_inet->sin.sin_addr);
191 1.1 kefren
192 1.1 kefren return so_inet;
193 1.1 kefren }
194 1.1 kefren
195 1.1 kefren /* creates a sockunion from a label */
196 1.1 kefren union sockunion *
197 1.1 kefren make_mpls_union(uint32_t label)
198 1.1 kefren {
199 1.1 kefren union sockunion *so_mpls;
200 1.1 kefren
201 1.2 christos so_mpls = calloc(1, sizeof(*so_mpls));
202 1.1 kefren
203 1.1 kefren if (!so_mpls) {
204 1.1 kefren fatalp("make_mpls_union: malloc problem\n");
205 1.1 kefren return NULL;
206 1.2 christos }
207 1.1 kefren
208 1.1 kefren so_mpls->smpls.smpls_len = sizeof(struct sockaddr_mpls);
209 1.1 kefren so_mpls->smpls.smpls_family = AF_MPLS;
210 1.1 kefren so_mpls->smpls.smpls_addr.shim.label = label;
211 1.1 kefren
212 1.1 kefren so_mpls->smpls.smpls_addr.s_addr =
213 1.1 kefren htonl(so_mpls->smpls.smpls_addr.s_addr);
214 1.1 kefren
215 1.1 kefren return so_mpls;
216 1.1 kefren }
217 1.1 kefren
218 1.1 kefren int
219 1.12 kefren compare_sockunion(const union sockunion * __restrict a,
220 1.12 kefren const union sockunion * __restrict b)
221 1.1 kefren {
222 1.1 kefren if (a->sa.sa_len != b->sa.sa_len)
223 1.1 kefren return 1;
224 1.1 kefren return memcmp(a, b, a->sa.sa_len);
225 1.1 kefren }
226 1.1 kefren
227 1.1 kefren union sockunion *
228 1.1 kefren from_cidr_to_union(uint8_t prefixlen)
229 1.1 kefren {
230 1.1 kefren union sockunion *u;
231 1.8 kefren uint32_t m = 0xFFFFFFFF;
232 1.1 kefren
233 1.2 christos u = calloc(1, sizeof(*u));
234 1.1 kefren
235 1.1 kefren if (!u) {
236 1.1 kefren fatalp("from_cidr_to_union: malloc problem\n");
237 1.1 kefren return NULL;
238 1.1 kefren }
239 1.1 kefren u->sin.sin_len = sizeof(struct sockaddr_in);
240 1.1 kefren u->sin.sin_family = AF_INET;
241 1.8 kefren if (prefixlen != 0) {
242 1.8 kefren m = (m >> (32 - prefixlen) ) << (32 - prefixlen);
243 1.8 kefren m = ntohl(m);
244 1.8 kefren u->sin.sin_addr.s_addr = m;
245 1.8 kefren }
246 1.1 kefren return u;
247 1.1 kefren }
248 1.1 kefren
249 1.1 kefren uint8_t
250 1.12 kefren from_mask_to_cidr(const char *mask)
251 1.1 kefren {
252 1.11 kefren struct in_addr addr;
253 1.11 kefren uint8_t plen = 0;
254 1.11 kefren
255 1.11 kefren if (inet_aton(mask, &addr) != 0)
256 1.11 kefren for (; addr.s_addr; plen++)
257 1.11 kefren addr.s_addr &= addr.s_addr - 1;
258 1.11 kefren return plen;
259 1.1 kefren }
260 1.1 kefren
261 1.1 kefren uint8_t
262 1.12 kefren from_union_to_cidr(const union sockunion *so_pref)
263 1.1 kefren {
264 1.12 kefren const struct sockaddr_in *sin = (const struct sockaddr_in*) so_pref;
265 1.1 kefren uint32_t a;
266 1.1 kefren uint8_t r;
267 1.1 kefren
268 1.1 kefren a = ntohl(sin->sin_addr.s_addr);
269 1.1 kefren for (r=0; a ; a = a << 1, r++);
270 1.1 kefren
271 1.1 kefren return r;
272 1.1 kefren }
273 1.1 kefren
274 1.1 kefren /* returns in mask the netmask created from CIDR prefixlen */
275 1.1 kefren void
276 1.1 kefren from_cidr_to_mask(uint8_t prefixlen, char *mask)
277 1.1 kefren {
278 1.11 kefren uint32_t a = 0;
279 1.11 kefren uint8_t plen = prefixlen < 32 ? prefixlen : 32;
280 1.1 kefren
281 1.11 kefren if (plen != 0)
282 1.11 kefren a = (0xffffffff >> (32 - plen)) << (32 - plen);
283 1.1 kefren snprintf(mask, 16, "%d.%d.%d.%d", a >> 24, (a << 8) >> 24,
284 1.11 kefren (a << 16) >> 24, (a << 24) >> 24);
285 1.1 kefren }
286 1.1 kefren
287 1.1 kefren /* From src/sbin/route/route.c */
288 1.1 kefren static const char *
289 1.1 kefren route_strerror(int error)
290 1.1 kefren {
291 1.1 kefren
292 1.1 kefren switch (error) {
293 1.1 kefren case ESRCH:
294 1.1 kefren return "not in table";
295 1.1 kefren case EBUSY:
296 1.1 kefren return "entry in use";
297 1.1 kefren case ENOBUFS:
298 1.1 kefren return "routing table overflow";
299 1.1 kefren default:
300 1.1 kefren return strerror(error);
301 1.1 kefren }
302 1.1 kefren }
303 1.1 kefren
304 1.1 kefren
305 1.1 kefren /* Adds a route. Or changes it. */
306 1.1 kefren int
307 1.1 kefren add_route(union sockunion *so_dest, union sockunion *so_prefix,
308 1.12 kefren union sockunion *so_gate, union sockunion *so_ifa,
309 1.12 kefren union sockunion *so_tag, int fr, int optype)
310 1.1 kefren {
311 1.1 kefren int l, rlen, rv = LDP_E_OK;
312 1.1 kefren struct rt_msg rm;
313 1.1 kefren char *cp;
314 1.1 kefren
315 1.1 kefren if(dont_catch)
316 1.1 kefren return LDP_E_OK;
317 1.1 kefren
318 1.1 kefren memset(&rm, 0, sizeof(rm));
319 1.1 kefren cp = rm.m_space;
320 1.1 kefren
321 1.1 kefren rm.m_rtm.rtm_type = (optype == RTM_READD) ? RTM_ADD : optype;
322 1.1 kefren rm.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
323 1.1 kefren
324 1.1 kefren rm.m_rtm.rtm_version = RTM_VERSION;
325 1.1 kefren rm.m_rtm.rtm_seq = ++rt_seq;
326 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST;
327 1.1 kefren if (so_gate)
328 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_GATEWAY;
329 1.1 kefren
330 1.1 kefren assert(so_dest);
331 1.1 kefren
332 1.1 kefren /* Order is: destination, gateway, netmask, genmask, ifp, ifa, tag */
333 1.1 kefren NEXTADDR(so_dest);
334 1.1 kefren if (so_gate)
335 1.1 kefren NEXTADDR(so_gate);
336 1.1 kefren
337 1.1 kefren if (so_prefix) {
338 1.12 kefren union sockunion *so_prefix_temp = so_prefix;
339 1.12 kefren
340 1.12 kefren if (fr != FREESO) {
341 1.12 kefren /* don't modify so_prefix */
342 1.12 kefren so_prefix_temp = calloc(1, so_prefix->sa.sa_len);
343 1.12 kefren if (so_prefix_temp == NULL)
344 1.12 kefren return LDP_E_MEMORY;
345 1.12 kefren memcpy(so_prefix_temp, so_prefix, so_prefix->sa.sa_len);
346 1.12 kefren }
347 1.12 kefren mask_addr(so_prefix_temp);
348 1.12 kefren NEXTADDR(so_prefix_temp);
349 1.12 kefren if (fr != FREESO)
350 1.12 kefren free(so_prefix_temp);
351 1.1 kefren /* XXX: looks like nobody cares about this */
352 1.1 kefren rm.m_rtm.rtm_flags |= RTF_MASK;
353 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_NETMASK;
354 1.1 kefren } else
355 1.1 kefren rm.m_rtm.rtm_flags |= RTF_HOST;
356 1.1 kefren
357 1.1 kefren /* route to mpls interface */
358 1.1 kefren if (optype != RTM_READD && so_dest->sa.sa_family != AF_MPLS) {
359 1.1 kefren NEXTADDR2(mplssockaddr);
360 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_IFP;
361 1.1 kefren }
362 1.1 kefren
363 1.1 kefren if (so_ifa != NULL) {
364 1.1 kefren NEXTADDR(so_ifa);
365 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_IFA;
366 1.1 kefren }
367 1.1 kefren
368 1.1 kefren if (so_tag) {
369 1.1 kefren NEXTADDR(so_tag);
370 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_TAG;
371 1.1 kefren }
372 1.1 kefren
373 1.1 kefren rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
374 1.1 kefren
375 1.1 kefren if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
376 1.1 kefren warnp("Error adding a route: %s\n", route_strerror(errno));
377 1.15 kefren warnp("Destination was: %s\n", satos(&so_dest->sa));
378 1.1 kefren if (so_prefix)
379 1.15 kefren warnp("Prefix was: %s\n", satos(&so_prefix->sa));
380 1.1 kefren if (so_gate)
381 1.15 kefren warnp("Gateway was: %s\n", satos(&so_gate->sa));
382 1.1 kefren rv = LDP_E_ROUTE_ERROR;
383 1.1 kefren }
384 1.12 kefren if (fr == FREESO) {
385 1.1 kefren free(so_dest);
386 1.1 kefren if (so_prefix)
387 1.1 kefren free(so_prefix);
388 1.1 kefren if (so_gate)
389 1.1 kefren free(so_gate);
390 1.1 kefren if (so_ifa)
391 1.1 kefren free(so_ifa);
392 1.1 kefren if (so_tag)
393 1.1 kefren free(so_tag);
394 1.1 kefren }
395 1.1 kefren
396 1.1 kefren return rv;
397 1.1 kefren }
398 1.1 kefren
399 1.1 kefren /* Deletes a route */
400 1.1 kefren int
401 1.1 kefren delete_route(union sockunion * so_dest, union sockunion * so_pref, int freeso)
402 1.1 kefren {
403 1.1 kefren int l, rlen;
404 1.1 kefren struct rt_msg rm;
405 1.1 kefren char *cp;
406 1.1 kefren
407 1.1 kefren if(dont_catch)
408 1.1 kefren return LDP_E_OK;
409 1.1 kefren
410 1.1 kefren memset(&rm, 0, sizeof(struct rt_msg));
411 1.1 kefren cp = rm.m_space;
412 1.1 kefren
413 1.1 kefren rm.m_rtm.rtm_type = RTM_DELETE;
414 1.1 kefren rm.m_rtm.rtm_version = RTM_VERSION;
415 1.1 kefren rm.m_rtm.rtm_seq = ++rt_seq;
416 1.1 kefren if (so_pref)
417 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
418 1.20 kefren else {
419 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST;
420 1.20 kefren rm.m_rtm.rtm_flags |= RTF_HOST;
421 1.20 kefren }
422 1.1 kefren
423 1.1 kefren /* destination, gateway, netmask, genmask, ifp, ifa */
424 1.1 kefren
425 1.1 kefren NEXTADDR(so_dest);
426 1.1 kefren
427 1.1 kefren if (so_pref) {
428 1.12 kefren union sockunion *so_pref_temp = so_pref;
429 1.12 kefren if (freeso != FREESO) {
430 1.12 kefren /* don't modify the original prefix */
431 1.12 kefren so_pref_temp = calloc(1, so_pref->sa.sa_len);
432 1.12 kefren if (so_pref_temp == NULL)
433 1.12 kefren return LDP_E_MEMORY;
434 1.12 kefren memcpy(so_pref_temp, so_pref, so_pref->sa.sa_len);
435 1.12 kefren }
436 1.12 kefren mask_addr(so_pref_temp);
437 1.12 kefren NEXTADDR(so_pref_temp);
438 1.12 kefren if (freeso != FREESO)
439 1.12 kefren free(so_pref_temp);
440 1.1 kefren }
441 1.1 kefren rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
442 1.1 kefren
443 1.1 kefren if (freeso == FREESO) {
444 1.1 kefren free(so_dest);
445 1.1 kefren if (so_pref)
446 1.1 kefren free(so_pref);
447 1.1 kefren }
448 1.1 kefren if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
449 1.1 kefren if(so_pref) {
450 1.1 kefren char spreftmp[INET_ADDRSTRLEN];
451 1.1 kefren strlcpy(spreftmp, inet_ntoa(so_pref->sin.sin_addr),
452 1.1 kefren INET_ADDRSTRLEN);
453 1.1 kefren warnp("Error deleting route(%s): %s/%s",
454 1.15 kefren route_strerror(errno), satos(&so_dest->sa),
455 1.1 kefren spreftmp);
456 1.1 kefren } else
457 1.1 kefren warnp("Error deleting route(%s) : %s",
458 1.15 kefren route_strerror(errno), satos(&so_dest->sa));
459 1.1 kefren return LDP_E_NO_SUCH_ROUTE;
460 1.1 kefren }
461 1.1 kefren return LDP_E_OK;
462 1.1 kefren }
463 1.1 kefren
464 1.18 kefren #if 0
465 1.1 kefren /*
466 1.1 kefren * Check for a route and returns it in rg
467 1.1 kefren * If exact_match is set it compares also the so_dest and so_pref
468 1.1 kefren * with the returned result
469 1.1 kefren */
470 1.1 kefren int
471 1.12 kefren get_route(struct rt_msg * rg, const union sockunion * so_dest,
472 1.12 kefren const union sockunion * so_pref, int exact_match)
473 1.1 kefren {
474 1.1 kefren int l, rlen, myseq;
475 1.1 kefren struct rt_msg rm;
476 1.1 kefren char *cp;
477 1.1 kefren union sockunion *su;
478 1.1 kefren
479 1.1 kefren memset(&rm, 0, sizeof(struct rt_msg));
480 1.1 kefren cp = rm.m_space;
481 1.1 kefren
482 1.1 kefren myseq = ++rt_seq;
483 1.1 kefren
484 1.1 kefren rm.m_rtm.rtm_type = RTM_GET;
485 1.1 kefren rm.m_rtm.rtm_version = RTM_VERSION;
486 1.1 kefren rm.m_rtm.rtm_seq = myseq;
487 1.1 kefren
488 1.1 kefren /*
489 1.1 kefren * rtm_addrs should contain what we provide into this message but
490 1.1 kefren * RTA_DST | RTA_IFP trick is allowed in order to find out the
491 1.1 kefren * interface.
492 1.1 kefren */
493 1.1 kefren
494 1.1 kefren rm.m_rtm.rtm_addrs = RTA_DST | RTA_IFP;
495 1.1 kefren
496 1.1 kefren /*
497 1.1 kefren * ORDER of fields is: destination, gateway, netmask, genmask, ifp,
498 1.1 kefren * ifa
499 1.1 kefren */
500 1.1 kefren
501 1.1 kefren NEXTADDR(so_dest);
502 1.1 kefren if (so_pref) {
503 1.12 kefren union sockunion *so_pref_temp = calloc(1, so_pref->sa.sa_len);
504 1.12 kefren
505 1.12 kefren if (so_pref_temp == NULL)
506 1.12 kefren return LDP_E_MEMORY;
507 1.1 kefren rm.m_rtm.rtm_addrs |= RTA_NETMASK;
508 1.12 kefren memcpy(so_pref_temp, so_pref, so_pref->sa.sa_len);
509 1.12 kefren mask_addr(so_pref_temp);
510 1.12 kefren NEXTADDR(so_pref_temp);
511 1.12 kefren free(so_pref_temp);
512 1.1 kefren }
513 1.1 kefren rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
514 1.1 kefren
515 1.17 kefren setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){1},
516 1.17 kefren sizeof(int));
517 1.17 kefren rlen = write(route_socket, (char *) &rm, l);
518 1.17 kefren setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){0},
519 1.17 kefren sizeof(int));
520 1.17 kefren
521 1.17 kefren if (rlen < l) {
522 1.1 kefren debugp("Cannot get a route !(rlen=%d instead of %d) - %s\n",
523 1.1 kefren rlen, l, strerror(errno));
524 1.1 kefren return LDP_E_NO_SUCH_ROUTE;
525 1.1 kefren } else
526 1.7 kefren for ( ; ; ) {
527 1.1 kefren rlen = read_route_socket((char *) rg,
528 1.1 kefren sizeof(struct rt_msg));
529 1.1 kefren if (rlen < 1)
530 1.1 kefren break;
531 1.1 kefren /*
532 1.1 kefren * We might lose important messages here. WORKAROUND:
533 1.1 kefren * For now I just try to save this messages and replay
534 1.1 kefren * them later
535 1.1 kefren */
536 1.7 kefren if (rg->m_rtm.rtm_pid == getpid() &&
537 1.7 kefren rg->m_rtm.rtm_seq == myseq)
538 1.7 kefren break;
539 1.17 kefren /* Fast skip */
540 1.17 kefren if (rg->m_rtm.rtm_type != RTM_ADD &&
541 1.17 kefren rg->m_rtm.rtm_type != RTM_DELETE &&
542 1.17 kefren rg->m_rtm.rtm_type != RTM_CHANGE &&
543 1.17 kefren rg->m_rtm.rtm_type != RTM_NEWADDR &&
544 1.17 kefren rg->m_rtm.rtm_type != RTM_DELADDR)
545 1.17 kefren continue;
546 1.17 kefren warnp("Added to replay PID: %d, SEQ: %d\n",
547 1.7 kefren rg->m_rtm.rtm_pid, rg->m_rtm.rtm_seq);
548 1.7 kefren memcpy(&replay_rt[replay_index], rg,
549 1.7 kefren sizeof(struct rt_msg));
550 1.7 kefren if (replay_index < REPLAY_MAX - 1)
551 1.7 kefren replay_index++;
552 1.7 kefren else
553 1.7 kefren fatalp("Replay index is full\n");
554 1.7 kefren }
555 1.1 kefren
556 1.7 kefren if (rlen <= (int)sizeof(struct rt_msghdr)) {
557 1.9 joerg debugp("Got only %d bytes, expecting at least %zu\n", rlen,
558 1.1 kefren sizeof(struct rt_msghdr));
559 1.1 kefren return LDP_E_ROUTE_ERROR;
560 1.1 kefren }
561 1.1 kefren
562 1.1 kefren /* Check if we don't have a less specific route */
563 1.1 kefren if (exact_match) {
564 1.1 kefren su = (union sockunion*)(rg->m_space);
565 1.1 kefren if (compare_sockunion(so_dest, su)) {
566 1.15 kefren debugp("Dest %s ", satos(&so_dest->sa));
567 1.15 kefren debugp("not like %s\n", satos(&su->sa));
568 1.1 kefren return LDP_E_NO_SUCH_ROUTE;
569 1.1 kefren }
570 1.1 kefren }
571 1.1 kefren
572 1.1 kefren return LDP_E_OK;
573 1.1 kefren }
574 1.1 kefren
575 1.18 kefren #endif /* 0 */
576 1.18 kefren
577 1.1 kefren /* triggered when a route event occurs */
578 1.1 kefren int
579 1.1 kefren check_route(struct rt_msg * rg, uint rlen)
580 1.1 kefren {
581 1.1 kefren union sockunion *so_dest = NULL, *so_gate = NULL, *so_pref = NULL;
582 1.1 kefren int so_pref_allocated = 0;
583 1.1 kefren int prefixlen;
584 1.15 kefren size_t size_cp;
585 1.1 kefren struct peer_map *pm;
586 1.1 kefren struct label *lab;
587 1.1 kefren char dest[50], gate[50], pref[50], oper[50];
588 1.1 kefren dest[0] = 0;
589 1.1 kefren gate[0] = 0;
590 1.1 kefren pref[0] = 0;
591 1.1 kefren
592 1.21 kefren if (rlen <= offsetof(struct rt_msghdr, rtm_type) ||
593 1.21 kefren rg->m_rtm.rtm_version != RTM_VERSION)
594 1.1 kefren return LDP_E_ROUTE_ERROR;
595 1.1 kefren
596 1.13 kefren if (rg->m_rtm.rtm_type == RTM_NEWADDR ||
597 1.13 kefren rg->m_rtm.rtm_type == RTM_DELADDR)
598 1.14 kefren return check_if_addr_updown(rg, rlen);
599 1.14 kefren
600 1.15 kefren size_cp = sizeof(struct rt_msghdr);
601 1.15 kefren CHECK_MINSA;
602 1.14 kefren
603 1.21 kefren if (my_pid == 0)
604 1.21 kefren my_pid = getpid();
605 1.21 kefren assert(my_pid != 0);
606 1.21 kefren
607 1.21 kefren if (rg->m_rtm.rtm_pid == my_pid ||
608 1.21 kefren (rg->m_rtm.rtm_pid != 0 && (rg->m_rtm.rtm_flags & RTF_DONE) == 0) ||
609 1.21 kefren (rg->m_rtm.rtm_type != RTM_ADD &&
610 1.21 kefren rg->m_rtm.rtm_type != RTM_DELETE &&
611 1.21 kefren rg->m_rtm.rtm_type != RTM_CHANGE))
612 1.1 kefren return LDP_E_OK;
613 1.1 kefren
614 1.13 kefren debugp("Check route triggered by PID: %d\n", rg->m_rtm.rtm_pid);
615 1.1 kefren
616 1.21 kefren if (rg->m_rtm.rtm_addrs & RTA_DST)
617 1.21 kefren so_dest = (union sockunion *) rg->m_space;
618 1.21 kefren else
619 1.21 kefren return LDP_E_ROUTE_ERROR;
620 1.1 kefren
621 1.1 kefren if (so_dest->sa.sa_family != AF_INET)
622 1.1 kefren return LDP_E_OK;/* We don't care about non-IP changes */
623 1.1 kefren
624 1.15 kefren CHECK_LEN(so_dest);
625 1.15 kefren
626 1.1 kefren if (rg->m_rtm.rtm_addrs & RTA_GATEWAY) {
627 1.15 kefren GETNEXT(so_gate, so_dest);
628 1.21 kefren if ((rg->m_rtm.rtm_flags & RTF_CLONING) == 0 &&
629 1.21 kefren so_gate->sa.sa_family != AF_INET &&
630 1.21 kefren so_gate->sa.sa_family != AF_MPLS)
631 1.1 kefren return LDP_E_OK;
632 1.1 kefren }
633 1.1 kefren if (rg->m_rtm.rtm_addrs & RTA_NETMASK) {
634 1.17 kefren if (so_gate != NULL) {
635 1.17 kefren GETNEXT(so_pref, so_gate);
636 1.1 kefren } else
637 1.17 kefren GETNEXT(so_pref, so_dest);
638 1.1 kefren }
639 1.1 kefren /* Calculate prefixlen */
640 1.1 kefren if (so_pref)
641 1.17 kefren prefixlen = from_union_to_cidr(so_pref);
642 1.1 kefren else {
643 1.1 kefren prefixlen = 32;
644 1.3 kefren if ((so_pref = from_cidr_to_union(32)) == NULL)
645 1.3 kefren return LDP_E_MEMORY;
646 1.1 kefren so_pref_allocated = 1;
647 1.1 kefren }
648 1.1 kefren
649 1.1 kefren so_pref->sa.sa_family = AF_INET;
650 1.1 kefren so_pref->sa.sa_len = sizeof(struct sockaddr_in);
651 1.23 kefren so_pref->sin.sin_port = 0;
652 1.23 kefren memset(&so_pref->sin.sin_zero, 0, sizeof(so_pref->sin.sin_zero));
653 1.1 kefren
654 1.21 kefren if (rg->m_rtm.rtm_flags & RTF_CLONING)
655 1.21 kefren so_gate = NULL;
656 1.21 kefren
657 1.1 kefren switch (rg->m_rtm.rtm_type) {
658 1.1 kefren case RTM_CHANGE:
659 1.6 kefren lab = label_get(so_dest, so_pref);
660 1.6 kefren if (lab) {
661 1.10 kefren send_withdraw_tlv_to_all(&so_dest->sa,
662 1.6 kefren prefixlen);
663 1.18 kefren label_reattach_route(lab, REATT_INET_DEL);
664 1.6 kefren label_del(lab);
665 1.6 kefren }
666 1.1 kefren /* Fallthrough */
667 1.1 kefren case RTM_ADD:
668 1.1 kefren /*
669 1.1 kefren * Check if the route is connected. If so, bind it to
670 1.1 kefren * POP_LABEL and send announce. If not, check if the prefix
671 1.1 kefren * was announced by a LDP neighbour and route it there
672 1.1 kefren */
673 1.1 kefren
674 1.1 kefren /* First of all check if we already know this one */
675 1.5 kefren if (label_get(so_dest, so_pref) == NULL) {
676 1.17 kefren /* Just add an IMPLNULL label */
677 1.17 kefren if (so_gate == NULL)
678 1.5 kefren label_add(so_dest, so_pref, NULL,
679 1.20 kefren MPLS_LABEL_IMPLNULL, NULL, 0,
680 1.20 kefren rg->m_rtm.rtm_flags & RTF_HOST);
681 1.1 kefren else {
682 1.10 kefren pm = ldp_test_mapping(&so_dest->sa,
683 1.10 kefren prefixlen, &so_gate->sa);
684 1.1 kefren if (pm) {
685 1.18 kefren /* create an implnull label as it
686 1.18 kefren * gets rewritten in mpls_add_label */
687 1.17 kefren lab = label_add(so_dest, so_pref,
688 1.18 kefren so_gate, MPLS_LABEL_IMPLNULL,
689 1.20 kefren pm->peer, pm->lm->label,
690 1.20 kefren rg->m_rtm.rtm_flags & RTF_HOST);
691 1.17 kefren if (lab != NULL)
692 1.17 kefren mpls_add_label(lab);
693 1.1 kefren free(pm);
694 1.1 kefren } else
695 1.5 kefren label_add(so_dest, so_pref, so_gate,
696 1.20 kefren MPLS_LABEL_IMPLNULL, NULL, 0,
697 1.20 kefren rg->m_rtm.rtm_flags & RTF_HOST);
698 1.1 kefren }
699 1.1 kefren } else /* We already know about this prefix */
700 1.17 kefren fatalp("Binding already there for prefix %s/%d !\n",
701 1.15 kefren satos(&so_dest->sa), prefixlen);
702 1.1 kefren break;
703 1.1 kefren case RTM_DELETE:
704 1.1 kefren /*
705 1.1 kefren * Send withdraw check the binding, delete the route, delete
706 1.1 kefren * the binding
707 1.1 kefren */
708 1.1 kefren lab = label_get(so_dest, so_pref);
709 1.1 kefren if (!lab)
710 1.1 kefren break;
711 1.10 kefren send_withdraw_tlv_to_all(&so_dest->sa, prefixlen);
712 1.6 kefren /* No readd or delete IP route. Just delete the MPLS route */
713 1.18 kefren label_reattach_route(lab, REATT_INET_NODEL);
714 1.1 kefren label_del(lab);
715 1.1 kefren break;
716 1.1 kefren }
717 1.1 kefren
718 1.7 kefren if (!debug_f && !warn_f) {
719 1.7 kefren if(so_pref_allocated)
720 1.7 kefren free(so_pref);
721 1.7 kefren return LDP_E_OK;
722 1.7 kefren }
723 1.7 kefren
724 1.1 kefren /* Rest is just for debug */
725 1.1 kefren
726 1.1 kefren if (so_dest)
727 1.15 kefren strlcpy(dest, satos(&so_dest->sa), sizeof(dest));
728 1.1 kefren if (so_pref)
729 1.15 kefren snprintf(pref, sizeof(pref), "%d", prefixlen);
730 1.1 kefren if (so_gate)
731 1.15 kefren strlcpy(gate, satos(&so_gate->sa), sizeof(gate));
732 1.1 kefren
733 1.1 kefren switch (rg->m_rtm.rtm_type) {
734 1.1 kefren case RTM_ADD:
735 1.1 kefren strlcpy(oper, "added", 20);
736 1.1 kefren break;
737 1.1 kefren case RTM_DELETE:
738 1.1 kefren strlcpy(oper, "delete", 20);
739 1.1 kefren break;
740 1.1 kefren case RTM_GET:
741 1.1 kefren strlcpy(oper, "get", 20);
742 1.1 kefren break;
743 1.1 kefren case RTM_CHANGE:
744 1.1 kefren strlcpy(oper, "change", 20);
745 1.1 kefren break;
746 1.1 kefren case RTM_LOSING:
747 1.1 kefren strlcpy(oper, "losing", 20);
748 1.1 kefren break;
749 1.14 kefren case RTM_REDIRECT:
750 1.14 kefren strlcpy(oper, "redirect", 20);
751 1.14 kefren break;
752 1.1 kefren case RTM_NEWADDR:
753 1.1 kefren strlcpy(oper, "new address", 20);
754 1.1 kefren break;
755 1.1 kefren case RTM_DELADDR:
756 1.1 kefren strlcpy(oper, "del address", 20);
757 1.1 kefren break;
758 1.1 kefren default:
759 1.14 kefren snprintf(oper, sizeof(oper), "unknown 0x%X operation",
760 1.1 kefren rg->m_rtm.rtm_type);
761 1.1 kefren }
762 1.1 kefren
763 1.16 kefren debugp("[check_route] Route %s: %s / %s -> %s by PID:%d\n", oper, dest,
764 1.1 kefren pref, gate, rg->m_rtm.rtm_pid);
765 1.1 kefren
766 1.1 kefren if(so_pref_allocated)
767 1.1 kefren free(so_pref);
768 1.1 kefren return LDP_E_OK;
769 1.1 kefren }
770 1.1 kefren
771 1.13 kefren /*
772 1.13 kefren * Checks NEWADDR and DELADDR messages and sends announcements accordingly
773 1.13 kefren */
774 1.13 kefren static int
775 1.14 kefren check_if_addr_updown(struct rt_msg * rg, uint rlen)
776 1.13 kefren {
777 1.13 kefren union sockunion *ifa, *netmask;
778 1.13 kefren struct ldp_peer *p;
779 1.13 kefren struct address_list_tlv al_tlv;
780 1.14 kefren struct ifa_msghdr *msghdr = (struct ifa_msghdr *)&rg->m_rtm;
781 1.15 kefren size_t size_cp = sizeof(struct ifa_msghdr);
782 1.13 kefren
783 1.14 kefren if (rlen < sizeof(struct ifa_msghdr) ||
784 1.14 kefren (msghdr->ifam_addrs & RTA_NETMASK) == 0 ||
785 1.14 kefren (msghdr->ifam_addrs & RTA_IFA) == 0)
786 1.13 kefren return LDP_E_ROUTE_ERROR;
787 1.13 kefren
788 1.15 kefren CHECK_MINSA;
789 1.15 kefren
790 1.14 kefren /* we should have RTA_NETMASK, RTA_IFP, RTA_IFA and RTA_BRD */
791 1.14 kefren ifa = netmask = (union sockunion *)(msghdr + 1);
792 1.13 kefren if (netmask->sa.sa_family != AF_INET)
793 1.13 kefren return LDP_E_OK;
794 1.15 kefren CHECK_LEN(netmask);
795 1.13 kefren
796 1.14 kefren if (msghdr->ifam_addrs & RTA_IFP)
797 1.15 kefren GETNEXT(ifa, ifa);
798 1.15 kefren
799 1.15 kefren GETNEXT(ifa, ifa);
800 1.13 kefren
801 1.14 kefren if (ifa->sa.sa_family != AF_INET ||
802 1.14 kefren ntohl(ifa->sin.sin_addr.s_addr) >> 24 == IN_LOOPBACKNET)
803 1.13 kefren return LDP_E_OK;
804 1.13 kefren
805 1.13 kefren memset(&al_tlv, 0, sizeof(al_tlv));
806 1.13 kefren al_tlv.type = rg->m_rtm.rtm_type == RTM_NEWADDR ? htons(LDP_ADDRESS) :
807 1.13 kefren htons(LDP_ADDRESS_WITHDRAW);
808 1.13 kefren al_tlv.length = htons(sizeof(al_tlv) - TLV_TYPE_LENGTH);
809 1.13 kefren al_tlv.messageid = htonl(get_message_id());
810 1.13 kefren al_tlv.a_type = htons(TLV_ADDRESS_LIST);
811 1.13 kefren al_tlv.a_length = htons(sizeof(al_tlv.a_af) + sizeof(al_tlv.a_address));
812 1.13 kefren al_tlv.a_af = htons(LDP_AF_INET);
813 1.13 kefren memcpy(&al_tlv.a_address, &ifa->sin.sin_addr, sizeof(al_tlv.a_address));
814 1.13 kefren
815 1.13 kefren SLIST_FOREACH(p, &ldp_peer_head, peers)
816 1.13 kefren if (p->state == LDP_PEER_ESTABLISHED)
817 1.13 kefren send_tlv(p, (struct tlv *)&al_tlv);
818 1.13 kefren
819 1.13 kefren return LDP_E_OK;
820 1.13 kefren }
821 1.13 kefren
822 1.1 kefren int
823 1.1 kefren bind_current_routes()
824 1.1 kefren {
825 1.15 kefren size_t needed, size_cp;
826 1.1 kefren int mib[6];
827 1.1 kefren char *buf, *next, *lim;
828 1.1 kefren struct rt_msghdr *rtmes;
829 1.1 kefren union sockunion *so_dst, *so_pref, *so_gate;
830 1.15 kefren uint rlen;
831 1.1 kefren
832 1.1 kefren mib[0] = CTL_NET;
833 1.1 kefren mib[1] = PF_ROUTE;
834 1.1 kefren mib[2] = 0;
835 1.1 kefren mib[3] = 0;
836 1.1 kefren mib[4] = NET_RT_DUMP;
837 1.1 kefren mib[5] = 0;
838 1.1 kefren if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
839 1.1 kefren fatalp("route-sysctl-estimate: %s",
840 1.1 kefren strerror(errno));
841 1.1 kefren return LDP_E_ROUTE_ERROR;
842 1.1 kefren }
843 1.1 kefren if ((buf = malloc(needed)) == 0)
844 1.1 kefren return LDP_E_ROUTE_ERROR;
845 1.1 kefren if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
846 1.1 kefren free(buf);
847 1.1 kefren return LDP_E_ROUTE_ERROR;
848 1.1 kefren }
849 1.1 kefren lim = buf + needed;
850 1.1 kefren
851 1.15 kefren for (next = buf; next < lim; next += rlen) {
852 1.1 kefren rtmes = (struct rt_msghdr *) next;
853 1.15 kefren rlen = rtmes->rtm_msglen;
854 1.15 kefren size_cp = sizeof(struct rt_msghdr);
855 1.17 kefren so_gate = so_pref = NULL;
856 1.1 kefren if (rtmes->rtm_flags & RTF_LLINFO) /* No need for arps */
857 1.1 kefren continue;
858 1.1 kefren if (!(rtmes->rtm_addrs & RTA_DST)) {
859 1.1 kefren debugp("No dst\n");
860 1.1 kefren continue;
861 1.1 kefren }
862 1.1 kefren
863 1.15 kefren CHECK_MINSA;
864 1.1 kefren so_dst = (union sockunion *) & rtmes[1];
865 1.15 kefren CHECK_LEN(so_dst);
866 1.17 kefren
867 1.1 kefren /*
868 1.10 kefren * This function is called only at startup, so use
869 1.10 kefren * this ocassion to delete all MPLS routes
870 1.1 kefren */
871 1.1 kefren if (so_dst->sa.sa_family == AF_MPLS) {
872 1.1 kefren delete_route(so_dst, NULL, NO_FREESO);
873 1.1 kefren debugp("MPLS route deleted.\n");
874 1.1 kefren continue;
875 1.1 kefren }
876 1.1 kefren
877 1.1 kefren if (so_dst->sa.sa_family != AF_INET) {
878 1.10 kefren /*debugp("sa_dst is not AF_INET\n");*/
879 1.1 kefren continue;
880 1.1 kefren }
881 1.1 kefren
882 1.1 kefren /* Check if it's the default gateway */
883 1.6 kefren if (so_dst->sin.sin_addr.s_addr == 0 && no_default_route != 0)
884 1.1 kefren continue;
885 1.1 kefren
886 1.15 kefren /* Check if it's loopback */
887 1.1 kefren if ((ntohl(so_dst->sin.sin_addr.s_addr) >> 24)==IN_LOOPBACKNET)
888 1.1 kefren continue;
889 1.1 kefren
890 1.1 kefren /* Get Gateway */
891 1.1 kefren if (rtmes->rtm_addrs & RTA_GATEWAY)
892 1.15 kefren GETNEXT(so_gate, so_dst);
893 1.1 kefren
894 1.1 kefren /* Get prefix */
895 1.3 kefren if (rtmes->rtm_flags & RTF_HOST) {
896 1.3 kefren if ((so_pref = from_cidr_to_union(32)) == NULL)
897 1.3 kefren return LDP_E_MEMORY;
898 1.15 kefren } else if (rtmes->rtm_addrs & RTA_GATEWAY) {
899 1.15 kefren GETNEXT(so_pref, so_gate);
900 1.15 kefren } else
901 1.15 kefren GETNEXT(so_pref, so_dst);
902 1.1 kefren
903 1.1 kefren so_pref->sa.sa_family = AF_INET;
904 1.1 kefren so_pref->sa.sa_len = sizeof(struct sockaddr_in);
905 1.22 kefren so_pref->sin.sin_port = 0;
906 1.22 kefren memset(&so_pref->sin.sin_zero, 0, 8);
907 1.1 kefren
908 1.1 kefren /* Also deletes when dest is IPv4 and gateway MPLS */
909 1.1 kefren if ((rtmes->rtm_addrs & RTA_GATEWAY) &&
910 1.1 kefren (so_gate->sa.sa_family == AF_MPLS)) {
911 1.1 kefren debugp("MPLS route to %s deleted.\n",
912 1.1 kefren inet_ntoa(so_dst->sin.sin_addr));
913 1.20 kefren delete_route(so_dst,
914 1.20 kefren rtmes->rtm_flags & RTF_HOST ? NULL : so_pref,
915 1.20 kefren NO_FREESO);
916 1.1 kefren if (rtmes->rtm_flags & RTF_HOST)
917 1.1 kefren free(so_pref);
918 1.1 kefren continue;
919 1.1 kefren }
920 1.17 kefren
921 1.17 kefren if (so_gate != NULL && so_gate->sa.sa_family == AF_LINK)
922 1.17 kefren so_gate = NULL; /* connected route */
923 1.17 kefren
924 1.16 kefren if (so_gate == NULL || so_gate->sa.sa_family == AF_INET)
925 1.5 kefren label_add(so_dst, so_pref, so_gate,
926 1.20 kefren MPLS_LABEL_IMPLNULL, NULL, 0,
927 1.20 kefren rtmes->rtm_flags & RTF_HOST);
928 1.1 kefren
929 1.1 kefren if (rtmes->rtm_flags & RTF_HOST)
930 1.1 kefren free(so_pref);
931 1.1 kefren }
932 1.1 kefren free(buf);
933 1.1 kefren return LDP_E_OK;
934 1.1 kefren }
935 1.1 kefren
936 1.1 kefren int
937 1.1 kefren flush_mpls_routes()
938 1.1 kefren {
939 1.15 kefren size_t needed, size_cp;
940 1.15 kefren int mib[6];
941 1.15 kefren uint rlen;
942 1.15 kefren char *buf, *next, *lim;
943 1.1 kefren struct rt_msghdr *rtm;
944 1.1 kefren union sockunion *so_dst, *so_pref, *so_gate;
945 1.1 kefren
946 1.1 kefren mib[0] = CTL_NET;
947 1.1 kefren mib[1] = PF_ROUTE;
948 1.1 kefren mib[2] = 0;
949 1.1 kefren mib[3] = 0;
950 1.1 kefren mib[4] = NET_RT_DUMP;
951 1.1 kefren mib[5] = 0;
952 1.1 kefren if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
953 1.1 kefren fatalp("route-sysctl-estimate: %s", strerror(errno));
954 1.1 kefren return LDP_E_ROUTE_ERROR;
955 1.1 kefren }
956 1.2 christos if ((buf = malloc(needed)) == NULL) {
957 1.2 christos fatalp("route-sysctl-estimate: %s", strerror(errno));
958 1.2 christos return LDP_E_MEMORY;
959 1.2 christos }
960 1.1 kefren if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
961 1.1 kefren free(buf);
962 1.1 kefren return LDP_E_ROUTE_ERROR;
963 1.1 kefren }
964 1.1 kefren lim = buf + needed;
965 1.1 kefren
966 1.15 kefren for (next = buf; next < lim; next += rlen) {
967 1.1 kefren rtm = (struct rt_msghdr *) next;
968 1.15 kefren size_cp = sizeof(struct rt_msghdr);
969 1.15 kefren rlen = rtm->rtm_msglen;
970 1.1 kefren so_pref = NULL;
971 1.1 kefren so_gate = NULL;
972 1.1 kefren if (rtm->rtm_flags & RTF_LLINFO) /* No need for arps */
973 1.1 kefren continue;
974 1.1 kefren if (!(rtm->rtm_addrs & RTA_DST)) {
975 1.1 kefren debugp("No dst\n");
976 1.1 kefren continue;
977 1.1 kefren }
978 1.1 kefren so_dst = (union sockunion *) & rtm[1];
979 1.1 kefren
980 1.1 kefren if (so_dst->sa.sa_family == AF_MPLS) {
981 1.1 kefren delete_route(so_dst, NULL, NO_FREESO);
982 1.1 kefren debugp("MPLS route deleted.\n");
983 1.1 kefren continue;
984 1.1 kefren }
985 1.1 kefren
986 1.20 kefren if ((rtm->rtm_addrs & RTA_GATEWAY) == 0)
987 1.20 kefren continue;
988 1.20 kefren GETNEXT(so_gate, so_dst);
989 1.20 kefren
990 1.20 kefren if ((rtm->rtm_flags & RTF_HOST) == 0)
991 1.15 kefren GETNEXT(so_pref, so_gate);
992 1.1 kefren
993 1.1 kefren if (so_gate->sa.sa_family == AF_MPLS) {
994 1.7 kefren if (so_dst->sa.sa_family == AF_INET)
995 1.7 kefren debugp("MPLS route to %s deleted.\n",
996 1.7 kefren inet_ntoa(so_dst->sin.sin_addr));
997 1.1 kefren delete_route(so_dst, so_pref, NO_FREESO);
998 1.1 kefren continue;
999 1.1 kefren }
1000 1.1 kefren
1001 1.1 kefren }
1002 1.1 kefren free(buf);
1003 1.1 kefren return LDP_E_OK;
1004 1.1 kefren }
1005