Skip to content

Commit 221b593

Browse files
authored
Multi-asic changes for config bgp commands and utilities. (sonic-net#910)
* Multi-asic changes for config bgp commands and utilities. * Review comments update * Optimized the logic of checking the internal hosts using AS number. * API changes due to rebase. Also setting ignore_local_hosts=false explicitly in BGP commands so that existing single ASIC platform implementation is unchanged.
1 parent 10c7ba1 commit 221b593

File tree

1 file changed

+133
-42
lines changed

1 file changed

+133
-42
lines changed

config/main.py

+133-42
Original file line numberDiff line numberDiff line change
@@ -356,88 +356,95 @@ def get_interface_naming_mode():
356356
mode = "default"
357357
return mode
358358

359-
def _is_neighbor_ipaddress(ipaddress):
359+
# Get the local BGP ASN from DEVICE_METADATA
360+
def get_local_bgp_asn(config_db):
361+
metadata = config_db.get_table('DEVICE_METADATA')
362+
return metadata['localhost']['bgp_asn']
363+
364+
def _is_neighbor_ipaddress(config_db, ipaddress):
360365
"""Returns True if a neighbor has the IP address <ipaddress>, False if not
361366
"""
362-
config_db = ConfigDBConnector()
363-
config_db.connect()
364367
entry = config_db.get_entry('BGP_NEIGHBOR', ipaddress)
365368
return True if entry else False
366369

367-
def _get_all_neighbor_ipaddresses():
370+
def _get_all_neighbor_ipaddresses(config_db, ignore_local_hosts=False):
368371
"""Returns list of strings containing IP addresses of all BGP neighbors
372+
if the flag ignore_local_hosts is set to True, additional check to see if
373+
if the BGP neighbor AS number is same as local BGP AS number, if so ignore that neigbor.
369374
"""
370-
config_db = ConfigDBConnector()
371-
config_db.connect()
372-
return config_db.get_table('BGP_NEIGHBOR').keys()
375+
addrs = []
376+
bgp_sessions = config_db.get_table('BGP_NEIGHBOR')
377+
local_as = get_local_bgp_asn(config_db)
378+
for addr, session in bgp_sessions.iteritems():
379+
if not ignore_local_hosts or (ignore_local_hosts and local_as != session['asn']):
380+
addrs.append(addr)
381+
return addrs
373382

374-
def _get_neighbor_ipaddress_list_by_hostname(hostname):
383+
def _get_neighbor_ipaddress_list_by_hostname(config_db, hostname):
375384
"""Returns list of strings, each containing an IP address of neighbor with
376385
hostname <hostname>. Returns empty list if <hostname> not a neighbor
377386
"""
378387
addrs = []
379-
config_db = ConfigDBConnector()
380-
config_db.connect()
381388
bgp_sessions = config_db.get_table('BGP_NEIGHBOR')
382389
for addr, session in bgp_sessions.iteritems():
383390
if session.has_key('name') and session['name'] == hostname:
384391
addrs.append(addr)
385392
return addrs
386393

387-
def _change_bgp_session_status_by_addr(ipaddress, status, verbose):
394+
def _change_bgp_session_status_by_addr(config_db, ipaddress, status, verbose):
388395
"""Start up or shut down BGP session by IP address
389396
"""
390397
verb = 'Starting' if status == 'up' else 'Shutting'
391398
click.echo("{} {} BGP session with neighbor {}...".format(verb, status, ipaddress))
392-
config_db = ConfigDBConnector()
393-
config_db.connect()
394399

395400
config_db.mod_entry('bgp_neighbor', ipaddress, {'admin_status': status})
396401

397-
def _change_bgp_session_status(ipaddr_or_hostname, status, verbose):
402+
def _change_bgp_session_status(config_db, ipaddr_or_hostname, status, verbose):
398403
"""Start up or shut down BGP session by IP address or hostname
399404
"""
400405
ip_addrs = []
401406

402407
# If we were passed an IP address, convert it to lowercase because IPv6 addresses were
403408
# stored in ConfigDB with all lowercase alphabet characters during minigraph parsing
404-
if _is_neighbor_ipaddress(ipaddr_or_hostname.lower()):
409+
if _is_neighbor_ipaddress(config_db, ipaddr_or_hostname.lower()):
405410
ip_addrs.append(ipaddr_or_hostname.lower())
406411
else:
407412
# If <ipaddr_or_hostname> is not the IP address of a neighbor, check to see if it's a hostname
408-
ip_addrs = _get_neighbor_ipaddress_list_by_hostname(ipaddr_or_hostname)
413+
ip_addrs = _get_neighbor_ipaddress_list_by_hostname(config_db, ipaddr_or_hostname)
409414

410415
if not ip_addrs:
411-
click.get_current_context().fail("Could not locate neighbor '{}'".format(ipaddr_or_hostname))
416+
return False
412417

413418
for ip_addr in ip_addrs:
414-
_change_bgp_session_status_by_addr(ip_addr, status, verbose)
419+
_change_bgp_session_status_by_addr(config_db, ip_addr, status, verbose)
420+
421+
return True
415422

416-
def _validate_bgp_neighbor(neighbor_ip_or_hostname):
423+
def _validate_bgp_neighbor(config_db, neighbor_ip_or_hostname):
417424
"""validates whether the given ip or host name is a BGP neighbor
418425
"""
419426
ip_addrs = []
420-
if _is_neighbor_ipaddress(neighbor_ip_or_hostname.lower()):
427+
if _is_neighbor_ipaddress(config_db, neighbor_ip_or_hostname.lower()):
421428
ip_addrs.append(neighbor_ip_or_hostname.lower())
422429
else:
423-
ip_addrs = _get_neighbor_ipaddress_list_by_hostname(neighbor_ip_or_hostname.upper())
424-
425-
if not ip_addrs:
426-
click.get_current_context().fail("Could not locate neighbor '{}'".format(neighbor_ip_or_hostname))
430+
ip_addrs = _get_neighbor_ipaddress_list_by_hostname(config_db, neighbor_ip_or_hostname.upper())
427431

428432
return ip_addrs
429433

430-
def _remove_bgp_neighbor_config(neighbor_ip_or_hostname):
434+
def _remove_bgp_neighbor_config(config_db, neighbor_ip_or_hostname):
431435
"""Removes BGP configuration of the given neighbor
432436
"""
433-
ip_addrs = _validate_bgp_neighbor(neighbor_ip_or_hostname)
434-
config_db = ConfigDBConnector()
435-
config_db.connect()
437+
ip_addrs = _validate_bgp_neighbor(config_db, neighbor_ip_or_hostname)
438+
439+
if not ip_addrs:
440+
return False
436441

437442
for ip_addr in ip_addrs:
438443
config_db.mod_entry('bgp_neighbor', ip_addr, None)
439444
click.echo("Removed configuration of BGP neighbor {}".format(ip_addr))
440445

446+
return True
447+
441448
def _change_hostname(hostname):
442449
current_hostname = os.uname()[1]
443450
if current_hostname != hostname:
@@ -1664,20 +1671,53 @@ def num_dumps(kdump_num_dumps):
16641671
@shutdown.command()
16651672
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
16661673
def all(verbose):
1667-
"""Shut down all BGP sessions"""
1674+
"""Shut down all BGP sessions
1675+
In the case of Multi-Asic platform, we shut only the EBGP sessions with external neighbors.
1676+
"""
16681677
log_info("'bgp shutdown all' executing...")
1669-
bgp_neighbor_ip_list = _get_all_neighbor_ipaddresses()
1670-
for ipaddress in bgp_neighbor_ip_list:
1671-
_change_bgp_session_status_by_addr(ipaddress, 'down', verbose)
1678+
namespaces = [DEFAULT_NAMESPACE]
1679+
ignore_local_hosts = False
1680+
1681+
if sonic_device_util.is_multi_npu():
1682+
ns_list = sonic_device_util.get_all_namespaces()
1683+
namespaces = ns_list['front_ns']
1684+
ignore_local_hosts = True
1685+
1686+
# Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the
1687+
# namespaces (in case of multi ASIC) and do the sepcified "action" on the BGP neighbor(s)
1688+
for namespace in namespaces:
1689+
config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace)
1690+
config_db.connect()
1691+
bgp_neighbor_ip_list = _get_all_neighbor_ipaddresses(config_db, ignore_local_hosts)
1692+
for ipaddress in bgp_neighbor_ip_list:
1693+
_change_bgp_session_status_by_addr(config_db, ipaddress, 'down', verbose)
16721694

