l2vpn.c revision 1.1
1/* $OpenBSD: l2vpn.c,v 1.1 2015/07/21 04:52:29 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 <sys/socket.h> 24#include <arpa/inet.h> 25 26#include <err.h> 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30 31#include "ldpd.h" 32#include "lde.h" 33#include "ldpe.h" 34#include "control.h" 35#include "log.h" 36 37RB_PROTOTYPE(fec_tree, fec, entry, fec_compare) 38extern struct fec_tree ft; 39 40extern struct ldpd_conf *ldeconf; 41extern struct ldpd_conf *leconf; 42 43struct l2vpn * 44l2vpn_new(const char *name) 45{ 46 struct l2vpn *l2vpn; 47 48 if ((l2vpn = calloc(1, sizeof(*l2vpn))) == NULL) 49 err(1, "l2vpn_new: calloc"); 50 51 strlcpy(l2vpn->name, name, sizeof(l2vpn->name)); 52 53 /* set default values */ 54 l2vpn->mtu = DEFAULT_L2VPN_MTU; 55 l2vpn->pw_type = PW_TYPE_ETHERNET; 56 57 return (l2vpn); 58} 59 60struct l2vpn * 61l2vpn_find(struct ldpd_conf *xconf, char *name) 62{ 63 struct l2vpn *l2vpn; 64 65 LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) 66 if (strcmp(l2vpn->name, name) == 0) 67 return (l2vpn); 68 69 return (NULL); 70} 71 72void 73l2vpn_del(struct l2vpn *l2vpn) 74{ 75 struct l2vpn_if *lif; 76 struct l2vpn_pw *pw; 77 78 while ((lif = LIST_FIRST(&l2vpn->if_list)) != NULL) { 79 LIST_REMOVE(lif, entry); 80 l2vpn_if_del(lif); 81 } 82 while ((pw = LIST_FIRST(&l2vpn->pw_list)) != NULL) { 83 LIST_REMOVE(pw, entry); 84 l2vpn_pw_del(pw); 85 } 86 87 free(l2vpn); 88} 89 90void 91l2vpn_init(struct l2vpn *l2vpn) 92{ 93 struct l2vpn_pw *pw; 94 95 LIST_FOREACH(pw, &l2vpn->pw_list, entry) 96 l2vpn_pw_init(pw); 97} 98 99struct l2vpn_if * 100l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif) 101{ 102 struct l2vpn_if *lif; 103 104 if ((lif = calloc(1, sizeof(*lif))) == NULL) 105 err(1, "l2vpn_if_new: calloc"); 106 107 lif->l2vpn = l2vpn; 108 strlcpy(lif->ifname, kif->ifname, sizeof(lif->ifname)); 109 lif->ifindex = kif->ifindex; 110 lif->flags = kif->flags; 111 lif->link_state = kif->link_state; 112 113 return (lif); 114} 115 116struct l2vpn_if * 117l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex) 118{ 119 struct l2vpn_if *lif; 120 121 LIST_FOREACH(lif, &l2vpn->if_list, entry) 122 if (lif->ifindex == ifindex) 123 return (lif); 124 125 return (NULL); 126} 127 128void 129l2vpn_if_del(struct l2vpn_if *lif) 130{ 131 free(lif); 132} 133 134struct l2vpn_pw * 135l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif) 136{ 137 struct l2vpn_pw *pw; 138 139 if ((pw = calloc(1, sizeof(*pw))) == NULL) 140 err(1, "l2vpn_pw_new: calloc"); 141 142 pw->l2vpn = l2vpn; 143 strlcpy(pw->ifname, kif->ifname, sizeof(pw->ifname)); 144 pw->ifindex = kif->ifindex; 145 146 return (pw); 147} 148 149struct l2vpn_pw * 150l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex) 151{ 152 struct l2vpn_pw *pw; 153 154 LIST_FOREACH(pw, &l2vpn->pw_list, entry) 155 if (pw->ifindex == ifindex) 156 return (pw); 157 158 return (NULL); 159} 160 161void 162l2vpn_pw_del(struct l2vpn_pw *pw) 163{ 164 struct fec fec; 165 166 if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY) 167 return; 168 169 l2vpn_pw_fec(pw, &fec); 170 lde_kernel_remove(&fec, pw->addr); 171 free(pw); 172} 173 174void 175l2vpn_pw_init(struct l2vpn_pw *pw) 176{ 177 struct fec fec; 178 179 if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY) 180 return; 181 182 l2vpn_pw_fec(pw, &fec); 183 lde_kernel_insert(&fec, pw->addr, 0, (void *)pw); 184} 185 186void 187l2vpn_pw_fec(struct l2vpn_pw *pw, struct fec *fec) 188{ 189 bzero(fec, sizeof(*fec)); 190 fec->type = FEC_TYPE_PWID; 191 fec->u.pwid.type = pw->l2vpn->pw_type; 192 fec->u.pwid.pwid = pw->pwid; 193 fec->u.pwid.nexthop.s_addr = pw->addr.s_addr; 194} 195 196void 197l2vpn_pw_reset(struct l2vpn_pw *pw) 198{ 199 pw->remote_group = 0; 200 pw->remote_mtu = 0; 201 if (!(pw->flags & F_PW_CONTROLWORD_CONF)) 202 pw->flags &= ~F_PW_CONTROLWORD; 203 if (!(pw->flags & F_PW_STATUSTLV_CONF)) 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 bzero(&fec, sizeof(fec)); 228 fec.type = FEC_TYPE_IPV4; 229 fec.u.ipv4.prefix.s_addr = pw->addr.s_addr; 230 fec.u.ipv4.prefixlen = 32; 231 fn = (struct fec_node *)fec_find(&ft, &fec); 232 if (fn == NULL) 233 return (0); 234 LIST_FOREACH(fnh, &fn->nexthops, entry) 235 if (fnh->remote_label == NO_LABEL) 236 return (0); 237 238 return (1); 239} 240 241int 242l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map) 243{ 244 struct fec_nh *fnh; 245 struct l2vpn_pw *pw; 246 247 /* NOTE: thanks martini & friends for all this mess */ 248 249 fnh = fec_nh_find(fn, ln->id); 250 if (fnh == NULL) 251 /* 252 * pseudowire not configured, return and record 253 * the mapping later 254 */ 255 return (0); 256 pw = (struct l2vpn_pw *) fnh->data; 257 258 l2vpn_pw_reset(pw); 259 260 /* RFC4447 - Section 6.2: control word negotiation */ 261 if (fec_find(&ln->sent_map, &fn->fec)) { 262 if ((map->flags & F_MAP_PW_CWORD) && 263 !(pw->flags & F_PW_CONTROLWORD_CONF)) { 264 /* ignore the received label mapping */ 265 return (1); 266 } else if (!(map->flags & F_MAP_PW_CWORD) && 267 (pw->flags & F_PW_CONTROLWORD_CONF)) { 268 /* TODO append a "Wrong C-bit" status code */ 269 lde_send_labelwithdraw(ln, fn); 270 271 pw->flags &= ~F_PW_CONTROLWORD; 272 lde_send_labelmapping(ln, fn, 1); 273 } 274 } else if (map->flags & F_MAP_PW_CWORD) { 275 if (pw->flags & F_PW_CONTROLWORD_CONF) 276 pw->flags |= F_PW_CONTROLWORD; 277 else 278 /* act as if no label mapping had been received */ 279 return (1); 280 } else 281 pw->flags &= ~F_PW_CONTROLWORD; 282 283 /* RFC4447 - Section 5.4.3: pseudowire status negotiation */ 284 if (fec_find(&ln->recv_map, &fn->fec) == NULL && 285 !(map->flags & F_MAP_PW_STATUS)) 286 pw->flags &= ~F_PW_STATUSTLV; 287 288 return (0); 289} 290 291void 292l2vpn_send_pw_status(u_int32_t peerid, u_int32_t status, struct fec *fec) 293{ 294 struct notify_msg nm; 295 296 bzero(&nm, sizeof(nm)); 297 nm.status = S_PW_STATUS; 298 299 nm.pw_status = status; 300 nm.flags |= F_NOTIF_PW_STATUS; 301 302 lde_fec2map(fec, &nm.fec); 303 nm.flags |= F_NOTIF_FEC; 304 305 lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0, 306 &nm, sizeof(nm)); 307} 308 309void 310l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) 311{ 312 struct fec fec; 313 struct fec_node *fn; 314 struct fec_nh *fnh; 315 struct l2vpn_pw *pw; 316 317 /* TODO group wildcard */ 318 if (!(nm->fec.flags & F_MAP_PW_ID)) 319 return; 320 321 lde_map2fec(&nm->fec, ln->id, &fec); 322 fn = (struct fec_node *)fec_find(&ft, &fec); 323 if (fn == NULL) 324 /* unknown fec */ 325 return; 326 327 fnh = fec_nh_find(fn, ln->id); 328 if (fnh == NULL) 329 return; 330 pw = (struct l2vpn_pw *) fnh->data; 331 332 /* remote status didn't change */ 333 if (pw->remote_status == nm->pw_status) 334 return; 335 336 pw->remote_status = nm->pw_status; 337 338 if (l2vpn_pw_ok(pw, fnh)) 339 lde_send_change_klabel(fn, fnh); 340 else 341 lde_send_delete_klabel(fn, fnh); 342} 343 344void 345l2vpn_sync_pws(struct in_addr addr) 346{ 347 struct l2vpn *l2vpn; 348 struct l2vpn_pw *pw; 349 struct fec fec; 350 struct fec_node *fn; 351 struct fec_nh *fnh; 352 353 LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) { 354 LIST_FOREACH(pw, &l2vpn->pw_list, entry) { 355 if (pw->addr.s_addr == addr.s_addr) { 356 l2vpn_pw_fec(pw, &fec); 357 fn = (struct fec_node *)fec_find(&ft, &fec); 358 if (fn == NULL) 359 continue; 360 fnh = fec_nh_find(fn, pw->addr); 361 if (fnh == NULL) 362 continue; 363 364 if (l2vpn_pw_ok(pw, fnh)) 365 lde_send_change_klabel(fn, fnh); 366 else 367 lde_send_delete_klabel(fn, fnh); 368 } 369 } 370 } 371} 372 373void 374l2vpn_pw_ctl(pid_t pid) 375{ 376 struct l2vpn *l2vpn; 377 struct l2vpn_pw *pw; 378 static struct ctl_pw pwctl; 379 380 LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) 381 LIST_FOREACH(pw, &l2vpn->pw_list, entry) { 382 bzero(&pwctl, sizeof(pwctl)); 383 strlcpy(pwctl.ifname, pw->ifname, 384 sizeof(pwctl.ifname)); 385 pwctl.pwid = pw->pwid; 386 pwctl.nexthop.s_addr = pw->addr.s_addr; 387 pwctl.status = pw->flags & F_PW_STATUS_UP; 388 389 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_PW, 0, 390 pid, &pwctl, sizeof(pwctl)); 391 } 392} 393 394void 395l2vpn_binding_ctl(pid_t pid) 396{ 397 struct fec *f; 398 struct fec_node *fn; 399 struct lde_map *me; 400 struct fec_nh *fnh; 401 struct l2vpn_pw *pw; 402 static struct ctl_pw pwctl; 403 404 RB_FOREACH(f, fec_tree, &ft) { 405 if (f->type != FEC_TYPE_PWID) 406 continue; 407 408 fn = (struct fec_node *)f; 409 if (fn->local_label == NO_LABEL && 410 LIST_EMPTY(&fn->downstream)) 411 continue; 412 413 fnh = fec_nh_find(fn, f->u.pwid.nexthop); 414 if (fnh != NULL) 415 pw = (struct l2vpn_pw *) fnh->data; 416 else 417 pw = NULL; 418 419 bzero(&pwctl, sizeof(pwctl)); 420 pwctl.type = f->u.pwid.type; 421 pwctl.pwid = f->u.pwid.pwid; 422 pwctl.nexthop = f->u.pwid.nexthop; 423 424 if (pw) { 425 pwctl.local_label = fn->local_label; 426 pwctl.local_gid = 0; 427 pwctl.local_ifmtu = pw->l2vpn->mtu; 428 } else 429 pwctl.local_label = NO_LABEL; 430 431 LIST_FOREACH(me, &fn->downstream, entry) 432 if (f->u.pwid.nexthop.s_addr == me->nexthop->id.s_addr) 433 break; 434 435 if (me) { 436 pwctl.remote_label = me->map.label; 437 pwctl.remote_gid = me->map.fec.pwid.group_id; 438 if (me->map.flags & F_MAP_PW_IFMTU) 439 pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu; 440 441 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING, 442 0, pid, &pwctl, sizeof(pwctl)); 443 } else if (pw) { 444 pwctl.remote_label = NO_LABEL; 445 446 lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING, 447 0, pid, &pwctl, sizeof(pwctl)); 448 } 449 } 450} 451 452/* ldpe */ 453 454void 455ldpe_l2vpn_init(struct l2vpn *l2vpn) 456{ 457 struct l2vpn_pw *pw; 458 459 LIST_FOREACH(pw, &l2vpn->pw_list, entry) 460 ldpe_l2vpn_pw_init(pw); 461} 462 463void 464ldpe_l2vpn_exit(struct l2vpn *l2vpn) 465{ 466 struct l2vpn_pw *pw; 467 468 LIST_FOREACH(pw, &l2vpn->pw_list, entry) 469 ldpe_l2vpn_pw_exit(pw); 470} 471 472void 473ldpe_l2vpn_pw_init(struct l2vpn_pw *pw) 474{ 475 struct tnbr *tnbr; 476 477 if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY) 478 return; 479 480 tnbr = tnbr_find(leconf, pw->addr); 481 if (tnbr->discovery_fd == 0) 482 tnbr_init(leconf, tnbr); 483} 484 485void 486ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw) 487{ 488 struct tnbr *tnbr; 489 490 if (pw->pwid == 0 || pw->addr.s_addr == INADDR_ANY) 491 return; 492 493 tnbr = tnbr_find(leconf, pw->addr); 494 if (tnbr) { 495 tnbr->pw_count--; 496 tnbr_check(tnbr); 497 } 498} 499