Skip to content

Commit

Permalink
Merge branch 'master-cisco-8000-config_command' of https://github.com…
Browse files Browse the repository at this point in the history
…/yucgu/sonic-utilities into master-cisco-8000-config_command
  • Loading branch information
yucgu committed Aug 10, 2022
2 parents 53d7792 + 9a8d9e3 commit abf4c47
Show file tree
Hide file tree
Showing 212 changed files with 13,642 additions and 11,714 deletions.
41 changes: 41 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->

## Security

Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).

If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.

## Reporting Security Issues

**Please do not report security vulnerabilities through public GitHub issues.**

Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).

If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).

You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).

Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:

* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue

This information will help us triage your report more quickly.

If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.

## Preferred Languages

We prefer all communications to be in English.

## Policy

Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).

<!-- END MICROSOFT SECURITY.MD BLOCK -->
4 changes: 2 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ resources:
repositories:
- repository: sonic-swss
type: github
name: Azure/sonic-swss
endpoint: build
name: sonic-net/sonic-swss
endpoint: sonic-net

stages:
- stage: Build
Expand Down
217 changes: 95 additions & 122 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from sonic_py_common import device_info, multi_asic
from sonic_py_common.interface import get_interface_table_name, get_port_table_name, get_intf_longname
from utilities_common import util_base
from swsscommon import swsscommon
from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector
from utilities_common.db import Db
from utilities_common.intf_filter import parse_interface_in_filter
Expand All @@ -47,6 +48,7 @@
from . import plugins
from .config_mgmt import ConfigMgmtDPB
from . import mclag
from . import syslog

# mock masic APIs for unit test
try:
Expand Down Expand Up @@ -667,7 +669,7 @@ def is_storm_control_supported(storm_type, namespace):
supported = state_db.get(state_db.STATE_DB, entry_name,"supported")
return supported

#API to configure the PORT_STORM_CONTROL table
#API to configure the PORT_STORM_CONTROL table
def storm_control_set_entry(port_name, kbps, storm_type, namespace):

if storm_control_interface_validate(port_name) is False:
Expand All @@ -692,7 +694,7 @@ def storm_control_set_entry(port_name, kbps, storm_type, namespace):

return True

#API to remove an entry from PORT_STORM_CONTROL table
#API to remove an entry from PORT_STORM_CONTROL table
def storm_control_delete_entry(port_name, storm_type):

if storm_control_interface_validate(port_name) is False:
Expand Down Expand Up @@ -1218,6 +1220,9 @@ def config(ctx):
config.add_command(mclag.mclag_member)
config.add_command(mclag.mclag_unique_ip)

# syslog module
config.add_command(syslog.syslog)

@config.command()
@click.option('-y', '--yes', is_flag=True, callback=_abort_if_false,
expose_value=False, prompt='Existing files will be overwritten, continue?')
Expand Down Expand Up @@ -1518,11 +1523,6 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart, disable_arp_cach
if multi_asic.is_multi_asic() and file_format == 'config_db':
num_cfg_file += num_asic

# Remove cached PG drop counters data
dropstat_dir_prefix = '/tmp/dropstat'
command = "rm -rf {}-*".format(dropstat_dir_prefix)
clicommon.run_command(command, display_cmd=True)

# If the user give the filename[s], extract the file names.
if filename is not None:
cfg_files = filename.split(',')
Expand Down Expand Up @@ -1890,19 +1890,11 @@ def hostname(new_hostname):

config_db = ConfigDBConnector()
config_db.connect()
config_db.mod_entry('DEVICE_METADATA' , 'localhost', {"hostname" : new_hostname})
try:
command = "service hostname-config restart"
clicommon.run_command(command, display_cmd=True)
except SystemExit as e:
click.echo("Restarting hostname-config service failed with error {}".format(e))
raise
config_db.mod_entry(swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, 'localhost',
{'hostname': new_hostname})