16731695
# 'neighbor' subcommand
16741696
@shutdown.command()
16751697
@click.argument('ipaddr_or_hostname', metavar='<ipaddr_or_hostname>', required=True)
16761698
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
16771699
def neighbor(ipaddr_or_hostname, verbose):
1678-
"""Shut down BGP session by neighbor IP address or hostname"""
1700+
"""Shut down BGP session by neighbor IP address or hostname.
1701+
User can specify either internal or external BGP neighbor to shutdown
1702+
"""
16791703
log_info("'bgp shutdown neighbor {}' executing...".format(ipaddr_or_hostname))
1680-
_change_bgp_session_status(ipaddr_or_hostname, 'down', verbose)
1704+
namespaces = [DEFAULT_NAMESPACE]
1705+
found_neighbor = False
1706+
1707+
if sonic_device_util.is_multi_npu():
1708+
ns_list = sonic_device_util.get_all_namespaces()
1709+
namespaces = ns_list['front_ns'] + ns_list['back_ns']
1710+
1711+
# Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the
1712+
# namespaces (in case of multi ASIC) and do the sepcified "action" on the BGP neighbor(s)
1713+
for namespace in namespaces:
1714+
config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace)
1715+
config_db.connect()
1716+
if _change_bgp_session_status(config_db, ipaddr_or_hostname, 'down', verbose):
1717+
found_neighbor = True
1718+
1719+
if not found_neighbor:
1720+
click.get_current_context().fail("Could not locate neighbor '{}'".format(ipaddr_or_hostname))
16811721

