Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VXLAN config and show utilities #870

Merged
merged 20 commits into from
Dec 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import utilities_common.cli as clicommon
from .utils import log


from . import aaa
from . import chassis_modules
from . import console
Expand All @@ -34,6 +33,7 @@
from . import muxcable
from . import nat
from . import vlan
from . import vxlan
from .config_mgmt import ConfigMgmtDPB

CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help', '-?'])
Expand Down Expand Up @@ -884,6 +884,7 @@ def config(ctx):
config.add_command(muxcable.muxcable)
config.add_command(nat.nat)
config.add_command(vlan.vlan)
config.add_command(vxlan.vxlan)

@config.command()
@click.option('-y', '--yes', is_flag=True, callback=_abort_if_false,
Expand Down Expand Up @@ -2930,6 +2931,56 @@ def del_vrf(ctx, vrf_name):
config_db.set_entry('VRF', vrf_name, None)


@vrf.command('add_vrf_vni_map')
@click.argument('vrfname', metavar='<vrf-name>', required=True, type=str)
@click.argument('vni', metavar='<vni>', required=True)
@click.pass_context
def add_vrf_vni_map(ctx, vrfname, vni):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you have some test coverage for this case as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok will do.

config_db = ctx.obj['config_db']
found = 0
if vrfname not in config_db.get_table('VRF').keys():
ctx.fail("vrf {} doesnt exists".format(vrfname))
if not vni.isdigit():
ctx.fail("Invalid VNI {}. Only valid VNI is accepted".format(vni))

if clicommon.vni_id_is_valid(int(vni)) is False:
ctx.fail("Invalid VNI {}. Valid range [1 to 16777215].".format(vni))

vxlan_table = config_db.get_table('VXLAN_TUNNEL_MAP')
vxlan_keys = vxlan_table.keys()
if vxlan_keys is not None:
for key in vxlan_keys:
if (vxlan_table[key]['vni'] == vni):
found = 1
break

if (found == 0):
ctx.fail("VLAN VNI not mapped. Please create VLAN VNI map entry first")

found = 0
vrf_table = config_db.get_table('VRF')
vrf_keys = vrf_table.keys()
if vrf_keys is not None:
for vrf_key in vrf_keys:
if ('vni' in vrf_table[vrf_key] and vrf_table[vrf_key]['vni'] == vni):
found = 1
break

if (found == 1):
ctx.fail("VNI already mapped to vrf {}".format(vrf_key))

config_db.mod_entry('VRF', vrfname, {"vni": vni})

@vrf.command('del_vrf_vni_map')
@click.argument('vrfname', metavar='<vrf-name>', required=True, type=str)
@click.pass_context
def del_vrf_vni_map(ctx, vrfname):
config_db = ctx.obj['config_db']
if vrfname not in config_db.get_table('VRF').keys():
ctx.fail("vrf {} doesnt exists".format(vrfname))

config_db.mod_entry('VRF', vrfname, {"vni": 0})

#
# 'route' group ('config route ...')
#
Expand Down
273 changes: 273 additions & 0 deletions config/vxlan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
import click
import utilities_common.cli as clicommon

#
# 'vxlan' group ('config vxlan ...')
#
@click.group()
def vxlan():
pass

@vxlan.command('add')
@click.argument('vxlan_name', metavar='<vxlan_name>', required=True)
@click.argument('src_ip', metavar='<src_ip>', required=True)
@clicommon.pass_db
def add_vxlan(db, vxlan_name, src_ip):
"""Add VXLAN"""
ctx = click.get_current_context()

if not clicommon.is_ipaddress(src_ip):
ctx.fail("{} invalid src ip address".format(src_ip))

vxlan_keys = db.cfgdb.get_keys('VXLAN_TUNNEL')
if not vxlan_keys:
vxlan_count = 0
else:
vxlan_count = len(vxlan_keys)

if(vxlan_count > 0):
ctx.fail("VTEP already configured.")

fvs = {'src_ip': src_ip}
db.cfgdb.set_entry('VXLAN_TUNNEL', vxlan_name, fvs)

@vxlan.command('del')
@click.argument('vxlan_name', metavar='<vxlan_name>', required=True)
@clicommon.pass_db
def del_vxlan(db, vxlan_name):
"""Del VXLAN"""
ctx = click.get_current_context()

vxlan_keys = db.cfgdb.get_keys('VXLAN_EVPN_NVO')
if not vxlan_keys:
vxlan_count = 0
else:
vxlan_count = len(vxlan_keys)

if(vxlan_count > 0):
ctx.fail("Please delete the EVPN NVO configuration.")

vxlan_keys = db.cfgdb.get_keys('CONFIG_DB', "VXLAN_TUNNEL_MAP|*")
if not vxlan_keys:
vxlan_count = 0
else:
vxlan_count = len(vxlan_keys)

if(vxlan_count > 0):
ctx.fail("Please delete all VLAN VNI mappings.")

db.cfgdb.set_entry('VXLAN_TUNNEL', vxlan_name, None)

@vxlan.group('evpn_nvo')
def vxlan_evpn_nvo():
pass

@vxlan_evpn_nvo.command('add')
@click.argument('nvo_name', metavar='<nvo_name>', required=True)
@click.argument('vxlan_name', metavar='<vxlan_name>', required=True)
@clicommon.pass_db
def add_vxlan_evpn_nvo(db, nvo_name, vxlan_name):
"""Add NVO"""
ctx = click.get_current_context()
vxlan_keys = db.cfgdb.get_keys('CONFIG_DB', "VXLAN_EVPN_NVO|*")
if not vxlan_keys:
vxlan_count = 0
else:
vxlan_count = len(vxlan_keys)

if(vxlan_count > 0):
ctx.fail("EVPN NVO already configured")

if len(db.cfgdb.get_entry('VXLAN_TUNNEL', vxlan_name)) == 0:
ctx.fail("VTEP {} not configured".format(vxlan_name))

fvs = {'source_vtep': vxlan_name}
db.cfgdb.set_entry('VXLAN_EVPN_NVO', nvo_name, fvs)

@vxlan_evpn_nvo.command('del')
@click.argument('nvo_name', metavar='<nvo_name>', required=True)
@clicommon.pass_db
def del_vxlan_evpn_nvo(db, nvo_name):
"""Del NVO"""
ctx = click.get_current_context()
vxlan_keys = db.cfgdb.get_keys('VXLAN_TUNNEL_MAP')
if not vxlan_keys:
vxlan_count = 0
else:
vxlan_count = len(vxlan_keys)

if(vxlan_count > 0):
ctx.fail("Please delete all VLAN VNI mappings.")
db.cfgdb.set_entry('VXLAN_EVPN_NVO', nvo_name, None)

@vxlan.group('map')
def vxlan_map():
pass

@vxlan_map.command('add')
@click.argument('vxlan_name', metavar='<vxlan_name>', required=True)
@click.argument('vlan', metavar='<vlan_id>', required=True)
@click.argument('vni', metavar='<vni>', required=True)
@clicommon.pass_db
def add_vxlan_map(db, vxlan_name, vlan, vni):
"""Add VLAN-VNI map entry"""
ctx = click.get_current_context()

if not vlan.isdigit():
ctx.fail("Invalid vlan {}. Only valid vlan is accepted".format(vni))
if clicommon.is_vlanid_in_range(int(vlan)) is False:
ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ")
if not vni.isdigit():
ctx.fail("Invalid VNI {}. Only valid VNI is accepted".format(vni))
if clicommon.vni_id_is_valid(int(vni)) is False:
ctx.fail("Invalid VNI {}. Valid range [1 to 16777215].".format(vni))

vlan_name = "Vlan" + vlan

if len(db.cfgdb.get_entry('VXLAN_TUNNEL', vxlan_name)) == 0:
ctx.fail("VTEP {} not configured".format(vxlan_name))

if len(db.cfgdb.get_entry('VLAN', vlan_name)) == 0:
ctx.fail("{} not configured".format(vlan_name))

vxlan_table = db.cfgdb.get_table('VXLAN_TUNNEL_MAP')
vxlan_keys = vxlan_table.keys()
if vxlan_keys is not None:
for key in vxlan_keys:
if (vxlan_table[key]['vlan'] == vlan_name):
ctx.fail(" Vlan Id already mapped ")
if (vxlan_table[key]['vni'] == vni):
ctx.fail(" VNI Id already mapped ")

fvs = {'vni': vni,
'vlan' : vlan_name}
mapname = vxlan_name + '|' + 'map_' + vni + '_' + vlan_name
db.cfgdb.set_entry('VXLAN_TUNNEL_MAP', mapname, fvs)

@vxlan_map.command('del')
@click.argument('vxlan_name', metavar='<vxlan_name>', required=True)
@click.argument('vlan', metavar='<vlan_id>', required=True)
@click.argument('vni', metavar='<vni>', required=True)
@clicommon.pass_db
def del_vxlan_map(db, vxlan_name, vlan, vni):
"""Del VLAN-VNI map entry"""
ctx = click.get_current_context()

if not vlan.isdigit():
ctx.fail("Invalid vlan {}. Only valid vlan is accepted".format(vni))
if clicommon.is_vlanid_in_range(int(vlan)) is False:
ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ")
if not vni.isdigit():
ctx.fail("Invalid VNI {}. Only valid VNI is accepted".format(vni))
if clicommon.vni_id_is_valid(int(vni)) is False:
ctx.fail("Invalid VNI {}. Valid range [1 to 16777215].".format(vni))

if len(db.cfgdb.get_entry('VXLAN_TUNNEL', vxlan_name)) == 0:
ctx.fail("VTEP {} not configured".format(vxlan_name))
found = 0
vrf_table = db.cfgdb.get_table('VRF')
vrf_keys = vrf_table.keys()
if vrf_keys is not None:
for vrf_key in vrf_keys:
if ('vni' in vrf_table[vrf_key] and vrf_table[vrf_key]['vni'] == vni):
found = 1
break

if (found == 1):
ctx.fail("VNI mapped to vrf {}, Please remove VRF VNI mapping".format(vrf_key))

mapname = vxlan_name + '|' + 'map_' + vni + '_' + vlan
db.cfgdb.set_entry('VXLAN_TUNNEL_MAP', mapname, None)
mapname = vxlan_name + '|' + 'map_' + vni + '_Vlan' + vlan
db.cfgdb.set_entry('VXLAN_TUNNEL_MAP', mapname, None)

@vxlan.group('map_range')
def vxlan_map_range():
pass

@vxlan_map_range.command('add')
@click.argument('vxlan_name', metavar='<vxlan_name>', required=True)
@click.argument('vlan_start', metavar='<vlan_start>', required=True, type=int)
@click.argument('vlan_end', metavar='<vlan_end>', required=True, type=int)
@click.argument('vni_start', metavar='<vni_start>', required=True, type=int)
@clicommon.pass_db
def add_vxlan_map_range(db, vxlan_name, vlan_start, vlan_end, vni_start):
"""Add Range of vlan-vni mappings"""
ctx = click.get_current_context()
if clicommon.is_vlanid_in_range(vlan_start) is False:
ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ")
if clicommon.is_vlanid_in_range(vlan_end) is False:
ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ")
if (vlan_start > vlan_end):
ctx.fail("vlan_end should be greater or equal to vlan_start")
if clicommon.vni_id_is_valid(vni_start) is False:
ctx.fail("Invalid VNI {}. Valid range [1 to 16777215].".format(vni_start))
if clicommon.vni_id_is_valid(vni_start+vlan_end-vlan_start) is False:
ctx.fail("Invalid VNI End {}. Valid range [1 to 16777215].".format(vni_start))

if len(db.cfgdb.get_entry('VXLAN_TUNNEL', vxlan_name)) == 0:
ctx.fail("VTEP {} not configured".format(vxlan_name))
vlan_end = vlan_end + 1
vxlan_table = db.cfgdb.get_table('VXLAN_TUNNEL_MAP')
vxlan_keys = vxlan_table.keys()

for vid in range (vlan_start, vlan_end):
vlan_name = 'Vlan{}'.format(vid)
vnid = vni_start+vid-vlan_start
vni_name = '{}'.format(vnid)
match_found = 'no'
if len(db.cfgdb.get_entry('VLAN', vlan_name)) == 0:
click.echo("{} not configured".format(vlan_name))
continue
if vxlan_keys is not None:
for key in vxlan_keys:
if (vxlan_table[key]['vlan'] == vlan_name):
print(vlan_name + " already mapped")
match_found = 'yes'
break
if (vxlan_table[key]['vni'] == vni_name):
print("VNI:" + vni_name + " already mapped ")
match_found = 'yes'
break
if (match_found == 'yes'):
continue
fvs = {'vni': vni_name,
'vlan' : vlan_name}
mapname = vxlan_name + '|' + 'map_' + vni_name + '_' + vlan_name
db.cfgdb.set_entry('VXLAN_TUNNEL_MAP', mapname, fvs)

@vxlan_map_range.command('del')
@click.argument('vxlan_name', metavar='<vxlan_name>', required=True)
@click.argument('vlan_start', metavar='<vlan_start>', required=True, type=int)
@click.argument('vlan_end', metavar='<vlan_end>', required=True, type=int)
@click.argument('vni_start', metavar='<vni_start>', required=True, type=int)
@clicommon.pass_db
def del_vxlan_map_range(db, vxlan_name, vlan_start, vlan_end, vni_start):
"""Del Range of vlan-vni mappings"""
ctx = click.get_current_context()
if clicommon.is_vlanid_in_range(vlan_start) is False:
ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ")
if clicommon.is_vlanid_in_range(vlan_end) is False:
ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ")
if (vlan_start > vlan_end):
ctx.fail("vlan_end should be greater or equal to vlan_start")
if clicommon.vni_id_is_valid(vni_start) is False:
ctx.fail("Invalid VNI {}. Valid range [1 to 16777215].".format(vni_start))
if clicommon.vni_id_is_valid(vni_start+vlan_end-vlan_start) is False:
ctx.fail("Invalid VNI End {}. Valid range [1 to 16777215].".format(vni_start))

if len(db.cfgdb.get_entry('VXLAN_TUNNEL', vxlan_name)) == 0:
ctx.fail("VTEP {} not configured".format(vxlan_name))

vlan_end = vlan_end + 1
for vid in range (vlan_start, vlan_end):
vlan_name = 'Vlan{}'.format(vid)
vnid = vni_start+vid-vlan_start
vni_name = '{}'.format(vnid)
if clicommon.is_vni_vrf_mapped(db, vni_name) is False:
print("Skipping Vlan {} VNI {} mapped delete. ".format(vlan_name, vni_name))
continue

mapname = vxlan_name + '|' + 'map_' + vni_name + '_' + vlan_name
db.cfgdb.set_entry('VXLAN_TUNNEL_MAP', mapname, None)

1 change: 1 addition & 0 deletions scripts/fast-reboot
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ function backup_database()
if not string.match(k, 'FDB_TABLE|') and not string.match(k, 'WARM_RESTART_TABLE|') \
and not string.match(k, 'MIRROR_SESSION_TABLE|') \
and not string.match(k, 'WARM_RESTART_ENABLE_TABLE|') \
and not string.match(k, 'VXLAN_TUNNEL_TABLE|') \
and not string.match(k, 'BUFFER_MAX_PARAM_TABLE|') then
redis.call('del', k)
end
Expand Down
1 change: 0 additions & 1 deletion show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,5 @@ def ztp(status, verbose):
cmd = cmd + " --verbose"
run_command(cmd, display_cmd=verbose)


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change doesn't look obligatory.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will handle this in the next PR.

if __name__ == '__main__':
cli()
Loading