mpls_routes.c revision 1.18
1/* $NetBSD: mpls_routes.c,v 1.18 2013/07/18 11:45:36 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 <poll.h>
47#include <stdio.h>
48#include <string.h>
49#include <unistd.h>
50
51#include "ldp.h"
52#include "ldp_errors.h"
53#include "ldp_peer.h"
54#include "mpls_interface.h"
55#include "tlv_stack.h"
56#include "label.h"
57#include "mpls_routes.h"
58#include "socketops.h"
59
60extern int      route_socket;
61int             rt_seq = 200;
62int		dont_catch = 0;
63extern int	no_default_route;
64extern int	debug_f, warn_f;
65
66struct rt_msg   replay_rt[REPLAY_MAX];
67int             replay_index = 0;
68
69#if 0
70static int read_route_socket(char *, int);
71#endif
72void	mask_addr(union sockunion *);
73int	compare_sockunion(const union sockunion *, const union sockunion *);
74static int check_if_addr_updown(struct rt_msg *, uint);
75
76extern struct sockaddr mplssockaddr;
77
78/* Many lines inspired or shamelessly stolen from sbin/route/route.c */
79
80#define NEXTADDR(u) \
81	do { l = RT_ROUNDUP(u->sa.sa_len); memcpy(cp, u, l); cp += l;} while(0);
82#define NEXTADDR2(u) \
83	do { l = RT_ROUNDUP(u.sa_len); memcpy(cp, &u, l); cp += l; } while(0);
84
85#define CHECK_LEN(sunion) \
86	if (size_cp + sunion->sa.sa_len > rlen) \
87		return LDP_E_ROUTE_ERROR; \
88	else \
89		size_cp += sunion->sa.sa_len;
90
91#define CHECK_MINSA \
92	if (size_cp + sizeof(sa_family_t) + sizeof(uint8_t) > rlen) \
93		return LDP_E_ROUTE_ERROR;
94
95#define GETNEXT(dstunion, origunion) \
96	do { \
97	CHECK_MINSA \
98	dstunion = (union sockunion *) ((char *) (origunion)  + \
99	RT_ROUNDUP((origunion)->sa.sa_len)); \
100	CHECK_LEN(dstunion) \
101	} while (0);
102
103#if 0
104static int
105read_route_socket(char *s, int max)
106{
107	int             rv, to_read;
108	struct rt_msghdr *rhdr;
109	struct pollfd pfd;
110
111	pfd.fd = route_socket;
112	pfd.events = POLLRDNORM;
113	pfd.revents = 0;
114
115	errno = 0;
116
117	do {
118		rv = poll(&pfd, 1, 100);
119	} while (rv == -1 && errno == EINTR);
120
121	if (rv < 1) {
122		if (rv == 0) {
123			fatalp("read_route_socket: poll timeout\n");
124		} else
125			fatalp("read_route_socket: poll: %s",
126			    strerror(errno));
127		return 0;
128	}
129
130	do {
131		rv = recv(route_socket, s, max, MSG_PEEK);
132	} while(rv == -1 && errno == EINTR);
133
134	if (rv < 1) {
135		debugp("read_route_socket: recv error\n");
136		return 0;
137	}
138	if (rv > max) {
139		rv = max;
140		debugp("read_route_socket: rv > max\n");
141	}
142
143	rhdr = (struct rt_msghdr *)s;
144	to_read = rhdr->rtm_msglen > max ? max : rhdr->rtm_msglen;
145	rv = 0;
146
147	do {
148		rv += recv(route_socket, s, to_read - rv, 0);
149	} while (rv != to_read);
150
151	return rv;
152}
153#endif	/* 0 */
154
155/* Recalculate length */
156void
157mask_addr(union sockunion * su)
158{
159/*
160	int             olen = su->sa.sa_len;
161	char           *cp1 = olen + (char *) su;
162
163	for (su->sa.sa_len = 0; cp1 > (char *) su;)
164		if (*--cp1 != 0) {
165			su->sa.sa_len = 1 + cp1 - (char *) su;
166			break;
167		}
168*/
169/* Let's use INET only version for the moment */
170su->sa.sa_len = 4 + from_union_to_cidr(su) / 8 +
171    ( from_union_to_cidr(su) % 8 ? 1 : 0 );
172}
173
174/* creates a sockunion from an IP address */
175union sockunion *
176make_inet_union(const char *s)
177{
178	union sockunion *so_inet;
179
180	so_inet = calloc(1, sizeof(*so_inet));
181
182	if (!so_inet) {
183		fatalp("make_inet_union: malloc problem\n");
184		return NULL;
185	}
186
187	so_inet->sin.sin_len = sizeof(struct sockaddr_in);
188	so_inet->sin.sin_family = AF_INET;
189	inet_aton(s, &so_inet->sin.sin_addr);
190
191	return so_inet;
192}
193
194/* creates a sockunion from a label */
195union sockunion *
196make_mpls_union(uint32_t label)
197{
198	union sockunion *so_mpls;
199
200	so_mpls = calloc(1, sizeof(*so_mpls));
201
202	if (!so_mpls) {
203		fatalp("make_mpls_union: malloc problem\n");
204		return NULL;
205	}
206
207	so_mpls->smpls.smpls_len = sizeof(struct sockaddr_mpls);
208	so_mpls->smpls.smpls_family = AF_MPLS;
209	so_mpls->smpls.smpls_addr.shim.label = label;
210
211	so_mpls->smpls.smpls_addr.s_addr =
212		htonl(so_mpls->smpls.smpls_addr.s_addr);
213
214	return so_mpls;
215}
216
217int
218compare_sockunion(const union sockunion * __restrict a,
219    const union sockunion * __restrict b)
220{
221	if (a->sa.sa_len != b->sa.sa_len)
222		return 1;
223	return memcmp(a, b, a->sa.sa_len);
224}
225
226union sockunion *
227from_cidr_to_union(uint8_t prefixlen)
228{
229	union sockunion *u;
230	uint32_t m = 0xFFFFFFFF;
231
232	u = calloc(1, sizeof(*u));
233
234	if (!u) {
235		fatalp("from_cidr_to_union: malloc problem\n");
236		return NULL;
237	}
238	u->sin.sin_len = sizeof(struct sockaddr_in);
239	u->sin.sin_family = AF_INET;
240	if (prefixlen != 0) {
241		m = (m >> (32 - prefixlen) ) << (32 - prefixlen);
242		m = ntohl(m);
243		u->sin.sin_addr.s_addr = m;
244	}
245	return u;
246}
247
248uint8_t
249from_mask_to_cidr(const char *mask)
250{
251	struct in_addr addr;
252	uint8_t plen = 0;
253
254	if (inet_aton(mask, &addr) != 0)
255		for (; addr.s_addr; plen++)
256			addr.s_addr &= addr.s_addr - 1;
257	return plen;
258}
259
260uint8_t
261from_union_to_cidr(const union sockunion *so_pref)
262{
263	const struct sockaddr_in *sin = (const struct sockaddr_in*) so_pref;
264	uint32_t a;
265	uint8_t r;
266
267	a = ntohl(sin->sin_addr.s_addr);
268	for (r=0; a ; a = a << 1, r++);
269
270	return r;
271}
272
273/* returns in mask the netmask created from CIDR prefixlen */
274void
275from_cidr_to_mask(uint8_t prefixlen, char *mask)
276{
277	uint32_t a = 0;
278	uint8_t plen = prefixlen < 32 ? prefixlen : 32;
279
280	if (plen != 0)
281		a = (0xffffffff >> (32 - plen)) << (32 - plen);
282	snprintf(mask, 16, "%d.%d.%d.%d", a >> 24, (a << 8) >> 24,
283	    (a << 16) >> 24, (a << 24) >> 24);
284}
285
286/* From src/sbin/route/route.c */
287static const char *
288route_strerror(int error)
289{
290
291	switch (error) {
292	case ESRCH:
293		return "not in table";
294	case EBUSY:
295		return "entry in use";
296	case ENOBUFS:
297		return "routing table overflow";
298	default:
299		return strerror(error);
300	}
301}
302
303
304/* Adds a route. Or changes it. */
305int
306add_route(union sockunion *so_dest, union sockunion *so_prefix,
307    union sockunion *so_gate, union sockunion *so_ifa,
308    union sockunion *so_tag, int fr, int optype)
309{
310	int             l, rlen, rv = LDP_E_OK;
311	struct rt_msg   rm;
312	char           *cp;
313
314	if(dont_catch)
315		return LDP_E_OK;
316
317	memset(&rm, 0, sizeof(rm));
318	cp = rm.m_space;
319
320	rm.m_rtm.rtm_type = (optype == RTM_READD) ? RTM_ADD : optype;
321	rm.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
322
323	rm.m_rtm.rtm_version = RTM_VERSION;
324	rm.m_rtm.rtm_seq = ++rt_seq;
325	rm.m_rtm.rtm_addrs = RTA_DST;
326	if (so_gate)
327		rm.m_rtm.rtm_addrs |= RTA_GATEWAY;
328
329	assert(so_dest);
330
331	/* Order is: destination, gateway, netmask, genmask, ifp, ifa, tag */
332	NEXTADDR(so_dest);
333	if (so_gate)
334		NEXTADDR(so_gate);
335
336	if (so_prefix) {
337		union sockunion *so_prefix_temp = so_prefix;
338
339		if (fr != FREESO) {
340			/* don't modify so_prefix */
341			so_prefix_temp = calloc(1, so_prefix->sa.sa_len);
342			if (so_prefix_temp == NULL)
343				return LDP_E_MEMORY;
344			memcpy(so_prefix_temp, so_prefix, so_prefix->sa.sa_len);
345		}
346		mask_addr(so_prefix_temp);
347		NEXTADDR(so_prefix_temp);
348		if (fr != FREESO)
349			free(so_prefix_temp);
350		/* XXX: looks like nobody cares about this */
351		rm.m_rtm.rtm_flags |= RTF_MASK;
352		rm.m_rtm.rtm_addrs |= RTA_NETMASK;
353	} else
354		rm.m_rtm.rtm_flags |= RTF_HOST;
355
356	/* route to mpls interface */
357	if (optype != RTM_READD && so_dest->sa.sa_family != AF_MPLS) {
358		NEXTADDR2(mplssockaddr);
359		rm.m_rtm.rtm_addrs |= RTA_IFP;
360	}
361
362	if (so_ifa != NULL) {
363		NEXTADDR(so_ifa);
364		rm.m_rtm.rtm_addrs |= RTA_IFA;
365	}
366
367	if (so_tag) {
368		NEXTADDR(so_tag);
369		rm.m_rtm.rtm_addrs |= RTA_TAG;
370	}
371
372	rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
373
374	if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
375		warnp("Error adding a route: %s\n", route_strerror(errno));
376		warnp("Destination was: %s\n", satos(&so_dest->sa));
377		if (so_prefix)
378			warnp("Prefix was: %s\n", satos(&so_prefix->sa));
379		if (so_gate)
380			warnp("Gateway was: %s\n", satos(&so_gate->sa));
381		rv = LDP_E_ROUTE_ERROR;
382	}
383	if (fr == FREESO) {
384		free(so_dest);
385		if (so_prefix)
386			free(so_prefix);
387		if (so_gate)
388			free(so_gate);
389		if (so_ifa)
390			free(so_ifa);
391		if (so_tag)
392			free(so_tag);
393	}
394
395	return rv;
396}
397
398/* Deletes a route */
399int
400delete_route(union sockunion * so_dest, union sockunion * so_pref, int freeso)
401{
402	int             l, rlen;
403	struct rt_msg   rm;
404	char           *cp;
405
406	if(dont_catch)
407		return LDP_E_OK;
408
409	memset(&rm, 0, sizeof(struct rt_msg));
410	cp = rm.m_space;
411
412	rm.m_rtm.rtm_type = RTM_DELETE;
413	rm.m_rtm.rtm_version = RTM_VERSION;
414	rm.m_rtm.rtm_seq = ++rt_seq;
415	if (so_pref)
416		rm.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
417	else
418		rm.m_rtm.rtm_addrs = RTA_DST;
419
420	/* destination, gateway, netmask, genmask, ifp, ifa */
421
422	NEXTADDR(so_dest);
423
424	if (so_pref) {
425		union sockunion *so_pref_temp = so_pref;
426		if (freeso != FREESO) {
427			/* don't modify the original prefix */
428			so_pref_temp = calloc(1, so_pref->sa.sa_len);
429			if (so_pref_temp == NULL)
430				return LDP_E_MEMORY;
431			memcpy(so_pref_temp, so_pref, so_pref->sa.sa_len);
432		}
433		mask_addr(so_pref_temp);
434		NEXTADDR(so_pref_temp);
435		if (freeso != FREESO)
436			free(so_pref_temp);
437	}
438	rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
439
440	if (freeso == FREESO) {
441		free(so_dest);
442		if (so_pref)
443			free(so_pref);
444	}
445	if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
446	    if(so_pref) {
447		char spreftmp[INET_ADDRSTRLEN];
448		strlcpy(spreftmp, inet_ntoa(so_pref->sin.sin_addr),
449		    INET_ADDRSTRLEN);
450		warnp("Error deleting route(%s): %s/%s",
451		    route_strerror(errno), satos(&so_dest->sa),
452		    spreftmp);
453	    } else
454		warnp("Error deleting route(%s) : %s",
455		    route_strerror(errno), satos(&so_dest->sa));
456	    return LDP_E_NO_SUCH_ROUTE;
457	}
458	return LDP_E_OK;
459}
460
461#if 0
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, const union sockunion * so_dest,
469    const 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		union sockunion *so_pref_temp = calloc(1, so_pref->sa.sa_len);
501
502		if (so_pref_temp == NULL)
503			return LDP_E_MEMORY;
504		rm.m_rtm.rtm_addrs |= RTA_NETMASK;
505		memcpy(so_pref_temp, so_pref, so_pref->sa.sa_len);
506		mask_addr(so_pref_temp);
507		NEXTADDR(so_pref_temp);
508		free(so_pref_temp);
509	}
510	rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
511
512	setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){1},
513	    sizeof(int));
514	rlen = write(route_socket, (char *) &rm, l);
515	setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){0},
516	    sizeof(int));
517
518	if (rlen < l) {
519		debugp("Cannot get a route !(rlen=%d instead of %d) - %s\n",
520		    rlen, l, strerror(errno));
521		return LDP_E_NO_SUCH_ROUTE;
522	} else
523		for ( ; ; ) {
524			rlen = read_route_socket((char *) rg,
525			    sizeof(struct rt_msg));
526			if (rlen < 1)
527				break;
528			/*
529			 * We might lose important messages here. WORKAROUND:
530			 * For now I just try to save this messages and replay
531			 * them later
532			 */
533			if (rg->m_rtm.rtm_pid == getpid() &&
534			    rg->m_rtm.rtm_seq == myseq)
535				break;
536			/* Fast skip */
537			if (rg->m_rtm.rtm_type != RTM_ADD &&
538			    rg->m_rtm.rtm_type != RTM_DELETE &&
539			    rg->m_rtm.rtm_type != RTM_CHANGE &&
540			    rg->m_rtm.rtm_type != RTM_NEWADDR &&
541			    rg->m_rtm.rtm_type != RTM_DELADDR)
542				continue;
543			warnp("Added to replay PID: %d, SEQ: %d\n",
544			    rg->m_rtm.rtm_pid, rg->m_rtm.rtm_seq);
545			memcpy(&replay_rt[replay_index], rg,
546			    sizeof(struct rt_msg));
547			if (replay_index < REPLAY_MAX - 1)
548				replay_index++;
549			else
550				fatalp("Replay index is full\n");
551		}
552
553	if (rlen <= (int)sizeof(struct rt_msghdr)) {
554		debugp("Got only %d bytes, expecting at least %zu\n", rlen,
555		    sizeof(struct rt_msghdr));
556		return LDP_E_ROUTE_ERROR;
557	}
558
559	/* Check if we don't have a less specific route */
560	if (exact_match) {
561		su = (union sockunion*)(rg->m_space);
562		if (compare_sockunion(so_dest, su)) {
563			debugp("Dest %s ", satos(&so_dest->sa));
564			debugp("not like %s\n", satos(&su->sa));
565			return LDP_E_NO_SUCH_ROUTE;
566		}
567	}
568
569	return LDP_E_OK;
570}
571
572#endif	/* 0 */
573
574/* triggered when a route event occurs */
575int
576check_route(struct rt_msg * rg, uint rlen)
577{
578	union sockunion *so_dest = NULL, *so_gate = NULL, *so_pref = NULL;
579	int             so_pref_allocated = 0;
580	int             prefixlen;
581	size_t		size_cp;
582	struct peer_map *pm;
583	struct label	*lab;
584	char            dest[50], gate[50], pref[50], oper[50];
585	dest[0] = 0;
586	gate[0] = 0;
587	pref[0] = 0;
588
589	if (rlen < 3 || rg->m_rtm.rtm_version != RTM_VERSION)
590		return LDP_E_ROUTE_ERROR;
591
592	if (rg->m_rtm.rtm_type == RTM_NEWADDR ||
593	    rg->m_rtm.rtm_type == RTM_DELADDR)
594		return check_if_addr_updown(rg, rlen);
595
596	size_cp = sizeof(struct rt_msghdr);
597	CHECK_MINSA;
598
599	if (rg->m_rtm.rtm_pid == getpid() ||
600	    ((rg->m_rtm.rtm_flags & RTF_DONE) == 0))
601		return LDP_E_OK;
602
603	debugp("Check route triggered by PID: %d\n", rg->m_rtm.rtm_pid);
604
605	so_dest = (union sockunion *) rg->m_space;
606
607	if (so_dest->sa.sa_family != AF_INET)
608		return LDP_E_OK;/* We don't care about non-IP changes */
609
610	CHECK_LEN(so_dest);
611
612	if (rg->m_rtm.rtm_addrs & RTA_GATEWAY) {
613		GETNEXT(so_gate, so_dest);
614		if ((so_gate->sa.sa_family != AF_INET) &&
615		    (so_gate->sa.sa_family != AF_MPLS))
616			return LDP_E_OK;
617	}
618	if (rg->m_rtm.rtm_addrs & RTA_NETMASK) {
619		if (so_gate != NULL) {
620			GETNEXT(so_pref, so_gate);
621		} else
622			GETNEXT(so_pref, so_dest);
623	}
624	/* Calculate prefixlen */
625	if (so_pref)
626		prefixlen = from_union_to_cidr(so_pref);
627	else {
628		prefixlen = 32;
629		if ((so_pref = from_cidr_to_union(32)) == NULL)
630			return LDP_E_MEMORY;
631		so_pref_allocated = 1;
632	}
633
634	so_pref->sa.sa_family = AF_INET;
635	so_pref->sa.sa_len = sizeof(struct sockaddr_in);
636
637	switch (rg->m_rtm.rtm_type) {
638	case RTM_CHANGE:
639		lab = label_get(so_dest, so_pref);
640		if (lab) {
641			send_withdraw_tlv_to_all(&so_dest->sa,
642			    prefixlen);
643			label_reattach_route(lab, REATT_INET_DEL);
644			label_del(lab);
645		}
646	/* Fallthrough */
647	case RTM_ADD:
648		/*
649		 * Check if the route is connected. If so, bind it to
650		 * POP_LABEL and send announce. If not, check if the prefix
651		 * was announced by a LDP neighbour and route it there
652		 */
653
654		/* First of all check if we already know this one */
655		if (label_get(so_dest, so_pref) == NULL) {
656			/* Just add an IMPLNULL label */
657			if (so_gate == NULL)
658				label_add(so_dest, so_pref, NULL,
659					MPLS_LABEL_IMPLNULL, NULL, 0);
660			else {
661				pm = ldp_test_mapping(&so_dest->sa,
662					 prefixlen, &so_gate->sa);
663				if (pm) {
664					/* create an implnull label as it
665					 * gets rewritten in mpls_add_label */
666					lab = label_add(so_dest, so_pref,
667					    so_gate, MPLS_LABEL_IMPLNULL,
668					    pm->peer, pm->lm->label);
669					if (lab != NULL)
670						mpls_add_label(lab);
671					free(pm);
672				} else
673					label_add(so_dest, so_pref, so_gate,
674					    MPLS_LABEL_IMPLNULL, NULL, 0);
675			}
676		} else	/* We already know about this prefix */
677			fatalp("Binding already there for prefix %s/%d !\n",
678			      satos(&so_dest->sa), prefixlen);
679		break;
680	case RTM_DELETE:
681		if (!so_gate)
682			break;	/* Non-existent route  XXX ?! */
683		/*
684		 * Send withdraw check the binding, delete the route, delete
685		 * the binding
686		 */
687		lab = label_get(so_dest, so_pref);
688		if (!lab)
689			break;
690		send_withdraw_tlv_to_all(&so_dest->sa, prefixlen);
691		/* No readd or delete IP route. Just delete the MPLS route */
692		label_reattach_route(lab, REATT_INET_NODEL);
693		label_del(lab);
694		break;
695	}
696
697	if (!debug_f && !warn_f) {
698		if(so_pref_allocated)
699			free(so_pref);
700		return LDP_E_OK;
701	}
702
703	/* Rest is just for debug */
704
705	if (so_dest)
706		strlcpy(dest, satos(&so_dest->sa), sizeof(dest));
707	if (so_pref)
708		snprintf(pref, sizeof(pref), "%d", prefixlen);
709	if (so_gate)
710		strlcpy(gate, satos(&so_gate->sa), sizeof(gate));
711
712	switch (rg->m_rtm.rtm_type) {
713	case RTM_ADD:
714		strlcpy(oper, "added", 20);
715		break;
716	case RTM_DELETE:
717		strlcpy(oper, "delete", 20);
718		break;
719	case RTM_GET:
720		strlcpy(oper, "get", 20);
721		break;
722	case RTM_CHANGE:
723		strlcpy(oper, "change", 20);
724		break;
725	case RTM_LOSING:
726		strlcpy(oper, "losing", 20);
727		break;
728	case RTM_REDIRECT:
729		strlcpy(oper, "redirect", 20);
730		break;
731	case RTM_NEWADDR:
732		strlcpy(oper, "new address", 20);
733		break;
734	case RTM_DELADDR:
735		strlcpy(oper, "del address", 20);
736		break;
737	default:
738		snprintf(oper, sizeof(oper), "unknown 0x%X operation",
739		    rg->m_rtm.rtm_type);
740	}
741
742	debugp("[check_route] Route %s: %s / %s -> %s by PID:%d\n", oper, dest,
743		pref, gate, rg->m_rtm.rtm_pid);
744
745	if(so_pref_allocated)
746		free(so_pref);
747	return LDP_E_OK;
748}
749
750/*
751 * Checks NEWADDR and DELADDR messages and sends announcements accordingly
752 */
753static int
754check_if_addr_updown(struct rt_msg * rg, uint rlen)
755{
756	union sockunion *ifa, *netmask;
757	struct ldp_peer *p;
758	struct address_list_tlv al_tlv;
759	struct ifa_msghdr *msghdr = (struct ifa_msghdr *)&rg->m_rtm;
760	size_t size_cp = sizeof(struct ifa_msghdr);
761
762	if (rlen < sizeof(struct ifa_msghdr) ||
763	    (msghdr->ifam_addrs & RTA_NETMASK) == 0 ||
764	    (msghdr->ifam_addrs & RTA_IFA) == 0)
765		return LDP_E_ROUTE_ERROR;
766
767	CHECK_MINSA;
768
769	/* we should have RTA_NETMASK, RTA_IFP, RTA_IFA and RTA_BRD */
770	ifa = netmask = (union sockunion *)(msghdr + 1);
771	if (netmask->sa.sa_family != AF_INET)
772		return LDP_E_OK;
773	CHECK_LEN(netmask);
774
775	if (msghdr->ifam_addrs & RTA_IFP)
776		GETNEXT(ifa, ifa);
777
778	GETNEXT(ifa, ifa);
779
780	if (ifa->sa.sa_family != AF_INET ||
781	    ntohl(ifa->sin.sin_addr.s_addr) >> 24 == IN_LOOPBACKNET)
782		return LDP_E_OK;
783
784	memset(&al_tlv, 0, sizeof(al_tlv));
785	al_tlv.type = rg->m_rtm.rtm_type == RTM_NEWADDR ? htons(LDP_ADDRESS) :
786	    htons(LDP_ADDRESS_WITHDRAW);
787	al_tlv.length = htons(sizeof(al_tlv) - TLV_TYPE_LENGTH);
788	al_tlv.messageid = htonl(get_message_id());
789	al_tlv.a_type = htons(TLV_ADDRESS_LIST);
790	al_tlv.a_length = htons(sizeof(al_tlv.a_af) + sizeof(al_tlv.a_address));
791	al_tlv.a_af = htons(LDP_AF_INET);
792	memcpy(&al_tlv.a_address, &ifa->sin.sin_addr, sizeof(al_tlv.a_address));
793
794	SLIST_FOREACH(p, &ldp_peer_head, peers)
795		if (p->state == LDP_PEER_ESTABLISHED)
796			send_tlv(p, (struct tlv *)&al_tlv);
797
798	return LDP_E_OK;
799}
800
801int
802bind_current_routes()
803{
804	size_t          needed, size_cp;
805	int             mib[6];
806	char           *buf, *next, *lim;
807	struct rt_msghdr *rtmes;
808	union sockunion *so_dst, *so_pref, *so_gate;
809	uint rlen;
810
811	mib[0] = CTL_NET;
812	mib[1] = PF_ROUTE;
813	mib[2] = 0;
814	mib[3] = 0;
815	mib[4] = NET_RT_DUMP;
816	mib[5] = 0;
817	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
818		fatalp("route-sysctl-estimate: %s",
819		    strerror(errno));
820		return LDP_E_ROUTE_ERROR;
821	}
822	if ((buf = malloc(needed)) == 0)
823		return LDP_E_ROUTE_ERROR;
824	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
825		free(buf);
826		return LDP_E_ROUTE_ERROR;
827	}
828	lim = buf + needed;
829
830	for (next = buf; next < lim; next += rlen) {
831		rtmes = (struct rt_msghdr *) next;
832		rlen = rtmes->rtm_msglen;
833		size_cp = sizeof(struct rt_msghdr);
834		so_gate = so_pref = NULL;
835		if (rtmes->rtm_flags & RTF_LLINFO)	/* No need for arps */
836			continue;
837		if (!(rtmes->rtm_addrs & RTA_DST)) {
838			debugp("No dst\n");
839			continue;
840		}
841
842		CHECK_MINSA;
843		so_dst = (union sockunion *) & rtmes[1];
844		CHECK_LEN(so_dst);
845
846		/*
847		 * This function is called only at startup, so use
848		 * this ocassion to delete all MPLS routes
849		 */
850		if (so_dst->sa.sa_family == AF_MPLS) {
851			delete_route(so_dst, NULL, NO_FREESO);
852			debugp("MPLS route deleted.\n");
853			continue;
854		}
855
856		if (so_dst->sa.sa_family != AF_INET) {
857			/*debugp("sa_dst is not AF_INET\n");*/
858			continue;
859		}
860
861		/* Check if it's the default gateway */
862		if (so_dst->sin.sin_addr.s_addr == 0 && no_default_route != 0)
863			continue;
864
865		/* Check if it's loopback */
866		if ((ntohl(so_dst->sin.sin_addr.s_addr) >> 24)==IN_LOOPBACKNET)
867			continue;
868
869		/* Get Gateway */
870		if (rtmes->rtm_addrs & RTA_GATEWAY)
871			GETNEXT(so_gate, so_dst);
872
873		/* Get prefix */
874		if (rtmes->rtm_flags & RTF_HOST) {
875			if ((so_pref = from_cidr_to_union(32)) == NULL)
876				return LDP_E_MEMORY;
877		} else if (rtmes->rtm_addrs & RTA_GATEWAY) {
878			GETNEXT(so_pref, so_gate);
879		} else
880			GETNEXT(so_pref, so_dst);
881
882		so_pref->sa.sa_family = AF_INET;
883		so_pref->sa.sa_len = sizeof(struct sockaddr_in);
884
885		/* Also deletes when dest is IPv4 and gateway MPLS */
886		if ((rtmes->rtm_addrs & RTA_GATEWAY) &&
887		    (so_gate->sa.sa_family == AF_MPLS)) {
888			debugp("MPLS route to %s deleted.\n",
889			    inet_ntoa(so_dst->sin.sin_addr));
890			delete_route(so_dst, so_pref, NO_FREESO);
891			if (rtmes->rtm_flags & RTF_HOST)
892				free(so_pref);
893			continue;
894		}
895
896		if (so_gate != NULL && so_gate->sa.sa_family == AF_LINK)
897			so_gate = NULL;	/* connected route */
898
899		if (so_gate == NULL || so_gate->sa.sa_family == AF_INET)
900			label_add(so_dst, so_pref, so_gate,
901			    MPLS_LABEL_IMPLNULL, NULL, 0);
902
903		if (rtmes->rtm_flags & RTF_HOST)
904			free(so_pref);
905	}
906	free(buf);
907	return LDP_E_OK;
908}
909
910int
911flush_mpls_routes()
912{
913	size_t needed, size_cp;
914	int mib[6];
915	uint rlen;
916	char *buf, *next, *lim;
917	struct rt_msghdr *rtm;
918	union sockunion *so_dst, *so_pref, *so_gate;
919
920	mib[0] = CTL_NET;
921	mib[1] = PF_ROUTE;
922	mib[2] = 0;
923	mib[3] = 0;
924	mib[4] = NET_RT_DUMP;
925	mib[5] = 0;
926	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
927		fatalp("route-sysctl-estimate: %s", strerror(errno));
928		return LDP_E_ROUTE_ERROR;
929	}
930	if ((buf = malloc(needed)) == NULL) {
931		fatalp("route-sysctl-estimate: %s", strerror(errno));
932		return LDP_E_MEMORY;
933	}
934	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
935		free(buf);
936		return LDP_E_ROUTE_ERROR;
937	}
938	lim = buf + needed;
939
940	for (next = buf; next < lim; next += rlen) {
941		rtm = (struct rt_msghdr *) next;
942		size_cp = sizeof(struct rt_msghdr);
943		rlen = rtm->rtm_msglen;
944		so_pref = NULL;
945		so_gate = NULL;
946		if (rtm->rtm_flags & RTF_LLINFO)	/* No need for arps */
947			continue;
948		if (!(rtm->rtm_addrs & RTA_DST)) {
949			debugp("No dst\n");
950			continue;
951		}
952		so_dst = (union sockunion *) & rtm[1];
953
954		if (so_dst->sa.sa_family == AF_MPLS) {
955			delete_route(so_dst, NULL, NO_FREESO);
956			debugp("MPLS route deleted.\n");
957			continue;
958		}
959
960		if (rtm->rtm_addrs & RTA_GATEWAY) {
961			GETNEXT(so_gate, so_dst);
962			GETNEXT(so_pref, so_gate);
963		} else
964			GETNEXT(so_pref, so_dst);
965
966		if (so_gate->sa.sa_family == AF_MPLS) {
967			if (so_dst->sa.sa_family == AF_INET)
968				debugp("MPLS route to %s deleted.\n",
969				    inet_ntoa(so_dst->sin.sin_addr));
970			delete_route(so_dst, so_pref, NO_FREESO);
971			continue;
972		}
973
974	}
975	free(buf);
976	return LDP_E_OK;
977}
978