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