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