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