mpls_routes.c revision 1.20 1 /* $NetBSD: mpls_routes.c,v 1.20 2013/07/24 09:05:53 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 <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
60 extern int route_socket;
61 int rt_seq = 200;
62 int dont_catch = 0;
63 extern int no_default_route;
64 extern int debug_f, warn_f;
65
66 struct rt_msg replay_rt[REPLAY_MAX];
67 int replay_index = 0;
68
69 #if 0
70 static int read_route_socket(char *, int);
71 #endif
72 void mask_addr(union sockunion *);
73 int compare_sockunion(const union sockunion *, const union sockunion *);
74 static int check_if_addr_updown(struct rt_msg *, uint);
75
76 extern 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
104 static int
105 read_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 */
156 void
157 mask_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 */
170 su->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 */
175 union sockunion *
176 make_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 */
195 union sockunion *
196 make_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
217 int
218 compare_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
226 union sockunion *
227 from_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
248 uint8_t
249 from_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
260 uint8_t
261 from_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 */
274 void
275 from_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 */
287 static const char *
288 route_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. */
305 int
306 add_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 */
399 int
400 delete_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 rm.m_rtm.rtm_flags |= RTF_HOST;
420 }
421
422 /* destination, gateway, netmask, genmask, ifp, ifa */
423
424 NEXTADDR(so_dest);
425
426 if (so_pref) {
427 union sockunion *so_pref_temp = so_pref;
428 if (freeso != FREESO) {
429 /* don't modify the original prefix */
430 so_pref_temp = calloc(1, so_pref->sa.sa_len);
431 if (so_pref_temp == NULL)
432 return LDP_E_MEMORY;
433 memcpy(so_pref_temp, so_pref, so_pref->sa.sa_len);
434 }
435 mask_addr(so_pref_temp);
436 NEXTADDR(so_pref_temp);
437 if (freeso != FREESO)
438 free(so_pref_temp);
439 }
440 rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
441
442 if (freeso == FREESO) {
443 free(so_dest);
444 if (so_pref)
445 free(so_pref);
446 }
447 if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
448 if(so_pref) {
449 char spreftmp[INET_ADDRSTRLEN];
450 strlcpy(spreftmp, inet_ntoa(so_pref->sin.sin_addr),
451 INET_ADDRSTRLEN);
452 warnp("Error deleting route(%s): %s/%s",
453 route_strerror(errno), satos(&so_dest->sa),
454 spreftmp);
455 } else
456 warnp("Error deleting route(%s) : %s",
457 route_strerror(errno), satos(&so_dest->sa));
458 return LDP_E_NO_SUCH_ROUTE;
459 }
460 return LDP_E_OK;
461 }
462
463 #if 0
464 /*
465 * Check for a route and returns it in rg
466 * If exact_match is set it compares also the so_dest and so_pref
467 * with the returned result
468 */
469 int
470 get_route(struct rt_msg * rg, const union sockunion * so_dest,
471 const union sockunion * so_pref, int exact_match)
472 {
473 int l, rlen, myseq;
474 struct rt_msg rm;
475 char *cp;
476 union sockunion *su;
477
478 memset(&rm, 0, sizeof(struct rt_msg));
479 cp = rm.m_space;
480
481 myseq = ++rt_seq;
482
483 rm.m_rtm.rtm_type = RTM_GET;
484 rm.m_rtm.rtm_version = RTM_VERSION;
485 rm.m_rtm.rtm_seq = myseq;
486
487 /*
488 * rtm_addrs should contain what we provide into this message but
489 * RTA_DST | RTA_IFP trick is allowed in order to find out the
490 * interface.
491 */
492
493 rm.m_rtm.rtm_addrs = RTA_DST | RTA_IFP;
494
495 /*
496 * ORDER of fields is: destination, gateway, netmask, genmask, ifp,
497 * ifa
498 */
499
500 NEXTADDR(so_dest);
501 if (so_pref) {
502 union sockunion *so_pref_temp = calloc(1, so_pref->sa.sa_len);
503
504 if (so_pref_temp == NULL)
505 return LDP_E_MEMORY;
506 rm.m_rtm.rtm_addrs |= RTA_NETMASK;
507 memcpy(so_pref_temp, so_pref, so_pref->sa.sa_len);
508 mask_addr(so_pref_temp);
509 NEXTADDR(so_pref_temp);
510 free(so_pref_temp);
511 }
512 rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
513
514 setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){1},
515 sizeof(int));
516 rlen = write(route_socket, (char *) &rm, l);
517 setsockopt(route_socket, SOL_SOCKET, SO_USELOOPBACK, &(int){0},
518 sizeof(int));
519
520 if (rlen < l) {
521 debugp("Cannot get a route !(rlen=%d instead of %d) - %s\n",
522 rlen, l, strerror(errno));
523 return LDP_E_NO_SUCH_ROUTE;
524 } else
525 for ( ; ; ) {
526 rlen = read_route_socket((char *) rg,
527 sizeof(struct rt_msg));
528 if (rlen < 1)
529 break;
530 /*
531 * We might lose important messages here. WORKAROUND:
532 * For now I just try to save this messages and replay
533 * them later
534 */
535 if (rg->m_rtm.rtm_pid == getpid() &&
536 rg->m_rtm.rtm_seq == myseq)
537 break;
538 /* Fast skip */
539 if (rg->m_rtm.rtm_type != RTM_ADD &&
540 rg->m_rtm.rtm_type != RTM_DELETE &&
541 rg->m_rtm.rtm_type != RTM_CHANGE &&
542 rg->m_rtm.rtm_type != RTM_NEWADDR &&
543 rg->m_rtm.rtm_type != RTM_DELADDR)
544 continue;
545 warnp("Added to replay PID: %d, SEQ: %d\n",
546 rg->m_rtm.rtm_pid, rg->m_rtm.rtm_seq);
547 memcpy(&replay_rt[replay_index], rg,
548 sizeof(struct rt_msg));
549 if (replay_index < REPLAY_MAX - 1)
550 replay_index++;
551 else
552 fatalp("Replay index is full\n");
553 }
554
555 if (rlen <= (int)sizeof(struct rt_msghdr)) {
556 debugp("Got only %d bytes, expecting at least %zu\n", rlen,
557 sizeof(struct rt_msghdr));
558 return LDP_E_ROUTE_ERROR;
559 }
560
561 /* Check if we don't have a less specific route */
562 if (exact_match) {
563 su = (union sockunion*)(rg->m_space);
564 if (compare_sockunion(so_dest, su)) {
565 debugp("Dest %s ", satos(&so_dest->sa));
566 debugp("not like %s\n", satos(&su->sa));
567 return LDP_E_NO_SUCH_ROUTE;
568 }
569 }
570
571 return LDP_E_OK;
572 }
573
574 #endif /* 0 */
575
576 /* triggered when a route event occurs */
577 int
578 check_route(struct rt_msg * rg, uint rlen)
579 {
580 union sockunion *so_dest = NULL, *so_gate = NULL, *so_pref = NULL;
581 int so_pref_allocated = 0;
582 int prefixlen;
583 size_t size_cp;
584 struct peer_map *pm;
585 struct label *lab;
586 char dest[50], gate[50], pref[50], oper[50];
587 dest[0] = 0;
588 gate[0] = 0;
589 pref[0] = 0;
590
591 if (rlen < 3 || rg->m_rtm.rtm_version != RTM_VERSION)
592 return LDP_E_ROUTE_ERROR;
593
594 if (rg->m_rtm.rtm_type == RTM_NEWADDR ||
595 rg->m_rtm.rtm_type == RTM_DELADDR)
596 return check_if_addr_updown(rg, rlen);
597
598 size_cp = sizeof(struct rt_msghdr);
599 CHECK_MINSA;
600
601 if (rg->m_rtm.rtm_pid == getpid() ||
602 ((rg->m_rtm.rtm_flags & RTF_DONE) == 0))
603 return LDP_E_OK;
604
605 debugp("Check route triggered by PID: %d\n", rg->m_rtm.rtm_pid);
606
607 so_dest = (union sockunion *) rg->m_space;
608
609 if (so_dest->sa.sa_family != AF_INET)
610 return LDP_E_OK;/* We don't care about non-IP changes */
611
612 CHECK_LEN(so_dest);
613
614 if (rg->m_rtm.rtm_addrs & RTA_GATEWAY) {
615 GETNEXT(so_gate, so_dest);
616 if ((so_gate->sa.sa_family != AF_INET) &&
617 (so_gate->sa.sa_family != AF_MPLS))
618 return LDP_E_OK;
619 }
620 if (rg->m_rtm.rtm_addrs & RTA_NETMASK) {
621 if (so_gate != NULL) {
622 GETNEXT(so_pref, so_gate);
623 } else
624 GETNEXT(so_pref, so_dest);
625 }
626 /* Calculate prefixlen */
627 if (so_pref)
628 prefixlen = from_union_to_cidr(so_pref);
629 else {
630 prefixlen = 32;
631 if ((so_pref = from_cidr_to_union(32)) == NULL)
632 return LDP_E_MEMORY;
633 so_pref_allocated = 1;
634 }
635
636 so_pref->sa.sa_family = AF_INET;
637 so_pref->sa.sa_len = sizeof(struct sockaddr_in);
638
639 switch (rg->m_rtm.rtm_type) {
640 case RTM_CHANGE:
641 lab = label_get(so_dest, so_pref);
642 if (lab) {
643 send_withdraw_tlv_to_all(&so_dest->sa,
644 prefixlen);
645 label_reattach_route(lab, REATT_INET_DEL);
646 label_del(lab);
647 }
648 /* Fallthrough */
649 case RTM_ADD:
650 /*
651 * Check if the route is connected. If so, bind it to
652 * POP_LABEL and send announce. If not, check if the prefix
653 * was announced by a LDP neighbour and route it there
654 */
655
656 /* First of all check if we already know this one */
657 if (label_get(so_dest, so_pref) == NULL) {
658 /* Just add an IMPLNULL label */
659 if (so_gate == NULL)
660 label_add(so_dest, so_pref, NULL,
661 MPLS_LABEL_IMPLNULL, NULL, 0,
662 rg->m_rtm.rtm_flags & RTF_HOST);
663 else {
664 pm = ldp_test_mapping(&so_dest->sa,
665 prefixlen, &so_gate->sa);
666 if (pm) {
667 /* create an implnull label as it
668 * gets rewritten in mpls_add_label */
669 lab = label_add(so_dest, so_pref,
670 so_gate, MPLS_LABEL_IMPLNULL,
671 pm->peer, pm->lm->label,
672 rg->m_rtm.rtm_flags & RTF_HOST);
673 if (lab != NULL)
674 mpls_add_label(lab);
675 free(pm);
676 } else
677 label_add(so_dest, so_pref, so_gate,
678 MPLS_LABEL_IMPLNULL, NULL, 0,
679 rg->m_rtm.rtm_flags & RTF_HOST);
680 }
681 } else /* We already know about this prefix */
682 fatalp("Binding already there for prefix %s/%d !\n",
683 satos(&so_dest->sa), prefixlen);
684 break;
685 case RTM_DELETE:
686 /*
687 * Send withdraw check the binding, delete the route, delete
688 * the binding
689 */
690 lab = label_get(so_dest, so_pref);
691 if (!lab)
692 break;
693 send_withdraw_tlv_to_all(&so_dest->sa, prefixlen);
694 /* No readd or delete IP route. Just delete the MPLS route */
695 label_reattach_route(lab, REATT_INET_NODEL);
696 label_del(lab);
697 break;
698 }
699
700 if (!debug_f && !warn_f) {
701 if(so_pref_allocated)
702 free(so_pref);
703 return LDP_E_OK;
704 }
705
706 /* Rest is just for debug */
707
708 if (so_dest)
709 strlcpy(dest, satos(&so_dest->sa), sizeof(dest));
710 if (so_pref)
711 snprintf(pref, sizeof(pref), "%d", prefixlen);
712 if (so_gate)
713 strlcpy(gate, satos(&so_gate->sa), sizeof(gate));
714
715 switch (rg->m_rtm.rtm_type) {
716 case RTM_ADD:
717 strlcpy(oper, "added", 20);
718 break;
719 case RTM_DELETE:
720 strlcpy(oper, "delete", 20);
721 break;
722 case RTM_GET:
723 strlcpy(oper, "get", 20);
724 break;
725 case RTM_CHANGE:
726 strlcpy(oper, "change", 20);
727 break;
728 case RTM_LOSING:
729 strlcpy(oper, "losing", 20);
730 break;
731 case RTM_REDIRECT:
732 strlcpy(oper, "redirect", 20);
733 break;
734 case RTM_NEWADDR:
735 strlcpy(oper, "new address", 20);
736 break;
737 case RTM_DELADDR:
738 strlcpy(oper, "del address", 20);
739 break;
740 default:
741 snprintf(oper, sizeof(oper), "unknown 0x%X operation",
742 rg->m_rtm.rtm_type);
743 }
744
745 debugp("[check_route] Route %s: %s / %s -> %s by PID:%d\n", oper, dest,
746 pref, gate, rg->m_rtm.rtm_pid);
747
748 if(so_pref_allocated)
749 free(so_pref);
750 return LDP_E_OK;
751 }
752
753 /*
754 * Checks NEWADDR and DELADDR messages and sends announcements accordingly
755 */
756 static int
757 check_if_addr_updown(struct rt_msg * rg, uint rlen)
758 {
759 union sockunion *ifa, *netmask;
760 struct ldp_peer *p;
761 struct address_list_tlv al_tlv;
762 struct ifa_msghdr *msghdr = (struct ifa_msghdr *)&rg->m_rtm;
763 size_t size_cp = sizeof(struct ifa_msghdr);
764
765 if (rlen < sizeof(struct ifa_msghdr) ||
766 (msghdr->ifam_addrs & RTA_NETMASK) == 0 ||
767 (msghdr->ifam_addrs & RTA_IFA) == 0)
768 return LDP_E_ROUTE_ERROR;
769
770 CHECK_MINSA;
771
772 /* we should have RTA_NETMASK, RTA_IFP, RTA_IFA and RTA_BRD */
773 ifa = netmask = (union sockunion *)(msghdr + 1);
774 if (netmask->sa.sa_family != AF_INET)
775 return LDP_E_OK;
776 CHECK_LEN(netmask);
777
778 if (msghdr->ifam_addrs & RTA_IFP)
779 GETNEXT(ifa, ifa);
780
781 GETNEXT(ifa, ifa);
782
783 if (ifa->sa.sa_family != AF_INET ||
784 ntohl(ifa->sin.sin_addr.s_addr) >> 24 == IN_LOOPBACKNET)
785 return LDP_E_OK;
786
787 memset(&al_tlv, 0, sizeof(al_tlv));
788 al_tlv.type = rg->m_rtm.rtm_type == RTM_NEWADDR ? htons(LDP_ADDRESS) :
789 htons(LDP_ADDRESS_WITHDRAW);
790 al_tlv.length = htons(sizeof(al_tlv) - TLV_TYPE_LENGTH);
791 al_tlv.messageid = htonl(get_message_id());
792 al_tlv.a_type = htons(TLV_ADDRESS_LIST);
793 al_tlv.a_length = htons(sizeof(al_tlv.a_af) + sizeof(al_tlv.a_address));
794 al_tlv.a_af = htons(LDP_AF_INET);
795 memcpy(&al_tlv.a_address, &ifa->sin.sin_addr, sizeof(al_tlv.a_address));
796
797 SLIST_FOREACH(p, &ldp_peer_head, peers)
798 if (p->state == LDP_PEER_ESTABLISHED)
799 send_tlv(p, (struct tlv *)&al_tlv);
800
801 return LDP_E_OK;
802 }
803
804 int
805 bind_current_routes()
806 {
807 size_t needed, size_cp;
808 int mib[6];
809 char *buf, *next, *lim;
810 struct rt_msghdr *rtmes;
811 union sockunion *so_dst, *so_pref, *so_gate;
812 uint rlen;
813
814 mib[0] = CTL_NET;
815 mib[1] = PF_ROUTE;
816 mib[2] = 0;
817 mib[3] = 0;
818 mib[4] = NET_RT_DUMP;
819 mib[5] = 0;
820 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
821 fatalp("route-sysctl-estimate: %s",
822 strerror(errno));
823 return LDP_E_ROUTE_ERROR;
824 }
825 if ((buf = malloc(needed)) == 0)
826 return LDP_E_ROUTE_ERROR;
827 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
828 free(buf);
829 return LDP_E_ROUTE_ERROR;
830 }
831 lim = buf + needed;
832
833 for (next = buf; next < lim; next += rlen) {
834 rtmes = (struct rt_msghdr *) next;
835 rlen = rtmes->rtm_msglen;
836 size_cp = sizeof(struct rt_msghdr);
837 so_gate = so_pref = NULL;
838 if (rtmes->rtm_flags & RTF_LLINFO) /* No need for arps */
839 continue;
840 if (!(rtmes->rtm_addrs & RTA_DST)) {
841 debugp("No dst\n");
842 continue;
843 }
844
845 CHECK_MINSA;
846 so_dst = (union sockunion *) & rtmes[1];
847 CHECK_LEN(so_dst);
848
849 /*
850 * This function is called only at startup, so use
851 * this ocassion to delete all MPLS routes
852 */
853 if (so_dst->sa.sa_family == AF_MPLS) {
854 delete_route(so_dst, NULL, NO_FREESO);
855 debugp("MPLS route deleted.\n");
856 continue;
857 }
858
859 if (so_dst->sa.sa_family != AF_INET) {
860 /*debugp("sa_dst is not AF_INET\n");*/
861 continue;
862 }
863
864 /* Check if it's the default gateway */
865 if (so_dst->sin.sin_addr.s_addr == 0 && no_default_route != 0)
866 continue;
867
868 /* Check if it's loopback */
869 if ((ntohl(so_dst->sin.sin_addr.s_addr) >> 24)==IN_LOOPBACKNET)
870 continue;
871
872 /* Get Gateway */
873 if (rtmes->rtm_addrs & RTA_GATEWAY)
874 GETNEXT(so_gate, so_dst);
875
876 /* Get prefix */
877 if (rtmes->rtm_flags & RTF_HOST) {
878 if ((so_pref = from_cidr_to_union(32)) == NULL)
879 return LDP_E_MEMORY;
880 } else if (rtmes->rtm_addrs & RTA_GATEWAY) {
881 GETNEXT(so_pref, so_gate);
882 } else
883 GETNEXT(so_pref, so_dst);
884
885 so_pref->sa.sa_family = AF_INET;
886 so_pref->sa.sa_len = sizeof(struct sockaddr_in);
887
888 /* Also deletes when dest is IPv4 and gateway MPLS */
889 if ((rtmes->rtm_addrs & RTA_GATEWAY) &&
890 (so_gate->sa.sa_family == AF_MPLS)) {
891 debugp("MPLS route to %s deleted.\n",
892 inet_ntoa(so_dst->sin.sin_addr));
893 delete_route(so_dst,
894 rtmes->rtm_flags & RTF_HOST ? NULL : so_pref,
895 NO_FREESO);
896 if (rtmes->rtm_flags & RTF_HOST)
897 free(so_pref);
898 continue;
899 }
900
901 if (so_gate != NULL && so_gate->sa.sa_family == AF_LINK)
902 so_gate = NULL; /* connected route */
903
904 if (so_gate == NULL || so_gate->sa.sa_family == AF_INET)
905 label_add(so_dst, so_pref, so_gate,
906 MPLS_LABEL_IMPLNULL, NULL, 0,
907 rtmes->rtm_flags & RTF_HOST);
908
909 if (rtmes->rtm_flags & RTF_HOST)
910 free(so_pref);
911 }
912 free(buf);
913 return LDP_E_OK;
914 }
915
916 int
917 flush_mpls_routes()
918 {
919 size_t needed, size_cp;
920 int mib[6];
921 uint rlen;
922 char *buf, *next, *lim;
923 struct rt_msghdr *rtm;
924 union sockunion *so_dst, *so_pref, *so_gate;
925
926 mib[0] = CTL_NET;
927 mib[1] = PF_ROUTE;
928 mib[2] = 0;
929 mib[3] = 0;
930 mib[4] = NET_RT_DUMP;
931 mib[5] = 0;
932 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
933 fatalp("route-sysctl-estimate: %s", strerror(errno));
934 return LDP_E_ROUTE_ERROR;
935 }
936 if ((buf = malloc(needed)) == NULL) {
937 fatalp("route-sysctl-estimate: %s", strerror(errno));
938 return LDP_E_MEMORY;
939 }
940 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
941 free(buf);
942 return LDP_E_ROUTE_ERROR;
943 }
944 lim = buf + needed;
945
946 for (next = buf; next < lim; next += rlen) {
947 rtm = (struct rt_msghdr *) next;
948 size_cp = sizeof(struct rt_msghdr);
949 rlen = rtm->rtm_msglen;
950 so_pref = NULL;
951 so_gate = NULL;
952 if (rtm->rtm_flags & RTF_LLINFO) /* No need for arps */
953 continue;
954 if (!(rtm->rtm_addrs & RTA_DST)) {
955 debugp("No dst\n");
956 continue;
957 }
958 so_dst = (union sockunion *) & rtm[1];
959
960 if (so_dst->sa.sa_family == AF_MPLS) {
961 delete_route(so_dst, NULL, NO_FREESO);
962 debugp("MPLS route deleted.\n");
963 continue;
964 }
965
966 if ((rtm->rtm_addrs & RTA_GATEWAY) == 0)
967 continue;
968 GETNEXT(so_gate, so_dst);
969
970 if ((rtm->rtm_flags & RTF_HOST) == 0)
971 GETNEXT(so_pref, so_gate);
972
973 if (so_gate->sa.sa_family == AF_MPLS) {
974 if (so_dst->sa.sa_family == AF_INET)
975 debugp("MPLS route to %s deleted.\n",
976 inet_ntoa(so_dst->sin.sin_addr));
977 delete_route(so_dst, so_pref, NO_FREESO);
978 continue;
979 }
980
981 }
982 free(buf);
983 return LDP_E_OK;
984 }
985