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