# Reload Monit configuration to pick up new hostname in case it changed
click.echo("Reloading Monit configuration ...")
clicommon.run_command("sudo monit reload")

click.echo("Please note loaded setting will be lost after system reboot. To preserve setting, run `config save`.")
click.echo('Please note loaded setting will be lost after system reboot. To'
' preserve setting, run `config save`.')

#
# 'synchronous_mode' command ('config synchronous_mode ...')
Expand All @@ -1929,6 +1921,21 @@ def synchronous_mode(sync_mode):
else:
raise click.BadParameter("Error: Invalid argument %s, expect either enable or disable" % sync_mode)

#
# 'yang_config_validation' command ('config yang_config_validation ...')
#
@config.command('yang_config_validation')
@click.argument('yang_config_validation', metavar='<enable|disable>', required=True)
def yang_config_validation(yang_config_validation):
# Enable or disable YANG validation on updates to ConfigDB
if yang_config_validation == 'enable' or yang_config_validation == 'disable':
config_db = ConfigDBConnector()
config_db.connect()
config_db.mod_entry('DEVICE_METADATA', 'localhost', {"yang_config_validation": yang_config_validation})
click.echo("""Wrote %s yang config validation into CONFIG_DB""" % yang_config_validation)
else:
raise click.BadParameter("Error: Invalid argument %s, expect either enable or disable" % yang_config_validation)

#
# 'portchannel' group ('config portchannel ...')
#
Expand Down Expand Up @@ -2828,22 +2835,6 @@ def warm_restart_bgp_eoiu(ctx, enable):
db = ctx.obj['db']
db.mod_entry('WARM_RESTART', 'bgp', {'bgp_eoiu': enable})

def mvrf_restart_services():
"""Restart interfaces-config service and NTP service when mvrf is changed"""
"""
When mvrf is enabled, eth0 should be moved to mvrf; when it is disabled,
move it back to default vrf. Restarting the "interfaces-config" service
will recreate the /etc/network/interfaces file and restart the
"networking" service that takes care of the eth0 movement.
NTP service should also be restarted to rerun the NTP service with or
without "cgexec" accordingly.
"""
cmd="service ntp stop"
os.system (cmd)
cmd="systemctl restart interfaces-config"
os.system (cmd)
cmd="service ntp start"
os.system (cmd)

def vrf_add_management_vrf(config_db):
"""Enable management vrf in config DB"""
Expand All @@ -2853,22 +2844,7 @@ def vrf_add_management_vrf(config_db):
click.echo("ManagementVRF is already Enabled.")
return None
config_db.mod_entry('MGMT_VRF_CONFIG', "vrf_global", {"mgmtVrfEnabled": "true"})
mvrf_restart_services()
"""
The regular expression for grep in below cmd is to match eth0 line in /proc/net/route, sample file:
$ cat /proc/net/route
Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
eth0 00000000 01803B0A 0003 0 0 202 00000000 0 0 0
"""
cmd = r"cat /proc/net/route | grep -E \"eth0\s+00000000\s+[0-9A-Z]+\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+202\" | wc -l"
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
output = proc.communicate()
if int(output[0]) >= 1:
cmd="ip -4 route del default dev eth0 metric 202"
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
proc.communicate()
if proc.returncode != 0:
click.echo("Could not delete eth0 route")


def vrf_delete_management_vrf(config_db):
"""Disable management vrf in config DB"""
Expand All @@ -2878,7 +2854,7 @@ def vrf_delete_management_vrf(config_db):
click.echo("ManagementVRF is already Disabled.")
return None
config_db.mod_entry('MGMT_VRF_CONFIG', "vrf_global", {"mgmtVrfEnabled": "false"})
mvrf_restart_services()


@config.group(cls=clicommon.AbbreviationGroup)
@click.pass_context
Expand Down Expand Up @@ -4114,20 +4090,6 @@ def _get_all_mgmtinterface_keys():
config_db.connect()
return list(config_db.get_table('MGMT_INTERFACE').keys())

