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