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