lde_lib.c revision 1.22
1/* $OpenBSD: lde_lib.c,v 1.22 2010/06/30 01:47:11 claudio Exp $ */ 2 3/* 4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/types.h> 20#include <sys/ioctl.h> 21#include <sys/time.h> 22#include <sys/socket.h> 23#include <net/if.h> 24#include <net/if_types.h> 25#include <netinet/in.h> 26#include <netmpls/mpls.h> 27#include <arpa/inet.h> 28#include <ctype.h> 29#include <err.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <unistd.h> 33#include <string.h> 34#include <event.h> 35 36#include "ldpd.h" 37#include "ldp.h" 38#include "log.h" 39#include "lde.h" 40 41static int fec_compare(struct fec *, struct fec *); 42 43RB_PROTOTYPE(fec_tree, fec, entry, fec_compare) 44RB_GENERATE(fec_tree, fec, entry, fec_compare) 45 46extern struct ldpd_conf *ldeconf; 47 48struct fec_tree rt = RB_INITIALIZER(&rt); 49 50/* FEC tree fucntions */ 51void 52fec_init(struct fec_tree *fh) 53{ 54 RB_INIT(fh); 55} 56 57static int 58fec_compare(struct fec *a, struct fec *b) 59{ 60 if (ntohl(a->prefix.s_addr) < ntohl(b->prefix.s_addr)) 61 return (-1); 62 if (ntohl(a->prefix.s_addr) > ntohl(b->prefix.s_addr)) 63 return (1); 64 if (a->prefixlen < b->prefixlen) 65 return (-1); 66 if (a->prefixlen > b->prefixlen) 67 return (1); 68 69 return (0); 70} 71 72struct fec * 73fec_find_prefix(struct fec_tree *fh, in_addr_t prefix, u_int8_t prefixlen) 74{ 75 struct fec s; 76 77 s.prefix.s_addr = prefix; 78 s.prefixlen = prefixlen; 79 80 return (fec_find(fh, &s)); 81} 82 83struct fec * 84fec_find(struct fec_tree *fh, struct fec *f) 85{ 86 return (RB_FIND(fec_tree, fh, f)); 87} 88 89 90int 91fec_insert(struct fec_tree *fh, struct fec *f) 92{ 93 if (RB_INSERT(fec_tree, fh, f) != NULL) 94 return (-1); 95 return (0); 96} 97 98int 99fec_remove(struct fec_tree *fh, struct fec *f) 100{ 101 if (RB_REMOVE(fec_tree, fh, f) == NULL) { 102 log_warnx("fec_remove failed for %s/%u", 103 inet_ntoa(f->prefix), f->prefixlen); 104 return (-1); 105 } 106 return (0); 107} 108 109void 110fec_clear(struct fec_tree *fh, void (*free_cb)(void *)) 111{ 112 struct fec *f; 113 114 while ((f = RB_ROOT(fh)) != NULL) { 115 fec_remove(fh, f); 116 free_cb(f); 117 } 118} 119 120 121void 122rt_dump(pid_t pid) 123{ 124 struct fec *f; 125 struct rt_node *r; 126 static struct ctl_rt rtctl; 127 128 RB_FOREACH(f, fec_tree, &rt) { 129 r = (struct rt_node *)f; 130 rtctl.prefix.s_addr = r->fec.prefix.s_addr; 131 rtctl.prefixlen = r->fec.prefixlen; 132 rtctl.nexthop.s_addr = r->nexthop.s_addr; 133 rtctl.flags = r->flags; 134 rtctl.local_label = r->local_label; 135 rtctl.remote_label = r->remote_label; 136 137 if (!r->present) 138 rtctl.in_use = 0; 139 else 140 rtctl.in_use = 1; 141 142 if (rtctl.nexthop.s_addr == htonl(INADDR_LOOPBACK)) 143 rtctl.connected = 1; 144 else 145 rtctl.connected = 0; 146 147 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid, &rtctl, 148 sizeof(rtctl)); 149 } 150} 151 152void 153rt_snap(u_int32_t peerid) 154{ 155 struct fec *f; 156 struct rt_node *r; 157 struct map map; 158 159 bzero(&map, sizeof(map)); 160 RB_FOREACH(f, fec_tree, &rt) { 161 r = (struct rt_node *)f; 162 map.prefix = r->fec.prefix; 163 map.prefixlen = r->fec.prefixlen; 164 map.label = r->local_label; 165 166 lde_imsg_compose_ldpe(IMSG_MAPPING_ADD, peerid, 0, &map, 167 sizeof(map)); 168 } 169} 170 171void 172rt_clear(void) 173{ 174 fec_clear(&rt, free); 175} 176 177void 178lde_kernel_insert(struct kroute *kr) 179{ 180 struct rt_node *rn; 181 struct lde_nbr_address *addr; 182 struct lde_map *map; 183 184 log_debug("kernel add route %s/%u", inet_ntoa(kr->prefix), 185 kr->prefixlen); 186 187 rn = (struct rt_node *)fec_find_prefix(&rt, kr->prefix.s_addr, 188 kr->prefixlen); 189 if (rn == NULL) { 190 rn = calloc(1, sizeof(*rn)); 191 if (rn == NULL) 192 fatal("lde_insert"); 193 194 rn->fec.prefix.s_addr = kr->prefix.s_addr; 195 rn->fec.prefixlen = kr->prefixlen; 196 rn->remote_label = NO_LABEL; 197 rn->local_label = NO_LABEL; 198 LIST_INIT(&rn->upstream); 199 LIST_INIT(&rn->downstream); 200 201 if (fec_insert(&rt, &rn->fec)) 202 log_warnx("failed to add %s/%u to rt tree", 203 inet_ntoa(rn->fec.prefix), rn->fec.prefixlen); 204 } 205 206 if (rn->present) { 207 if (kr->nexthop.s_addr == rn->nexthop.s_addr) 208 return; 209 210 /* The nexthop has changed, change also the label associated 211 with prefix */ 212 rn->remote_label = NO_LABEL; 213 rn->nexthop.s_addr = kr->nexthop.s_addr; 214 215 if ((ldeconf->mode & MODE_RET_LIBERAL) == 0) { 216 /* XXX: we support just liberal retention for now */ 217 log_warnx("lde_kernel_insert: missing mode"); 218 return; 219 } 220 221 LIST_FOREACH(map, &rn->downstream, entry) { 222 addr = lde_address_find(map->nexthop, &rn->nexthop); 223 if (addr != NULL) { 224 rn->remote_label = map->label; 225 break; 226 } 227 } 228 229 log_debug("lde_kernel_insert: prefix %s%u, " 230 "changing label to %u", inet_ntoa(rn->fec.prefix), 231 rn->fec.prefixlen, map ? map->label : 0); 232 233 lde_send_change_klabel(rn); 234 return; 235 } 236 237 rn->present = 1; 238 rn->nexthop.s_addr = kr->nexthop.s_addr; 239 240 /* There is static assigned label for this route, record it in lib */ 241 if (kr->local_label != NO_LABEL) { 242 rn->local_label = kr->local_label; 243 return; 244 } 245 246 LIST_FOREACH(map, &rn->downstream, entry) { 247 addr = lde_address_find(map->nexthop, &rn->nexthop); 248 if (addr != NULL) { 249 rn->remote_label = map->label; 250 break; 251 } 252 } 253 254 if (rn->local_label == NO_LABEL) { 255 /* Directly connected route */ 256 if (kr->nexthop.s_addr == INADDR_ANY) { 257 rn->local_label = MPLS_LABEL_IMPLNULL; 258 rn->nexthop.s_addr = htonl(INADDR_LOOPBACK); 259 } else 260 rn->local_label = lde_assign_label(); 261 } 262 263 lde_send_insert_klabel(rn); 264 265 /* Redistribute the current mapping to every nbr */ 266 lde_nbr_do_mappings(rn); 267} 268 269void 270lde_kernel_remove(struct kroute *kr) 271{ 272 struct rt_node *rn; 273 struct lde_map *map; 274 struct lde_nbr *ln; 275 276 log_debug("kernel remove route %s/%u", inet_ntoa(kr->prefix), 277 kr->prefixlen); 278 279 rn = (struct rt_node *)fec_find_prefix(&rt, kr->prefix.s_addr, 280 kr->prefixlen); 281 if (rn == NULL) 282 return; 283 284 if (ldeconf->mode & MODE_RET_LIBERAL) { 285 ln = lde_find_address(rn->nexthop); 286 if (ln) { 287 map = calloc(1, sizeof(*map)); 288 if (map == NULL) 289 fatal("lde_kernel_remove"); 290 291 map->label = rn->remote_label; 292 map->fec = rn->fec; 293 map->nexthop = ln; 294 LIST_INSERT_HEAD(&rn->downstream, map, entry); 295 if (fec_insert(&ln->recv_map, &map->fec)) 296 log_warnx("failed to add %s/%u to recv map (1)", 297 inet_ntoa(map->fec.prefix), 298 map->fec.prefixlen); 299 } 300 } 301 302 rn->remote_label = NO_LABEL; 303 rn->nexthop.s_addr = INADDR_ANY; 304 rn->present = 0; 305} 306 307void 308lde_check_mapping(struct map *map, struct lde_nbr *ln) 309{ 310 struct rt_node *rn; 311 struct lde_nbr_address *addr; 312 struct lde_map *me; 313 314 log_debug("label mapping from nbr %s, FEC %s/%u, label %u", 315 inet_ntoa(ln->id), log_fec(map), map->label); 316 317 rn = (struct rt_node *)fec_find_prefix(&rt, map->prefix.s_addr, 318 map->prefixlen); 319 if (rn == NULL) { 320 /* The route is not yet in fib. If we are in liberal mode 321 * create a route and record the label */ 322 if (ldeconf->mode & MODE_RET_CONSERVATIVE) 323 return; 324 325 rn = calloc(1, sizeof(*rn)); 326 if (rn == NULL) 327 fatal("lde_check_mapping"); 328 329 rn->fec.prefix = map->prefix; 330 rn->fec.prefixlen = map->prefixlen; 331 rn->local_label = lde_assign_label(); 332 rn->remote_label = NO_LABEL; 333 rn->present = 0; 334 335 LIST_INIT(&rn->upstream); 336 LIST_INIT(&rn->downstream); 337 338 if (fec_insert(&rt, &rn->fec)) 339 log_warnx("failed to add %s/%u to rt tree", 340 inet_ntoa(rn->fec.prefix), rn->fec.prefixlen); 341 } 342 343 LIST_FOREACH(me, &rn->downstream, entry) { 344 if (ln == me->nexthop) { 345 if (me->label == map->label) { 346 /* Duplicate: RFC says to send back a release, 347 * even though we did not release the actual 348 * mapping. This is confusing. 349 */ 350 lde_send_labelrelease(ln->peerid, map); 351 return; 352 } 353 /* old mapping that is now changed */ 354 break; 355 } 356 } 357 358 addr = lde_address_find(ln, &rn->nexthop); 359 if (addr == NULL || !rn->present) { 360 /* route not yet available */ 361 if (ldeconf->mode & MODE_RET_CONSERVATIVE) { 362 lde_send_labelrelease(ln->peerid, map); 363 return; 364 } 365 /* in liberal mode just note the mapping */ 366 if (me == NULL) { 367 me = calloc(1, sizeof(*me)); 368 if (me == NULL) 369 fatal("lde_check_mapping"); 370 me->fec = rn->fec; 371 me->nexthop = ln; 372 373 LIST_INSERT_HEAD(&rn->downstream, me, entry); 374 if (fec_insert(&ln->recv_map, &me->fec)) 375 log_warnx("failed to add %s/%u to recv map (2)", 376 inet_ntoa(me->fec.prefix), 377 me->fec.prefixlen); 378 } 379 me->label = map->label; 380 381 return; 382 } 383 384 rn->remote_label = map->label; 385 386 /* If we are ingress for this LSP install the label */ 387 if (rn->nexthop.s_addr == INADDR_ANY) 388 lde_send_change_klabel(rn); 389 390 /* Record the mapping from this peer */ 391 if (me == NULL) { 392 me = calloc(1, sizeof(*me)); 393 if (me == NULL) 394 fatal("lde_check_mapping"); 395 396 me->fec = rn->fec; 397 me->nexthop = ln; 398 LIST_INSERT_HEAD(&rn->downstream, me, entry); 399 if (fec_insert(&ln->recv_map, &me->fec)) 400 log_warnx("failed to add %s/%u to recv map (3)", 401 inet_ntoa(me->fec.prefix), me->fec.prefixlen); 402 } 403 me->label = map->label; 404 405 lde_send_change_klabel(rn); 406 407 /* Redistribute the current mapping to every nbr */ 408 lde_nbr_do_mappings(rn); 409} 410 411void 412lde_check_request(struct map *map, struct lde_nbr *ln) 413{ 414 struct lde_req *lre; 415 struct rt_node *rn; 416 struct lde_nbr *lnn; 417 struct map localmap; 418 419 log_debug("label request from nbr %s, FEC %s", 420 inet_ntoa(ln->id), log_fec(map)); 421 422 rn = (struct rt_node *)fec_find_prefix(&rt, map->prefix.s_addr, 423 map->prefixlen); 424 if (rn == NULL || rn->remote_label == NO_LABEL) { 425 lde_send_notification(ln->peerid, S_NO_ROUTE, map->messageid, 426 MSG_TYPE_LABELREQUEST); 427 return; 428 } 429 430 if (lde_address_find(ln, &rn->nexthop)) { 431 lde_send_notification(ln->peerid, S_LOOP_DETECTED, 432 map->messageid, MSG_TYPE_LABELREQUEST); 433 return; 434 } 435 436 lre = (struct lde_req *)fec_find(&ln->recv_req, &rn->fec); 437 if (lre != NULL) 438 return; 439 440 if (rn->nexthop.s_addr == INADDR_ANY || 441 rn->remote_label != NO_LABEL) { 442 bzero(&localmap, sizeof(localmap)); 443 localmap.prefix = map->prefix; 444 localmap.prefixlen = map->prefixlen; 445 localmap.label = rn->local_label; 446 447 lde_send_labelmapping(ln->peerid, &localmap); 448 } else { 449 lnn = lde_find_address(rn->nexthop); 450 if (lnn == NULL) 451 /* XXX this feels wrong.... */ 452 return; 453 454 lde_send_labelrequest(lnn->peerid, map); 455 456 lre = calloc(1, sizeof(*lre)); 457 if (lre == NULL) 458 fatal("lde_check_request"); 459 460 lre->fec = rn->fec; 461 lre->msgid = map->messageid; 462 463 if (fec_insert(&ln->recv_req, &lre->fec)) 464 log_warnx("failed to add %s/%u to recv req", 465 inet_ntoa(lre->fec.prefix), lre->fec.prefixlen); 466 } 467} 468 469void 470lde_check_release(struct map *map, struct lde_nbr *ln) 471{ 472 log_debug("label mapping from nbr %s, FEC %s", 473 inet_ntoa(ln->id), log_fec(map)); 474 475 /* check withdraw list */ 476 /* check sent map list */ 477} 478