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