Adding initial test cases, include enumeration conversion, address review comments
Change-Id: I59a19f80289464c934ad16d2d2ce1c78a6ba6f2c
diff --git a/experiments/plugin/protobuf.py b/experiments/plugin/protobuf.py
index 433ae30..fc177b7 100644
--- a/experiments/plugin/protobuf.py
+++ b/experiments/plugin/protobuf.py
@@ -17,13 +17,24 @@
"""pyang plugin to convert a yang schema to a protobuf schema
- - very basic support for leaf, leaf-list, containers, list
+ - basic support for leaf, leaf-list, containers, list
+
+ - this plugin requires pyang to be present and is run using pyang as
+ follows:
+
+ $ pyang --plugindir /voltha/experiments/plugin -f protobuf -o
+ <protofile> -p /voltha/tests/utests/netconf/yang
+ /voltha/tests/utests/netconf/yang/<yang file>
+
+ - pyang validates the yanhg definition first and then invoke this plugin
+ to convert the yang model into protobuf.
"""
from pyang import plugin, statements, error
from pyang.util import unique_prefixes
+
# Register the Protobuf plugin
def pyang_plugin_init():
plugin.register_plugin(ProtobufPlugin())
@@ -42,37 +53,54 @@
def set_headers(self, module_name):
self.headers.append('syntax = "proto3";')
- self.headers.append('package {};'.format(module_name))
+ self.headers.append('package {};'.format(module_name.replace('-',
+ '_')))
def _print_container(self, container, out, level=0):
spaces = ' ' * level
out.append(''.join([spaces, 'message {} '.format(container.name)]))
out.append(''.join('{\n'))
- for idx, l in enumerate(container.leafs):
- leafspaces = ''.join([spaces, ' '])
- out.append(''.join([leafspaces, '{}{} {} = {} ;\n'.format(
- 'repeated ' if l.leaf_list else '',
- l.type,
- l.name,
- idx + 1)]))
+ self._print_leaf(container.leafs, out, spaces)
+
+ for l in container.ylist:
+ self._print_list(l, out, level)
for inner in container.containers:
self._print_container(inner, out, level + 1)
out.append(''.join([spaces, '}\n']))
- def _print_list(self, ylist, out):
+ def _print_list(self, ylist, out, level=0):
+ spaces = ' ' * level
out.append('message {} '.format(ylist.name))
out.append('{\n')
- for idx, l in enumerate(ylist.leafs):
- leafspaces = ' '
- out.append(''.join([leafspaces, '{}{} {} = {} ;\n'.format(
- 'repeated ' if l.leaf_list else '',
- l.type,
- l.name,
- idx + 1)]))
+ self._print_leaf(ylist.leafs, out, spaces)
+
+ for l in ylist.ylist:
+ self._print_list(l, out, level + 1)
+
out.append('}\n')
+ def _print_leaf(self, leafs, out, spaces):
+ for idx, l in enumerate(leafs):
+ leafspaces = ''.join([spaces, ' '])
+ if l.type == "enum":
+ out.append(''.join([leafspaces, 'enum {}\n'.format(l.name)]))
+ out.append(''.join([leafspaces, '{\n']))
+ self._print_enumeration(l.enumeration, out, leafspaces)
+ out.append(''.join([leafspaces, '}\n']))
+ else:
+ out.append(''.join([leafspaces, '{}{} {} = {} ;\n'.format(
+ 'repeated ' if l.leaf_list else '',
+ l.type,
+ l.name,
+ idx + 1)]))
+
+ def _print_enumeration(self, yang_enum, out, spaces):
+ enumspaces = ''.join([spaces, ' '])
+ for idx, e in enumerate(yang_enum):
+ out.append(''.join([enumspaces, '{}\n'.format(e)]))
+
def print_proto(self):
out = []
for h in self.headers:
@@ -80,13 +108,16 @@
out.append('\n')
for m in self.messages:
out.append('{}\n'.format(m))
- out.append('\n')
+ if self.messages:
+ out.append('\n')
for l in self.ylist:
self._print_list(l, out)
- out.append('\n')
+ if self.ylist:
+ out.append('\n')
for c in self.containers:
self._print_container(c, out)
- out.append('\n')
+ if self.containers:
+ out.append('\n')
return out
@@ -97,12 +128,15 @@
self.containers = []
self.enums = []
self.leafs = []
+ self.ylist = []
class YangList():
def __init__(self):
self.name = None
self.leafs = []
+ self.containers = []
+ self.ylist = []
class YangLeaf():
@@ -110,9 +144,15 @@
self.name = None
self.type = None
self.leaf_list = False
+ self.enumeration = []
self.description = None
+class YangEnumeration():
+ def __init__(self):
+ self.value = []
+
+
class ProtobufPlugin(plugin.PyangPlugin):
def add_output_format(self, fmts):
self.multiple_modules = True
@@ -127,13 +167,43 @@
self.real_prefix = unique_prefixes(ctx)
for m in modules:
+ # m.pprint()
+ # statements.print_tree(m)
proto = Protobuf()
proto.set_headers(m.i_modulename)
+ self.process_substatements(m, proto, None)
self.process_children(m, proto, None)
out = proto.print_proto()
for i in out:
fd.write(i)
+ def process_substatements(self, node, parent, pmod):
+ """Process all substmts.
+ """
+ for st in node.substmts:
+ if st.keyword in ["rpc", "notification"]: continue
+ if st.keyword in ["choice", "case"]:
+ self.process_substatements(st, parent, pmod)
+ continue
+
+ if st.i_module.i_modulename == pmod:
+ nmod = pmod
+ else:
+ nmod = st.i_module.i_modulename
+
+ if st.keyword in ["container", "grouping"]:
+ c = YangContainer()
+ c.name = st.arg
+ self.process_substatements(st, c, nmod)
+ parent.containers.append(c)
+ elif st.keyword == "list":
+ l = YangList()
+ l.name = st.arg
+ self.process_substatements(st, l, nmod)
+ parent.ylist.append(l)
+ elif st.keyword in ["leaf", "leaf-list"]:
+ self.process_leaf(st, parent, st.keyword == "leaf-list")
+
def process_children(self, node, parent, pmod):
"""Process all children of `node`, except "rpc" and "notification".
"""
@@ -144,14 +214,9 @@
continue
if ch.i_module.i_modulename == pmod:
nmod = pmod
- nodename = ch.arg
- print pmod, nodename
else:
nmod = ch.i_module.i_modulename
- nodename = "%s:%s" % (nmod, ch.arg)
- ndata = [ch.keyword]
- if ch.keyword == "container":
- print ch.keyword
+ if ch.keyword in ["container", "grouping"]:
c = YangContainer()
c.name = ch.arg
self.process_children(ch, c, nmod)
@@ -170,33 +235,35 @@
leaf = YangLeaf()
leaf.name = node.arg
leaf.type = self.get_protobuf_type(node.search_one("type"))
+ if leaf.type == "enum":
+ self.process_enumeration(node, leaf)
# leaf.type = self.base_type(node.search_one("type"))
leaf.description = node.search_one("description")
leaf.leaf_list = leaf_list
parent.leafs.append(leaf)
+ def process_enumeration(self, node, leaf):
+ enumeration_dict = {}
+ start_node = None
+ for child in node.substmts:
+ if child.keyword == "type":
+ start_node = child;
+ break
+
+ for enum in start_node.search('enum'):
+ val = enum.search_one('value')
+ if val is not None:
+ enumeration_dict[enum.arg] = int(val.arg)
+ else:
+ enumeration_dict[enum.arg] = '0'
+
+ for key, value in enumerate(enumeration_dict):
+ leaf.enumeration.append('{} = {} ;'.format(value, key))
+
def get_protobuf_type(self, type):
- protobuf_types_map = dict(
- binary='Any',
- bits='bytes',
- boolean='bool',
- decimal64='sint64',
- empty='string',
- int8='int32',
- int16='int32',
- int32='int32',
- int64='int64',
- string='string',
- uint8='uint32',
- uint16='uint32',
- uint32='uint32',
- uint64='uint64',
- union='OneOf',
- enumeration='enum'
- )
type = self.base_type(type)
- if protobuf_types_map[type]:
- return protobuf_types_map[type]
+ if type in self.protobuf_types_map.keys():
+ return self.protobuf_types_map[type]
else:
return type
@@ -213,7 +280,28 @@
if type.arg == "decimal64":
return [type.arg, int(type.search_one("fraction-digits").arg)]
elif type.arg == "union":
- return [type.arg,
- [self.base_type(x) for x in type.i_type_spec.types]]
+ # TODO convert union properly
+ return type.arg
+ # return [type.arg,
+ # [self.base_type(x) for x in type.i_type_spec.types]]
else:
return type.arg
+
+ protobuf_types_map = dict(
+ binary='Any',
+ bits='bytes',
+ boolean='bool',
+ decimal64='sint64',
+ empty='string',
+ int8='int32',
+ int16='int32',
+ int32='int32',
+ int64='int64',
+ string='string',
+ uint8='uint32',
+ uint16='uint32',
+ uint32='uint32',
+ uint64='uint64',
+ union='string', # TODO : not correct mapping
+ enumeration='enum'
+ )
diff --git a/tests/itests/__init__.py b/tests/itests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/itests/__init__.py
diff --git a/tests/utests/netconf/yang/basic.yang b/tests/utests/netconf/yang/basic.yang
new file mode 100644
index 0000000..7bba944
--- /dev/null
+++ b/tests/utests/netconf/yang/basic.yang
@@ -0,0 +1,17 @@
+module basic {
+ namespace "urn:acme:yang:basic";
+ prefix "basic";
+
+ grouping commonAttributes {
+ leaf my-id {
+ type uint8;
+ }
+ leaf my-name {
+ type string;
+ }
+ leaf my-status {
+ type boolean;
+ config false;
+ }
+ }
+}
diff --git a/tests/utests/netconf/yang/container.yang b/tests/utests/netconf/yang/container.yang
new file mode 100644
index 0000000..dbc5dfb
--- /dev/null
+++ b/tests/utests/netconf/yang/container.yang
@@ -0,0 +1,34 @@
+module container {
+ yang-version "1";
+ namespace "http://rob.sh/yang/test/base-test";
+ prefix "foo";
+ organization "BugReports Inc";
+ contact "A bug reporter";
+
+ description
+ "A test module that checks that the plugin works OK";
+ revision 2014-01-01 {
+ description "april-fools";
+ reference "fooled-you";
+ }
+
+ container int-container {
+ description
+ "A container";
+ choice name {
+ case me {
+ leaf eight {
+ type int8;
+ description
+ "A test leaf for uint8";
+ }
+ }
+ case myself {
+ leaf nine {
+ type int16;
+ description "i am nine";
+ }
+ }
+ }
+ }
+}
diff --git a/tests/utests/netconf/yang/cord-tenant.yang b/tests/utests/netconf/yang/cord-tenant.yang
new file mode 100644
index 0000000..c858094
--- /dev/null
+++ b/tests/utests/netconf/yang/cord-tenant.yang
@@ -0,0 +1,90 @@
+module cord-tenant {
+ namespace "urn:ietf:params:xml:ns:yang:cord-tenant";
+ prefix cord;
+ yang-version 1.1;
+
+ import xos-controller { prefix xos; }
+
+ organization
+ "Open Networking Lab (CORD) / Corenova Technologies";
+
+ contact
+ "Larry Peterson <llp@onlab.us>
+ Peter K. Lee <peter@corenova.com>";
+
+ description
+ "This module contains a collection of core models for CORD.
+
+ Copyright (c) 2016 ON.LAB and the persons identified as authors
+ of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject to
+ the license terms of the Apache License, Version 2.0 which
+ accompanies this distribution, and is available at
+ (http://www.apache.org/licenses/LICENSE-2.0).";
+
+ revision 2016-09-29 {
+ description "Combine CORD subscriber and augment XOS.";
+ }
+ revision 2016-07-22 {
+ description "Initial revision.";
+ }
+
+ identity cord-subscriber {
+ base xos:xos-subscriber;
+ }
+ /*
+ * Groupings
+ */
+ grouping subscriber {
+ /*
+ uses xos:subscriber {
+ refine kind { default cord-subscriber; }
+ }
+ */
+ leaf label {
+ config false;
+ type string {
+ pattern '^cordSubscriber-\w+$';
+ }
+ }
+ leaf status {
+ type enumeration {
+ enum "enabled" {
+ description "Enabled";
+ value 1;
+ }
+ enum "suspended" {
+ description "Suspended";
+ }
+ enum "delinquent" {
+ description "Delinquent";
+ }
+ enum "violation" {
+ description "Copyright Violation";
+ }
+ }
+ default enabled;
+ }
+ leaf demo {
+ type boolean;
+ default false;
+ }
+ }
+ /*
+ * Augmentations to XOS
+
+ augment "/xos:tenant" {
+ container cord {
+ description "Register cord as a tenant into XOS";
+ list subscriber {
+ key id;
+ description
+ "Each entry represents a unique CORD subscriber.";
+ uses cord:subscriber;
+ }
+ }
+ }
+ */
+}
diff --git a/tests/utests/netconf/yang/cord-volt-service.yang b/tests/utests/netconf/yang/cord-volt-service.yang
new file mode 100644
index 0000000..111421e
--- /dev/null
+++ b/tests/utests/netconf/yang/cord-volt-service.yang
@@ -0,0 +1,195 @@
+module cord-volt-service {
+ namespace "urn:ietf:params:xml:ns:yang:cord-volt-service";
+ prefix volt;
+ yang-version 1.1;
+
+ import cord-tenant { prefix cord; }
+ import xos-controller { prefix xos; }
+ import xos-types { prefix xtype; }
+
+ organization
+ "Open Networking Lab (CORD) / Corenova Technologies";
+
+ contact
+ "Larry Peterson <llp@onlab.us>
+ Peter K. Lee <peter@corenova.com>";
+
+ revision 2016-09-09 {
+ description "Initial revision.";
+ }
+
+ identity virtual-olt { base xos:xos-service; }
+
+ feature onos-app-olt {
+ description "System facility to configure VLAN tags on the OLT.";
+ }
+ feature onos-app-aaa {
+ description "System facility to broker authentication between CPE and Radius server.";
+ }
+ /*
+ * Type definitions
+ */
+ typedef bandwidth {
+ type xtype:bandwidth;
+ default 1000000000; // VOLT bandwidth default is 1Gbps
+ }
+ typedef subscriber-outflow {
+ type leafref {
+ path "/volt:controller/volt:port/volt:id";
+ }
+ }
+ /*
+ * Groupings
+ */
+ grouping devices-list {
+ grouping olt-device {
+ description
+ "This grouping describes an OLT device which contains ODN link attachments.";
+
+ leaf name {
+ description "name of OLT device";
+ type string {
+ length 1..254;
+ }
+ }
+ leaf mac { type xtype:mac-address; mandatory true; }
+
+ container uplink {
+ description "Uplink description of the OLT device.";
+ leaf network { type xtype:network-identifier; }
+ leaf tag {
+ type xtype:vlan;
+ description
+ "Represents S-Tag for instructing OLT to associate a VLAN tag for
+ traffic originating from OLT device.";
+ }
+ }
+ list link {
+ description
+ "Each link represents an ONU/ONT (Optical Network Termination) endpoint
+ connection.";
+
+ key serial;
+ unique tag;
+
+ leaf mac { type xtype:mac-address; mandatory true; }
+ leaf serial { type string; mandatory true; }
+ leaf active { type boolean; default false; }
+ leaf tag {
+ type xtype:vlan;
+ description
+ "Represents C-Tag for instructing ONT to add/remove vlan tag for
+ traffic within OLT device.";
+ }
+ }
+ }
+ list device {
+ description
+ "Each entry represents an OLT device.";
+ key mac;
+ //unique 'uplink/tag';
+ uses olt-device;
+ }
+ }
+ grouping subscriber {
+ description
+ "This grouping represents a VOLT service subscriber along with
+ references to ONU/ONT access endpoints used by the subscriber.";
+
+ container tags {
+ description
+ "Each entry represents a unique combination of the OLT uplink VLAN
+ (outer tag) and the ONU/ONT link VLAN (inner tag) connecting
+ into the fabric for the subscriber.";
+
+ leaf outer {
+ type leafref {
+ path "/volt:controller/volt:device/volt:uplink/volt:tag";
+ }
+ }
+ leaf inner {
+ type leafref {
+ path "/volt:controller/volt:device/volt:link/volt:tag";
+ }
+ }
+ }
+ leaf outflow {
+ description
+ "Each entry represents a unique openflow port ID that the subscriber
+ uses to connect into the fabric from the VOLT service.";
+ config false;
+ type subscriber-outflow;
+ }
+ }
+
+ /*
+ * Configuration data nodes
+ */
+ container controller {
+ description
+ "The controller configuration block represents a VOLT agent/controller
+ which manages multiple OLT devices. The VOLT agent provides
+ aggregate abstraction of the entire PON as a sigle switch to
+ the controller. Each port entry of the agent represents each
+ ONU/ONT endpoint as a separate openflow port.";
+
+ uses xos:service {
+ refine kind {
+ default virtual-olt;
+ }
+ augment "subscriber" { uses volt:subscriber; }
+ }
+ // additional service specific configurations
+ uses devices-list;
+ list port {
+ description
+ "Each entry represents an ONU/ONT endpoint connected across OLT devices.";
+ key id;
+ leaf id {
+ description "OpenFlow Port ID";
+ type xtype:flow-identifier;
+ mandatory true;
+ }
+ leaf link {
+ type leafref {
+ path '/volt:controller/device/link/serial';
+ }
+ mandatory true;
+ }
+ }
+ container radius {
+ if-feature onos-app-aaa;
+ // configuration for how to broker authentication requests
+ }
+ }
+ /*
+ * Augmentations to CORD Tenant in XOS
+ */
+ augment "/xos:tenant/cord:cord/cord:subscriber" {
+ container service {
+ leaf id {
+ type leafref {
+ path "/volt:controller/subscriber/id";
+ }
+ }
+ leaf c-tag {
+ config false;
+ type leafref {
+ path "/volt:controller/subscriber/tags/outer";
+ }
+ }
+ leaf s-tag {
+ config false;
+ type leafref {
+ path "/volt:controller/subscriber/tags/inner";
+ }
+ }
+ leaf uplink-speed {
+ type volt:bandwidth;
+ }
+ leaf downlink-speed {
+ type volt:bandwidth;
+ }
+ }
+ }
+}
diff --git a/tests/utests/netconf/yang/corenova-node.yang b/tests/utests/netconf/yang/corenova-node.yang
new file mode 100644
index 0000000..e0873e0
--- /dev/null
+++ b/tests/utests/netconf/yang/corenova-node.yang
@@ -0,0 +1,41 @@
+module corenova-node {
+ namespace "urn:corenova:node";
+ prefix node;
+
+ organization
+ "Corenova Technologies, Inc.";
+
+ contact
+ "Peter K. Lee <peter@corenova.com>";
+
+ description
+ "This module defines extensions to dynamically control schema node
+ display and access overlay controls";
+
+ feature corenova-node {
+ description
+ "this is to indicate the agent supports dynamic schema node
+ link and view constraints.";
+ }
+
+ extension link {
+ description
+ "Links a new 'link-name' element to an alternate data node element in
+ the schema data tree referenced by the 'path' sub statement. It
+ can be used within 'container' or 'list' type data element to
+ hold one or more such 'links' as part of its configuration data
+ tree. The new link element becomes a 'mirror' instance of the
+ target node found in the path expression.";
+ argument link-name {
+ yin-element true;
+ }
+ }
+
+ extension view {
+ description
+ "Informs the interface layers that only the data nodes referenced
+ within the value argument should be made visible to the
+ consumer.";
+ argument value;
+ }
+}
diff --git a/tests/utests/netconf/yang/mix_simple_types.yang b/tests/utests/netconf/yang/mix_simple_types.yang
new file mode 100644
index 0000000..c73b6cf
--- /dev/null
+++ b/tests/utests/netconf/yang/mix_simple_types.yang
@@ -0,0 +1,91 @@
+module mix-simple-types {
+ yang-version "1";
+ namespace "http://rob.sh/yang/test/base-test";
+ prefix "foo";
+ organization "BugReports Inc";
+ contact "A bug reporter";
+
+ description
+ "A test module that checks that the plugin works OK";
+ revision 2014-01-01 {
+ description "april-fools";
+ reference "fooled-you";
+ }
+
+ container int-container {
+ description
+ "A container";
+ choice name {
+ case me {
+ leaf eight {
+ type int8;
+ description
+ "A test leaf for uint8";
+ }
+ }
+ case myself {
+ leaf nine {
+ type int16;
+ description "i am nine";
+ }
+ }
+ }
+ leaf ten {
+ type int16;
+ description "i am ten";
+ }
+ }
+
+ list user {
+ key "name";
+ leaf name {
+ type string;
+ }
+ leaf full-name {
+ type string;
+ }
+ leaf class {
+ type string;
+ }
+ }
+
+ container container1 {
+ description
+ "A container";
+ choice name {
+ case acase {
+ leaf a {
+ type boolean;
+ description
+ "A test leaf for uint8";
+ }
+ }
+ case bcase {
+ leaf b {
+ type binary;
+ description "i am nine";
+ }
+ }
+ }
+ leaf mleaf {
+ type string;
+ description "i am string";
+ }
+ leaf-list mleaf_list {
+ type string;
+ description "i am repeated string";
+ }
+ container inner-container {
+ description
+ "A container";
+ leaf mleaf1 {
+ type string;
+ description "i am leaf1";
+ }
+ leaf mleaf2 {
+ type string;
+ description "i am leaf2";
+ }
+ }
+ }
+}
diff --git a/tests/utests/netconf/yang/openconfig-extensions.yang b/tests/utests/netconf/yang/openconfig-extensions.yang
new file mode 100644
index 0000000..d5e9442
--- /dev/null
+++ b/tests/utests/netconf/yang/openconfig-extensions.yang
@@ -0,0 +1,69 @@
+module openconfig-extensions {
+
+ yang-version "1";
+
+ // namespace
+ namespace "http://openconfig.net/yang/openconfig-ext";
+
+ prefix "ocext";
+
+ // meta
+ organization "OpenConfig working group";
+
+ contact
+ "OpenConfig working group
+ www.openconfig.net";
+
+ description
+ "This module provides extensions to the YANG language to allow
+ OpenConfig specific functionality and meta-data to be defined.";
+
+ revision "2015-10-09" {
+ description
+ "Initial OpenConfig public release";
+ }
+
+ revision "2015-10-05" {
+ description
+ "Initial revision";
+ reference "TBD";
+ }
+
+ // extension statements
+ extension openconfig-version {
+ argument "semver" {
+ yin-element false;
+ }
+ description
+ "The OpenConfig version number for the module. This is
+ expressed as a semantic version number of the form:
+ x.y.z
+ where:
+ * x corresponds to the major version,
+ * y corresponds to a minor version,
+ * z corresponds to a patch version.
+ This version corresponds to the model file within which it is
+ defined, and does not cover the whole set of OpenConfig models.
+ Where several modules are used to build up a single block of
+ functionality, the same module version is specified across each
+ file that makes up the module.
+
+ A major version number of 0 indicates that this model is still
+ in development (whether within OpenConfig or with industry
+ partners), and is potentially subject to change.
+
+ Following a release of major version 1, all modules will
+ increment major revision number where backwards incompatible
+ changes to the model are made.
+
+ The minor version is changed when features are added to the
+ model that do not impact current clients use of the model.
+
+ The patch-level version is incremented when non-feature changes
+ (such as bugfixes or clarifications to human-readable
+ descriptions that do not impact model functionality) are made
+ that maintain backwards compatibility.
+
+ The version number is stored in the module meta-data.";
+ }
+}
\ No newline at end of file
diff --git a/tests/utests/netconf/yang/openconfig-interfaces.yang b/tests/utests/netconf/yang/openconfig-interfaces.yang
new file mode 100644
index 0000000..332f7e1
--- /dev/null
+++ b/tests/utests/netconf/yang/openconfig-interfaces.yang
@@ -0,0 +1,933 @@
+module openconfig-interfaces {
+
+ yang-version "1";
+
+ // namespace
+ namespace "http://openconfig.net/yang/interfaces";
+
+ prefix "oc-if";
+
+ // import some basic types
+ import ietf-interfaces { prefix ietf-if; }
+ import ietf-yang-types { prefix yang; }
+ import openconfig-extensions { prefix oc-ext; }
+
+ // meta
+ organization "OpenConfig working group";
+
+ contact
+ "OpenConfig working group
+ netopenconfig@googlegroups.com";
+
+ description
+ "Model for managing network interfaces and subinterfaces. This
+ module also defines convenience types / groupings for other
+ models to create references to interfaces:
+
+ base-interface-ref (type) - reference to a base interface
+ interface-ref (grouping) - container for reference to a
+ interface + subinterface
+ interface-ref-state (grouping) - container for read-only
+ (opstate) reference to interface + subinterface
+
+ This model reuses data items defined in the IETF YANG model for
+ interfaces described by RFC 7223 with an alternate structure
+ (particularly for operational state data) and and with
+ additional configuration items.";
+
+ oc-ext:openconfig-version "1.0.2";
+
+ revision "2016-05-26" {
+ description
+ "OpenConfig public release";
+ reference "1.0.2";
+ }
+
+
+ // typedef statements
+
+ typedef base-interface-ref {
+ type leafref {
+ path "/oc-if:interfaces/oc-if:interface/oc-if:name";
+ }
+ description
+ "Reusable type for by-name reference to a base interface.
+ This type may be used in cases where ability to reference
+ a subinterface is not required.";
+ }
+
+ typedef interface-id {
+ type string;
+ description
+ "User-defined identifier for an interface, generally used to
+ name a interface reference. The id can be arbitrary but a
+ useful convention is to use a combination of base interface
+ name and subinterface index.";
+ }
+
+ // grouping statements
+
+ grouping interface-ref-common {
+ description
+ "Reference leafrefs to interface / subinterface";
+
+ leaf interface {
+ type leafref {
+ path "/oc-if:interfaces/oc-if:interface/oc-if:name";
+ }
+ description
+ "Reference to a base interface. If a reference to a
+ subinterface is required, this leaf must be specified
+ to indicate the base interface.";
+ }
+
+ leaf subinterface {
+ type leafref {
+ path "/oc-if:interfaces/" +
+ "oc-if:interface[oc-if:name=current()/../interface]/" +
+ "oc-if:subinterfaces/oc-if:subinterface/oc-if:index";
+ }
+ description
+ "Reference to a subinterface -- this requires the base
+ interface to be specified using the interface leaf in
+ this container. If only a reference to a base interface
+ is requuired, this leaf should not be set.";
+ }
+ }
+
+ grouping interface-ref-state-container {
+ description
+ "Reusable opstate w/container for a reference to an
+ interface or subinterface";
+
+ container state {
+ config false;
+ description
+ "Operational state for interface-ref";
+
+ uses interface-ref-common;
+ }
+ }
+
+ grouping interface-ref {
+ description
+ "Reusable definition for a reference to an interface or
+ subinterface";
+
+ container interface-ref {
+ description
+ "Reference to an interface or subinterface";
+
+ container config {
+ description
+ "Configured reference to interface / subinterface";
+
+ uses interface-ref-common;
+ }
+
+ uses interface-ref-state-container;
+ }
+ }
+
+ grouping interface-ref-state {
+ description
+ "Reusable opstate w/container for a reference to an
+ interface or subinterface";
+
+ container interface-ref {
+ description
+ "Reference to an interface or subinterface";
+
+ uses interface-ref-state-container;
+ }
+ }
+
+
+ grouping interface-common-config {
+ description
+ "Configuration data data nodes common to physical interfaces
+ and subinterfaces";
+
+ leaf name {
+ type string;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ The name of the interface.
+
+ A device MAY restrict the allowed values for this leaf,
+ possibly depending on the type of the interface.
+ For system-controlled interfaces, this leaf is the
+ device-specific name of the interface. The 'config false'
+ list interfaces/interface[name]/state contains the currently
+ existing interfaces on the device.
+
+ If a client tries to create configuration for a
+ system-controlled interface that is not present in the
+ corresponding state list, the server MAY reject
+ the request if the implementation does not support
+ pre-provisioning of interfaces or if the name refers to
+ an interface that can never exist in the system. A
+ NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.
+
+ The IETF model in RFC 7223 provides YANG features for the
+ following (i.e., pre-provisioning and arbitrary-names),
+ however they are omitted here:
+
+ If the device supports pre-provisioning of interface
+ configuration, the 'pre-provisioning' feature is
+ advertised.
+
+ If the device allows arbitrarily named user-controlled
+ interfaces, the 'arbitrary-names' feature is advertised.
+
+ When a configured user-controlled interface is created by
+ the system, it is instantiated with the same name in the
+ /interfaces/interface[name]/state list.";
+ reference
+ "RFC 7223: A YANG Data Model for Interface Management";
+ }
+
+ leaf description {
+ type string;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ A textual description of the interface.
+
+ A server implementation MAY map this leaf to the ifAlias
+ MIB object. Such an implementation needs to use some
+ mechanism to handle the differences in size and characters
+ allowed between this leaf and ifAlias. The definition of
+ such a mechanism is outside the scope of this document.
+
+ Since ifAlias is defined to be stored in non-volatile
+ storage, the MIB implementation MUST map ifAlias to the
+ value of 'description' in the persistently stored
+ datastore.
+
+ Specifically, if the device supports ':startup', when
+ ifAlias is read the device MUST return the value of
+ 'description' in the 'startup' datastore, and when it is
+ written, it MUST be written to the 'running' and 'startup'
+ datastores. Note that it is up to the implementation to
+
+ decide whether to modify this single leaf in 'startup' or
+ perform an implicit copy-config from 'running' to
+ 'startup'.
+
+ If the device does not support ':startup', ifAlias MUST
+ be mapped to the 'description' leaf in the 'running'
+ datastore.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAlias";
+ }
+
+ leaf enabled {
+ type boolean;
+ default "true";
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ This leaf contains the configured, desired state of the
+ interface.
+
+ Systems that implement the IF-MIB use the value of this
+ leaf in the 'running' datastore to set
+ IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry
+ has been initialized, as described in RFC 2863.
+
+ Changes in this leaf in the 'running' datastore are
+ reflected in ifAdminStatus, but if ifAdminStatus is
+ changed over SNMP, this leaf is not affected.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ }
+
+ grouping interface-phys-config {
+ description
+ "Configuration data for physical interfaces";
+
+ leaf type {
+ type identityref {
+ base ietf-if:interface-type;
+ }
+ mandatory true;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ The type of the interface.
+
+ When an interface entry is created, a server MAY
+ initialize the type leaf with a valid value, e.g., if it
+ is possible to derive the type from the name of the
+ interface.
+
+ If a client tries to set the type of an interface to a
+ value that can never be used by the system, e.g., if the
+ type is not supported or if the type does not match the
+ name of the interface, the server MUST reject the request.
+ A NETCONF server MUST reply with an rpc-error with the
+ error-tag 'invalid-value' in this case.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifType";
+ }
+
+ leaf mtu {
+ type uint16;
+ description
+ "Set the max transmission unit size in octets
+ for the physical interface. If this is not set, the mtu is
+ set to the operational default -- e.g., 1514 bytes on an
+ Ethernet interface.";
+ }
+
+ uses interface-common-config;
+ }
+
+ grouping interface-phys-holdtime-config {
+ description
+ "Configuration data for interface hold-time settings --
+ applies to physical interfaces.";
+
+ leaf up {
+ type uint32;
+ units milliseconds;
+ default 0;
+ description
+ "Dampens advertisement when the interface
+ transitions from down to up. A zero value means dampening
+ is turned off, i.e., immediate notification.";
+ }
+
+ leaf down {
+ type uint32;
+ units milliseconds;
+ default 0;
+ description
+ "Dampens advertisement when the interface transitions from
+ up to down. A zero value means dampening is turned off,
+ i.e., immediate notification.";
+ }
+ }
+
+ grouping interface-phys-holdtime-state {
+ description
+ "Operational state data for interface hold-time.";
+ }
+
+ grouping interface-phys-holdtime-top {
+ description
+ "Top-level grouping for setting link transition
+ dampening on physical and other types of interfaces.";
+
+ container hold-time {
+ description
+ "Top-level container for hold-time settings to enable
+ dampening advertisements of interface transitions.";
+
+ container config {
+ description
+ "Configuration data for interface hold-time settings.";
+
+ uses interface-phys-holdtime-config;
+ }
+
+ container state {
+
+ config false;
+
+ description
+ "Operational state data for interface hold-time.";
+
+ uses interface-phys-holdtime-config;
+ uses interface-phys-holdtime-state;
+ }
+ }
+ }
+
+ grouping interface-common-state {
+ description
+ "Operational state data (in addition to intended configuration)
+ at the global level for this interface";
+
+ leaf ifindex {
+ type uint32;
+ description
+ "System assigned number for each interface. Corresponds to
+ ifIndex object in SNMP Interface MIB";
+ reference
+ "RFC 2863 - The Interfaces Group MIB";
+ }
+
+ leaf admin-status {
+ type enumeration {
+ enum UP {
+ description
+ "Ready to pass packets.";
+ }
+ enum DOWN {
+ description
+ "Not ready to pass packets and not in some test mode.";
+ }
+ enum TESTING {
+ //TODO: This is generally not supported as a configured
+ //admin state, though it's in the standard interfaces MIB.
+ //Consider removing it.
+ description
+ "In some test mode.";
+ }
+ }
+ //TODO:consider converting to an identity to have the
+ //flexibility to remove some values defined by RFC 7223 that
+ //are not used or not implemented consistently.
+ mandatory true;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ The desired state of the interface. In RFC 7223 this leaf
+ has the same read semantics as ifAdminStatus. Here, it
+ reflects the administrative state as set by enabling or
+ disabling the interface.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifAdminStatus";
+ }
+
+ leaf oper-status {
+ type enumeration {
+ enum UP {
+ value 1;
+ description
+ "Ready to pass packets.";
+ }
+ enum DOWN {
+ value 2;
+ description
+ "The interface does not pass any packets.";
+ }
+ enum TESTING {
+ value 3;
+ description
+ "In some test mode. No operational packets can
+ be passed.";
+ }
+ enum UNKNOWN {
+ value 4;
+ description
+ "Status cannot be determined for some reason.";
+ }
+ enum DORMANT {
+ value 5;
+ description
+ "Waiting for some external event.";
+ }
+ enum NOT_PRESENT {
+ value 6;
+ description
+ "Some component (typically hardware) is missing.";
+ }
+ enum LOWER_LAYER_DOWN {
+ value 7;
+ description
+ "Down due to state of lower-layer interface(s).";
+ }
+ }
+ //TODO:consider converting to an identity to have the
+ //flexibility to remove some values defined by RFC 7223 that
+ //are not used or not implemented consistently.
+ mandatory true;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ The current operational state of the interface.
+
+ This leaf has the same semantics as ifOperStatus.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOperStatus";
+ }
+
+ leaf last-change {
+ type yang:timeticks;
+ description
+ "Date and time of the last state change of the interface
+ (e.g., up-to-down transition). This corresponds to the
+ ifLastChange object in the standard interface MIB.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifLastChange";
+ }
+
+ }
+
+
+ grouping interface-counters-state {
+ description
+ "Operational state representing interface counters
+ and statistics. Some of these are adapted from RFC 7223";
+
+ //TODO: we may need to break this list of counters into those
+ //that would appear for physical vs. subinterface or logical
+ //interfaces. For now, just replicating the full stats
+ //grouping to both interface and subinterface.
+
+ container counters {
+ description
+ "A collection of interface-related statistics objects.";
+
+ reference
+ "RFC 7223 - A YANG Data Model for Interface
+ Management";
+
+ leaf in-octets {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ The total number of octets received on the interface,
+ including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInOctets";
+ }
+
+ leaf in-unicast-pkts {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, that were not addressed to a
+ multicast or broadcast address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts";
+ }
+
+ leaf in-broadcast-pkts {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, that were addressed to a broadcast
+ address at this sub-layer.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInBroadcastPkts";
+ }
+
+ leaf in-multicast-pkts {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+
+ The number of packets, delivered by this sub-layer to a
+ higher (sub-)layer, that were addressed to a multicast
+ address at this sub-layer. For a MAC-layer protocol,
+ this includes both Group and Functional addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCInMulticastPkts";
+ }
+
+ leaf in-discards {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+ Changed the counter type to counter64.
+
+ The number of inbound packets that were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being deliverable to a higher-layer
+ protocol. One possible reason for discarding such a
+ packet could be to free up buffer space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+
+
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInDiscards";
+ }
+
+ leaf in-errors {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+ Changed the counter type to counter64.
+
+ For packet-oriented interfaces, the number of inbound
+ packets that contained errors preventing them from being
+ deliverable to a higher-layer protocol. For character-
+ oriented or fixed-length interfaces, the number of
+ inbound transmission units that contained errors
+ preventing them from being deliverable to a higher-layer
+ protocol.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInErrors";
+ }
+
+ leaf in-unknown-protos {
+ type yang:counter32;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+ Changed the counter type to counter64.
+
+ For packet-oriented interfaces, the number of packets
+ received via the interface that were discarded because
+ of an unknown or unsupported protocol. For
+ character-oriented or fixed-length interfaces that
+ support protocol multiplexing, the number of
+ transmission units received via the interface that were
+ discarded because of an unknown or unsupported protocol.
+ For any interface that does not support protocol
+ multiplexing, this counter is not present.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos";
+ }
+
+ leaf out-octets {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+ Changed the counter type to counter64.
+
+ The total number of octets transmitted out of the
+ interface, including framing characters.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutOctets";
+ }
+
+ leaf out-unicast-pkts {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ The total number of packets that higher-level protocols
+ requested be transmitted, and that were not addressed
+ to a multicast or broadcast address at this sub-layer,
+ including those that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts";
+ }
+
+ leaf out-broadcast-pkts {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+
+ The total number of packets that higher-level protocols
+ requested be transmitted, and that were addressed to a
+ broadcast address at this sub-layer, including those
+ that were discarded or not sent.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutBroadcastPkts";
+ }
+
+
+ leaf out-multicast-pkts {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+ Changed the counter type to counter64.
+
+ The total number of packets that higher-level protocols
+ requested be transmitted, and that were addressed to a
+ multicast address at this sub-layer, including those
+ that were discarded or not sent. For a MAC-layer
+ protocol, this includes both Group and Functional
+ addresses.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB -
+ ifHCOutMulticastPkts";
+ }
+
+ leaf out-discards {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+ Changed the counter type to counter64.
+
+ The number of outbound packets that were chosen to be
+ discarded even though no errors had been detected to
+ prevent their being transmitted. One possible reason
+ for discarding such a packet could be to free up buffer
+ space.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutDiscards";
+ }
+
+ leaf out-errors {
+ type yang:counter64;
+ description
+ "[adapted from IETF interfaces model (RFC 7223)]
+ Changed the counter type to counter64.
+
+ For packet-oriented interfaces, the number of outbound
+ packets that could not be transmitted because of errors.
+ For character-oriented or fixed-length interfaces, the
+ number of outbound transmission units that could not be
+ transmitted because of errors.
+
+ Discontinuities in the value of this counter can occur
+ at re-initialization of the management system, and at
+ other times as indicated by the value of
+ 'discontinuity-time'.";
+ reference
+ "RFC 2863: The Interfaces Group MIB - ifOutErrors";
+ }
+
+ leaf last-clear {
+ type yang:date-and-time;
+ description
+ "Indicates the last time the interface counters were
+ cleared.";
+ }
+ }
+ }
+
+ // data definition statements
+
+ grouping sub-unnumbered-config {
+ description
+ "Configuration data for unnumbered subinterfaces";
+
+ leaf enabled {
+ type boolean;
+ default false;
+ description
+ "Indicates that the subinterface is unnumbered. By default
+ the subinterface is numbered, i.e., expected to have an
+ IP address configuration.";
+ }
+ }
+
+ grouping sub-unnumbered-state {
+ description
+ "Operational state data unnumbered subinterfaces";
+ }
+
+ grouping sub-unnumbered-top {
+ description
+ "Top-level grouping unnumbered subinterfaces";
+
+ container unnumbered {
+ description
+ "Top-level container for setting unnumbered interfaces.
+ Includes reference the interface that provides the
+ address information";
+
+ container config {
+ description
+ "Configuration data for unnumbered interface";
+
+ uses sub-unnumbered-config;
+ }
+
+ container state {
+
+ config false;
+
+ description
+ "Operational state data for unnumbered interfaces";
+
+ uses sub-unnumbered-config;
+ uses sub-unnumbered-state;
+ }
+
+ uses oc-if:interface-ref;
+ }
+ }
+
+ grouping subinterfaces-config {
+ description
+ "Configuration data for subinterfaces";
+
+ leaf index {
+ type uint32;
+ default 0;
+ description
+ "The index of the subinterface, or logical interface number.
+ On systems with no support for subinterfaces, or not using
+ subinterfaces, this value should default to 0, i.e., the
+ default subinterface.";
+ }
+
+ uses interface-common-config;
+
+ }
+
+ grouping subinterfaces-state {
+ description
+ "Operational state data for subinterfaces";
+
+ uses interface-common-state;
+ uses interface-counters-state;
+ }
+
+ grouping subinterfaces-top {
+ description
+ "Subinterface data for logical interfaces associated with a
+ given interface";
+
+ container subinterfaces {
+ description
+ "Enclosing container for the list of subinterfaces associated
+ with a physical interface";
+
+ list subinterface {
+ key "index";
+
+ description
+ "The list of subinterfaces (logical interfaces) associated
+ with a physical interface";
+
+ leaf index {
+ type leafref {
+ path "../config/index";
+ }
+ description
+ "The index number of the subinterface -- used to address
+ the logical interface";
+ }
+
+ container config {
+ description
+ "Configurable items at the subinterface level";
+
+ uses subinterfaces-config;
+ }
+
+ container state {
+
+ config false;
+ description
+ "Operational state data for logical interfaces";
+
+ uses subinterfaces-config;
+ uses subinterfaces-state;
+ }
+ }
+ }
+ }
+
+ grouping interfaces-top {
+ description
+ "Top-level grouping for interface configuration and
+ operational state data";
+
+ container interfaces {
+ description
+ "Top level container for interfaces, including configuration
+ and state data.";
+
+
+ list interface {
+ key "name";
+
+ description
+ "The list of named interfaces on the device.";
+
+ leaf name {
+ type leafref {
+ path "../config/name";
+ }
+ description
+ "References the configured name of the interface";
+ //TODO: need to consider whether this should actually
+ //reference the name in the state subtree, which
+ //presumably would be the system-assigned name, or the
+ //configured name. Points to the config/name now
+ //because of YANG 1.0 limitation that the list
+ //key must have the same "config" as the list, and
+ //also can't point to a non-config node.
+ }
+
+ container config {
+ description
+ "Configurable items at the global, physical interface
+ level";
+
+ uses interface-phys-config;
+ }
+
+ container state {
+
+ config false;
+ description
+ "Operational state data at the global interface level";
+
+ uses interface-phys-config;
+ uses interface-common-state;
+ uses interface-counters-state;
+ }
+
+ uses interface-phys-holdtime-top;
+ uses subinterfaces-top;
+ }
+ }
+ }
+
+ uses interfaces-top;
+
+
+}
diff --git a/tests/utests/netconf/yang/openconfig-local-routing.yang b/tests/utests/netconf/yang/openconfig-local-routing.yang
new file mode 100644
index 0000000..556bbee
--- /dev/null
+++ b/tests/utests/netconf/yang/openconfig-local-routing.yang
@@ -0,0 +1,402 @@
+module openconfig-local-routing {
+
+ yang-version "1";
+
+ // namespace
+ namespace "http://openconfig.net/yang/local-routing";
+
+ prefix "oc-loc-rt";
+
+ // import some basic types
+ import ietf-inet-types { prefix inet; }
+ import openconfig-policy-types { prefix oc-pt; }
+ import openconfig-extensions { prefix oc-ext; }
+ import openconfig-interfaces { prefix oc-if; }
+
+ // meta
+ organization "OpenConfig working group";
+
+ contact
+ "OpenConfig working group
+ www.openconfig.net";
+
+ description
+ "This module describes configuration and operational state data
+ for routes that are locally generated, i.e., not created by
+ dynamic routing protocols. These include static routes, locally
+ created aggregate routes for reducing the number of constituent
+ routes that must be advertised, summary routes for IGPs, etc.
+
+ This model expresses locally generated routes as generically as
+ possible, avoiding configuration of protocol-specific attributes
+ at the time of route creation. This is primarily to avoid
+ assumptions about how underlying router implementations handle
+ route attributes in various routing table data structures they
+ maintain. Hence, the definition of locally generated routes
+ essentially creates 'bare' routes that do not have any protocol-
+ specific attributes.
+
+ When protocol-specific attributes must be attached to a route
+ (e.g., communities on a locally defined route meant to be
+ advertised via BGP), the attributes should be attached via a
+ protocol-specific policy after importing the route into the
+ protocol for distribution (again via routing policy).";
+
+ oc-ext:openconfig-version "1.0.0";
+
+ revision "2016-05-11" {
+ description
+ "OpenConfig public release";
+ reference "1.0.0";
+ }
+
+
+ // identity statements
+
+ identity LOCAL_DEFINED_NEXT_HOP {
+ description
+ "A base identity type of local defined next-hops";
+ }
+
+ identity DROP {
+ base LOCAL_DEFINED_NEXT_HOP;
+ description
+ "Discard traffic for the corresponding destination";
+ }
+
+ identity LOCAL_LINK {
+ base LOCAL_DEFINED_NEXT_HOP;
+ description
+ "Treat traffic towards addresses within the specified
+ next-hop prefix as though they are connected to a local
+ link. When the LOCAL_LINK next-hop type is specified,
+ an interface must also be specified such that
+ the local system can determine which link to trigger
+ link-layer address discovery against";
+ }
+
+ // typedef statements
+
+ typedef local-defined-next-hop {
+ type identityref {
+ base LOCAL_DEFINED_NEXT_HOP;
+ }
+ description
+ "Pre-defined next-hop designation for locally generated
+ routes";
+ }
+
+ // grouping statements
+
+ grouping local-generic-settings {
+ description
+ "Generic options that can be set on local routes When
+ they are defined";
+
+ leaf set-tag {
+ type oc-pt:tag-type;
+ description
+ "Set a generic tag value on the route. This tag can be
+ used for filtering routes that are distributed to other
+ routing protocols.";
+ }
+ }
+
+ grouping local-static-config {
+ description
+ "Configuration data for static routes.";
+
+ leaf prefix {
+ type inet:ip-prefix;
+ description
+ "Destination prefix for the static route, either IPv4 or
+ IPv6.";
+ }
+
+ uses local-generic-settings;
+ }
+
+ grouping local-static-state {
+ description
+ "Operational state data for static routes";
+ }
+
+
+ grouping local-static-nexthop-config {
+ description
+ "Configuration parameters related to each next-hop entry
+ specified for a static route";
+
+ leaf index {
+ type string;
+ description
+ "An user-specified identifier utilised to uniquely reference
+ the next-hop entry in the next-hop list. The value of this
+ index has no semantic meaning other than for referencing
+ the entry.";
+ }
+
+ leaf next-hop {
+ type union {
+ type inet:ip-address-no-zone;
+ type local-defined-next-hop;
+ }
+ description
+ "The next-hop that is to be used for the static route
+ - this may be specified as an IP address, an interface
+ or a pre-defined next-hop type - for instance, DROP or
+ LOCAL_LINK. When this leaf is not set, and the interface-ref
+ value is specified for the next-hop, then the system should
+ treat the prefix as though it is directly connected to the
+ interface.";
+ }
+
+ leaf metric {
+ type uint32;
+ description
+ "A metric which is utilised to specify the preference of
+ the next-hop entry when it is injected into the RIB. The
+ lower the metric, the more preferable the prefix is. When
+ this value is not specified the metric is inherited from
+ the default metric utilised for static routes within the
+ network instance that the static routes are being
+ instantiated. When multiple next-hops are specified for a
+ static route, the metric is utilised to determine which of
+ the next-hops is to be installed in the RIB. When multiple
+ next-hops have the same metric (be it specified, or simply
+ the default) then these next-hops should all be installed
+ in the RIB";
+ }
+
+ leaf recurse {
+ type boolean;
+ default false;
+ description
+ "Determines whether the next-hop should be allowed to
+ be looked up recursively - i.e., via a RIB entry which has
+ been installed by a routing protocol, or another static route
+ - rather than needing to be connected directly to an
+ interface of the local system within the current network
+ instance. When the interface reference specified within the
+ next-hop entry is set (i.e., is not null) then forwarding is
+ restricted to being via the interface specified - and
+ recursion is hence disabled.";
+ }
+ }
+
+ grouping local-static-nexthop-state {
+ description
+ "Operational state parameters relating to a next-hop entry
+ for a static route";
+ }
+
+
+ grouping local-static-top {
+ description
+ "Top-level grouping for the list of static route definitions";
+
+ container static-routes {
+ description
+ "Enclosing container for the list of static routes";
+
+ list static {
+ key prefix;
+ description
+ "List of locally configured static routes";
+
+ leaf prefix {
+ type leafref {
+ path "../config/prefix";
+ }
+ description
+ "Reference to the destination prefix list key.";
+ }
+
+ container config {
+ description
+ "Configuration data for static routes";
+
+ uses local-static-config;
+ }
+
+ container state {
+
+ config false;
+
+ description
+ "Operational state data for static routes";
+
+ uses local-static-config;
+ uses local-static-state;
+ }
+
+ container next-hops {
+ description
+ "Configuration and state parameters relating to the
+ next-hops that are to be utilised for the static
+ route being specified";
+
+ list next-hop {
+ key index;
+
+ description
+ "A list of next-hops to be utilised for the static
+ route being specified.";
+
+ leaf index {
+ type leafref {
+ path "../config/index";
+ }
+ description
+ "A reference to the index of the current next-hop.
+ The index is intended to be a user-specified value
+ which can be used to reference the next-hop in
+ question, without any other semantics being
+ assigned to it.";
+ }
+
+ container config {
+ description
+ "Configuration parameters relating to the next-hop
+ entry";
+
+ uses local-static-nexthop-config;
+ }
+
+ container state {
+ config false;
+ description
+ "Operational state parameters relating to the
+ next-hop entry";
+
+ uses local-static-nexthop-config;
+ uses local-static-nexthop-state;
+ }
+
+ uses oc-if:interface-ref;
+ }
+ }
+ }
+ }
+ }
+
+ grouping local-aggregate-config {
+ description
+ "Configuration data for aggregate routes";
+
+ leaf prefix {
+ type inet:ip-prefix;
+ description
+ "Aggregate prefix to be advertised";
+ }
+
+ leaf discard {
+ type boolean;
+ default false;
+ description
+ "When true, install the aggregate route with a discard
+ next-hop -- traffic destined to the aggregate will be
+ discarded with no ICMP message generated. When false,
+ traffic destined to an aggregate address when no
+ constituent routes are present will generate an ICMP
+ unreachable message.";
+ }
+
+ uses local-generic-settings;
+
+ }
+
+ grouping local-aggregate-state {
+ description
+ "Operational state data for local aggregate advertisement
+ definitions";
+ }
+
+ grouping local-aggregate-top {
+ description
+ "Top-level grouping for local aggregates";
+
+ container local-aggregates {
+ description
+ "Enclosing container for locally-defined aggregate
+ routes";
+
+ list aggregate {
+ key prefix;
+ description
+ "List of aggregates";
+
+ leaf prefix {
+ type leafref {
+ path "../config/prefix";
+ }
+ description
+ "Reference to the configured prefix for this aggregate";
+ }
+
+ container config {
+ description
+ "Configuration data for aggregate advertisements";
+
+ uses local-aggregate-config;
+ }
+
+ container state {
+
+ config false;
+
+ description
+ "Operational state data for aggregate
+ advertisements";
+
+ uses local-aggregate-config;
+ uses local-aggregate-state;
+ }
+ }
+ }
+ }
+
+ grouping local-routes-config {
+ description
+ "Configuration data for locally defined routes";
+ }
+
+ grouping local-routes-state {
+ description
+ "Operational state data for locally defined routes";
+ }
+
+ grouping local-routes-top {
+ description
+ "Top-level grouping for local routes";
+
+ container local-routes {
+ description
+ "Top-level container for local routes";
+
+ container config {
+ description
+ "Configuration data for locally defined routes";
+
+ uses local-routes-config;
+ }
+
+ container state {
+
+ config false;
+
+ description
+ "Operational state data for locally defined routes";
+
+ uses local-routes-config;
+ uses local-routes-state;
+ }
+
+ uses local-static-top;
+ uses local-aggregate-top;
+ }
+ }
+
+ uses local-routes-top;
+
+}
diff --git a/tests/utests/netconf/yang/openconfig-policy-types.yang b/tests/utests/netconf/yang/openconfig-policy-types.yang
new file mode 100644
index 0000000..8e1fe36
--- /dev/null
+++ b/tests/utests/netconf/yang/openconfig-policy-types.yang
@@ -0,0 +1,178 @@
+module openconfig-policy-types {
+
+ yang-version "1";
+
+ // namespace
+ namespace "http://openconfig.net/yang/policy-types";
+
+ prefix "oc-pol-types";
+
+ // import some basic types
+ import ietf-yang-types { prefix yang; }
+ import openconfig-extensions { prefix oc-ext; }
+
+ // meta
+ organization
+ "OpenConfig working group";
+
+ contact
+ "OpenConfig working group
+ netopenconfig@googlegroups.com";
+
+ description
+ "This module contains general data definitions for use in routing
+ policy. It can be imported by modules that contain protocol-
+ specific policy conditions and actions.";
+
+ oc-ext:openconfig-version "2.0.1";
+
+ revision "2016-05-12" {
+ description
+ "OpenConfig public release";
+ reference "2.0.1";
+ }
+
+ // identity statements
+
+ identity ATTRIBUTE_COMPARISON {
+ description
+ "base type for supported comparison operators on route
+ attributes";
+ }
+
+ identity ATTRIBUTE_EQ {
+ base ATTRIBUTE_COMPARISON;
+ description "== comparison";
+ }
+
+ identity ATTRIBUTE_GE {
+ base ATTRIBUTE_COMPARISON;
+ description ">= comparison";
+ }
+
+ identity ATTRIBUTE_LE {
+ base ATTRIBUTE_COMPARISON;
+ description "<= comparison";
+ }
+
+ typedef match-set-options-type {
+ type enumeration {
+ enum ANY {
+ description "match is true if given value matches any member
+ of the defined set";
+ }
+ enum ALL {
+ description "match is true if given value matches all
+ members of the defined set";
+ }
+ enum INVERT {
+ description "match is true if given value does not match any
+ member of the defined set";
+ }
+ }
+ default ANY;
+ description
+ "Options that govern the behavior of a match statement. The
+ default behavior is ANY, i.e., the given value matches any
+ of the members of the defined set";
+ }
+
+ typedef match-set-options-restricted-type {
+ type enumeration {
+ enum ANY {
+ description "match is true if given value matches any member
+ of the defined set";
+ }
+ enum INVERT {
+ description "match is true if given value does not match any
+ member of the defined set";
+ }
+ }
+ default ANY;
+ description
+ "Options that govern the behavior of a match statement. The
+ default behavior is ANY, i.e., the given value matches any
+ of the members of the defined set. Note this type is a
+ restricted version of the match-set-options-type.";
+ //TODO: restriction on enumerated types is only allowed in
+ //YANG 1.1. Until then, we will require this additional type
+ }
+
+ grouping attribute-compare-operators {
+ description "common definitions for comparison operations in
+ condition statements";
+
+ leaf operator {
+ type identityref {
+ base ATTRIBUTE_COMPARISON;
+ }
+ description
+ "type of comparison to be performed";
+ }
+
+ leaf value {
+ type uint32;
+ description
+ "value to compare with the community count";
+ }
+ }
+
+ typedef tag-type {
+ type union {
+ type uint32;
+ type yang:hex-string;
+ }
+ description "type for expressing route tags on a local system,
+ including IS-IS and OSPF; may be expressed as either decimal or
+ hexidecimal integer";
+ reference
+ "RFC 2178 OSPF Version 2
+ RFC 5130 A Policy Control Mechanism in IS-IS Using
+ Administrative Tags";
+ }
+
+ identity INSTALL_PROTOCOL_TYPE {
+ description
+ "Base type for protocols which can install prefixes into the
+ RIB";
+ }
+
+ identity BGP {
+ base INSTALL_PROTOCOL_TYPE;
+ description "BGP";
+ reference "RFC 4271";
+ }
+
+ identity ISIS {
+ base INSTALL_PROTOCOL_TYPE;
+ description "IS-IS";
+ reference "ISO/IEC 10589";
+ }
+
+ identity OSPF {
+ base INSTALL_PROTOCOL_TYPE;
+ description "OSPFv2";
+ reference "RFC 2328";
+ }
+
+ identity OSPF3 {
+ base INSTALL_PROTOCOL_TYPE;
+ description "OSPFv3";
+ reference "RFC 5340";
+ }
+
+ identity STATIC {
+ base INSTALL_PROTOCOL_TYPE;
+ description "Locally-installed static route";
+ }
+
+ identity DIRECTLY_CONNECTED {
+ base INSTALL_PROTOCOL_TYPE;
+ description "A directly connected route";
+ }
+
+ identity LOCAL_AGGREGATE {
+ base INSTALL_PROTOCOL_TYPE;
+ description "Locally defined aggregate route";
+ }
+}
diff --git a/tests/utests/netconf/yang/xos-accessibility.yang b/tests/utests/netconf/yang/xos-accessibility.yang
new file mode 100644
index 0000000..9cebf1b
--- /dev/null
+++ b/tests/utests/netconf/yang/xos-accessibility.yang
@@ -0,0 +1,462 @@
+module xos-unreconciled-models {
+ namespace "urn:ietf:params:xml:ns:yang:xos-incomplete";
+ prefix xacc;
+ yang-version 1.1;
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+ import xos-types { prefix xtype; }
+
+ organization
+ "Open Networking Lab (XOS) / Corenova Technologies";
+
+ contact
+ "Larry Peterson <llp@onlab.us>
+ Peter K. Lee <peter@corenova.com>";
+
+ description
+ "This module contains a collection of core models for XOS.
+
+ Copyright (c) 2016 ON.LAB and the persons identified as authors of
+ the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms of the Apache License, Version 2.0 which accompanies this
+ distribution, and is available at
+ (http://www.apache.org/licenses/LICENSE-2.0).";
+
+ revision 2016-09-13 {
+ description "Initial revision.";
+ }
+
+ /* Future Consideration
+ typedef image {
+ type unique-identifier;
+ }
+ typedef controller-network {
+ type unique-identifier;
+ }
+ typedef site {
+ type unique-identifier;
+ }
+ typedef tenant-root-role {
+ type unique-identifier;
+ }
+ typedef slice-role {
+ type unique-identifier;
+ }
+ typedef site-deployment {
+ type unique-identifier;
+ }
+ typedef tenant-privilege {
+ type unique-identifier;
+ }
+ typedef tag {
+ type unique-identifier;
+ }
+ typedef user-credential {
+ type unique-identifier;
+ }
+ typedef invoice {
+ type unique-identifier;
+ }
+ typedef slice-privilege {
+ type unique-identifier;
+ }
+ typedef flavor {
+ type unique-identifier;
+ }
+ typedef port {
+ type unique-identifier;
+ }
+ typedef service-role {
+ type unique-identifier;
+ }
+ typedef controller-site {
+ type unique-identifier;
+ }
+ typedef controller-slice {
+ type unique-identifier;
+ }
+ typedef tenant-role {
+ type unique-identifier;
+ }
+ typedef slice {
+ type unique-identifier;
+ }
+ typedef network {
+ type unique-identifier;
+ }
+ typedef controller-role {
+ type unique-identifier;
+ }
+ typedef diag {
+ type unique-identifier;
+ }
+ typedef service-class {
+ type unique-identifier;
+ }
+ typedef tenant-attribute {
+ type unique-identifier;
+ }
+ typedef site-role {
+ type unique-identifier;
+ }
+ typedef subscriber {
+ type unique-identifier;
+ }
+ typedef instance {
+ type unique-identifier;
+ }
+ typedef charge {
+ type unique-identifier;
+ }
+ typedef program {
+ type unique-identifier;
+ }
+ typedef role {
+ type unique-identifier;
+ }
+ typedef usable-object {
+ type unique-identifier;
+ }
+ typedef node-label {
+ type unique-identifier;
+ }
+ typedef slice-credential {
+ type unique-identifier;
+ }
+ typedef node {
+ type unique-identifier;
+ }
+ typedef address-pool {
+ type unique-identifier;
+ }
+ typedef dashboard-view {
+ type unique-identifier;
+ }
+ typedef network-parameter {
+ type unique-identifier;
+ }
+ typedef image-deployments {
+ type unique-identifier;
+ }
+ typedef controller-user {
+ type unique-identifier;
+ }
+ typedef reserved-resource {
+ type unique-identifier;
+ }
+ typedef network-template {
+ type unique-identifier;
+ }
+ typedef controller-dashboard-view {
+ type unique-identifier;
+ }
+ typedef user-dashboard-view {
+ type unique-identifier;
+ }
+ typedef controller {
+ type unique-identifier;
+ }
+ typedef user {
+ type unique-identifier;
+ }
+ typedef deployment {
+ type unique-identifier;
+ }
+ typedef reservation {
+ type unique-identifier;
+ }
+ typedef site-privilege {
+ type unique-identifier;
+ }
+ typedef payment {
+ type unique-identifier;
+ }
+ typedef tenant {
+ type unique-identifier;
+ }
+ typedef network-slice {
+ type unique-identifier;
+ }
+ typedef account {
+ type unique-identifier;
+ }
+ typedef tenant-root {
+ type unique-identifier;
+ }
+ typedef service {
+ type unique-identifier;
+ }
+ typedef controller-slice-privilege {
+ type unique-identifier;
+ }
+ typedef site-credential {
+ type unique-identifier;
+ }
+ typedef deployment-privilege {
+ type unique-identifier;
+ }
+ typedef network-parameter-type {
+ type unique-identifier;
+ }
+ typedef provider {
+ type unique-identifier;
+ }
+ typedef tenant-with-container {
+ type unique-identifier;
+ }
+ typedef deployment-role {
+ type unique-identifier;
+ }
+ typedef project {
+ type unique-identifier;
+ }
+ typedef tenant-root-privilege {
+ type unique-identifier;
+ }
+ typedef slice-tag {
+ type unique-identifier;
+ }
+ typedef coarse-tenant {
+ type unique-identifier;
+ }
+ typedef router {
+ type unique-identifier;
+ }
+ typedef service-resource {
+ type unique-identifier;
+ }
+ typedef service-privilege {
+ type unique-identifier;
+ }
+ */
+ grouping service-class {
+ uses xos-base;
+
+ leaf description {
+ type string;
+ }
+ leaf commitment {
+ type uint32;
+ }
+ leaf membership-fee {
+ type uint32;
+ }
+ leaf membership-fee-months {
+ type uint32;
+ }
+ leaf upgrade-requires-approval {
+ type boolean;
+ }
+ }
+ grouping invoice {
+ uses xos-base;
+ leaf date {
+ type xtype:datetime;
+ }
+ leaf account {
+ type xtype:account;
+ }
+ }
+
+ grouping charge {
+ uses xos-base;
+ leaf account {
+ type xtype:account;
+ }
+ leaf slice {
+ type xtype:slice;
+ }
+ leaf kind {
+ type string;
+ }
+ leaf state {
+ type string;
+ }
+ leaf date {
+ type xtype:datetime;
+ }
+ leaf object {
+ type xtype:object;
+ }
+ leaf amount {
+ type decimal64;
+ }
+ leaf core-hours {
+ type decimal64;
+ }
+ leaf invoice {
+ type xtype:invoice;
+ }
+ }
+
+ grouping role {
+ uses xos-base;
+ leaf role-type {
+ type string;
+ }
+ leaf role {
+ type string;
+ }
+ leaf description {
+ type string;
+ }
+ leaf content-type {
+ type xtype:content-type;
+ }
+ }
+
+ grouping dashboard-view {
+ uses xos-base;
+ leaf url {
+ type string;
+ }
+ leaf enabled {
+ type boolean;
+ }
+ }
+
+ grouping controller-dashboard-view {
+ uses xos-base;
+ leaf controller {
+ type xtype:controller;
+ }
+ leaf dashboardView {
+ type xtype:dashboardView;
+ }
+ leaf enabled {
+ type boolean;
+ }
+ leaf url {
+ type string;
+ }
+ }
+
+ grouping user-dashboard-view {
+ uses xos-base;
+ leaf user {
+ type xtype:user;
+ }
+ leaf dashboardView {
+ type xtype:dashboardView;
+ }
+ leaf order {
+ type uint32;
+ }
+ }
+ grouping service-privilege {
+ uses xos-base;
+ leaf user {
+ type xtype:user;
+ }
+ leaf service {
+ type xtype:service;
+ }
+ leaf role {
+ type xtype:role;
+ }
+ }
+
+ grouping payment {
+ uses xos-base;
+ leaf account {
+ type xtype:account;
+ }
+ leaf amount {
+ type decimal64;
+ }
+ leaf date {
+ type xtype:datetime;
+ }
+ }
+
+ grouping account {
+ uses xos-base;
+ leaf site {
+ type xtype:site;
+ }
+ }
+
+ grouping service-resource {
+ uses xos-base;
+ leaf service-class {
+ type xtype:service-class;
+ }
+
+ leaf max-units-deployment {
+ type uint32;
+ }
+
+ leaf max-units-node {
+ type uint32;
+ }
+
+ leaf max-duration {
+ type uint32;
+ }
+
+ leaf bucket-in-rate {
+ type uint32;
+ }
+
+ leaf bucket-max-size {
+ type uint32;
+ }
+
+ leaf cost {
+ type uint32;
+ }
+
+ leaf calendar-reservable {
+ type boolean;
+ }
+ }
+
+ grouping diag {
+ uses xos-base;
+
+ }
+
+ grouping program {
+ uses xos-base;
+ leaf description {
+ type string;
+ }
+
+ leaf kind {
+ type string;
+ }
+
+ leaf command {
+ type string;
+ }
+
+ leaf owner {
+ type xtype:owner;
+ }
+
+ leaf contents {
+ type string;
+ }
+
+ leaf output {
+ type string;
+ }
+
+ leaf messages {
+ type string;
+ }
+
+ leaf status {
+ type string;
+ }
+ }
+
+ grouping usable-object {
+ uses xos-base;
+ }
+
+}
diff --git a/tests/utests/netconf/yang/xos-controller.yang b/tests/utests/netconf/yang/xos-controller.yang
new file mode 100644
index 0000000..40ce8a6
--- /dev/null
+++ b/tests/utests/netconf/yang/xos-controller.yang
@@ -0,0 +1,225 @@
+module xos-controller {
+ namespace "urn:ietf:params:xml:ns:yang:xos-controller";
+ prefix xos;
+ yang-version 1.1;
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+ import iana-crypt-hash { prefix ianach; }
+ import yang-meta-types { prefix meta; }
+ import xos-types { prefix xtype; }
+
+ organization
+ "Open Networking Lab / Corenova Technologies";
+
+ contact
+ "Larry Peterson <llp@onlab.us>
+ Peter K. Lee <peter@corenova.com>";
+
+ description
+ "This module contains a collection of core models for XOS. The core
+ models represent primary first-order entities such as Tenant,
+ Subscriber, Provider, and Service.
+
+ Copyright (c) 2016 ON.LAB and the persons identified as authors of
+ the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms of the Apache License, Version 2.0 which accompanies this
+ distribution, and is available at
+ (http://www.apache.org/licenses/LICENSE-2.0).";
+
+ revision 2016-07-14 {
+ description "Initial revision.";
+ }
+
+ identity xos-tenant {
+ description "Describes the type of tenant within XOS";
+ }
+ identity xos-subscriber {
+ base xos-tenant;
+ }
+ identity xos-provider {
+ base xos-tenant;
+ }
+ identity xos-service {
+ base xos-provider;
+ }
+
+ feature synchronizer {
+ description
+ "Enables configuration synchronization to the distributed store.";
+ }
+ /*
+ * Groupings
+ */
+ grouping record {
+ description "Synchronizer-specific properties for model entities";
+
+ leaf created { type yang:date-and-time; }
+ leaf updated { type yang:date-and-time; }
+ leaf enacted { type yang:date-and-time; }
+ leaf policed { type yang:date-and-time; }
+
+ leaf writable { type boolean; default true; }
+ leaf locked { type boolean; default false; }
+ leaf deleted { type boolean; default false; }
+
+ leaf dirty {
+ config false;
+ type boolean;
+ default false;
+ }
+
+ container sync {
+ anydata register {
+ description "scratchpad used by the Observer";
+ }
+ leaf progress {
+ type enumeration {
+ enum provisioning {
+ value 0;
+ description "Provisioning in progress";
+ }
+ }
+ }
+ leaf disabled { type boolean; default false; }
+ leaf enforced { type boolean; default true; }
+
+ list policy {
+ // TODO: how are policy defined/enforced?
+ }
+ }
+ action diff {
+ description "retrieve diff of model state if dirty";
+ }
+ action save {
+ description "trigger save into data store via synchronizer";
+ }
+ }
+ grouping credentials-list {
+ list credential {
+ key token;
+ leaf token {
+ type string;
+ }
+ leaf password {
+ type meta:password;
+ }
+ leaf user {
+ type xtype:unique-identifier;
+ }
+ leaf role {
+ type xtype:access-role;
+ }
+ }
+ }
+ grouping parameter {
+ leaf name { type yang:yang-identifier; }
+ leaf value { type string; }
+ leaf content-type { type string; }
+ leaf object-id { type uint32; }
+ }
+ grouping tenant {
+ leaf id {
+ type xtype:unique-identifier;
+ mandatory true;
+ }
+ leaf name { type string { length 0..255; } }
+ leaf kind {
+ config false;
+ type identityref {
+ base xos-tenant;
+ }
+ }
+ leaf description { type meta:description; }
+ leaf enabled { type boolean; default true; }
+ container record {
+ if-feature synchronizer;
+ uses xos:record;
+ }
+ }
+ grouping subscriber {
+ uses xos:tenant {
+ refine kind { default xos-subscriber; }
+ }
+ leaf connectivity {
+ type enumeration {
+ enum public { description "Public"; }
+ enum private { description "Private"; }
+ enum private-unidirectional { description "Private Uni-directional"; }
+ enum na { description "Not Applicable"; }
+ }
+ default na;
+ }
+ }
+ grouping provider {
+ uses xos:tenant {
+ refine kind { default xos-provider; }
+ }
+ uses xos:credentials-list;
+ }
+ grouping service {
+ uses xos:provider {
+ refine 'name' {
+ description "Name of the Service";
+ }
+ }
+ leaf view-url {
+ type inet:uri;
+ }
+ leaf icon-url {
+ type inet:uri;
+ }
+ leaf published {
+ type boolean;
+ default true;
+ }
+ list keypair {
+ description "collection of public/private key pair(s)";
+ // should be a specific typedef for storing this content
+ leaf public { type string { length 0..1024; } }
+ leaf private { type string { length 0..1024; } }
+ }
+ list attribute {
+ key name;
+ leaf name { type string { length 0..128; } }
+ leaf value { type string; }
+ status deprecated;
+ reference "XOS: service-specific-attribute";
+ description "backwards-compatible attribute association";
+ }
+ leaf service-specific-id {
+ type xtype:unique-identifier;
+ status deprecated;
+ }
+ list subscriber {
+ description
+ "Each entry represents a subscriber of the service. Each unique service
+ provider should augment this block with service specific
+ attributes.";
+ key id;
+ uses xos:subscriber;
+ notification subscriber-added;
+ notification subscriber-deleted;
+ }
+ // TODO: need to better understand relationship between Service and VTN
+ }
+ /*
+ * Configuration data nodes (main configuration tree for XOS)
+ */
+ container core {
+ description
+ "Primary endpoint for additional core entities to augment";
+ uses xos:provider;
+ }
+ container service {
+ description
+ "Primary endpoint for services to augment";
+ }
+ container tenant {
+ description
+ "Primary endpoint for tenants to augment";
+ }
+}
diff --git a/tests/utests/netconf/yang/xos-core-service.yang b/tests/utests/netconf/yang/xos-core-service.yang
new file mode 100644
index 0000000..3923221
--- /dev/null
+++ b/tests/utests/netconf/yang/xos-core-service.yang
@@ -0,0 +1,120 @@
+module xos-core-service {
+ namespace "urn:xos:core:service";
+ prefix xos-cs;
+
+ import complex-types { prefix ct; }
+
+ revision 2015-10-01 {
+ description "Initial revision.";
+ }
+
+ grouping service-attribute {
+ leaf name { type string { length 128; } }
+ leaf value { type string { length 1024; } }
+ leaf service {
+ type instance-identifier { ct:instance-type Service; require-instance true; }
+ }
+ }
+
+ grouping service-role {
+ leaf role {
+ type enumeration {
+ enum "admin";
+ //enum "Admin";
+ }
+ }
+ }
+
+ grouping common-model-attr {
+ leaf kind {
+ type string { length 30; }
+ default "generic";
+ }
+ leaf name { type string { length 255; } }
+ }
+
+ ct:complex-type ServiceElement {
+ ct:abstract true;
+ leaf enabled { type boolean; default true; }
+ }
+
+ ct:complex-type Service {
+ ct:extends ServiceElement;
+
+ leaf description {
+ type string { length 255; }
+ description "Description of Service";
+ }
+ leaf published { type boolean; default true; }
+
+ uses common-model-attr {
+ refine kind {
+ description "Kind of Service";
+ }
+ refine name {
+ description "Service Name";
+ }
+ }
+ }
+
+ ct:complex-type User {
+ ct:extends ServiceElement;
+ // TBD - should go to a separate xos-core-user module or such
+ }
+
+ ct:complex-type ServicePrivilege {
+ key "user-service-role";
+
+ leaf user {
+ type instance-identifier { ct:instance-type User; require-instance true; }
+ }
+ leaf service {
+ type instance-identifier { ct:instance-type Service; }
+ }
+ uses service-role;
+ }
+
+ ct:complex-type TenantRoot {
+ ct:extends ServiceElement;
+
+ description
+ "A tenantRoot is one of the things that can sit at the root of a chain
+ of tenancy. This object represents a node.";
+ uses common-model-attr;
+ }
+
+ ct:complex-type ContainerImage {
+ // TBD
+ }
+
+ ct:complex-type Tenancy {
+ ct:extends ServiceElement;
+
+ description
+ "A Tenancy describes relationship between a subscriber and a provider";
+
+ uses common-model-attr;
+
+ leaf provider { type instance-identifer { ct:instance-type Service; } }
+ leaf subscriber {
+ type instance-identifier {
+ ct:instance-type ServiceElement;
+ }
+ }
+
+ // adding stuff from TenantWithContainer here...
+ leaf creator { type instance-identifier { ct:instance-type User; } }
+ leaf image { type instance-identifier { ct:instance-type ContainerImage; } }
+ }
+
+ ct:complex-type Subscriber {
+ ct:extends TenantRoot;
+ refine kind { default "Subscriber"; }
+ }
+
+ ct:complex-type Provider {
+ ct:extends TenantRoot;
+ refine kind { default "Provider"; }
+ }
+
+}
diff --git a/tests/utests/netconf/yang/xos-openstack.yang b/tests/utests/netconf/yang/xos-openstack.yang
new file mode 100644
index 0000000..3f79fe0
--- /dev/null
+++ b/tests/utests/netconf/yang/xos-openstack.yang
@@ -0,0 +1,190 @@
+module xos-controller {
+ namespace "urn:ietf:params:xml:ns:yang:xos-controller";
+ prefix xcontrol;
+ yang-version 1.1;
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+ import xos-core { prefix xos; }
+ import xos-types { prefix xtype; }
+
+ organization
+ "Open Networking Lab (XOS) / Corenova Technologies";
+
+ contact
+ "Larry Peterson <llp@onlab.us>
+ Peter K. Lee <peter@corenova.com>";
+
+ description
+ "This module contains a collection of Controller models for XOS.
+
+ Copyright (c) 2016 ON.LAB and the persons identified as authors of
+ the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms of the Apache License, Version 2.0 which accompanies this
+ distribution, and is available at
+ (http://www.apache.org/licenses/LICENSE-2.0).";
+
+ revision 2016-09-23 {
+ description "Initial revision.";
+ }
+
+ grouping controller {
+ uses xos:provider;
+ leaf backend-type {
+ type string;
+ }
+ leaf version {
+ type string;
+ }
+ leaf auth-url {
+ type string;
+ }
+ leaf admin-user {
+ type string;
+ }
+ leaf admin-password {
+ type string;
+ }
+ leaf admin-tenant {
+ type string;
+ }
+ leaf domain {
+ type string;
+ }
+ container message-queue {
+ leaf rabbit-host {
+ type string;
+ }
+ leaf rabbit-user {
+ type string;
+ }
+ leaf rabbit-password {
+ type string;
+ }
+ }
+ leaf deployment {
+ type xtype:deployment;
+ }
+ }
+ grouping controller-site-privilege {
+ uses xos:tenant;
+
+ leaf controller {
+ type xtype:controller;
+ }
+
+ leaf site-privilege {
+ type xtype:site-privilege;
+ }
+
+ container synchronizer {
+ if-feature xos:synchronizer;
+ leaf role-id {
+ type string;
+ }
+ }
+ }
+ grouping controller-network {
+ uses xos:tenant;
+ leaf network {
+ type xtype:network;
+ }
+ leaf controller {
+ type xtype:controller;
+ }
+ leaf subnet {
+ type string;
+ }
+ container synchronizer {
+ if-feature synchronizer;
+ leaf net-id {
+ type string;
+ }
+ leaf router-id {
+ type string;
+ }
+ leaf subnet-id {
+ type string;
+ }
+ }
+ }
+ grouping controller-site {
+ uses xos:tenant;
+ leaf site {
+ type xtype:site;
+ }
+
+ leaf controller {
+ type xtype:controller;
+ }
+
+ container synchronizer {
+ if-feature synchronizer;
+ leaf tenant-id {
+ type string;
+ }
+ }
+ }
+ grouping controller-slice {
+ uses xos:tenant;
+ leaf controller {
+ type xtype:controller;
+ }
+ leaf slice {
+ type xtype:slice;
+ }
+
+ container synchronizer {
+ if-feature synchronizer;
+ leaf tenant-id {
+ type string;
+ }
+ }
+ }
+ grouping controller-role {
+ uses xos:tenant;
+ leaf role {
+ type string;
+ }
+ }
+ grouping controller-user {
+ uses xos:tenant;
+ leaf user {
+ type xtype:user;
+ }
+
+ leaf controller {
+ type xtype:controller;
+ }
+
+ container synchronizer {
+ if-feature synchronizer {
+ leaf kuser-id {
+ type string;
+ }
+ }
+ }
+ }
+ grouping controller-slice-privilege {
+ uses xos:tenant;
+ leaf controller {
+ type xtype:controller;
+ }
+
+ leaf slice-privilege {
+ type xtype:slice-privilege;
+ }
+
+ container synchronizer {
+ if-feature synchronizer {
+ leaf role-id {
+ type string;
+ }
+ }
+ }
+ }
+
+}
diff --git a/tests/utests/netconf/yang/xos-package.yang b/tests/utests/netconf/yang/xos-package.yang
new file mode 100644
index 0000000..e6a0537
--- /dev/null
+++ b/tests/utests/netconf/yang/xos-package.yang
@@ -0,0 +1,84 @@
+module xos-package {
+ namespace "urn:ietf:params:xml:ns:yang:xos-package";
+ prefix xpkg;
+ yang-version 1.1;
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+ import yang-meta-types { prefix meta; }
+ import xos-controller { prefix xos; }
+ import xos-types { prefix xtype; }
+
+ organization
+ "Open Networking Lab (XOS) / Corenova Technologies";
+
+ contact
+ "Larry Peterson <llp@onlab.us>
+ Peter K. Lee <peter@corenova.com>";
+
+ description
+ "This module contains a collection of Package models for XOS.
+
+ Copyright (c) 2016 ON.LAB and the persons identified as authors of
+ the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms of the Apache License, Version 2.0 which accompanies this
+ distribution, and is available at
+ (http://www.apache.org/licenses/LICENSE-2.0).";
+
+ revision 2016-09-29 {
+ description "Initial revision.";
+ }
+ typedef package-identifier {
+ type yang:yang-identifier;
+ }
+
+ identity xos-package {
+ base xos:xos-tenant;
+ }
+ /*
+ * Groupings
+ */
+ grouping package-info {
+ uses meta:yang-package-info {
+ refine version {
+ description "Version of Service Definition";
+ }
+ refine description {
+ description "Description of the Service Package";
+ }
+ }
+ container controller {
+ leaf model {
+ type leafref {
+ path "../../model/name";
+ }
+ mandatory true;
+ }
+ leaf initializer {
+ type meta:filename;
+ }
+ leaf synchronizer {
+ type meta:filename;
+ }
+ leaf public-key {
+ type meta:filename;
+ }
+ leaf private-key {
+ type meta:filename;
+ }
+ }
+ }
+ /*
+ * Augmentations to XOS
+ */
+ augment "/xos:core" {
+ list package {
+ key id;
+ uses package-info;
+ }
+ }
+}
+
diff --git a/tests/utests/netconf/yang/xos-slice.yang b/tests/utests/netconf/yang/xos-slice.yang
new file mode 100644
index 0000000..1878575
--- /dev/null
+++ b/tests/utests/netconf/yang/xos-slice.yang
@@ -0,0 +1,263 @@
+module xos-slice {
+ namespace "urn:ietf:params:xml:ns:yang:xos-slice";
+ prefix xslice;
+ yang-version 1.1;
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+ import xos-controller { prefix xos; }
+ import xos-types { prefix xtype; }
+ import opnfv-infrastructure { prefix nfvi; }
+
+ organization
+ "Open Networking Lab (XOS) / Corenova Technologies, Inc.";
+
+ contact
+ "Larry Peterson <llp@onlab.us>
+ Peter K. Lee <peter@corenova.com>";
+
+ description
+ "This module contains a collection of Slice and related models for XOS.
+
+ Copyright (c) 2016 ON.LAB and the persons identified as authors of
+ the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms of the Apache License, Version 2.0 which accompanies this
+ distribution, and is available at
+ (http://www.apache.org/licenses/LICENSE-2.0).";
+
+ revision 2016-09-13 {
+ description "Initial revision.";
+ }
+
+ grouping slice {
+ description
+ "A slice is a logically centralized container for network and compute resources";
+
+ uses xos:provider {
+ refine "name" { description "Name of the slice"; }
+ }
+ leaf slice-url {
+ description "A URL describing the purpose of this slice";
+ type inet:uri;
+ // blank true;
+ }
+ leaf-list instances {
+ type leafref {
+ path "/nfvi:controller/compute/server/id";
+ }
+ }
+ leaf-list networks {
+ type leafref {
+ path "/nfvi:controller/fabric/network/id";
+ }
+ }
+ container policy {
+ leaf max-instances {
+ description "The maximum number of VMs that this slice is allowed to allocate";
+ type uint16;
+ }
+ leaf default-flavor {
+ type leafref {
+ path "/nfvi:controller/compute/flavor/id";
+ }
+ }
+ leaf default-image {
+ type leafref {
+ path "/nfvi:controller/compute/image/id";
+ }
+ }
+ leaf default-node {
+ type leafref {
+ path "/nfvi:controller/compute/host/id";
+ }
+ }
+ leaf mount-data-sets {
+ type string {
+ length 0..256;
+ }
+ default "GenBank";
+ }
+ leaf default-isolation {
+ type xtype:isolation;
+ }
+ }
+ leaf network {
+ description
+ "The network that the slice uses to connect to other slices and to the Internet.";
+ type enumeration {
+ enum none;
+ enum host;
+ enum bridged;
+ enum noauto;
+ }
+ default none;
+ }
+ leaf-list ports {
+ description
+ "The ports to be exposed for other slices to connect to";
+ type uint16;
+ }
+ leaf creator {
+ type leafref {
+ path "/xos:core/user/id";
+ }
+ }
+ leaf-list tags {
+ type string;
+ }
+ // below are deprecated and should not be used
+ leaf service {
+ description "The service that runs in this slice";
+ status deprecated;
+ }
+ // TOOD: need to better understand relationship between Service and Slice
+ action scale {
+ description "Adjust scale for slice(s)";
+ }
+ }
+
+ /*
+ * Augmentations to XOS core and NFVI modules
+ */
+ augment "/xos:core" {
+ list slice {
+ key id;
+ uses xslice:slice;
+ }
+ }
+
+ augment "/nfvi:controller/nfvi:compute/nfvi:server" {
+ leaf slice {
+ // do we need this circular reference?
+ }
+ leaf deployment {
+ type leafref {
+ path "/xos:core/deployment/id";
+ }
+ }
+ leaf isolation {
+ type xtype:isolation;
+ }
+ leaf-list volumes {
+ type string; // should be leafref
+ }
+ // leaf parent {
+ // type xtype:parent;
+ // }
+ container synchronizer {
+ if-feature synchronizer;
+ leaf instance-id {
+ type string;
+ }
+ leaf instance-uuid {
+ type string;
+ }
+ leaf instance-name {
+ type string;
+ }
+ leaf ip {
+ type inet:ip-address;
+ }
+ }
+ }
+ augment "/nfvi:controller/nfvi:compute/nfvi:image" {
+ leaf template {
+ type leafref {
+ path "/xos:core/template/id";
+ }
+ }
+ leaf-list deployments {
+ type leafref {
+ path "/xos:core/deployment/id";
+ }
+ }
+ container synchronizer {
+ if-feature xos:synchronizer;
+ leaf glance-image-id {
+ type string;
+ }
+ }
+ }
+ augment "/nfvi:controller/nfvi:fabric/nfvi:network" {
+ leaf autoconnect {
+ type boolean;
+ default true;
+ }
+ leaf-list labels {
+ type string;
+ }
+ container policy {
+ leaf guaranteed-bandwidth {
+ type uint32;
+ }
+ leaf permit-all-slices {
+ type boolean;
+ default true;
+ }
+ container parameters {
+ list topology {
+ key name;
+ uses xos:parameter;
+ }
+ list controller {
+ key name;
+ uses xos:parameter;
+ }
+ list network {
+ key name;
+ uses xos:parameter;
+ }
+ }
+ }
+ container synchronizer {
+ if-feature synchronizer;
+ leaf network-id {
+ type string;
+ }
+ leaf router-id {
+ type string;
+ }
+ leaf subnet-id {
+ type string;
+ }
+ }
+ }
+ augment "/nfvi:controller/nfvi:fabric/nfvi:network/nfvi:subnet/nfvi:port" {
+ leaf instance {
+ type instance-identifier;
+ }
+ leaf xos-created {
+ type boolean;
+ status deprecated;
+ }
+ container synchronizer {
+ if-feature xos:synchronizer;
+ leaf ip {
+ type inet:ip-address;
+ }
+ leaf port-id {
+ type yang:uuid;
+ }
+ leaf mac {
+ type yang:mac-address;
+ }
+ }
+ }
+ augment "/nfvi:controller/nfvi:fabric/nfvi:network/nfvi:subnet/nfvi:dhcp/nfvi:pool" {
+ leaf gateway-ip {
+ type inet:ip-address;
+ }
+ leaf gateway-mac {
+ type yang:mac-address;
+ }
+ leaf cidr {
+ type string;
+ }
+ leaf inuse {
+ type boolean;
+ }
+ }
+}
diff --git a/tests/utests/netconf/yang/xos-topology.yang b/tests/utests/netconf/yang/xos-topology.yang
new file mode 100644
index 0000000..469cb84
--- /dev/null
+++ b/tests/utests/netconf/yang/xos-topology.yang
@@ -0,0 +1,224 @@
+module xos-topology {
+ namespace "urn:ietf:params:xml:ns:yang:xos-topology";
+ prefix xtop;
+ yang-version 1.1;
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+ import yang-meta-types { prefix meta; }
+ import xos-controller { prefix xos; }
+ import xos-types { prefix xtype; }
+
+ organization
+ "Open Networking Lab (XOS) / Corenova Technologies";
+
+ contact
+ "Larry Peterson <llp@onlab.us>
+ Peter K. Lee <peter@corenova.com>";
+
+ description
+ "This module contains a collection of Topology models for XOS.
+
+ Copyright (c) 2016 ON.LAB and the persons identified as authors of
+ the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms of the Apache License, Version 2.0 which accompanies this
+ distribution, and is available at
+ (http://www.apache.org/licenses/LICENSE-2.0).";
+
+ revision 2016-09-13 {
+ description "Initial revision.";
+ }
+
+ grouping deployment {
+ uses xos:provider {
+ refine "name" { description "Name of the deployment"; }
+ }
+ leaf-list sites {
+ config false;
+ type leafref {
+ path "/xos:core/site/id";
+ }
+ }
+ leaf-list templates {
+ type leafref {
+ path "/xos:core/template/id";
+ }
+ }
+ }
+ grouping site {
+ uses xos:provider {
+ refine "name" { description "Name of the site"; }
+ }
+ leaf site-url {
+ description "A URL describing the purpose of this site";
+ type inet:uri;
+ }
+ container location {
+ leaf geoposition {
+ type string; // what is this data format?
+ }
+ leaf longitude {
+ type decimal64;
+ }
+ leaf latitude {
+ type decimal64;
+ }
+ }
+ leaf is-public {
+ type boolean;
+ }
+ leaf login-base {
+ type string;
+ }
+ leaf deployment {
+ type leafref {
+ path "/xos:core/deployment/id";
+ }
+ }
+ leaf-list nodes {
+ config false;
+ type leafref {
+ path "/xos:core/node/id";
+ }
+ }
+ leaf-list users {
+ config false;
+ type leafref {
+ path "/xos:core/user/id";
+ }
+ }
+ leaf hosts-nodes {
+ config false;
+ type boolean;
+ }
+ leaf hosts-users {
+ config false;
+ type boolean;
+ }
+ container synchronizer {
+ if-feature xos:synchronizer;
+ leaf availability-zone {
+ type string;
+ }
+ }
+ }
+ grouping node {
+ uses xos:tenant;
+ leaf site {
+ type leafref {
+ path "/xos:core/site/id";
+ }
+ }
+ leaf deployment {
+ config false;
+ type leafref {
+ path "/xos:core/deployment/id";
+ }
+ }
+ }
+ grouping user {
+ uses xos:tenant {
+ refine 'name' {
+ config false;
+ description "Name of the user";
+ }
+ }
+ leaf firstname {
+ type meta:person-name;
+ }
+ leaf lastname {
+ type meta:person-name;
+ }
+ leaf email {
+ type meta:email-address;
+ }
+ leaf phone {
+ type meta:phone-number;
+ }
+ leaf timezone {
+ type meta:timezone;
+ }
+ leaf site {
+ type leafref {
+ path "/xos:core/site/id";
+ }
+ }
+ container credential {
+ leaf username {
+ type yang:yang-identifier;
+ }
+ leaf password {
+ type meta:password;
+ }
+ leaf role {
+ type xtype:access-role;
+ }
+ leaf public-key {
+ type string;
+ }
+ leaf login-page {
+ type inet:uri;
+ }
+ leaf last-login {
+ config false;
+ type yang:date-and-time;
+ }
+ }
+ }
+ grouping network-template {
+ uses xos:tenant;
+ leaf guaranteed-bandwidth {
+ type uint32;
+ }
+ leaf visibility {
+ type string;
+ }
+ leaf translation {
+ type string;
+ }
+ leaf access {
+ type string;
+ }
+ leaf shared-network-name {
+ type string;
+ }
+ leaf shared-network-id {
+ type string;
+ }
+ leaf topology-kind {
+ type string;
+ }
+ leaf controller-kind {
+ type string;
+ }
+ }
+
+ /*
+ * Augmentations to XOS core
+ */
+ augment "/xos:core" {
+ list template {
+ key id;
+ uses xtop:network-template;
+ }
+ list deployment {
+ key id;
+ uses xtop:deployment;
+ }
+ list site {
+ key id;
+ uses xtop:site;
+ }
+ list node {
+ key id;
+ uses xtop:node;
+ }
+ list user {
+ key id;
+ uses xtop:user;
+ }
+ }
+}
diff --git a/tests/utests/netconf/yang/xos-types.yang b/tests/utests/netconf/yang/xos-types.yang
new file mode 100644
index 0000000..289587a
--- /dev/null
+++ b/tests/utests/netconf/yang/xos-types.yang
@@ -0,0 +1,87 @@
+module xos-types {
+ namespace "urn:ietf:params:xml:ns:yang:xos-types";
+ prefix xtype;
+ yang-version 1.1;
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+
+ organization
+ "Open Networking Lab (CORD) / Corenova Technologies";
+
+ contact
+ "Larry Peterson <llp@onlab.us>
+ Peter K. Lee <peter@corenova.com>";
+
+ description
+ "This module contains a collection of common models and types for XOS.
+
+ Copyright (c) 2016 ON.LAB and the persons identified as authors of
+ the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms of the Apache License, Version 2.0 which accompanies this
+ distribution, and is available at
+ (http://www.apache.org/licenses/LICENSE-2.0).";
+
+ revision 2016-09-12 {
+ description "Initial revision.";
+ }
+
+ /*
+ * Typedefs
+ */
+ typedef unique-identifier {
+ description "defines valid formats for external reference id";
+ type union {
+ type uint32 { range 1..max; }
+ type yang:uuid;
+ type inet:uri;
+ }
+ }
+ typedef flow-identifier {
+ description "defines valid format for identifying a flow";
+ type yang:uuid;
+ }
+ typedef network-identifier {
+ description "defines valid format for identifying a network";
+ type yang:uuid;
+ }
+ typedef mac-address {
+ description "defines valid format for mac-address";
+ type yang:mac-address;
+ }
+ typedef bandwidth {
+ type uint32 {
+ range 1000000..max; // should be at least 1 Mbps?
+ }
+ units 'bps';
+ }
+ typedef vlan {
+ type uint16 { range 0..4095; }
+ }
+ typedef isolation {
+ type enumeration {
+ enum vm { description 'Virtual Machine'; }
+ enum lxc { description 'Container'; }
+ enum hybrid { description 'Container in Virtual Machine'; }
+ }
+ default 'vm';
+ }
+ typedef access-role {
+ type enumeration {
+ enum admin;
+ enum staff;
+ enum user;
+ }
+ default 'user';
+ }
+ typedef certificate {
+ description
+ "Captures a security certificate, should be improved for better validation";
+ type string {
+ length 0..1024;
+ }
+ }
+}
diff --git a/tests/utests/netconf/yang/xos-unreconciled-models.yang b/tests/utests/netconf/yang/xos-unreconciled-models.yang
new file mode 100644
index 0000000..491a153
--- /dev/null
+++ b/tests/utests/netconf/yang/xos-unreconciled-models.yang
@@ -0,0 +1,462 @@
+module xos-accessibility {
+ namespace "urn:ietf:params:xml:ns:yang:xos-accessibility";
+ prefix xacc;
+ yang-version 1.1;
+
+ import ietf-yang-types { prefix yang; }
+ import ietf-inet-types { prefix inet; }
+ import xos-types { prefix xtype; }
+
+ organization
+ "Open Networking Lab (XOS) / Corenova Technologies";
+
+ contact
+ "Larry Peterson <llp@onlab.us>
+ Peter K. Lee <peter@corenova.com>";
+
+ description
+ "This module contains a collection of core models for XOS.
+
+ Copyright (c) 2016 ON.LAB and the persons identified as authors of
+ the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, is permitted pursuant to, and subject to the license
+ terms of the Apache License, Version 2.0 which accompanies this
+ distribution, and is available at
+ (http://www.apache.org/licenses/LICENSE-2.0).";
+
+ revision 2016-09-13 {
+ description "Initial revision.";
+ }
+
+ /* Future Consideration
+ typedef image {
+ type unique-identifier;
+ }
+ typedef controller-network {
+ type unique-identifier;
+ }
+ typedef site {
+ type unique-identifier;
+ }
+ typedef tenant-root-role {
+ type unique-identifier;
+ }
+ typedef slice-role {
+ type unique-identifier;
+ }
+ typedef site-deployment {
+ type unique-identifier;
+ }
+ typedef tenant-privilege {
+ type unique-identifier;
+ }
+ typedef tag {
+ type unique-identifier;
+ }
+ typedef user-credential {
+ type unique-identifier;
+ }
+ typedef invoice {
+ type unique-identifier;
+ }
+ typedef slice-privilege {
+ type unique-identifier;
+ }
+ typedef flavor {
+ type unique-identifier;
+ }
+ typedef port {
+ type unique-identifier;
+ }
+ typedef service-role {
+ type unique-identifier;
+ }
+ typedef controller-site {
+ type unique-identifier;
+ }
+ typedef controller-slice {
+ type unique-identifier;
+ }
+ typedef tenant-role {
+ type unique-identifier;
+ }
+ typedef slice {
+ type unique-identifier;
+ }
+ typedef network {
+ type unique-identifier;
+ }
+ typedef controller-role {
+ type unique-identifier;
+ }
+ typedef diag {
+ type unique-identifier;
+ }
+ typedef service-class {
+ type unique-identifier;
+ }
+ typedef tenant-attribute {
+ type unique-identifier;
+ }
+ typedef site-role {
+ type unique-identifier;
+ }
+ typedef subscriber {
+ type unique-identifier;
+ }
+ typedef instance {
+ type unique-identifier;
+ }
+ typedef charge {
+ type unique-identifier;
+ }
+ typedef program {
+ type unique-identifier;
+ }
+ typedef role {
+ type unique-identifier;
+ }
+ typedef usable-object {
+ type unique-identifier;
+ }
+ typedef node-label {
+ type unique-identifier;
+ }
+ typedef slice-credential {
+ type unique-identifier;
+ }
+ typedef node {
+ type unique-identifier;
+ }
+ typedef address-pool {
+ type unique-identifier;
+ }
+ typedef dashboard-view {
+ type unique-identifier;
+ }
+ typedef network-parameter {
+ type unique-identifier;
+ }
+ typedef image-deployments {
+ type unique-identifier;
+ }
+ typedef controller-user {
+ type unique-identifier;
+ }
+ typedef reserved-resource {
+ type unique-identifier;
+ }
+ typedef network-template {
+ type unique-identifier;
+ }
+ typedef controller-dashboard-view {
+ type unique-identifier;
+ }
+ typedef user-dashboard-view {
+ type unique-identifier;
+ }
+ typedef controller {
+ type unique-identifier;
+ }
+ typedef user {
+ type unique-identifier;
+ }
+ typedef deployment {
+ type unique-identifier;
+ }
+ typedef reservation {
+ type unique-identifier;
+ }
+ typedef site-privilege {
+ type unique-identifier;
+ }
+ typedef payment {
+ type unique-identifier;
+ }
+ typedef tenant {
+ type unique-identifier;
+ }
+ typedef network-slice {
+ type unique-identifier;
+ }
+ typedef account {
+ type unique-identifier;
+ }
+ typedef tenant-root {
+ type unique-identifier;
+ }
+ typedef service {
+ type unique-identifier;
+ }
+ typedef controller-slice-privilege {
+ type unique-identifier;
+ }
+ typedef site-credential {
+ type unique-identifier;
+ }
+ typedef deployment-privilege {
+ type unique-identifier;
+ }
+ typedef network-parameter-type {
+ type unique-identifier;
+ }
+ typedef provider {
+ type unique-identifier;
+ }
+ typedef tenant-with-container {
+ type unique-identifier;
+ }
+ typedef deployment-role {
+ type unique-identifier;
+ }
+ typedef project {
+ type unique-identifier;
+ }
+ typedef tenant-root-privilege {
+ type unique-identifier;
+ }
+ typedef slice-tag {
+ type unique-identifier;
+ }
+ typedef coarse-tenant {
+ type unique-identifier;
+ }
+ typedef router {
+ type unique-identifier;
+ }
+ typedef service-resource {
+ type unique-identifier;
+ }
+ typedef service-privilege {
+ type unique-identifier;
+ }
+ */
+ grouping service-class {
+ uses xos-base;
+
+ leaf description {
+ type string;
+ }
+ leaf commitment {
+ type uint32;
+ }
+ leaf membership-fee {
+ type uint32;
+ }
+ leaf membership-fee-months {
+ type uint32;
+ }
+ leaf upgrade-requires-approval {
+ type boolean;
+ }
+ }
+ grouping invoice {
+ uses xos-base;
+ leaf date {
+ type xtype:datetime;
+ }
+ leaf account {
+ type xtype:account;
+ }
+ }
+
+ grouping charge {
+ uses xos-base;
+ leaf account {
+ type xtype:account;
+ }
+ leaf slice {
+ type xtype:slice;
+ }
+ leaf kind {
+ type string;
+ }
+ leaf state {
+ type string;
+ }
+ leaf date {
+ type xtype:datetime;
+ }
+ leaf object {
+ type xtype:object;
+ }
+ leaf amount {
+ type decimal64;
+ }
+ leaf core-hours {
+ type decimal64;
+ }
+ leaf invoice {
+ type xtype:invoice;
+ }
+ }
+
+ grouping role {
+ uses xos-base;
+ leaf role-type {
+ type string;
+ }
+ leaf role {
+ type string;
+ }
+ leaf description {
+ type string;
+ }
+ leaf content-type {
+ type xtype:content-type;
+ }
+ }
+
+ grouping dashboard-view {
+ uses xos-base;
+ leaf url {
+ type string;
+ }
+ leaf enabled {
+ type boolean;
+ }
+ }
+
+ grouping controller-dashboard-view {
+ uses xos-base;
+ leaf controller {
+ type xtype:controller;
+ }
+ leaf dashboardView {
+ type xtype:dashboardView;
+ }
+ leaf enabled {
+ type boolean;
+ }
+ leaf url {
+ type string;
+ }
+ }
+
+ grouping user-dashboard-view {
+ uses xos-base;
+ leaf user {
+ type xtype:user;
+ }
+ leaf dashboardView {
+ type xtype:dashboardView;
+ }
+ leaf order {
+ type uint32;
+ }
+ }
+ grouping service-privilege {
+ uses xos-base;
+ leaf user {
+ type xtype:user;
+ }
+ leaf service {
+ type xtype:service;
+ }
+ leaf role {
+ type xtype:role;
+ }
+ }
+
+ grouping payment {
+ uses xos-base;
+ leaf account {
+ type xtype:account;
+ }
+ leaf amount {
+ type decimal64;
+ }
+ leaf date {
+ type xtype:datetime;
+ }
+ }
+
+ grouping account {
+ uses xos-base;
+ leaf site {
+ type xtype:site;
+ }
+ }
+
+ grouping service-resource {
+ uses xos-base;
+ leaf service-class {
+ type xtype:service-class;
+ }
+
+ leaf max-units-deployment {
+ type uint32;
+ }
+
+ leaf max-units-node {
+ type uint32;
+ }
+
+ leaf max-duration {
+ type uint32;
+ }
+
+ leaf bucket-in-rate {
+ type uint32;
+ }
+
+ leaf bucket-max-size {
+ type uint32;
+ }
+
+ leaf cost {
+ type uint32;
+ }
+
+ leaf calendar-reservable {
+ type boolean;
+ }
+ }
+
+ grouping diag {
+ uses xos-base;
+
+ }
+
+ grouping program {
+ uses xos-base;
+ leaf description {
+ type string;
+ }
+
+ leaf kind {
+ type string;
+ }
+
+ leaf command {
+ type string;
+ }
+
+ leaf owner {
+ type xtype:owner;
+ }
+
+ leaf contents {
+ type string;
+ }
+
+ leaf output {
+ type string;
+ }
+
+ leaf messages {
+ type string;
+ }
+
+ leaf status {
+ type string;
+ }
+ }
+
+ grouping usable-object {
+ uses xos-base;
+ }
+
+}
diff --git a/tests/utests/netconf/yang/yang_to_protobuf_test.py b/tests/utests/netconf/yang/yang_to_protobuf_test.py
new file mode 100644
index 0000000..cd142fd
--- /dev/null
+++ b/tests/utests/netconf/yang/yang_to_protobuf_test.py
@@ -0,0 +1,198 @@
+#
+# Copyright 2016 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
+import json
+import os
+from unittest import TestCase
+import time
+from tests.itests.docutests.test_utils import run_command_to_completion_with_raw_stdout
+from tests.utests.chameleon.protoc_plugins.test_utils import load_file
+
+
+pyang_cmd = "pyang --plugindir /voltha/experiments/plugin -f protobuf " \
+ "-p /voltha/tests/utests/netconf/yang " \
+ "/voltha/tests/utests/netconf/yang/{}"
+
+class YangToProtoBufTests(TestCase):
+
+ def _compare_file(self, response, expected_response):
+ # compare two files and strip empty lines, blanks, etc
+ def _filter(x):
+ x.strip()
+ return x is not None
+
+ response = filter(_filter,response.split())
+ expected_response = filter(_filter,expected_response.split())
+ self.assertEqual(set(response), set(expected_response))
+
+
+ def test_01_basic_def(self):
+ print "Test_01_basic_def_Start:------------------"
+ t0 = time.time()
+
+ # input file: /voltha/tests/utests/netconf/yang/basic.yang
+
+ expected_response = """
+ syntax = "proto3";
+ package basic;
+
+ message commonAttributes {
+ uint32 my-id = 1 ;
+ string my-name = 2 ;
+ bool my-status = 3 ;
+ }
+ """
+
+ try:
+ cmd = pyang_cmd.format('basic.yang')
+ print 'running command: {}'.format(cmd)
+ response, err, rc = run_command_to_completion_with_raw_stdout(cmd)
+ self.assertEqual(rc, 0)
+
+ self._compare_file(response, expected_response)
+ finally:
+ print "Test_01_basic_def_End:------------------ took {} " \
+ "secs\n\n".format(time.time() - t0)
+
+
+ def test_02_container_def(self):
+ print "Test_02_container_def_Start:------------------"
+ t0 = time.time()
+
+ # input file: /voltha/tests/utests/netconf/yang/container.yang
+
+ expected_response = """
+ syntax = "proto3";
+ package container;
+
+ message int-container {
+ int32 eight = 1 ;
+ int32 nine = 2 ;
+ }
+ message int-container {
+ int32 eight = 1 ;
+ int32 nine = 2 ;
+ }
+ """
+
+ try:
+ cmd = pyang_cmd.format('container.yang')
+ print 'running command: {}'.format(cmd)
+ response, err, rc = run_command_to_completion_with_raw_stdout(cmd)
+ self.assertEqual(rc, 0)
+
+ self._compare_file(response, expected_response)
+ finally:
+ print "Test_02_container_def_End:------------------ took {} " \
+ "secs\n\n".format(time.time() - t0)
+
+
+ def test_03_mix_simple_types(self):
+ print "Test_03_mix_simple_types_Start:------------------"
+ t0 = time.time()
+
+ # input file: /voltha/tests/utests/netconf/yang/mix_simple_types.yang
+
+ expected_response = """
+ syntax = "proto3";
+ package mix_simple_types;
+
+ message user {
+ string name = 1 ;
+ string full-name = 2 ;
+ string class = 3 ;
+ }
+ message user {
+ string name = 1 ;
+ string full-name = 2 ;
+ string class = 3 ;
+ }
+
+ message int-container {
+ int32 eight = 1 ;
+ int32 nine = 2 ;
+ int32 ten = 3 ;
+ }
+ message container1 {
+ bool a = 1 ;
+ Any b = 2 ;
+ string mleaf = 3 ;
+ repeated string mleaf_list = 4 ;
+ message inner-container {
+ string mleaf1 = 1 ;
+ string mleaf2 = 2 ;
+ }
+ }
+ message int-container {
+ int32 eight = 1 ;
+ int32 nine = 2 ;
+ int32 ten = 3 ;
+ }
+ message container1 {
+ bool a = 1 ;
+ Any b = 2 ;
+ string mleaf = 3 ;
+ repeated string mleaf_list = 4 ;
+ message inner-container {
+ string mleaf1 = 1 ;
+ string mleaf2 = 2 ;
+ }
+ }
+ """
+
+ try:
+ cmd = pyang_cmd.format('mix_simple_types.yang')
+ print 'running command: {}'.format(cmd)
+ response, err, rc = run_command_to_completion_with_raw_stdout(cmd)
+ self.assertEqual(rc, 0)
+
+ self._compare_file(response, expected_response)
+ finally:
+ print "Test_03_mix_simple_types_End:------------------ took {} " \
+ "secs\n\n".format(time.time() - t0)
+
+
+ def test_04_cord_tenant(self):
+ print "Test_04_cord_tenant_Start:------------------"
+ t0 = time.time()
+
+ # input file: /voltha/tests/utests/netconf/yang/cord-tenant.yang
+
+ expected_response = """
+ syntax = "proto3";
+ package cord_tenant;
+
+ message subscriber {
+ string label = 1 ;
+ enum status
+ {
+ violation = 0 ;
+ enabled = 1 ;
+ delinquent = 2 ;
+ suspended = 3 ;
+ }
+ bool demo = 3 ;
+ }
+ """
+ try:
+ cmd = pyang_cmd.format('cord-tenant.yang')
+ print 'running command: {}'.format(cmd)
+ response, err, rc = run_command_to_completion_with_raw_stdout(cmd)
+ self.assertEqual(rc, 0)
+
+ self._compare_file(response, expected_response)
+ finally:
+ print "Test_04_cord_tenant_End:------------------ took {} " \
+ "secs\n\n".format(time.time() - t0)