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