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