16821722
@bgp.group(cls=AbbreviationGroup)
16831723
def startup():
@@ -1688,20 +1728,53 @@ def startup():
16881728
@startup.command()
16891729
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
16901730
def all(verbose):
1691-
"""Start up all BGP sessions"""
1731+
"""Start up all BGP sessions
1732+
In the case of Multi-Asic platform, we startup only the EBGP sessions with external neighbors.
1733+
"""
16921734
log_info("'bgp startup all' executing...")
1693-
bgp_neighbor_ip_list = _get_all_neighbor_ipaddresses()
1694-
for ipaddress in bgp_neighbor_ip_list:
1695-
_change_bgp_session_status(ipaddress, 'up', verbose)
1735+
namespaces = [DEFAULT_NAMESPACE]
1736+
ignore_local_hosts = False
1737+
1738+
if sonic_device_util.is_multi_npu():
1739+
ns_list = sonic_device_util.get_all_namespaces()
1740+
namespaces = ns_list['front_ns']
1741+
ignore_local_hosts = True
1742+
1743+
# Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the
1744+
# namespaces (in case of multi ASIC) and do the sepcified "action" on the BGP neighbor(s)
1745+
for namespace in namespaces:
1746+
config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace)
1747+
config_db.connect()
1748+
bgp_neighbor_ip_list = _get_all_neighbor_ipaddresses(config_db, ignore_local_hosts)
1749+
for ipaddress in bgp_neighbor_ip_list:
1750+
_change_bgp_session_status_by_addr(config_db, ipaddress, 'up', verbose)
16961751

16971752
# 'neighbor' subcommand
16981753
@startup.command()
16991754
@click.argument('ipaddr_or_hostname', metavar='<ipaddr_or_hostname>', required=True)
17001755
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
17011756
def neighbor(ipaddr_or_hostname, verbose):
1702-
"""Start up BGP session by neighbor IP address or hostname"""
17031757
log_info("'bgp startup neighbor {}' executing...".format(ipaddr_or_hostname))
1704-
_change_bgp_session_status(ipaddr_or_hostname, 'up', verbose)
1758+
"""Start up BGP session by neighbor IP address or hostname.
1759+
User can specify either internal or external BGP neighbor to startup
1760+
"""
1761+
namespaces = [DEFAULT_NAMESPACE]
1762+
found_neighbor = False
1763+
1764+
if sonic_device_util.is_multi_npu():
1765+
ns_list = sonic_device_util.get_all_namespaces()
1766+
namespaces = ns_list['front_ns'] + ns_list['back_ns']
1767+
1768+
# Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the
1769+
# namespaces (in case of multi ASIC) and do the sepcified "action" on the BGP neighbor(s)
1770+
for namespace in namespaces:
1771+
config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace)
1772+
config_db.connect()
1773+
if _change_bgp_session_status(config_db, ipaddr_or_hostname, 'up', verbose):
1774+
found_neighbor = True
1775+
1776+
if not found_neighbor:
1777+
click.get_current_context().fail("Could not locate neighbor '{}'".format(ipaddr_or_hostname))
17051778

17061779
#
17071780
# 'remove' subgroup ('config bgp remove ...')
@@ -1715,8 +1788,26 @@ def remove():
17151788
@remove.command('neighbor')
17161789
@click.argument('neighbor_ip_or_hostname', metavar='<neighbor_ip_or_hostname>', required=True)
17171790
def remove_neighbor(neighbor_ip_or_hostname):
1718-
"""Deletes BGP neighbor configuration of given hostname or ip from devices"""
1719-
_remove_bgp_neighbor_config(neighbor_ip_or_hostname)
1791+
"""Deletes BGP neighbor configuration of given hostname or ip from devices
1792+
User can specify either internal or external BGP neighbor to remove
1793+
"""
1794+
namespaces = [DEFAULT_NAMESPACE]
1795+
removed_neighbor = False
1796+
1797+
if sonic_device_util.is_multi_npu():
1798+
ns_list = sonic_device_util.get_all_namespaces()
1799+
namespaces = ns_list['front_ns'] + ns_list['back_ns']
1800+
1801+
# Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the
1802+
# namespaces (in case of multi ASIC) and do the sepcified "action" on the BGP neighbor(s)
1803+
for namespace in namespaces:
1804+
config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace)
1805+
config_db.connect()
1806+
if _remove_bgp_neighbor_config(config_db, neighbor_ip_or_hostname):
1807+
removed_neighbor = True
1808+
1809+
if not removed_neighbor:
1810+
click.get_current_context().fail("Could not locate neighbor '{}'".format(neighbor_ip_or_hostname))
17201811

17211812
#
17221813
# 'interface' group ('config interface ...')

0 commit comments

Comments
 (0)