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