/* * Copyright (C) 2016 by Open Source Routing. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA */ #include #include "ldpd.h" #include "ldpe.h" #include "lde.h" #include "log.h" #include "command.h" #include "vrf.h" #include "if.h" #include "vty.h" #include "ldp_vty.h" static int ldp_config_write(struct vty *); static void ldp_af_iface_config_write(struct vty *, int); static void ldp_af_config_write(struct vty *, int, struct ldpd_conf *, struct ldpd_af_conf *); static int ldp_l2vpn_config_write(struct vty *); static void ldp_l2vpn_pw_config_write(struct vty *, struct l2vpn_pw *); static int ldp_vty_get_af(struct vty *); static int ldp_iface_is_configured(struct ldpd_conf *, const char *); struct cmd_node ldp_node = { .name = "ldp", .node = LDP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-ldp)# ", .config_write = ldp_config_write, }; struct cmd_node ldp_ipv4_node = { .name = "ldp ipv4", .node = LDP_IPV4_NODE, .parent_node = LDP_NODE, .prompt = "%s(config-ldp-af)# ", }; struct cmd_node ldp_ipv6_node = { .name = "ldp ipv6", .node = LDP_IPV6_NODE, .parent_node = LDP_NODE, .prompt = "%s(config-ldp-af)# ", }; struct cmd_node ldp_ipv4_iface_node = { .name = "ldp ipv4 interface", .node = LDP_IPV4_IFACE_NODE, .parent_node = LDP_IPV4_NODE, .prompt = "%s(config-ldp-af-if)# ", }; struct cmd_node ldp_ipv6_iface_node = { .name = "ldp ipv6 interface", .node = LDP_IPV6_IFACE_NODE, .parent_node = LDP_IPV6_NODE, .prompt = "%s(config-ldp-af-if)# ", }; struct cmd_node ldp_l2vpn_node = { .name = "ldp l2vpn", .node = LDP_L2VPN_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-l2vpn)# ", .config_write = ldp_l2vpn_config_write, }; struct cmd_node ldp_pseudowire_node = { .name = "ldp", .node = LDP_PSEUDOWIRE_NODE, .parent_node = LDP_L2VPN_NODE, .prompt = "%s(config-l2vpn-pw)# ", }; int ldp_get_address(const char *str, int *af, union ldpd_addr *addr) { if (!str || !af || !addr) return (-1); memset(addr, 0, sizeof(*addr)); if (inet_pton(AF_INET, str, &addr->v4) == 1) { *af = AF_INET; return (0); } if (inet_pton(AF_INET6, str, &addr->v6) == 1) { *af = AF_INET6; return (0); } return (-1); } static void ldp_af_iface_config_write(struct vty *vty, int af) { struct iface *iface; struct iface_af *ia; RB_FOREACH(iface, iface_head, &ldpd_conf->iface_tree) { ia = iface_af_get(iface, af); if (!ia->enabled) continue; vty_out (vty, " !\n"); vty_out (vty, " interface %s\n", iface->name); if (ia->hello_holdtime != LINK_DFLT_HOLDTIME && ia->hello_holdtime != 0) vty_out (vty, " discovery hello holdtime %u\n", ia->hello_holdtime); if (ia->hello_interval != DEFAULT_HELLO_INTERVAL && ia->hello_interval != 0) vty_out (vty, " discovery hello interval %u\n", ia->hello_interval); vty_out (vty, " exit\n"); } } static void ldp_af_config_write(struct vty *vty, int af, struct ldpd_conf *conf, struct ldpd_af_conf *af_conf) { struct tnbr *tnbr; if (!(af_conf->flags & F_LDPD_AF_ENABLED)) return; vty_out (vty, " !\n"); vty_out (vty, " address-family %s\n", af_name(af)); if (af_conf->lhello_holdtime != LINK_DFLT_HOLDTIME && af_conf->lhello_holdtime != 0 ) vty_out (vty, " discovery hello holdtime %u\n", af_conf->lhello_holdtime); if (af_conf->lhello_interval != DEFAULT_HELLO_INTERVAL && af_conf->lhello_interval != 0) vty_out (vty, " discovery hello interval %u\n", af_conf->lhello_interval); if (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) { vty_out(vty, " discovery targeted-hello accept"); if (af_conf->acl_thello_accept_from[0] != '\0') vty_out(vty, " from %s", af_conf->acl_thello_accept_from); vty_out (vty, "\n"); } if (af_conf->thello_holdtime != TARGETED_DFLT_HOLDTIME && af_conf->thello_holdtime != 0) vty_out (vty, " discovery targeted-hello holdtime %u\n", af_conf->thello_holdtime); if (af_conf->thello_interval != DEFAULT_HELLO_INTERVAL && af_conf->thello_interval != 0) vty_out (vty, " discovery targeted-hello interval %u\n", af_conf->thello_interval); if (ldp_addrisset(af, &af_conf->trans_addr)) vty_out (vty, " discovery transport-address %s\n", log_addr(af, &af_conf->trans_addr)); else vty_out (vty, " ! Incomplete config, specify a discovery transport-address\n"); if ((af_conf->flags & F_LDPD_AF_ALLOCHOSTONLY) || af_conf->acl_label_allocate_for[0] != '\0') { vty_out(vty, " label local allocate"); if (af_conf->flags & F_LDPD_AF_ALLOCHOSTONLY) vty_out(vty, " host-routes"); else vty_out(vty, " for %s", af_conf->acl_label_allocate_for); vty_out (vty, "\n"); } if (af_conf->acl_label_advertise_for[0] != '\0' || af_conf->acl_label_advertise_to[0] != '\0') { vty_out(vty, " label local advertise"); if (af_conf->acl_label_advertise_to[0] != '\0') vty_out(vty, " to %s", af_conf->acl_label_advertise_to); if (af_conf->acl_label_advertise_for[0] != '\0') vty_out(vty, " for %s", af_conf->acl_label_advertise_for); vty_out (vty, "\n"); } if (af_conf->flags & F_LDPD_AF_EXPNULL) { vty_out(vty, " label local advertise explicit-null"); if (af_conf->acl_label_expnull_for[0] != '\0') vty_out(vty, " for %s", af_conf->acl_label_expnull_for); vty_out (vty, "\n"); } if (af_conf->acl_label_accept_for[0] != '\0' || af_conf->acl_label_accept_from[0] != '\0') { vty_out(vty, " label remote accept"); if (af_conf->acl_label_accept_from[0] != '\0') vty_out(vty, " from %s", af_conf->acl_label_accept_from); if (af_conf->acl_label_accept_for[0] != '\0') vty_out(vty, " for %s", af_conf->acl_label_accept_for); vty_out (vty, "\n"); } if (af_conf->flags & F_LDPD_AF_NO_GTSM) vty_out (vty, " ttl-security disable\n"); if (af_conf->keepalive != DEFAULT_KEEPALIVE) vty_out (vty, " session holdtime %u\n",af_conf->keepalive); RB_FOREACH(tnbr, tnbr_head, &ldpd_conf->tnbr_tree) { if (tnbr->af == af) { vty_out (vty, " !\n"); vty_out (vty, " neighbor %s targeted\n", log_addr(tnbr->af, &tnbr->addr)); } } ldp_af_iface_config_write(vty, af); vty_out(vty, " !\n"); vty_out(vty, " exit-address-family\n"); } static int ldp_config_write(struct vty *vty) { struct nbr_params *nbrp; if (!(ldpd_conf->flags & F_LDPD_ENABLED)) return (0); vty_out (vty, "mpls ldp\n"); if (ldpd_conf->rtr_id.s_addr != INADDR_ANY) vty_out(vty, " router-id %pI4\n", &ldpd_conf->rtr_id); if (ldpd_conf->lhello_holdtime != LINK_DFLT_HOLDTIME && ldpd_conf->lhello_holdtime != 0) vty_out (vty, " discovery hello holdtime %u\n", ldpd_conf->lhello_holdtime); if (ldpd_conf->lhello_interval != DEFAULT_HELLO_INTERVAL && ldpd_conf->lhello_interval != 0) vty_out (vty, " discovery hello interval %u\n", ldpd_conf->lhello_interval); if (ldpd_conf->thello_holdtime != TARGETED_DFLT_HOLDTIME && ldpd_conf->thello_holdtime != 0) vty_out (vty, " discovery targeted-hello holdtime %u\n", ldpd_conf->thello_holdtime); if (ldpd_conf->thello_interval != DEFAULT_HELLO_INTERVAL && ldpd_conf->thello_interval != 0) vty_out (vty, " discovery targeted-hello interval %u\n", ldpd_conf->thello_interval); if (ldpd_conf->trans_pref == DUAL_STACK_LDPOV4) vty_out (vty, " dual-stack transport-connection prefer ipv4\n"); if (ldpd_conf->flags & F_LDPD_DS_CISCO_INTEROP) vty_out (vty, " dual-stack cisco-interop\n"); if (ldpd_conf->flags & F_LDPD_ORDERED_CONTROL) vty_out (vty, " ordered-control\n"); if (ldpd_conf->wait_for_sync_interval != DFLT_WAIT_FOR_SYNC && ldpd_conf->wait_for_sync_interval != 0) vty_out (vty, " wait-for-sync %u\n", ldpd_conf->wait_for_sync_interval); if (ldpd_conf->flags & F_LDPD_ALLOW_BROKEN_LSP) vty_out(vty, " install allow-broken-lsp\n"); RB_FOREACH(nbrp, nbrp_head, &ldpd_conf->nbrp_tree) { if (nbrp->flags & F_NBRP_KEEPALIVE) vty_out (vty, " neighbor %pI4 session holdtime %u\n", &nbrp->lsr_id,nbrp->keepalive); if (nbrp->flags & F_NBRP_GTSM) { if (nbrp->gtsm_enabled) vty_out (vty, " neighbor %pI4 ttl-security hops %u\n", &nbrp->lsr_id, nbrp->gtsm_hops); else vty_out (vty, " neighbor %pI4 ttl-security disable\n",&nbrp->lsr_id); } if (nbrp->auth.method == AUTH_MD5SIG) vty_out (vty, " neighbor %pI4 password %s\n", &nbrp->lsr_id,nbrp->auth.md5key); } ldp_af_config_write(vty, AF_INET, ldpd_conf, &ldpd_conf->ipv4); ldp_af_config_write(vty, AF_INET6, ldpd_conf, &ldpd_conf->ipv6); vty_out (vty, " !\n"); vty_out (vty, "exit\n"); vty_out (vty, "!\n"); return (1); } static void ldp_l2vpn_pw_config_write(struct vty *vty, struct l2vpn_pw *pw) { int missing_lsrid = 0; int missing_pwid = 0; vty_out (vty, " !\n"); vty_out (vty, " member pseudowire %s\n", pw->ifname); if (pw->lsr_id.s_addr != INADDR_ANY) vty_out (vty, " neighbor lsr-id %pI4\n",&pw->lsr_id); else missing_lsrid = 1; if (pw->flags & F_PW_STATIC_NBR_ADDR) vty_out (vty, " neighbor address %s\n", log_addr(pw->af, &pw->addr)); if (pw->pwid != 0) vty_out (vty, " pw-id %u\n", pw->pwid); else missing_pwid = 1; if (!(pw->flags & F_PW_CWORD_CONF)) vty_out (vty, " control-word exclude\n"); if (!(pw->flags & F_PW_STATUSTLV_CONF)) vty_out (vty, " pw-status disable\n"); if (missing_lsrid) vty_out (vty, " ! Incomplete config, specify a neighbor lsr-id\n"); if (missing_pwid) vty_out (vty," ! Incomplete config, specify a pw-id\n"); vty_out (vty, " exit\n"); } static int ldp_l2vpn_config_write(struct vty *vty) { struct l2vpn *l2vpn; struct l2vpn_if *lif; struct l2vpn_pw *pw; RB_FOREACH(l2vpn, l2vpn_head, &ldpd_conf->l2vpn_tree) { vty_out (vty, "l2vpn %s type vpls\n", l2vpn->name); if (l2vpn->pw_type != DEFAULT_PW_TYPE) vty_out (vty, " vc type ethernet-tagged\n"); if (l2vpn->mtu != DEFAULT_L2VPN_MTU) vty_out (vty, " mtu %u\n", l2vpn->mtu); if (l2vpn->br_ifname[0] != '\0') vty_out (vty, " bridge %s\n",l2vpn->br_ifname); RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree) vty_out (vty, " member interface %s\n",lif->ifname); RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) ldp_l2vpn_pw_config_write(vty, pw); RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree) ldp_l2vpn_pw_config_write(vty, pw); vty_out (vty, " !\n"); vty_out (vty, "exit\n"); vty_out (vty, "!\n"); } return (0); } static int ldp_vty_get_af(struct vty *vty) { switch (vty->node) { case LDP_IPV4_NODE: case LDP_IPV4_IFACE_NODE: return (AF_INET); case LDP_IPV6_NODE: case LDP_IPV6_IFACE_NODE: return (AF_INET6); default: fatalx("ldp_vty_get_af: unexpected node"); } } static int ldp_iface_is_configured(struct ldpd_conf *xconf, const char *ifname) { struct l2vpn *l2vpn; if (if_lookup_name(xconf, ifname)) return (1); RB_FOREACH(l2vpn, l2vpn_head, &xconf->l2vpn_tree) { if (l2vpn_if_find(l2vpn, ifname)) return (1); if (l2vpn_pw_find(l2vpn, ifname)) return (1); } return (0); } int ldp_vty_mpls_ldp(struct vty *vty, const char *negate) { if (negate) vty_conf->flags &= ~F_LDPD_ENABLED; else { vty->node = LDP_NODE; vty_conf->flags |= F_LDPD_ENABLED; } /* register / de-register to recv info from zebra */ ldp_zebra_regdereg_zebra_info(!negate); ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_address_family(struct vty *vty, const char *negate, const char *af_str) { struct ldpd_af_conf *af_conf; int af; if (af_str == NULL) return (CMD_WARNING_CONFIG_FAILED); if (strcmp(af_str, "ipv4") == 0) { af = AF_INET; af_conf = &vty_conf->ipv4; } else if (strcmp(af_str, "ipv6") == 0) { af = AF_INET6; af_conf = &vty_conf->ipv6; } else return (CMD_WARNING_CONFIG_FAILED); if (negate) { af_conf->flags &= ~F_LDPD_AF_ENABLED; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } switch (af) { case AF_INET: vty->node = LDP_IPV4_NODE; break; case AF_INET6: vty->node = LDP_IPV6_NODE; break; default: fatalx("ldp_vty_address_family: unknown af"); } af_conf->flags |= F_LDPD_AF_ENABLED; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_disc_holdtime(struct vty *vty, const char *negate, enum hello_type hello_type, long secs) { struct ldpd_af_conf *af_conf; struct iface *iface; struct iface_af *ia; int af; switch (vty->node) { case LDP_NODE: if (negate) { switch (hello_type) { case HELLO_LINK: vty_conf->lhello_holdtime = LINK_DFLT_HOLDTIME; break; case HELLO_TARGETED: vty_conf->thello_holdtime = TARGETED_DFLT_HOLDTIME; break; } } else { switch (hello_type) { case HELLO_LINK: vty_conf->lhello_holdtime = secs; break; case HELLO_TARGETED: vty_conf->thello_holdtime = secs; break; } } ldp_config_apply(vty, vty_conf); break; case LDP_IPV4_NODE: case LDP_IPV6_NODE: af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); if (negate) { switch (hello_type) { case HELLO_LINK: af_conf->lhello_holdtime = 0; break; case HELLO_TARGETED: af_conf->thello_holdtime = 0; break; } } else { switch (hello_type) { case HELLO_LINK: af_conf->lhello_holdtime = secs; break; case HELLO_TARGETED: af_conf->thello_holdtime = secs; break; } } ldp_config_apply(vty, vty_conf); break; case LDP_IPV4_IFACE_NODE: case LDP_IPV6_IFACE_NODE: af = ldp_vty_get_af(vty); iface = VTY_GET_CONTEXT(iface); VTY_CHECK_CONTEXT(iface); ia = iface_af_get(iface, af); if (negate) ia->hello_holdtime = 0; else ia->hello_holdtime = secs; ldp_config_apply(vty, vty_conf); break; default: fatalx("ldp_vty_disc_holdtime: unexpected node"); } return (CMD_SUCCESS); } int ldp_vty_disc_interval(struct vty *vty, const char *negate, enum hello_type hello_type, long secs) { struct ldpd_af_conf *af_conf; struct iface *iface; struct iface_af *ia; int af; switch (vty->node) { case LDP_NODE: if (negate) { switch (hello_type) { case HELLO_LINK: vty_conf->lhello_interval = DEFAULT_HELLO_INTERVAL; break; case HELLO_TARGETED: vty_conf->thello_interval = DEFAULT_HELLO_INTERVAL; break; } } else { switch (hello_type) { case HELLO_LINK: vty_conf->lhello_interval = secs; break; case HELLO_TARGETED: vty_conf->thello_interval = secs; break; } } ldp_config_apply(vty, vty_conf); break; case LDP_IPV4_NODE: case LDP_IPV6_NODE: af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); if (negate) { switch (hello_type) { case HELLO_LINK: af_conf->lhello_interval = 0; break; case HELLO_TARGETED: af_conf->thello_interval = 0; break; } } else { switch (hello_type) { case HELLO_LINK: af_conf->lhello_interval = secs; break; case HELLO_TARGETED: af_conf->thello_interval = secs; break; } } ldp_config_apply(vty, vty_conf); break; case LDP_IPV4_IFACE_NODE: case LDP_IPV6_IFACE_NODE: af = ldp_vty_get_af(vty); iface = VTY_GET_CONTEXT(iface); VTY_CHECK_CONTEXT(iface); ia = iface_af_get(iface, af); if (negate) ia->hello_interval = 0; else ia->hello_interval = secs; ldp_config_apply(vty, vty_conf); break; default: fatalx("ldp_vty_disc_interval: unexpected node"); } return (CMD_SUCCESS); } int ldp_vty_targeted_hello_accept(struct vty *vty, const char *negate, const char *acl_from_str) { struct ldpd_af_conf *af_conf; int af; af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); if (negate) { af_conf->flags &= ~F_LDPD_AF_THELLO_ACCEPT; af_conf->acl_thello_accept_from[0] = '\0'; } else { af_conf->flags |= F_LDPD_AF_THELLO_ACCEPT; if (acl_from_str) strlcpy(af_conf->acl_thello_accept_from, acl_from_str, sizeof(af_conf->acl_thello_accept_from)); else af_conf->acl_thello_accept_from[0] = '\0'; } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_nbr_session_holdtime(struct vty *vty, const char *negate, struct in_addr lsr_id, long secs) { struct nbr_params *nbrp; if (bad_addr_v4(lsr_id)) { vty_out (vty, "%% Malformed address\n"); return (CMD_WARNING_CONFIG_FAILED); } nbrp = nbr_params_find(vty_conf, lsr_id); if (negate) { if (nbrp == NULL) return (CMD_SUCCESS); nbrp->keepalive = 0; nbrp->flags &= ~F_NBRP_KEEPALIVE; } else { if (nbrp == NULL) { nbrp = nbr_params_new(lsr_id); RB_INSERT(nbrp_head, &vty_conf->nbrp_tree, nbrp); QOBJ_REG(nbrp, nbr_params); } else if (nbrp->keepalive == secs) return (CMD_SUCCESS); nbrp->keepalive = secs; nbrp->flags |= F_NBRP_KEEPALIVE; } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_af_session_holdtime(struct vty *vty, const char *negate, long secs) { struct ldpd_af_conf *af_conf; int af; af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); if (negate) af_conf->keepalive = DEFAULT_KEEPALIVE; else af_conf->keepalive = secs; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_interface(struct vty *vty, const char *negate, const char *ifname) { int af; struct iface *iface; struct iface_af *ia; if (ifname == NULL) { vty_out (vty, "%% Missing IF name\n"); return (CMD_WARNING_CONFIG_FAILED); } af = ldp_vty_get_af(vty); iface = if_lookup_name(vty_conf, ifname); if (negate) { if (iface == NULL) return (CMD_SUCCESS); ia = iface_af_get(iface, af); if (ia->enabled == 0) return (CMD_SUCCESS); ia->enabled = 0; ia->hello_holdtime = 0; ia->hello_interval = 0; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } if (iface == NULL) { if (ldp_iface_is_configured(vty_conf, ifname)) { vty_out (vty,"%% Interface is already in use\n"); return (CMD_SUCCESS); } iface = if_new(ifname); ia = iface_af_get(iface, af); ia->enabled = 1; RB_INSERT(iface_head, &vty_conf->iface_tree, iface); QOBJ_REG(iface, iface); ldp_config_apply(vty, vty_conf); } else { ia = iface_af_get(iface, af); if (!ia->enabled) { ia->enabled = 1; ldp_config_apply(vty, vty_conf); } } switch (af) { case AF_INET: VTY_PUSH_CONTEXT(LDP_IPV4_IFACE_NODE, iface); break; case AF_INET6: VTY_PUSH_CONTEXT(LDP_IPV6_IFACE_NODE, iface); break; default: break; } return (CMD_SUCCESS); } int ldp_vty_trans_addr(struct vty *vty, const char *negate, const char *addr_str) { struct ldpd_af_conf *af_conf; int af; af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); if (negate) memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr)); else { if (addr_str == NULL || inet_pton(af, addr_str, &af_conf->trans_addr) != 1 || bad_addr(af, &af_conf->trans_addr)) { vty_out (vty, "%% Malformed address\n"); return (CMD_SUCCESS); } } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_neighbor_targeted(struct vty *vty, const char *negate, const char *addr_str) { int af; union ldpd_addr addr; struct tnbr *tnbr; af = ldp_vty_get_af(vty); if (addr_str == NULL || inet_pton(af, addr_str, &addr) != 1 || bad_addr(af, &addr)) { vty_out (vty, "%% Malformed address\n"); return (CMD_WARNING_CONFIG_FAILED); } if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&addr.v6)) { vty_out (vty, "%% Address can not be link-local\n"); return (CMD_WARNING_CONFIG_FAILED); } tnbr = tnbr_find(vty_conf, af, &addr); if (negate) { if (tnbr == NULL) return (CMD_SUCCESS); QOBJ_UNREG(tnbr); RB_REMOVE(tnbr_head, &vty_conf->tnbr_tree, tnbr); free(tnbr); ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } if (tnbr) return (CMD_SUCCESS); tnbr = tnbr_new(af, &addr); tnbr->flags |= F_TNBR_CONFIGURED; RB_INSERT(tnbr_head, &vty_conf->tnbr_tree, tnbr); QOBJ_REG(tnbr, tnbr); ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_label_advertise(struct vty *vty, const char *negate, const char *acl_to_str, const char *acl_for_str) { struct ldpd_af_conf *af_conf; int af; af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); if (negate) { af_conf->acl_label_advertise_to[0] = '\0'; af_conf->acl_label_advertise_for[0] = '\0'; } else { if (acl_to_str) strlcpy(af_conf->acl_label_advertise_to, acl_to_str, sizeof(af_conf->acl_label_advertise_to)); else af_conf->acl_label_advertise_to[0] = '\0'; if (acl_for_str) strlcpy(af_conf->acl_label_advertise_for, acl_for_str, sizeof(af_conf->acl_label_advertise_for)); else af_conf->acl_label_advertise_for[0] = '\0'; } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_label_allocate(struct vty *vty, const char *negate, const char *host_routes, const char *acl_for_str) { struct ldpd_af_conf *af_conf; int af; af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); af_conf->flags &= ~F_LDPD_AF_ALLOCHOSTONLY; af_conf->acl_label_allocate_for[0] = '\0'; if (!negate) { if (host_routes) af_conf->flags |= F_LDPD_AF_ALLOCHOSTONLY; else strlcpy(af_conf->acl_label_allocate_for, acl_for_str, sizeof(af_conf->acl_label_allocate_for)); } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_label_expnull(struct vty *vty, const char *negate, const char *acl_for_str) { struct ldpd_af_conf *af_conf; int af; af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); if (negate) { af_conf->flags &= ~F_LDPD_AF_EXPNULL; af_conf->acl_label_expnull_for[0] = '\0'; } else { af_conf->flags |= F_LDPD_AF_EXPNULL; if (acl_for_str) strlcpy(af_conf->acl_label_expnull_for, acl_for_str, sizeof(af_conf->acl_label_expnull_for)); else af_conf->acl_label_expnull_for[0] = '\0'; } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_label_accept(struct vty *vty, const char *negate, const char *acl_from_str, const char *acl_for_str) { struct ldpd_af_conf *af_conf; int af; af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); if (negate) { af_conf->acl_label_accept_from[0] = '\0'; af_conf->acl_label_accept_for[0] = '\0'; } else { if (acl_from_str) strlcpy(af_conf->acl_label_accept_from, acl_from_str, sizeof(af_conf->acl_label_accept_from)); else af_conf->acl_label_accept_from[0] = '\0'; if (acl_for_str) strlcpy(af_conf->acl_label_accept_for, acl_for_str, sizeof(af_conf->acl_label_accept_for)); else af_conf->acl_label_accept_for[0] = '\0'; } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_ttl_security(struct vty *vty, const char *negate) { struct ldpd_af_conf *af_conf; int af; af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); if (negate) af_conf->flags &= ~F_LDPD_AF_NO_GTSM; else af_conf->flags |= F_LDPD_AF_NO_GTSM; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_router_id(struct vty *vty, const char *negate, struct in_addr address) { if (negate) vty_conf->rtr_id.s_addr = INADDR_ANY; else { if (bad_addr_v4(address)) { vty_out (vty, "%% Malformed address\n"); return (CMD_SUCCESS); } vty_conf->rtr_id = address; } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_ordered_control(struct vty *vty, const char *negate) { if (negate) vty_conf->flags &= ~F_LDPD_ORDERED_CONTROL; else vty_conf->flags |= F_LDPD_ORDERED_CONTROL; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_wait_for_sync_interval(struct vty *vty, const char *negate, long secs) { switch (vty->node) { case LDP_NODE: if (negate) vty_conf->wait_for_sync_interval = DFLT_WAIT_FOR_SYNC; else vty_conf->wait_for_sync_interval = secs; ldp_config_apply(vty, vty_conf); break; default: fatalx("ldp_vty_wait_for_sync_interval: unexpected node"); } return (CMD_SUCCESS); } int ldp_vty_allow_broken_lsp(struct vty *vty, const char *negate) { if (negate) vty_conf->flags &= ~F_LDPD_ALLOW_BROKEN_LSP; else vty_conf->flags |= F_LDPD_ALLOW_BROKEN_LSP; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_ds_cisco_interop(struct vty *vty, const char * negate) { if (negate) vty_conf->flags &= ~F_LDPD_DS_CISCO_INTEROP; else vty_conf->flags |= F_LDPD_DS_CISCO_INTEROP; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_trans_pref_ipv4(struct vty *vty, const char *negate) { if (negate) vty_conf->trans_pref = DUAL_STACK_LDPOV6; else vty_conf->trans_pref = DUAL_STACK_LDPOV4; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_neighbor_password(struct vty *vty, const char *negate, struct in_addr lsr_id, const char *password_str) { size_t password_len; struct nbr_params *nbrp; if (password_str == NULL) { vty_out (vty, "%% Missing password\n"); return (CMD_WARNING_CONFIG_FAILED); } if (bad_addr_v4(lsr_id)) { vty_out (vty, "%% Malformed address\n"); return (CMD_WARNING_CONFIG_FAILED); } nbrp = nbr_params_find(vty_conf, lsr_id); if (negate) { if (nbrp == NULL) return (CMD_SUCCESS); memset(&nbrp->auth, 0, sizeof(nbrp->auth)); nbrp->auth.method = AUTH_NONE; } else { if (nbrp == NULL) { nbrp = nbr_params_new(lsr_id); RB_INSERT(nbrp_head, &vty_conf->nbrp_tree, nbrp); QOBJ_REG(nbrp, nbr_params); } else if (nbrp->auth.method == AUTH_MD5SIG && strcmp(nbrp->auth.md5key, password_str) == 0) return (CMD_SUCCESS); password_len = strlcpy(nbrp->auth.md5key, password_str, sizeof(nbrp->auth.md5key)); if (password_len >= sizeof(nbrp->auth.md5key)) vty_out(vty, "%% password has been truncated to %zu characters.", sizeof(nbrp->auth.md5key) - 1); nbrp->auth.md5key_len = strlen(nbrp->auth.md5key); nbrp->auth.method = AUTH_MD5SIG; } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_neighbor_ttl_security(struct vty *vty, const char *negate, struct in_addr lsr_id, const char *hops_str) { struct nbr_params *nbrp; long int hops = 0; char *ep; if (bad_addr_v4(lsr_id)) { vty_out (vty, "%% Malformed address\n"); return (CMD_WARNING_CONFIG_FAILED); } if (hops_str) { hops = strtol(hops_str, &ep, 10); if (*ep != '\0' || hops < 1 || hops > 254) { vty_out (vty, "%% Invalid hop count\n"); return (CMD_SUCCESS); } } nbrp = nbr_params_find(vty_conf, lsr_id); if (negate) { if (nbrp == NULL) return (CMD_SUCCESS); nbrp->flags &= ~(F_NBRP_GTSM|F_NBRP_GTSM_HOPS); nbrp->gtsm_enabled = 0; nbrp->gtsm_hops = 0; } else { if (nbrp == NULL) { nbrp = nbr_params_new(lsr_id); RB_INSERT(nbrp_head, &vty_conf->nbrp_tree, nbrp); QOBJ_REG(nbrp, nbr_params); } nbrp->flags |= F_NBRP_GTSM; nbrp->flags &= ~F_NBRP_GTSM_HOPS; if (hops_str) { nbrp->gtsm_enabled = 1; nbrp->gtsm_hops = hops; nbrp->flags |= F_NBRP_GTSM_HOPS; } else nbrp->gtsm_enabled = 0; } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn(struct vty *vty, const char *negate, const char *name_str) { struct l2vpn *l2vpn; struct l2vpn_if *lif; struct l2vpn_pw *pw; if (name_str == NULL) { vty_out (vty, "%% Missing name\n"); return (CMD_WARNING_CONFIG_FAILED); } l2vpn = l2vpn_find(vty_conf, name_str); if (negate) { if (l2vpn == NULL) return (CMD_SUCCESS); RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree) QOBJ_UNREG(lif); RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_tree) QOBJ_UNREG(pw); RB_FOREACH(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree) QOBJ_UNREG(pw); QOBJ_UNREG(l2vpn); RB_REMOVE(l2vpn_head, &vty_conf->l2vpn_tree, l2vpn); l2vpn_del(l2vpn); ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } if (l2vpn) { VTY_PUSH_CONTEXT(LDP_L2VPN_NODE, l2vpn); return (CMD_SUCCESS); } l2vpn = l2vpn_new(name_str); l2vpn->type = L2VPN_TYPE_VPLS; RB_INSERT(l2vpn_head, &vty_conf->l2vpn_tree, l2vpn); QOBJ_REG(l2vpn, l2vpn); VTY_PUSH_CONTEXT(LDP_L2VPN_NODE, l2vpn); ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn_bridge(struct vty *vty, const char *negate, const char *ifname) { VTY_DECLVAR_CONTEXT(l2vpn, l2vpn); if (negate) memset(l2vpn->br_ifname, 0, sizeof(l2vpn->br_ifname)); else { if (ifname == NULL) { vty_out (vty, "%% Missing IF name\n"); return (CMD_WARNING_CONFIG_FAILED); } strlcpy(l2vpn->br_ifname, ifname, sizeof(l2vpn->br_ifname)); } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn_mtu(struct vty *vty, const char *negate, long mtu) { VTY_DECLVAR_CONTEXT(l2vpn, l2vpn); if (negate) l2vpn->mtu = DEFAULT_L2VPN_MTU; else l2vpn->mtu = mtu; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn_pwtype(struct vty *vty, const char *negate, const char *type_str) { VTY_DECLVAR_CONTEXT(l2vpn, l2vpn); int pw_type; if (type_str == NULL) { vty_out (vty, "%% Missing type\n"); return (CMD_WARNING_CONFIG_FAILED); } if (strcmp(type_str, "ethernet") == 0) pw_type = PW_TYPE_ETHERNET; else pw_type = PW_TYPE_ETHERNET_TAGGED; if (negate) l2vpn->pw_type = DEFAULT_PW_TYPE; else l2vpn->pw_type = pw_type; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn_interface(struct vty *vty, const char *negate, const char *ifname) { VTY_DECLVAR_CONTEXT(l2vpn, l2vpn); struct l2vpn_if *lif; if (ifname == NULL) { vty_out (vty, "%% Missing IF name\n"); return (CMD_WARNING_CONFIG_FAILED); } lif = l2vpn_if_find(l2vpn, ifname); if (negate) { if (lif == NULL) return (CMD_SUCCESS); QOBJ_UNREG(lif); RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif); free(lif); ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } if (lif) return (CMD_SUCCESS); if (ldp_iface_is_configured(vty_conf, ifname)) { vty_out (vty, "%% Interface is already in use\n"); return (CMD_SUCCESS); } lif = l2vpn_if_new(l2vpn, ifname); RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, lif); QOBJ_REG(lif, l2vpn_if); ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn_pseudowire(struct vty *vty, const char *negate, const char *ifname) { VTY_DECLVAR_CONTEXT(l2vpn, l2vpn); struct l2vpn_pw *pw; if (ifname == NULL) { vty_out (vty, "%% Missing IF name\n"); return (CMD_WARNING_CONFIG_FAILED); } pw = l2vpn_pw_find(l2vpn, ifname); if (negate) { if (pw == NULL) return (CMD_SUCCESS); QOBJ_UNREG(pw); if (pw->lsr_id.s_addr == INADDR_ANY || pw->pwid == 0) RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw); else RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw); free(pw); ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } if (pw) { VTY_PUSH_CONTEXT_SUB(LDP_PSEUDOWIRE_NODE, pw); return (CMD_SUCCESS); } if (ldp_iface_is_configured(vty_conf, ifname)) { vty_out (vty, "%% Interface is already in use\n"); return (CMD_SUCCESS); } pw = l2vpn_pw_new(l2vpn, ifname); pw->flags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF; RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw); QOBJ_REG(pw, l2vpn_pw); VTY_PUSH_CONTEXT_SUB(LDP_PSEUDOWIRE_NODE, pw); ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn_pw_cword(struct vty *vty, const char *negate, const char *preference_str) { VTY_DECLVAR_CONTEXT_SUB(l2vpn_pw, pw); if (negate) pw->flags |= F_PW_CWORD_CONF; else { if (!preference_str) { vty_out (vty, "%% Missing preference\n"); return (CMD_WARNING_CONFIG_FAILED); } if (preference_str[0] == 'e') pw->flags &= ~F_PW_CWORD_CONF; else pw->flags |= F_PW_CWORD_CONF; } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn_pw_nbr_addr(struct vty *vty, const char *negate, const char *addr_str) { VTY_DECLVAR_CONTEXT_SUB(l2vpn_pw, pw); int af; union ldpd_addr addr; if (ldp_get_address(addr_str, &af, &addr) == -1 || bad_addr(af, &addr)) { vty_out (vty, "%% Malformed address\n"); return (CMD_WARNING_CONFIG_FAILED); } if (negate) { pw->af = AF_UNSPEC; memset(&pw->addr, 0, sizeof(pw->addr)); pw->flags &= ~F_PW_STATIC_NBR_ADDR; } else { pw->af = af; pw->addr = addr; pw->flags |= F_PW_STATIC_NBR_ADDR; } ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn_pw_nbr_id(struct vty *vty, const char *negate, struct in_addr lsr_id) { VTY_DECLVAR_CONTEXT_SUB(l2vpn_pw, pw); if (bad_addr_v4(lsr_id)) { vty_out (vty, "%% Malformed address\n"); return (CMD_WARNING_CONFIG_FAILED); } if (negate) pw->lsr_id.s_addr = INADDR_ANY; else pw->lsr_id = lsr_id; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn_pw_pwid(struct vty *vty, const char *negate, long pwid) { VTY_DECLVAR_CONTEXT_SUB(l2vpn_pw, pw); if (negate) pw->pwid = 0; else pw->pwid = pwid; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } int ldp_vty_l2vpn_pw_pwstatus(struct vty *vty, const char *negate) { VTY_DECLVAR_CONTEXT_SUB(l2vpn_pw, pw); if (negate) pw->flags |= F_PW_STATUSTLV_CONF; else pw->flags &= ~F_PW_STATUSTLV_CONF; ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); } struct iface * iface_new_api(struct ldpd_conf *conf, const char *name) { const char *ifname = name; struct iface *iface; if (ldp_iface_is_configured(conf, ifname)) return (NULL); iface = if_new(name); RB_INSERT(iface_head, &conf->iface_tree, iface); QOBJ_REG(iface, iface); return (iface); } void iface_del_api(struct ldpd_conf *conf, struct iface *iface) { QOBJ_UNREG(iface); RB_REMOVE(iface_head, &conf->iface_tree, iface); free(iface); } struct tnbr * tnbr_new_api(struct ldpd_conf *conf, int af, union ldpd_addr *addr) { struct tnbr *tnbr; if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&addr->v6)) return (NULL); if (tnbr_find(conf, af, addr)) return (NULL); tnbr = tnbr_new(af, addr); tnbr->flags |= F_TNBR_CONFIGURED; RB_INSERT(tnbr_head, &conf->tnbr_tree, tnbr); QOBJ_REG(tnbr, tnbr); return (tnbr); } void tnbr_del_api(struct ldpd_conf *conf, struct tnbr *tnbr) { QOBJ_UNREG(tnbr); RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr); free(tnbr); } struct nbr_params * nbrp_new_api(struct ldpd_conf *conf, struct in_addr lsr_id) { struct nbr_params *nbrp; if (nbr_params_find(conf, lsr_id)) return (NULL); nbrp = nbr_params_new(lsr_id); RB_INSERT(nbrp_head, &conf->nbrp_tree, nbrp); QOBJ_REG(nbrp, nbr_params); return (nbrp); } void nbrp_del_api(struct ldpd_conf *conf, struct nbr_params *nbrp) { QOBJ_UNREG(nbrp); RB_REMOVE(nbrp_head, &conf->nbrp_tree, nbrp); free(nbrp); } struct l2vpn * l2vpn_new_api(struct ldpd_conf *conf, const char *name) { struct l2vpn *l2vpn; if (l2vpn_find(conf, name)) return (NULL); l2vpn = l2vpn_new(name); l2vpn->type = L2VPN_TYPE_VPLS; RB_INSERT(l2vpn_head, &conf->l2vpn_tree, l2vpn); QOBJ_REG(l2vpn, l2vpn); return (l2vpn); } void l2vpn_del_api(struct ldpd_conf *conf, struct l2vpn *l2vpn) { struct l2vpn_if *lif; struct l2vpn_pw *pw; while (!RB_EMPTY(l2vpn_if_head, &l2vpn->if_tree)) { lif = RB_ROOT(l2vpn_if_head, &l2vpn->if_tree); QOBJ_UNREG(lif); RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif); free(lif); } while (!RB_EMPTY(l2vpn_pw_head, &l2vpn->pw_tree)) { pw = RB_ROOT(l2vpn_pw_head, &l2vpn->pw_tree); QOBJ_UNREG(pw); RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw); free(pw); } while (!RB_EMPTY(l2vpn_pw_head, &l2vpn->pw_inactive_tree)) { pw = RB_ROOT(l2vpn_pw_head, &l2vpn->pw_inactive_tree); QOBJ_UNREG(pw); RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw); free(pw); } QOBJ_UNREG(l2vpn); RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn); free(l2vpn); } struct l2vpn_if * l2vpn_if_new_api(struct ldpd_conf *conf, struct l2vpn *l2vpn, const char *ifname) { struct l2vpn_if *lif; if (ldp_iface_is_configured(conf, ifname)) return (NULL); lif = l2vpn_if_new(l2vpn, ifname); RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, lif); QOBJ_REG(lif, l2vpn_if); return (lif); } void l2vpn_if_del_api(struct l2vpn *l2vpn, struct l2vpn_if *lif) { QOBJ_UNREG(lif); RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif); free(lif); } struct l2vpn_pw * l2vpn_pw_new_api(struct ldpd_conf *conf, struct l2vpn *l2vpn, const char *ifname) { struct l2vpn_pw *pw; if (ldp_iface_is_configured(conf, ifname)) return (NULL); pw = l2vpn_pw_new(l2vpn, ifname); pw->flags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF; RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw); QOBJ_REG(pw, l2vpn_pw); return (pw); } void l2vpn_pw_del_api(struct l2vpn *l2vpn, struct l2vpn_pw *pw) { QOBJ_UNREG(pw); RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw); free(pw); }