mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-31 16:56:31 +00:00 
			
		
		
		
	 07679ad98a
			
		
	
	
		07679ad98a
		
	
	
	
	
		
			
			There is a possibility that the same line can be matched as a command in some node and its parent node. In this case, when reading the config, this line is always executed as a command of the child node. For example, with the following config: ``` router ospf network 193.168.0.0/16 area 0 ! mpls ldp discovery hello interval 111 ! ``` Line `mpls ldp` is processed as command `mpls ldp-sync` inside the `router ospf` node. This leads to a complete loss of `mpls ldp` node configuration. To eliminate this issue and all possible similar issues, let's print an explicit "exit" at the end of every node config. This commit also changes indentation for a couple of existing exit commands so that all existing commands are on the same level as their corresponding node-entering commands. Fixes #9206. Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
		
			
				
	
	
		
			1659 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1659 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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 <zebra.h>
 | |
| 
 | |
| #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);
 | |
| }
 |