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