Adding ONOS Segment Routing CLI files to new repo
diff --git a/cli/run_config.py b/cli/run_config.py
new file mode 100755
index 0000000..e3fc80c
--- /dev/null
+++ b/cli/run_config.py
@@ -0,0 +1,1096 @@
+#
+# Copyright (c) 2012,2013 Big Switch Networks, Inc.
+#
+# Licensed under the Eclipse Public License, Version 1.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+
+# sdnsh - The Controller Shell
+
+#
+# show running-config
+# and associated
+#
+
+import datetime
+import re
+import utif
+import modi
+
+from midw import *
+from vnsw import *
+
+
+def init_running_config(bs, modi):
+ global sdnsh, mi
+ sdnsh = bs
+ mi = modi
+
+
+running_config_registry = {}
+
+running_config_command_choices = {
+ 'optional' : True,
+ 'choices' : (
+ )
+}
+
+#
+# --------------------------------------------------------------------------------
+
+def register_running_config(name, order, feature, running_config_proc, command_tuple = None):
+ """
+ Register a callback to manage the display of component running configs
+
+ @feature a predicate to call, returns True/False to enable/disable this entry
+ """
+ running_config_registry[name] = { 'order' : order,
+ 'feature' : feature,
+ 'proc' : running_config_proc }
+ if command_tuple:
+ global running_config_command_choices
+ running_config_command_choices['choices'] += command_tuple
+
+#
+# --------------------------------------------------------------------------------
+
+def registry_items_enabled():
+ """
+ Return a list of active running config entries, this is a subset of
+ the registered items, only items which are currently enabled via features
+ """
+ return [name for name in running_config_registry.keys()
+ if running_config_registry[name]['feature'] == None or
+ running_config_registry[name]['feature'](sdnsh) == True]
+
+
+#
+# --------------------------------------------------------------------------------
+
+def perform_running_config(name, context, config, words):
+ """
+ Callout to append to config
+ """
+ if name in running_config_registry:
+ running_config_registry[name]['proc'](context, config, words)
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_include_alias(config, indent, obj_type, key):
+ """
+ Given an obj_type and an id, add the alias for this obj_type
+ to the config.
+
+ The table lookup is a bit difficult to understand; keep in
+ mind, for example, the 'host-alias' table has a primary
+ key called id, and a foreign key called 'host'.
+
+ Return False if no alias exists, and True when one was added to 'config'
+ """
+ if obj_type in mi.alias_obj_type_xref:
+ for alias in mi.alias_obj_type_xref[obj_type]:
+ field = mi.alias_obj_type_field(alias)
+ try:
+ row = sdnsh.get_table_from_store(alias, field, key)
+ except:
+ row = []
+
+ if len(row) > 1:
+ sdnsh.warning('%s %s: alias count > 1' % (alias, key))
+ elif len(row) == 1:
+ config.append("%s%s %s\n" %
+ (' ' * indent, alias, row[0]['id']))
+
+
+#
+# --------------------------------------------------------------------------------
+
+def not_default_value(obj_type, field, value):
+ """
+ Return True when the value passed in is not the default value.
+ """
+ default_value = mi.field_default_value(obj_type, field)
+ if (mi.is_null_allowed(obj_type, field) and value != None) or \
+ (not mi.is_null_allowed(obj_type, field) and default_value != None
+ and (default_value != value)):
+ return True
+ return False
+
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_include_field(config, obj_type, field, value,
+ indent, prefix = ""):
+ """
+ Identify fields of obj_types who's values differ from the default
+ values, since these need to be included into the running-config
+ """
+ if mi.not_default_value(obj_type, field, value):
+ #
+ if mi.is_field_string(obj_type, field):
+ config.append(' ' * (indent + indent) + prefix + field +
+ " %s\n" % utif.quote_string(value))
+ else:
+ config.append(' ' * (indent + indent) + prefix + field +
+ ' %s\n' % value)
+
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_vns_acl(config, vns_name, acl, vns_acl_entries,indent=0):
+ """
+ factored out due to excessive indent level in do_show_running_config
+ and to allow re-use in 'show vns <n> running-config'
+ """
+ key = mi.pk('vns-access-list')
+
+ config.append(' ' *2*indent + 'access-list %s\n' % acl['name'])
+
+ #
+ vns_acl_fields = ['priority', 'description']
+ for field in vns_acl_fields:
+ running_config_include_field(config,
+ 'vns-access-list', field,
+ acl.get(field, ''), indent+1)
+
+ vns_acl_entries = sorted(vns_acl_entries,
+ cmp=lambda x,y: int(x['rule']) - int(y['rule']))
+
+ for acl_entry in vns_acl_entries:
+ config.append(' ' *2*(indent+1) + '%s %s %s %s\n' % (
+ acl_entry['rule'],
+ acl_entry['action'],
+ acl_entry['type'],
+ vns_acl_entry_to_text(acl_entry)))
+
+
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_vns_if_rule(config,
+ vns_if_rule_entries,indent=0):
+ """
+ factored out due to excessive indent level in do_show_running_config
+ and to allow re-use in 'show vns <n> running-config'
+
+ 'vns_if_rule_entries' are all the entries to concatenate to the confi
+ """
+ for rule in vns_if_rule_entries:
+ config.append(' ' *2*indent +'interface-rule %s\n' % rule['rule'])
+
+ #
+ # mi.obj_type_config_fields('vns-interface-rule') isn't used
+ # here since switch/port is collected together (managed together)
+ for field in ['description', 'active', 'priority', ]:
+ running_config_include_field(config,
+ 'vns-interface-rule', field,
+ rule.get(field, ''), indent+1,)
+
+ for field in [ 'mac', 'ip-subnet', 'vlans', 'tags']:
+ running_config_include_field(config,
+ 'vns-interface-rule', field,
+ rule.get(field, ''), indent+1, 'match ')
+ if rule.get('allow-multiple', False):
+ config.append(' ' * 2*(indent+1) + 'allow-multiple\n');
+ if rule.get('vlan-tag-on-egress', False):
+ config.append(' ' * 2*(indent+1) + 'vlan-tag-on-egress\n');
+
+ #
+ # Manage switch and ports differently, placing both on the
+ # same line when ports exist, and replacing the switch alias
+ # when its available.
+ if 'switch' in rule:
+ dpid_or_alias = alias_lookup_with_foreign_key('switch-alias',
+ rule['switch'])
+ if dpid_or_alias == None:
+ dpid_or_alias = rule['switch'] # dpid
+ if 'ports' in rule:
+ config.append(' ' *2*(indent+1) + 'match switch %s %s\n' %
+ (dpid_or_alias, rule['ports']))
+ else:
+ config.append(' ' *2*(indent+1) + 'match switch %s\n' % dpid_or_alias)
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_active_vns_interfaces(vns_name, vns_interface_acl):
+ """
+ Return a list of interfaces which have configuration information needing
+ to be saved
+ """
+ active = {}
+ key = mi.pk('vns-interface-access-list')
+
+ for if_acl in vns_interface_acl:
+ id_fields = if_acl[key].split('|')
+ vns_id= id_fields[0] +'|' + id_fields[1]
+ if vns_id == vns_name:
+ active[id_fields[2]] = None
+
+ return active.keys()
+#
+#--------------------------------------------------------------
+#
+def running_config_tenant_details(config, tenant):
+ """
+ Display the details for the fields of a tenant which may have
+ non-default values.
+ """
+ if tenant['active'] != mi.field_default_value('tenant', 'active'):
+ config.append('no active\n')
+ # mi.obj_type_config_fields('vns-definition') only shows fields which are
+ # user editable, which is none, since only the command descriptions
+ # modify the fields. XXX func which returns fields which can be updated
+ # via command descriptions?
+ tenant_fields = ['description', 'origin']
+
+ for field in sorted(tenant_fields):
+ running_config_include_field(config,
+ 'tenant', field,
+ tenant.get(field,''), 1)
+
+#
+#--------------------------------------------------------------
+#
+def running_config_tenant_router_details(config, vrouter,indent=0):
+ """
+ Display the details for the fields of a vrouter which may have
+ non-default values.
+ """
+ vrouter_fields = ['description', 'origin']
+
+ for field in sorted(vrouter_fields):
+ running_config_include_field(config,
+ 'virtualrouter', field,
+ vrouter.get(field,''), indent+1)
+
+#
+#--------------------------------------------------------------
+#
+def running_config_router_interface_details(config, vr_interface, indent=0):
+ """
+ Display the details for the fields of a router interface which may have
+ non-default values.
+ """
+ if 'vns-connected' in vr_interface and vr_interface['vns-connected'] is not None:
+ vns=vr_interface['vns-connected'].split('|')
+ vns_name=vns[1]
+ config.append(' ' *2*indent + 'interface %s vns %s \n' % (vr_interface['vriname'],vns_name))
+ elif 'router-connected' in vr_interface and vr_interface['router-connected'] is not None:
+ router=vr_interface['router-connected'].split('|')
+ tenant_name=router[0]
+ router_name=router[1]
+ config.append(' ' *2*indent +'interface %s tenant %s %s \n' % (vr_interface['vriname'],tenant_name, router_name))
+
+ if vr_interface['active'] != mi.field_default_value('virtualrouter-interface', 'active'):
+ config.append(' ' *2*(indent+1) + 'no active\n')
+
+ vri_fields = ['origin']
+
+ for field in sorted(vri_fields):
+ running_config_include_field(config,
+ 'virtualrouter-interface', field,
+ vr_interface.get(field,''), indent+1)
+ try:
+ ip_address_pool = sdnsh.get_table_from_store('interface-address-pool','virtual-router-interface', vr_interface['id'], "exact")
+ except Exception:
+ ip_address_pool = {}
+ pass
+ for ip_address in ip_address_pool:
+ config.append(' ' *2*(indent+1) + 'ip %s\n' % (utif.ip_and_neg_mask(ip_address['ip-address'],ip_address['subnet-mask'])))
+
+#
+#--------------------------------------------------------------
+#
+def running_config_router_rule_details(config, vr_route,indent=0):
+ """
+ Display the details for the fields of a router interface which may have
+ non-default values.
+ """
+ config_str=' ' * 2*indent
+ if 'src-tenant' in vr_route and vr_route['src-tenant'] is not None:
+ config_str+=('route from tenant %s' % vr_route['src-tenant'])
+ if 'src-vns' in vr_route and vr_route['src-vns'] is not None:
+ vns=vr_route['src-vns'].split('|')
+ vns_name=vns[1]
+ config_str+=(' vns %s' % vns_name)
+ else:
+ if 'src-ip' in vr_route and vr_route['src-ip'] is not None:
+ config_str+=('route from %s' % (utif.ip_and_neg_mask(vr_route['src-ip'],vr_route['src-ip-mask'])))
+ else:
+ config_str+=('route from any')
+
+ config_str+=(' to')
+
+ if 'dst-tenant' in vr_route and vr_route['dst-tenant'] is not None:
+ config_str+=(' tenant %s' % vr_route['dst-tenant'])
+ if 'dst-vns' in vr_route and vr_route['dst-vns'] is not None:
+ vns=vr_route['dst-vns'].split('|')
+ vns_name=vns[1]
+ config_str+=(' vns %s' % vns_name)
+ else:
+ if 'dst-ip' in vr_route and vr_route['dst-ip'] is not None:
+ config_str+=(' %s' % (utif.ip_and_neg_mask(vr_route['dst-ip'],vr_route['dst-ip-mask'])))
+ else:
+ config_str+=(' any')
+
+ if 'nh-ip' in vr_route and vr_route['nh-ip'] is not None:
+ config_str+=(' %s' % vr_route['nh-ip'])
+ if 'gateway-pool' in vr_route and vr_route['gateway-pool'] is not None:
+ gwpool= vr_route['gateway-pool'].split('|')
+ gwpool_name=gwpool[-1]
+ config_str+=(' gw-pool %s' % gwpool_name)
+ if 'outgoing-intf' in vr_route and vr_route['outgoing-intf'] is not None:
+ intf= vr_route['outgoing-intf'].split('|')
+ intf_name=intf[-1]
+ config_str+=(' %s' % intf_name)
+
+ config_str+=(' %s\n' % vr_route['action'])
+ config.append(config_str)
+
+#
+#--------------------------------------------------------------
+#
+def running_config_router_gwpool_details(config, vr_gwpool, indent=0):
+ """
+ Display the details for the fields of a router gateway pool which may have
+ non-default values.
+ """
+ config.append(' ' *2*indent + 'gateway-pool %s\n' % (vr_gwpool['vrgwname']))
+
+ try:
+ gw_address_pool = sdnsh.get_table_from_store('gateway-address-pool','virtual-router-gwpool', vr_gwpool['id'], "exact")
+ except Exception:
+ gw_address_pool = {}
+ pass
+ for gw_address in gw_address_pool:
+ config.append(' ' *2*(indent+1) + 'ip %s\n' % gw_address['ip-address'])
+
+#
+# --------------------------------------------------------------------------------
+
+
+def running_config_vns_details(config, vns,indent=0):
+ """
+ Display the details for the fields of a vns which may have
+ non-default values.
+ """
+ if vns['active'] != mi.field_default_value('vns-definition', 'active'):
+ config.append(' ' *2*indent + 'no active\n')
+ # mi.obj_type_config_fields('vns-definition') only shows fields which are
+ # user editable, which is none, since only the command descriptions
+ # modify the fields. XXX func which returns fields which can be updated
+ # via command descriptions?
+ vns_fields = ['description', 'priority', 'origin',
+ 'arp-mode', 'dhcp-mode', 'dhcp-ip', 'broadcast']
+
+ for field in sorted(vns_fields):
+ running_config_include_field(config,
+ 'vns-definition', field,
+ vns.get(field,''), indent)
+ vns_use_fields = ['address-space']
+ for field in sorted(vns_use_fields):
+ running_config_include_field(config,
+ 'vns-definition', field,
+ vns.get(field,''), indent, "use ")
+
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_vns_if_and_access_group(config, vns_name, if_name, vns_interface_acl,indent=0):
+ """
+ Decorate the config with access_group details
+ """
+ obj_type = 'vns-interface-access-list'
+ key = mi.pk(obj_type)
+
+ for if_acl in vns_interface_acl:
+ # add compound key field names ('vns', 'name', etc) into if_acl
+ mi.split_compound_into_dict(obj_type, key, if_acl)
+ vns_id=if_acl['tenant'] +'|' + if_acl['vnsname']
+ if vns_id == vns_name and if_acl['interface'] == if_name:
+ config.append(' '*2*indent + "access-group %s %s\n" %
+ (if_acl['name'], if_acl['in-out']))
+
+
+
+#
+# --------------------------------------------------------------------------------
+
+def firewall_rule(rule):
+ """
+ Return a string, the command which enabled this particular firewall rule
+ """
+ tcp_ports = {6633: "openflow",
+ 80: "web",
+ 443: "ssl",
+ 22: "ssh"}
+
+ src = ''
+ if 'src-ip' in rule and rule['src-ip'] != '':
+ src = 'from %s ' % rule['src-ip']
+ dst = ''
+ if 'vrrp-ip' in rule and rule['vrrp-ip'] != '':
+ dst = 'local-ip %s ' % rule['vrrp-ip']
+
+ if rule['proto'] == 'tcp' and rule['port'] in tcp_ports:
+ allow = tcp_ports[rule['port']]
+ return "firewall allow %s%s%s" % (src, dst, allow)
+ elif rule['proto'] == 'vrrp':
+ return "firewall allow %s%svrrp" % (src, dst)
+ else:
+ return ("firewall allow %s%s%s %s" %
+ (src, dst, rule['proto'], rule['port']))
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_firewall_rule(config, rule):
+ """
+ Return a string, the command which enabled this particular firewall rule
+ """
+ config.append(" %s\n" % firewall_rule(rule))
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_feature(context, config, words):
+ """
+ Decorate config with the feature commands
+ """
+ feature = sdnsh.get_table_from_store('feature')
+
+ if len(feature) == 0:
+ return
+
+ f_config = []
+
+ for field in mi.obj_type_fields('feature'):
+ if field == mi.pk('feature'):
+ continue
+ if mi.is_foreign_key('feature', field):
+ continue
+ default_value = mi.field_default_value('feature', field)
+ name = field.replace('-feature','')
+ if mi.not_default_value('feature', field, feature[0][field]):
+ if default_value == True:
+ f_config.append('no feature %s\n' % name)
+ else:
+ f_config.append('feature %s\n' % name)
+
+ if len(f_config) > 0:
+ config.append('! features enabled/disabled\n')
+ config += f_config
+
+feature_running_config_tuple = (
+(
+ {
+ 'optional' : False,
+ 'field' : 'running-config',
+ 'type' : 'enum',
+ 'values' : 'feature',
+ 'short-help' : 'Configuration for enabled/disabled features',
+ 'doc' : 'running-config|show-feature',
+ },
+ ),
+)
+
+register_running_config('feature', 1000, None, running_config_feature, feature_running_config_tuple)
+
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_controller_node(context, config, words):
+ """
+ Decorate config with controller-node details.
+ """
+ #
+ controller_nodes = sdnsh.get_table_from_store("controller-node")
+ controller_ifs = sdnsh.get_table_from_store("controller-interface")
+ controller_dnses = sdnsh.get_table_from_store("controller-domain-name-server")
+ firewall_rules = sdnsh.get_table_from_store("firewall-rule")
+
+ controller_alias_dict = create_obj_type_dict('controller-alias', 'controller')
+
+ key = mi.pk('controller-node')
+ if len(words) > 0:
+ if not words[0] in [c[key] for c in controller_nodes]:
+ return sdnsh.error_msg('No such controller "%s"' % words[0])
+
+ for c in controller_nodes:
+ if len(words) > 0 and c[key] != words[0]:
+ continue
+
+ c_config = []
+
+ if c[key] in controller_alias_dict:
+ c_config.append(' controller-alias %s\n' %
+ controller_alias_dict[c[key]][0]['alias'])
+
+ # mi.obj_type_config_fields() doesn't work, since
+ # these fields aren't directly editable.
+ for field in ['ntp-server',
+ 'time-zone',
+ 'domain-lookups-enabled',
+ 'domain-name']:
+ default_value = mi.field_default_value('controller-node', field)
+ if field == 'ntp-server' and c.get(field, '') != default_value:
+ c_config.append(' ntp server %s\n' % c.get(field,''))
+ elif field == 'time-zone' and c.get(field, '') != default_value:
+ c_config.append(' clock timezone %s\n' % c.get(field, ''))
+ elif field == 'domain-lookups-enabled' and c.get(field, '') != default_value:
+ c_config.append(' ip domain lookup\n')
+ elif field == 'domain-name' and c.get(field, '') != default_value:
+ c_config.append(' ip domain name %s\n' % c.get(field, ''))
+
+ dns_key = mi.pk('controller-domain-name-server')
+ related_dns = [x for x in controller_dnses if x[dns_key].startswith(c[key])]
+ if related_dns:
+ sorted_dns = sorted(related_dns, key=lambda x: x['timestamp'],
+ cmp=lambda x,y: cmp(int(x), int(y)))
+ for dns in sorted_dns:
+ c_config.append(' ip name-server %s\n' % dns['ip'])
+
+ for field in ['default-gateway',
+ 'logging-enabled']:
+ default_value = mi.field_default_value('controller-node', field)
+ if field == 'logging-enabled' and c.get(field, '') != default_value:
+ c_config.append(' logging on\n')
+ elif field == 'default-gateway' and c.get(field, '') != default_value:
+ c_config.append(' ip default-gateway %s\n' % c.get(field, ''))
+
+ default_logging_server = mi.field_default_value('controller-node', 'logging-server')
+ default_logging_level = mi.field_default_value('controller-node', 'logging-level')
+ logging_server = c.get('logging-server', '')
+ logging_level = c.get('logging-level', '')
+ if ((logging_server != default_logging_server) or
+ (logging_level != default_logging_level)):
+ c_config.append(' logging server %s' % logging_server)
+ if logging_level != default_logging_level:
+ c_config.append(' level %s' % logging_level)
+ c_config.append('\n')
+
+ open_ports = [22, 6633]
+ cif_key = mi.pk('controller-interface')
+ fr_key = mi.pk('firewall-rule')
+ for cif in controller_ifs:
+ if cif[cif_key].startswith(c[key]):
+ fields = cif[cif_key].split('|')
+ cconfig = []
+ if len(fields) > 2:
+ if_n = int(fields[2]) # interface number is the 3rd field
+ ip_mode = 'static'
+ if 'mode' in cif and cif['mode'] != '':
+ if cif['mode'] != mi.field_default_value('controller-interface',
+ 'mode'):
+ #
+ # currently no checks are made to warn
+ # the user when 'dhcp' mode has been
+ # selected, and ip/netmask are set.
+ cconfig.append(' ip mode %s\n' % cif['mode'])
+ ip_mode = cif['mode']
+
+ if (ip_mode == 'static' and
+ 'ip' in cif and cif['ip'] != '' and
+ 'netmask' in cif and cif['netmask'] != ''):
+ cconfig.append(' ip address %s %s\n' %
+ (cif['ip'], cif['netmask']))
+
+ rules_for_cif = [r for r in firewall_rules
+ if r['interface'] == cif[cif_key]]
+ # look for deleted default firewall rules for first interface
+ if if_n == 0:
+ default_rule_missing = list(open_ports)
+ for rule in rules_for_cif:
+ if rule['proto'] == 'tcp' and rule['port'] in default_rule_missing:
+ default_rule_missing = filter(lambda p: p != rule['port'],
+ default_rule_missing)
+ for dr in default_rule_missing:
+ cconfig.append(' no firewall %s tcp\n' % dr)
+
+ for rule in rules_for_cif:
+ # ignore default rules
+ if if_n == 0 and rule['proto'] == 'tcp' and rule['port'] in open_ports:
+ continue
+ running_config_firewall_rule(cconfig, rule)
+ if len(cconfig) > 0 or cif[cif_key] != 'localhost|Ethernet|0':
+ # mi.obj_type_config_fields() doesn't work, since
+ # these fields aren't directly editable.
+ c_config.append(' interface %s %s\n' %
+ (fields[1], fields[2]))
+
+ c_config += cconfig
+ if len(c_config) != 0 or c[key] != 'localhost':
+ config.append('!\ncontroller-node %s\n' % c[key])
+ config.append(''.join(c_config))
+
+controller_node_running_config_tuple = (
+ (
+ {
+ 'optional' : False,
+ 'field' : 'running-config',
+ 'type' : 'enum',
+ 'values' : 'controller-node',
+ 'short-help' : 'Configuration for controller nodes',
+ 'doc' : 'running-config|show-controller-node',
+ },
+ {
+ 'field' : 'word',
+ 'type' : 'identifier',
+ 'completion' : 'complete-from-another',
+ 'other' : 'controller-node|id',
+ 'parent-field' : None,
+ 'action' : 'legacy-cli',
+ 'optional' : True,
+ }
+ ),
+)
+
+register_running_config('controller-node', 2000, None,
+ running_config_controller_node, controller_node_running_config_tuple)
+
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_switch(context, config, words):
+ """
+ Switch running-config
+ """
+
+ switches = sdnsh.get_table_from_store("switch-config")
+ flow_table_entries = sdnsh.get_table_from_store('flow-entry')
+
+ switch_interface_configs_dict = create_obj_type_dict('switch-interface-config',
+ 'switch')
+
+ switch_interface_alias_dict = create_obj_type_dict('switch-interface-alias',
+ 'switch-interface')
+ key = mi.pk('switch-config')
+ if len(words) > 0:
+ if not words[0] in [s[key] for s in switches]:
+ return sdnsh.error_msg('No such switch "%s"' % words[0])
+
+ for s in switches:
+ #
+ #
+ if len(words) > 0 and s[key] != words[0]:
+ continue
+
+ sw_config = []
+ sw_config.append('!\nswitch %s\n' % s[key])
+ #
+ # add any alias for this id if it exists
+ running_config_include_alias(sw_config, 1, 'switch-config', s[key])
+
+ if mi.not_default_value('switch-config', 'core-switch', s.get('core-switch','')):
+ sw_config.append(" core-switch\n") # default is not enabled
+
+ if mi.not_default_value('switch-config', 'tunnel-termination', s.get('tunnel-termination','')):
+ sw_config.append(" tunnel termination %s\n" %
+ s['tunnel-termination'])
+
+ #
+ # Look for matching switch interface config's
+ sic_key = mi.pk('switch-interface-config')
+ for sic in switch_interface_configs_dict.get(s[key], []):
+ fields = sic[sic_key].split('|')
+ if len(fields) > 1:
+ sic_config = []
+ # XXX perhaps mi.obj_type_config_fields() here?
+ running_config_include_field(sic_config,
+ 'switch-interface-config',
+ 'mode',
+ sic['mode'], 2,
+ 'switchport ')
+
+ if sic[sic_key] in switch_interface_alias_dict:
+ sic_config.append(' interface-alias %s\n' %
+ switch_interface_alias_dict[sic[sic_key]][0]['id'])
+
+ if len(sic_config) > 0:
+ sw_config.append(' interface %s\n' % fields[1])
+ sw_config += sic_config
+
+ for fte in flow_table_entries: #
+ # how to handle defaults?
+ if fte['switch'] == s[key]:
+ sw_config.append(' flow-entry %s\n' % fte['name'])
+ fields_to_print = mi.cli_model_info.get_fields_to_print('flow-entry')
+ for f in fields_to_print:
+ v = fte.get(f, "")
+ if v != "" and f != 'name' and f != 'switch':
+ field_info = mi.cli_model_info.get_field_info('flow-entry', f)
+ if v == field_info.get('default', None) and f != 'active':
+ pass # literally, don't print this one
+ else:
+ sw_config.append(' %s %s\n' % (f, v))
+ config += sw_config
+
+switch_running_config_tuple = (
+ (
+ {
+ 'optional' : False,
+ 'field' : 'running-config',
+ 'type' : 'enum',
+ 'values' : 'switch',
+ 'short-help' : 'Configuration for switches',
+ 'doc' : 'running-config|show-switch',
+ },
+ {
+ 'field' : 'word',
+ 'type' : 'dpid',
+ 'completion' : 'complete-from-another',
+ 'other' : 'switch|dpid',
+ 'parent-field' : None,
+ 'action' : 'legacy-cli',
+ 'data-handler' : 'alias-to-value',
+ 'optional' : True,
+ }
+ ),
+)
+
+register_running_config('switch', 3000, None, running_config_switch, switch_running_config_tuple)
+
+
+#
+# --------------------------------------------------------------------------------
+
+def running_config_host(context, config, words):
+ """
+ Add host details, including tags.
+ """
+
+ # When there are no tags, and no host-aliases, the hosts don't need
+ # to be read. If it were possible to determine the number of entries
+ # without querying, then it would make sense to consider enumerating
+ # the host-aliases and tags if they were substantially smaller than
+ # the number of hosts.
+ #
+
+ host_alias_dict = create_obj_type_dict("host-alias", 'host')
+ host_security_ip = create_obj_type_dict("host-security-ip-address", 'host')
+ host_security_ap = create_obj_type_dict("host-security-attachment-point", 'host')
+ switch_config = create_obj_type_dict('switch-interface-config', 'id')
+
+ # Notice that only hosts configured are enumerated here, since
+ # discovered hosts can't have configuration. All configuration
+ # is attached to configured hosts, which are joined after discovered
+ # hosts for show commands.
+ hosts = sdnsh.get_table_from_store("host-config")
+ key = mi.pk('host-config')
+
+ if len(words) > 0:
+ if not words[0] in [h[key] for h in hosts]:
+ return sdnsh.error_msg('No such host "%s"' % words[0])
+
+ for h in hosts:
+ if len(words) > 0 and words[0] != h[key]:
+ continue
+
+ # host_config holds 'config' only for host.
+ host_config = []
+ a_s = ''
+ if h.get('address-space','') != 'default':
+ a_s = 'address-space %s ' % h['address-space']
+ vlan = ''
+ if h.get('vlan', '') != '':
+ vlan = 'vlan %s ' % h['vlan']
+ host_config.append('!\nhost %s%s%s\n' % (a_s, vlan, h['mac']))
+ #
+ # add the host alias for this id if it exists
+ if h[key] in host_alias_dict:
+ host_config.append(" host-alias %s\n" %
+ host_alias_dict[h[key]][0]['id'])
+
+ #
+ # check for security policies
+ if h[key] in host_security_ip:
+ for ip in host_security_ip[h[key]]:
+ host_config.append(" security policy bind ip-address %s\n" % ip['ip-address'])
+
+ if h[key] in host_security_ap:
+ for ap in host_security_ap[h[key]]:
+ host_config.append(" security policy bind attachment-point %s %s\n" %
+ (ap.get('dpid', 'all'),
+ utif.quote_string(ap['if-name-regex'])))
+
+ config += host_config
+
+
+host_running_config_tuple = (
+ (
+ {
+ 'optional' : False,
+ 'field' : 'running-config',
+ 'type' : 'enum',
+ 'values' : 'host',
+ 'short-help' : 'Configuration for hosts',
+ 'doc' : 'running-config|show-host',
+ },
+ {
+ 'field' : 'word',
+ 'type' : 'host',
+ 'completion' : 'complete-from-another',
+ 'other' : 'host|mac',
+ 'parent-field' : None,
+ 'data-handler' : 'alias-to-value',
+ 'action' : 'legacy-cli',
+ 'optional' : True,
+ }
+ ),
+)
+
+register_running_config('host', 5000, None, running_config_host, host_running_config_tuple)
+
+def running_config_vns(context, config, words):
+ """
+ Add the VNS configuration detils
+ this command will only generate vns under default tenant
+ other vnss will be generated under running_config_tenant
+ """
+ #generate specific vns configuration, used in tenant config generation too
+ if len(words) > 0:
+ # XXX should the vns-definiiton also be included?
+ sdnsh.show_vns_definition_running_config(config, words[0])
+ config += sdnsh.show_vns_running_config(words[0])
+ return
+
+ #generate all VNSs for default tenant, this is used backward compatible as "show running-config vns"
+ try:
+ vns_def = sdnsh.get_table_from_store('vns-definition')
+ except Exception:
+ vns_def = []
+
+ try:
+ vns_rules = create_obj_type_dict('vns-interface-rule', 'vns')
+ except Exception:
+ vns_rules = {}
+
+ try:
+ vns_acls = create_obj_type_dict('vns-access-list', 'vns')
+ except Exception:
+ vns_acls = {}
+
+ try:
+ vns_acl_entries = create_obj_type_dict('vns-access-list-entry',
+ 'vns-access-list')
+ except Exception:
+ vns_acl_entries = {}
+
+ try:
+ vns_interface = create_obj_type_dict('vns-interface-config', 'vns')
+ except Exception:
+ vns_interface = {}
+
+ try:
+ vns_interface_acl = create_obj_type_dict('vns-interface-access-list',
+ 'vns-interface')
+ except Exception:
+ vns_interface_acl = {}
+
+ #
+ # vns-definition
+ for vns in vns_def:
+ if vns['tenant']=='default':
+ vns_name = vns['id']
+ config.append('!\nvns-definition %s\n' % vns['vnsname'])
+ running_config_vns_details(config, vns)
+ if vns_name in vns_rules:
+ running_config_vns_if_rule(config,
+ vns_rules[vns_name],indent=1)
+ #
+ # vns
+ acl_key = mi.pk('vns-access-list')
+ if_key = mi.pk('vns-interface-config')
+
+ for vns in vns_def:
+ if vns['tenant'] =='default':
+ vns_name = vns['id']
+ vns_config = []
+
+ for acl in vns_acls.get(vns_name, []):
+ acl_id = acl[acl_key] # compound primary key value
+ running_config_vns_acl(vns_config, vns_name, acl, vns_acl_entries[acl_id],indent=1)
+
+ for vns_if in vns_interface.get(vns_name, []):
+ vns_if_acl_config = []
+ vns_if_id = vns_if[if_key] # compound primary key value
+ if vns_if_id in vns_interface_acl:
+ running_config_vns_if_and_access_group(vns_if_acl_config,
+ vns_name,
+ vns_if['interface'],
+ vns_interface_acl[vns_if_id],indent=1)
+ if vns_if_acl_config:
+ vns_config.append(" interface %s\n" % vns_if['interface'])
+ vns_config += vns_if_acl_config
+
+ if len(vns_config) > 0:
+ config.append('!\nvns %s\n' % vns['vnsname'])
+ config += vns_config
+ vns_config = []
+
+
+def is_vns_enabled(context):
+ return context.netvirt_feature_enabled()
+
+vns_running_config_tuple = (
+ (
+ {
+ 'optional' : False,
+ 'field' : 'running-config',
+ 'type' : 'enum',
+ 'values' : 'vns',
+ 'short-help' : 'Configuration for network virtualization',
+ 'doc' : 'running-config|show-vns',
+ },
+ {
+ 'field' : 'word',
+ 'type' : 'identifier',
+ 'completion' : 'complete-from-another',
+ 'other' : 'vns-definition|vnsname',
+ 'parent-field' : None,
+ 'action' : 'legacy-cli',
+ 'optional' : True,
+ }
+ ),
+)
+
+register_running_config('vns', 7000, is_vns_enabled, running_config_vns, vns_running_config_tuple)
+
+#tenant running config
+def running_config_tenant(context, config, words):
+
+ if len(words) > 0:
+ # XXX should the vns-definiiton also be included?
+ sdnsh.show_tenant_running_config(config, words[0])
+ return
+
+ try:
+ tenants = sdnsh.get_table_from_store('tenant')
+ except Exception:
+ tenants = []
+
+ for tenant in tenants:
+ sdnsh.show_tenant_running_config(config, tenant['name'])
+
+
+tenant_running_config_tuple = (
+ (
+ {
+ 'optional' : False,
+ 'field' : 'running-config',
+ 'type' : 'enum',
+ 'values' : 'tenant',
+ 'short-help' : 'Configuration for Tenant',
+ 'doc' : 'running-config|show-tenant',
+ },
+ {
+ 'field' : 'word',
+ 'type' : 'identifier',
+ 'completion' : 'complete-from-another',
+ 'other' : 'tenant|name',
+ 'parent-field' : None,
+ 'action' : 'legacy-cli',
+ 'optional' : True,
+ }
+ ),
+)
+
+register_running_config('tenant', 7000, is_vns_enabled, running_config_tenant, tenant_running_config_tuple)
+
+def running_config_static_arp(context, config, words):
+
+ try:
+ staticARPs = sdnsh.get_table_from_store('static-arp')
+ except Exception:
+ staticARPs = []
+ first=True
+ for arp in staticARPs:
+ if first:
+ config.append('!\narp %s %s\n' % (arp['ip'], arp['mac']))
+ first=False
+ else:
+ config.append('arp %s %s\n' % (arp['ip'], arp['mac']))
+
+staticARP_running_config_tuple = (
+ (
+ {
+ 'optional' : False,
+ 'field' : 'running-config',
+ 'type' : 'enum',
+ 'values' : 'static-arp',
+ 'short-help' : 'Configuration for static ARP entry',
+ 'doc' : 'running-config|show-static-arp',
+ },
+ ),
+)
+
+register_running_config('static-arp', 6000, None, running_config_static_arp, staticARP_running_config_tuple)
+
+
+#
+# --------------------------------------------------------------------------------
+
+def implement_show_running_config(words):
+ """
+ Manager for the 'show running-config' command, which calls the
+ specific detail functions for any of the parameters.
+ """
+
+ # LOOK! hardwired - need to use the obj_type_info and the field_list
+ # LOOK! how are these sorted?
+ config = []
+ if len(words) > 0:
+ # pick the word
+ choice = utif.full_word_from_choices(words[0],
+ registry_items_enabled())
+ if sdnsh.netvirt_feature_enabled() and 'vns'.startswith(words[0]):
+ if choice:
+ return sdnsh.error_msg("%s and %s ambiguous" % (choice, 'vns'))
+ choice = 'vns'
+
+ if choice:
+ perform_running_config(choice, sdnsh, config, words)
+ else:
+ return sdnsh.error_msg("unknown running-config item: %s" % words[0])
+ # config[:-1] removes the last trailing newline
+ return ''.join(config)[:-1]
+ else:
+ # Create the order based on the registration value
+ running_config_order = sorted(registry_items_enabled(),
+ key=lambda item: running_config_registry[item]['order'])
+ exclude_list=['vns']
+ for rc in running_config_order:
+ if rc not in exclude_list:
+ perform_running_config(rc, sdnsh, config, words)
+
+ prefix = []
+ if len(config) > 0:
+ date_string = datetime.datetime.now().strftime("%Y-%m-%d.%H:%M:%S %Z")
+ prefix.append("!\n! ")
+ prefix.append(sdnsh.do_show_version(words))
+ prefix.append("\n! Current Time: ")
+ prefix.append(date_string)
+ prefix.append("\n!\n")
+ prefix.append("version 1.0\n") # need a better determination of command syntax version
+
+ # config[:-1] removes the last trailing newline
+ return ''.join(prefix) + ''.join(config)[:-1]
+
+