Downport BGPM and addrack patches to configlet_201811 branch (#3669)
* BGPm for 201811 (#3601) * Feature is downported * Add monitors to the test minigraphs * Test * No pfx filer * Fix bgp sample * Quagga requires to activate peer-group before configuration * Add bgpcfgd and bgpd.peer template * Catch exception if rendering external template * Fix tests
This commit is contained in:
parent
aa6adc1384
commit
a96ed09ff3
@ -1,65 +1,282 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import redis
|
||||
import subprocess
|
||||
import datetime
|
||||
import time
|
||||
import syslog
|
||||
from swsssdk import ConfigDBConnector
|
||||
import signal
|
||||
import traceback
|
||||
import os
|
||||
import shutil
|
||||
from collections import defaultdict
|
||||
from pprint import pprint
|
||||
|
||||
class BGPConfigDaemon:
|
||||
import jinja2
|
||||
import netaddr
|
||||
from swsscommon import swsscommon
|
||||
|
||||
|
||||
g_run = True
|
||||
g_debug = False
|
||||
|
||||
|
||||
def run_command(command, shell=False):
|
||||
str_cmd = " ".join(command)
|
||||
if g_debug:
|
||||
syslog.syslog(syslog.LOG_DEBUG, "execute command {}.".format(str_cmd))
|
||||
p = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
syslog.syslog(syslog.LOG_ERR, 'command execution returned {}. Command: "{}", stdout: "{}", stderr: "{}"'.format(p.returncode, str_cmd, stdout, stderr))
|
||||
|
||||
return p.returncode, stdout, stderr
|
||||
|
||||
class TemplateFabric(object):
|
||||
def __init__(self):
|
||||
j2_template_paths = ['/usr/share/sonic/templates']
|
||||
j2_loader = jinja2.FileSystemLoader(j2_template_paths)
|
||||
j2_env = jinja2.Environment(loader=j2_loader, trim_blocks=True)
|
||||
j2_env.filters['ipv4'] = self.is_ipv4
|
||||
j2_env.filters['ipv6'] = self.is_ipv6
|
||||
self.env = j2_env
|
||||
|
||||
def from_file(self, filename):
|
||||
return self.env.get_template(filename)
|
||||
|
||||
def from_string(self, tmpl):
|
||||
return self.env.from_string(tmpl)
|
||||
|
||||
@staticmethod
|
||||
def is_ipv4(value):
|
||||
if not value:
|
||||
return False
|
||||
if isinstance(value, netaddr.IPNetwork):
|
||||
addr = value
|
||||
else:
|
||||
try:
|
||||
addr = netaddr.IPNetwork(str(value))
|
||||
except:
|
||||
return False
|
||||
return addr.version == 4
|
||||
|
||||
@staticmethod
|
||||
def is_ipv6(value):
|
||||
if not value:
|
||||
return False
|
||||
if isinstance(value, netaddr.IPNetwork):
|
||||
addr = value
|
||||
else:
|
||||
try:
|
||||
addr = netaddr.IPNetwork(str(value))
|
||||
except:
|
||||
return False
|
||||
return addr.version == 6
|
||||
|
||||
|
||||
class BGPConfigManager(object):
|
||||
def __init__(self, daemon):
|
||||
self.bgp_asn = None
|
||||
self.meta = None
|
||||
self.bgp_messages = []
|
||||
self.peers = self.load_peers() # we can have bgp monitors peers here. it could be fixed by adding support for it here
|
||||
fabric = TemplateFabric()
|
||||
self.bgp_peer_add_template = fabric.from_file('bgpd.peer.conf.j2')
|
||||
self.bgp_peer_del_template = fabric.from_string('no neighbor {{ neighbor_addr }}')
|
||||
self.bgp_peer_shutdown = fabric.from_string('neighbor {{ neighbor_addr }} shutdown')
|
||||
self.bgp_peer_no_shutdown = fabric.from_string('no neighbor {{ neighbor_addr }} shutdown')
|
||||
daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, self.__metadata_handler)
|
||||
daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME, self.__bgp_handler)
|
||||
|
||||
def load_peers(self):
|
||||
peers = set()
|
||||
for ip_type in ["ip", "ipv6"]:
|
||||
command = ["vtysh", "-c", "show %s bgp summary" % ip_type]
|
||||
rc, out, err = run_command(command)
|
||||
if rc == 0:
|
||||
inside = False
|
||||
for line in out.split("\n"):
|
||||
if "Neighbor V" in line:
|
||||
inside = True
|
||||
elif "Total number of neighbors" in line:
|
||||
break
|
||||
elif inside:
|
||||
if line.startswith("*"):
|
||||
continue
|
||||
space = line.find(" ")
|
||||
if space == -1:
|
||||
peers.add(line)
|
||||
else:
|
||||
peers.add(line[:space])
|
||||
return peers
|
||||
|
||||
def __metadata_handler(self, key, op, data):
|
||||
if key != "localhost" \
|
||||
or "bgp_asn" not in data \
|
||||
or self.bgp_asn == data["bgp_asn"]:
|
||||
return
|
||||
|
||||
# TODO add ASN update commands
|
||||
|
||||
self.meta = { 'localhost': data }
|
||||
self.bgp_asn = data["bgp_asn"]
|
||||
self.__update_bgp()
|
||||
|
||||
def __update_bgp(self):
|
||||
cmds = []
|
||||
for key, op, data in self.bgp_messages:
|
||||
if op == swsscommon.SET_COMMAND:
|
||||
if key not in self.peers:
|
||||
try:
|
||||
txt = self.bgp_peer_add_template.render(DEVICE_METADATA=self.meta, neighbor_addr=key, bgp_session=data)
|
||||
cmds.append(txt)
|
||||
except:
|
||||
syslog.syslog(syslog.LOG_ERR, 'Peer {}. Error in rendering the template for "SET" command {}'.format(key, data))
|
||||
else:
|
||||
syslog.syslog(syslog.LOG_INFO, 'Peer {} added with attributes {}'.format(key, data))
|
||||
self.peers.add(key)
|
||||
else:
|
||||
# when the peer is already configured we support "shutdown/no shutdown"
|
||||
# commands for the peers only
|
||||
if "admin_status" in data:
|
||||
if data['admin_status'] == 'up':
|
||||
cmds.append(self.bgp_peer_no_shutdown.render(neighbor_addr=key))
|
||||
syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "up"'.format(key))
|
||||
elif data['admin_status'] == 'down':
|
||||
cmds.append(self.bgp_peer_shutdown.render(neighbor_addr=key))
|
||||
syslog.syslog(syslog.LOG_INFO, 'Peer {} admin state is set to "down"'.format(key))
|
||||
else:
|
||||
syslog.syslog(syslog.LOG_ERR, "Peer {}: Can't update the peer. has wrong attribute value attr['admin_status'] = '{}'".format(key, data['admin_status']))
|
||||
else:
|
||||
syslog.syslog(syslog.LOG_INFO, "Peer {}: Can't update the peer. No 'admin_status' attribute in the request".format(key))
|
||||
elif op == swsscommon.DEL_COMMAND:
|
||||
if key in self.peers:
|
||||
cmds.append(self.bgp_peer_del_template.render(neighbor_addr=key))
|
||||
syslog.syslog(syslog.LOG_INFO, 'Peer {} has been removed'.format(key))
|
||||
self.peers.remove(key)
|
||||
else:
|
||||
syslog.syslog(syslog.LOG_WARNING, 'Peer {} is not found'.format(key))
|
||||
self.bgp_messages = []
|
||||
|
||||
for cmd in cmds:
|
||||
self.__apply_cmd(cmd)
|
||||
|
||||
def __apply_cmd(self, cmd):
|
||||
lines = [line for line in cmd.split("\n") if not line.startswith('!') and line.strip() != ""]
|
||||
if len(lines) == 0:
|
||||
return
|
||||
offset = len(lines[0]) - len(lines[0].lstrip())
|
||||
chunks = ["dummy"]
|
||||
for line in cmd.split("\n"):
|
||||
c_offset = len(line) - len(line.lstrip())
|
||||
if c_offset > offset:
|
||||
chunks.append(line.strip())
|
||||
elif c_offset < offset:
|
||||
chunks.pop()
|
||||
chunks.pop()
|
||||
chunks.append(line.strip())
|
||||
else:
|
||||
chunks.pop()
|
||||
chunks.append(line.strip())
|
||||
|
||||
command = ["vtysh", "-c", "conf t", "-c", "router bgp %s" % self.bgp_asn]
|
||||
for chunk in chunks:
|
||||
command.append("-c")
|
||||
command.append(chunk)
|
||||
run_command(command)
|
||||
|
||||
def __bgp_handler(self, key, op, data):
|
||||
self.bgp_messages.append((key, op, data))
|
||||
# If ASN is not set, we just cache this message until the ASN is set.
|
||||
if self.bgp_asn is not None:
|
||||
self.__update_bgp()
|
||||
|
||||
|
||||
class Daemon(object):
|
||||
SELECT_TIMEOUT = 1000
|
||||
DATABASE_LIST = [ swsscommon.CONFIG_DB ]
|
||||
|
||||
def __init__(self):
|
||||
self.config_db = ConfigDBConnector()
|
||||
self.config_db.connect()
|
||||
self.bgp_asn = self.config_db.get_entry('DEVICE_METADATA', 'localhost')['bgp_asn']
|
||||
self.bgp_neighbor = self.config_db.get_table('BGP_NEIGHBOR')
|
||||
self.db_connectors = { db : swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) for db in Daemon.DATABASE_LIST }
|
||||
self.selector = swsscommon.Select()
|
||||
self.callbacks = defaultdict(lambda : defaultdict(list)) # db -> table -> []
|
||||
self.subscribers = set()
|
||||
|
||||
def __run_command(self, command):
|
||||
# print command
|
||||
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
|
||||
stdout = p.communicate()[0]
|
||||
p.wait()
|
||||
if p.returncode != 0:
|
||||
syslog.syslog(syslog.LOG_ERR, '[bgp cfgd] command execution returned {}. Command: "{}", stdout: "{}"'.format(p.returncode, command, stdout))
|
||||
def add_manager(self, db, table_name, callback):
|
||||
if db not in Daemon.DATABASE_LIST:
|
||||
raise ValueError("database {} isn't supported. Supported '{}' only.".format(db, ",".join(Daemon.DATABASE_LIST)))
|
||||
|
||||
def metadata_handler(self, key, data):
|
||||
if key == 'localhost' and data.has_key('bgp_asn'):
|
||||
if data['bgp_asn'] != self.bgp_asn:
|
||||
syslog.syslog(syslog.LOG_INFO, '[bgp cfgd] ASN changed to {} from {}, restart BGP...'.format(data['bgp_asn'], self.bgp_asn))
|
||||
self.__run_command("supervisorctl restart start.sh")
|
||||
self.__run_command("service quagga restart")
|
||||
self.bgp_asn = data['bgp_asn']
|
||||
if table_name not in self.callbacks[db]:
|
||||
conn = self.db_connectors[db]
|
||||
subscriber = swsscommon.SubscriberStateTable(conn, table_name)
|
||||
self.subscribers.add(subscriber)
|
||||
self.selector.addSelectable(subscriber)
|
||||
self.callbacks[db][table_name].append(callback)
|
||||
|
||||
def bgp_handler(self, key, data):
|
||||
syslog.syslog(syslog.LOG_INFO, '[bgp cfgd] value for {} changed to {}'.format(key, data))
|
||||
if not data:
|
||||
# Neighbor is deleted
|
||||
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'no neighbor {}'".format(self.bgp_asn, key)
|
||||
self.__run_command(command)
|
||||
self.bgp_neighbor.pop(key)
|
||||
else:
|
||||
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} remote-as {}'".format(self.bgp_asn, key, data['asn'])
|
||||
self.__run_command(command)
|
||||
if data.has_key('name'):
|
||||
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} description {}'".format(self.bgp_asn, key, data['name'])
|
||||
self.__run_command(command)
|
||||
if data.has_key('admin_status'):
|
||||
command_mod = 'no ' if data['admin_status'] == 'up' else ''
|
||||
command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c '{}neighbor {} shutdown'".format(self.bgp_asn, command_mod, key)
|
||||
self.__run_command(command)
|
||||
self.bgp_neighbor[key] = data
|
||||
def run(self):
|
||||
while g_run:
|
||||
state, _ = self.selector.select(Daemon.SELECT_TIMEOUT)
|
||||
if state == self.selector.TIMEOUT:
|
||||
continue
|
||||
elif state == self.selector.ERROR:
|
||||
raise Exception("Received error from select")
|
||||
|
||||
def start(self):
|
||||
self.config_db.subscribe('BGP_NEIGHBOR',
|
||||
lambda table, key, data: self.bgp_handler(key, data))
|
||||
self.config_db.subscribe('DEVICE_METADATA',
|
||||
lambda table, key, data: self.metadata_handler(key, data))
|
||||
self.config_db.listen()
|
||||
for subscriber in self.subscribers:
|
||||
key, op, fvs = subscriber.pop()
|
||||
if not key:
|
||||
continue
|
||||
if g_debug:
|
||||
syslog.syslog(syslog.LOG_DEBUG, "Received message : {}".format((key, op, fvs)))
|
||||
for callback in self.callbacks[subscriber.getDbConnector().getDbId()][subscriber.getTableName()]:
|
||||
callback(key, op, dict(fvs))
|
||||
|
||||
|
||||
def wait_for_bgpd():
|
||||
# wait for 20 seconds
|
||||
stop_time = datetime.datetime.now() + datetime.timedelta(seconds=20)
|
||||
syslog.syslog(syslog.LOG_INFO, "Start waiting for bgpd: %s" % str(datetime.datetime.now()))
|
||||
while datetime.datetime.now() < stop_time:
|
||||
rc, out, err = run_command(["ps", "ax"])
|
||||
if rc == 0 and "bgpd" in out:
|
||||
for line in out.split("\n"):
|
||||
if "/usr/lib/quagga/bgpd" in line:
|
||||
time.sleep(0.01) # wait that bgpd connected to vtysh
|
||||
syslog.syslog(syslog.LOG_INFO, "bgpd connected to vtysh: %s" % str(datetime.datetime.now()))
|
||||
return
|
||||
time.sleep(0.1) # sleep 100 ms
|
||||
raise RuntimeError("bgpd hasn't been started in 20 seconds")
|
||||
|
||||
|
||||
def main():
|
||||
daemon = BGPConfigDaemon()
|
||||
daemon.start()
|
||||
wait_for_bgpd()
|
||||
daemon = Daemon()
|
||||
bgp_manager = BGPConfigManager(daemon)
|
||||
daemon.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
def signal_handler(signum, frame):
|
||||
global g_run
|
||||
g_run = False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
rc = 0
|
||||
try:
|
||||
syslog.openlog('bgpcfgd')
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
syslog.syslog(syslog.LOG_NOTICE, "Keyboard interrupt")
|
||||
except RuntimeError as e:
|
||||
syslog.syslog(syslog.LOG_CRIT, "%s" % str(e))
|
||||
rc = -2
|
||||
except Exception as e:
|
||||
syslog.syslog(syslog.LOG_CRIT, "Got an exception %s: Traceback: %s" % (str(e), traceback.format_exc()))
|
||||
rc = -1
|
||||
finally:
|
||||
syslog.closelog()
|
||||
try:
|
||||
sys.exit(rc)
|
||||
except SystemExit:
|
||||
os._exit(rc)
|
||||
|
@ -63,42 +63,6 @@ router bgp {{ DEVICE_METADATA['localhost']['bgp_asn'] }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock vlan_advertisement %}
|
||||
{% block bgp_sessions %}
|
||||
{% for neighbor_addr, bgp_session in BGP_NEIGHBOR.iteritems() %}
|
||||
{% if bgp_session['asn'] | int != 0 %}
|
||||
neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }}
|
||||
neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }}
|
||||
{# set the bgp neighbor timers if they have not default values #}
|
||||
{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60)
|
||||
or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %}
|
||||
neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }}
|
||||
{% endif %}
|
||||
{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %}
|
||||
neighbor {{ neighbor_addr }} shutdown
|
||||
{% endif %}
|
||||
{% if neighbor_addr | ipv4 %}
|
||||
address-family ipv4
|
||||
{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %}
|
||||
neighbor {{ neighbor_addr }} allowas-in 1
|
||||
{% endif %}
|
||||
neighbor {{ neighbor_addr }} activate
|
||||
neighbor {{ neighbor_addr }} soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
{% endif %}
|
||||
{% if neighbor_addr | ipv6 %}
|
||||
address-family ipv6
|
||||
{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %}
|
||||
neighbor {{ neighbor_addr }} allowas-in 1
|
||||
{% endif %}
|
||||
neighbor {{ neighbor_addr }} activate
|
||||
neighbor {{ neighbor_addr }} soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock bgp_sessions %}
|
||||
{% block bgp_peers_with_range %}
|
||||
{% if BGP_PEER_RANGE %}
|
||||
{% for bgp_peer in BGP_PEER_RANGE.values() %}
|
||||
|
34
dockers/docker-fpm-quagga/bgpd.peer.conf.j2
Normal file
34
dockers/docker-fpm-quagga/bgpd.peer.conf.j2
Normal file
@ -0,0 +1,34 @@
|
||||
{% block bgp_session %}
|
||||
{% if bgp_session['asn'] | int != 0 %}
|
||||
neighbor {{ neighbor_addr }} remote-as {{ bgp_session['asn'] }}
|
||||
neighbor {{ neighbor_addr }} description {{ bgp_session['name'] }}
|
||||
{# set the bgp neighbor timers if they have not default values #}
|
||||
{% if (bgp_session['keepalive'] is defined and bgp_session['keepalive'] | int != 60)
|
||||
or (bgp_session['holdtime'] is defined and bgp_session['holdtime'] | int != 180) %}
|
||||
neighbor {{ neighbor_addr }} timers {{ bgp_session['keepalive'] }} {{ bgp_session['holdtime'] }}
|
||||
{% endif %}
|
||||
{% if bgp_session.has_key('admin_status') and bgp_session['admin_status'] == 'down' or not bgp_session.has_key('admin_status') and DEVICE_METADATA['localhost'].has_key('default_bgp_status') and DEVICE_METADATA['localhost']['default_bgp_status'] == 'down' %}
|
||||
neighbor {{ neighbor_addr }} shutdown
|
||||
{% endif %}
|
||||
{% if neighbor_addr | ipv4 %}
|
||||
address-family ipv4 unicast
|
||||
{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %}
|
||||
neighbor {{ neighbor_addr }} allowas-in 1
|
||||
{% endif %}
|
||||
neighbor {{ neighbor_addr }} activate
|
||||
neighbor {{ neighbor_addr }} soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
{% endif %}
|
||||
{% if neighbor_addr | ipv6 %}
|
||||
address-family ipv6
|
||||
{% if DEVICE_METADATA['localhost']['type'] == 'ToRRouter' %}
|
||||
neighbor {{ neighbor_addr }} allowas-in 1
|
||||
{% endif %}
|
||||
neighbor {{ neighbor_addr }} activate
|
||||
neighbor {{ neighbor_addr }} soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock bgp_session %}
|
@ -18,8 +18,6 @@ echo "# Config files managed by sonic-config-engine" > /var/sonic/config_status
|
||||
|
||||
rm -f /var/run/rsyslogd.pid
|
||||
|
||||
supervisorctl start bgpcfgd
|
||||
|
||||
supervisorctl start rsyslogd
|
||||
|
||||
# Start Quagga processes
|
||||
@ -27,3 +25,5 @@ supervisorctl start zebra
|
||||
supervisorctl start bgpd
|
||||
|
||||
supervisorctl start fpmsyncd
|
||||
|
||||
supervisorctl start bgpcfgd
|
||||
|
@ -32,70 +32,6 @@ router bgp 65100
|
||||
network fc00:1::32/64
|
||||
exit-address-family
|
||||
network 192.168.0.1/27
|
||||
neighbor 10.0.0.57 remote-as 64600
|
||||
neighbor 10.0.0.57 description ARISTA01T1
|
||||
address-family ipv4
|
||||
neighbor 10.0.0.57 allowas-in 1
|
||||
neighbor 10.0.0.57 activate
|
||||
neighbor 10.0.0.57 soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
neighbor 10.0.0.59 remote-as 64600
|
||||
neighbor 10.0.0.59 description ARISTA02T1
|
||||
address-family ipv4
|
||||
neighbor 10.0.0.59 allowas-in 1
|
||||
neighbor 10.0.0.59 activate
|
||||
neighbor 10.0.0.59 soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
neighbor 10.0.0.61 remote-as 64600
|
||||
neighbor 10.0.0.61 description ARISTA03T1
|
||||
address-family ipv4
|
||||
neighbor 10.0.0.61 allowas-in 1
|
||||
neighbor 10.0.0.61 activate
|
||||
neighbor 10.0.0.61 soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
neighbor 10.0.0.63 remote-as 64600
|
||||
neighbor 10.0.0.63 description ARISTA04T1
|
||||
address-family ipv4
|
||||
neighbor 10.0.0.63 allowas-in 1
|
||||
neighbor 10.0.0.63 activate
|
||||
neighbor 10.0.0.63 soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
neighbor fc00::7a remote-as 64600
|
||||
neighbor fc00::7a description ARISTA03T1
|
||||
address-family ipv6
|
||||
neighbor fc00::7a allowas-in 1
|
||||
neighbor fc00::7a activate
|
||||
neighbor fc00::7a soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
neighbor fc00::7e remote-as 64600
|
||||
neighbor fc00::7e description ARISTA04T1
|
||||
address-family ipv6
|
||||
neighbor fc00::7e allowas-in 1
|
||||
neighbor fc00::7e activate
|
||||
neighbor fc00::7e soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
neighbor fc00::72 remote-as 64600
|
||||
neighbor fc00::72 description ARISTA01T1
|
||||
address-family ipv6
|
||||
neighbor fc00::72 allowas-in 1
|
||||
neighbor fc00::72 activate
|
||||
neighbor fc00::72 soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
neighbor fc00::76 remote-as 64600
|
||||
neighbor fc00::76 description ARISTA02T1
|
||||
address-family ipv6
|
||||
neighbor fc00::76 allowas-in 1
|
||||
neighbor fc00::76 activate
|
||||
neighbor fc00::76 soft-reconfiguration inbound
|
||||
maximum-paths 64
|
||||
exit-address-family
|
||||
neighbor BGPMON_V4 peer-group
|
||||
neighbor BGPMON_V4 activate
|
||||
neighbor BGPMON_V4 update-source 10.1.0.32
|
||||
|
Loading…
Reference in New Issue
Block a user