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