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