1 /* $NetBSD: ldp_peer.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 <netinet/in.h> 35 #include <netmpls/mpls.h> 36 #include <arpa/inet.h> 37 38 #include <stdlib.h> 39 #include <strings.h> 40 #include <stdio.h> 41 #include <unistd.h> 42 #include <errno.h> 43 #include "socketops.h" 44 #include "ldp_errors.h" 45 #include "ldp.h" 46 #include "tlv_stack.h" 47 #include "mpls_interface.h" 48 #include "notifications.h" 49 #include "ldp_peer.h" 50 51 struct in_addr *myaddresses; 52 53 void 54 ldp_peer_init(void) 55 { 56 SLIST_INIT(&ldp_peer_head); 57 myaddresses = NULL; 58 } 59 60 /* 61 * soc should be > 1 if there is already a TCP socket for this else we'll 62 * initiate a new one 63 */ 64 struct ldp_peer * 65 ldp_peer_new(struct in_addr * ldp_id, struct in_addr * a, 66 struct in_addr * tradd, uint16_t holdtime, int soc) 67 { 68 struct ldp_peer *p; 69 int s = soc; 70 struct sockaddr_in sa; 71 72 if (s < 1) { 73 s = socket(PF_INET, SOCK_STREAM, 0); 74 memset(&sa, 0, sizeof(sa)); 75 sa.sin_len = sizeof(sa); 76 sa.sin_family = AF_INET; 77 78 if (tradd) 79 memcpy(&sa.sin_addr, tradd, 80 sizeof(struct in_addr)); 81 else 82 memcpy(&sa.sin_addr, a, 83 sizeof(struct in_addr)); 84 sa.sin_port = htons(LDP_PORT); 85 86 set_ttl(s); 87 } 88 89 /* Set the peer in CONNECTING/CONNECTED state */ 90 p = calloc(1, sizeof(*p)); 91 92 if (!p) { 93 fatalp("ldp_peer_new: malloc problem\n"); 94 return NULL; 95 } 96 97 SLIST_INSERT_HEAD(&ldp_peer_head, p, peers); 98 memcpy(&p->address, a, sizeof(struct in_addr)); 99 memcpy(&p->ldp_id, ldp_id, sizeof(struct in_addr)); 100 if (tradd) 101 memcpy(&p->transport_address, tradd, 102 sizeof(struct in_addr)); 103 else 104 memcpy(&p->transport_address, a, 105 sizeof(struct in_addr)); 106 p->holdtime = holdtime > LDP_HOLDTIME ? holdtime : LDP_HOLDTIME; 107 p->socket = s; 108 if (soc < 1) { 109 p->state = LDP_PEER_CONNECTING; 110 p->master = 1; 111 } else { 112 p->state = LDP_PEER_CONNECTED; 113 p->master = 0; 114 set_ttl(p->socket); 115 } 116 SLIST_INIT(&p->ldp_peer_address_head); 117 SLIST_INIT(&p->label_mapping_head); 118 p->timeout = p->holdtime; 119 120 /* And connect to peer */ 121 if (soc < 1) 122 if (connect(s, (struct sockaddr *) & sa, sizeof(sa)) == -1) { 123 if (errno == EINTR) { 124 return p; /* We take care of this in 125 * big_loop */ 126 } 127 warnp("connect to %s failed: %s\n", 128 inet_ntoa(sa.sin_addr), strerror(errno)); 129 ldp_peer_holddown(p); 130 return NULL; 131 } 132 p->state = LDP_PEER_CONNECTED; 133 return p; 134 } 135 136 void 137 ldp_peer_holddown(struct ldp_peer * p) 138 { 139 if (!p) 140 return; 141 if (p->state == LDP_PEER_ESTABLISHED) 142 mpls_delete_ldp_peer(p); 143 p->state = LDP_PEER_HOLDDOWN; 144 p->timeout = LDP_HOLDTIME; 145 shutdown(p->socket, SHUT_RDWR); 146 ldp_peer_delete_all_mappings(p); 147 del_all_ifaddr(p); 148 fatalp("LDP Neighbour %s is DOWN\n", inet_ntoa(p->ldp_id)); 149 } 150 151 void 152 ldp_peer_holddown_all() 153 { 154 struct ldp_peer *p; 155 156 SLIST_FOREACH(p, &ldp_peer_head, peers) { 157 if ((p->state == LDP_PEER_ESTABLISHED) || 158 (p->state == LDP_PEER_CONNECTED)) 159 send_notification(p, get_message_id(), NOTIF_SHUTDOWN); 160 ldp_peer_holddown(p); 161 } 162 } 163 164 void 165 ldp_peer_delete(struct ldp_peer * p) 166 { 167 168 if (!p) 169 return; 170 171 SLIST_REMOVE(&ldp_peer_head, p, ldp_peer, peers); 172 close(p->socket); 173 warnp("LDP Neighbor %s holddown timer expired\n", inet_ntoa(p->ldp_id)); 174 free(p); 175 } 176 177 struct ldp_peer * 178 get_ldp_peer(struct in_addr * a) 179 { 180 struct ldp_peer *p; 181 182 SLIST_FOREACH(p, &ldp_peer_head, peers) { 183 if (!memcmp((void *) a, (void *) &p->ldp_id, 184 sizeof(struct in_addr))) 185 return p; 186 if (!memcmp((void *) a, (void *) &p->address, 187 sizeof(struct in_addr))) 188 return p; 189 if (check_ifaddr(p, a)) 190 return p; 191 } 192 return NULL; 193 } 194 195 struct ldp_peer * 196 get_ldp_peer_by_socket(int s) 197 { 198 struct ldp_peer *p; 199 200 SLIST_FOREACH(p, &ldp_peer_head, peers) 201 if (p->socket == s) 202 return p; 203 return NULL; 204 } 205 206 /* 207 * Adds address list bounded to a specific peer 208 * Returns the number of addresses inserted successfuly 209 */ 210 int 211 add_ifaddresses(struct ldp_peer * p, struct al_tlv * a) 212 { 213 int i, c, n; 214 struct in_addr *ia; 215 216 /* 217 * Check if tlv is Address type, if it's correct size (at least one 218 * address) and if it's IPv4 219 */ 220 221 if ((ntohs(a->type) != TLV_ADDRESS_LIST) || 222 (ntohs(a->length) < sizeof(a->af) + sizeof(struct in_addr)) || 223 (ntohs(a->af) != LDP_AF_INET)) 224 return 0; 225 226 /* Number of addresses to insert */ 227 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr); 228 229 debugp("Trying to add %d addresses to peer %s ... \n", n, 230 inet_ntoa(p->ldp_id)); 231 232 for (ia = (struct in_addr *) & a->address, c = 0, i = 0; i < n; i++) { 233 if (add_ifaddr(p, &ia[i]) == LDP_E_OK) 234 c++; 235 } 236 237 debugp("Added %d addresses\n", c); 238 239 return c; 240 } 241 242 int 243 del_ifaddresses(struct ldp_peer * p, struct al_tlv * a) 244 { 245 int i, c, n; 246 struct in_addr *ia; 247 248 /* 249 * Check if tlv is Address type, if it's correct size (at least one 250 * address) and if it's IPv4 251 */ 252 253 if (ntohs(a->type) != TLV_ADDRESS_LIST || 254 ntohs(a->length) > sizeof(a->af) + sizeof(struct in_addr) || 255 ntohs(a->af) != LDP_AF_INET) 256 return -1; 257 258 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr); 259 260 debugp("Trying to delete %d addresses from peer %s ... \n", n, 261 inet_ntoa(p->ldp_id)); 262 263 for (ia = (struct in_addr *) & a[1], c = 0, i = 0; i < n; i++) { 264 if (del_ifaddr(p, &ia[i]) == LDP_E_OK) 265 c++; 266 } 267 268 debugp("Deleted %d addresses\n", c); 269 270 return c; 271 } 272 273 274 /* Adds a _SINGLE_ address to a specific peer */ 275 int 276 add_ifaddr(struct ldp_peer * p, struct in_addr * a) 277 { 278 struct ldp_peer_address *lpa; 279 280 /* Is it already there ? */ 281 if (check_ifaddr(p, a)) 282 return LDP_E_ALREADY_DONE; 283 284 lpa = calloc(1, sizeof(*lpa)); 285 286 if (!lpa) { 287 fatalp("add_ifaddr: malloc problem\n"); 288 return LDP_E_MEMORY; 289 } 290 291 memcpy(&lpa->address, a, sizeof(struct in_addr)); 292 293 SLIST_INSERT_HEAD(&p->ldp_peer_address_head, lpa, addresses); 294 return LDP_E_OK; 295 } 296 297 /* Deletes an address bounded to a specific peer */ 298 int 299 del_ifaddr(struct ldp_peer * p, struct in_addr * a) 300 { 301 struct ldp_peer_address *wp; 302 303 wp = check_ifaddr(p, a); 304 if (!wp) 305 return LDP_E_NOENT; 306 307 SLIST_REMOVE(&p->ldp_peer_address_head, wp, ldp_peer_address, 308 addresses); 309 free(wp); 310 return LDP_E_OK; 311 } 312 313 /* Checks if an address is already bounded */ 314 struct ldp_peer_address * 315 check_ifaddr(struct ldp_peer * p, struct in_addr * a) 316 { 317 struct ldp_peer_address *wp; 318 319 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) 320 if (memcmp(a, &wp->address, sizeof(struct in_addr)) == 0) 321 return wp; 322 return NULL; 323 } 324 325 void 326 del_all_ifaddr(struct ldp_peer * p) 327 { 328 struct ldp_peer_address *wp; 329 330 while (!SLIST_EMPTY(&p->ldp_peer_address_head)) { 331 wp = SLIST_FIRST(&p->ldp_peer_address_head); 332 SLIST_REMOVE_HEAD(&p->ldp_peer_address_head, addresses); 333 free(wp); 334 } 335 } 336 337 void 338 print_bounded_addresses(struct ldp_peer * p) 339 { 340 struct ldp_peer_address *wp; 341 char abuf[512]; 342 343 snprintf(abuf, sizeof(abuf), "Addresses bounded to peer %s: ", 344 inet_ntoa(p->address)); 345 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) { 346 strncat(abuf, inet_ntoa(wp->address), sizeof(abuf) -1); 347 strncat(abuf, " ", sizeof(abuf) -1); 348 } 349 warnp("%s\n", abuf); 350 } 351 352 void 353 add_my_if_addrs(struct in_addr * a, int count) 354 { 355 myaddresses = calloc((count + 1), sizeof(*myaddresses)); 356 357 if (!myaddresses) { 358 fatalp("add_my_if_addrs: malloc problem\n"); 359 return; 360 } 361 memcpy(myaddresses, a, count * sizeof(struct in_addr)); 362 myaddresses[count].s_addr = 0; 363 } 364 365 /* Adds a label and a prefix to a specific peer */ 366 int 367 ldp_peer_add_mapping(struct ldp_peer * p, struct in_addr * a, int prefix, 368 int label) 369 { 370 struct label_mapping *lma; 371 372 if (!p) 373 return -1; 374 if (ldp_peer_get_lm(p, a, prefix)) 375 return LDP_E_ALREADY_DONE; 376 377 lma = malloc(sizeof(*lma)); 378 379 if (!lma) { 380 fatalp("ldp_peer_add_mapping: malloc problem\n"); 381 return LDP_E_MEMORY; 382 } 383 384 memcpy(&lma->address, a, sizeof(struct in_addr)); 385 lma->prefix = prefix; 386 lma->label = label; 387 388 SLIST_INSERT_HEAD(&p->label_mapping_head, lma, mappings); 389 390 return LDP_E_OK; 391 } 392 393 int 394 ldp_peer_delete_mapping(struct ldp_peer * p, struct in_addr * a, int prefix) 395 { 396 struct label_mapping *lma; 397 398 if (!a) 399 return ldp_peer_delete_all_mappings(p); 400 401 lma = ldp_peer_get_lm(p, a, prefix); 402 if (!lma) 403 return LDP_E_NOENT; 404 405 SLIST_REMOVE(&p->label_mapping_head, lma, label_mapping, mappings); 406 free(lma); 407 408 return LDP_E_OK; 409 } 410 411 struct label_mapping * 412 ldp_peer_get_lm(struct ldp_peer * p, struct in_addr * a, int prefix) 413 { 414 struct label_mapping *rv; 415 416 if (!p) 417 return NULL; 418 419 SLIST_FOREACH(rv, &p->label_mapping_head, mappings) 420 if ((rv->prefix == prefix) && (!memcmp(a, &rv->address, 421 sizeof(struct in_addr)))) 422 break; 423 424 return rv; 425 426 } 427 428 int 429 ldp_peer_delete_all_mappings(struct ldp_peer * p) 430 { 431 struct label_mapping *lma; 432 433 while(!SLIST_EMPTY(&p->label_mapping_head)) { 434 lma = SLIST_FIRST(&p->label_mapping_head); 435 SLIST_REMOVE_HEAD(&p->label_mapping_head, mappings); 436 free(lma); 437 } 438 439 return LDP_E_OK; 440 } 441 442 /* returns a mapping and its peer */ 443 struct peer_map * 444 ldp_test_mapping(struct in_addr * a, int prefix, struct in_addr * gate) 445 { 446 struct ldp_peer *lpeer; 447 struct peer_map *rv = NULL; 448 struct label_mapping *lm = NULL; 449 450 /* Checks if it's LPDID, else checks if it's an interface */ 451 452 lpeer = get_ldp_peer(gate); 453 if (!lpeer) { 454 debugp("Gateway %s is not an LDP peer\n", inet_ntoa(*gate)); 455 return NULL; 456 } 457 if (lpeer->state != LDP_PEER_ESTABLISHED) { 458 warnp("ldp_test_mapping: peer is down ?!\n"); 459 return NULL; 460 } 461 lm = ldp_peer_get_lm(lpeer, a, prefix); 462 463 if (!lm) { 464 debugp("Cannot match that prefix to the specified peer\n"); 465 return NULL; 466 } 467 rv = malloc(sizeof(*rv)); 468 469 if (!rv) { 470 fatalp("ldp_test_mapping: malloc problem\n"); 471 return NULL; 472 } 473 474 rv->lm = lm; 475 rv->peer = lpeer; 476 477 return rv; 478 } 479 480 /* Name from state */ 481 const char * ldp_state_to_name(int state) 482 { 483 switch(state) { 484 case LDP_PEER_CONNECTING: 485 return "CONNECTING"; 486 case LDP_PEER_CONNECTED: 487 return "CONNECTED"; 488 case LDP_PEER_ESTABLISHED: 489 return "ESTABLISHED"; 490 case LDP_PEER_HOLDDOWN: 491 return "HOLDDOWN"; 492 } 493 return "UNKNOWN"; 494 } 495