def mgmt_ip_restart_services():
"""Restart the required services when mgmt inteface IP address is changed"""
"""
Whenever the eth0 IP address is changed, restart the "interfaces-config"
service which regenerates the /etc/network/interfaces file and restarts
the networking service to make the new/null IP address effective for eth0.
"ntp-config" service should also be restarted based on the new
eth0 IP address since the ntp.conf (generated from ntp.conf.j2) is
made to listen on that particular eth0 IP address or reset it back.
"""
cmd="systemctl restart interfaces-config"
os.system (cmd)
cmd="systemctl restart ntp-config"
os.system (cmd)

#
# 'mtu' subcommand
Expand Down Expand Up @@ -4198,8 +4160,6 @@ def fec(ctx, interface_name, interface_fec, verbose):
# Get the config_db connector
config_db = ctx.obj['config_db']

if interface_fec not in ["rs", "fc", "none"]:
ctx.fail("'fec not in ['rs', 'fc', 'none']!")
if clicommon.get_interface_naming_mode() == "alias":
interface_name = interface_alias_to_name(config_db, interface_name)
if interface_name is None:
Expand Down Expand Up @@ -4275,7 +4235,6 @@ def add(ctx, interface_name, ip_addr, gw):
config_db.set_entry("MGMT_INTERFACE", (interface_name, str(ip_address)), {"NULL": "NULL"})
else:
config_db.set_entry("MGMT_INTERFACE", (interface_name, str(ip_address)), {"gwaddr": gw})
mgmt_ip_restart_services()

return

Expand Down Expand Up @@ -4315,7 +4274,6 @@ def remove(ctx, interface_name, ip_addr):

if interface_name == 'eth0':
config_db.set_entry("MGMT_INTERFACE", (interface_name, str(ip_address)), None)
mgmt_ip_restart_services()
return

table_name = get_interface_table_name(interface_name)
Expand Down Expand Up @@ -4720,6 +4678,67 @@ def transceiver(ctx):
"""SFP transceiver configuration"""
pass

#
# 'frequency' subcommand ('config interface transceiver frequency ...')
#
@transceiver.command()
@click.pass_context
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.argument('frequency', metavar='<frequency>', required=True, type=int)
def frequency(ctx, interface_name, frequency):
"""Set transciever (only for 400G-ZR) frequency"""
# Get the config_db connector
config_db = ctx.obj['config_db']

if clicommon.get_interface_naming_mode() == "alias":
interface_name = interface_alias_to_name(config_db, interface_name)
if interface_name is None:
ctx.fail("'interface_name' is None!")

if interface_name_is_valid(config_db, interface_name) is False:
ctx.fail("Interface name is invalid. Please enter a valid interface name!!")

log.log_info("{} Setting transceiver frequency {} GHz".format(interface_name, frequency))

if ctx.obj['namespace'] is DEFAULT_NAMESPACE:
command = "portconfig -p {} -F {}".format(interface_name, frequency)
else:
command = "portconfig -p {} -F {} -n {}".format(interface_name, frequency, ctx.obj['namespace'])

clicommon.run_command(command)


#
# 'tx_power' subcommand ('config interface transceiver tx_power ...')
# For negative float use:-
# config interface transceiver tx_power Ethernet0 -- -27.4"
#
@transceiver.command('tx_power')
@click.pass_context
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.argument('tx-power', metavar='<tx-power>', required=True, type=float)
def tx_power(ctx, interface_name, tx_power):
"""Set transciever (only for 400G-ZR) Tx laser power"""
# Get the config_db connector
config_db = ctx.obj['config_db']

if clicommon.get_interface_naming_mode() == "alias":
interface_name = interface_alias_to_name(config_db, interface_name)
if interface_name is None:
ctx.fail("'interface_name' is None!")

if interface_name_is_valid(config_db, interface_name) is False:
ctx.fail("Interface name is invalid. Please enter a valid interface name!!")

