-
Notifications
You must be signed in to change notification settings - Fork 819
[config]Static routes to config_db #1534
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
Changes from 11 commits
47696b9
7de1946
eb87991
93220d9
cab6c7a
fbff2e4
1a02681
6392385
91723c8
091082b
bc26317
605f455
5e41d96
e4b14b0
11d74e9
847399f
319a3ea
bc14735
fb6d0eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ | |
| import subprocess | ||
| import sys | ||
| import time | ||
| import itertools | ||
|
|
||
| from socket import AF_INET, AF_INET6 | ||
| from minigraph import parse_device_desc_xml | ||
|
|
@@ -783,6 +784,49 @@ def validate_mirror_session_config(config_db, session_name, dst_port, src_port, | |
|
|
||
| return True | ||
|
|
||
| def cli_sroute_to_config(ctx, command_str): | ||
| if len(command_str) < 4 or len(command_str) > 9: | ||
| ctx.fail("argument is not in pattern prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop <[vrf <vrf_name>] <A.B.C.D>>|<dev <dev_name>>!") | ||
| if "prefix" not in command_str: | ||
| ctx.fail("argument is incomplete, prefix not found!") | ||
| if "nexthop" not in command_str: | ||
| ctx.fail("argument is incomplete, nexthop not found!") | ||
| for i in range(0,len(command_str)): | ||
| if "nexthop" == command_str[i]: | ||
| prefix_str = command_str[:i] | ||
| nexthop_str = command_str[i:] | ||
|
|
||
| config_entry = {} | ||
| ip_prefix = "" | ||
| vrf_name = "" | ||
|
|
||
| if prefix_str: | ||
| if len(prefix_str) == 2: | ||
| ip_prefix = prefix_str[1] | ||
| elif len(prefix_str) == 4: | ||
| vrf_name = prefix_str[2] | ||
| ip_prefix = prefix_str[3] | ||
| else: | ||
| ctx.fail("prefix is not in pattern!") | ||
| if nexthop_str: | ||
| if len(nexthop_str) == 2: | ||
| config_entry["nexthop"] = nexthop_str[1] | ||
| elif len(nexthop_str) == 3: | ||
| config_entry["ifname"] = nexthop_str[2] | ||
| elif len(nexthop_str) == 4: | ||
| config_entry["nexthop"] = nexthop_str[3] | ||
| config_entry["nexthop-vrf"] = nexthop_str[2] | ||
| else: | ||
| ctx.fail("nexthop is not in pattern!") | ||
|
|
||
| key = "" | ||
| if not vrf_name == "": | ||
| key = vrf_name + "|" + ip_prefix | ||
| else: | ||
| key = ip_prefix | ||
|
|
||
| return key, config_entry | ||
|
|
||
| def update_sonic_environment(): | ||
| """Prepare sonic environment variable using SONiC environment template file. | ||
| """ | ||
|
|
@@ -3153,111 +3197,89 @@ def del_vrf_vni_map(ctx, vrfname): | |
| @click.pass_context | ||
| def route(ctx): | ||
| """route-related configuration tasks""" | ||
| pass | ||
| config_db = ConfigDBConnector() | ||
| config_db.connect() | ||
| ctx.obj = {} | ||
| ctx.obj['config_db'] = config_db | ||
|
|
||
| @route.command('add', context_settings={"ignore_unknown_options":True}) | ||
| @click.argument('command_str', metavar='prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop <[vrf <vrf_name>] <A.B.C.D>>|<dev <dev_name>>', nargs=-1, type=click.Path()) | ||
| @click.pass_context | ||
| def add_route(ctx, command_str): | ||
| """Add route command""" | ||
| if len(command_str) < 4 or len(command_str) > 9: | ||
| ctx.fail("argument is not in pattern prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop <[vrf <vrf_name>] <A.B.C.D>>|<dev <dev_name>>!") | ||
| if "prefix" not in command_str: | ||
| ctx.fail("argument is incomplete, prefix not found!") | ||
| if "nexthop" not in command_str: | ||
| ctx.fail("argument is incomplete, nexthop not found!") | ||
| for i in range(0, len(command_str)): | ||
| if "nexthop" == command_str[i]: | ||
| prefix_str = command_str[:i] | ||
| nexthop_str = command_str[i:] | ||
| vrf_name = "" | ||
| cmd = 'sudo vtysh -c "configure terminal" -c "ip route' | ||
| if prefix_str: | ||
| if len(prefix_str) == 2: | ||
| prefix_mask = prefix_str[1] | ||
| cmd += ' {}'.format(prefix_mask) | ||
| elif len(prefix_str) == 4: | ||
| vrf_name = prefix_str[2] | ||
| prefix_mask = prefix_str[3] | ||
| cmd += ' {}'.format(prefix_mask) | ||
| else: | ||
| ctx.fail("prefix is not in pattern!") | ||
| if nexthop_str: | ||
| if len(nexthop_str) == 2: | ||
| ip = nexthop_str[1] | ||
| if vrf_name == "": | ||
| cmd += ' {}'.format(ip) | ||
| else: | ||
| cmd += ' {} vrf {}'.format(ip, vrf_name) | ||
| elif len(nexthop_str) == 3: | ||
| dev_name = nexthop_str[2] | ||
| if vrf_name == "": | ||
| cmd += ' {}'.format(dev_name) | ||
| else: | ||
| cmd += ' {} vrf {}'.format(dev_name, vrf_name) | ||
| elif len(nexthop_str) == 4: | ||
| vrf_name_dst = nexthop_str[2] | ||
| ip = nexthop_str[3] | ||
| if vrf_name == "": | ||
| cmd += ' {} nexthop-vrf {}'.format(ip, vrf_name_dst) | ||
| config_db = ctx.obj['config_db'] | ||
| key, route = cli_sroute_to_config(ctx, command_str) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that we are writing to DB, lets check the correctness of key (like a valid ip prefix) |
||
| # Check if exist entry with key | ||
| keys = config_db.get_keys('STATIC_ROUTE') | ||
| if key in keys: | ||
| # If exist update current entry | ||
| current_entry = config_db.get_entry('STATIC_ROUTE', key) | ||
|
|
||
| ENTRY_NAME = ['nexthop', 'nexthop-vrf', 'ifname'] | ||
| for entry in ENTRY_NAME: | ||
| if not entry in current_entry: | ||
| current_entry[entry] = '' | ||
shi-su marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if entry in route: | ||
| current_entry[entry] += ',' + route[entry] | ||
| else: | ||
| cmd += ' {} vrf {} nexthop-vrf {}'.format(ip, vrf_name, vrf_name_dst) | ||
| else: | ||
| ctx.fail("nexthop is not in pattern!") | ||
| cmd += '"' | ||
| clicommon.run_command(cmd) | ||
| current_entry[entry] += ',' | ||
shi-su marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| config_db.set_entry("STATIC_ROUTE", key, current_entry) | ||
| else: | ||
| config_db.set_entry("STATIC_ROUTE", key, route) | ||
shi-su marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| @route.command('del', context_settings={"ignore_unknown_options":True}) | ||
| @click.argument('command_str', metavar='prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop <[vrf <vrf_name>] <A.B.C.D>>|<dev <dev_name>>', nargs=-1, type=click.Path()) | ||
| @click.pass_context | ||
| def del_route(ctx, command_str): | ||
| """Del route command""" | ||
| if len(command_str) < 4 or len(command_str) > 9: | ||
| ctx.fail("argument is not in pattern prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop <[vrf <vrf_name>] <A.B.C.D>>|<dev <dev_name>>!") | ||
| if "prefix" not in command_str: | ||
| ctx.fail("argument is incomplete, prefix not found!") | ||
| if "nexthop" not in command_str: | ||
| ctx.fail("argument is incomplete, nexthop not found!") | ||
| for i in range(0, len(command_str)): | ||
| if "nexthop" == command_str[i]: | ||
| prefix_str = command_str[:i] | ||
| nexthop_str = command_str[i:] | ||
| vrf_name = "" | ||
| cmd = 'sudo vtysh -c "configure terminal" -c "no ip route' | ||
| if prefix_str: | ||
| if len(prefix_str) == 2: | ||
| prefix_mask = prefix_str[1] | ||
| cmd += ' {}'.format(prefix_mask) | ||
| elif len(prefix_str) == 4: | ||
| vrf_name = prefix_str[2] | ||
| prefix_mask = prefix_str[3] | ||
| cmd += ' {}'.format(prefix_mask) | ||
| else: | ||
| ctx.fail("prefix is not in pattern!") | ||
| if nexthop_str: | ||
| if len(nexthop_str) == 2: | ||
| ip = nexthop_str[1] | ||
| if vrf_name == "": | ||
| cmd += ' {}'.format(ip) | ||
| else: | ||
| cmd += ' {} vrf {}'.format(ip, vrf_name) | ||
| elif len(nexthop_str) == 3: | ||
| dev_name = nexthop_str[2] | ||
| if vrf_name == "": | ||
| cmd += ' {}'.format(dev_name) | ||
| else: | ||
| cmd += ' {} vrf {}'.format(dev_name, vrf_name) | ||
| elif len(nexthop_str) == 4: | ||
| vrf_name_dst = nexthop_str[2] | ||
| ip = nexthop_str[3] | ||
| if vrf_name == "": | ||
| cmd += ' {} nexthop-vrf {}'.format(ip, vrf_name_dst) | ||
| config_db = ctx.obj['config_db'] | ||
| key, route = cli_sroute_to_config(ctx, command_str) | ||
| keys = config_db.get_keys('STATIC_ROUTE') | ||
| prefix_tuple = tuple(key.split('|')) | ||
| if not key in keys and not prefix_tuple in keys: | ||
| ctx.fail('Route {} doesnt exist'.format(key)) | ||
| else: | ||
| current_entry = config_db.get_entry('STATIC_ROUTE', key) | ||
|
|
||
| ENTRY_NAME = ['nexthop', 'nexthop-vrf', 'ifname'] | ||
| nh = [''] | ||
| nh_vrf = [''] | ||
| ifname = [''] | ||
| if 'nexthop' in current_entry: | ||
| nh = current_entry['nexthop'].split(',') | ||
| if 'nexthop-vrf' in current_entry: | ||
| nh_vrf = current_entry['nexthop-vrf'].split(',') | ||
| if 'ifname' in current_entry: | ||
| ifname = current_entry['ifname'].split(',') | ||
|
|
||
| nh_zip = list(itertools.zip_longest(nh, nh_vrf, ifname, fillvalue='')) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you add some comments to understand the logic in this section? |
||
| cmd_tuple = () | ||
|
|
||
| for entry in ENTRY_NAME: | ||
| if entry in route: | ||
| cmd_tuple += (route[entry],) | ||
| else: | ||
| cmd += ' {} vrf {} nexthop-vrf {}'.format(ip, vrf_name, vrf_name_dst) | ||
| cmd_tuple += ('',) | ||
|
|
||
| if cmd_tuple in nh_zip: | ||
| idx = nh_zip.index(cmd_tuple) | ||
| if len(nh) - 1 >= idx: | ||
| del nh[idx] | ||
| if len(nh_vrf) - 1 >= idx: | ||
| del nh_vrf[idx] | ||
| if len(ifname) - 1 >= idx: | ||
| del ifname[idx] | ||
| else: | ||
| ctx.fail("nexthop is not in pattern!") | ||
| cmd += '"' | ||
| clicommon.run_command(cmd) | ||
| ctx.fail('Not found {} in {}'.format(cmd_tuple, key)) | ||
|
|
||
| if len(nh) == 0 or (len(nh) == 1 and nh[0] == ''): | ||
| config_db.set_entry("STATIC_ROUTE", key, None) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if user just deletes the route without mentioning any nexthops, then the route is expected to be fully deleted.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the user tries to delete a route without nexthop (for example, 'сonfig del config route del prefix 1.2.3.4/32'), he will receive an error: 'argument is not in pattern'. So if the user has previously added ECMP routes, he must remove them one by one.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, user should be able to delete the entire route at once. |
||
| else: | ||
| current_entry['nexthop'] = ','.join((str(e)) for e in nh) | ||
| current_entry['nexthop-vrf'] = ','.join((str(e)) for e in nh_vrf) | ||
| current_entry['ifname'] = ','.join((str(e)) for e in ifname) | ||
| config_db.set_entry("STATIC_ROUTE", key, current_entry) | ||
|
|
||
| # | ||
| # 'acl' group ('config acl ...') | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add the support for multi asic ?
Similar to how it is done for interface command https://github.com/Azure/sonic-utilities/blob/08337aa7637b290bb8407c38b2a5dbe3e8383b3e/config/main.py#L2359
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@arlakshm, can we add multiasic as another enhancement PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@prsunny, Sure. Can we create an issue or task to track this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created issue - #1608