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