l2vpn.c revision 1.20
1/* $OpenBSD: l2vpn.c,v 1.20 2016/07/01 23:33:46 renato Exp $ */ 2 3/* 4 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> 5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 6 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 7 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22#include <sys/types.h> 23#include <stdlib.h> 24#include <string.h> 25#include <limits.h> 26 27#include "ldpd.h" 28#include "ldpe.h" 29#include "lde.h" 30#include "log.h" 31 32static void l2vpn_pw_fec(struct l2vpn_pw *, struct fec *); 33 34struct l2vpn * 35l2vpn_new(const char *name) 36{ 37 struct l2vpn *l2vpn; 38 39 if ((l2vpn = calloc(1, sizeof(*l2vpn))) == NULL) 40 fatal("l2vpn_new: calloc"); 41 42 strlcpy(l2vpn->name, name, sizeof(l2vpn->name)); 43 44 /* set default values */ 45 l2vpn->mtu = DEFAULT_L2VPN_MTU; 46 l2vpn->pw_type = DEFAULT_PW_TYPE; 47 48 LIST_INIT(&l2vpn->if_list); 49 LIST_INIT(&l2vpn->pw_list); 50 51 return (l2vpn); 52} 53 54struct l2vpn * 55l2vpn_find(struct ldpd_conf *xconf, const char *name) 56{ 57 struct l2vpn *l2vpn; 58 59 LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) 60 if (strcmp(l2vpn->name, name) == 0) 61 return (l2vpn); 62 63 return (NULL); 64} 65 66void 67l2vpn_del(struct l2vpn *l2vpn) 68{ 69 struct l2vpn_if *lif; 70 struct l2vpn_pw *pw; 71 72 while ((lif = LIST_FIRST(&l2vpn->if_list)) != NULL) { 73 LIST_REMOVE(lif, entry); 74 free(lif); 75 } 76 while ((pw = LIST_FIRST(&l2vpn->pw_list)) != NULL) { 77 LIST_REMOVE(pw, entry); 78 free(pw); 79 } 80 81 free(l2vpn); 82} 83 84void 85l2vpn_init(struct l2vpn *l2vpn) 86{ 87 struct l2vpn_pw *pw; 88 89 LIST_FOREACH(pw, &l2vpn->pw_list, entry) 90 l2vpn_pw_init(pw); 91} 92 93void 94l2vpn_exit(struct l2vpn *l2vpn) 95{ 96 struct l2vpn_pw *pw; 97 98 LIST_FOREACH(pw, &l2vpn->pw_list, entry) 99 l2vpn_pw_exit(pw); 100} 101 102struct l2vpn_if * 103l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif) 104{ 105 struct l2vpn_if *lif; 106 107 if ((lif = calloc(1, sizeof(*lif))) == NULL) 108 fatal("l2vpn_if_new: calloc"); 109 110 lif->l2vpn = l2vpn; 111 strlcpy(lif->ifname, kif->ifname, sizeof(lif->ifname)); 112 lif->ifindex = kif->ifindex; 113 lif->flags = kif->flags; 114 lif->link_state = kif->link_state; 115 116 return (lif); 117} 118 119struct l2vpn_if * 120l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex) 121{ 122 struct l2vpn_if *lif; 123 124 LIST_FOREACH(lif, &l2vpn->if_list, entry) 125 if (lif->ifindex == ifindex) 126 return (lif); 127 128 return (NULL); 129} 130 131struct l2vpn_pw * 132l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif) 133{ 134 struct l2vpn_pw *pw; 135 136 if ((pw = calloc(1, sizeof(*pw))) == NULL) 137 fatal("l2vpn_pw_new: calloc"); 138 139 pw->l2vpn = l2vpn; 140 strlcpy(pw->ifname, kif->ifname, sizeof(pw->ifname)); 141 pw->ifindex = kif->ifindex; 142 143 return (pw); 144} 145 146struct l2vpn_pw * 147l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex) 148{ 149 struct l2vpn_pw *pw; 150 151 LIST_FOREACH(pw, &l2vpn->pw_list, entry) 152 if (pw->ifindex == ifindex) 153 return (pw); 154 155 return (NULL); 156} 157 158void 159l2vpn_pw_init(struct l2vpn_pw *pw) 160{ 161 struct fec fec; 162 163 l2vpn_pw_reset(pw); 164 165 l2vpn_pw_fec(pw, &fec); 166 lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 167 0, (void *)pw); 168} 169 170void 171l2vpn_pw_exit(struct l2vpn_pw *pw) 172{ 173 struct fec fec; 174 175 l2vpn_pw_fec(pw, &fec); 176 lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0); 177} 178 179static void 180l2vpn_pw_fec(struct l2vpn_pw *pw, struct fec *fec) 181{ 182 memset(fec, 0, sizeof(*fec)); 183 fec->type = FEC_TYPE_PWID; 184 fec->u.pwid.type = pw->l2vpn->pw_type; 185 fec->u.pwid.pwid = pw->pwid; 186 fec->u.pwid.lsr_id = pw->lsr_id; 187} 188 189void 190l2vpn_pw_reset(struct l2vpn_pw *pw) 191{ 192 pw->remote_group = 0; 193 pw->remote_mtu = 0; 194 pw->remote_status = 0; 195 196 if (pw->flags & F_PW_CWORD_CONF) 197 pw->flags |= F_PW_CWORD; 198 else 199 pw->flags &= ~F_PW_CWORD; 200 201 if (pw->flags & F_PW_STATUSTLV_CONF) 202 pw->flags |= F_PW_STATUSTLV; 203 else 204 pw->flags &= ~F_PW_STATUSTLV; 205} 206 207int 208l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh) 209{ 210 struct fec fec; 211 struct fec_node *fn; 212 213 /* check for a remote label */ 214 if (fnh->remote_label == NO_LABEL) 215 return (0); 216 217 /* MTUs must match */ 218 if (pw->l2vpn->mtu != pw->remote_mtu) 219 return (0); 220 221 /* check pw status if applicable */ 222 if ((pw->flags & F_PW_STATUSTLV) && 223 pw->remote_status != PW_FORWARDING) 224 return (0); 225 226 /* check for a working lsp to the nexthop */ 227 memset(&fec, 0, sizeof(fec)); 228 switch (pw->af) { 229 case AF_INET: 230 fec.type = FEC_TYPE_IPV4; 231 fec.u.ipv4.prefix = pw->addr.v4; 232 fec.u.ipv4.prefixlen = 32; 233 break; 234 case AF_INET6: 235 fec.type = FEC_TYPE_IPV6; 236 fec.u.ipv6.prefix = pw->addr.v6; 237 fec.u.ipv6.prefixlen = 128; 238 break; 239 default: 240 fatalx("l2vpn_pw_ok: unknown af"); 241 } 242 243 fn = (struct fec_node *)fec_find(&ft, &fec); 244 if (fn == NULL || fn->local_label == NO_LABEL) 245 return (0); 246 /* 247 * Need to ensure that there's a label binding for all nexthops. 248 * Otherwise, ECMP for this route could render the pseudowire unusable. 249 */ 250 LIST_FOREACH(fnh, &fn->nexthops, entry) 251 if (fnh->remote_label == NO_LABEL) 252 return (0); 253 254 return (1); 255} 256 257int 258l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map) 259{ 260 struct l2vpn_pw *pw; 261 struct status_tlv status; 262 263 /* NOTE: thanks martini & friends for all this mess */ 264 265 pw = (struct l2vpn_pw *) fn->data; 266 if (pw == NULL) 267 /* 268 * pseudowire not configured, return and record 269 * the mapping later 270 */ 271 return (0); 272 273 /* RFC4447 - Section 6.2: control word negotiation */ 274 if (fec_find(&ln->sent_map, &fn->fec)) { 275 if ((map->flags & F_MAP_PW_CWORD) && 276 !(pw->flags & F_PW_CWORD_CONF)) { 277 /* ignore the received label mapping */ 278 return (1); 279 } else if (!(map->flags & F_MAP_PW_CWORD) && 280 (pw->flags & F_PW_CWORD_CONF)) { 281 /* append a "Wrong C-bit" status code */ 282 status.status_code = S_WRONG_CBIT; 283 status.msg_id = map->messageid; 284 status.msg_type = htons(MSG_TYPE_LABELMAPPING); 285 lde_send_labelwithdraw(ln, fn, NO_LABEL, &status); 286 287 pw->flags &= ~F_PW_CWORD; 288 lde_send_labelmapping(ln, fn, 1); 289 } 290 } else if (map->flags & F_MAP_PW_CWORD) { 291 if (pw->flags & F_PW_CWORD_CONF) 292 pw->flags |= F_PW_CWORD; 293 else 294 /* act as if no label mapping had been received */ 295 return (1); 296 } else 297 pw->flags &= ~F_PW_CWORD; 298 299 /* RFC4447 - Section 5.4.3: pseudowire status negotiation */ 300 if (fec_find(&ln->recv_map, &fn->fec) == NULL && 301 !(map->flags & F_MAP_PW_STATUS)) 302 pw->flags &= ~F_PW_STATUSTLV; 303 304 return (0); 305} 306 307void 308l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec) 309{ 310 struct notify_msg nm; 311 312 memset(&nm, 0, sizeof(nm)); 313 nm.status = S_PW_STATUS; 314 315 nm.pw_status = status; 316 nm.flags |= F_NOTIF_PW_STATUS; 317 318 lde_fec2map(fec, &nm.fec); 319 nm.flags |= F_NOTIF_FEC; 320 321 lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0, 322 &nm, sizeof(nm)); 323} 324 325void 326l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) 327{ 328 struct fec fec; 329 struct fec_node *fn; 330 struct fec_nh *fnh; 331 struct l2vpn_pw *pw; 332 333 /* TODO group wildcard */ 334 if (!(nm->fec.flags & F_MAP_PW_ID)) 335 return; 336 337 lde_map2fec(&nm->fec, ln->id, &fec); 338 fn = (struct fec_node *)fec_find(&ft, &fec); 339 if (fn == NULL) 340 /* unknown fec */ 341 return; 342 343 pw = (struct l2vpn_pw *) fn->data; 344 if (pw == NULL) 345 return; 346 347 fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, 0); 348 if (fnh == NULL) 349 return; 350 351 /* remote status didn't change */ 352 if (pw->remote_status == nm->pw_status) 353 return; 354 355 pw->remote_status = nm->pw_status; 356 357 if (l2vpn_pw_ok(pw, fnh)) 358 lde_send_change_klabel(fn, fnh); 359 else 360 lde_send_delete_klabel(fn, fnh); 361} 362 363void 364l2vpn_sync_pws(int af, union ldpd_addr *addr) 365{ 366 struct l2vpn *l2vpn; 367 struct l2vpn_pw *pw; 368 struct fec fec; 369 struct fec_node *fn; 370 struct fec_nh *fnh; 371 372 LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) { 373 LIST_FOREACH(pw, &l2vpn->pw_list, entry) { 374 if (af != pw->af || ldp_addrcmp(af, &pw->addr, addr)) 375 continue; 376 377 l2vpn_pw_fec(pw, &fec); 378 fn = (struct fec_node *)fec_find(&ft, &fec); 379 if (fn == NULL) 380 continue; 381 fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *) 382 &pw->lsr_id, 0); 383 if (fnh == NULL) 384 continue; 385 386 if (l2vpn_pw_ok(pw, fnh)) 387 lde_send_change_klabel(fn, fnh); 388 else 389 lde_send_delete_klabel(fn, fnh); 390 } 391 } 392} 393 394void 395l2vpn_pw_ctl(pid_t pid) 396{ 397 struct l2vpn *l2vpn; 398 struct l2vpn_pw *pw; 399 static struct ctl_pw pwctl; 400 401 LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) 402 LIST_FOREACH(pw, &l2vpn->pw_list, entry) { 403 memset(&pwctl, 0, sizeof(pwctl)); 404 strlcpy(pwctl.ifname, pw->ifname, 405 sizeof(pwctl.ifname)); 406 pwctl.pwid = pw->pwid; 407 pwctl.lsr_id = pw->lsr_id; 408 pwctl.status = pw->flags & F_PW_STATUS_UP; 409 410 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0, 411 pid, &pwctl, sizeof(pwctl)); 412 } 413} 414 415void 416l2vpn_binding_ctl(pid_t pid) 417{ 418 struct fec *f; 419 struct fec_node *fn; 420 struct lde_map *me; 421 struct l2vpn_pw *pw; 422 static struct ctl_pw pwctl; 423 424 RB_FOREACH(f, fec_tree, &ft) { 425 if (f->type != FEC_TYPE_PWID) 426 continue; 427 428 fn = (struct fec_node *)f; 429 if (fn->local_label == NO_LABEL && 430 LIST_EMPTY(&fn->downstream)) 431 continue; 432 433 memset(&pwctl, 0, sizeof(pwctl)); 434 pwctl.type = f->u.pwid.type; 435 pwctl.pwid = f->u.pwid.pwid; 436 pwctl.lsr_id = f->u.pwid.lsr_id; 437 438 pw = (struct l2vpn_pw *) fn->data; 439 if (pw) { 440 pwctl.local_label = fn->local_label; 441 pwctl.local_gid = 0; 442 pwctl.local_ifmtu = pw->l2vpn->mtu; 443 } else 444 pwctl.local_label = NO_LABEL; 445 446 LIST_FOREACH(me, &fn->downstream, entry) 447 if (f->u.pwid.lsr_id.s_addr == me->nexthop->id.s_addr) 448 break; 449 450 if (me) { 451 pwctl.remote_label = me->map.label; 452 pwctl.remote_gid = me->map.fec.pwid.group_id; 453 if (me->map.flags & F_MAP_PW_IFMTU) 454 pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu; 455 456 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING, 457 0, pid, &pwctl, sizeof(pwctl)); 458 } else if (pw) { 459 pwctl.remote_label = NO_LABEL; 460 461 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING, 462 0, pid, &pwctl, sizeof(pwctl)); 463 } 464 } 465} 466 467/* ldpe */ 468 469void 470ldpe_l2vpn_init(struct l2vpn *l2vpn) 471{ 472 struct l2vpn_pw *pw; 473 474 LIST_FOREACH(pw, &l2vpn->pw_list, entry) 475 ldpe_l2vpn_pw_init(pw); 476} 477 478void 479ldpe_l2vpn_exit(struct l2vpn *l2vpn) 480{ 481 struct l2vpn_pw *pw; 482 483 LIST_FOREACH(pw, &l2vpn->pw_list, entry) 484 ldpe_l2vpn_pw_exit(pw); 485} 486 487void 488ldpe_l2vpn_pw_init(struct l2vpn_pw *pw) 489{ 490 struct tnbr *tnbr; 491 492 tnbr = tnbr_find(leconf, pw->af, &pw->addr); 493 if (tnbr == NULL) { 494 tnbr = tnbr_new(leconf, pw->af, &pw->addr); 495 tnbr_update(tnbr); 496 LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry); 497 } 498 499 tnbr->pw_count++; 500} 501 502void 503ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw) 504{ 505 struct tnbr *tnbr; 506 507 tnbr = tnbr_find(leconf, pw->af, &pw->addr); 508 if (tnbr) { 509 tnbr->pw_count--; 510 tnbr_check(tnbr); 511 } 512} 513