Home | History | Annotate | Line # | Download | only in ldpd
mpls_routes.c revision 1.9.2.1
      1  1.9.2.1       tls /* $NetBSD: mpls_routes.c,v 1.9.2.1 2013/02/25 00:30:43 tls 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.9.2.1       tls make_inet_union(const 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.9.2.1       tls 			send_withdraw_tlv_to_all(&so_dest->sa,
    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.9.2.1       tls 				pm = ldp_test_mapping(&so_dest->sa,
    643  1.9.2.1       tls 					 prefixlen, &so_gate->sa);
    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.9.2.1       tls 					  &so_dest->sa, 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.9.2.1       tls 		send_withdraw_tlv_to_all(&so_dest->sa, 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.9.2.1       tls 		 * This function is called only at startup, so use
    769  1.9.2.1       tls 		 * this ocassion 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.9.2.1       tls 			/*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