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]
+
+