1 /* $OpenBSD: rde_mfc.c,v 1.8 2009/09/22 16:24:21 michele Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 5 * Copyright (c) 2006 Esben Norby <norby@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/socket.h> 22 #include <sys/tree.h> 23 #include <netinet/in.h> 24 #include <arpa/inet.h> 25 #include <err.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include "igmp.h" 30 #include "dvmrp.h" 31 #include "dvmrpd.h" 32 #include "log.h" 33 #include "dvmrpe.h" 34 #include "rde.h" 35 36 /* multicast forwarding cache */ 37 38 void mfc_send_prune(struct rt_node *, struct mfc_node *); 39 void mfc_add_prune(struct mfc_node *, struct prune *); 40 struct prune_node *mfc_find_prune(struct mfc_node *, struct prune *); 41 void mfc_delete_prune(struct mfc_node *, 42 struct prune_node *); 43 44 int prune_compare(struct mfc_node *, struct rt_node *, int); 45 void prune_expire_timer(int, short, void *); 46 int mfc_reset_prune_expire_timer(struct prune_node *); 47 48 49 void mfc_expire_timer(int, short, void *); 50 int mfc_start_expire_timer(struct mfc_node *); 51 int mfc_reset_expire_timer(struct mfc_node *); 52 void mfc_prune_timer(int, short, void *); 53 int mfc_start_prune_timer(struct mfc_node *); 54 int mfc_reset_prune_timer(struct mfc_node *); 55 56 int mfc_compare(struct mfc_node *, struct mfc_node *); 57 void mfc_invalidate(void); 58 59 RB_HEAD(mfc_tree, mfc_node) mfc; 60 RB_PROTOTYPE(mfc_tree, mfc_node, entry, mfc_compare) 61 RB_GENERATE(mfc_tree, mfc_node, entry, mfc_compare) 62 63 extern struct dvmrpd_conf *rdeconf; 64 65 /* timers */ 66 void 67 mfc_expire_timer(int fd, short event, void *arg) 68 { 69 struct mfc_node *mn = arg; 70 struct mfc nmfc; 71 72 log_debug("mfc_expire_timer: group %s", inet_ntoa(mn->group)); 73 74 /* remove route entry */ 75 nmfc.origin = mn->origin; 76 nmfc.group = mn->group; 77 rde_imsg_compose_parent(IMSG_MFC_DEL, 0, &nmfc, sizeof(nmfc)); 78 79 event_del(&mn->expiration_timer); 80 mfc_remove(mn); 81 } 82 83 int 84 mfc_reset_expire_timer(struct mfc_node *mn) 85 { 86 struct timeval tv; 87 88 timerclear(&tv); 89 tv.tv_sec = ROUTE_EXPIRATION_TIME; 90 return (evtimer_add(&mn->expiration_timer, &tv)); 91 } 92 93 int 94 mfc_start_expire_timer(struct mfc_node *mn) 95 { 96 struct timeval tv; 97 98 log_debug("mfc_start_expire_timer: group %s", inet_ntoa(mn->group)); 99 100 timerclear(&tv); 101 tv.tv_sec = ROUTE_EXPIRATION_TIME; 102 return (evtimer_add(&mn->expiration_timer, &tv)); 103 } 104 105 void 106 mfc_prune_timer(int fd, short event, void *arg) 107 { 108 struct mfc_node *mn = arg; 109 110 log_debug("mfc_prune_timer: group %s", inet_ntoa(mn->group)); 111 112 event_del(&mn->prune_timer); 113 } 114 115 int 116 mfc_start_prune_timer(struct mfc_node *mn) 117 { 118 struct timeval tv; 119 120 log_debug("mfc_start_prune_timer: group %s", inet_ntoa(mn->group)); 121 122 timerclear(&tv); 123 tv.tv_sec = MAX_PRUNE_LIFETIME; 124 return (evtimer_add(&mn->prune_timer, &tv)); 125 } 126 127 int 128 mfc_reset_prune_timer(struct mfc_node *mn) 129 { 130 struct timeval tv; 131 132 timerclear(&tv); 133 tv.tv_sec = MAX_PRUNE_LIFETIME; 134 return (evtimer_add(&mn->prune_timer, &tv)); 135 } 136 137 /* route table */ 138 void 139 mfc_init(void) 140 { 141 RB_INIT(&mfc); 142 } 143 144 int 145 mfc_compare(struct mfc_node *a, struct mfc_node *b) 146 { 147 if (ntohl(a->origin.s_addr) < ntohl(b->origin.s_addr)) 148 return (-1); 149 if (ntohl(a->origin.s_addr) > ntohl(b->origin.s_addr)) 150 return (1); 151 if (ntohl(a->group.s_addr) < ntohl(b->group.s_addr)) 152 return (-1); 153 if (ntohl(a->group.s_addr) > ntohl(b->group.s_addr)) 154 return (1); 155 return (0); 156 } 157 158 struct mfc_node * 159 mfc_find(in_addr_t origin, in_addr_t group) 160 { 161 struct mfc_node s; 162 163 s.origin.s_addr = origin; 164 s.group.s_addr = group; 165 166 return (RB_FIND(mfc_tree, &mfc, &s)); 167 } 168 169 int 170 mfc_insert(struct mfc_node *m) 171 { 172 if (RB_INSERT(mfc_tree, &mfc, m) != NULL) { 173 log_warnx("mfc_insert failed for group %s", 174 inet_ntoa(m->group)); 175 free(m); 176 return (-1); 177 } 178 179 return (0); 180 } 181 182 int 183 mfc_remove(struct mfc_node *m) 184 { 185 if (RB_REMOVE(mfc_tree, &mfc, m) == NULL) { 186 log_warnx("mfc_remove failed for group %s", 187 inet_ntoa(m->group)); 188 return (-1); 189 } 190 191 free(m); 192 return (0); 193 } 194 195 void 196 mfc_clear(void) 197 { 198 struct mfc_node *m; 199 200 while ((m = RB_MIN(mfc_tree, &mfc)) != NULL) 201 mfc_remove(m); 202 } 203 204 void 205 mfc_dump(pid_t pid) 206 { 207 static struct ctl_mfc mfcctl; 208 struct timespec now; 209 struct timeval tv, now2, res; 210 struct mfc_node *mn; 211 int i; 212 213 clock_gettime(CLOCK_MONOTONIC, &now); 214 215 RB_FOREACH(mn, mfc_tree, &mfc) { 216 mfcctl.origin.s_addr = mn->origin.s_addr; 217 mfcctl.group.s_addr = mn->group.s_addr; 218 mfcctl.uptime = now.tv_sec - mn->uptime; 219 mfcctl.ifindex = mn->ifindex; 220 221 for (i = 0; i < MAXVIFS; i ++) { 222 mfcctl.ttls[i] = mn->ttls[i]; 223 } 224 225 gettimeofday(&now2, NULL); 226 if (evtimer_pending(&mn->expiration_timer, &tv)) { 227 timersub(&tv, &now2, &res); 228 mfcctl.expire = res.tv_sec; 229 } else 230 mfcctl.expire = -1; 231 232 rde_imsg_compose_dvmrpe(IMSG_CTL_SHOW_MFC, 0, pid, &mfcctl, 233 sizeof(mfcctl)); 234 } 235 } 236 237 struct rt_node * 238 mfc_find_origin(struct in_addr group) 239 { 240 struct mfc_node *mn; 241 242 RB_FOREACH(mn, mfc_tree, &mfc) 243 if (group.s_addr == mn->group.s_addr) 244 return (rt_match_origin(mn->origin.s_addr)); 245 246 return (NULL); 247 } 248 249 void 250 mfc_send_prune(struct rt_node *rn, struct mfc_node *mn) 251 { 252 struct prune p; 253 254 bzero(&p, sizeof(p)); 255 256 p.origin.s_addr = (mn->origin.s_addr & 257 htonl(prefixlen2mask(rn->prefixlen))); 258 p.netmask.s_addr = htonl(prefixlen2mask(rn->prefixlen)); 259 p.group.s_addr = mn->group.s_addr; 260 p.nexthop.s_addr = rn->nexthop.s_addr; 261 p.ifindex = mn->ifindex; 262 263 rde_imsg_compose_dvmrpe(IMSG_SEND_PRUNE, 0, 0, &p, sizeof(p)); 264 265 mfc_start_prune_timer(mn); 266 } 267 268 void 269 mfc_update_source(struct rt_node *rn) 270 { 271 struct mfc_node *mn; 272 struct mfc m; 273 int i; 274 u_int8_t found; 275 276 RB_FOREACH(mn, mfc_tree, &mfc) { 277 if (rn->prefix.s_addr == (mn->origin.s_addr & 278 htonl(prefixlen2mask(rn->prefixlen)))) { 279 mn->ifindex = rn->ifindex; 280 281 found = 0; 282 283 for (i = 0; i < MAXVIFS; i++) { 284 mn->ttls[i] = rn->ttls[i]; 285 if (mn->ttls[i] != 0) 286 found = 1; 287 } 288 289 m.origin.s_addr = mn->origin.s_addr; 290 m.group.s_addr = mn->group.s_addr; 291 m.ifindex = mn->ifindex; 292 293 for (i = 0; i < MAXVIFS; i++) 294 m.ttls[i] = mn->ttls[i]; 295 296 rde_imsg_compose_parent(IMSG_MFC_ADD, 0, &m, sizeof(m)); 297 298 mfc_reset_expire_timer(mn); 299 300 if (!found && !rn->connected) 301 mfc_send_prune(rn, mn); 302 } 303 } 304 } 305 306 void 307 mfc_update(struct mfc *nmfc) 308 { 309 struct mfc_node *mn; 310 struct rt_node *rn; 311 struct timespec now; 312 int i; 313 u_int8_t found = 0; 314 315 clock_gettime(CLOCK_MONOTONIC, &now); 316 317 if ((mn = mfc_find(nmfc->origin.s_addr, nmfc->group.s_addr)) == NULL) { 318 if ((mn = calloc(1, sizeof(struct mfc_node))) == NULL) 319 fatalx("mfc_update"); 320 321 mn->origin.s_addr = nmfc->origin.s_addr; 322 mn->group.s_addr = nmfc->group.s_addr; 323 mn->ifindex = nmfc->ifindex; 324 mn->uptime = now.tv_sec; 325 for (i = 0; i < MAXVIFS; i++) { 326 mn->ttls[i] = nmfc->ttls[i]; 327 if (mn->ttls[i] != 0) 328 found = 1; 329 } 330 331 if (mfc_insert(mn) == 0) { 332 rde_imsg_compose_parent(IMSG_MFC_ADD, 0, nmfc, 333 sizeof(*nmfc)); 334 } 335 336 evtimer_set(&mn->expiration_timer, mfc_expire_timer, mn); 337 evtimer_set(&mn->prune_timer, mfc_expire_timer, mn); 338 mfc_start_expire_timer(mn); 339 340 if (!found) { 341 /* We removed all downstream interfaces, 342 start the pruning process */ 343 rn = rt_match_origin(mn->origin.s_addr); 344 if (rn == NULL) { 345 fatal("mfc_update: cannot find information " 346 " about source"); 347 } 348 349 mfc_send_prune(rn, mn); 350 } 351 } 352 } 353 354 void 355 mfc_delete(struct mfc *nmfc) 356 { 357 struct mfc_node *mn; 358 359 if ((mn = mfc_find(nmfc->origin.s_addr, nmfc->group.s_addr)) == NULL) 360 return; 361 362 /* XXX decide if it should really be removed */ 363 mfc_remove(mn); 364 365 /* XXX notify parent */ 366 } 367 368 int 369 mfc_check_members(struct rt_node *rn, struct iface *iface) 370 { 371 struct mfc_node *mn; 372 373 RB_FOREACH(mn, mfc_tree, &mfc) { 374 if (mn->origin.s_addr == rn->prefix.s_addr) { 375 if (rde_group_list_find(iface, mn->group) 376 != NULL) 377 return (1); 378 } 379 } 380 381 return (0); 382 } 383 384 void 385 mfc_recv_prune(struct prune *p) 386 { 387 struct rt_node *rn; 388 struct mfc_node *mn; 389 struct prune_node *pn; 390 struct iface *iface; 391 struct mfc m; 392 393 iface = if_find_index(p->ifindex); 394 if (iface == NULL) { 395 log_debug("mfc_recv_prune: unknown interface"); 396 return; 397 } 398 399 rn = rt_match_origin(p->origin.s_addr); 400 if (rn == NULL) { 401 log_debug("mfc_recv_prune: no information for %s\n", 402 inet_ntoa(p->origin)); 403 return; 404 } 405 406 if (srt_find_ds(rn, p->nexthop.s_addr) == NULL) { 407 log_debug("mfc_recv_prune: prune received from a " 408 "non downstream neighbor\n"); 409 return; 410 } 411 412 mn = mfc_find(p->origin.s_addr, p->group.s_addr); 413 if (mn) { 414 log_debug("mfc_recv_prune: no information for %s\n", 415 inet_ntoa(p->origin)); 416 return; 417 } 418 419 pn = mfc_find_prune(mn, p); 420 if (pn == NULL) { 421 mfc_add_prune(mn, p); 422 if (prune_compare(mn, rn, p->ifindex) && 423 !rde_group_list_find(iface, p->group)) { 424 mn->ttls[p->ifindex] = 0; 425 426 m.ifindex = p->ifindex; 427 m.origin.s_addr = p->origin.s_addr; 428 m.group.s_addr = p->group.s_addr; 429 mfc_update(&m); 430 } 431 } else 432 mfc_reset_prune_expire_timer(pn); 433 } 434 435 void 436 mfc_add_prune(struct mfc_node *mn, struct prune *p) 437 { 438 struct prune_node *pn; 439 struct timeval tv; 440 441 pn = calloc(1, sizeof(struct prune)); 442 if (pn == NULL) 443 fatal("prune_add"); 444 445 timerclear(&tv); 446 tv.tv_sec = MAX_PRUNE_LIFETIME; 447 448 pn->nbr.s_addr = p->nexthop.s_addr; 449 pn->ifindex = p->ifindex; 450 pn->parent = mn; 451 452 evtimer_set(&pn->lifetime_timer, prune_expire_timer, pn); 453 evtimer_add(&pn->lifetime_timer, &tv); 454 455 LIST_INSERT_HEAD(&mn->prune_list, pn, entry); 456 457 mn->prune_cnt[p->ifindex]++; 458 } 459 460 struct prune_node * 461 mfc_find_prune(struct mfc_node *mn, struct prune *p) 462 { 463 struct prune_node *pn; 464 465 LIST_FOREACH(pn, &mn->prune_list, entry) { 466 if (p->nexthop.s_addr == pn->nbr.s_addr) 467 return (pn); 468 } 469 470 return (NULL); 471 } 472 473 void 474 mfc_delete_prune(struct mfc_node *mn, struct prune_node *pn) 475 { 476 unsigned int ifindex = pn->ifindex; 477 478 if (evtimer_pending(&pn->lifetime_timer, NULL)) 479 if (evtimer_del(&pn->lifetime_timer) == -1) 480 fatal("mfc_delete_prune"); 481 482 LIST_REMOVE(pn, entry); 483 free(pn); 484 mn->prune_cnt[ifindex]--; 485 } 486 487 int 488 prune_compare(struct mfc_node *mn, struct rt_node *rn, int ifindex) 489 { 490 if (mn->prune_cnt[ifindex] == rn->ds_cnt[ifindex]) 491 return (1); 492 493 return (0); 494 } 495 496 int 497 mfc_reset_prune_expire_timer(struct prune_node *pn) 498 { 499 struct timeval tv; 500 501 timerclear(&tv); 502 tv.tv_sec = MAX_PRUNE_LIFETIME; 503 504 return (evtimer_add(&pn->lifetime_timer, &tv)); 505 } 506 507 void 508 prune_expire_timer(int fd, short event, void *arg) 509 { 510 struct prune_node *pn = arg; 511 512 LIST_REMOVE(pn, entry); 513 514 pn->parent->prune_cnt[pn->ifindex]--; 515 pn->parent->ttls[pn->ifindex] = 1; 516 517 free(pn); 518 } 519