log.log_info("{} Setting transceiver power {} dBm".format(interface_name, tx_power))

if ctx.obj['namespace'] is DEFAULT_NAMESPACE:
command = "portconfig -p {} -P {}".format(interface_name, tx_power)
else:
command = "portconfig -p {} -P {} -n {}".format(interface_name, tx_power, ctx.obj['namespace'])

clicommon.run_command(command)

#
# 'lpmode' subcommand ('config interface transceiver lpmode ...')
#
Expand Down Expand Up @@ -5061,6 +5080,12 @@ def del_vrf(ctx, vrf_name):
ctx.fail("'vrf_name' is not start with Vrf, mgmt or management!")
if len(vrf_name) > 15:
ctx.fail("'vrf_name' is too long!")
syslog_table = config_db.get_table("SYSLOG_SERVER")
syslog_vrf_dev = "mgmt" if vrf_name == "management" else vrf_name
for syslog_entry, syslog_data in syslog_table.items():
syslog_vrf = syslog_data.get("vrf")
if syslog_vrf == syslog_vrf_dev:
ctx.fail("Failed to remove VRF device: {} is in use by SYSLOG_SERVER|{}".format(syslog_vrf, syslog_entry))
if (vrf_name == 'mgmt' or vrf_name == 'management'):
vrf_delete_management_vrf(config_db)
else:
Expand Down Expand Up @@ -6087,58 +6112,6 @@ def enable(enable):
command = "ztp enable"
clicommon.run_command(command, display_cmd=True)

#
# 'syslog' group ('config syslog ...')
#
@config.group(cls=clicommon.AbbreviationGroup, name='syslog')
@click.pass_context
def syslog_group(ctx):
"""Syslog server configuration tasks"""
config_db = ConfigDBConnector()
config_db.connect()
ctx.obj = {'db': config_db}

@syslog_group.command('add')
@click.argument('syslog_ip_address', metavar='<syslog_ip_address>', required=True)
@click.pass_context
def add_syslog_server(ctx, syslog_ip_address):
""" Add syslog server IP """
if not clicommon.is_ipaddress(syslog_ip_address):
ctx.fail('Invalid ip address')
db = ctx.obj['db']
syslog_servers = db.get_table("SYSLOG_SERVER")
if syslog_ip_address in syslog_servers:
click.echo("Syslog server {} is already configured".format(syslog_ip_address))
return
else:
db.set_entry('SYSLOG_SERVER', syslog_ip_address, {'NULL': 'NULL'})
click.echo("Syslog server {} added to configuration".format(syslog_ip_address))
try:
click.echo("Restarting rsyslog-config service...")
clicommon.run_command("systemctl restart rsyslog-config", display_cmd=False)
except SystemExit as e:
ctx.fail("Restart service rsyslog-config failed with error {}".format(e))

@syslog_group.command('del')
@click.argument('syslog_ip_address', metavar='<syslog_ip_address>', required=True)
@click.pass_context
def del_syslog_server(ctx, syslog_ip_address):
""" Delete syslog server IP """
if not clicommon.is_ipaddress(syslog_ip_address):
ctx.fail('Invalid IP address')
db = ctx.obj['db']
syslog_servers = db.get_table("SYSLOG_SERVER")
if syslog_ip_address in syslog_servers:
db.set_entry('SYSLOG_SERVER', '{}'.format(syslog_ip_address), None)
click.echo("Syslog server {} removed from configuration".format(syslog_ip_address))
else:
ctx.fail("Syslog server {} is not configured.".format(syslog_ip_address))
try:
click.echo("Restarting rsyslog-config service...")
clicommon.run_command("systemctl restart rsyslog-config", display_cmd=False)
except SystemExit as e:
ctx.fail("Restart service rsyslog-config failed with error {}".format(e))

#
# 'ntp' group ('config ntp ...')
#
Expand Down
Loading

0 comments on commit abf4c47

Please sign in to comment.