1 /* $NetBSD: mpls_routes.c,v 1.2 2010/12/09 00:10:59 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Mihai Chelaru <kefren@NetBSD.org> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 #include <sys/param.h> 35 #include <sys/sysctl.h> 36 #include <net/if.h> 37 #include <net/route.h> 38 #include <netinet/in.h> 39 #include <netmpls/mpls.h> 40 41 #include <arpa/inet.h> 42 43 #include <assert.h> 44 #include <stdlib.h> 45 #include <errno.h> 46 #include <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 = calloc(1, sizeof(*so_inet)); 162 163 if (!so_inet) { 164 fatalp("make_inet_union: malloc problem\n"); 165 return NULL; 166 } 167 168 so_inet->sin.sin_len = sizeof(struct sockaddr_in); 169 so_inet->sin.sin_family = AF_INET; 170 inet_aton(s, &so_inet->sin.sin_addr); 171 172 return so_inet; 173 } 174 175 /* creates a sockunion from a label */ 176 union sockunion * 177 make_mpls_union(uint32_t label) 178 { 179 union sockunion *so_mpls; 180 181 so_mpls = calloc(1, sizeof(*so_mpls)); 182 183 if (!so_mpls) { 184 fatalp("make_mpls_union: malloc problem\n"); 185 return NULL; 186 } 187 188 so_mpls->smpls.smpls_len = sizeof(struct sockaddr_mpls); 189 so_mpls->smpls.smpls_family = AF_MPLS; 190 so_mpls->smpls.smpls_addr.shim.label = label; 191 192 so_mpls->smpls.smpls_addr.s_addr = 193 htonl(so_mpls->smpls.smpls_addr.s_addr); 194 195 return so_mpls; 196 } 197 198 int 199 compare_sockunion(union sockunion * __restrict a, 200 union sockunion * __restrict b) 201 { 202 if (a->sa.sa_len != b->sa.sa_len) 203 return 1; 204 return memcmp(a, b, a->sa.sa_len); 205 } 206 207 union sockunion * 208 from_cidr_to_union(uint8_t prefixlen) 209 { 210 union sockunion *u; 211 int32_t n = -1; 212 uint32_t *m = (uint32_t*)&n; 213 214 *m = (*m >> (32 - prefixlen) ) << (32 - prefixlen); 215 *m = ntohl(*m); 216 217 u = calloc(1, sizeof(*u)); 218 219 if (!u) { 220 fatalp("from_cidr_to_union: malloc problem\n"); 221 return NULL; 222 } 223 u->sin.sin_len = sizeof(struct sockaddr_in); 224 u->sin.sin_family = AF_INET; 225 u->sin.sin_addr.s_addr = *m; 226 227 return u; 228 229 } 230 231 uint8_t 232 from_mask_to_cidr(char *mask) 233 { 234 /* LoL (although I don't think about something faster right now) */ 235 char mtest[20]; 236 uint8_t i; 237 238 for (i = 1; i < 32; i++) { 239 from_cidr_to_mask(i, mtest); 240 if (!strcmp(mask, mtest)) 241 break; 242 } 243 return i; 244 } 245 246 uint8_t 247 from_union_to_cidr(union sockunion *so_pref) 248 { 249 struct sockaddr_in *sin = (struct sockaddr_in*)so_pref; 250 uint32_t a; 251 uint8_t r; 252 253 a = ntohl(sin->sin_addr.s_addr); 254 for (r=0; a ; a = a << 1, r++); 255 256 return r; 257 } 258 259 /* returns in mask the netmask created from CIDR prefixlen */ 260 void 261 from_cidr_to_mask(uint8_t prefixlen, char *mask) 262 { 263 uint32_t a = 0, p = prefixlen; 264 if (prefixlen > 32) { 265 strlcpy(mask, "255.255.255.255", 16); 266 return; 267 } 268 for (; p > 0; p--) { 269 a = a >> (p - 1); 270 a += 1; 271 a = a << (p - 1); 272 } 273 /* is this OK ? */ 274 #if _BYTE_ORDER == _LITTLE_ENDIAN 275 a = a << (32 - prefixlen); 276 #endif 277 278 snprintf(mask, 16, "%d.%d.%d.%d", a >> 24, (a << 8) >> 24, 279 (a << 16) >> 24, (a << 24) >> 24); 280 } 281 282 char * 283 mpls_ntoa(union mpls_shim ms) 284 { 285 static char ret[255]; 286 union mpls_shim ms2; 287 288 ms2.s_addr = ntohl(ms.s_addr); 289 snprintf(ret, sizeof(ret), "%d", ms2.shim.label); 290 return ret; 291 } 292 293 char * 294 union_ntoa(union sockunion * so) 295 { 296 static char defret[] = "Unknown family address"; 297 switch (so->sa.sa_family) { 298 case AF_INET: 299 return inet_ntoa(so->sin.sin_addr); 300 case AF_LINK: 301 return link_ntoa(&so->sdl); 302 case AF_MPLS: 303 return mpls_ntoa(so->smpls.smpls_addr); 304 } 305 fatalp("Unknown family address in union_ntoa: %d\n", 306 so->sa.sa_family); 307 return defret; 308 } 309 310 /* From src/sbin/route/route.c */ 311 static const char * 312 route_strerror(int error) 313 { 314 315 switch (error) { 316 case ESRCH: 317 return "not in table"; 318 case EBUSY: 319 return "entry in use"; 320 case ENOBUFS: 321 return "routing table overflow"; 322 default: 323 return strerror(error); 324 } 325 } 326 327 328 /* Adds a route. Or changes it. */ 329 int 330 add_route(union sockunion *so_dest, union sockunion *so_prefix, 331 union sockunion *so_gate, union sockunion *so_ifa, union sockunion *so_tag, 332 int fr, int optype) 333 { 334 int l, rlen, rv = LDP_E_OK; 335 struct rt_msg rm; 336 char *cp; 337 338 if(dont_catch) 339 return LDP_E_OK; 340 341 memset(&rm, 0, sizeof(rm)); 342 cp = rm.m_space; 343 344 rm.m_rtm.rtm_type = (optype == RTM_READD) ? RTM_ADD : optype; 345 rm.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 346 347 rm.m_rtm.rtm_version = RTM_VERSION; 348 rm.m_rtm.rtm_seq = ++rt_seq; 349 rm.m_rtm.rtm_addrs = RTA_DST; 350 if (so_gate) 351 rm.m_rtm.rtm_addrs |= RTA_GATEWAY; 352 353 assert(so_dest); 354 355 /* Order is: destination, gateway, netmask, genmask, ifp, ifa, tag */ 356 NEXTADDR(so_dest); 357 if (so_gate) 358 NEXTADDR(so_gate); 359 360 if (so_prefix) { 361 mask_addr(so_prefix); 362 NEXTADDR(so_prefix); 363 /* XXX: looks like nobody cares about this */ 364 rm.m_rtm.rtm_flags |= RTF_MASK; 365 rm.m_rtm.rtm_addrs |= RTA_NETMASK; 366 } else 367 rm.m_rtm.rtm_flags |= RTF_HOST; 368 369 /* route to mpls interface */ 370 if (optype != RTM_READD && so_dest->sa.sa_family != AF_MPLS) { 371 NEXTADDR2(mplssockaddr); 372 rm.m_rtm.rtm_addrs |= RTA_IFP; 373 } 374 375 if (so_ifa != NULL) { 376 NEXTADDR(so_ifa); 377 rm.m_rtm.rtm_addrs |= RTA_IFA; 378 } 379 380 if (so_tag) { 381 NEXTADDR(so_tag); 382 rm.m_rtm.rtm_addrs |= RTA_TAG; 383 } 384 385 rm.m_rtm.rtm_msglen = l = cp - (char *) &rm; 386 387 if ((rlen = write(route_socket, (char *) &rm, l)) < l) { 388 warnp("Error adding a route: %s\n", route_strerror(errno)); 389 warnp("Destination was: %s\n", union_ntoa(so_dest)); 390 if (so_prefix) 391 warnp("Prefix was: %s\n", union_ntoa(so_prefix)); 392 if (so_gate) 393 warnp("Gateway was: %s\n", union_ntoa(so_gate)); 394 rv = LDP_E_ROUTE_ERROR; 395 } 396 if (fr) { 397 free(so_dest); 398 if (so_prefix) 399 free(so_prefix); 400 if (so_gate) 401 free(so_gate); 402 if (so_ifa) 403 free(so_ifa); 404 if (so_tag) 405 free(so_tag); 406 } 407 408 return rv; 409 } 410 411 /* Deletes a route */ 412 int 413 delete_route(union sockunion * so_dest, union sockunion * so_pref, int freeso) 414 { 415 int l, rlen; 416 struct rt_msg rm; 417 char *cp; 418 419 if(dont_catch) 420 return LDP_E_OK; 421 422 memset(&rm, 0, sizeof(struct rt_msg)); 423 cp = rm.m_space; 424 425 rm.m_rtm.rtm_type = RTM_DELETE; 426 rm.m_rtm.rtm_version = RTM_VERSION; 427 rm.m_rtm.rtm_seq = ++rt_seq; 428 if (so_pref) 429 rm.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK; 430 else 431 rm.m_rtm.rtm_addrs = RTA_DST; 432 433 /* destination, gateway, netmask, genmask, ifp, ifa */ 434 435 NEXTADDR(so_dest); 436 437 if (so_pref) { 438 mask_addr(so_pref); 439 NEXTADDR(so_pref); 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), union_ntoa(so_dest), 455 spreftmp); 456 } else 457 warnp("Error deleting route(%s) : %s", 458 route_strerror(errno), union_ntoa(so_dest)); 459 return LDP_E_NO_SUCH_ROUTE; 460 } 461 return LDP_E_OK; 462 } 463 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, union sockunion * so_dest, 471 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 rm.m_rtm.rtm_addrs |= RTA_NETMASK; 503 mask_addr(so_pref); 504 NEXTADDR(so_pref); 505 } 506 rm.m_rtm.rtm_msglen = l = cp - (char *) &rm; 507 508 if ((rlen = write(route_socket, (char *) &rm, l)) < l) { 509 debugp("Cannot get a route !(rlen=%d instead of %d) - %s\n", 510 rlen, l, strerror(errno)); 511 return LDP_E_NO_SUCH_ROUTE; 512 } else 513 do { 514 rlen = read_route_socket((char *) rg, 515 sizeof(struct rt_msg)); 516 if (rlen < 1) 517 break; 518 /* 519 * We might lose important messages here. WORKAROUND: 520 * For now I just try to save this messages and replay 521 * them later 522 */ 523 if ((rg->m_rtm.rtm_pid != getpid()) || 524 (rg->m_rtm.rtm_seq != myseq)) { 525 /* 526 * Shortcut: my pid but not 527 * the expected sequence 528 */ 529 if (rg->m_rtm.rtm_pid == getpid()) 530 continue; 531 532 debugp("Added to replay PID: %d, SEQ: %d\n", 533 rg->m_rtm.rtm_pid, rg->m_rtm.rtm_seq); 534 memcpy(&replay_rt[replay_index], rg, 535 sizeof(struct rt_msg)); 536 if (replay_index < REPLAY_MAX - 1) 537 replay_index++; 538 continue; 539 } 540 } while ((rg->m_rtm.rtm_seq != myseq) || 541 (rg->m_rtm.rtm_pid != getpid())); 542 543 if ((uint)rlen <= sizeof(struct rt_msghdr)) { 544 debugp("Got only %d bytes, expecting at least %u\n", rlen, 545 sizeof(struct rt_msghdr)); 546 return LDP_E_ROUTE_ERROR; 547 } 548 549 /* Check if we don't have a less specific route */ 550 if (exact_match) { 551 su = (union sockunion*)(rg->m_space); 552 if (compare_sockunion(so_dest, su)) { 553 debugp("Dest %s ", union_ntoa(so_dest)); 554 debugp("not like %s\n", union_ntoa(su)); 555 return LDP_E_NO_SUCH_ROUTE; 556 } 557 } 558 559 return LDP_E_OK; 560 } 561 562 563 /* triggered when a route event occurs */ 564 int 565 check_route(struct rt_msg * rg, uint rlen) 566 { 567 union sockunion *so_dest = NULL, *so_gate = NULL, *so_pref = NULL; 568 int so_pref_allocated = 0; 569 int prefixlen; 570 struct peer_map *pm; 571 struct label *lab; 572 char dest[50], gate[50], pref[50], oper[50]; 573 dest[0] = 0; 574 gate[0] = 0; 575 pref[0] = 0; 576 577 if (rlen <= sizeof(struct rt_msghdr)) 578 return LDP_E_ROUTE_ERROR; 579 580 if (rg->m_rtm.rtm_version != RTM_VERSION) 581 return LDP_E_ROUTE_ERROR; 582 583 if ((rg->m_rtm.rtm_flags & RTF_DONE) == 0) 584 return LDP_E_OK; 585 586 if (rg->m_rtm.rtm_pid == getpid()) /* We did it.. */ 587 return LDP_E_OK; 588 else 589 debugp("Check route triggered by PID: %d\n", rg->m_rtm.rtm_pid); 590 591 so_dest = (union sockunion *) rg->m_space; 592 593 if (so_dest->sa.sa_family != AF_INET) 594 return LDP_E_OK;/* We don't care about non-IP changes */ 595 596 if (rg->m_rtm.rtm_addrs & RTA_GATEWAY) { 597 so_gate = GETNEXT(so_dest); 598 if ((so_gate->sa.sa_family != AF_INET) && 599 (so_gate->sa.sa_family != AF_MPLS)) 600 return LDP_E_OK; 601 } 602 if (rg->m_rtm.rtm_addrs & RTA_NETMASK) { 603 if (so_gate) 604 so_pref = so_gate; 605 else 606 so_pref = so_dest; 607 so_pref = GETNEXT(so_pref); 608 } 609 if (!(rg->m_rtm.rtm_flags & RTF_GATEWAY)) { 610 if (rg->m_rtm.rtm_addrs & RTA_GENMASK) { 611 debugp("Used GENMASK\n"); 612 } else 613 debugp("No GENMASK to use\n"); 614 } 615 /* Calculate prefixlen */ 616 if (so_pref) 617 prefixlen = from_mask_to_cidr(inet_ntoa(so_pref->sin.sin_addr)); 618 else { 619 prefixlen = 32; 620 so_pref = from_cidr_to_union(32); 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 warnp("XXX: RTM_CHANGE\n"); 630 /* Fallthrough */ 631 case RTM_ADD: 632 /* 633 * Check if the route is connected. If so, bind it to 634 * POP_LABEL and send announce. If not, check if the prefix 635 * was announced by a LDP neighbour and route it there 636 */ 637 638 /* First of all check if we already know this one */ 639 lab = label_get(so_dest, so_pref); 640 if (!lab) { 641 if (!(rg->m_rtm.rtm_flags & RTF_GATEWAY)) 642 lab = label_add(so_dest, so_pref, NULL, 643 MPLS_LABEL_IMPLNULL, NULL, 0); 644 else { 645 pm = ldp_test_mapping(&so_dest->sin.sin_addr, 646 prefixlen, &so_gate->sin.sin_addr); 647 if (pm) { 648 lab = label_add(so_dest, so_pref, 649 so_gate, 0, NULL, 0); 650 mpls_add_label(pm->peer, rg, 651 &so_dest->sin.sin_addr, prefixlen, 652 pm->lm->label, ROUTE_LOOKUP_LOOP); 653 free(pm); 654 } else 655 lab = label_add(so_dest, so_pref, 656 so_gate, MPLS_LABEL_IMPLNULL, 657 NULL, 0); 658 } 659 } else /* We already know about this prefix */ 660 debugp("Binding already there for prefix %s/%d !\n", 661 union_ntoa(so_dest), prefixlen); 662 break; 663 case RTM_DELETE: 664 if (!so_gate) 665 break; /* Non-existent route XXX ?! */ 666 /* 667 * Send withdraw check the binding, delete the route, delete 668 * the binding 669 */ 670 lab = label_get(so_dest, so_pref); 671 if (!lab) 672 break; 673 send_withdraw_tlv_to_all(&so_dest->sin.sin_addr, prefixlen); 674 /* No readd as IPv4. Also don't even try to delete it */ 675 label_reattach_route(lab, LDP_READD_NODEL); 676 label_del(lab); 677 break; 678 } 679 680 /* Rest is just for debug */ 681 682 if (so_dest) 683 strlcpy(dest, union_ntoa(so_dest), 16); 684 if (so_pref) 685 snprintf(pref, 3, "%d", prefixlen); 686 if (so_gate) 687 strlcpy(gate, union_ntoa(so_gate), 16); 688 689 switch (rg->m_rtm.rtm_type) { 690 case RTM_ADD: 691 strlcpy(oper, "added", 20); 692 break; 693 case RTM_DELETE: 694 strlcpy(oper, "delete", 20); 695 break; 696 case RTM_GET: 697 strlcpy(oper, "get", 20); 698 break; 699 case RTM_CHANGE: 700 strlcpy(oper, "change", 20); 701 break; 702 case RTM_LOSING: 703 strlcpy(oper, "losing", 20); 704 break; 705 case RTM_NEWADDR: 706 strlcpy(oper, "new address", 20); 707 break; 708 case RTM_DELADDR: 709 strlcpy(oper, "del address", 20); 710 break; 711 default: 712 snprintf(oper, 50, "unknown 0x%X operation", 713 rg->m_rtm.rtm_type); 714 } 715 716 warnp("[check_route] Route %s: %s / %s -> %s by PID:%d\n", oper, dest, 717 pref, gate, rg->m_rtm.rtm_pid); 718 719 if(so_pref_allocated) 720 free(so_pref); 721 return LDP_E_OK; 722 } 723 724 int 725 bind_current_routes() 726 { 727 size_t needed; 728 int mib[6]; 729 char *buf, *next, *lim; 730 struct rt_msghdr *rtmes; 731 union sockunion *so_dst, *so_pref, *so_gate; 732 struct label *lab; 733 734 mib[0] = CTL_NET; 735 mib[1] = PF_ROUTE; 736 mib[2] = 0; 737 mib[3] = 0; 738 mib[4] = NET_RT_DUMP; 739 mib[5] = 0; 740 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 741 fatalp("route-sysctl-estimate: %s", 742 strerror(errno)); 743 return LDP_E_ROUTE_ERROR; 744 } 745 if ((buf = malloc(needed)) == 0) 746 return LDP_E_ROUTE_ERROR; 747 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 748 free(buf); 749 return LDP_E_ROUTE_ERROR; 750 } 751 lim = buf + needed; 752 753 for (next = buf; next < lim; next += rtmes->rtm_msglen) { 754 rtmes = (struct rt_msghdr *) next; 755 so_pref = NULL; 756 so_gate = NULL; 757 if (rtmes->rtm_flags & RTF_LLINFO) /* No need for arps */ 758 continue; 759 if (!(rtmes->rtm_addrs & RTA_DST)) { 760 debugp("No dst\n"); 761 continue; 762 } 763 764 so_dst = (union sockunion *) & rtmes[1]; 765 766 /* 767 * As this function is call only at startup use this ocassion 768 * to delete all MPLS routes 769 */ 770 if (so_dst->sa.sa_family == AF_MPLS) { 771 delete_route(so_dst, NULL, NO_FREESO); 772 debugp("MPLS route deleted.\n"); 773 continue; 774 } 775 776 if (so_dst->sa.sa_family != AF_INET) { 777 debugp("sa_dst is not AF_INET\n"); 778 continue; 779 } 780 781 /* Check if it's the default gateway */ 782 if (so_dst->sin.sin_addr.s_addr == 0) 783 continue; 784 785 /* XXX: Check if it's loopback */ 786 if ((ntohl(so_dst->sin.sin_addr.s_addr) >> 24)==IN_LOOPBACKNET) 787 continue; 788 789 /* Get Gateway */ 790 if (rtmes->rtm_addrs & RTA_GATEWAY) 791 so_gate = GETNEXT(so_dst); 792 793 /* Get prefix */ 794 if (rtmes->rtm_flags & RTF_HOST) 795 so_pref = from_cidr_to_union(32); 796 else if (rtmes->rtm_addrs & RTA_GATEWAY) 797 so_pref = GETNEXT(so_gate); 798 else 799 so_pref = GETNEXT(so_dst); 800 801 so_pref->sa.sa_family = AF_INET; 802 so_pref->sa.sa_len = sizeof(struct sockaddr_in); 803 804 /* Also deletes when dest is IPv4 and gateway MPLS */ 805 if ((rtmes->rtm_addrs & RTA_GATEWAY) && 806 (so_gate->sa.sa_family == AF_MPLS)) { 807 debugp("MPLS route to %s deleted.\n", 808 inet_ntoa(so_dst->sin.sin_addr)); 809 delete_route(so_dst, so_pref, NO_FREESO); 810 if (rtmes->rtm_flags & RTF_HOST) 811 free(so_pref); 812 continue; 813 } 814 if (so_gate->sa.sa_family == AF_INET) 815 lab = label_add(so_dst, so_pref, so_gate, 816 MPLS_LABEL_IMPLNULL, NULL, 0); 817 818 if (rtmes->rtm_flags & RTF_HOST) 819 free(so_pref); 820 } 821 free(buf); 822 return LDP_E_OK; 823 } 824 825 int 826 flush_mpls_routes() 827 { 828 size_t needed; 829 int mib[6]; 830 char *buf, *next, *lim; 831 struct rt_msghdr *rtm; 832 union sockunion *so_dst, *so_pref, *so_gate; 833 834 mib[0] = CTL_NET; 835 mib[1] = PF_ROUTE; 836 mib[2] = 0; 837 mib[3] = 0; 838 mib[4] = NET_RT_DUMP; 839 mib[5] = 0; 840 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 841 fatalp("route-sysctl-estimate: %s", strerror(errno)); 842 return LDP_E_ROUTE_ERROR; 843 } 844 if ((buf = malloc(needed)) == NULL) { 845 fatalp("route-sysctl-estimate: %s", strerror(errno)); 846 return LDP_E_MEMORY; 847 } 848 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 849 free(buf); 850 return LDP_E_ROUTE_ERROR; 851 } 852 lim = buf + needed; 853 854 for (next = buf; next < lim; next += rtm->rtm_msglen) { 855 rtm = (struct rt_msghdr *) next; 856 so_pref = NULL; 857 so_gate = NULL; 858 if (rtm->rtm_flags & RTF_LLINFO) /* No need for arps */ 859 continue; 860 if (!(rtm->rtm_addrs & RTA_DST)) { 861 debugp("No dst\n"); 862 continue; 863 } 864 so_dst = (union sockunion *) & rtm[1]; 865 866 if (so_dst->sa.sa_family == AF_MPLS) { 867 delete_route(so_dst, NULL, NO_FREESO); 868 debugp("MPLS route deleted.\n"); 869 continue; 870 } 871 872 if (rtm->rtm_addrs & RTA_GATEWAY) { 873 so_gate = GETNEXT(so_dst); 874 so_pref = GETNEXT(so_gate); 875 } else 876 so_pref = GETNEXT(so_dst); 877 878 if (so_gate->sa.sa_family == AF_MPLS) { 879 debugp("MPLS route to %s deleted.\n", 880 inet_ntoa(so_dst->sin.sin_addr)); 881 delete_route(so_dst, so_pref, NO_FREESO); 882 continue; 883 } 884 885 } 886 free(buf); 887 return LDP_E_OK; 888 } 889