This commit consists of:
1) Dockerizing the netconf server
2) Update proto2yang to support module imports
3) Provide a set of yang modules derived from the proto files in voltha.
These files as well as the slight mmodifications to the proto files are
provided in the experiments/netconf/proto2yang directory
4) Code to automatically pull proto files from voltha into the netconf server,
compiles them and produce the yang equivalent files.
5) Add a getvoltha netconf API to provide voltha state information (basic at
this time). There is potential to make this generic once we experiment
with additional APIs
Change-Id: I94f3a1f871b8025ad675d5f9b9b626d1be8b8d36
diff --git a/Dockerfile.netconf b/Dockerfile.netconf
new file mode 100644
index 0000000..b46a822
--- /dev/null
+++ b/Dockerfile.netconf
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+FROM cord/voltha-base
+
+MAINTAINER Zsolt Haraszti <zharaszt@ciena.com>
+MAINTAINER Ali Al-Shabibi <ali.al-shabibi@onlab.us>
+MAINTAINER Nathan Knuth <nathan.knuth@tibitcom.com>
+
+# Install protoc version 3.0.0; this is not yet the supported
+# version on xenial, so we need to "backport" it
+RUN apt-get update && \
+ apt-get install -y zlib1g-dev wget && \
+ wget http://ftp.us.debian.org/debian/pool/main/p/protobuf/libprotoc10_3.0.0-9_amd64.deb && \
+ wget http://ftp.us.debian.org/debian/pool/main/p/protobuf/libprotobuf-lite10_3.0.0-9_amd64.deb && \
+ wget http://ftp.us.debian.org/debian/pool/main/p/protobuf/libprotobuf-dev_3.0.0-9_amd64.deb && \
+ wget http://ftp.us.debian.org/debian/pool/main/p/protobuf/libprotobuf10_3.0.0-9_amd64.deb && \
+ wget http://ftp.us.debian.org/debian/pool/main/p/protobuf/protobuf-compiler_3.0.0-9_amd64.deb && \
+ dpkg -i *.deb && \
+ protoc --version && \
+ rm -f *.deb
+
+# Bundle app source
+RUN mkdir /netconf && touch /netconf/__init__.py
+ENV PYTHONPATH=/netconf
+COPY common /netconf/common
+COPY netconf /netconf/netconf
+
+# Exposing process and default entry point
+CMD ["python", "netconf/netconf/main.py"]
diff --git a/Makefile b/Makefile
index 00fecd9..76bee5e 100644
--- a/Makefile
+++ b/Makefile
@@ -75,12 +75,14 @@
@echo
build: protos docker-base
- docker build -t cord/voltha -f docker/Dockerfile.voltha .
- docker build -t cord/chameleon -f docker/Dockerfile.chameleon .
- docker build -t cord/ofagent -f docker/Dockerfile.ofagent .
- docker build -t cord/podder -f docker/Dockerfile.podder .
+ docker build -t cord/voltha -f Dockerfile.voltha .
+ docker build -t cord/chameleon -f Dockerfile.chameleon .
+ docker build -t cord/ofagent -f Dockerfile.ofagent .
+ docker build -t cord/podder -f Dockerfile.podder .
+ docker build -t cord/netconf -f Dockerfile.netconf .
docker build -t cord/shovel -f docker/Dockerfile.shovel .
+
docker-base:
docker build -t cord/voltha-base -f docker/Dockerfile.base .
@@ -88,6 +90,7 @@
make -C voltha/protos
make -C chameleon/protos
make -C ofagent/protos
+ make -C netconf/protos
install-protoc:
make -C voltha/protos install-protoc
diff --git a/compose/docker-compose-system-test.yml b/compose/docker-compose-system-test.yml
index 6cd3c48..443fc01 100644
--- a/compose/docker-compose-system-test.yml
+++ b/compose/docker-compose-system-test.yml
@@ -202,3 +202,31 @@
- fluentd
volumes:
- "/var/run/docker.sock:/tmp/docker.sock"
+
+ #
+ # Netconf server instance(s)
+ #
+ netconf:
+ image: cord/netconf
+ command: [
+ "/netconf/netconf/main.py",
+ "-v",
+ "--consul=${DOCKER_HOST_IP}:8500",
+ "--fluentd=fluentd:24224",
+ "--grpc-endpoint=@voltha-grpc",
+ "--instance-id-is-container-name",
+ "-v"
+ ]
+ ports:
+ - "1830:1830"
+ depends_on:
+ - consul
+ - voltha
+ links:
+ - consul
+ - fluentd
+ environment:
+ SERVICE_1830_NAME: "netconf-server"
+ volumes:
+ - "/var/run/docker.sock:/tmp/docker.sock"
+
diff --git a/experiments/netconf/proto2yang/adapter.proto b/experiments/netconf/proto2yang/adapter.proto
new file mode 100644
index 0000000..2e16f96
--- /dev/null
+++ b/experiments/netconf/proto2yang/adapter.proto
@@ -0,0 +1,41 @@
+syntax = "proto3";
+
+package voltha;
+
+import "google/protobuf/any.proto";
+import "common.proto";
+import "meta.proto";
+
+
+message AdapterConfig {
+
+ // Common adapter config attributes here
+ LogLevel log_level = 1;
+
+ // Custom (vendor-specific) configuration attributes
+ google.protobuf.Any additional_config = 64;
+
+}
+
+// Adapter (software plugin)
+message Adapter {
+
+ // Unique name of adapter, matching the python packate name under
+ // voltha/adapters.
+ string id = 1 [(access) = READ_ONLY];
+ string vendor = 2 [(access) = READ_ONLY];
+ string version = 3 [(access) = READ_ONLY];
+
+ // Adapter configuration
+ AdapterConfig config = 16;
+
+ // Custom descriptors and custom configuration
+ google.protobuf.Any additional_description = 64 [(access) = READ_ONLY];
+
+ repeated string logical_device_ids = 4; // Logical devices "owned"
+
+}
+
+message Adapters {
+ repeated Adapter items = 1;
+}
diff --git a/experiments/netconf/proto2yang/adapter_orig.proto b/experiments/netconf/proto2yang/adapter_orig.proto
new file mode 100644
index 0000000..4af54c3
--- /dev/null
+++ b/experiments/netconf/proto2yang/adapter_orig.proto
@@ -0,0 +1,41 @@
+syntax = "proto3";
+
+package voltha;
+
+import "google/protobuf/any.proto";
+import "common.proto";
+import "meta.proto";
+
+
+message AdapterConfig {
+
+ // Common adapter config attributes here
+ LogLevel.LogLevel log_level = 1;
+
+ // Custom (vendor-specific) configuration attributes
+ google.protobuf.Any additional_config = 64;
+
+}
+
+// Adapter (software plugin)
+message Adapter {
+
+ // Unique name of adapter, matching the python packate name under
+ // voltha/adapters.
+ string id = 1 [(access) = READ_ONLY];
+ string vendor = 2 [(access) = READ_ONLY];
+ string version = 3 [(access) = READ_ONLY];
+
+ // Adapter configuration
+ AdapterConfig config = 16;
+
+ // Custom descriptors and custom configuration
+ google.protobuf.Any additional_description = 64 [(access) = READ_ONLY];
+
+ repeated string logical_device_ids = 4; // Logical devices "owned"
+
+}
+
+message Adapters {
+ repeated Adapter items = 1;
+}
diff --git a/experiments/netconf/proto2yang/adapter_tibit.proto b/experiments/netconf/proto2yang/adapter_tibit.proto
new file mode 100644
index 0000000..ac9f1ec
--- /dev/null
+++ b/experiments/netconf/proto2yang/adapter_tibit.proto
@@ -0,0 +1,24 @@
+syntax = "proto3";
+
+package vendor.x2;
+
+// Vendor specific adapter descriptor data
+message AdapterDescription {
+ string foo = 1;
+ uint32 arg1 = 2;
+ uint32 arg2 = 3;
+ uint32 arg3 = 4;
+ uint32 arg4 = 5;
+ uint32 arg5 = 6;
+ uint32 arg6 = 7;
+}
+
+// Vendor specific adapter configuration data
+message AdapterConfig {
+ uint64 conf1 = 1;
+ uint64 conf2 = 2;
+ uint64 conf3 = 3;
+ uint64 conf4 = 4;
+ uint64 conf5 = 5;
+ repeated string things = 6;
+}
diff --git a/experiments/netconf/proto2yang/addressbook1.proto b/experiments/netconf/proto2yang/addressbook1.proto
new file mode 100644
index 0000000..b90dcdb
--- /dev/null
+++ b/experiments/netconf/proto2yang/addressbook1.proto
@@ -0,0 +1,21 @@
+// See README.txt for information and build instructions.
+
+syntax = "proto3";
+
+package tutorial;
+
+import "addressbook.proto";
+
+// Our address book file is just one of these.
+message AddressBook {
+ repeated Person people = 1;
+ repeated Adapter adapters = 2;
+}
+
+message TestOF {
+// repeated openflow_13.ofp_group_entry flow_groups = 1;
+ // repeated openflow_13.ofp_switch_features hell = 1;
+ // repeated openflow_13.ofp_flow_mod mod = 2;
+ // repeated openflow_13.ofp_flow_stats stats = 3;
+ repeated ofp_group_entry groupi = 4;
+}
diff --git a/experiments/netconf/proto2yang/common.proto b/experiments/netconf/proto2yang/common.proto
new file mode 100644
index 0000000..0ec8ce3
--- /dev/null
+++ b/experiments/netconf/proto2yang/common.proto
@@ -0,0 +1,71 @@
+syntax = "proto3";
+
+package voltha;
+
+// Convey a resource identifier
+message ID {
+ string id = 1;
+}
+
+
+// Logging verbosity level
+enum LogLevel {
+ DEBUG = 0;
+ INFO = 1;
+ WARNING = 2;
+ ERROR = 3;
+ CRITICAL = 4;
+}
+
+// Administrative State
+enum AdminState {
+
+ // The administrative state of the device is unknown
+ AS_UNKNOWN = 0;
+
+ // The device is pre-provisioned into Voltha, but not contacted by it
+ AS_PREPROVISIONED = 1;
+
+ // The device is enabled for activation and operation
+ AS_ENABLED = 3;
+
+ // The device is disabled and shall not perform its intended forwarding
+ // functions other than being available for re-activation.
+ AS_DISABLED = 2;
+}
+
+// Operational Status
+enum OperStatus {
+
+ // The status of the device is unknown at this point
+ OS_UNKNOWN = 0;
+
+ // The device has been discovered, but not yet activated
+ OS_DISCOVERED = 1;
+
+ // The device is being activated (booted, rebooted, upgraded, etc.)
+ OS_ACTIVATING = 2;
+
+ // Service impacting tests are being conducted
+ OS_TESTING = 3;
+
+ // The device is up and active
+ OS_ACTIVE = 4;
+
+ // The device has failed and cannot fulfill its intended role
+ OS_FAILED = 5;
+}
+
+// Connectivity Status
+enum ConnectStatus {
+
+ // The device connectivity status is unknown
+ CS_UNKNOWN = 0;
+
+ // The device cannot be reached by Voltha
+ CS_UNREACHABLE = 1;
+
+ // There is live communication between device and Voltha
+ CS_REACHABLE = 2;
+}
+
diff --git a/experiments/netconf/proto2yang/common_orig.proto b/experiments/netconf/proto2yang/common_orig.proto
new file mode 100644
index 0000000..1497d56
--- /dev/null
+++ b/experiments/netconf/proto2yang/common_orig.proto
@@ -0,0 +1,81 @@
+syntax = "proto3";
+
+package voltha;
+
+// Convey a resource identifier
+message ID {
+ string id = 1;
+}
+
+message LogLevel {
+
+ // Logging verbosity level
+ enum LogLevel {
+ DEBUG = 0;
+ INFO = 1;
+ WARNING = 2;
+ ERROR = 3;
+ CRITICAL = 4;
+ }
+}
+
+message AdminState {
+
+ // Administrative State
+ enum AdminState {
+
+ // The administrative state of the device is unknown
+ UNKNOWN = 0;
+
+ // The device is pre-provisioned into Voltha, but not contacted by it
+ PREPROVISIONED = 1;
+
+ // The device is enabled for activation and operation
+ ENABLED = 3;
+
+ // The device is disabled and shall not perform its intended forwarding
+ // functions other than being available for re-activation.
+ DISABLED = 2;
+ }
+}
+
+message OperStatus {
+
+ // Operational Status
+ enum OperStatus {
+
+ // The status of the device is unknown at this point
+ UNKNOWN = 0;
+
+ // The device has been discovered, but not yet activated
+ DISCOVERED = 1;
+
+ // The device is being activated (booted, rebooted, upgraded, etc.)
+ ACTIVATING = 2;
+
+ // Service impacting tests are being conducted
+ TESTING = 3;
+
+ // The device is up and active
+ ACTIVE = 4;
+
+ // The device has failed and cannot fulfill its intended role
+ FAILED = 5;
+ }
+}
+
+message ConnectStatus {
+
+ // Connectivity Status
+ enum ConnectStatus {
+
+ // The device connectivity status is unknown
+ UNKNOWN = 0;
+
+ // The device cannot be reached by Voltha
+ UNREACHABLE = 1;
+
+ // There is live communication between device and Voltha
+ REACHABLE = 2;
+ }
+}
diff --git a/experiments/netconf/proto2yang/device.proto b/experiments/netconf/proto2yang/device.proto
new file mode 100644
index 0000000..ac0f7e7
--- /dev/null
+++ b/experiments/netconf/proto2yang/device.proto
@@ -0,0 +1,135 @@
+syntax = "proto3";
+
+package voltha;
+
+import "meta.proto";
+import "google/protobuf/any.proto";
+import "common.proto";
+import "openflow_13.proto";
+
+// A Device Type
+message DeviceType {
+
+ // Unique name for the device type
+ string id = 1;
+
+ // Name of the adapter that handles device type
+ string adapter = 2;
+
+ // Capabilitities
+
+ bool accepts_bulk_flow_update = 3;
+ bool accepts_add_remove_flow_updates = 4;
+
+}
+
+// A plurality of device types
+message DeviceTypes {
+ repeated DeviceType items = 1;
+}
+
+message Port {
+
+ enum PortType {
+ UNKNOWN = 0;
+ ETHERNET_NNI = 1;
+ ETHERNET_UNI = 2;
+ PON_OLT = 3;
+ PON_ONU = 4;
+ }
+
+ uint32 port_no = 1; // Device-unique port number
+
+ string label = 2; // Arbitrary port label
+
+ PortType type = 3; // Type of port
+
+ AdminState admin_state = 5;
+
+ OperStatus oper_status = 6;
+
+ string device_id = 7; // Unique .id of device that owns this port
+
+ message PeerPort {
+ string device_id = 1;
+ uint32 port_no = 2;
+ }
+ repeated PeerPort peers = 8;
+
+}
+
+message Ports {
+ repeated Port items = 1;
+}
+
+// A Physical Device instance
+message Device {
+
+ // Voltha's device identifier
+ string id = 1 [(access) = READ_ONLY];
+
+ // Device type, refers to one of the registered device types
+ string type = 2 [(access) = READ_ONLY];
+
+ // Is this device a root device. Each logical switch has one root
+ // device that is associated with the logical flow switch.
+ bool root = 3 [(access) = READ_ONLY];
+
+ // Parent device id, in the device tree (for a root device, the parent_id
+ // is the logical_device.id)
+ string parent_id = 4 [(access) = READ_ONLY];
+ uint32 parent_port_no = 20 [(access) = READ_ONLY];
+
+ // Vendor, version, serial number, etc.
+ string vendor = 5 [(access) = READ_ONLY];
+ string model = 6 [(access) = READ_ONLY];
+ string hardware_version = 7 [(access) = READ_ONLY];
+ string firmware_version = 8 [(access) = READ_ONLY];
+ string software_version = 9 [(access) = READ_ONLY];
+ string serial_number = 10 [(access) = READ_ONLY];
+
+ // Addapter that takes care of device
+ string adapter = 11 [(access) = READ_ONLY];
+
+ // Device contact on vlan (if 0, no vlan)
+ uint32 vlan = 12;
+
+ message ProxyAddress {
+ string device_id = 1; // Which device to use as proxy to this device
+ uint32 channel_id = 2; // Sub-address within proxy device
+ };
+
+ oneof address {
+ // Device contact MAC address (format: "xx:xx:xx:xx:xx:xx")
+ string mac_address = 13;
+
+ // Device contact IPv4 address (format: "a.b.c.d" or can use hostname too)
+ string ipv4_address = 14;
+
+ // Device contact IPv6 address using the canonical string form
+ // ("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx")
+ string ipv6_address = 15;
+
+ ProxyAddress proxy_device = 19;
+ };
+
+ AdminState admin_state = 16;
+
+ OperStatus oper_status = 17 [(access) = READ_ONLY];
+
+ ConnectStatus connect_status = 18 [(access) = READ_ONLY];
+
+ // TODO additional common attribute here
+
+ // Device type specific attributes
+ google.protobuf.Any custom = 64;
+
+ repeated Port ports = 128 [(child_node) = {key: "port_no"}];
+ openflow_13.Flows flows = 129 [(child_node) = {}];
+ openflow_13.FlowGroups flow_groups = 130 [(child_node) = {}];
+
+}
+
+message Devices {
+ repeated Device items = 1;
+}
diff --git a/experiments/netconf/proto2yang/device_orig.proto b/experiments/netconf/proto2yang/device_orig.proto
new file mode 100644
index 0000000..0a1e9b2
--- /dev/null
+++ b/experiments/netconf/proto2yang/device_orig.proto
@@ -0,0 +1,135 @@
+syntax = "proto3";
+
+package voltha;
+
+import "meta.proto";
+import "google/protobuf/any.proto";
+import "common.proto";
+import "openflow_13.proto";
+
+// A Device Type
+message DeviceType {
+
+ // Unique name for the device type
+ string id = 1;
+
+ // Name of the adapter that handles device type
+ string adapter = 2;
+
+ // Capabilitities
+
+ bool accepts_bulk_flow_update = 3;
+ bool accepts_add_remove_flow_updates = 4;
+
+}
+
+// A plurality of device types
+message DeviceTypes {
+ repeated DeviceType items = 1;
+}
+
+message Port {
+
+ enum PortType {
+ UNKNOWN = 0;
+ ETHERNET_NNI = 1;
+ ETHERNET_UNI = 2;
+ PON_OLT = 3;
+ PON_ONU = 4;
+ }
+
+ uint32 port_no = 1; // Device-unique port number
+
+ string label = 2; // Arbitrary port label
+
+ PortType type = 3; // Type of port
+
+ AdminState.AdminState admin_state = 5;
+
+ OperStatus.OperStatus oper_status = 6;
+
+ string device_id = 7; // Unique .id of device that owns this port
+
+ message PeerPort {
+ string device_id = 1;
+ uint32 port_no = 2;
+ }
+ repeated PeerPort peers = 8;
+
+}
+
+message Ports {
+ repeated Port items = 1;
+}
+
+// A Physical Device instance
+message Device {
+
+ // Voltha's device identifier
+ string id = 1 [(access) = READ_ONLY];
+
+ // Device type, refers to one of the registered device types
+ string type = 2 [(access) = READ_ONLY];
+
+ // Is this device a root device. Each logical switch has one root
+ // device that is associated with the logical flow switch.
+ bool root = 3 [(access) = READ_ONLY];
+
+ // Parent device id, in the device tree (for a root device, the parent_id
+ // is the logical_device.id)
+ string parent_id = 4 [(access) = READ_ONLY];
+ uint32 parent_port_no = 20 [(access) = READ_ONLY];
+
+ // Vendor, version, serial number, etc.
+ string vendor = 5 [(access) = READ_ONLY];
+ string model = 6 [(access) = READ_ONLY];
+ string hardware_version = 7 [(access) = READ_ONLY];
+ string firmware_version = 8 [(access) = READ_ONLY];
+ string software_version = 9 [(access) = READ_ONLY];
+ string serial_number = 10 [(access) = READ_ONLY];
+
+ // Addapter that takes care of device
+ string adapter = 11 [(access) = READ_ONLY];
+
+ // Device contact on vlan (if 0, no vlan)
+ uint32 vlan = 12;
+
+ message ProxyAddress {
+ string device_id = 1; // Which device to use as proxy to this device
+ uint32 channel_id = 2; // Sub-address within proxy device
+ };
+
+ oneof address {
+ // Device contact MAC address (format: "xx:xx:xx:xx:xx:xx")
+ string mac_address = 13;
+
+ // Device contact IPv4 address (format: "a.b.c.d" or can use hostname too)
+ string ipv4_address = 14;
+
+ // Device contact IPv6 address using the canonical string form
+ // ("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx")
+ string ipv6_address = 15;
+
+ ProxyAddress proxy_device = 19;
+ };
+
+ AdminState.AdminState admin_state = 16;
+
+ OperStatus.OperStatus oper_status = 17 [(access) = READ_ONLY];
+
+ ConnectStatus.ConnectStatus connect_status = 18 [(access) = READ_ONLY];
+
+ // TODO additional common attribute here
+
+ // Device type specific attributes
+ google.protobuf.Any custom = 64;
+
+ repeated Port ports = 128 [(child_node) = {key: "port_no"}];
+ openflow_13.Flows flows = 129 [(child_node) = {}];
+ openflow_13.FlowGroups flow_groups = 130 [(child_node) = {}];
+
+}
+
+message Devices {
+ repeated Device items = 1;
+}
diff --git a/experiments/netconf/proto2yang/health.proto b/experiments/netconf/proto2yang/health.proto
new file mode 100644
index 0000000..19383a9
--- /dev/null
+++ b/experiments/netconf/proto2yang/health.proto
@@ -0,0 +1,34 @@
+syntax = "proto3";
+
+package voltha;
+
+import "google/api/annotations.proto";
+import "google/protobuf/empty.proto";
+import "meta.proto";
+
+// Encode health status of a Voltha instance
+message HealthStatus {
+
+ // Health states
+ enum HealthState {
+ HEALTHY = 0; // The instance is healthy
+ OVERLOADED = 1; // The instance is overloaded, decrease query rate
+ DYING = 2; // The instance is in a critical condition, do not use it
+ }
+
+ // Current state of health of this Voltha instance
+ HealthState state = 1 [(access) = READ_ONLY];
+}
+
+// Health related services
+service HealthService {
+
+ // Return current health status of a Voltha instance
+ rpc GetHealthStatus(google.protobuf.Empty) returns (HealthStatus) {
+ option (google.api.http) = {
+ get: "/health"
+ };
+ }
+
+}
+
diff --git a/experiments/netconf/proto2yang/ietf-adapter.yang b/experiments/netconf/proto2yang/ietf-adapter.yang
new file mode 100644
index 0000000..42ef6e3
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-adapter.yang
@@ -0,0 +1,105 @@
+
+module ietf-adapter {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-adapter";
+ prefix adapter;
+
+ import ietf-common { prefix common ; }
+ import ietf-any { prefix any ; }
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+
+ grouping AdapterConfig {
+ description
+ "";
+ leaf log_level {
+ type common:LogLevel;
+
+ description
+ "Common adapter config attributes here";
+ }
+
+ container additional_config {
+ uses any:Any;
+
+ description
+ "Custom (vendor-specific) configuration attributes";
+ }
+
+ }
+
+ grouping Adapter {
+ description
+ "Adapter (software plugin)";
+ leaf id {
+ type string;
+ description
+ "Unique name of adapter, matching the python packate name under
+ voltha adapters.";
+ }
+
+ leaf vendor {
+ type string;
+ description
+ "";
+ }
+
+ leaf version {
+ type string;
+ description
+ "";
+ }
+
+ container config {
+ uses AdapterConfig;
+
+ description
+ "Adapter configuration";
+ }
+
+ container additional_description {
+ uses any:Any;
+
+ description
+ "Custom descriptors and custom configuration";
+ }
+
+ list logical_device_ids {
+ key "logical_device_ids";
+ leaf logical_device_ids {
+ type string;
+ description
+ "Logical devices owned ";
+ }
+ description
+ "Logical devices owned ";
+ }
+
+ }
+
+ grouping Adapters {
+ description
+ "";
+ list items {
+ key "id";
+ uses Adapter;
+
+ description
+ "";
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-annotations.yang b/experiments/netconf/proto2yang/ietf-annotations.yang
new file mode 100644
index 0000000..8af4415
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-annotations.yang
@@ -0,0 +1,22 @@
+
+module ietf-annotations {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-annotations";
+ prefix annotations;
+
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-any.yang b/experiments/netconf/proto2yang/ietf-any.yang
new file mode 100644
index 0000000..bf318af
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-any.yang
@@ -0,0 +1,127 @@
+
+module ietf-any {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-any";
+ prefix any;
+
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+
+ grouping Any {
+ description
+ "`Any` contains an arbitrary serialized protocol buffer message along with a
+ URL that describes the type of the serialized message.
+
+ Protobuf library provides support to pack unpack Any values in the form
+ of utility functions or additional generated methods of the Any type.
+
+ Example 1: Pack and unpack a message in C++.
+
+ Foo foo = ...;
+ Any any;
+ any.PackFrom(foo);
+ ...
+ if (any.UnpackTo(&foo))
+ ...
+
+
+ Example 2: Pack and unpack a message in Java.
+
+ Foo foo = ...;
+ Any any = Any.pack(foo);
+ ...
+ if (any.is(Foo.class))
+ foo = any.unpack(Foo.class);
+
+
+ Example 3: Pack and unpack a message in Python.
+
+ foo = Foo(...)
+ any = Any()
+ any.Pack(foo)
+ ...
+ if any.Is(Foo.DESCRIPTOR):
+ any.Unpack(foo)
+ ...
+
+ The pack methods provided by protobuf library will by default use
+ 'type.googleapis.com full.type.name' as the type URL and the unpack
+ methods only use the fully qualified type name after the last ' '
+ in the type URL, for example foo.bar.com x y.z will yield type
+ name y.z .
+
+
+ JSON
+ ====
+ The JSON representation of an `Any` value uses the regular
+ representation of the deserialized, embedded message, with an
+ additional field `@type` which contains the type URL. Example:
+
+ package google.profile;
+ message Person
+ string first_name = 1;
+ string last_name = 2;
+
+
+
+ @type : type.googleapis.com google.profile.Person ,
+ firstName : <string>,
+ lastName : <string>
+
+
+ If the embedded message type is well-known and has a custom JSON
+ representation, that representation will be embedded adding a field
+ `value` which holds the custom JSON in addition to the `@type`
+ field. Example (for message google.protobuf.Duration ):
+
+
+ @type : type.googleapis.com google.protobuf.Duration ,
+ value : 1.212s
+ ";
+ leaf type_url {
+ type string;
+ description
+ "A URL resource name whose content describes the type of the
+ serialized protocol buffer message.
+
+ For URLs which use the scheme `http`, `https`, or no scheme, the
+ following restrictions and interpretations apply:
+
+ If no scheme is provided, `https` is assumed.
+ The last segment of the URL's path must represent the fully
+ qualified name of the type (as in `path google.protobuf.Duration`).
+ The name should be in a canonical form (e.g., leading . is
+ not accepted).
+ An HTTP GET on the URL must yield a google.protobuf.Type
+ value in binary format, or produce an error.
+ Applications are allowed to cache lookup results based on the
+ URL, or have them precompiled into a binary to avoid any
+ lookup. Therefore, binary compatibility needs to be preserved
+ on changes to types. (Use versioned type names to manage
+ breaking changes.)
+
+ Schemes other than `http`, `https` (or the empty scheme) might be
+ used with implementation specific semantics.";
+ }
+
+ leaf value {
+ type binary;
+ description
+ "Must be a valid serialized protocol buffer of the above specified type.";
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-common.yang b/experiments/netconf/proto2yang/ietf-common.yang
new file mode 100644
index 0000000..b2f6fab
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-common.yang
@@ -0,0 +1,111 @@
+
+module ietf-common {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-common";
+ prefix common;
+
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+ typedef LogLevel {
+ type enumeration {
+ enum DEBUG {
+ description "";
+ }
+ enum INFO {
+ description "";
+ }
+ enum WARNING {
+ description "";
+ }
+ enum ERROR {
+ description "";
+ }
+ enum CRITICAL {
+ description "";
+ }
+ }
+ description
+ "Logging verbosity level";
+ }
+ typedef AdminState {
+ type enumeration {
+ enum AS_UNKNOWN {
+ description "";
+ }
+ enum AS_PREPROVISIONED {
+ description "";
+ }
+ enum AS_ENABLED {
+ description "";
+ }
+ enum AS_DISABLED {
+ description "";
+ }
+ }
+ description
+ "Administrative State";
+ }
+ typedef OperStatus {
+ type enumeration {
+ enum OS_UNKNOWN {
+ description "";
+ }
+ enum OS_DISCOVERED {
+ description "";
+ }
+ enum OS_ACTIVATING {
+ description "";
+ }
+ enum OS_TESTING {
+ description "";
+ }
+ enum OS_ACTIVE {
+ description "";
+ }
+ enum OS_FAILED {
+ description "";
+ }
+ }
+ description
+ "Operational Status";
+ }
+ typedef ConnectStatus {
+ type enumeration {
+ enum CS_UNKNOWN {
+ description "";
+ }
+ enum CS_UNREACHABLE {
+ description "";
+ }
+ enum CS_REACHABLE {
+ description "";
+ }
+ }
+ description
+ "Connectivity Status";
+ }
+
+ grouping ID {
+ description
+ "Convey a resource identifier";
+ leaf id {
+ type string;
+ description
+ "";
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-descriptor.yang b/experiments/netconf/proto2yang/ietf-descriptor.yang
new file mode 100644
index 0000000..487f100
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-descriptor.yang
@@ -0,0 +1,1331 @@
+
+module ietf-descriptor {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-descriptor";
+ prefix descriptor;
+
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+
+ container FileDescriptorSet {
+ description
+ "The protocol compiler can output a FileDescriptorSet containing the .proto
+ files it parses.";
+ list file {
+ key "name";
+ uses FileDescriptorProto;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping FileDescriptorProto {
+ description
+ "Describes a complete .proto file.";
+ leaf name {
+ type string;
+ description
+ "file name, relative to root of source tree";
+ }
+
+ leaf package {
+ type string;
+ description
+ "e.g. foo , foo.bar , etc.";
+ }
+
+ list dependency {
+ key "dependency";
+ leaf dependency {
+ type string;
+ description
+ "Names of files imported by this file.";
+ }
+ description
+ "Names of files imported by this file.";
+ }
+
+ list public_dependency {
+ key "public_dependency";
+ leaf public_dependency {
+ type int32;
+ description
+ "Indexes of the public imported files in the dependency list above.";
+ }
+ description
+ "Indexes of the public imported files in the dependency list above.";
+ }
+
+ list weak_dependency {
+ key "weak_dependency";
+ leaf weak_dependency {
+ type int32;
+ description
+ "Indexes of the weak imported files in the dependency list.
+ For Google-internal migration only. Do not use.";
+ }
+ description
+ "Indexes of the weak imported files in the dependency list.
+ For Google-internal migration only. Do not use.";
+ }
+
+ list message_type {
+ key "name";
+ uses DescriptorProto;
+
+ description
+ "All top-level definitions in this file.";
+ }
+
+ list enum_type {
+ key "name";
+ uses EnumDescriptorProto;
+
+ description
+ "";
+ }
+
+ list service {
+ key "name";
+ uses ServiceDescriptorProto;
+
+ description
+ "";
+ }
+
+ list extension {
+ key "name";
+ uses FieldDescriptorProto;
+
+ description
+ "";
+ }
+
+ container options {
+ uses FileOptions;
+
+ description
+ "";
+ }
+
+ container source_code_info {
+ uses SourceCodeInfo;
+
+ description
+ "This field contains optional information about the original source code.
+ You may safely remove this entire field without harming runtime
+ functionality of the descriptors -- the information is needed only by
+ development tools.";
+ }
+
+ leaf syntax {
+ type string;
+ description
+ "The syntax of the proto file.
+ The supported values are proto2 and proto3 .";
+ }
+
+ }
+
+ grouping DescriptorProto {
+ description
+ "Describes a message type.";
+ leaf name {
+ type string;
+ description
+ "";
+ }
+
+ list field {
+ key "name";
+ uses FieldDescriptorProto;
+
+ description
+ "";
+ }
+
+ list extension {
+ key "name";
+ uses FieldDescriptorProto;
+
+ description
+ "";
+ }
+
+ list nested_type {
+ key "name";
+ uses DescriptorProto;
+
+ description
+ "";
+ }
+
+ list enum_type {
+ key "name";
+ uses EnumDescriptorProto;
+
+ description
+ "";
+ }
+
+
+ list oneof_decl {
+ key "name";
+ uses OneofDescriptorProto;
+
+ description
+ "";
+ }
+
+ container options {
+ uses MessageOptions;
+
+ description
+ "";
+ }
+
+
+ list reserved_name {
+ key "reserved_name";
+ leaf reserved_name {
+ type string;
+ description
+ "Reserved field names, which may not be used by fields in the same message.
+ A given name may only be reserved once.";
+ }
+ description
+ "Reserved field names, which may not be used by fields in the same message.
+ A given name may only be reserved once.";
+ }
+
+ grouping ExtensionRange {
+ description
+ "";
+ leaf start {
+ type int32;
+ description
+ "";
+ }
+
+ leaf end {
+ type int32;
+ description
+ "";
+ }
+
+ }
+
+ grouping ReservedRange {
+ description
+ "Range of reserved tag numbers. Reserved tag numbers may not be used by
+ fields or extension ranges in the same message. Reserved ranges may
+ not overlap.";
+ leaf start {
+ type int32;
+ description
+ "Inclusive.";
+ }
+
+ leaf end {
+ type int32;
+ description
+ "Exclusive.";
+ }
+
+ }
+
+ }
+
+ grouping FieldDescriptorProto {
+ description
+ "Describes a field within a message.";
+ leaf name {
+ type string;
+ description
+ "";
+ }
+
+ leaf number {
+ type int32;
+ description
+ "";
+ }
+
+ leaf label {
+ type Label;
+ description
+ "";
+ }
+
+ leaf type {
+ type Type;
+ description
+ "If type_name is set, this need not be set. If both this and type_name
+ are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.";
+ }
+
+ leaf type_name {
+ type string;
+ description
+ "For message and enum types, this is the name of the type. If the name
+ starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
+ rules are used to find the type (i.e. first the nested types within this
+ message are searched, then within the parent, on up to the root
+ namespace).";
+ }
+
+ leaf extendee {
+ type string;
+ description
+ "For extensions, this is the name of the type being extended. It is
+ resolved in the same manner as type_name.";
+ }
+
+ leaf default_value {
+ type string;
+ description
+ "For numeric types, contains the original text representation of the value.
+ For booleans, true or false .
+ For strings, contains the default text contents (not escaped in any way).
+ For bytes, contains the C escaped value. All bytes >= 128 are escaped.
+ TODO(kenton): Base-64 encode?";
+ }
+
+ leaf oneof_index {
+ type int32;
+ description
+ "If set, gives the index of a oneof in the containing type's oneof_decl
+ list. This field is a member of that oneof.";
+ }
+
+ leaf json_name {
+ type string;
+ description
+ "JSON name of this field. The value is set by protocol compiler. If the
+ user has set a json_name option on this field, that option's value
+ will be used. Otherwise, it's deduced from the field's name by converting
+ it to camelCase.";
+ }
+
+ container options {
+ uses FieldOptions;
+
+ description
+ "";
+ }
+
+ typedef Type {
+ type enumeration {
+ enum TYPE_DOUBLE {
+ description "";
+ }
+ enum TYPE_FLOAT {
+ description "";
+ }
+ enum TYPE_INT64 {
+ description "";
+ }
+ enum TYPE_UINT64 {
+ description "";
+ }
+ enum TYPE_INT32 {
+ description "";
+ }
+ enum TYPE_FIXED64 {
+ description "";
+ }
+ enum TYPE_FIXED32 {
+ description "";
+ }
+ enum TYPE_BOOL {
+ description "";
+ }
+ enum TYPE_STRING {
+ description "";
+ }
+ enum TYPE_GROUP {
+ description "";
+ }
+ enum TYPE_MESSAGE {
+ description "";
+ }
+ enum TYPE_BYTES {
+ description "";
+ }
+ enum TYPE_UINT32 {
+ description "";
+ }
+ enum TYPE_ENUM {
+ description "";
+ }
+ enum TYPE_SFIXED32 {
+ description "";
+ }
+ enum TYPE_SFIXED64 {
+ description "";
+ }
+ enum TYPE_SINT32 {
+ description "";
+ }
+ enum TYPE_SINT64 {
+ description "";
+ }
+ }
+ description
+ "";
+ }
+
+ typedef Label {
+ type enumeration {
+ enum LABEL_OPTIONAL {
+ description "";
+ }
+ enum LABEL_REQUIRED {
+ description "";
+ }
+ enum LABEL_REPEATED {
+ description "";
+ }
+ }
+ description
+ "";
+ }
+
+ }
+
+ grouping OneofDescriptorProto {
+ description
+ "Describes a oneof.";
+ leaf name {
+ type string;
+ description
+ "";
+ }
+
+ container options {
+ uses OneofOptions;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping EnumDescriptorProto {
+ description
+ "Describes an enum type.";
+ leaf name {
+ type string;
+ description
+ "";
+ }
+
+ list value {
+ key "name";
+ uses EnumValueDescriptorProto;
+
+ description
+ "";
+ }
+
+ container options {
+ uses EnumOptions;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping EnumValueDescriptorProto {
+ description
+ "Describes a value within an enum.";
+ leaf name {
+ type string;
+ description
+ "";
+ }
+
+ leaf number {
+ type int32;
+ description
+ "";
+ }
+
+ container options {
+ uses EnumValueOptions;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping ServiceDescriptorProto {
+ description
+ "Describes a service.";
+ leaf name {
+ type string;
+ description
+ "";
+ }
+
+ list method {
+ key "name";
+ uses MethodDescriptorProto;
+
+ description
+ "";
+ }
+
+ container options {
+ uses ServiceOptions;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping MethodDescriptorProto {
+ description
+ "Describes a method of a service.";
+ leaf name {
+ type string;
+ description
+ "";
+ }
+
+ leaf input_type {
+ type string;
+ description
+ "Input and output type names. These are resolved in the same way as
+ FieldDescriptorProto.type_name, but must refer to a message type.";
+ }
+
+ leaf output_type {
+ type string;
+ description
+ "";
+ }
+
+ container options {
+ uses MethodOptions;
+
+ description
+ "";
+ }
+
+ leaf client_streaming {
+ type boolean;
+ description
+ "Identifies if client streams multiple client messages";
+ }
+
+ leaf server_streaming {
+ type boolean;
+ description
+ "Identifies if server streams multiple server messages";
+ }
+
+ }
+
+ grouping FileOptions {
+ description
+ "===================================================================
+ Options
+Each of the definitions above may have options attached. These are
+ just annotations which may cause code to be generated slightly differently
+ or may contain hints for code that manipulates protocol messages.
+
+ Clients may define custom options as extensions of the Options messages.
+ These extensions may not yet be known at parsing time, so the parser cannot
+ store the values in them. Instead it stores them in a field in the Options
+ message called uninterpreted_option. This field must have the same name
+ across all Options messages. We then use this field to populate the
+ extensions when we build a descriptor, at which point all protos have been
+ parsed and so all extensions are known.
+
+ Extension numbers for custom options may be chosen as follows:
+ For options which will only be used within a single application or
+ organization, or for experimental options, use field numbers 50000
+ through 99999. It is up to you to ensure that you do not use the
+ same number for multiple options.
+ For options which will be published and used publicly by multiple
+ independent entities, e-mail protobuf-global-extension-registry@google.com
+ to reserve extension numbers. Simply provide your project name (e.g.
+ Objective-C plugin) and your project website (if available) -- there's no
+ need to explain how you intend to use them. Usually you only need one
+ extension number. You can declare multiple options with only one extension
+ number by putting them in a sub-message. See the Custom Options section of
+ the docs for examples:
+ https: developers.google.com protocol-buffers docs proto#options
+ If this turns out to be popular, a web service will be set up
+ to automatically assign option numbers.";
+ leaf java_package {
+ type string;
+ description
+ "Sets the Java package where classes generated from this .proto will be
+ placed. By default, the proto package is used, but this is often
+ inappropriate because proto packages do not normally start with backwards
+ domain names.";
+ }
+
+ leaf java_outer_classname {
+ type string;
+ description
+ "If set, all the classes from the .proto file are wrapped in a single
+ outer class with the given name. This applies to both Proto1
+ (equivalent to the old --one_java_file option) and Proto2 (where
+ a .proto always translates to a single class, but you may want to
+ explicitly choose the class name).";
+ }
+
+ leaf java_multiple_files {
+ type boolean;
+ description
+ "If set true, then the Java code generator will generate a separate .java
+ file for each top-level message, enum, and service defined in the .proto
+ file. Thus, these types will not be nested inside the outer class
+ named by java_outer_classname. However, the outer class will still be
+ generated to contain the file's getDescriptor() method as well as any
+ top-level extensions defined in the file.";
+ }
+
+ leaf java_generate_equals_and_hash {
+ type boolean;
+ description
+ "If set true, then the Java code generator will generate equals() and
+ hashCode() methods for all messages defined in the .proto file.
+ This increases generated code size, potentially substantially for large
+ protos, which may harm a memory-constrained application.
+ - In the full runtime this is a speed optimization, as the
+ AbstractMessage base class includes reflection-based implementations of
+ these methods.
+ - In the lite runtime, setting this option changes the semantics of
+ equals() and hashCode() to more closely match those of the full runtime;
+ the generated methods compute their results based on field values rather
+ than object identity. (Implementations should not assume that hashcodes
+ will be consistent across runtimes or versions of the protocol compiler.)";
+ }
+
+ leaf java_string_check_utf8 {
+ type boolean;
+ description
+ "If set true, then the Java2 code generator will generate code that
+ throws an exception whenever an attempt is made to assign a non-UTF-8
+ byte sequence to a string field.
+ Message reflection will do the same.
+ However, an extension field still accepts non-UTF-8 byte sequences.
+ This option has no effect on when used with the lite runtime.";
+ }
+
+ leaf optimize_for {
+ type OptimizeMode;
+ description
+ "";
+ }
+
+ leaf go_package {
+ type string;
+ description
+ "Sets the Go package where structs generated from this .proto will be
+ placed. If omitted, the Go package will be derived from the following:
+ - The basename of the package import path, if provided.
+ - Otherwise, the package statement in the .proto file, if present.
+ - Otherwise, the basename of the .proto file, without extension.";
+ }
+
+ leaf cc_generic_services {
+ type boolean;
+ description
+ "Should generic services be generated in each language? Generic services
+ are not specific to any particular RPC system. They are generated by the
+ main code generators in each language (without additional plugins).
+ Generic services were the only kind of service generation supported by
+ early versions of google.protobuf.
+
+ Generic services are now considered deprecated in favor of using plugins
+ that generate code specific to your particular RPC system. Therefore,
+ these default to false. Old code which depends on generic services should
+ explicitly set them to true.";
+ }
+
+ leaf java_generic_services {
+ type boolean;
+ description
+ "";
+ }
+
+ leaf py_generic_services {
+ type boolean;
+ description
+ "";
+ }
+
+ leaf deprecated {
+ type boolean;
+ description
+ "Is this file deprecated?
+ Depending on the target platform, this can emit Deprecated annotations
+ for everything in the file, or it will be completely ignored; in the very
+ least, this is a formalization for deprecating files.";
+ }
+
+ leaf cc_enable_arenas {
+ type boolean;
+ description
+ "Enables the use of arenas for the proto messages in this file. This applies
+ only to generated classes for C++.";
+ }
+
+ leaf objc_class_prefix {
+ type string;
+ description
+ "Sets the objective c class prefix which is prepended to all objective c
+ generated classes from this .proto. There is no default.";
+ }
+
+ leaf csharp_namespace {
+ type string;
+ description
+ "Namespace for generated classes; defaults to the package.";
+ }
+
+ list uninterpreted_option {
+ key "identifier_value";
+ uses UninterpretedOption;
+
+ description
+ "The parser stores options it doesn't recognize here. See above.";
+ }
+
+ typedef OptimizeMode {
+ type enumeration {
+ enum SPEED {
+ description "";
+ }
+ enum CODE_SIZE {
+ description "";
+ }
+ enum LITE_RUNTIME {
+ description "";
+ }
+ }
+ description
+ "Generated classes can be optimized for speed or code size.";
+ }
+
+ }
+
+ grouping MessageOptions {
+ description
+ "";
+ leaf message_set_wire_format {
+ type boolean;
+ description
+ "Set true to use the old proto1 MessageSet wire format for extensions.
+ This is provided for backwards-compatibility with the MessageSet wire
+ format. You should not use this for any other reason: It's less
+ efficient, has fewer features, and is more complicated.
+
+ The message must be defined exactly as follows:
+ message Foo
+ option message_set_wire_format = true;
+ extensions 4 to max;
+
+ Note that the message cannot have any defined fields; MessageSets only
+ have extensions.
+
+ All extensions of your type must be singular messages; e.g. they cannot
+ be int32s, enums, or repeated messages.
+
+ Because this is an option, the above two restrictions are not enforced by
+ the protocol compiler.";
+ }
+
+ leaf no_standard_descriptor_accessor {
+ type boolean;
+ description
+ "Disables the generation of the standard descriptor() accessor, which can
+ conflict with a field of the same name. This is meant to make migration
+ from proto1 easier; new code should avoid fields named descriptor .";
+ }
+
+ leaf deprecated {
+ type boolean;
+ description
+ "Is this message deprecated?
+ Depending on the target platform, this can emit Deprecated annotations
+ for the message, or it will be completely ignored; in the very least,
+ this is a formalization for deprecating messages.";
+ }
+
+ leaf map_entry {
+ type boolean;
+ description
+ "Whether the message is an automatically generated map entry type for the
+ maps field.
+
+ For maps fields:
+ map<KeyType, ValueType> map_field = 1;
+ The parsed descriptor looks like:
+ message MapFieldEntry
+ option map_entry = true;
+ optional KeyType key = 1;
+ optional ValueType value = 2;
+
+ repeated MapFieldEntry map_field = 1;
+
+ Implementations may choose not to generate the map_entry=true message, but
+ use a native map in the target language to hold the keys and values.
+ The reflection APIs in such implementions still need to work as
+ if the field is a repeated message field.
+
+ NOTE: Do not set the option in .proto files. Always use the maps syntax
+ instead. The option should only be implicitly set by the proto compiler
+ parser.";
+ }
+
+ list uninterpreted_option {
+ key "identifier_value";
+ uses UninterpretedOption;
+
+ description
+ "The parser stores options it doesn't recognize here. See above.";
+ }
+
+ }
+
+ grouping FieldOptions {
+ description
+ "";
+ leaf ctype {
+ type CType;
+ description
+ "The ctype option instructs the C++ code generator to use a different
+ representation of the field than it normally would. See the specific
+ options below. This option is not yet implemented in the open source
+ release -- sorry, we'll try to include it in a future version!";
+ }
+
+ leaf packed {
+ type boolean;
+ description
+ "The packed option can be enabled for repeated primitive fields to enable
+ a more efficient representation on the wire. Rather than repeatedly
+ writing the tag and type for each element, the entire array is encoded as
+ a single length-delimited blob. In proto3, only explicit setting it to
+ false will avoid using packed encoding.";
+ }
+
+ leaf jstype {
+ type JSType;
+ description
+ "The jstype option determines the JavaScript type used for values of the
+ field. The option is permitted only for 64 bit integral and fixed types
+ (int64, uint64, sint64, fixed64, sfixed64). By default these types are
+ represented as JavaScript strings. This avoids loss of precision that can
+ happen when a large value is converted to a floating point JavaScript
+ numbers. Specifying JS_NUMBER for the jstype causes the generated
+ JavaScript code to use the JavaScript number type instead of strings.
+ This option is an enum to permit additional types to be added,
+ e.g. goog.math.Integer.";
+ }
+
+ leaf lazy {
+ type boolean;
+ description
+ "Should this field be parsed lazily? Lazy applies only to message-type
+ fields. It means that when the outer message is initially parsed, the
+ inner message's contents will not be parsed but instead stored in encoded
+ form. The inner message will actually be parsed when it is first accessed.
+
+ This is only a hint. Implementations are free to choose whether to use
+ eager or lazy parsing regardless of the value of this option. However,
+ setting this option true suggests that the protocol author believes that
+ using lazy parsing on this field is worth the additional bookkeeping
+ overhead typically needed to implement it.
+
+ This option does not affect the public interface of any generated code;
+ all method signatures remain the same. Furthermore, thread-safety of the
+ interface is not affected by this option; const methods remain safe to
+ call from multiple threads concurrently, while non-const methods continue
+ to require exclusive access.
+
+
+ Note that implementations may choose not to check required fields within
+ a lazy sub-message. That is, calling IsInitialized() on the outher message
+ may return true even if the inner message has missing required fields.
+ This is necessary because otherwise the inner message would have to be
+ parsed in order to perform the check, defeating the purpose of lazy
+ parsing. An implementation which chooses not to check required fields
+ must be consistent about it. That is, for any particular sub-message, the
+ implementation must either always check its required fields, or never
+ check its required fields, regardless of whether or not the message has
+ been parsed.";
+ }
+
+ leaf deprecated {
+ type boolean;
+ description
+ "Is this field deprecated?
+ Depending on the target platform, this can emit Deprecated annotations
+ for accessors, or it will be completely ignored; in the very least, this
+ is a formalization for deprecating fields.";
+ }
+
+ leaf weak {
+ type boolean;
+ description
+ "For Google-internal migration only. Do not use.";
+ }
+
+ list uninterpreted_option {
+ key "identifier_value";
+ uses UninterpretedOption;
+
+ description
+ "The parser stores options it doesn't recognize here. See above.";
+ }
+
+ typedef CType {
+ type enumeration {
+ enum STRING {
+ description "";
+ }
+ enum CORD {
+ description "";
+ }
+ enum STRING_PIECE {
+ description "";
+ }
+ }
+ description
+ "";
+ }
+
+ typedef JSType {
+ type enumeration {
+ enum JS_NORMAL {
+ description "";
+ }
+ enum JS_STRING {
+ description "";
+ }
+ enum JS_NUMBER {
+ description "";
+ }
+ }
+ description
+ "";
+ }
+
+ }
+
+ grouping OneofOptions {
+ description
+ "";
+ list uninterpreted_option {
+ key "identifier_value";
+ uses UninterpretedOption;
+
+ description
+ "The parser stores options it doesn't recognize here. See above.";
+ }
+
+ }
+
+ grouping EnumOptions {
+ description
+ "";
+ leaf allow_alias {
+ type boolean;
+ description
+ "Set this option to true to allow mapping different tag names to the same
+ value.";
+ }
+
+ leaf deprecated {
+ type boolean;
+ description
+ "Is this enum deprecated?
+ Depending on the target platform, this can emit Deprecated annotations
+ for the enum, or it will be completely ignored; in the very least, this
+ is a formalization for deprecating enums.";
+ }
+
+ list uninterpreted_option {
+ key "identifier_value";
+ uses UninterpretedOption;
+
+ description
+ "The parser stores options it doesn't recognize here. See above.";
+ }
+
+ }
+
+ grouping EnumValueOptions {
+ description
+ "";
+ leaf deprecated {
+ type boolean;
+ description
+ "Is this enum value deprecated?
+ Depending on the target platform, this can emit Deprecated annotations
+ for the enum value, or it will be completely ignored; in the very least,
+ this is a formalization for deprecating enum values.";
+ }
+
+ list uninterpreted_option {
+ key "identifier_value";
+ uses UninterpretedOption;
+
+ description
+ "The parser stores options it doesn't recognize here. See above.";
+ }
+
+ }
+
+ grouping ServiceOptions {
+ description
+ "";
+ leaf deprecated {
+ type boolean;
+ description
+ "Is this service deprecated?
+ Depending on the target platform, this can emit Deprecated annotations
+ for the service, or it will be completely ignored; in the very least,
+ this is a formalization for deprecating services.
+Note: Field numbers 1 through 32 are reserved for Google's internal RPC
+ framework. We apologize for hoarding these numbers to ourselves, but
+ we were already using them long before we decided to release Protocol
+ Buffers.";
+ }
+
+ list uninterpreted_option {
+ key "identifier_value";
+ uses UninterpretedOption;
+
+ description
+ "The parser stores options it doesn't recognize here. See above.";
+ }
+
+ }
+
+ grouping MethodOptions {
+ description
+ "";
+ leaf deprecated {
+ type boolean;
+ description
+ "Is this method deprecated?
+ Depending on the target platform, this can emit Deprecated annotations
+ for the method, or it will be completely ignored; in the very least,
+ this is a formalization for deprecating methods.
+Note: Field numbers 1 through 32 are reserved for Google's internal RPC
+ framework. We apologize for hoarding these numbers to ourselves, but
+ we were already using them long before we decided to release Protocol
+ Buffers.";
+ }
+
+ list uninterpreted_option {
+ key "identifier_value";
+ uses UninterpretedOption;
+
+ description
+ "The parser stores options it doesn't recognize here. See above.";
+ }
+
+ }
+
+ grouping UninterpretedOption {
+ description
+ "A message representing a option the parser does not recognize. This only
+ appears in options protos created by the compiler::Parser class.
+ DescriptorPool resolves these when building Descriptor objects. Therefore,
+ options protos in descriptor objects (e.g. returned by Descriptor::options(),
+ or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
+ in them.";
+
+ leaf identifier_value {
+ type string;
+ description
+ "The value of the uninterpreted option, in whatever type the tokenizer
+ identified it as during parsing. Exactly one of these should be set.";
+ }
+
+ leaf positive_int_value {
+ type uint64;
+ description
+ "";
+ }
+
+ leaf negative_int_value {
+ type int64;
+ description
+ "";
+ }
+
+ leaf double_value {
+ type decimal64 {
+ fraction-digits 5;
+ }
+ description
+ "";
+ }
+
+ leaf string_value {
+ type binary;
+ description
+ "";
+ }
+
+ leaf aggregate_value {
+ type string;
+ description
+ "";
+ }
+
+ grouping NamePart {
+ description
+ "The name of the uninterpreted option. Each string represents a segment in
+ a dot-separated name. is_extension is true iff a segment represents an
+ extension (denoted with parentheses in options specs in .proto files).
+ E.g., foo , false , bar.baz , true , qux , false represents
+ foo.(bar.baz).qux .";
+ leaf name_part {
+ type string;
+ description
+ "";
+ }
+
+ leaf is_extension {
+ type boolean;
+ description
+ "";
+ }
+
+ }
+
+ }
+
+ grouping SourceCodeInfo {
+ description
+ "Encapsulates information about the original source file from which a
+ FileDescriptorProto was generated.
+===================================================================
+ Optional source code info";
+
+ grouping Location {
+ description
+ "";
+ list path {
+ key "path";
+ leaf path {
+ type int32;
+ description
+ "Identifies which part of the FileDescriptorProto was defined at this
+ location.
+
+ Each element is a field number or an index. They form a path from
+ the root FileDescriptorProto to the place where the definition. For
+ example, this path:
+ 4, 3, 2, 7, 1
+ refers to:
+ file.message_type(3) 4, 3
+ .field(7) 2, 7
+ .name() 1
+ This is because FileDescriptorProto.message_type has field number 4:
+ repeated DescriptorProto message_type = 4;
+ and DescriptorProto.field has field number 2:
+ repeated FieldDescriptorProto field = 2;
+ and FieldDescriptorProto.name has field number 1:
+ optional string name = 1;
+
+ Thus, the above path gives the location of a field name. If we removed
+ the last element:
+ 4, 3, 2, 7
+ this path refers to the whole field declaration (from the beginning
+ of the label to the terminating semicolon).";
+ }
+ description
+ "Identifies which part of the FileDescriptorProto was defined at this
+ location.
+
+ Each element is a field number or an index. They form a path from
+ the root FileDescriptorProto to the place where the definition. For
+ example, this path:
+ 4, 3, 2, 7, 1
+ refers to:
+ file.message_type(3) 4, 3
+ .field(7) 2, 7
+ .name() 1
+ This is because FileDescriptorProto.message_type has field number 4:
+ repeated DescriptorProto message_type = 4;
+ and DescriptorProto.field has field number 2:
+ repeated FieldDescriptorProto field = 2;
+ and FieldDescriptorProto.name has field number 1:
+ optional string name = 1;
+
+ Thus, the above path gives the location of a field name. If we removed
+ the last element:
+ 4, 3, 2, 7
+ this path refers to the whole field declaration (from the beginning
+ of the label to the terminating semicolon).";
+ }
+
+ list span {
+ key "span";
+ leaf span {
+ type int32;
+ description
+ "Always has exactly three or four elements: start line, start column,
+ end line (optional, otherwise assumed same as start line), end column.
+ These are packed into a single field for efficiency. Note that line
+ and column numbers are zero-based -- typically you will want to add
+ 1 to each before displaying to a user.";
+ }
+ description
+ "Always has exactly three or four elements: start line, start column,
+ end line (optional, otherwise assumed same as start line), end column.
+ These are packed into a single field for efficiency. Note that line
+ and column numbers are zero-based -- typically you will want to add
+ 1 to each before displaying to a user.";
+ }
+
+ leaf leading_comments {
+ type string;
+ description
+ "If this SourceCodeInfo represents a complete declaration, these are any
+ comments appearing before and after the declaration which appear to be
+ attached to the declaration.
+
+ A series of line comments appearing on consecutive lines, with no other
+ tokens appearing on those lines, will be treated as a single comment.
+
+ leading_detached_comments will keep paragraphs of comments that appear
+ before (but not connected to) the current element. Each paragraph,
+ separated by empty lines, will be one comment element in the repeated
+ field.
+
+ Only the comment content is provided; comment markers (e.g. ) are
+ stripped out. For block comments, leading whitespace and an asterisk
+ will be stripped from the beginning of each line other than the first.
+ Newlines are included in the output.
+
+ Examples:
+
+ optional int32 foo = 1; Comment attached to foo.
+ Comment attached to bar.
+ optional int32 bar = 2;
+
+ optional string baz = 3;
+ Comment attached to baz.
+ Another line attached to baz.
+
+ Comment attached to qux.
+
+ Another line attached to qux.
+ optional double qux = 4;
+
+ Detached comment for corge. This is not leading or trailing comments
+ to qux or corge because there are blank lines separating it from
+ both.
+
+ Detached comment for corge paragraph 2.
+
+ optional string corge = 5;
+ Block comment attached
+ to corge. Leading asterisks
+ will be removed.
+ Block comment attached to
+ grault.
+ optional int32 grault = 6;
+
+ ignored detached comments.";
+ }
+
+ leaf trailing_comments {
+ type string;
+ description
+ "";
+ }
+
+ list leading_detached_comments {
+ key "leading_detached_comments";
+ leaf leading_detached_comments {
+ type string;
+ description
+ "";
+ }
+ description
+ "";
+ }
+
+ }
+
+ }
+
+ container GeneratedCodeInfo {
+ description
+ "Describes the relationship between generated code and its original source
+ file. A GeneratedCodeInfo message is associated with only one generated
+ source file, but may contain references to different source .proto files.";
+
+ grouping Annotation {
+ description
+ "";
+ list path {
+ key "path";
+ leaf path {
+ type int32;
+ description
+ "Identifies the element in the original source .proto file. This field
+ is formatted the same as SourceCodeInfo.Location.path.";
+ }
+ description
+ "Identifies the element in the original source .proto file. This field
+ is formatted the same as SourceCodeInfo.Location.path.";
+ }
+
+ leaf source_file {
+ type string;
+ description
+ "Identifies the filesystem path to the original source .proto.";
+ }
+
+ leaf begin {
+ type int32;
+ description
+ "Identifies the starting offset in bytes in the generated code
+ that relates to the identified object.";
+ }
+
+ leaf end {
+ type int32;
+ description
+ "Identifies the ending offset in bytes in the generated code that
+ relates to the identified offset. The end offset should be one past
+ the last relevant byte (so the length of the text = end - begin).";
+ }
+
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-device.yang b/experiments/netconf/proto2yang/ietf-device.yang
new file mode 100644
index 0000000..0a37cf3
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-device.yang
@@ -0,0 +1,349 @@
+
+module ietf-device {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-device";
+ prefix device;
+
+ import ietf-openflow_13 { prefix openflow_13 ; }
+ import ietf-common { prefix common ; }
+ import ietf-any { prefix any ; }
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+
+ grouping DeviceType {
+ description
+ "A Device Type";
+ leaf id {
+ type string;
+ description
+ "Unique name for the device type";
+ }
+
+ leaf adapter {
+ type string;
+ description
+ "Name of the adapter that handles device type";
+ }
+
+ leaf accepts_bulk_flow_update {
+ type boolean;
+ description
+ "Capabilitities";
+ }
+
+ leaf accepts_add_remove_flow_updates {
+ type boolean;
+ description
+ "";
+ }
+
+ }
+
+ grouping DeviceTypes {
+ description
+ "A plurality of device types";
+ list items {
+ key "id";
+ uses DeviceType;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping Port {
+ description
+ "";
+ leaf port_no {
+ type uint32;
+ description
+ "Device-unique port number";
+ }
+
+ leaf label {
+ type string;
+ description
+ "Arbitrary port label";
+ }
+
+ leaf type {
+ type PortType;
+ description
+ "Type of port";
+ }
+
+ leaf admin_state {
+ type common:AdminState;
+
+ description
+ "";
+ }
+
+ leaf oper_status {
+ type common:OperStatus;
+
+ description
+ "";
+ }
+
+ leaf device_id {
+ type string;
+ description
+ "Unique .id of device that owns this port";
+ }
+
+
+ typedef PortType {
+ type enumeration {
+ enum UNKNOWN {
+ description "";
+ }
+ enum ETHERNET_NNI {
+ description "";
+ }
+ enum ETHERNET_UNI {
+ description "";
+ }
+ enum PON_OLT {
+ description "";
+ }
+ enum PON_ONU {
+ description "";
+ }
+ }
+ description
+ "";
+ }
+
+ grouping PeerPort {
+ description
+ "";
+ leaf device_id {
+ type string;
+ description
+ "";
+ }
+
+ leaf port_no {
+ type uint32;
+ description
+ "";
+ }
+
+ }
+
+ }
+
+ grouping Ports {
+ description
+ "";
+ list items {
+ key "port_no";
+ uses Port;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping Device {
+ description
+ "A Physical Device instance";
+ leaf id {
+ type string;
+ description
+ "Voltha's device identifier";
+ }
+
+ leaf type {
+ type string;
+ description
+ "Device type, refers to one of the registered device types";
+ }
+
+ leaf root {
+ type boolean;
+ description
+ "Is this device a root device. Each logical switch has one root
+ device that is associated with the logical flow switch.";
+ }
+
+ leaf parent_id {
+ type string;
+ description
+ "Parent device id, in the device tree (for a root device, the parent_id
+ is the logical_device.id)";
+ }
+
+ leaf parent_port_no {
+ type uint32;
+ description
+ "";
+ }
+
+ leaf vendor {
+ type string;
+ description
+ "Vendor, version, serial number, etc.";
+ }
+
+ leaf model {
+ type string;
+ description
+ "";
+ }
+
+ leaf hardware_version {
+ type string;
+ description
+ "";
+ }
+
+ leaf firmware_version {
+ type string;
+ description
+ "";
+ }
+
+ leaf software_version {
+ type string;
+ description
+ "";
+ }
+
+ leaf serial_number {
+ type string;
+ description
+ "";
+ }
+
+ leaf adapter {
+ type string;
+ description
+ "Addapter that takes care of device";
+ }
+
+ leaf vlan {
+ type uint32;
+ description
+ "Device contact on vlan (if 0, no vlan)";
+ }
+
+ leaf mac_address {
+ type string;
+ description
+ "Device contact MAC address (format: xx:xx:xx:xx:xx:xx )";
+ }
+
+ leaf ipv4_address {
+ type string;
+ description
+ "Device contact IPv4 address (format: a.b.c.d or can use hostname too)";
+ }
+
+ leaf ipv6_address {
+ type string;
+ description
+ "Device contact IPv6 address using the canonical string form
+ ( xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx )";
+ }
+
+
+ leaf admin_state {
+ type common:AdminState;
+
+ description
+ "";
+ }
+
+ leaf oper_status {
+ type common:OperStatus;
+
+ description
+ "";
+ }
+
+ leaf connect_status {
+ type common:ConnectStatus;
+
+ description
+ "";
+ }
+
+ container custom {
+ uses any:Any;
+
+ description
+ "Device type specific attributes
+TODO additional common attribute here";
+ }
+
+ list ports {
+ key "port_no";
+ uses Port;
+
+ description
+ "";
+ }
+
+ container flows {
+ uses openflow_13:Flows;
+
+ description
+ "";
+ }
+
+ container flow_groups {
+ uses openflow_13:FlowGroups;
+
+ description
+ "";
+ }
+
+ grouping ProxyAddress {
+ description
+ "";
+ leaf device_id {
+ type string;
+ description
+ "Which device to use as proxy to this device";
+ }
+
+ leaf channel_id {
+ type uint32;
+ description
+ "Sub-address within proxy device";
+ }
+
+ }
+
+ }
+
+ grouping Devices {
+ description
+ "";
+ list items {
+ key "id";
+ uses Device;
+
+ description
+ "";
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-empty.yang b/experiments/netconf/proto2yang/ietf-empty.yang
new file mode 100644
index 0000000..c2ee52b
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-empty.yang
@@ -0,0 +1,35 @@
+
+module ietf-empty {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-empty";
+ prefix empty;
+
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+
+ grouping Empty {
+ description
+ "A generic empty message that you can re-use to avoid defining duplicated
+ empty messages in your APIs. A typical example is to use it as the request
+ or the response type of an API method. For instance:
+
+ service Foo
+ rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+
+
+ The JSON representation for `Empty` is empty JSON object ` `.";
+ }
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-health.yang b/experiments/netconf/proto2yang/ietf-health.yang
new file mode 100644
index 0000000..e79c30a
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-health.yang
@@ -0,0 +1,65 @@
+
+module ietf-health {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-health";
+ prefix health;
+
+ import ietf-empty { prefix empty ; }
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+
+ grouping HealthStatus {
+ description
+ "Encode health status of a Voltha instance";
+ leaf state {
+ type HealthState;
+ description
+ "Current state of health of this Voltha instance";
+ }
+
+ typedef HealthState {
+ type enumeration {
+ enum HEALTHY {
+ description "";
+ }
+ enum OVERLOADED {
+ description "";
+ }
+ enum DYING {
+ description "";
+ }
+ }
+ description
+ "Health states";
+ }
+
+ }
+
+ /* Health related services" */
+ rpc HealthService-GetHealthStatus {
+ description
+ "Return current health status of a Voltha instance";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses HealthStatus;
+
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-http.yang b/experiments/netconf/proto2yang/ietf-http.yang
new file mode 100644
index 0000000..3d9cf2c
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-http.yang
@@ -0,0 +1,158 @@
+
+module ietf-http {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-http";
+ prefix http;
+
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+
+ grouping HttpRule {
+ description
+ "`HttpRule` defines the mapping of an RPC method to one or more HTTP REST API
+ methods. The mapping determines what portions of the request message are
+ populated from the path, query parameters, or body of the HTTP request. The
+ mapping is typically specified as an `google.api.http` annotation, see
+ google api annotations.proto for details.
+
+ The mapping consists of a mandatory field specifying a path template and an
+ optional `body` field specifying what data is represented in the HTTP request
+ body. The field name for the path indicates the HTTP method. Example:
+
+ ```
+ package google.storage.v2;
+
+ import google api annotations.proto ;
+
+ service Storage
+ rpc CreateObject(CreateObjectRequest) returns (Object)
+ option (google.api.http)
+ post: v2 bucket_name=buckets objects
+ body: object
+ ;
+ ;
+
+ ```
+
+ Here `bucket_name` and `object` bind to fields of the request message
+ `CreateObjectRequest`.
+
+ The rules for mapping HTTP path, query parameters, and body fields
+ to the request message are as follows:
+
+ 1. The `body` field specifies either ` ` or a field path, or is
+ omitted. If omitted, it assumes there is no HTTP body.
+ 2. Leaf fields (recursive expansion of nested messages in the
+ request) can be classified into three types:
+ (a) Matched in the URL template.
+ (b) Covered by body (if body is ` `, everything except (a) fields;
+ else everything under the body field)
+ (c) All other fields.
+ 3. URL query parameters found in the HTTP request are mapped to (c) fields.
+ 4. Any body sent with an HTTP request can contain only (b) fields.
+
+ The syntax of the path template is as follows:
+
+ Template = Segments Verb ;
+ Segments = Segment Segment ;
+ Segment = | | LITERAL | Variable ;
+ Variable = FieldPath = Segments ;
+ FieldPath = IDENT . IDENT ;
+ Verb = : LITERAL ;
+
+ ` ` matches a single path component, ` ` zero or more path components, and
+ `LITERAL` a constant. A `Variable` can match an entire path as specified
+ again by a template; this nested template must not contain further variables.
+ If no template is given with a variable, it matches a single path component.
+ The notation ` var ` is henceforth equivalent to ` var= `.
+
+ Use CustomHttpPattern to specify any HTTP method that is not included in the
+ pattern field, such as HEAD, or to leave the HTTP method unspecified for
+ a given URL path rule. The wild-card rule is useful for services that provide
+ content to Web (HTML) clients.";
+ leaf get {
+ type string;
+ description
+ "Used for listing and getting information about resources.";
+ }
+
+ leaf put {
+ type string;
+ description
+ "Used for updating a resource.";
+ }
+
+ leaf post {
+ type string;
+ description
+ "Used for creating a resource.";
+ }
+
+ leaf delete {
+ type string;
+ description
+ "Used for deleting a resource.";
+ }
+
+ leaf patch {
+ type string;
+ description
+ "Used for updating a resource.";
+ }
+
+ container custom {
+ uses CustomHttpPattern;
+
+ description
+ "Custom pattern is used for defining custom verbs.";
+ }
+
+ leaf body {
+ type string;
+ description
+ "The name of the request field whose value is mapped to the HTTP body, or
+ ` ` for mapping all fields not captured by the path pattern to the HTTP
+ body.";
+ }
+
+ list additional_bindings {
+ key "get";
+ uses HttpRule;
+
+ description
+ "Additional HTTP bindings for the selector. Nested bindings must not
+ specify a selector and must not contain additional bindings.";
+ }
+
+ }
+
+ grouping CustomHttpPattern {
+ description
+ "A custom pattern is used for defining custom HTTP verb.";
+ leaf kind {
+ type string;
+ description
+ "The name of this custom HTTP verb.";
+ }
+
+ leaf path {
+ type string;
+ description
+ "The path matched by this custom verb.";
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-logical_device.yang b/experiments/netconf/proto2yang/ietf-logical_device.yang
new file mode 100644
index 0000000..6c65d4d
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-logical_device.yang
@@ -0,0 +1,144 @@
+
+module ietf-logical_device {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-logical_device";
+ prefix logical_device;
+
+ import ietf-openflow_13 { prefix openflow_13 ; }
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+
+ grouping LogicalPort {
+ description
+ "";
+ leaf id {
+ type string;
+ description
+ "";
+ }
+
+ container ofp_port {
+ uses openflow_13:ofp_port;
+
+ description
+ "";
+ }
+
+ leaf device_id {
+ type string;
+ description
+ "";
+ }
+
+ leaf device_port_no {
+ type uint32;
+ description
+ "";
+ }
+
+ leaf root_port {
+ type boolean;
+ description
+ "";
+ }
+
+ }
+
+ grouping LogicalPorts {
+ description
+ "";
+ list items {
+ key "id";
+ uses LogicalPort;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping LogicalDevice {
+ description
+ "";
+ leaf id {
+ type string;
+ description
+ "unique id of logical device";
+ }
+
+ leaf datapath_id {
+ type uint64;
+ description
+ "unique datapath id for the logical device (used by the SDN controller)";
+ }
+
+ container desc {
+ uses openflow_13:ofp_desc;
+
+ description
+ "device description";
+ }
+
+ container switch_features {
+ uses openflow_13:ofp_switch_features;
+
+ description
+ "device features";
+ }
+
+ leaf root_device_id {
+ type string;
+ description
+ "name of the root device anchoring logical device";
+ }
+
+ list ports {
+ key "id";
+ uses LogicalPort;
+
+ description
+ "logical device ports";
+ }
+
+ container flows {
+ uses openflow_13:Flows;
+
+ description
+ "flows configured on the logical device";
+ }
+
+ container flow_groups {
+ uses openflow_13:FlowGroups;
+
+ description
+ "flow groups configured on the logical device";
+ }
+
+ }
+
+ grouping LogicalDevices {
+ description
+ "";
+ list items {
+ key "id";
+ uses LogicalDevice;
+
+ description
+ "";
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-meta.yang b/experiments/netconf/proto2yang/ietf-meta.yang
new file mode 100644
index 0000000..92a480a
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-meta.yang
@@ -0,0 +1,45 @@
+
+module ietf-meta {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-meta";
+ prefix meta;
+
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+ typedef Access {
+ type enumeration {
+ enum CONFIG {
+ description "";
+ }
+ enum READ_ONLY {
+ description "";
+ }
+ }
+ description
+ "";
+ }
+
+ container ChildNode {
+ description
+ "";
+ leaf key {
+ type string;
+ description
+ "";
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-openflow_13.yang b/experiments/netconf/proto2yang/ietf-openflow_13.yang
new file mode 100644
index 0000000..43b0bcb
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-openflow_13.yang
@@ -0,0 +1,4873 @@
+
+module ietf-openflow_13 {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-openflow_13";
+ prefix openflow_13;
+
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+ typedef ofp_port_no {
+ type enumeration {
+ enum OFPP_INVALID {
+ description "";
+ }
+ enum OFPP_MAX {
+ description "";
+ }
+ enum OFPP_IN_PORT {
+ description "";
+ }
+ enum OFPP_TABLE {
+ description "";
+ }
+ enum OFPP_NORMAL {
+ description "";
+ }
+ enum OFPP_FLOOD {
+ description "";
+ }
+ enum OFPP_ALL {
+ description "";
+ }
+ enum OFPP_CONTROLLER {
+ description "";
+ }
+ enum OFPP_LOCAL {
+ description "";
+ }
+ enum OFPP_ANY {
+ description "";
+ }
+ }
+ description
+ "Port numbering. Ports are numbered starting from 1.Version number:
+ OpenFlow versions released: 0x01 = 1.0 ; 0x02 = 1.1 ; 0x03 = 1.2
+ 0x04 = 1.3
+The most significant bit in the version field is reserved and must
+ be set to zero.
+#define OFP_VERSION 0x04
+#define PIPELINE_TABLES 64
+#define OFP_MAX_TABLE_NAME_LEN 32
+#define OFP_MAX_PORT_NAME_LEN 16
+Official IANA registered port for OpenFlow.#define OFP_TCP_PORT 6653
+#define OFP_SSL_PORT 6653
+#define OFP_ETH_ALEN 6 Bytes in an Ethernet address. ";
+ }
+ typedef ofp_type {
+ type enumeration {
+ enum OFPT_HELLO {
+ description "";
+ }
+ enum OFPT_ERROR {
+ description "";
+ }
+ enum OFPT_ECHO_REQUEST {
+ description "";
+ }
+ enum OFPT_ECHO_REPLY {
+ description "";
+ }
+ enum OFPT_EXPERIMENTER {
+ description "";
+ }
+ enum OFPT_FEATURES_REQUEST {
+ description "";
+ }
+ enum OFPT_FEATURES_REPLY {
+ description "";
+ }
+ enum OFPT_GET_CONFIG_REQUEST {
+ description "";
+ }
+ enum OFPT_GET_CONFIG_REPLY {
+ description "";
+ }
+ enum OFPT_SET_CONFIG {
+ description "";
+ }
+ enum OFPT_PACKET_IN {
+ description "";
+ }
+ enum OFPT_FLOW_REMOVED {
+ description "";
+ }
+ enum OFPT_PORT_STATUS {
+ description "";
+ }
+ enum OFPT_PACKET_OUT {
+ description "";
+ }
+ enum OFPT_FLOW_MOD {
+ description "";
+ }
+ enum OFPT_GROUP_MOD {
+ description "";
+ }
+ enum OFPT_PORT_MOD {
+ description "";
+ }
+ enum OFPT_TABLE_MOD {
+ description "";
+ }
+ enum OFPT_MULTIPART_REQUEST {
+ description "";
+ }
+ enum OFPT_MULTIPART_REPLY {
+ description "";
+ }
+ enum OFPT_BARRIER_REQUEST {
+ description "";
+ }
+ enum OFPT_BARRIER_REPLY {
+ description "";
+ }
+ enum OFPT_QUEUE_GET_CONFIG_REQUEST {
+ description "";
+ }
+ enum OFPT_QUEUE_GET_CONFIG_REPLY {
+ description "";
+ }
+ enum OFPT_ROLE_REQUEST {
+ description "";
+ }
+ enum OFPT_ROLE_REPLY {
+ description "";
+ }
+ enum OFPT_GET_ASYNC_REQUEST {
+ description "";
+ }
+ enum OFPT_GET_ASYNC_REPLY {
+ description "";
+ }
+ enum OFPT_SET_ASYNC {
+ description "";
+ }
+ enum OFPT_METER_MOD {
+ description "";
+ }
+ }
+ description
+ "";
+ }
+ typedef ofp_hello_elem_type {
+ type enumeration {
+ enum OFPHET_INVALID {
+ description "";
+ }
+ enum OFPHET_VERSIONBITMAP {
+ description "";
+ }
+ }
+ description
+ "Hello elements types.";
+ }
+ typedef ofp_config_flags {
+ type enumeration {
+ enum OFPC_FRAG_NORMAL {
+ description "";
+ }
+ enum OFPC_FRAG_DROP {
+ description "";
+ }
+ enum OFPC_FRAG_REASM {
+ description "";
+ }
+ enum OFPC_FRAG_MASK {
+ description "";
+ }
+ }
+ description
+ "#define OFP_DEFAULT_MISS_SEND_LEN 128";
+ }
+ typedef ofp_table_config {
+ type enumeration {
+ enum OFPTC_INVALID {
+ description "";
+ }
+ enum OFPTC_DEPRECATED_MASK {
+ description "";
+ }
+ }
+ description
+ "Flags to configure the table. Reserved for future use.";
+ }
+ typedef ofp_table {
+ type enumeration {
+ enum OFPTT_INVALID {
+ description "";
+ }
+ enum OFPTT_MAX {
+ description "";
+ }
+ enum OFPTT_ALL {
+ description "";
+ }
+ }
+ description
+ "Table numbering. Tables can use any number up to OFPT_MAX.";
+ }
+ typedef ofp_capabilities {
+ type enumeration {
+ enum OFPC_INVALID {
+ description "";
+ }
+ enum OFPC_FLOW_STATS {
+ description "";
+ }
+ enum OFPC_TABLE_STATS {
+ description "";
+ }
+ enum OFPC_PORT_STATS {
+ description "";
+ }
+ enum OFPC_GROUP_STATS {
+ description "";
+ }
+ enum OFPC_IP_REASM {
+ description "";
+ }
+ enum OFPC_QUEUE_STATS {
+ description "";
+ }
+ enum OFPC_PORT_BLOCKED {
+ description "";
+ }
+ }
+ description
+ "Capabilities supported by the datapath.";
+ }
+ typedef ofp_port_config {
+ type enumeration {
+ enum OFPPC_INVALID {
+ description "";
+ }
+ enum OFPPC_PORT_DOWN {
+ description "";
+ }
+ enum OFPPC_NO_RECV {
+ description "";
+ }
+ enum OFPPC_NO_FWD {
+ description "";
+ }
+ enum OFPPC_NO_PACKET_IN {
+ description "";
+ }
+ }
+ description
+ "Flags to indicate behavior of the physical port. These flags are
+ used in ofp_port to describe the current configuration. They are
+ used in the ofp_port_mod message to configure the port's behavior.";
+ }
+ typedef ofp_port_state {
+ type enumeration {
+ enum OFPPS_INVALID {
+ description "";
+ }
+ enum OFPPS_LINK_DOWN {
+ description "";
+ }
+ enum OFPPS_BLOCKED {
+ description "";
+ }
+ enum OFPPS_LIVE {
+ description "";
+ }
+ }
+ description
+ "Current state of the physical port. These are not configurable from
+ the controller.";
+ }
+ typedef ofp_port_features {
+ type enumeration {
+ enum OFPPF_INVALID {
+ description "";
+ }
+ enum OFPPF_10MB_HD {
+ description "";
+ }
+ enum OFPPF_10MB_FD {
+ description "";
+ }
+ enum OFPPF_100MB_HD {
+ description "";
+ }
+ enum OFPPF_100MB_FD {
+ description "";
+ }
+ enum OFPPF_1GB_HD {
+ description "";
+ }
+ enum OFPPF_1GB_FD {
+ description "";
+ }
+ enum OFPPF_10GB_FD {
+ description "";
+ }
+ enum OFPPF_40GB_FD {
+ description "";
+ }
+ enum OFPPF_100GB_FD {
+ description "";
+ }
+ enum OFPPF_1TB_FD {
+ description "";
+ }
+ enum OFPPF_OTHER {
+ description "";
+ }
+ enum OFPPF_COPPER {
+ description "";
+ }
+ enum OFPPF_FIBER {
+ description "";
+ }
+ enum OFPPF_AUTONEG {
+ description "";
+ }
+ enum OFPPF_PAUSE {
+ description "";
+ }
+ enum OFPPF_PAUSE_ASYM {
+ description "";
+ }
+ }
+ description
+ "Features of ports available in a datapath.";
+ }
+ typedef ofp_port_reason {
+ type enumeration {
+ enum OFPPR_ADD {
+ description "";
+ }
+ enum OFPPR_DELETE {
+ description "";
+ }
+ enum OFPPR_MODIFY {
+ description "";
+ }
+ }
+ description
+ "What changed about the physical port";
+ }
+ typedef ofp_match_type {
+ type enumeration {
+ enum OFPMT_STANDARD {
+ description "";
+ }
+ enum OFPMT_OXM {
+ description "";
+ }
+ }
+ description
+ "The match type indicates the match structure (set of fields that compose the
+ match) in use. The match type is placed in the type field at the beginning
+ of all match structures. The OpenFlow Extensible Match type corresponds
+ to OXM TLV format described below and must be supported by all OpenFlow
+ switches. Extensions that define other match types may be published on the
+ ONF wiki. Support for extensions is optional.
+## -------------------------- #### OpenFlow Extensible Match. #### -------------------------- ##";
+ }
+ typedef ofp_oxm_class {
+ type enumeration {
+ enum OFPXMC_NXM_0 {
+ description "";
+ }
+ enum OFPXMC_NXM_1 {
+ description "";
+ }
+ enum OFPXMC_OPENFLOW_BASIC {
+ description "";
+ }
+ enum OFPXMC_EXPERIMENTER {
+ description "";
+ }
+ }
+ description
+ "OXM Class IDs.
+ The high order bit differentiate reserved classes from member classes.
+ Classes 0x0000 to 0x7FFF are member classes, allocated by ONF.
+ Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation.
+Components of a OXM TLV header.
+ Those macros are not valid for the experimenter class, macros for the
+ experimenter class will depend on the experimenter header used.#define OXM_HEADER__(CLASS, FIELD, HASMASK, LENGTH)
+ (((CLASS) << 16) | ((FIELD) << 9) | ((HASMASK) << 8) | (LENGTH))
+#define OXM_HEADER(CLASS, FIELD, LENGTH)
+ OXM_HEADER__(CLASS, FIELD, 0, LENGTH)
+#define OXM_HEADER_W(CLASS, FIELD, LENGTH)
+ OXM_HEADER__(CLASS, FIELD, 1, (LENGTH) 2)
+#define OXM_CLASS(HEADER) ((HEADER) >> 16)
+#define OXM_FIELD(HEADER) (((HEADER) >> 9) & 0x7f)
+#define OXM_TYPE(HEADER) (((HEADER) >> 9) & 0x7fffff)
+#define OXM_HASMASK(HEADER) (((HEADER) >> 8) & 1)
+#define OXM_LENGTH(HEADER) ((HEADER) & 0xff)
+
+#define OXM_MAKE_WILD_HEADER(HEADER)
+ OXM_HEADER_W(OXM_CLASS(HEADER), OXM_FIELD(HEADER), OXM_LENGTH(HEADER))";
+ }
+ typedef oxm_ofb_field_types {
+ type enumeration {
+ enum OFPXMT_OFB_IN_PORT {
+ description "";
+ }
+ enum OFPXMT_OFB_IN_PHY_PORT {
+ description "";
+ }
+ enum OFPXMT_OFB_METADATA {
+ description "";
+ }
+ enum OFPXMT_OFB_ETH_DST {
+ description "";
+ }
+ enum OFPXMT_OFB_ETH_SRC {
+ description "";
+ }
+ enum OFPXMT_OFB_ETH_TYPE {
+ description "";
+ }
+ enum OFPXMT_OFB_VLAN_VID {
+ description "";
+ }
+ enum OFPXMT_OFB_VLAN_PCP {
+ description "";
+ }
+ enum OFPXMT_OFB_IP_DSCP {
+ description "";
+ }
+ enum OFPXMT_OFB_IP_ECN {
+ description "";
+ }
+ enum OFPXMT_OFB_IP_PROTO {
+ description "";
+ }
+ enum OFPXMT_OFB_IPV4_SRC {
+ description "";
+ }
+ enum OFPXMT_OFB_IPV4_DST {
+ description "";
+ }
+ enum OFPXMT_OFB_TCP_SRC {
+ description "";
+ }
+ enum OFPXMT_OFB_TCP_DST {
+ description "";
+ }
+ enum OFPXMT_OFB_UDP_SRC {
+ description "";
+ }
+ enum OFPXMT_OFB_UDP_DST {
+ description "";
+ }
+ enum OFPXMT_OFB_SCTP_SRC {
+ description "";
+ }
+ enum OFPXMT_OFB_SCTP_DST {
+ description "";
+ }
+ enum OFPXMT_OFB_ICMPV4_TYPE {
+ description "";
+ }
+ enum OFPXMT_OFB_ICMPV4_CODE {
+ description "";
+ }
+ enum OFPXMT_OFB_ARP_OP {
+ description "";
+ }
+ enum OFPXMT_OFB_ARP_SPA {
+ description "";
+ }
+ enum OFPXMT_OFB_ARP_TPA {
+ description "";
+ }
+ enum OFPXMT_OFB_ARP_SHA {
+ description "";
+ }
+ enum OFPXMT_OFB_ARP_THA {
+ description "";
+ }
+ enum OFPXMT_OFB_IPV6_SRC {
+ description "";
+ }
+ enum OFPXMT_OFB_IPV6_DST {
+ description "";
+ }
+ enum OFPXMT_OFB_IPV6_FLABEL {
+ description "";
+ }
+ enum OFPXMT_OFB_ICMPV6_TYPE {
+ description "";
+ }
+ enum OFPXMT_OFB_ICMPV6_CODE {
+ description "";
+ }
+ enum OFPXMT_OFB_IPV6_ND_TARGET {
+ description "";
+ }
+ enum OFPXMT_OFB_IPV6_ND_SLL {
+ description "";
+ }
+ enum OFPXMT_OFB_IPV6_ND_TLL {
+ description "";
+ }
+ enum OFPXMT_OFB_MPLS_LABEL {
+ description "";
+ }
+ enum OFPXMT_OFB_MPLS_TC {
+ description "";
+ }
+ enum OFPXMT_OFB_MPLS_BOS {
+ description "";
+ }
+ enum OFPXMT_OFB_PBB_ISID {
+ description "";
+ }
+ enum OFPXMT_OFB_TUNNEL_ID {
+ description "";
+ }
+ enum OFPXMT_OFB_IPV6_EXTHDR {
+ description "";
+ }
+ }
+ description
+ "OXM Flow field types for OpenFlow basic class.";
+ }
+ typedef ofp_vlan_id {
+ type enumeration {
+ enum OFPVID_NONE {
+ description "";
+ }
+ enum OFPVID_PRESENT {
+ description "";
+ }
+ }
+ description
+ "The VLAN id is 12-bits, so we can use the entire 16 bits to indicate
+ special conditions.";
+ }
+ typedef ofp_ipv6exthdr_flags {
+ type enumeration {
+ enum OFPIEH_INVALID {
+ description "";
+ }
+ enum OFPIEH_NONEXT {
+ description "";
+ }
+ enum OFPIEH_ESP {
+ description "";
+ }
+ enum OFPIEH_AUTH {
+ description "";
+ }
+ enum OFPIEH_DEST {
+ description "";
+ }
+ enum OFPIEH_FRAG {
+ description "";
+ }
+ enum OFPIEH_ROUTER {
+ description "";
+ }
+ enum OFPIEH_HOP {
+ description "";
+ }
+ enum OFPIEH_UNREP {
+ description "";
+ }
+ enum OFPIEH_UNSEQ {
+ description "";
+ }
+ }
+ description
+ "Bit definitions for IPv6 Extension Header pseudo-field.#define OFP_VLAN_NONE OFPVID_NONE";
+ }
+ typedef ofp_action_type {
+ type enumeration {
+ enum OFPAT_OUTPUT {
+ description "";
+ }
+ enum OFPAT_COPY_TTL_OUT {
+ description "";
+ }
+ enum OFPAT_COPY_TTL_IN {
+ description "";
+ }
+ enum OFPAT_SET_MPLS_TTL {
+ description "";
+ }
+ enum OFPAT_DEC_MPLS_TTL {
+ description "";
+ }
+ enum OFPAT_PUSH_VLAN {
+ description "";
+ }
+ enum OFPAT_POP_VLAN {
+ description "";
+ }
+ enum OFPAT_PUSH_MPLS {
+ description "";
+ }
+ enum OFPAT_POP_MPLS {
+ description "";
+ }
+ enum OFPAT_SET_QUEUE {
+ description "";
+ }
+ enum OFPAT_GROUP {
+ description "";
+ }
+ enum OFPAT_SET_NW_TTL {
+ description "";
+ }
+ enum OFPAT_DEC_NW_TTL {
+ description "";
+ }
+ enum OFPAT_SET_FIELD {
+ description "";
+ }
+ enum OFPAT_PUSH_PBB {
+ description "";
+ }
+ enum OFPAT_POP_PBB {
+ description "";
+ }
+ enum OFPAT_EXPERIMENTER {
+ description "";
+ }
+ }
+ description
+ "## ----------------- #### OpenFlow Actions. #### ----------------- ##";
+ }
+ typedef ofp_controller_max_len {
+ type enumeration {
+ enum OFPCML_INVALID {
+ description "";
+ }
+ enum OFPCML_MAX {
+ description "";
+ }
+ enum OFPCML_NO_BUFFER {
+ description "";
+ }
+ }
+ description
+ "";
+ }
+ typedef ofp_instruction_type {
+ type enumeration {
+ enum OFPIT_INVALID {
+ description "";
+ }
+ enum OFPIT_GOTO_TABLE {
+ description "";
+ }
+ enum OFPIT_WRITE_METADATA {
+ description "";
+ }
+ enum OFPIT_WRITE_ACTIONS {
+ description "";
+ }
+ enum OFPIT_APPLY_ACTIONS {
+ description "";
+ }
+ enum OFPIT_CLEAR_ACTIONS {
+ description "";
+ }
+ enum OFPIT_METER {
+ description "";
+ }
+ enum OFPIT_EXPERIMENTER {
+ description "";
+ }
+ }
+ description
+ "## ---------------------- #### OpenFlow Instructions. #### ---------------------- ##";
+ }
+ typedef ofp_flow_mod_command {
+ type enumeration {
+ enum OFPFC_ADD {
+ description "";
+ }
+ enum OFPFC_MODIFY {
+ description "";
+ }
+ enum OFPFC_MODIFY_STRICT {
+ description "";
+ }
+ enum OFPFC_DELETE {
+ description "";
+ }
+ enum OFPFC_DELETE_STRICT {
+ description "";
+ }
+ }
+ description
+ "## --------------------------- #### OpenFlow Flow Modification. #### --------------------------- ##";
+ }
+ typedef ofp_flow_mod_flags {
+ type enumeration {
+ enum OFPFF_INVALID {
+ description "";
+ }
+ enum OFPFF_SEND_FLOW_REM {
+ description "";
+ }
+ enum OFPFF_CHECK_OVERLAP {
+ description "";
+ }
+ enum OFPFF_RESET_COUNTS {
+ description "";
+ }
+ enum OFPFF_NO_PKT_COUNTS {
+ description "";
+ }
+ enum OFPFF_NO_BYT_COUNTS {
+ description "";
+ }
+ }
+ description
+ "Value used in idle_timeout and hard_timeout to indicate that the entry
+ is permanent.#define OFP_FLOW_PERMANENT 0
+By default, choose a priority in the middle.#define OFP_DEFAULT_PRIORITY 0x8000";
+ }
+ typedef ofp_group {
+ type enumeration {
+ enum OFPG_INVALID {
+ description "";
+ }
+ enum OFPG_MAX {
+ description "";
+ }
+ enum OFPG_ALL {
+ description "";
+ }
+ enum OFPG_ANY {
+ description "";
+ }
+ }
+ description
+ "Group numbering. Groups can use any number up to OFPG_MAX.";
+ }
+ typedef ofp_group_mod_command {
+ type enumeration {
+ enum OFPGC_ADD {
+ description "";
+ }
+ enum OFPGC_MODIFY {
+ description "";
+ }
+ enum OFPGC_DELETE {
+ description "";
+ }
+ }
+ description
+ "Group commands";
+ }
+ typedef ofp_group_type {
+ type enumeration {
+ enum OFPGT_ALL {
+ description "";
+ }
+ enum OFPGT_SELECT {
+ description "";
+ }
+ enum OFPGT_INDIRECT {
+ description "";
+ }
+ enum OFPGT_FF {
+ description "";
+ }
+ }
+ description
+ "Group types. Values in the range 128; 255 are reserved for experimental
+ use.";
+ }
+ typedef ofp_packet_in_reason {
+ type enumeration {
+ enum OFPR_NO_MATCH {
+ description "";
+ }
+ enum OFPR_ACTION {
+ description "";
+ }
+ enum OFPR_INVALID_TTL {
+ description "";
+ }
+ }
+ description
+ "Why is this packet being sent to the controller?";
+ }
+ typedef ofp_flow_removed_reason {
+ type enumeration {
+ enum OFPRR_IDLE_TIMEOUT {
+ description "";
+ }
+ enum OFPRR_HARD_TIMEOUT {
+ description "";
+ }
+ enum OFPRR_DELETE {
+ description "";
+ }
+ enum OFPRR_GROUP_DELETE {
+ description "";
+ }
+ enum OFPRR_METER_DELETE {
+ description "";
+ }
+ }
+ description
+ "Why was this flow removed?";
+ }
+ typedef ofp_meter {
+ type enumeration {
+ enum OFPM_ZERO {
+ description "";
+ }
+ enum OFPM_MAX {
+ description "";
+ }
+ enum OFPM_SLOWPATH {
+ description "";
+ }
+ enum OFPM_CONTROLLER {
+ description "";
+ }
+ enum OFPM_ALL {
+ description "";
+ }
+ }
+ description
+ "Meter numbering. Flow meters can use any number up to OFPM_MAX.";
+ }
+ typedef ofp_meter_band_type {
+ type enumeration {
+ enum OFPMBT_INVALID {
+ description "";
+ }
+ enum OFPMBT_DROP {
+ description "";
+ }
+ enum OFPMBT_DSCP_REMARK {
+ description "";
+ }
+ enum OFPMBT_EXPERIMENTER {
+ description "";
+ }
+ }
+ description
+ "Meter band types";
+ }
+ typedef ofp_meter_mod_command {
+ type enumeration {
+ enum OFPMC_ADD {
+ description "";
+ }
+ enum OFPMC_MODIFY {
+ description "";
+ }
+ enum OFPMC_DELETE {
+ description "";
+ }
+ }
+ description
+ "Meter commands";
+ }
+ typedef ofp_meter_flags {
+ type enumeration {
+ enum OFPMF_INVALID {
+ description "";
+ }
+ enum OFPMF_KBPS {
+ description "";
+ }
+ enum OFPMF_PKTPS {
+ description "";
+ }
+ enum OFPMF_BURST {
+ description "";
+ }
+ enum OFPMF_STATS {
+ description "";
+ }
+ }
+ description
+ "Meter configuration flags";
+ }
+ typedef ofp_error_type {
+ type enumeration {
+ enum OFPET_HELLO_FAILED {
+ description "";
+ }
+ enum OFPET_BAD_REQUEST {
+ description "";
+ }
+ enum OFPET_BAD_ACTION {
+ description "";
+ }
+ enum OFPET_BAD_INSTRUCTION {
+ description "";
+ }
+ enum OFPET_BAD_MATCH {
+ description "";
+ }
+ enum OFPET_FLOW_MOD_FAILED {
+ description "";
+ }
+ enum OFPET_GROUP_MOD_FAILED {
+ description "";
+ }
+ enum OFPET_PORT_MOD_FAILED {
+ description "";
+ }
+ enum OFPET_TABLE_MOD_FAILED {
+ description "";
+ }
+ enum OFPET_QUEUE_OP_FAILED {
+ description "";
+ }
+ enum OFPET_SWITCH_CONFIG_FAILED {
+ description "";
+ }
+ enum OFPET_ROLE_REQUEST_FAILED {
+ description "";
+ }
+ enum OFPET_METER_MOD_FAILED {
+ description "";
+ }
+ enum OFPET_TABLE_FEATURES_FAILED {
+ description "";
+ }
+ enum OFPET_EXPERIMENTER {
+ description "";
+ }
+ }
+ description
+ "Values for 'type' in ofp_error_message. These values are immutable: they
+ will not change in future versions of the protocol (although new values may
+ be added).";
+ }
+ typedef ofp_hello_failed_code {
+ type enumeration {
+ enum OFPHFC_INCOMPATIBLE {
+ description "";
+ }
+ enum OFPHFC_EPERM {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_HELLO_FAILED. 'data' contains an
+ ASCII text string that may give failure details.";
+ }
+ typedef ofp_bad_request_code {
+ type enumeration {
+ enum OFPBRC_BAD_VERSION {
+ description "";
+ }
+ enum OFPBRC_BAD_TYPE {
+ description "";
+ }
+ enum OFPBRC_BAD_MULTIPART {
+ description "";
+ }
+ enum OFPBRC_BAD_EXPERIMENTER {
+ description "";
+ }
+ enum OFPBRC_BAD_EXP_TYPE {
+ description "";
+ }
+ enum OFPBRC_EPERM {
+ description "";
+ }
+ enum OFPBRC_BAD_LEN {
+ description "";
+ }
+ enum OFPBRC_BUFFER_EMPTY {
+ description "";
+ }
+ enum OFPBRC_BUFFER_UNKNOWN {
+ description "";
+ }
+ enum OFPBRC_BAD_TABLE_ID {
+ description "";
+ }
+ enum OFPBRC_IS_SLAVE {
+ description "";
+ }
+ enum OFPBRC_BAD_PORT {
+ description "";
+ }
+ enum OFPBRC_BAD_PACKET {
+ description "";
+ }
+ enum OFPBRC_MULTIPART_BUFFER_OVERFLOW {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_BAD_REQUEST. 'data' contains at least
+ the first 64 bytes of the failed request.";
+ }
+ typedef ofp_bad_action_code {
+ type enumeration {
+ enum OFPBAC_BAD_TYPE {
+ description "";
+ }
+ enum OFPBAC_BAD_LEN {
+ description "";
+ }
+ enum OFPBAC_BAD_EXPERIMENTER {
+ description "";
+ }
+ enum OFPBAC_BAD_EXP_TYPE {
+ description "";
+ }
+ enum OFPBAC_BAD_OUT_PORT {
+ description "";
+ }
+ enum OFPBAC_BAD_ARGUMENT {
+ description "";
+ }
+ enum OFPBAC_EPERM {
+ description "";
+ }
+ enum OFPBAC_TOO_MANY {
+ description "";
+ }
+ enum OFPBAC_BAD_QUEUE {
+ description "";
+ }
+ enum OFPBAC_BAD_OUT_GROUP {
+ description "";
+ }
+ enum OFPBAC_MATCH_INCONSISTENT {
+ description "";
+ }
+ enum OFPBAC_UNSUPPORTED_ORDER {
+ description "";
+ }
+ enum OFPBAC_BAD_TAG {
+ description "";
+ }
+ enum OFPBAC_BAD_SET_TYPE {
+ description "";
+ }
+ enum OFPBAC_BAD_SET_LEN {
+ description "";
+ }
+ enum OFPBAC_BAD_SET_ARGUMENT {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least
+ the first 64 bytes of the failed request.";
+ }
+ typedef ofp_bad_instruction_code {
+ type enumeration {
+ enum OFPBIC_UNKNOWN_INST {
+ description "";
+ }
+ enum OFPBIC_UNSUP_INST {
+ description "";
+ }
+ enum OFPBIC_BAD_TABLE_ID {
+ description "";
+ }
+ enum OFPBIC_UNSUP_METADATA {
+ description "";
+ }
+ enum OFPBIC_UNSUP_METADATA_MASK {
+ description "";
+ }
+ enum OFPBIC_BAD_EXPERIMENTER {
+ description "";
+ }
+ enum OFPBIC_BAD_EXP_TYPE {
+ description "";
+ }
+ enum OFPBIC_BAD_LEN {
+ description "";
+ }
+ enum OFPBIC_EPERM {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_BAD_INSTRUCTION. 'data' contains at
+ least the first 64 bytes of the failed request.";
+ }
+ typedef ofp_bad_match_code {
+ type enumeration {
+ enum OFPBMC_BAD_TYPE {
+ description "";
+ }
+ enum OFPBMC_BAD_LEN {
+ description "";
+ }
+ enum OFPBMC_BAD_TAG {
+ description "";
+ }
+ enum OFPBMC_BAD_DL_ADDR_MASK {
+ description "";
+ }
+ enum OFPBMC_BAD_NW_ADDR_MASK {
+ description "";
+ }
+ enum OFPBMC_BAD_WILDCARDS {
+ description "";
+ }
+ enum OFPBMC_BAD_FIELD {
+ description "";
+ }
+ enum OFPBMC_BAD_VALUE {
+ description "";
+ }
+ enum OFPBMC_BAD_MASK {
+ description "";
+ }
+ enum OFPBMC_BAD_PREREQ {
+ description "";
+ }
+ enum OFPBMC_DUP_FIELD {
+ description "";
+ }
+ enum OFPBMC_EPERM {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_BAD_MATCH. 'data' contains at least
+ the first 64 bytes of the failed request.";
+ }
+ typedef ofp_flow_mod_failed_code {
+ type enumeration {
+ enum OFPFMFC_UNKNOWN {
+ description "";
+ }
+ enum OFPFMFC_TABLE_FULL {
+ description "";
+ }
+ enum OFPFMFC_BAD_TABLE_ID {
+ description "";
+ }
+ enum OFPFMFC_OVERLAP {
+ description "";
+ }
+ enum OFPFMFC_EPERM {
+ description "";
+ }
+ enum OFPFMFC_BAD_TIMEOUT {
+ description "";
+ }
+ enum OFPFMFC_BAD_COMMAND {
+ description "";
+ }
+ enum OFPFMFC_BAD_FLAGS {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains
+ at least the first 64 bytes of the failed request.";
+ }
+ typedef ofp_group_mod_failed_code {
+ type enumeration {
+ enum OFPGMFC_GROUP_EXISTS {
+ description "";
+ }
+ enum OFPGMFC_INVALID_GROUP {
+ description "";
+ }
+ enum OFPGMFC_WEIGHT_UNSUPPORTED {
+ description "";
+ }
+ enum OFPGMFC_OUT_OF_GROUPS {
+ description "";
+ }
+ enum OFPGMFC_OUT_OF_BUCKETS {
+ description "";
+ }
+ enum OFPGMFC_CHAINING_UNSUPPORTED {
+ description "";
+ }
+ enum OFPGMFC_WATCH_UNSUPPORTED {
+ description "";
+ }
+ enum OFPGMFC_LOOP {
+ description "";
+ }
+ enum OFPGMFC_UNKNOWN_GROUP {
+ description "";
+ }
+ enum OFPGMFC_CHAINED_GROUP {
+ description "";
+ }
+ enum OFPGMFC_BAD_TYPE {
+ description "";
+ }
+ enum OFPGMFC_BAD_COMMAND {
+ description "";
+ }
+ enum OFPGMFC_BAD_BUCKET {
+ description "";
+ }
+ enum OFPGMFC_BAD_WATCH {
+ description "";
+ }
+ enum OFPGMFC_EPERM {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_GROUP_MOD_FAILED. 'data' contains
+ at least the first 64 bytes of the failed request.";
+ }
+ typedef ofp_port_mod_failed_code {
+ type enumeration {
+ enum OFPPMFC_BAD_PORT {
+ description "";
+ }
+ enum OFPPMFC_BAD_HW_ADDR {
+ description "";
+ }
+ enum OFPPMFC_BAD_CONFIG {
+ description "";
+ }
+ enum OFPPMFC_BAD_ADVERTISE {
+ description "";
+ }
+ enum OFPPMFC_EPERM {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED. 'data' contains
+ at least the first 64 bytes of the failed request.";
+ }
+ typedef ofp_table_mod_failed_code {
+ type enumeration {
+ enum OFPTMFC_BAD_TABLE {
+ description "";
+ }
+ enum OFPTMFC_BAD_CONFIG {
+ description "";
+ }
+ enum OFPTMFC_EPERM {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_TABLE_MOD_FAILED. 'data' contains
+ at least the first 64 bytes of the failed request.";
+ }
+ typedef ofp_queue_op_failed_code {
+ type enumeration {
+ enum OFPQOFC_BAD_PORT {
+ description "";
+ }
+ enum OFPQOFC_BAD_QUEUE {
+ description "";
+ }
+ enum OFPQOFC_EPERM {
+ description "";
+ }
+ }
+ description
+ "ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains
+ at least the first 64 bytes of the failed request";
+ }
+ typedef ofp_switch_config_failed_code {
+ type enumeration {
+ enum OFPSCFC_BAD_FLAGS {
+ description "";
+ }
+ enum OFPSCFC_BAD_LEN {
+ description "";
+ }
+ enum OFPSCFC_EPERM {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_SWITCH_CONFIG_FAILED. 'data' contains
+ at least the first 64 bytes of the failed request.";
+ }
+ typedef ofp_role_request_failed_code {
+ type enumeration {
+ enum OFPRRFC_STALE {
+ description "";
+ }
+ enum OFPRRFC_UNSUP {
+ description "";
+ }
+ enum OFPRRFC_BAD_ROLE {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_ROLE_REQUEST_FAILED. 'data' contains
+ at least the first 64 bytes of the failed request.";
+ }
+ typedef ofp_meter_mod_failed_code {
+ type enumeration {
+ enum OFPMMFC_UNKNOWN {
+ description "";
+ }
+ enum OFPMMFC_METER_EXISTS {
+ description "";
+ }
+ enum OFPMMFC_INVALID_METER {
+ description "";
+ }
+ enum OFPMMFC_UNKNOWN_METER {
+ description "";
+ }
+ enum OFPMMFC_BAD_COMMAND {
+ description "";
+ }
+ enum OFPMMFC_BAD_FLAGS {
+ description "";
+ }
+ enum OFPMMFC_BAD_RATE {
+ description "";
+ }
+ enum OFPMMFC_BAD_BURST {
+ description "";
+ }
+ enum OFPMMFC_BAD_BAND {
+ description "";
+ }
+ enum OFPMMFC_BAD_BAND_VALUE {
+ description "";
+ }
+ enum OFPMMFC_OUT_OF_METERS {
+ description "";
+ }
+ enum OFPMMFC_OUT_OF_BANDS {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_METER_MOD_FAILED. 'data' contains
+ at least the first 64 bytes of the failed request.";
+ }
+ typedef ofp_table_features_failed_code {
+ type enumeration {
+ enum OFPTFFC_BAD_TABLE {
+ description "";
+ }
+ enum OFPTFFC_BAD_METADATA {
+ description "";
+ }
+ enum OFPTFFC_BAD_TYPE {
+ description "";
+ }
+ enum OFPTFFC_BAD_LEN {
+ description "";
+ }
+ enum OFPTFFC_BAD_ARGUMENT {
+ description "";
+ }
+ enum OFPTFFC_EPERM {
+ description "";
+ }
+ }
+ description
+ "ofp_error_msg 'code' values for OFPET_TABLE_FEATURES_FAILED. 'data' contains
+ at least the first 64 bytes of the failed request.";
+ }
+ typedef ofp_multipart_type {
+ type enumeration {
+ enum OFPMP_DESC {
+ description "";
+ }
+ enum OFPMP_FLOW {
+ description "";
+ }
+ enum OFPMP_AGGREGATE {
+ description "";
+ }
+ enum OFPMP_TABLE {
+ description "";
+ }
+ enum OFPMP_PORT_STATS {
+ description "";
+ }
+ enum OFPMP_QUEUE {
+ description "";
+ }
+ enum OFPMP_GROUP {
+ description "";
+ }
+ enum OFPMP_GROUP_DESC {
+ description "";
+ }
+ enum OFPMP_GROUP_FEATURES {
+ description "";
+ }
+ enum OFPMP_METER {
+ description "";
+ }
+ enum OFPMP_METER_CONFIG {
+ description "";
+ }
+ enum OFPMP_METER_FEATURES {
+ description "";
+ }
+ enum OFPMP_TABLE_FEATURES {
+ description "";
+ }
+ enum OFPMP_PORT_DESC {
+ description "";
+ }
+ enum OFPMP_EXPERIMENTER {
+ description "";
+ }
+ }
+ description
+ "";
+ }
+ typedef ofp_multipart_request_flags {
+ type enumeration {
+ enum OFPMPF_REQ_INVALID {
+ description "";
+ }
+ enum OFPMPF_REQ_MORE {
+ description "";
+ }
+ }
+ description
+ "Backward compatibility with 1.3.1 - avoid breaking the API.#define ofp_multipart_types ofp_multipart_type";
+ }
+ typedef ofp_multipart_reply_flags {
+ type enumeration {
+ enum OFPMPF_REPLY_INVALID {
+ description "";
+ }
+ enum OFPMPF_REPLY_MORE {
+ description "";
+ }
+ }
+ description
+ "";
+ }
+ typedef ofp_table_feature_prop_type {
+ type enumeration {
+ enum OFPTFPT_INSTRUCTIONS {
+ description "";
+ }
+ enum OFPTFPT_INSTRUCTIONS_MISS {
+ description "";
+ }
+ enum OFPTFPT_NEXT_TABLES {
+ description "";
+ }
+ enum OFPTFPT_NEXT_TABLES_MISS {
+ description "";
+ }
+ enum OFPTFPT_WRITE_ACTIONS {
+ description "";
+ }
+ enum OFPTFPT_WRITE_ACTIONS_MISS {
+ description "";
+ }
+ enum OFPTFPT_APPLY_ACTIONS {
+ description "";
+ }
+ enum OFPTFPT_APPLY_ACTIONS_MISS {
+ description "";
+ }
+ enum OFPTFPT_MATCH {
+ description "";
+ }
+ enum OFPTFPT_WILDCARDS {
+ description "";
+ }
+ enum OFPTFPT_WRITE_SETFIELD {
+ description "";
+ }
+ enum OFPTFPT_WRITE_SETFIELD_MISS {
+ description "";
+ }
+ enum OFPTFPT_APPLY_SETFIELD {
+ description "";
+ }
+ enum OFPTFPT_APPLY_SETFIELD_MISS {
+ description "";
+ }
+ enum OFPTFPT_EXPERIMENTER {
+ description "";
+ }
+ enum OFPTFPT_EXPERIMENTER_MISS {
+ description "";
+ }
+ }
+ description
+ "Table Feature property types.
+ Low order bit cleared indicates a property for a regular Flow Entry.
+ Low order bit set indicates a property for the Table-Miss Flow Entry.";
+ }
+ typedef ofp_group_capabilities {
+ type enumeration {
+ enum OFPGFC_INVALID {
+ description "";
+ }
+ enum OFPGFC_SELECT_WEIGHT {
+ description "";
+ }
+ enum OFPGFC_SELECT_LIVENESS {
+ description "";
+ }
+ enum OFPGFC_CHAINING {
+ description "";
+ }
+ enum OFPGFC_CHAINING_CHECKS {
+ description "";
+ }
+ }
+ description
+ "Group configuration flagsBackward compatibility with 1.3.1 - avoid breaking the API.#define ofp_group_desc_stats ofp_group_desc";
+ }
+ typedef ofp_queue_properties {
+ type enumeration {
+ enum OFPQT_INVALID {
+ description "";
+ }
+ enum OFPQT_MIN_RATE {
+ description "";
+ }
+ enum OFPQT_MAX_RATE {
+ description "";
+ }
+ enum OFPQT_EXPERIMENTER {
+ description "";
+ }
+ }
+ description
+ "All ones is used to indicate all queues in a port (for stats retrieval).#define OFPQ_ALL 0xffffffff
+Min rate > 1000 means not configured.#define OFPQ_MIN_RATE_UNCFG 0xffff
+Max rate > 1000 means not configured.#define OFPQ_MAX_RATE_UNCFG 0xffff";
+ }
+ typedef ofp_controller_role {
+ type enumeration {
+ enum OFPCR_ROLE_NOCHANGE {
+ description "";
+ }
+ enum OFPCR_ROLE_EQUAL {
+ description "";
+ }
+ enum OFPCR_ROLE_MASTER {
+ description "";
+ }
+ enum OFPCR_ROLE_SLAVE {
+ description "";
+ }
+ }
+ description
+ "Controller roles.Configures the role of the sending controller. The default role is:
+
+ - Equal (OFPCR_ROLE_EQUAL), which allows the controller access to all
+ OpenFlow features. All controllers have equal responsibility.
+
+ The other possible roles are a related pair:
+
+ - Master (OFPCR_ROLE_MASTER) is equivalent to Equal, except that there
+ may be at most one Master controller at a time: when a controller
+ configures itself as Master, any existing Master is demoted to the
+ Slave role.
+
+ - Slave (OFPCR_ROLE_SLAVE) allows the controller read-only access to
+ OpenFlow features. In particular attempts to modify the flow table
+ will be rejected with an OFPBRC_EPERM error.
+
+ Slave controllers do not receive OFPT_PACKET_IN or OFPT_FLOW_REMOVED
+ messages, but they do receive OFPT_PORT_STATUS messages.";
+ }
+
+ container ofp_header {
+ description
+ "Header on all OpenFlow packets.";
+ leaf version {
+ type uint32;
+ description
+ "OFP_VERSION.";
+ }
+
+ leaf type {
+ type ofp_type;
+
+ description
+ "One of the OFPT_ constants.";
+ }
+
+ leaf xid {
+ type uint32;
+ description
+ "Transaction id associated with this packet.
+Replies use the same id as was in the request
+to facilitate pairing.";
+ }
+
+ }
+
+ grouping ofp_hello_elem_header {
+ description
+ "Common header for all Hello Elements";
+ leaf type {
+ type ofp_hello_elem_type;
+
+ description
+ "One of OFPHET_ .";
+ }
+
+ container versionbitmap {
+ uses ofp_hello_elem_versionbitmap;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping ofp_hello_elem_versionbitmap {
+ description
+ "Version bitmap Hello Element";
+ list bitmaps {
+ key "bitmaps";
+ leaf bitmaps {
+ type uint32;
+ description
+ "List of bitmaps - supported versions";
+ }
+ description
+ "List of bitmaps - supported versions";
+ }
+
+ }
+
+ container ofp_hello {
+ description
+ "OFPT_HELLO. This message includes zero or more hello elements having
+ variable size. Unknown elements types must be ignored skipped, to allow
+ for future extensions.ofp_header header;";
+ list elements {
+ key "type";
+ uses ofp_hello_elem_header;
+
+ description
+ "Hello element list0 or more";
+ }
+
+ }
+
+ container ofp_switch_config {
+ description
+ "Switch configuration.";
+ leaf flags {
+ type uint32;
+ description
+ "ofp_header header;
+Bitmap of OFPC_ flags.";
+ }
+
+ leaf miss_send_len {
+ type uint32;
+ description
+ "Max bytes of packet that datapath
+should send to the controller. See
+ofp_controller_max_len for valid values.";
+ }
+
+ }
+
+ container ofp_table_mod {
+ description
+ "Configure Modify behavior of a flow table";
+ leaf table_id {
+ type uint32;
+ description
+ "ofp_header header;
+ID of the table, OFPTT_ALL indicates all tables";
+ }
+
+ leaf config {
+ type uint32;
+ description
+ "Bitmap of OFPTC_ flags";
+ }
+
+ }
+
+ grouping ofp_port {
+ description
+ "Description of a port";
+ leaf port_no {
+ type uint32;
+ description
+ "";
+ }
+
+ list hw_addr {
+ key "hw_addr";
+ leaf hw_addr {
+ type uint32;
+ description
+ " OFP_ETH_ALEN ;";
+ }
+ description
+ " OFP_ETH_ALEN ;";
+ }
+
+ leaf name {
+ type string;
+ description
+ "Null-terminated";
+ }
+
+ leaf config {
+ type uint32;
+ description
+ "Bitmap of OFPPC_ flags.";
+ }
+
+ leaf state {
+ type uint32;
+ description
+ "Bitmap of OFPPS_ flags.";
+ }
+
+ leaf curr {
+ type uint32;
+ description
+ "Bitmaps of OFPPF_ that describe features. All bits zeroed if
+ unsupported or unavailable.Current features.";
+ }
+
+ leaf advertised {
+ type uint32;
+ description
+ "Features being advertised by the port.";
+ }
+
+ leaf supported {
+ type uint32;
+ description
+ "Features supported by the port.";
+ }
+
+ leaf peer {
+ type uint32;
+ description
+ "Features advertised by peer.";
+ }
+
+ leaf curr_speed {
+ type uint32;
+ description
+ "Current port bitrate in kbps.";
+ }
+
+ leaf max_speed {
+ type uint32;
+ description
+ "Max port bitrate in kbps";
+ }
+
+ }
+
+ grouping ofp_switch_features {
+ description
+ "Switch features.";
+ leaf datapath_id {
+ type uint64;
+ description
+ "ofp_header header;
+Datapath unique ID. The lower 48-bits are for
+a MAC address, while the upper 16-bits are
+implementer-defined.";
+ }
+
+ leaf n_buffers {
+ type uint32;
+ description
+ "Max packets buffered at once.";
+ }
+
+ leaf n_tables {
+ type uint32;
+ description
+ "Number of tables supported by datapath.";
+ }
+
+ leaf auxiliary_id {
+ type uint32;
+ description
+ "Identify auxiliary connections";
+ }
+
+ leaf capabilities {
+ type uint32;
+ description
+ "Features.Bitmap of support ofp_capabilities .";
+ }
+
+ }
+
+ container ofp_port_status {
+ description
+ "A physical port has changed in the datapath";
+ leaf reason {
+ type ofp_port_reason;
+
+ description
+ "ofp_header header;
+One of OFPPR_ .";
+ }
+
+ container desc {
+ uses ofp_port;
+
+ description
+ "";
+ }
+
+ }
+
+ container ofp_port_mod {
+ description
+ "Modify behavior of the physical port";
+ leaf port_no {
+ type uint32;
+ description
+ "ofp_header header;";
+ }
+
+ list hw_addr {
+ key "hw_addr";
+ leaf hw_addr {
+ type uint32;
+ description
+ " OFP_ETH_ALEN ;";
+ }
+ description
+ " OFP_ETH_ALEN ;";
+ }
+
+ leaf config {
+ type uint32;
+ description
+ "The hardware address is not
+configurable. This is used to
+sanity-check the request, so it must
+be the same as returned in an
+ofp_port struct.Bitmap of OFPPC_ flags.";
+ }
+
+ leaf mask {
+ type uint32;
+ description
+ "Bitmap of OFPPC_ flags to be changed.";
+ }
+
+ leaf advertise {
+ type uint32;
+ description
+ "Bitmap of OFPPF_ . Zero all bits to prevent
+any action taking place.";
+ }
+
+ }
+
+ grouping ofp_match {
+ description
+ "Fields to match against flows";
+ leaf type {
+ type ofp_match_type;
+
+ description
+ "One of OFPMT_ ";
+ }
+
+ list oxm_fields {
+ key "oxm_class";
+ uses ofp_oxm_field;
+
+ description
+ "0 or more";
+ }
+
+ }
+
+ grouping ofp_oxm_field {
+ description
+ "OXM Flow match fields";
+ leaf oxm_class {
+ type ofp_oxm_class;
+
+ description
+ "";
+ }
+
+ container ofb_field {
+ uses ofp_oxm_ofb_field;
+
+ description
+ "2 and 3 reserved for NXM_0 and NXM-1 OXM classes";
+ }
+
+ container experimenter_field {
+ uses ofp_oxm_experimenter_field;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping ofp_oxm_ofb_field {
+ description
+ "OXM OpenFlow Basic Match Field";
+ leaf type {
+ type oxm_ofb_field_types;
+
+ description
+ "";
+ }
+
+ leaf has_mask {
+ type boolean;
+ description
+ "";
+ }
+
+ leaf port {
+ type uint32;
+ description
+ "#define OXM_OF_IN_PORT OXM_HEADER (0x8000, OFPXMT_OFB_IN_PORT, 4)
+Used for OFPXMT_OFB_IN_PORTOpenFlow port on which the packet was received.
+ May be a physical port, a logical port, or the reserved port OFPP_LOCAL
+
+ Prereqs: None.
+
+ Format: 32-bit integer in network byte order.
+
+ Masking: Not maskable.";
+ }
+
+ leaf physical_port {
+ type uint32;
+ description
+ "#define OXM_OF_IN_PHY_PORT OXM_HEADER (0x8000, OFPXMT_OFB_IN_PHY_PORT, 4)
+Used for OFPXMT_OF_IN_PHY_PORTPhysical port on which the packet was received.
+
+ Consider a packet received on a tunnel interface defined over a link
+ aggregation group (LAG) with two physical port members. If the tunnel
+ interface is the logical port bound to OpenFlow. In this case,
+ OFPXMT_OF_IN_PORT is the tunnel's port number and OFPXMT_OF_IN_PHY_PORT is
+ the physical port number of the LAG on which the tunnel is configured.
+
+ When a packet is received directly on a physical port and not processed by a
+ logical port, OFPXMT_OF_IN_PORT and OFPXMT_OF_IN_PHY_PORT have the same
+ value.
+
+ This field is usually not available in a regular match and only available
+ in ofp_packet_in messages when it's different from OXM_OF_IN_PORT.
+
+ Prereqs: OXM_OF_IN_PORT must be present.
+
+ Format: 32-bit integer in network byte order.
+
+ Masking: Not maskable.";
+ }
+
+ leaf table_metadata {
+ type uint64;
+ description
+ "#define OXM_OF_METADATA OXM_HEADER (0x8000, OFPXMT_OFB_METADATA, 8)
+#define OXM_OF_METADATA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_METADATA, 8)
+Used for OFPXMT_OFB_METADATATable metadata.
+
+ Prereqs: None.
+
+ Format: 64-bit integer in network byte order.
+
+ Masking: Arbitrary masks.";
+ }
+
+ leaf eth_dst {
+ type binary;
+ description
+ "#define OXM_OF_ETH_DST OXM_HEADER (0x8000, OFPXMT_OFB_ETH_DST, 6)
+#define OXM_OF_ETH_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ETH_DST, 6)
+#define OXM_OF_ETH_SRC OXM_HEADER (0x8000, OFPXMT_OFB_ETH_SRC, 6)
+#define OXM_OF_ETH_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ETH_SRC, 6)
+Used for OFPXMT_OFB_ETH_DST (exactly 6 bytes)Source or destination address in Ethernet header.
+
+ Prereqs: None.
+
+ Format: 48-bit Ethernet MAC address.
+
+ Masking: Arbitrary masks.";
+ }
+
+ leaf eth_src {
+ type binary;
+ description
+ "Used for OFPXMT_OFB_ETH_SRC (exactly 6 bytes)";
+ }
+
+ leaf eth_type {
+ type uint32;
+ description
+ "#define OXM_OF_ETH_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ETH_TYPE,2)
+Used for OFPXMT_OFB_ETH_TYPEPacket's Ethernet type.
+
+ Prereqs: None.
+
+ Format: 16-bit integer in network byte order.
+
+ Masking: Not maskable.";
+ }
+
+ leaf vlan_vid {
+ type uint32;
+ description
+ "#define OXM_OF_VLAN_VID OXM_HEADER (0x8000, OFPXMT_OFB_VLAN_VID, 2)
+#define OXM_OF_VLAN_VID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_VLAN_VID, 2)
+Used for OFPXMT_OFB_VLAN_VID802.1Q VID.
+
+ For a packet with an 802.1Q header, this is the VLAN-ID (VID) from the
+ outermost tag, with the CFI bit forced to 1. For a packet with no 802.1Q
+ header, this has value OFPVID_NONE.
+
+ Prereqs: None.
+
+ Format: 16-bit integer in network byte order with bit 13 indicating
+ presence of VLAN header and 3 most-significant bits forced to 0.
+ Only the lower 13 bits have meaning.
+
+ Masking: Arbitrary masks.
+
+ This field can be used in various ways:
+
+ - If it is not constrained at all, the nx_match matches packets without
+ an 802.1Q header or with an 802.1Q header that has any VID value.
+
+ - Testing for an exact match with 0x0 matches only packets without
+ an 802.1Q header.
+
+ - Testing for an exact match with a VID value with CFI=1 matches packets
+ that have an 802.1Q header with a specified VID.
+
+ - Testing for an exact match with a nonzero VID value with CFI=0 does
+ not make sense. The switch may reject this combination.
+
+ - Testing with nxm_value=0, nxm_mask=0x0fff matches packets with no 802.1Q
+ header or with an 802.1Q header with a VID of 0.
+
+ - Testing with nxm_value=0x1000, nxm_mask=0x1000 matches packets with
+ an 802.1Q header that has any VID value.";
+ }
+
+ leaf vlan_pcp {
+ type uint32;
+ description
+ "#define OXM_OF_VLAN_PCP OXM_HEADER (0x8000, OFPXMT_OFB_VLAN_PCP, 1)
+Used for OFPXMT_OFB_VLAN_PCP802.1Q PCP.
+
+ For a packet with an 802.1Q header, this is the VLAN-PCP from the
+ outermost tag. For a packet with no 802.1Q header, this has value
+ 0.
+
+ Prereqs: OXM_OF_VLAN_VID must be different from OFPVID_NONE.
+
+ Format: 8-bit integer with 5 most-significant bits forced to 0.
+ Only the lower 3 bits have meaning.
+
+ Masking: Not maskable.";
+ }
+
+ leaf ip_dscp {
+ type uint32;
+ description
+ "#define OXM_OF_IP_DSCP OXM_HEADER (0x8000, OFPXMT_OFB_IP_DSCP, 1)
+Used for OFPXMT_OFB_IP_DSCPThe Diff Serv Code Point (DSCP) bits of the IP header.
+ Part of the IPv4 ToS field or the IPv6 Traffic Class field.
+
+ Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+
+ Format: 8-bit integer with 2 most-significant bits forced to 0.
+ Only the lower 6 bits have meaning.
+
+ Masking: Not maskable.";
+ }
+
+ leaf ip_ecn {
+ type uint32;
+ description
+ "#define OXM_OF_IP_ECN OXM_HEADER (0x8000, OFPXMT_OFB_IP_ECN, 1)
+Used for OFPXMT_OFB_IP_ECNThe ECN bits of the IP header.
+ Part of the IPv4 ToS field or the IPv6 Traffic Class field.
+
+ Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+
+ Format: 8-bit integer with 6 most-significant bits forced to 0.
+ Only the lower 2 bits have meaning.
+
+ Masking: Not maskable.";
+ }
+
+ leaf ip_proto {
+ type uint32;
+ description
+ "#define OXM_OF_IP_PROTO OXM_HEADER (0x8000, OFPXMT_OFB_IP_PROTO, 1)
+Used for OFPXMT_OFB_IP_PROTOThe protocol byte in the IP header.
+
+ Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+
+ Format: 8-bit integer.
+
+ Masking: Not maskable.";
+ }
+
+ leaf ipv4_src {
+ type uint32;
+ description
+ "#define OXM_OF_IPV4_SRC OXM_HEADER (0x8000, OFPXMT_OFB_IPV4_SRC, 4)
+#define OXM_OF_IPV4_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV4_SRC, 4)
+#define OXM_OF_IPV4_DST OXM_HEADER (0x8000, OFPXMT_OFB_IPV4_DST, 4)
+#define OXM_OF_IPV4_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV4_DST, 4)
+Used for OFPXMT_OFB_IPV4_SRCThe source or destination address in the IP header.
+
+ Prereqs: OXM_OF_ETH_TYPE must match 0x0800 exactly.
+
+ Format: 32-bit integer in network byte order.
+
+ Masking: Arbitrary masks.";
+ }
+
+ leaf ipv4_dst {
+ type uint32;
+ description
+ "Used for OFPXMT_OFB_IPV4_DST";
+ }
+
+ leaf tcp_src {
+ type uint32;
+ description
+ "#define OXM_OF_TCP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_TCP_SRC, 2)
+#define OXM_OF_TCP_DST OXM_HEADER (0x8000, OFPXMT_OFB_TCP_DST, 2)
+Used for OFPXMT_OFB_TCP_SRCThe source or destination port in the TCP header.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+ OXM_OF_IP_PROTO must match 6 exactly.
+
+ Format: 16-bit integer in network byte order.
+
+ Masking: Not maskable.";
+ }
+
+ leaf tcp_dst {
+ type uint32;
+ description
+ "Used for OFPXMT_OFB_TCP_DST";
+ }
+
+ leaf udp_src {
+ type uint32;
+ description
+ "#define OXM_OF_UDP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_UDP_SRC, 2)
+#define OXM_OF_UDP_DST OXM_HEADER (0x8000, OFPXMT_OFB_UDP_DST, 2)
+Used for OFPXMT_OFB_UDP_SRCThe source or destination port in the UDP header.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd.
+ OXM_OF_IP_PROTO must match 17 exactly.
+
+ Format: 16-bit integer in network byte order.
+
+ Masking: Not maskable.";
+ }
+
+ leaf udp_dst {
+ type uint32;
+ description
+ "Used for OFPXMT_OFB_UDP_DST";
+ }
+
+ leaf sctp_src {
+ type uint32;
+ description
+ "#define OXM_OF_SCTP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_SCTP_SRC, 2)
+#define OXM_OF_SCTP_DST OXM_HEADER (0x8000, OFPXMT_OFB_SCTP_DST, 2)
+Used for OFPXMT_OFB_SCTP_SRCThe source or destination port in the SCTP header.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd.
+ OXM_OF_IP_PROTO must match 132 exactly.
+
+ Format: 16-bit integer in network byte order.
+
+ Masking: Not maskable.";
+ }
+
+ leaf sctp_dst {
+ type uint32;
+ description
+ "Used for OFPXMT_OFB_SCTP_DST";
+ }
+
+ leaf icmpv4_type {
+ type uint32;
+ description
+ "#define OXM_OF_ICMPV4_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV4_TYPE, 1)
+#define OXM_OF_ICMPV4_CODE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV4_CODE, 1)
+Used for OFPXMT_OFB_ICMPV4_TYPEThe type or code in the ICMP header.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x0800 exactly.
+ OXM_OF_IP_PROTO must match 1 exactly.
+
+ Format: 8-bit integer.
+
+ Masking: Not maskable.";
+ }
+
+ leaf icmpv4_code {
+ type uint32;
+ description
+ "Used for OFPXMT_OFB_ICMPV4_CODE";
+ }
+
+ leaf arp_op {
+ type uint32;
+ description
+ "#define OXM_OF_ARP_OP OXM_HEADER (0x8000, OFPXMT_OFB_ARP_OP, 2)
+Used for OFPXMT_OFB_ARP_OPARP opcode.
+
+ For an Ethernet+IP ARP packet, the opcode in the ARP header. Always 0
+ otherwise.
+
+ Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly.
+
+ Format: 16-bit integer in network byte order.
+
+ Masking: Not maskable.";
+ }
+
+ leaf arp_spa {
+ type uint32;
+ description
+ "#define OXM_OF_ARP_SPA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_SPA, 4)
+#define OXM_OF_ARP_SPA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ARP_SPA, 4)
+#define OXM_OF_ARP_TPA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_TPA, 4)
+#define OXM_OF_ARP_TPA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ARP_TPA, 4)
+For OFPXMT_OFB_ARP_SPAFor an Ethernet+IP ARP packet, the source or target protocol address
+ in the ARP header. Always 0 otherwise.
+
+ Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly.
+
+ Format: 32-bit integer in network byte order.
+
+ Masking: Arbitrary masks.";
+ }
+
+ leaf arp_tpa {
+ type uint32;
+ description
+ "For OFPXMT_OFB_ARP_TPA";
+ }
+
+ leaf arp_sha {
+ type binary;
+ description
+ "#define OXM_OF_ARP_SHA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_SHA, 6)
+#define OXM_OF_ARP_SHA_W OXM_HEADER_W (0x8000, OFPXMT_OFB_ARP_SHA, 6)
+#define OXM_OF_ARP_THA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_THA, 6)
+#define OXM_OF_ARP_THA_W OXM_HEADER_W (0x8000, OFPXMT_OFB_ARP_THA, 6)
+For OFPXMT_OFB_ARP_SHA (6 bytes)For an Ethernet+IP ARP packet, the source or target hardware address
+ in the ARP header. Always 0 otherwise.
+
+ Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly.
+
+ Format: 48-bit Ethernet MAC address.
+
+ Masking: Not maskable.";
+ }
+
+ leaf arp_tha {
+ type binary;
+ description
+ "For OFPXMT_OFB_ARP_THA (6 bytes)";
+ }
+
+ leaf ipv6_src {
+ type binary;
+ description
+ "#define OXM_OF_IPV6_SRC OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_SRC, 16)
+#define OXM_OF_IPV6_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_SRC, 16)
+#define OXM_OF_IPV6_DST OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_DST, 16)
+#define OXM_OF_IPV6_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_DST, 16)
+For OFPXMT_OFB_IPV6_SRCThe source or destination address in the IPv6 header.
+
+ Prereqs: OXM_OF_ETH_TYPE must match 0x86dd exactly.
+
+ Format: 128-bit IPv6 address.
+
+ Masking: Arbitrary masks.";
+ }
+
+ leaf ipv6_dst {
+ type binary;
+ description
+ "For OFPXMT_OFB_IPV6_DST";
+ }
+
+ leaf ipv6_flabel {
+ type uint32;
+ description
+ "#define OXM_OF_IPV6_FLABEL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_FLABEL, 4)
+#define OXM_OF_IPV6_FLABEL_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_FLABEL, 4)
+For OFPXMT_OFB_IPV6_FLABELThe IPv6 Flow Label
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x86dd exactly
+
+ Format: 32-bit integer with 12 most-significant bits forced to 0.
+ Only the lower 20 bits have meaning.
+
+ Masking: Arbitrary masks.";
+ }
+
+ leaf icmpv6_type {
+ type uint32;
+ description
+ "#define OXM_OF_ICMPV6_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV6_TYPE, 1)
+#define OXM_OF_ICMPV6_CODE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV6_CODE, 1)
+For OFPXMT_OFB_ICMPV6_TYPEThe type or code in the ICMPv6 header.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ OXM_OF_IP_PROTO must match 58 exactly.
+
+ Format: 8-bit integer.
+
+ Masking: Not maskable.";
+ }
+
+ leaf icmpv6_code {
+ type uint32;
+ description
+ "For OFPXMT_OFB_ICMPV6_CODE";
+ }
+
+ leaf ipv6_nd_target {
+ type binary;
+ description
+ "#define OXM_OF_IPV6_ND_TARGET OXM_HEADER
+ (0x8000, OFPXMT_OFB_IPV6_ND_TARGET, 16)
+For OFPXMT_OFB_IPV6_ND_TARGETThe target address in an IPv6 Neighbor Discovery message.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ OXM_OF_IP_PROTO must match 58 exactly.
+ OXM_OF_ICMPV6_TYPE must be either 135 or 136.
+
+ Format: 128-bit IPv6 address.
+
+ Masking: Not maskable.";
+ }
+
+ leaf ipv6_nd_ssl {
+ type binary;
+ description
+ "#define OXM_OF_IPV6_ND_SLL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_SLL, 6)
+For OFPXMT_OFB_IPV6_ND_SLLThe source link-layer address option in an IPv6 Neighbor Discovery
+ message.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ OXM_OF_IP_PROTO must match 58 exactly.
+ OXM_OF_ICMPV6_TYPE must be exactly 135.
+
+ Format: 48-bit Ethernet MAC address.
+
+ Masking: Not maskable.";
+ }
+
+ leaf ipv6_nd_tll {
+ type binary;
+ description
+ "#define OXM_OF_IPV6_ND_TLL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_TLL, 6)
+For OFPXMT_OFB_IPV6_ND_TLLThe target link-layer address option in an IPv6 Neighbor Discovery
+ message.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ OXM_OF_IP_PROTO must match 58 exactly.
+ OXM_OF_ICMPV6_TYPE must be exactly 136.
+
+ Format: 48-bit Ethernet MAC address.
+
+ Masking: Not maskable.";
+ }
+
+ leaf mpls_label {
+ type uint32;
+ description
+ "#define OXM_OF_MPLS_LABEL OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_LABEL, 4)
+For OFPXMT_OFB_MPLS_LABELThe LABEL in the first MPLS shim header.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly.
+
+ Format: 32-bit integer in network byte order with 12 most-significant
+ bits forced to 0. Only the lower 20 bits have meaning.
+
+ Masking: Not maskable.";
+ }
+
+ leaf mpls_tc {
+ type uint32;
+ description
+ "#define OXM_OF_MPLS_TC OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_TC, 1)
+For OFPXMT_OFB_MPLS_TCThe TC in the first MPLS shim header.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly.
+
+ Format: 8-bit integer with 5 most-significant bits forced to 0.
+ Only the lower 3 bits have meaning.
+
+ Masking: Not maskable.";
+ }
+
+ leaf mpls_bos {
+ type uint32;
+ description
+ "#define OXM_OF_MPLS_BOS OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_BOS, 1)
+For OFPXMT_OFB_MPLS_BOSThe BoS bit in the first MPLS shim header.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly.
+
+ Format: 8-bit integer with 7 most-significant bits forced to 0.
+ Only the lowest bit have a meaning.
+
+ Masking: Not maskable.";
+ }
+
+ leaf pbb_isid {
+ type uint32;
+ description
+ "#define OXM_OF_PBB_ISID OXM_HEADER (0x8000, OFPXMT_OFB_PBB_ISID, 3)
+#define OXM_OF_PBB_ISID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_PBB_ISID, 3)
+For OFPXMT_OFB_PBB_ISIDIEEE 802.1ah I-SID.
+
+ For a packet with a PBB header, this is the I-SID from the
+ outermost service tag.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x88E7 exactly.
+
+ Format: 24-bit integer in network byte order.
+
+ Masking: Arbitrary masks.";
+ }
+
+ leaf tunnel_id {
+ type uint64;
+ description
+ "#define OXM_OF_TUNNEL_ID OXM_HEADER (0x8000, OFPXMT_OFB_TUNNEL_ID, 8)
+#define OXM_OF_TUNNEL_ID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_TUNNEL_ID, 8)
+For OFPXMT_OFB_TUNNEL_IDLogical Port Metadata.
+
+ Metadata associated with a logical port.
+ If the logical port performs encapsulation and decapsulation, this
+ is the demultiplexing field from the encapsulation header.
+ For example, for a packet received via GRE tunnel including a (32-bit) key,
+ the key is stored in the low 32-bits and the high bits are zeroed.
+ For a MPLS logical port, the low 20 bits represent the MPLS Label.
+ For a VxLAN logical port, the low 24 bits represent the VNI.
+ If the packet is not received through a logical port, the value is 0.
+
+ Prereqs: None.
+
+ Format: 64-bit integer in network byte order.
+
+ Masking: Arbitrary masks.";
+ }
+
+ leaf ipv6_exthdr {
+ type uint32;
+ description
+ "#define OXM_OF_IPV6_EXTHDR OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_EXTHDR, 2)
+#define OXM_OF_IPV6_EXTHDR_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_EXTHDR, 2)
+For OFPXMT_OFB_IPV6_EXTHDRThe IPv6 Extension Header pseudo-field.
+
+ Prereqs:
+ OXM_OF_ETH_TYPE must match 0x86dd exactly
+
+ Format: 16-bit integer with 7 most-significant bits forced to 0.
+ Only the lower 9 bits have meaning.
+
+ Masking: Maskable.";
+ }
+
+ leaf table_metadata_mask {
+ type uint64;
+ description
+ "For OFPXMT_OFB_METADATA";
+ }
+
+ leaf eth_dst_mask {
+ type binary;
+ description
+ "For OFPXMT_OFB_ETH_DST (exactly 6 bytes)";
+ }
+
+ leaf eth_src_mask {
+ type binary;
+ description
+ "For OFPXMT_OFB_ETH_SRC (exactly 6 bytes)";
+ }
+
+ leaf vlan_vid_mask {
+ type uint32;
+ description
+ "For OFPXMT_OFB_VLAN_VID";
+ }
+
+ leaf ipv4_src_mask {
+ type uint32;
+ description
+ "For OFPXMT_OFB_IPV4_SRC";
+ }
+
+ leaf ipv4_dst_mask {
+ type uint32;
+ description
+ "For OFPXMT_OFB_IPV4_DST";
+ }
+
+ leaf arp_spa_mask {
+ type uint32;
+ description
+ "For OFPXMT_OFB_ARP_SPA";
+ }
+
+ leaf arp_tpa_mask {
+ type uint32;
+ description
+ "For OFPXMT_OFB_ARP_TPA";
+ }
+
+ leaf ipv6_src_mask {
+ type binary;
+ description
+ "For OFPXMT_OFB_IPV6_SRC";
+ }
+
+ leaf ipv6_dst_mask {
+ type binary;
+ description
+ "For OFPXMT_OFB_IPV6_DST";
+ }
+
+ leaf ipv6_flabel_mask {
+ type uint32;
+ description
+ "For OFPXMT_OFB_IPV6_FLABEL";
+ }
+
+ leaf pbb_isid_mask {
+ type uint32;
+ description
+ "For OFPXMT_OFB_PBB_ISID";
+ }
+
+ leaf tunnel_id_mask {
+ type uint64;
+ description
+ "For OFPXMT_OFB_TUNNEL_ID";
+ }
+
+ leaf ipv6_exthdr_mask {
+ type uint32;
+ description
+ "For OFPXMT_OFB_IPV6_EXTHDR";
+ }
+
+ }
+
+ grouping ofp_oxm_experimenter_field {
+ description
+ "Header for OXM experimenter match fields.
+ The experimenter class should not use OXM_HEADER() macros for defining
+ fields due to this extra header.";
+ leaf oxm_header {
+ type uint32;
+ description
+ "oxm_class = OFPXMC_EXPERIMENTER";
+ }
+
+ leaf experimenter {
+ type uint32;
+ description
+ "Experimenter ID which takes the same
+form as in struct ofp_experimenter_header.";
+ }
+
+ }
+
+ grouping ofp_action {
+ description
+ "Action header that is common to all actions. The length includes the
+ header and any padding used to make the action 64-bit aligned.
+ NB: The length of an action must always be a multiple of eight.";
+ leaf type {
+ type ofp_action_type;
+
+ description
+ "One of OFPAT_ .";
+ }
+
+ container output {
+ uses ofp_action_output;
+
+ description
+ "";
+ }
+
+ container mpls_ttl {
+ uses ofp_action_mpls_ttl;
+
+ description
+ "";
+ }
+
+ container push {
+ uses ofp_action_push;
+
+ description
+ "";
+ }
+
+ container pop_mpls {
+ uses ofp_action_pop_mpls;
+
+ description
+ "";
+ }
+
+ container group {
+ uses ofp_action_group;
+
+ description
+ "";
+ }
+
+ container nw_ttl {
+ uses ofp_action_nw_ttl;
+
+ description
+ "";
+ }
+
+ container set_field {
+ uses ofp_action_set_field;
+
+ description
+ "";
+ }
+
+ container experimenter {
+ uses ofp_action_experimenter;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping ofp_action_output {
+ description
+ "Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
+ When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
+ number of bytes to send. A 'max_len' of zero means no bytes of the
+ packet should be sent. A 'max_len' of OFPCML_NO_BUFFER means that
+ the packet is not buffered and the complete packet is to be sent to
+ the controller.";
+ leaf port {
+ type uint32;
+ description
+ "Output port.";
+ }
+
+ leaf max_len {
+ type uint32;
+ description
+ "Max length to send to controller.";
+ }
+
+ }
+
+ grouping ofp_action_mpls_ttl {
+ description
+ "Action structure for OFPAT_SET_MPLS_TTL.";
+ leaf mpls_ttl {
+ type uint32;
+ description
+ "MPLS TTL";
+ }
+
+ }
+
+ grouping ofp_action_push {
+ description
+ "Action structure for OFPAT_PUSH_VLAN MPLS PBB.";
+ leaf ethertype {
+ type uint32;
+ description
+ "Ethertype";
+ }
+
+ }
+
+ grouping ofp_action_pop_mpls {
+ description
+ "Action structure for OFPAT_POP_MPLS.";
+ leaf ethertype {
+ type uint32;
+ description
+ "Ethertype";
+ }
+
+ }
+
+ grouping ofp_action_group {
+ description
+ "Action structure for OFPAT_GROUP.";
+ leaf group_id {
+ type uint32;
+ description
+ "Group identifier.";
+ }
+
+ }
+
+ grouping ofp_action_nw_ttl {
+ description
+ "Action structure for OFPAT_SET_NW_TTL.";
+ leaf nw_ttl {
+ type uint32;
+ description
+ "IP TTL";
+ }
+
+ }
+
+ grouping ofp_action_set_field {
+ description
+ "Action structure for OFPAT_SET_FIELD.";
+ container field {
+ uses ofp_oxm_field;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping ofp_action_experimenter {
+ description
+ "Action header for OFPAT_EXPERIMENTER.
+ The rest of the body is experimenter-defined.";
+ leaf experimenter {
+ type uint32;
+ description
+ "Experimenter ID which takes the same
+form as in struct
+ofp_experimenter_header.";
+ }
+
+ leaf data {
+ type binary;
+ description
+ "";
+ }
+
+ }
+
+ grouping ofp_instruction {
+ description
+ "Instruction header that is common to all instructions. The length includes
+ the header and any padding used to make the instruction 64-bit aligned.
+ NB: The length of an instruction must always be a multiple of eight.";
+ leaf type {
+ type uint32;
+ description
+ "Instruction type";
+ }
+
+ container goto_table {
+ uses ofp_instruction_goto_table;
+
+ description
+ "";
+ }
+
+ container write_metadata {
+ uses ofp_instruction_write_metadata;
+
+ description
+ "";
+ }
+
+ container actions {
+ uses ofp_instruction_actions;
+
+ description
+ "";
+ }
+
+ container meter {
+ uses ofp_instruction_meter;
+
+ description
+ "";
+ }
+
+ container experimenter {
+ uses ofp_instruction_experimenter;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping ofp_instruction_goto_table {
+ description
+ "Instruction structure for OFPIT_GOTO_TABLE";
+ leaf table_id {
+ type uint32;
+ description
+ "Set next table in the lookup pipeline";
+ }
+
+ }
+
+ grouping ofp_instruction_write_metadata {
+ description
+ "Instruction structure for OFPIT_WRITE_METADATA";
+ leaf metadata {
+ type uint64;
+ description
+ "Metadata value to write";
+ }
+
+ leaf metadata_mask {
+ type uint64;
+ description
+ "Metadata write bitmask";
+ }
+
+ }
+
+ grouping ofp_instruction_actions {
+ description
+ "Instruction structure for OFPIT_WRITE APPLY CLEAR_ACTIONS";
+ list actions {
+ key "type";
+ uses ofp_action;
+
+ description
+ "0 or more actions associated
+with OFPIT_WRITE_ACTIONS and
+OFPIT_APPLY_ACTIONS";
+ }
+
+ }
+
+ grouping ofp_instruction_meter {
+ description
+ "Instruction structure for OFPIT_METER";
+ leaf meter_id {
+ type uint32;
+ description
+ "Meter instance.";
+ }
+
+ }
+
+ grouping ofp_instruction_experimenter {
+ description
+ "Instruction structure for experimental instructions";
+ leaf experimenter {
+ type uint32;
+ description
+ "Experimenter ID which takes the same form
+as in struct ofp_experimenter_header.";
+ }
+
+ leaf data {
+ type binary;
+ description
+ "Experimenter-defined arbitrary additional data.";
+ }
+
+ }
+
+ grouping ofp_flow_mod {
+ description
+ "Flow setup and teardown (controller -> datapath).";
+ leaf cookie {
+ type uint64;
+ description
+ "ofp_header header;
+Opaque controller-issued identifier.";
+ }
+
+ leaf cookie_mask {
+ type uint64;
+ description
+ "Mask used to restrict the cookie bits
+that must match when the command is
+OFPFC_MODIFY or OFPFC_DELETE . A value
+of 0 indicates no restriction.";
+ }
+
+ leaf table_id {
+ type uint32;
+ description
+ "ID of the table to put the flow in.
+For OFPFC_DELETE_ commands, OFPTT_ALL
+can also be used to delete matching
+flows from all tables.";
+ }
+
+ leaf command {
+ type ofp_flow_mod_command;
+
+ description
+ "One of OFPFC_ .";
+ }
+
+ leaf idle_timeout {
+ type uint32;
+ description
+ "Idle time before discarding (seconds).";
+ }
+
+ leaf hard_timeout {
+ type uint32;
+ description
+ "Max time before discarding (seconds).";
+ }
+
+ leaf priority {
+ type uint32;
+ description
+ "Priority level of flow entry.";
+ }
+
+ leaf buffer_id {
+ type uint32;
+ description
+ "Buffered packet to apply to, or
+OFP_NO_BUFFER.
+Not meaningful for OFPFC_DELETE .";
+ }
+
+ leaf out_port {
+ type uint32;
+ description
+ "For OFPFC_DELETE commands, require
+matching entries to include this as an
+output port. A value of OFPP_ANY
+indicates no restriction.";
+ }
+
+ leaf out_group {
+ type uint32;
+ description
+ "For OFPFC_DELETE commands, require
+matching entries to include this as an
+output group. A value of OFPG_ANY
+indicates no restriction.";
+ }
+
+ leaf flags {
+ type uint32;
+ description
+ "Bitmap of OFPFF_ flags.";
+ }
+
+ container match {
+ uses ofp_match;
+
+ description
+ "Fields to match. Variable size.";
+ }
+
+ list instructions {
+ key "type";
+ uses ofp_instruction;
+
+ description
+ "0 or more.";
+ }
+
+ }
+
+ grouping ofp_bucket {
+ description
+ "Bucket for use in groups.";
+ leaf weight {
+ type uint32;
+ description
+ "Relative weight of bucket. Only
+defined for select groups.";
+ }
+
+ leaf watch_port {
+ type uint32;
+ description
+ "Port whose state affects whether this
+bucket is live. Only required for fast
+failover groups.";
+ }
+
+ leaf watch_group {
+ type uint32;
+ description
+ "Group whose state affects whether this
+bucket is live. Only required for fast
+failover groups.";
+ }
+
+ list actions {
+ key "type";
+ uses ofp_action;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping ofp_group_mod {
+ description
+ "Group setup and teardown (controller -> datapath).";
+ leaf command {
+ type ofp_group_mod_command;
+
+ description
+ "ofp_header header;
+One of OFPGC_ .";
+ }
+
+ leaf type {
+ type ofp_group_type;
+
+ description
+ "One of OFPGT_ .";
+ }
+
+ leaf group_id {
+ type uint32;
+ description
+ "Group identifier.";
+ }
+
+ list buckets {
+ key "weight";
+ uses ofp_bucket;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping ofp_packet_out {
+ description
+ "Send packet (controller -> datapath).Special buffer-id to indicate 'no buffer'#define OFP_NO_BUFFER 0xffffffff";
+ leaf buffer_id {
+ type uint32;
+ description
+ "ofp_header header;
+ID assigned by datapath (OFP_NO_BUFFER
+if none).";
+ }
+
+ leaf in_port {
+ type uint32;
+ description
+ "Packet's input port or OFPP_CONTROLLER.";
+ }
+
+ list actions {
+ key "type";
+ uses ofp_action;
+
+ description
+ "Action list - 0 or more.";
+ }
+
+ leaf data {
+ type binary;
+ description
+ "The variable size action list is optionally followed by packet data.
+ This data is only present and meaningful if buffer_id == -1.Packet data.";
+ }
+
+ }
+
+ grouping ofp_packet_in {
+ description
+ "Packet received on port (datapath -> controller).";
+ leaf buffer_id {
+ type uint32;
+ description
+ "ofp_header header;
+ID assigned by datapath.";
+ }
+
+ leaf reason {
+ type ofp_packet_in_reason;
+
+ description
+ "Reason packet is being sent";
+ }
+
+ leaf table_id {
+ type uint32;
+ description
+ "ID of the table that was looked up";
+ }
+
+ leaf cookie {
+ type uint64;
+ description
+ "Cookie of the flow entry that was looked up.";
+ }
+
+ container match {
+ uses ofp_match;
+
+ description
+ "Packet metadata. Variable size.";
+ }
+
+ leaf data {
+ type binary;
+ description
+ "Ethernet frame";
+ }
+
+ }
+
+ container ofp_flow_removed {
+ description
+ "Flow removed (datapath -> controller).";
+ leaf cookie {
+ type uint64;
+ description
+ "ofp_header header;
+Opaque controller-issued identifier.";
+ }
+
+ leaf priority {
+ type uint32;
+ description
+ "Priority level of flow entry.";
+ }
+
+ leaf reason {
+ type ofp_flow_removed_reason;
+
+ description
+ "One of OFPRR_ .";
+ }
+
+ leaf table_id {
+ type uint32;
+ description
+ "ID of the table";
+ }
+
+ leaf duration_sec {
+ type uint32;
+ description
+ "Time flow was alive in seconds.";
+ }
+
+ leaf duration_nsec {
+ type uint32;
+ description
+ "Time flow was alive in nanoseconds beyond
+duration_sec.";
+ }
+
+ leaf idle_timeout {
+ type uint32;
+ description
+ "Idle timeout from original flow mod.";
+ }
+
+ leaf hard_timeout {
+ type uint32;
+ description
+ "Hard timeout from original flow mod.";
+ }
+
+ leaf packet_count {
+ type uint64;
+ description
+ "";
+ }
+
+ leaf byte_count {
+ type uint64;
+ description
+ "";
+ }
+
+ container match {
+ uses ofp_match;
+
+ description
+ "Description of fields. Variable size.";
+ }
+
+ }
+
+ grouping ofp_meter_band_header {
+ description
+ "Common header for all meter bands";
+ leaf type {
+ type ofp_meter_band_type;
+
+ description
+ "One of OFPMBT_ .";
+ }
+
+ leaf len {
+ type uint32;
+ description
+ "Length in bytes of this band.";
+ }
+
+ leaf rate {
+ type uint32;
+ description
+ "Rate for this band.";
+ }
+
+ leaf burst_size {
+ type uint32;
+ description
+ "Size of bursts.";
+ }
+
+ }
+
+ container ofp_meter_band_drop {
+ description
+ "OFPMBT_DROP band - drop packets";
+ leaf type {
+ type uint32;
+ description
+ "OFPMBT_DROP.";
+ }
+
+ leaf len {
+ type uint32;
+ description
+ "Length in bytes of this band.";
+ }
+
+ leaf rate {
+ type uint32;
+ description
+ "Rate for dropping packets.";
+ }
+
+ leaf burst_size {
+ type uint32;
+ description
+ "Size of bursts.";
+ }
+
+ }
+
+ container ofp_meter_band_dscp_remark {
+ description
+ "OFPMBT_DSCP_REMARK band - Remark DSCP in the IP header";
+ leaf type {
+ type uint32;
+ description
+ "OFPMBT_DSCP_REMARK.";
+ }
+
+ leaf len {
+ type uint32;
+ description
+ "Length in bytes of this band.";
+ }
+
+ leaf rate {
+ type uint32;
+ description
+ "Rate for remarking packets.";
+ }
+
+ leaf burst_size {
+ type uint32;
+ description
+ "Size of bursts.";
+ }
+
+ leaf prec_level {
+ type uint32;
+ description
+ "Number of drop precedence level to add.";
+ }
+
+ }
+
+ container ofp_meter_band_experimenter {
+ description
+ "OFPMBT_EXPERIMENTER band - Experimenter type.
+ The rest of the band is experimenter-defined.";
+ leaf type {
+ type ofp_meter_band_type;
+
+ description
+ "One of OFPMBT_ .";
+ }
+
+ leaf len {
+ type uint32;
+ description
+ "Length in bytes of this band.";
+ }
+
+ leaf rate {
+ type uint32;
+ description
+ "Rate for this band.";
+ }
+
+ leaf burst_size {
+ type uint32;
+ description
+ "Size of bursts.";
+ }
+
+ leaf experimenter {
+ type uint32;
+ description
+ "Experimenter ID which takes the
+same form as in struct
+ofp_experimenter_header.";
+ }
+
+ }
+
+ container ofp_meter_mod {
+ description
+ "Meter configuration. OFPT_METER_MOD.";
+ leaf command {
+ type ofp_meter_mod_command;
+
+ description
+ "ofp_header header = 1;
+One of OFPMC_ .";
+ }
+
+ leaf flags {
+ type uint32;
+ description
+ "Bitmap of OFPMF_ flags.";
+ }
+
+ leaf meter_id {
+ type uint32;
+ description
+ "Meter instance.";
+ }
+
+ list bands {
+ key "type";
+ uses ofp_meter_band_header;
+
+ description
+ "The band list length is
+inferred from the length field
+in the header.";
+ }
+
+ }
+
+ container ofp_error_msg {
+ description
+ "OFPT_ERROR: Error message (datapath -> controller).";
+ leaf type {
+ type uint32;
+ description
+ "ofp_header header;";
+ }
+
+ leaf code {
+ type uint32;
+ description
+ "";
+ }
+
+ leaf data {
+ type binary;
+ description
+ "Variable-length data. Interpreted based
+on the type and code. No padding.";
+ }
+
+ }
+
+ container ofp_error_experimenter_msg {
+ description
+ "OFPET_EXPERIMENTER: Error message (datapath -> controller).ofp_header header;";
+ leaf type {
+ type uint32;
+ description
+ "OFPET_EXPERIMENTER.";
+ }
+
+ leaf exp_type {
+ type uint32;
+ description
+ "Experimenter defined.";
+ }
+
+ leaf experimenter {
+ type uint32;
+ description
+ "Experimenter ID which takes the same form
+as in struct ofp_experimenter_header.";
+ }
+
+ leaf data {
+ type binary;
+ description
+ "Variable-length data. Interpreted based
+on the type and code. No padding.";
+ }
+
+ }
+
+ container ofp_multipart_request {
+ description
+ "";
+ leaf type {
+ type ofp_multipart_type;
+
+ description
+ "ofp_header header;
+One of the OFPMP_ constants.";
+ }
+
+ leaf flags {
+ type uint32;
+ description
+ "OFPMPF_REQ_ flags.";
+ }
+
+ leaf body {
+ type binary;
+ description
+ "Body of the request. 0 or more bytes.";
+ }
+
+ }
+
+ container ofp_multipart_reply {
+ description
+ "";
+ leaf type {
+ type ofp_multipart_type;
+
+ description
+ "ofp_header header;
+One of the OFPMP_ constants.";
+ }
+
+ leaf flags {
+ type uint32;
+ description
+ "OFPMPF_REPLY_ flags.";
+ }
+
+ leaf body {
+ type binary;
+ description
+ "Body of the reply. 0 or more bytes.";
+ }
+
+ }
+
+ grouping ofp_desc {
+ description
+ "Body of reply to OFPMP_DESC request. Each entry is a NULL-terminated
+ ASCII string.#define DESC_STR_LEN 256
+#define SERIAL_NUM_LEN 32";
+ leaf mfr_desc {
+ type string;
+ description
+ "Manufacturer description.";
+ }
+
+ leaf hw_desc {
+ type string;
+ description
+ "Hardware description.";
+ }
+
+ leaf sw_desc {
+ type string;
+ description
+ "Software description.";
+ }
+
+ leaf serial_num {
+ type string;
+ description
+ "Serial number.";
+ }
+
+ leaf dp_desc {
+ type string;
+ description
+ "Human readable description of datapath.";
+ }
+
+ }
+
+ container ofp_flow_stats_request {
+ description
+ "Body for ofp_multipart_request of type OFPMP_FLOW.";
+ leaf table_id {
+ type uint32;
+ description
+ "ID of table to read (from ofp_table_stats),
+OFPTT_ALL for all tables.";
+ }
+
+ leaf out_port {
+ type uint32;
+ description
+ "Require matching entries to include this
+as an output port. A value of OFPP_ANY
+indicates no restriction.";
+ }
+
+ leaf out_group {
+ type uint32;
+ description
+ "Require matching entries to include this
+as an output group. A value of OFPG_ANY
+indicates no restriction.";
+ }
+
+ leaf cookie {
+ type uint64;
+ description
+ "Require matching entries to contain this
+cookie value";
+ }
+
+ leaf cookie_mask {
+ type uint64;
+ description
+ "Mask used to restrict the cookie bits that
+must match. A value of 0 indicates
+no restriction.";
+ }
+
+ container match {
+ uses ofp_match;
+
+ description
+ "Fields to match. Variable size.";
+ }
+
+ }
+
+ grouping ofp_flow_stats {
+ description
+ "Body of reply to OFPMP_FLOW request.";
+ leaf id {
+ type uint64;
+ description
+ "Unique ID of flow within device.";
+ }
+
+ leaf table_id {
+ type uint32;
+ description
+ "ID of table flow came from.";
+ }
+
+ leaf duration_sec {
+ type uint32;
+ description
+ "Time flow has been alive in seconds.";
+ }
+
+ leaf duration_nsec {
+ type uint32;
+ description
+ "Time flow has been alive in nanoseconds
+beyond duration_sec.";
+ }
+
+ leaf priority {
+ type uint32;
+ description
+ "Priority of the entry.";
+ }
+
+ leaf idle_timeout {
+ type uint32;
+ description
+ "Number of seconds idle before expiration.";
+ }
+
+ leaf hard_timeout {
+ type uint32;
+ description
+ "Number of seconds before expiration.";
+ }
+
+ leaf flags {
+ type uint32;
+ description
+ "Bitmap of OFPFF_ flags.";
+ }
+
+ leaf cookie {
+ type uint64;
+ description
+ "Opaque controller-issued identifier.";
+ }
+
+ leaf packet_count {
+ type uint64;
+ description
+ "Number of packets in flow.";
+ }
+
+ leaf byte_count {
+ type uint64;
+ description
+ "Number of bytes in flow.";
+ }
+
+ container match {
+ uses ofp_match;
+
+ description
+ "Description of fields. Variable size.";
+ }
+
+ list instructions {
+ key "type";
+ uses ofp_instruction;
+
+ description
+ "Instruction set
+(0 or more)";
+ }
+
+ }
+
+ container ofp_aggregate_stats_request {
+ description
+ "Body for ofp_multipart_request of type OFPMP_AGGREGATE.";
+ leaf table_id {
+ type uint32;
+ description
+ "ID of table to read (from ofp_table_stats)
+OFPTT_ALL for all tables.";
+ }
+
+ leaf out_port {
+ type uint32;
+ description
+ "Require matching entries to include this
+as an output port. A value of OFPP_ANY
+indicates no restriction.";
+ }
+
+ leaf out_group {
+ type uint32;
+ description
+ "Require matching entries to include this
+as an output group. A value of OFPG_ANY
+indicates no restriction.";
+ }
+
+ leaf cookie {
+ type uint64;
+ description
+ "Require matching entries to contain this
+cookie value";
+ }
+
+ leaf cookie_mask {
+ type uint64;
+ description
+ "Mask used to restrict the cookie bits that
+must match. A value of 0 indicates
+no restriction.";
+ }
+
+ container match {
+ uses ofp_match;
+
+ description
+ "Fields to match. Variable size.";
+ }
+
+ }
+
+ container ofp_aggregate_stats_reply {
+ description
+ "Body of reply to OFPMP_AGGREGATE request.";
+ leaf packet_count {
+ type uint64;
+ description
+ "Number of packets in flows.";
+ }
+
+ leaf byte_count {
+ type uint64;
+ description
+ "Number of bytes in flows.";
+ }
+
+ leaf flow_count {
+ type uint32;
+ description
+ "Number of flows.";
+ }
+
+ }
+
+ grouping ofp_table_feature_property {
+ description
+ "Common header for all Table Feature Properties";
+ leaf type {
+ type ofp_table_feature_prop_type;
+
+ description
+ "One of OFPTFPT_ .";
+ }
+
+ container instructions {
+ uses ofp_table_feature_prop_instructions;
+
+ description
+ "";
+ }
+
+ container next_tables {
+ uses ofp_table_feature_prop_next_tables;
+
+ description
+ "";
+ }
+
+ container actions {
+ uses ofp_table_feature_prop_actions;
+
+ description
+ "";
+ }
+
+ container oxm {
+ uses ofp_table_feature_prop_oxm;
+
+ description
+ "";
+ }
+
+ container experimenter {
+ uses ofp_table_feature_prop_experimenter;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping ofp_table_feature_prop_instructions {
+ description
+ "Instructions property";
+ list instructions {
+ key "type";
+ uses ofp_instruction;
+
+ description
+ "One of OFPTFPT_INSTRUCTIONS,
+OFPTFPT_INSTRUCTIONS_MISS.List of instructions";
+ }
+
+ }
+
+ grouping ofp_table_feature_prop_next_tables {
+ description
+ "Next Tables property";
+ list next_table_ids {
+ key "next_table_ids";
+ leaf next_table_ids {
+ type uint32;
+ description
+ "One of OFPTFPT_NEXT_TABLES,
+OFPTFPT_NEXT_TABLES_MISS.List of table ids.";
+ }
+ description
+ "One of OFPTFPT_NEXT_TABLES,
+OFPTFPT_NEXT_TABLES_MISS.List of table ids.";
+ }
+
+ }
+
+ grouping ofp_table_feature_prop_actions {
+ description
+ "Actions property";
+ list actions {
+ key "type";
+ uses ofp_action;
+
+ description
+ "One of OFPTFPT_WRITE_ACTIONS,
+OFPTFPT_WRITE_ACTIONS_MISS,
+OFPTFPT_APPLY_ACTIONS,
+OFPTFPT_APPLY_ACTIONS_MISS.List of actions";
+ }
+
+ }
+
+ grouping ofp_table_feature_prop_oxm {
+ description
+ "Match, Wildcard or Set-Field propertyOne of OFPTFPT_MATCH,
+OFPTFPT_WILDCARDS,
+OFPTFPT_WRITE_SETFIELD,
+OFPTFPT_WRITE_SETFIELD_MISS,
+OFPTFPT_APPLY_SETFIELD,
+OFPTFPT_APPLY_SETFIELD_MISS.";
+ list oxm_ids {
+ key "oxm_ids";
+ leaf oxm_ids {
+ type uint32;
+ description
+ "TODO is this a uint32???Array of OXM headers";
+ }
+ description
+ "TODO is this a uint32???Array of OXM headers";
+ }
+
+ }
+
+ grouping ofp_table_feature_prop_experimenter {
+ description
+ "Experimenter table feature property";
+ leaf experimenter {
+ type uint32;
+ description
+ "One of OFPTFPT_EXPERIMENTER,
+OFPTFPT_EXPERIMENTER_MISS.Experimenter ID which takes the same
+form as in struct
+ofp_experimenter_header.";
+ }
+
+ leaf exp_type {
+ type uint32;
+ description
+ "Experimenter defined.";
+ }
+
+ list experimenter_data {
+ key "experimenter_data";
+ leaf experimenter_data {
+ type uint32;
+ description
+ "";
+ }
+ description
+ "";
+ }
+
+ }
+
+ container ofp_table_features {
+ description
+ "Body for ofp_multipart_request of type OFPMP_TABLE_FEATURES.
+ Body of reply to OFPMP_TABLE_FEATURES request.";
+ leaf table_id {
+ type uint32;
+ description
+ "Identifier of table. Lower numbered tables
+are consulted first.";
+ }
+
+ leaf name {
+ type string;
+ description
+ "";
+ }
+
+ leaf metadata_match {
+ type uint64;
+ description
+ "Bits of metadata table can match.";
+ }
+
+ leaf metadata_write {
+ type uint64;
+ description
+ "Bits of metadata table can write.";
+ }
+
+ leaf config {
+ type uint32;
+ description
+ "Bitmap of OFPTC_ values";
+ }
+
+ leaf max_entries {
+ type uint32;
+ description
+ "Max number of entries supported.";
+ }
+
+ list properties {
+ key "type";
+ uses ofp_table_feature_property;
+
+ description
+ "Table Feature Property list";
+ }
+
+ }
+
+ container ofp_table_stats {
+ description
+ "Body of reply to OFPMP_TABLE request.";
+ leaf table_id {
+ type uint32;
+ description
+ "Identifier of table. Lower numbered tables
+are consulted first.";
+ }
+
+ leaf active_count {
+ type uint32;
+ description
+ "Number of active entries.";
+ }
+
+ leaf lookup_count {
+ type uint64;
+ description
+ "Number of packets looked up in table.";
+ }
+
+ leaf matched_count {
+ type uint64;
+ description
+ "Number of packets that hit table.";
+ }
+
+ }
+
+ container ofp_port_stats_request {
+ description
+ "Body for ofp_multipart_request of type OFPMP_PORT.";
+ leaf port_no {
+ type uint32;
+ description
+ "OFPMP_PORT message must request statistics
+ either for a single port (specified in
+ port_no) or for all ports (if port_no ==
+ OFPP_ANY).";
+ }
+
+ }
+
+ container ofp_port_stats {
+ description
+ "Body of reply to OFPMP_PORT request. If a counter is unsupported, set
+ the field to all ones.";
+ leaf port_no {
+ type uint32;
+ description
+ "";
+ }
+
+ leaf rx_packets {
+ type uint64;
+ description
+ "Number of received packets.";
+ }
+
+ leaf tx_packets {
+ type uint64;
+ description
+ "Number of transmitted packets.";
+ }
+
+ leaf rx_bytes {
+ type uint64;
+ description
+ "Number of received bytes.";
+ }
+
+ leaf tx_bytes {
+ type uint64;
+ description
+ "Number of transmitted bytes.";
+ }
+
+ leaf rx_dropped {
+ type uint64;
+ description
+ "Number of packets dropped by RX.";
+ }
+
+ leaf tx_dropped {
+ type uint64;
+ description
+ "Number of packets dropped by TX.";
+ }
+
+ leaf rx_errors {
+ type uint64;
+ description
+ "Number of receive errors. This is a super-set
+of more specific receive errors and should be
+greater than or equal to the sum of all
+rx_ _err values.";
+ }
+
+ leaf tx_errors {
+ type uint64;
+ description
+ "Number of transmit errors. This is a super-set
+of more specific transmit errors and should be
+greater than or equal to the sum of all
+tx_ _err values (none currently defined.)";
+ }
+
+ leaf rx_frame_err {
+ type uint64;
+ description
+ "Number of frame alignment errors.";
+ }
+
+ leaf rx_over_err {
+ type uint64;
+ description
+ "Number of packets with RX overrun.";
+ }
+
+ leaf rx_crc_err {
+ type uint64;
+ description
+ "Number of CRC errors.";
+ }
+
+ leaf collisions {
+ type uint64;
+ description
+ "Number of collisions.";
+ }
+
+ leaf duration_sec {
+ type uint32;
+ description
+ "Time port has been alive in seconds.";
+ }
+
+ leaf duration_nsec {
+ type uint32;
+ description
+ "Time port has been alive in nanoseconds
+beyond duration_sec.";
+ }
+
+ }
+
+ container ofp_group_stats_request {
+ description
+ "Body of OFPMP_GROUP request.";
+ leaf group_id {
+ type uint32;
+ description
+ "All groups if OFPG_ALL.";
+ }
+
+ }
+
+ grouping ofp_bucket_counter {
+ description
+ "Used in group stats replies.";
+ leaf packet_count {
+ type uint64;
+ description
+ "Number of packets processed by bucket.";
+ }
+
+ leaf byte_count {
+ type uint64;
+ description
+ "Number of bytes processed by bucket.";
+ }
+
+ }
+
+ grouping ofp_group_stats {
+ description
+ "Body of reply to OFPMP_GROUP request.";
+ leaf group_id {
+ type uint32;
+ description
+ "Group identifier.";
+ }
+
+ leaf ref_count {
+ type uint32;
+ description
+ "Number of flows or groups that directly
+forward to this group.";
+ }
+
+ leaf packet_count {
+ type uint64;
+ description
+ "Number of packets processed by group.";
+ }
+
+ leaf byte_count {
+ type uint64;
+ description
+ "Number of bytes processed by group.";
+ }
+
+ leaf duration_sec {
+ type uint32;
+ description
+ "Time group has been alive in seconds.";
+ }
+
+ leaf duration_nsec {
+ type uint32;
+ description
+ "Time group has been alive in nanoseconds
+beyond duration_sec.";
+ }
+
+ list bucket_stats {
+ key "packet_count";
+ uses ofp_bucket_counter;
+
+ description
+ "One counter set per
+bucket.";
+ }
+
+ }
+
+ container ofp_group_desc {
+ description
+ "Body of reply to OFPMP_GROUP_DESC request.";
+ leaf type {
+ type ofp_group_type;
+
+ description
+ "One of OFPGT_ .";
+ }
+
+ leaf group_id {
+ type uint32;
+ description
+ "Group identifier.";
+ }
+
+ list buckets {
+ key "weight";
+ uses ofp_bucket;
+
+ description
+ "List of buckets - 0 or more.";
+ }
+
+ }
+
+ grouping ofp_group_entry {
+ description
+ "";
+ leaf type {
+ type ofp_group_type;
+
+ description
+ "One of OFPGT_ .";
+ }
+
+ leaf group_id {
+ type uint32;
+ description
+ "Group identifier.";
+ }
+
+ list buckets {
+ key "weight";
+ uses ofp_bucket;
+
+ description
+ "List of buckets - 0 or more.";
+ }
+
+ container stats {
+ uses ofp_group_stats;
+
+ description
+ "ofp_group_desc desc = 1;";
+ }
+
+ }
+
+ container ofp_group_features {
+ description
+ "Body of reply to OFPMP_GROUP_FEATURES request. Group features.";
+ leaf types {
+ type uint32;
+ description
+ "Bitmap of (1 << OFPGT_ ) values supported.";
+ }
+
+ leaf capabilities {
+ type uint32;
+ description
+ "Bitmap of OFPGFC_ capability supported.";
+ }
+
+ list max_groups {
+ key "max_groups";
+ leaf max_groups {
+ type uint32;
+ description
+ "Maximum number of groups for each type.";
+ }
+ description
+ "Maximum number of groups for each type.";
+ }
+
+ list actions {
+ key "actions";
+ leaf actions {
+ type uint32;
+ description
+ "Bitmaps of (1 << OFPAT_ ) values
+supported.";
+ }
+ description
+ "Bitmaps of (1 << OFPAT_ ) values
+supported.";
+ }
+
+ }
+
+ container ofp_meter_multipart_request {
+ description
+ "Body of OFPMP_METER and OFPMP_METER_CONFIG requests.";
+ leaf meter_id {
+ type uint32;
+ description
+ "Meter instance, or OFPM_ALL.";
+ }
+
+ }
+
+ grouping ofp_meter_band_stats {
+ description
+ "Statistics for each meter band";
+ leaf packet_band_count {
+ type uint64;
+ description
+ "Number of packets in band.";
+ }
+
+ leaf byte_band_count {
+ type uint64;
+ description
+ "Number of bytes in band.";
+ }
+
+ }
+
+ container ofp_meter_stats {
+ description
+ "Body of reply to OFPMP_METER request. Meter statistics.";
+ leaf meter_id {
+ type uint32;
+ description
+ "Meter instance.";
+ }
+
+ leaf flow_count {
+ type uint32;
+ description
+ "Number of flows bound to meter.";
+ }
+
+ leaf packet_in_count {
+ type uint64;
+ description
+ "Number of packets in input.";
+ }
+
+ leaf byte_in_count {
+ type uint64;
+ description
+ "Number of bytes in input.";
+ }
+
+ leaf duration_sec {
+ type uint32;
+ description
+ "Time meter has been alive in seconds.";
+ }
+
+ leaf duration_nsec {
+ type uint32;
+ description
+ "Time meter has been alive in nanoseconds
+beyond duration_sec.";
+ }
+
+ list band_stats {
+ key "packet_band_count";
+ uses ofp_meter_band_stats;
+
+ description
+ "The band_stats length is
+inferred from the length field.";
+ }
+
+ }
+
+ container ofp_meter_config {
+ description
+ "Body of reply to OFPMP_METER_CONFIG request. Meter configuration.";
+ leaf flags {
+ type uint32;
+ description
+ "All OFPMF_ that apply.";
+ }
+
+ leaf meter_id {
+ type uint32;
+ description
+ "Meter instance.";
+ }
+
+ list bands {
+ key "type";
+ uses ofp_meter_band_header;
+
+ description
+ "The bands length is
+inferred from the length field.";
+ }
+
+ }
+
+ container ofp_meter_features {
+ description
+ "Body of reply to OFPMP_METER_FEATURES request. Meter features.";
+ leaf max_meter {
+ type uint32;
+ description
+ "Maximum number of meters.";
+ }
+
+ leaf band_types {
+ type uint32;
+ description
+ "Bitmaps of (1 << OFPMBT_ ) values supported.";
+ }
+
+ leaf capabilities {
+ type uint32;
+ description
+ "Bitmaps of ofp_meter_flags .";
+ }
+
+ leaf max_bands {
+ type uint32;
+ description
+ "Maximum bands per meters";
+ }
+
+ leaf max_color {
+ type uint32;
+ description
+ "Maximum color value";
+ }
+
+ }
+
+ container ofp_experimenter_multipart_header {
+ description
+ "Body for ofp_multipart_request reply of type OFPMP_EXPERIMENTER.";
+ leaf experimenter {
+ type uint32;
+ description
+ "Experimenter ID which takes the same form
+as in struct ofp_experimenter_header.";
+ }
+
+ leaf exp_type {
+ type uint32;
+ description
+ "Experimenter defined.";
+ }
+
+ leaf data {
+ type binary;
+ description
+ "Experimenter-defined arbitrary additional data.";
+ }
+
+ }
+
+ container ofp_experimenter_header {
+ description
+ "Experimenter extension.";
+ leaf experimenter {
+ type uint32;
+ description
+ "ofp_header header; Type OFPT_EXPERIMENTER.
+Experimenter ID:
+ - MSB 0: low-order bytes are IEEE OUI.
+ - MSB != 0: defined by ONF.";
+ }
+
+ leaf exp_type {
+ type uint32;
+ description
+ "Experimenter defined.";
+ }
+
+ leaf data {
+ type binary;
+ description
+ "Experimenter-defined arbitrary additional data.";
+ }
+
+ }
+
+ grouping ofp_queue_prop_header {
+ description
+ "Common description for a queue.";
+ leaf property {
+ type uint32;
+ description
+ "One of OFPQT_.";
+ }
+
+ leaf len {
+ type uint32;
+ description
+ "Length of property, including this header.";
+ }
+
+ }
+
+ container ofp_queue_prop_min_rate {
+ description
+ "Min-Rate queue property description.";
+ container prop_header {
+ uses ofp_queue_prop_header;
+
+ description
+ "prop: OFPQT_MIN, len: 16.";
+ }
+
+ leaf rate {
+ type uint32;
+ description
+ "In 1 10 of a percent = 0;>1000 -> disabled.";
+ }
+
+ }
+
+ container ofp_queue_prop_max_rate {
+ description
+ "Max-Rate queue property description.";
+ container prop_header {
+ uses ofp_queue_prop_header;
+
+ description
+ "prop: OFPQT_MAX, len: 16.";
+ }
+
+ leaf rate {
+ type uint32;
+ description
+ "In 1 10 of a percent = 0;>1000 -> disabled.";
+ }
+
+ }
+
+ container ofp_queue_prop_experimenter {
+ description
+ "Experimenter queue property description.";
+ container prop_header {
+ uses ofp_queue_prop_header;
+
+ description
+ "prop: OFPQT_EXPERIMENTER";
+ }
+
+ leaf experimenter {
+ type uint32;
+ description
+ "Experimenter ID which takes the same
+form as in struct
+ofp_experimenter_header.";
+ }
+
+ leaf data {
+ type binary;
+ description
+ "Experimenter defined data.";
+ }
+
+ }
+
+ grouping ofp_packet_queue {
+ description
+ "Full description for a queue.";
+ leaf queue_id {
+ type uint32;
+ description
+ "id for the specific queue.";
+ }
+
+ leaf port {
+ type uint32;
+ description
+ "Port this queue is attached to.";
+ }
+
+ list properties {
+ key "property";
+ uses ofp_queue_prop_header;
+
+ description
+ "List of properties.";
+ }
+
+ }
+
+ container ofp_queue_get_config_request {
+ description
+ "Query for port queue configuration.";
+ leaf port {
+ type uint32;
+ description
+ "ofp_header header;
+Port to be queried. Should refer
+to a valid physical port (i.e. <= OFPP_MAX),
+or OFPP_ANY to request all configured
+queues.";
+ }
+
+ }
+
+ container ofp_queue_get_config_reply {
+ description
+ "Queue configuration for a given port.";
+ leaf port {
+ type uint32;
+ description
+ "ofp_header header;";
+ }
+
+ list queues {
+ key "queue_id";
+ uses ofp_packet_queue;
+
+ description
+ "List of configured queues.";
+ }
+
+ }
+
+ container ofp_action_set_queue {
+ description
+ "OFPAT_SET_QUEUE action struct: send packets to given queue on port.";
+ leaf type {
+ type uint32;
+ description
+ "OFPAT_SET_QUEUE.";
+ }
+
+ leaf queue_id {
+ type uint32;
+ description
+ "Queue id for the packets.";
+ }
+
+ }
+
+ container ofp_queue_stats_request {
+ description
+ "";
+ leaf port_no {
+ type uint32;
+ description
+ "All ports if OFPP_ANY.";
+ }
+
+ leaf queue_id {
+ type uint32;
+ description
+ "All queues if OFPQ_ALL.";
+ }
+
+ }
+
+ container ofp_queue_stats {
+ description
+ "";
+ leaf port_no {
+ type uint32;
+ description
+ "";
+ }
+
+ leaf queue_id {
+ type uint32;
+ description
+ "Queue i.d";
+ }
+
+ leaf tx_bytes {
+ type uint64;
+ description
+ "Number of transmitted bytes.";
+ }
+
+ leaf tx_packets {
+ type uint64;
+ description
+ "Number of transmitted packets.";
+ }
+
+ leaf tx_errors {
+ type uint64;
+ description
+ "Number of packets dropped due to overrun.";
+ }
+
+ leaf duration_sec {
+ type uint32;
+ description
+ "Time queue has been alive in seconds.";
+ }
+
+ leaf duration_nsec {
+ type uint32;
+ description
+ "Time queue has been alive in nanoseconds
+beyond duration_sec.";
+ }
+
+ }
+
+ container ofp_role_request {
+ description
+ "Role request and reply message.";
+ leaf role {
+ type ofp_controller_role;
+
+ description
+ "ofp_header header; Type OFPT_ROLE_REQUEST OFPT_ROLE_REPLY.
+One of OFPCR_ROLE_ .";
+ }
+
+ leaf generation_id {
+ type uint64;
+ description
+ "Master Election Generation Id";
+ }
+
+ }
+
+ container ofp_async_config {
+ description
+ "Asynchronous message configuration.";
+ list packet_in_mask {
+ key "packet_in_mask";
+ leaf packet_in_mask {
+ type uint32;
+ description
+ "ofp_header header; OFPT_GET_ASYNC_REPLY or OFPT_SET_ASYNC.
+Bitmasks of OFPR_ values.";
+ }
+ description
+ "ofp_header header; OFPT_GET_ASYNC_REPLY or OFPT_SET_ASYNC.
+Bitmasks of OFPR_ values.";
+ }
+
+ list port_status_mask {
+ key "port_status_mask";
+ leaf port_status_mask {
+ type uint32;
+ description
+ "Bitmasks of OFPPR_ values.";
+ }
+ description
+ "Bitmasks of OFPPR_ values.";
+ }
+
+ list flow_removed_mask {
+ key "flow_removed_mask";
+ leaf flow_removed_mask {
+ type uint32;
+ description
+ "Bitmasks of OFPRR_ values.";
+ }
+ description
+ "Bitmasks of OFPRR_ values.";
+ }
+
+ }
+
+ grouping FlowTableUpdate {
+ description
+ "ADDITIONAL VOLTHA SPECIFIC MESSAGE TYPES, AIDING RPC CALLS";
+ leaf id {
+ type string;
+ description
+ "Device.id or LogicalDevice.id";
+ }
+
+ container flow_mod {
+ uses ofp_flow_mod;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping FlowGroupTableUpdate {
+ description
+ "";
+ leaf id {
+ type string;
+ description
+ "Device.id or LogicalDevice.id";
+ }
+
+ container group_mod {
+ uses ofp_group_mod;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping Flows {
+ description
+ "";
+ list items {
+ key "id";
+ uses ofp_flow_stats;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping FlowGroups {
+ description
+ "";
+ list items {
+ key "type";
+ uses ofp_group_entry;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping PacketIn {
+ description
+ "";
+ leaf id {
+ type string;
+ description
+ "LogicalDevice.id";
+ }
+
+ container packet_in {
+ uses ofp_packet_in;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping PacketOut {
+ description
+ "";
+ leaf id {
+ type string;
+ description
+ "LogicalDevice.id";
+ }
+
+ container packet_out {
+ uses ofp_packet_out;
+
+ description
+ "";
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/ietf-voltha.yang b/experiments/netconf/proto2yang/ietf-voltha.yang
new file mode 100644
index 0000000..b79eef1
--- /dev/null
+++ b/experiments/netconf/proto2yang/ietf-voltha.yang
@@ -0,0 +1,798 @@
+
+module ietf-voltha {
+
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-voltha";
+ prefix voltha;
+
+ import ietf-openflow_13 { prefix openflow_13 ; }
+ import ietf-adapter { prefix adapter ; }
+ import ietf-health { prefix health ; }
+ import ietf-common { prefix common ; }
+ import ietf-device { prefix device ; }
+ import ietf-logical_device { prefix logical_device ; }
+ import ietf-empty { prefix empty ; }
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+
+ grouping DeviceGroup {
+ description
+ "";
+ leaf id {
+ type string;
+ description
+ "";
+ }
+
+ list logical_devices {
+ key "id";
+ uses logical_device:LogicalDevice;
+
+ description
+ "";
+ }
+
+ list devices {
+ key "id";
+ uses device:Device;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping DeviceGroups {
+ description
+ "";
+ list items {
+ key "id";
+ uses DeviceGroup;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping VolthaInstance {
+ description
+ "Top-level (root) node for a Voltha Instance";
+ leaf instance_id {
+ type string;
+ description
+ "";
+ }
+
+ leaf version {
+ type string;
+ description
+ "";
+ }
+
+ leaf log_level {
+ type common:LogLevel;
+
+ description
+ "";
+ }
+
+ container health {
+ uses health:HealthStatus;
+
+ description
+ "";
+ }
+
+ list adapters {
+ key "id";
+ uses adapter:Adapter;
+
+ description
+ "";
+ }
+
+ list logical_devices {
+ key "id";
+ uses logical_device:LogicalDevice;
+
+ description
+ "";
+ }
+
+ list devices {
+ key "id";
+ uses device:Device;
+
+ description
+ "";
+ }
+
+ list device_types {
+ key "id";
+ uses device:DeviceType;
+
+ description
+ "";
+ }
+
+ list device_groups {
+ key "id";
+ uses DeviceGroup;
+
+ description
+ "";
+ }
+
+ }
+
+ grouping VolthaInstances {
+ description
+ "";
+ list items {
+ key "items";
+ leaf items {
+ type string;
+ description
+ "";
+ }
+ description
+ "";
+ }
+
+ }
+
+ grouping Voltha {
+ description
+ "Voltha representing the entire Voltha cluster";
+ leaf version {
+ type string;
+ description
+ "";
+ }
+
+ leaf log_level {
+ type common:LogLevel;
+
+ description
+ "";
+ }
+
+ list instances {
+ key "instance_id";
+ uses VolthaInstance;
+
+ description
+ "";
+ }
+
+ list adapters {
+ key "id";
+ uses adapter:Adapter;
+
+ description
+ "";
+ }
+
+ list logical_devices {
+ key "id";
+ uses logical_device:LogicalDevice;
+
+ description
+ "";
+ }
+
+ list devices {
+ key "id";
+ uses device:Device;
+
+ description
+ "";
+ }
+
+ list device_groups {
+ key "id";
+ uses DeviceGroup;
+
+ description
+ "";
+ }
+
+ }
+
+ /* Cluster-wide Voltha APIs
+
+ These APIs are potentially dispatched to the leader of the Voltha cluster,
+ to a specific Voltha instance which owns the given device or logical device." */
+ rpc VolthaGlobalService-GetVoltha {
+ description
+ "Get high level information on the Voltha cluster";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses Voltha;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListVolthaInstances {
+ description
+ "List all Voltha cluster instances";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses VolthaInstances;
+
+ }
+ }
+
+ rpc VolthaGlobalService-GetVolthaInstance {
+ description
+ "Get details on a Voltha cluster instance";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses VolthaInstance;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListLogicalDevices {
+ description
+ "List all logical devices managed by the Voltha cluster";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses logical_device:LogicalDevices;
+
+ }
+ }
+
+ rpc VolthaGlobalService-GetLogicalDevice {
+ description
+ "Get additional information on a given logical device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses logical_device:LogicalDevice;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListLogicalDevicePorts {
+ description
+ "List ports of a logical device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses logical_device:LogicalPorts;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListLogicalDeviceFlows {
+ description
+ "List all flows of a logical device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses openflow_13:Flows;
+
+ }
+ }
+
+ rpc VolthaGlobalService-UpdateLogicalDeviceFlowTable {
+ description
+ "Update flow table for logical device";
+ input {
+ uses openflow_13:FlowTableUpdate;
+
+ }
+ output {
+ uses empty:Empty;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListLogicalDeviceFlowGroups {
+ description
+ "List all flow groups of a logical device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses openflow_13:FlowGroups;
+
+ }
+ }
+
+ rpc VolthaGlobalService-UpdateLogicalDeviceFlowGroupTable {
+ description
+ "Update group table for device";
+ input {
+ uses openflow_13:FlowGroupTableUpdate;
+
+ }
+ output {
+ uses empty:Empty;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListDevices {
+ description
+ "List all physical devices controlled by the Voltha cluster";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses device:Devices;
+
+ }
+ }
+
+ rpc VolthaGlobalService-GetDevice {
+ description
+ "Get more information on a given physical device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses device:Device;
+
+ }
+ }
+
+ rpc VolthaGlobalService-CreateDevice {
+ description
+ "Pre-provision a new physical device";
+ input {
+ uses device:Device;
+
+ }
+ output {
+ uses device:Device;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ActivateDevice {
+ description
+ "Activate a pre-provisioned device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses empty:Empty;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListDevicePorts {
+ description
+ "List ports of a device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses device:Ports;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListDeviceFlows {
+ description
+ "List all flows of a device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses openflow_13:Flows;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListDeviceFlowGroups {
+ description
+ "List all flow groups of a device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses openflow_13:FlowGroups;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListDeviceTypes {
+ description
+ "List device types known to Voltha";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses device:DeviceTypes;
+
+ }
+ }
+
+ rpc VolthaGlobalService-GetDeviceType {
+ description
+ "Get additional information on a device type";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses device:DeviceType;
+
+ }
+ }
+
+ rpc VolthaGlobalService-ListDeviceGroups {
+ description
+ "List all device sharding groups";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses DeviceGroups;
+
+ }
+ }
+
+ rpc VolthaGlobalService-GetDeviceGroup {
+ description
+ "Get additional information on a device group";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses DeviceGroup;
+
+ }
+ }
+
+
+ /* Per-instance APIs
+
+ These APIs are always served locally by the Voltha instance on which the
+ call is made." */
+ rpc VolthaLocalService-GetVolthaInstance {
+ description
+ "Get information on this Voltha instance";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses VolthaInstance;
+
+ }
+ }
+
+ rpc VolthaLocalService-GetHealth {
+ description
+ "Get the health state of the Voltha instance";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses health:HealthStatus;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListAdapters {
+ description
+ "List all active adapters (plugins) in this Voltha instance";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses adapter:Adapters;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListLogicalDevices {
+ description
+ "List all logical devices managed by this Voltha instance";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses logical_device:LogicalDevices;
+
+ }
+ }
+
+ rpc VolthaLocalService-GetLogicalDevice {
+ description
+ "Get additional information on given logical device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses logical_device:LogicalDevice;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListLogicalDevicePorts {
+ description
+ "List ports of a logical device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses logical_device:LogicalPorts;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListLogicalDeviceFlows {
+ description
+ "List all flows of a logical device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses openflow_13:Flows;
+
+ }
+ }
+
+ rpc VolthaLocalService-UpdateLogicalDeviceFlowTable {
+ description
+ "Update flow table for logical device";
+ input {
+ uses openflow_13:FlowTableUpdate;
+
+ }
+ output {
+ uses empty:Empty;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListLogicalDeviceFlowGroups {
+ description
+ "List all flow groups of a logical device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses openflow_13:FlowGroups;
+
+ }
+ }
+
+ rpc VolthaLocalService-UpdateLogicalDeviceFlowGroupTable {
+ description
+ "Update group table for logical device";
+ input {
+ uses openflow_13:FlowGroupTableUpdate;
+
+ }
+ output {
+ uses empty:Empty;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListDevices {
+ description
+ "List all physical devices managed by this Voltha instance";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses device:Devices;
+
+ }
+ }
+
+ rpc VolthaLocalService-GetDevice {
+ description
+ "Get additional information on this device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses device:Device;
+
+ }
+ }
+
+ rpc VolthaLocalService-CreateDevice {
+ description
+ "Pre-provision a new physical device";
+ input {
+ uses device:Device;
+
+ }
+ output {
+ uses device:Device;
+
+ }
+ }
+
+ rpc VolthaLocalService-ActivateDevice {
+ description
+ "Activate a pre-provisioned device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses empty:Empty;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListDevicePorts {
+ description
+ "List ports of a device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses device:Ports;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListDeviceFlows {
+ description
+ "List all flows of a device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses openflow_13:Flows;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListDeviceFlowGroups {
+ description
+ "List all flow groups of a device";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses openflow_13:FlowGroups;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListDeviceTypes {
+ description
+ "List device types know to Voltha instance";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses device:DeviceTypes;
+
+ }
+ }
+
+ rpc VolthaLocalService-GetDeviceType {
+ description
+ "Get additional information on given device type";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses device:DeviceType;
+
+ }
+ }
+
+ rpc VolthaLocalService-ListDeviceGroups {
+ description
+ "List device sharding groups managed by this Voltha instance";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses DeviceGroups;
+
+ }
+ }
+
+ rpc VolthaLocalService-GetDeviceGroup {
+ description
+ "Get more information on given device shard";
+ input {
+ uses common:ID;
+
+ }
+ output {
+ uses DeviceGroup;
+
+ }
+ }
+
+ rpc VolthaLocalService-StreamPacketsOut {
+ description
+ "Stream control packets to the dataplane
+This does not have an HTTP representation";
+ input {
+ uses openflow_13:PacketOut;
+
+ }
+ output {
+ uses empty:Empty;
+
+ }
+ }
+
+ rpc VolthaLocalService-ReceivePacketsIn {
+ description
+ "Receive control packet stream
+This does not have an HTTP representation";
+ input {
+ uses empty:Empty;
+
+ }
+ output {
+ uses openflow_13:PacketIn;
+
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/experiments/netconf/proto2yang/logical_device.proto b/experiments/netconf/proto2yang/logical_device.proto
new file mode 100644
index 0000000..94d9588
--- /dev/null
+++ b/experiments/netconf/proto2yang/logical_device.proto
@@ -0,0 +1,52 @@
+syntax = "proto3";
+
+package voltha;
+
+import "meta.proto";
+import "google/api/annotations.proto";
+import "openflow_13.proto";
+
+
+message LogicalPort {
+ string id = 1;
+ openflow_13.ofp_port ofp_port = 2;
+ string device_id = 3;
+ uint32 device_port_no = 4;
+ bool root_port = 5;
+}
+
+message LogicalPorts {
+ repeated LogicalPort items = 1;
+}
+
+message LogicalDevice {
+
+ // unique id of logical device
+ string id = 1;
+
+ // unique datapath id for the logical device (used by the SDN controller)
+ uint64 datapath_id = 2;
+
+ // device description
+ openflow_13.ofp_desc desc = 3;
+
+ // device features
+ openflow_13.ofp_switch_features switch_features = 4;
+
+ // name of the root device anchoring logical device
+ string root_device_id = 5;
+
+ // logical device ports
+ repeated LogicalPort ports = 128 [(child_node) = {key: "id"}];
+
+ // flows configured on the logical device
+ openflow_13.Flows flows = 129 [(child_node) = {}];
+
+ // flow groups configured on the logical device
+ openflow_13.FlowGroups flow_groups = 130 [(child_node) = {}];
+
+}
+
+message LogicalDevices {
+ repeated LogicalDevice items = 1;
+}
diff --git a/experiments/netconf/proto2yang/meta.proto b/experiments/netconf/proto2yang/meta.proto
new file mode 100644
index 0000000..d16668a
--- /dev/null
+++ b/experiments/netconf/proto2yang/meta.proto
@@ -0,0 +1,46 @@
+// Copyright (c) 2015, Google Inc.
+//
+// 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.
+
+// This file contains annotation definitions that can be used to describe
+// a configuration tree.
+
+syntax = "proto3";
+
+package voltha;
+
+import "google/protobuf/descriptor.proto";
+
+message ChildNode {
+ string key = 1;
+}
+
+enum Access {
+ CONFIG = 0; // read-write, stored
+ READ_ONLY = 1; // read-only field
+}
+
+extend google.protobuf.FieldOptions {
+
+ // If present, it indicates that this field is stored as external child node
+ // or children nodes in Voltha's internal configuration tree.
+ // If the field is a container field and if the option specifies a key
+ // the child objects will be addressible by that key.
+ ChildNode child_node = 7761772;
+
+ // This annotation can be used to indicate that a field is read-only,
+ // from the perspective of NBI access. Backend plugins and system
+ // internals can update the field but the update requests through the
+ // NBI will ignore for instance a field that is marked as read-only (RO).
+ Access access = 7761773;
+}
diff --git a/experiments/netconf/proto2yang/openflow_13.proto b/experiments/netconf/proto2yang/openflow_13.proto
new file mode 100644
index 0000000..0e403fd
--- /dev/null
+++ b/experiments/netconf/proto2yang/openflow_13.proto
@@ -0,0 +1,2278 @@
+/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
+ * Junior University
+ * Copyright (c) 2011, 2012 Open Networking Foundation
+ *
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
+ */
+
+/* OpenFlow: protocol between controller and datapath. */
+
+/*
+ * This is a relatively straightforward rendering of OpenFlow message
+ * definitions into protocol buffer messages. We preserved the snake
+ * case syntax, and made the following changes:
+ * - all pad fields dropped
+ * - for each enum value above 0x7fffffff the MSB is dropped. For example,
+ * 0xffffffff is now 0x7fffffff.
+ * - '<type> thing[...]' is replaced with 'repeated <type> thing'
+ * - 'char thing[...]' is replaced with 'string thing'
+ * - 'uint8_t data[...]' is replaced with 'bytes data'
+ * - the following systematic changes are done to various integer types:
+ * uint8_t -> uint32
+ * uint16_t -> uint32
+ * uint32_t -> uint32
+ * uint64_t -> uint64
+ * - removed most length, len, size fields where these values can be determined
+ * from the explicitly encoded length of "repeated" protobuf fields.
+ * - explicit use of enum types whereever it is unambigous (and not used as
+ * bitmask/flags value.
+ *
+ */
+syntax = "proto3";
+
+package openflow_13;
+
+
+/* Version number:
+ * OpenFlow versions released: 0x01 = 1.0 ; 0x02 = 1.1 ; 0x03 = 1.2
+ * 0x04 = 1.3
+ */
+/* The most significant bit in the version field is reserved and must
+ * be set to zero.
+ */
+//#define OFP_VERSION 0x04
+//#define PIPELINE_TABLES 64
+//#define OFP_MAX_TABLE_NAME_LEN 32
+//#define OFP_MAX_PORT_NAME_LEN 16
+/* Official IANA registered port for OpenFlow. */
+//#define OFP_TCP_PORT 6653
+//#define OFP_SSL_PORT 6653
+
+//#define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */
+
+/* Port numbering. Ports are numbered starting from 1. */
+enum ofp_port_no {
+ OFPP_INVALID = 0;
+
+ /* Maximum number of physical and logical switch ports. */
+ OFPP_MAX = 0x7fffff00;
+
+ /* Reserved OpenFlow Port (fake output "ports"). */
+ OFPP_IN_PORT = 0x7ffffff8; /* Send the packet out the input port. This
+ reserved port must be explicitly used
+ in order to send back out of the input
+ port. */
+ OFPP_TABLE = 0x7ffffff9; /* Submit the packet to the first flow table
+ NB: This destination port can only be
+ used in packet-out messages. */
+ OFPP_NORMAL = 0x7ffffffa; /* Forward using non-OpenFlow pipeline. */
+ OFPP_FLOOD = 0x7ffffffb; /* Flood using non-OpenFlow pipeline. */
+ OFPP_ALL = 0x7ffffffc; /* All standard ports except input port. */
+ OFPP_CONTROLLER = 0x7ffffffd; /* Send to controller. */
+ OFPP_LOCAL = 0x7ffffffe; /* Local openflow "port". */
+ OFPP_ANY = 0x7fffffff; /* Special value used in some requests when
+ no port is specified (i.e. wildcarded).*/
+};
+
+enum ofp_type {
+
+ /* Immutable messages. */
+ OFPT_HELLO = 0; /* Symmetric message */
+ OFPT_ERROR = 1; /* Symmetric message */
+ OFPT_ECHO_REQUEST = 2; /* Symmetric message */
+ OFPT_ECHO_REPLY = 3; /* Symmetric message */
+ OFPT_EXPERIMENTER = 4; /* Symmetric message */
+
+ /* Switch configuration messages. */
+ OFPT_FEATURES_REQUEST = 5; /* Controller/switch message */
+ OFPT_FEATURES_REPLY = 6; /* Controller/switch message */
+ OFPT_GET_CONFIG_REQUEST = 7; /* Controller/switch message */
+ OFPT_GET_CONFIG_REPLY = 8; /* Controller/switch message */
+ OFPT_SET_CONFIG = 9; /* Controller/switch message */
+
+ /* Asynchronous messages. */
+ OFPT_PACKET_IN = 10; /* Async message */
+ OFPT_FLOW_REMOVED = 11; /* Async message */
+ OFPT_PORT_STATUS = 12; /* Async message */
+
+ /* Controller command messages. */
+ OFPT_PACKET_OUT = 13; /* Controller/switch message */
+ OFPT_FLOW_MOD = 14; /* Controller/switch message */
+ OFPT_GROUP_MOD = 15; /* Controller/switch message */
+ OFPT_PORT_MOD = 16; /* Controller/switch message */
+ OFPT_TABLE_MOD = 17; /* Controller/switch message */
+
+ /* Multipart messages. */
+ OFPT_MULTIPART_REQUEST = 18; /* Controller/switch message */
+ OFPT_MULTIPART_REPLY = 19; /* Controller/switch message */
+
+ /* Barrier messages. */
+ OFPT_BARRIER_REQUEST = 20; /* Controller/switch message */
+ OFPT_BARRIER_REPLY = 21; /* Controller/switch message */
+
+ /* Queue Configuration messages. */
+ OFPT_QUEUE_GET_CONFIG_REQUEST = 22; /* Controller/switch message */
+ OFPT_QUEUE_GET_CONFIG_REPLY = 23; /* Controller/switch message */
+
+ /* Controller role change request messages. */
+ OFPT_ROLE_REQUEST = 24; /* Controller/switch message */
+ OFPT_ROLE_REPLY = 25; /* Controller/switch message */
+
+ /* Asynchronous message configuration. */
+ OFPT_GET_ASYNC_REQUEST = 26; /* Controller/switch message */
+ OFPT_GET_ASYNC_REPLY = 27; /* Controller/switch message */
+ OFPT_SET_ASYNC = 28; /* Controller/switch message */
+
+ /* Meters and rate limiters configuration messages. */
+ OFPT_METER_MOD = 29; /* Controller/switch message */
+};
+
+/* Header on all OpenFlow packets. */
+message ofp_header {
+ uint32 version = 1; /* OFP_VERSION. */
+ ofp_type type = 2; /* One of the OFPT_ constants. */
+ uint32 xid = 3; /* Transaction id associated with this packet.
+ Replies use the same id as was in the request
+ to facilitate pairing. */
+};
+
+/* Hello elements types.
+ */
+enum ofp_hello_elem_type {
+ OFPHET_INVALID = 0;
+ OFPHET_VERSIONBITMAP = 1; /* Bitmap of version supported. */
+};
+
+/* Common header for all Hello Elements */
+message ofp_hello_elem_header {
+ ofp_hello_elem_type type = 1; /* One of OFPHET_*. */
+ oneof element {
+ ofp_hello_elem_versionbitmap versionbitmap = 2;
+ }
+};
+
+/* Version bitmap Hello Element */
+message ofp_hello_elem_versionbitmap {
+ repeated uint32 bitmaps = 2; /* List of bitmaps - supported versions */
+};
+
+/* OFPT_HELLO. This message includes zero or more hello elements having
+ * variable size. Unknown elements types must be ignored/skipped, to allow
+ * for future extensions. */
+message ofp_hello {
+ //ofp_header header;
+ /* Hello element list */
+ repeated ofp_hello_elem_header elements = 1; /* 0 or more */
+};
+
+//#define OFP_DEFAULT_MISS_SEND_LEN 128
+
+enum ofp_config_flags {
+ /* Handling of IP fragments. */
+ OFPC_FRAG_NORMAL = 0; /* No special handling for fragments. */
+ OFPC_FRAG_DROP = 1; /* Drop fragments. */
+ OFPC_FRAG_REASM = 2; /* Reassemble (only if OFPC_IP_REASM set). */
+ OFPC_FRAG_MASK = 3; /* Bitmask of flags dealing with frag. */
+};
+
+/* Switch configuration. */
+message ofp_switch_config {
+ //ofp_header header;
+ uint32 flags = 1; /* Bitmap of OFPC_* flags. */
+ uint32 miss_send_len = 2; /* Max bytes of packet that datapath
+ should send to the controller. See
+ ofp_controller_max_len for valid values.
+ */
+};
+
+/* Flags to configure the table. Reserved for future use. */
+enum ofp_table_config {
+ OFPTC_INVALID = 0;
+ OFPTC_DEPRECATED_MASK = 3; /* Deprecated bits */
+};
+
+/* Table numbering. Tables can use any number up to OFPT_MAX. */
+enum ofp_table {
+
+ OFPTT_INVALID = 0;
+
+ /* Last usable table number. */
+ OFPTT_MAX = 0xfe;
+
+ /* Fake tables. */
+ OFPTT_ALL = 0xff; /* Wildcard table used for table config,
+ flow stats and flow deletes. */
+};
+
+
+/* Configure/Modify behavior of a flow table */
+message ofp_table_mod {
+ //ofp_header header;
+ uint32 table_id = 1; /* ID of the table, OFPTT_ALL indicates all tables */
+ uint32 config = 2; /* Bitmap of OFPTC_* flags */
+};
+
+/* Capabilities supported by the datapath. */
+enum ofp_capabilities {
+ OFPC_INVALID = 0;
+ OFPC_FLOW_STATS = 1; /* Flow statistics. */
+ OFPC_TABLE_STATS = 2; /* Table statistics. */
+ OFPC_PORT_STATS = 4; /* Port statistics. */
+ OFPC_GROUP_STATS = 8; /* Group statistics. */
+ OFPC_IP_REASM = 32; /* Can reassemble IP fragments. */
+ OFPC_QUEUE_STATS = 64; /* Queue statistics. */
+ OFPC_PORT_BLOCKED = 256; /* Switch will block looping ports. */
+};
+
+/* Flags to indicate behavior of the physical port. These flags are
+ * used in ofp_port to describe the current configuration. They are
+ * used in the ofp_port_mod message to configure the port's behavior.
+ */
+enum ofp_port_config {
+ OFPPC_INVALID = 0;
+ OFPPC_PORT_DOWN = 1; /* Port is administratively down. */
+
+ OFPPC_NO_RECV = 4; /* Drop all packets received by port. */
+ OFPPC_NO_FWD = 32; /* Drop packets forwarded to port. */
+ OFPPC_NO_PACKET_IN = 64; /* Do not send packet-in msgs for port. */
+};
+
+/* Current state of the physical port. These are not configurable from
+ * the controller.
+ */
+enum ofp_port_state {
+ OFPPS_INVALID = 0;
+ OFPPS_LINK_DOWN = 1; /* No physical link present. */
+ OFPPS_BLOCKED = 2; /* Port is blocked */
+ OFPPS_LIVE = 4; /* Live for Fast Failover Group. */
+};
+
+/* Features of ports available in a datapath. */
+enum ofp_port_features {
+ OFPPF_INVALID = 0;
+ OFPPF_10MB_HD = 1; /* 10 Mb half-duplex rate support. */
+ OFPPF_10MB_FD = 2; /* 10 Mb full-duplex rate support. */
+ OFPPF_100MB_HD = 4; /* 100 Mb half-duplex rate support. */
+ OFPPF_100MB_FD = 8; /* 100 Mb full-duplex rate support. */
+ OFPPF_1GB_HD = 16; /* 1 Gb half-duplex rate support. */
+ OFPPF_1GB_FD = 32; /* 1 Gb full-duplex rate support. */
+ OFPPF_10GB_FD = 64; /* 10 Gb full-duplex rate support. */
+ OFPPF_40GB_FD = 128; /* 40 Gb full-duplex rate support. */
+ OFPPF_100GB_FD = 256; /* 100 Gb full-duplex rate support. */
+ OFPPF_1TB_FD = 512; /* 1 Tb full-duplex rate support. */
+ OFPPF_OTHER = 1024; /* Other rate, not in the list. */
+ OFPPF_COPPER = 2048; /* Copper medium. */
+ OFPPF_FIBER = 4096; /* Fiber medium. */
+ OFPPF_AUTONEG = 8192; /* Auto-negotiation. */
+ OFPPF_PAUSE = 16384; /* Pause. */
+ OFPPF_PAUSE_ASYM = 32768; /* Asymmetric pause. */
+};
+
+/* Description of a port */
+message ofp_port {
+ uint32 port_no = 1;
+ repeated uint32 hw_addr = 2; // [OFP_ETH_ALEN];
+ string name = 3; /* Null-terminated */
+
+ uint32 config = 4; /* Bitmap of OFPPC_* flags. */
+ uint32 state = 5; /* Bitmap of OFPPS_* flags. */
+
+ /* Bitmaps of OFPPF_* that describe features. All bits zeroed if
+ * unsupported or unavailable. */
+ uint32 curr = 6; /* Current features. */
+ uint32 advertised = 7; /* Features being advertised by the port. */
+ uint32 supported = 8; /* Features supported by the port. */
+ uint32 peer = 9; /* Features advertised by peer. */
+ uint32 curr_speed = 10; /* Current port bitrate in kbps. */
+ uint32 max_speed = 11; /* Max port bitrate in kbps */
+};
+
+/* Switch features. */
+message ofp_switch_features {
+ //ofp_header header;
+ uint64 datapath_id = 1; /* Datapath unique ID. The lower 48-bits are for
+ a MAC address, while the upper 16-bits are
+ implementer-defined. */
+
+ uint32 n_buffers = 2; /* Max packets buffered at once. */
+
+ uint32 n_tables = 3; /* Number of tables supported by datapath. */
+ uint32 auxiliary_id = 4; /* Identify auxiliary connections */
+
+ /* Features. */
+ uint32 capabilities = 5; /* Bitmap of support "ofp_capabilities". */
+};
+
+/* What changed about the physical port */
+enum ofp_port_reason {
+ OFPPR_ADD = 0; /* The port was added. */
+ OFPPR_DELETE = 1; /* The port was removed. */
+ OFPPR_MODIFY = 2; /* Some attribute of the port has changed. */
+};
+
+/* A physical port has changed in the datapath */
+message ofp_port_status {
+ //ofp_header header;
+ ofp_port_reason reason = 1; /* One of OFPPR_*. */
+ ofp_port desc = 2;
+};
+
+/* Modify behavior of the physical port */
+message ofp_port_mod {
+ //ofp_header header;
+ uint32 port_no = 1;
+ repeated uint32 hw_addr = 2; //[OFP_ETH_ALEN];
+ /* The hardware address is not
+ configurable. This is used to
+ sanity-check the request, so it must
+ be the same as returned in an
+ ofp_port struct. */
+ uint32 config = 3; /* Bitmap of OFPPC_* flags. */
+ uint32 mask = 4; /* Bitmap of OFPPC_* flags to be changed. */
+
+ uint32 advertise = 5; /* Bitmap of OFPPF_*. Zero all bits to prevent
+ any action taking place. */
+};
+
+/* ## -------------------------- ## */
+/* ## OpenFlow Extensible Match. ## */
+/* ## -------------------------- ## */
+
+/* The match type indicates the match structure (set of fields that compose the
+ * match) in use. The match type is placed in the type field at the beginning
+ * of all match structures. The "OpenFlow Extensible Match" type corresponds
+ * to OXM TLV format described below and must be supported by all OpenFlow
+ * switches. Extensions that define other match types may be published on the
+ * ONF wiki. Support for extensions is optional.
+ */
+enum ofp_match_type {
+ OFPMT_STANDARD = 0; /* Deprecated. */
+ OFPMT_OXM = 1; /* OpenFlow Extensible Match */
+};
+
+/* Fields to match against flows */
+message ofp_match {
+ ofp_match_type type = 1; /* One of OFPMT_* */
+ repeated ofp_oxm_field oxm_fields = 2; /* 0 or more */
+};
+
+/* Components of a OXM TLV header.
+ * Those macros are not valid for the experimenter class, macros for the
+ * experimenter class will depend on the experimenter header used. */
+//#define OXM_HEADER__(CLASS, FIELD, HASMASK, LENGTH) \
+// (((CLASS) << 16) | ((FIELD) << 9) | ((HASMASK) << 8) | (LENGTH))
+//#define OXM_HEADER(CLASS, FIELD, LENGTH) \
+// OXM_HEADER__(CLASS, FIELD, 0, LENGTH)
+//#define OXM_HEADER_W(CLASS, FIELD, LENGTH) \
+// OXM_HEADER__(CLASS, FIELD, 1, (LENGTH) * 2)
+//#define OXM_CLASS(HEADER) ((HEADER) >> 16)
+//#define OXM_FIELD(HEADER) (((HEADER) >> 9) & 0x7f)
+//#define OXM_TYPE(HEADER) (((HEADER) >> 9) & 0x7fffff)
+//#define OXM_HASMASK(HEADER) (((HEADER) >> 8) & 1)
+//#define OXM_LENGTH(HEADER) ((HEADER) & 0xff)
+//
+//#define OXM_MAKE_WILD_HEADER(HEADER) \
+// OXM_HEADER_W(OXM_CLASS(HEADER), OXM_FIELD(HEADER), OXM_LENGTH(HEADER))
+
+/* OXM Class IDs.
+ * The high order bit differentiate reserved classes from member classes.
+ * Classes 0x0000 to 0x7FFF are member classes, allocated by ONF.
+ * Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation.
+ */
+enum ofp_oxm_class {
+ OFPXMC_NXM_0 = 0x0000; /* Backward compatibility with NXM */
+ OFPXMC_NXM_1 = 0x0001; /* Backward compatibility with NXM */
+ OFPXMC_OPENFLOW_BASIC = 0x8000; /* Basic class for OpenFlow */
+ OFPXMC_EXPERIMENTER = 0xFFFF; /* Experimenter class */
+};
+
+/* OXM Flow field types for OpenFlow basic class. */
+enum oxm_ofb_field_types {
+ OFPXMT_OFB_IN_PORT = 0; /* Switch input port. */
+ OFPXMT_OFB_IN_PHY_PORT = 1; /* Switch physical input port. */
+ OFPXMT_OFB_METADATA = 2; /* Metadata passed between tables. */
+ OFPXMT_OFB_ETH_DST = 3; /* Ethernet destination address. */
+ OFPXMT_OFB_ETH_SRC = 4; /* Ethernet source address. */
+ OFPXMT_OFB_ETH_TYPE = 5; /* Ethernet frame type. */
+ OFPXMT_OFB_VLAN_VID = 6; /* VLAN id. */
+ OFPXMT_OFB_VLAN_PCP = 7; /* VLAN priority. */
+ OFPXMT_OFB_IP_DSCP = 8; /* IP DSCP (6 bits in ToS field). */
+ OFPXMT_OFB_IP_ECN = 9; /* IP ECN (2 bits in ToS field). */
+ OFPXMT_OFB_IP_PROTO = 10; /* IP protocol. */
+ OFPXMT_OFB_IPV4_SRC = 11; /* IPv4 source address. */
+ OFPXMT_OFB_IPV4_DST = 12; /* IPv4 destination address. */
+ OFPXMT_OFB_TCP_SRC = 13; /* TCP source port. */
+ OFPXMT_OFB_TCP_DST = 14; /* TCP destination port. */
+ OFPXMT_OFB_UDP_SRC = 15; /* UDP source port. */
+ OFPXMT_OFB_UDP_DST = 16; /* UDP destination port. */
+ OFPXMT_OFB_SCTP_SRC = 17; /* SCTP source port. */
+ OFPXMT_OFB_SCTP_DST = 18; /* SCTP destination port. */
+ OFPXMT_OFB_ICMPV4_TYPE = 19; /* ICMP type. */
+ OFPXMT_OFB_ICMPV4_CODE = 20; /* ICMP code. */
+ OFPXMT_OFB_ARP_OP = 21; /* ARP opcode. */
+ OFPXMT_OFB_ARP_SPA = 22; /* ARP source IPv4 address. */
+ OFPXMT_OFB_ARP_TPA = 23; /* ARP target IPv4 address. */
+ OFPXMT_OFB_ARP_SHA = 24; /* ARP source hardware address. */
+ OFPXMT_OFB_ARP_THA = 25; /* ARP target hardware address. */
+ OFPXMT_OFB_IPV6_SRC = 26; /* IPv6 source address. */
+ OFPXMT_OFB_IPV6_DST = 27; /* IPv6 destination address. */
+ OFPXMT_OFB_IPV6_FLABEL = 28; /* IPv6 Flow Label */
+ OFPXMT_OFB_ICMPV6_TYPE = 29; /* ICMPv6 type. */
+ OFPXMT_OFB_ICMPV6_CODE = 30; /* ICMPv6 code. */
+ OFPXMT_OFB_IPV6_ND_TARGET = 31; /* Target address for ND. */
+ OFPXMT_OFB_IPV6_ND_SLL = 32; /* Source link-layer for ND. */
+ OFPXMT_OFB_IPV6_ND_TLL = 33; /* Target link-layer for ND. */
+ OFPXMT_OFB_MPLS_LABEL = 34; /* MPLS label. */
+ OFPXMT_OFB_MPLS_TC = 35; /* MPLS TC. */
+ OFPXMT_OFB_MPLS_BOS = 36; /* MPLS BoS bit. */
+ OFPXMT_OFB_PBB_ISID = 37; /* PBB I-SID. */
+ OFPXMT_OFB_TUNNEL_ID = 38; /* Logical Port Metadata. */
+ OFPXMT_OFB_IPV6_EXTHDR = 39; /* IPv6 Extension Header pseudo-field */
+};
+
+/* OXM Flow match fields */
+message ofp_oxm_field {
+ ofp_oxm_class oxm_class = 1;
+ oneof field {
+ /* 2 and 3 reserved for NXM_0 and NXM-1 OXM classes */
+ ofp_oxm_ofb_field ofb_field = 4;
+ ofp_oxm_experimenter_field experimenter_field = 5;
+ }
+}
+
+/* OXM OpenFlow Basic Match Field */
+message ofp_oxm_ofb_field {
+ oxm_ofb_field_types type = 1;
+ bool has_mask = 2;
+ oneof value {
+
+ /* OpenFlow port on which the packet was received.
+ * May be a physical port, a logical port, or the reserved port OFPP_LOCAL
+ *
+ * Prereqs: None.
+ *
+ * Format: 32-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IN_PORT OXM_HEADER (0x8000, OFPXMT_OFB_IN_PORT, 4)
+ uint32 port = 3; /* Used for OFPXMT_OFB_IN_PORT */
+
+ /* Physical port on which the packet was received.
+ *
+ * Consider a packet received on a tunnel interface defined over a link
+ * aggregation group (LAG) with two physical port members. If the tunnel
+ * interface is the logical port bound to OpenFlow. In this case,
+ * OFPXMT_OF_IN_PORT is the tunnel's port number and OFPXMT_OF_IN_PHY_PORT is
+ * the physical port number of the LAG on which the tunnel is configured.
+ *
+ * When a packet is received directly on a physical port and not processed by a
+ * logical port, OFPXMT_OF_IN_PORT and OFPXMT_OF_IN_PHY_PORT have the same
+ * value.
+ *
+ * This field is usually not available in a regular match and only available
+ * in ofp_packet_in messages when it's different from OXM_OF_IN_PORT.
+ *
+ * Prereqs: OXM_OF_IN_PORT must be present.
+ *
+ * Format: 32-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IN_PHY_PORT OXM_HEADER (0x8000, OFPXMT_OFB_IN_PHY_PORT, 4)
+ uint32 physical_port = 4; /* Used for OFPXMT_OF_IN_PHY_PORT */
+
+ /* Table metadata.
+ *
+ * Prereqs: None.
+ *
+ * Format: 64-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks.
+ */
+ //#define OXM_OF_METADATA OXM_HEADER (0x8000, OFPXMT_OFB_METADATA, 8)
+ //#define OXM_OF_METADATA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_METADATA, 8)
+ uint64 table_metadata = 5; /* Used for OFPXMT_OFB_METADATA */
+
+ /* Source or destination address in Ethernet header.
+ *
+ * Prereqs: None.
+ *
+ * Format: 48-bit Ethernet MAC address.
+ *
+ * Masking: Arbitrary masks. */
+ //#define OXM_OF_ETH_DST OXM_HEADER (0x8000, OFPXMT_OFB_ETH_DST, 6)
+ //#define OXM_OF_ETH_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ETH_DST, 6)
+ //#define OXM_OF_ETH_SRC OXM_HEADER (0x8000, OFPXMT_OFB_ETH_SRC, 6)
+ //#define OXM_OF_ETH_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ETH_SRC, 6)
+ bytes eth_dst = 6; /* Used for OFPXMT_OFB_ETH_DST (exactly 6 bytes) */
+ bytes eth_src = 7; /* Used for OFPXMT_OFB_ETH_SRC (exactly 6 bytes) */
+
+ /* Packet's Ethernet type.
+ *
+ * Prereqs: None.
+ *
+ * Format: 16-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_ETH_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ETH_TYPE,2)
+ uint32 eth_type = 8; /* Used for OFPXMT_OFB_ETH_TYPE */
+
+ /* 802.1Q VID.
+ *
+ * For a packet with an 802.1Q header, this is the VLAN-ID (VID) from the
+ * outermost tag, with the CFI bit forced to 1. For a packet with no 802.1Q
+ * header, this has value OFPVID_NONE.
+ *
+ * Prereqs: None.
+ *
+ * Format: 16-bit integer in network byte order with bit 13 indicating
+ * presence of VLAN header and 3 most-significant bits forced to 0.
+ * Only the lower 13 bits have meaning.
+ *
+ * Masking: Arbitrary masks.
+ *
+ * This field can be used in various ways:
+ *
+ * - If it is not constrained at all, the nx_match matches packets without
+ * an 802.1Q header or with an 802.1Q header that has any VID value.
+ *
+ * - Testing for an exact match with 0x0 matches only packets without
+ * an 802.1Q header.
+ *
+ * - Testing for an exact match with a VID value with CFI=1 matches packets
+ * that have an 802.1Q header with a specified VID.
+ *
+ * - Testing for an exact match with a nonzero VID value with CFI=0 does
+ * not make sense. The switch may reject this combination.
+ *
+ * - Testing with nxm_value=0, nxm_mask=0x0fff matches packets with no 802.1Q
+ * header or with an 802.1Q header with a VID of 0.
+ *
+ * - Testing with nxm_value=0x1000, nxm_mask=0x1000 matches packets with
+ * an 802.1Q header that has any VID value.
+ */
+ //#define OXM_OF_VLAN_VID OXM_HEADER (0x8000, OFPXMT_OFB_VLAN_VID, 2)
+ //#define OXM_OF_VLAN_VID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_VLAN_VID, 2)
+ uint32 vlan_vid = 9; /* Used for OFPXMT_OFB_VLAN_VID */
+
+ /* 802.1Q PCP.
+ *
+ * For a packet with an 802.1Q header, this is the VLAN-PCP from the
+ * outermost tag. For a packet with no 802.1Q header, this has value
+ * 0.
+ *
+ * Prereqs: OXM_OF_VLAN_VID must be different from OFPVID_NONE.
+ *
+ * Format: 8-bit integer with 5 most-significant bits forced to 0.
+ * Only the lower 3 bits have meaning.
+ *
+ * Masking: Not maskable.
+ */
+ //#define OXM_OF_VLAN_PCP OXM_HEADER (0x8000, OFPXMT_OFB_VLAN_PCP, 1)
+ uint32 vlan_pcp = 10; /* Used for OFPXMT_OFB_VLAN_PCP */
+
+ /* The Diff Serv Code Point (DSCP) bits of the IP header.
+ * Part of the IPv4 ToS field or the IPv6 Traffic Class field.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+ *
+ * Format: 8-bit integer with 2 most-significant bits forced to 0.
+ * Only the lower 6 bits have meaning.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IP_DSCP OXM_HEADER (0x8000, OFPXMT_OFB_IP_DSCP, 1)
+ uint32 ip_dscp = 11; /* Used for OFPXMT_OFB_IP_DSCP */
+
+ /* The ECN bits of the IP header.
+ * Part of the IPv4 ToS field or the IPv6 Traffic Class field.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+ *
+ * Format: 8-bit integer with 6 most-significant bits forced to 0.
+ * Only the lower 2 bits have meaning.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IP_ECN OXM_HEADER (0x8000, OFPXMT_OFB_IP_ECN, 1)
+ uint32 ip_ecn = 12; /* Used for OFPXMT_OFB_IP_ECN */
+
+ /* The "protocol" byte in the IP header.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+ *
+ * Format: 8-bit integer.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IP_PROTO OXM_HEADER (0x8000, OFPXMT_OFB_IP_PROTO, 1)
+ uint32 ip_proto = 13; /* Used for OFPXMT_OFB_IP_PROTO */
+
+ /* The source or destination address in the IP header.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must match 0x0800 exactly.
+ *
+ * Format: 32-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks.
+ */
+ //#define OXM_OF_IPV4_SRC OXM_HEADER (0x8000, OFPXMT_OFB_IPV4_SRC, 4)
+ //#define OXM_OF_IPV4_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV4_SRC, 4)
+ //#define OXM_OF_IPV4_DST OXM_HEADER (0x8000, OFPXMT_OFB_IPV4_DST, 4)
+ //#define OXM_OF_IPV4_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV4_DST, 4)
+ uint32 ipv4_src = 14; /* Used for OFPXMT_OFB_IPV4_SRC */
+ uint32 ipv4_dst = 15; /* Used for OFPXMT_OFB_IPV4_DST */
+
+ /* The source or destination port in the TCP header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+ * OXM_OF_IP_PROTO must match 6 exactly.
+ *
+ * Format: 16-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_TCP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_TCP_SRC, 2)
+ //#define OXM_OF_TCP_DST OXM_HEADER (0x8000, OFPXMT_OFB_TCP_DST, 2)
+ uint32 tcp_src = 16; /* Used for OFPXMT_OFB_TCP_SRC */
+ uint32 tcp_dst = 17; /* Used for OFPXMT_OFB_TCP_DST */
+
+ /* The source or destination port in the UDP header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd.
+ * OXM_OF_IP_PROTO must match 17 exactly.
+ *
+ * Format: 16-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_UDP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_UDP_SRC, 2)
+ //#define OXM_OF_UDP_DST OXM_HEADER (0x8000, OFPXMT_OFB_UDP_DST, 2)
+ uint32 udp_src = 18; /* Used for OFPXMT_OFB_UDP_SRC */
+ uint32 udp_dst = 19; /* Used for OFPXMT_OFB_UDP_DST */
+
+ /* The source or destination port in the SCTP header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd.
+ * OXM_OF_IP_PROTO must match 132 exactly.
+ *
+ * Format: 16-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_SCTP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_SCTP_SRC, 2)
+ //#define OXM_OF_SCTP_DST OXM_HEADER (0x8000, OFPXMT_OFB_SCTP_DST, 2)
+ uint32 sctp_src = 20; /* Used for OFPXMT_OFB_SCTP_SRC */
+ uint32 sctp_dst = 21; /* Used for OFPXMT_OFB_SCTP_DST */
+
+ /* The type or code in the ICMP header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x0800 exactly.
+ * OXM_OF_IP_PROTO must match 1 exactly.
+ *
+ * Format: 8-bit integer.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_ICMPV4_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV4_TYPE, 1)
+ //#define OXM_OF_ICMPV4_CODE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV4_CODE, 1)
+ uint32 icmpv4_type = 22; /* Used for OFPXMT_OFB_ICMPV4_TYPE */
+ uint32 icmpv4_code = 23; /* Used for OFPXMT_OFB_ICMPV4_CODE */
+
+ /* ARP opcode.
+ *
+ * For an Ethernet+IP ARP packet, the opcode in the ARP header. Always 0
+ * otherwise.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly.
+ *
+ * Format: 16-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_ARP_OP OXM_HEADER (0x8000, OFPXMT_OFB_ARP_OP, 2)
+ uint32 arp_op = 24; /* Used for OFPXMT_OFB_ARP_OP */
+
+ /* For an Ethernet+IP ARP packet, the source or target protocol address
+ * in the ARP header. Always 0 otherwise.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly.
+ *
+ * Format: 32-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks.
+ */
+ //#define OXM_OF_ARP_SPA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_SPA, 4)
+ //#define OXM_OF_ARP_SPA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ARP_SPA, 4)
+ //#define OXM_OF_ARP_TPA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_TPA, 4)
+ //#define OXM_OF_ARP_TPA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ARP_TPA, 4)
+ uint32 arp_spa = 25; /* For OFPXMT_OFB_ARP_SPA */
+ uint32 arp_tpa = 26; /* For OFPXMT_OFB_ARP_TPA */
+
+ /* For an Ethernet+IP ARP packet, the source or target hardware address
+ * in the ARP header. Always 0 otherwise.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly.
+ *
+ * Format: 48-bit Ethernet MAC address.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_ARP_SHA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_SHA, 6)
+ //#define OXM_OF_ARP_SHA_W OXM_HEADER_W (0x8000, OFPXMT_OFB_ARP_SHA, 6)
+ //#define OXM_OF_ARP_THA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_THA, 6)
+ //#define OXM_OF_ARP_THA_W OXM_HEADER_W (0x8000, OFPXMT_OFB_ARP_THA, 6)
+ bytes arp_sha = 27; /* For OFPXMT_OFB_ARP_SHA (6 bytes) */
+ bytes arp_tha = 28; /* For OFPXMT_OFB_ARP_THA (6 bytes) */
+
+ /* The source or destination address in the IPv6 header.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ *
+ * Format: 128-bit IPv6 address.
+ *
+ * Masking: Arbitrary masks.
+ */
+ //#define OXM_OF_IPV6_SRC OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_SRC, 16)
+ //#define OXM_OF_IPV6_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_SRC, 16)
+ //#define OXM_OF_IPV6_DST OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_DST, 16)
+ //#define OXM_OF_IPV6_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_DST, 16)
+ bytes ipv6_src = 29; /* For OFPXMT_OFB_IPV6_SRC */
+ bytes ipv6_dst = 30; /* For OFPXMT_OFB_IPV6_DST */
+
+ /* The IPv6 Flow Label
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly
+ *
+ * Format: 32-bit integer with 12 most-significant bits forced to 0.
+ * Only the lower 20 bits have meaning.
+ *
+ * Masking: Arbitrary masks.
+ */
+ //#define OXM_OF_IPV6_FLABEL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_FLABEL, 4)
+ //#define OXM_OF_IPV6_FLABEL_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_FLABEL, 4)
+ uint32 ipv6_flabel = 31; /* For OFPXMT_OFB_IPV6_FLABEL */
+
+ /* The type or code in the ICMPv6 header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ * OXM_OF_IP_PROTO must match 58 exactly.
+ *
+ * Format: 8-bit integer.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_ICMPV6_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV6_TYPE, 1)
+ //#define OXM_OF_ICMPV6_CODE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV6_CODE, 1)
+ uint32 icmpv6_type = 32; /* For OFPXMT_OFB_ICMPV6_TYPE */
+ uint32 icmpv6_code = 33; /* For OFPXMT_OFB_ICMPV6_CODE */
+
+ /* The target address in an IPv6 Neighbor Discovery message.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ * OXM_OF_IP_PROTO must match 58 exactly.
+ * OXM_OF_ICMPV6_TYPE must be either 135 or 136.
+ *
+ * Format: 128-bit IPv6 address.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IPV6_ND_TARGET OXM_HEADER \
+ // (0x8000, OFPXMT_OFB_IPV6_ND_TARGET, 16)
+ bytes ipv6_nd_target = 34; /* For OFPXMT_OFB_IPV6_ND_TARGET */
+
+ /* The source link-layer address option in an IPv6 Neighbor Discovery
+ * message.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ * OXM_OF_IP_PROTO must match 58 exactly.
+ * OXM_OF_ICMPV6_TYPE must be exactly 135.
+ *
+ * Format: 48-bit Ethernet MAC address.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IPV6_ND_SLL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_SLL, 6)
+ bytes ipv6_nd_ssl = 35; /* For OFPXMT_OFB_IPV6_ND_SLL */
+
+ /* The target link-layer address option in an IPv6 Neighbor Discovery
+ * message.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ * OXM_OF_IP_PROTO must match 58 exactly.
+ * OXM_OF_ICMPV6_TYPE must be exactly 136.
+ *
+ * Format: 48-bit Ethernet MAC address.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IPV6_ND_TLL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_TLL, 6)
+ bytes ipv6_nd_tll = 36; /* For OFPXMT_OFB_IPV6_ND_TLL */
+
+ /* The LABEL in the first MPLS shim header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly.
+ *
+ * Format: 32-bit integer in network byte order with 12 most-significant
+ * bits forced to 0. Only the lower 20 bits have meaning.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_MPLS_LABEL OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_LABEL, 4)
+ uint32 mpls_label = 37; /* For OFPXMT_OFB_MPLS_LABEL */
+
+ /* The TC in the first MPLS shim header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly.
+ *
+ * Format: 8-bit integer with 5 most-significant bits forced to 0.
+ * Only the lower 3 bits have meaning.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_MPLS_TC OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_TC, 1)
+ uint32 mpls_tc = 38; /* For OFPXMT_OFB_MPLS_TC */
+
+ /* The BoS bit in the first MPLS shim header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly.
+ *
+ * Format: 8-bit integer with 7 most-significant bits forced to 0.
+ * Only the lowest bit have a meaning.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_MPLS_BOS OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_BOS, 1)
+ uint32 mpls_bos = 39; /* For OFPXMT_OFB_MPLS_BOS */
+
+ /* IEEE 802.1ah I-SID.
+ *
+ * For a packet with a PBB header, this is the I-SID from the
+ * outermost service tag.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x88E7 exactly.
+ *
+ * Format: 24-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks. */
+ //#define OXM_OF_PBB_ISID OXM_HEADER (0x8000, OFPXMT_OFB_PBB_ISID, 3)
+ //#define OXM_OF_PBB_ISID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_PBB_ISID, 3)
+ uint32 pbb_isid = 40; /* For OFPXMT_OFB_PBB_ISID */
+
+ /* Logical Port Metadata.
+ *
+ * Metadata associated with a logical port.
+ * If the logical port performs encapsulation and decapsulation, this
+ * is the demultiplexing field from the encapsulation header.
+ * For example, for a packet received via GRE tunnel including a (32-bit) key,
+ * the key is stored in the low 32-bits and the high bits are zeroed.
+ * For a MPLS logical port, the low 20 bits represent the MPLS Label.
+ * For a VxLAN logical port, the low 24 bits represent the VNI.
+ * If the packet is not received through a logical port, the value is 0.
+ *
+ * Prereqs: None.
+ *
+ * Format: 64-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks. */
+ //#define OXM_OF_TUNNEL_ID OXM_HEADER (0x8000, OFPXMT_OFB_TUNNEL_ID, 8)
+ //#define OXM_OF_TUNNEL_ID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_TUNNEL_ID, 8)
+ uint64 tunnel_id = 41; /* For OFPXMT_OFB_TUNNEL_ID */
+
+ /* The IPv6 Extension Header pseudo-field.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly
+ *
+ * Format: 16-bit integer with 7 most-significant bits forced to 0.
+ * Only the lower 9 bits have meaning.
+ *
+ * Masking: Maskable. */
+ //#define OXM_OF_IPV6_EXTHDR OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_EXTHDR, 2)
+ //#define OXM_OF_IPV6_EXTHDR_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_EXTHDR, 2)
+ uint32 ipv6_exthdr = 42; /* For OFPXMT_OFB_IPV6_EXTHDR */
+
+ }
+
+ /* Optional mask values (must be present when has_mask is true */
+ oneof mask {
+ uint64 table_metadata_mask = 105; /* For OFPXMT_OFB_METADATA */
+
+ bytes eth_dst_mask = 106; /* For OFPXMT_OFB_ETH_DST (exactly 6 bytes)*/
+ bytes eth_src_mask = 107; /* For OFPXMT_OFB_ETH_SRC (exactly 6 bytes)*/
+
+ uint32 vlan_vid_mask = 109; /* For OFPXMT_OFB_VLAN_VID */
+
+ uint32 ipv4_src_mask = 114; /* For OFPXMT_OFB_IPV4_SRC */
+ uint32 ipv4_dst_mask = 115; /* For OFPXMT_OFB_IPV4_DST */
+
+ uint32 arp_spa_mask = 125; /* For OFPXMT_OFB_ARP_SPA */
+ uint32 arp_tpa_mask = 126; /* For OFPXMT_OFB_ARP_TPA */
+
+ bytes ipv6_src_mask = 129; /* For OFPXMT_OFB_IPV6_SRC */
+ bytes ipv6_dst_mask = 130; /* For OFPXMT_OFB_IPV6_DST */
+
+ uint32 ipv6_flabel_mask = 131; /* For OFPXMT_OFB_IPV6_FLABEL */
+
+ uint32 pbb_isid_mask = 140; /* For OFPXMT_OFB_PBB_ISID */
+
+ uint64 tunnel_id_mask = 141; /* For OFPXMT_OFB_TUNNEL_ID */
+
+ uint32 ipv6_exthdr_mask = 142; /* For OFPXMT_OFB_IPV6_EXTHDR */
+ }
+
+}
+//#define OFPXMT_OFB_ALL ((UINT64_C(1) << 40) - 1)
+
+
+/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate
+ * special conditions.
+ */
+enum ofp_vlan_id {
+ OFPVID_NONE = 0x0000; /* No VLAN id was set. */
+ OFPVID_PRESENT = 0x1000; /* Bit that indicate that a VLAN id is set */
+};
+/* Define for compatibility */
+//#define OFP_VLAN_NONE OFPVID_NONE
+
+/* Bit definitions for IPv6 Extension Header pseudo-field. */
+enum ofp_ipv6exthdr_flags {
+ OFPIEH_INVALID = 0;
+ OFPIEH_NONEXT = 1; /* "No next header" encountered. */
+ OFPIEH_ESP = 2; /* Encrypted Sec Payload header present. */
+ OFPIEH_AUTH = 4; /* Authentication header present. */
+ OFPIEH_DEST = 8; /* 1 or 2 dest headers present. */
+ OFPIEH_FRAG = 16; /* Fragment header present. */
+ OFPIEH_ROUTER = 32; /* Router header present. */
+ OFPIEH_HOP = 64; /* Hop-by-hop header present. */
+ OFPIEH_UNREP = 128; /* Unexpected repeats encountered. */
+ OFPIEH_UNSEQ = 256; /* Unexpected sequencing encountered. */
+};
+
+/* Header for OXM experimenter match fields.
+ * The experimenter class should not use OXM_HEADER() macros for defining
+ * fields due to this extra header. */
+message ofp_oxm_experimenter_field {
+ uint32 oxm_header = 1; /* oxm_class = OFPXMC_EXPERIMENTER */
+ uint32 experimenter = 2; /* Experimenter ID which takes the same
+ form as in struct ofp_experimenter_header. */
+};
+
+/* ## ----------------- ## */
+/* ## OpenFlow Actions. ## */
+/* ## ----------------- ## */
+
+enum ofp_action_type {
+ OFPAT_OUTPUT = 0; /* Output to switch port. */
+ OFPAT_COPY_TTL_OUT = 11; /* Copy TTL "outwards" -- from next-to-outermost
+ to outermost */
+ OFPAT_COPY_TTL_IN = 12; /* Copy TTL "inwards" -- from outermost to
+ next-to-outermost */
+ OFPAT_SET_MPLS_TTL = 15; /* MPLS TTL */
+ OFPAT_DEC_MPLS_TTL = 16; /* Decrement MPLS TTL */
+
+ OFPAT_PUSH_VLAN = 17; /* Push a new VLAN tag */
+ OFPAT_POP_VLAN = 18; /* Pop the outer VLAN tag */
+ OFPAT_PUSH_MPLS = 19; /* Push a new MPLS tag */
+ OFPAT_POP_MPLS = 20; /* Pop the outer MPLS tag */
+ OFPAT_SET_QUEUE = 21; /* Set queue id when outputting to a port */
+ OFPAT_GROUP = 22; /* Apply group. */
+ OFPAT_SET_NW_TTL = 23; /* IP TTL. */
+ OFPAT_DEC_NW_TTL = 24; /* Decrement IP TTL. */
+ OFPAT_SET_FIELD = 25; /* Set a header field using OXM TLV format. */
+ OFPAT_PUSH_PBB = 26; /* Push a new PBB service tag (I-TAG) */
+ OFPAT_POP_PBB = 27; /* Pop the outer PBB service tag (I-TAG) */
+ OFPAT_EXPERIMENTER = 0xffff;
+};
+
+/* Action header that is common to all actions. The length includes the
+ * header and any padding used to make the action 64-bit aligned.
+ * NB: The length of an action *must* always be a multiple of eight. */
+message ofp_action {
+ ofp_action_type type = 1; /* One of OFPAT_*. */
+ oneof action {
+ ofp_action_output output = 2;
+ ofp_action_mpls_ttl mpls_ttl = 3;
+ ofp_action_push push = 4;
+ ofp_action_pop_mpls pop_mpls = 5;
+ ofp_action_group group = 6;
+ ofp_action_nw_ttl nw_ttl = 7;
+ ofp_action_set_field set_field = 8;
+ ofp_action_experimenter experimenter = 9;
+ }
+};
+
+enum ofp_controller_max_len {
+ OFPCML_INVALID = 0;
+ OFPCML_MAX = 0xffe5; /* maximum max_len value which can be used
+ to request a specific byte length. */
+ OFPCML_NO_BUFFER = 0xffff; /* indicates that no buffering should be
+ applied and the whole packet is to be
+ sent to the controller. */
+};
+
+/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
+ * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
+ * number of bytes to send. A 'max_len' of zero means no bytes of the
+ * packet should be sent. A 'max_len' of OFPCML_NO_BUFFER means that
+ * the packet is not buffered and the complete packet is to be sent to
+ * the controller. */
+message ofp_action_output {
+ uint32 port = 1; /* Output port. */
+ uint32 max_len = 2; /* Max length to send to controller. */
+};
+
+/* Action structure for OFPAT_SET_MPLS_TTL. */
+message ofp_action_mpls_ttl {
+ uint32 mpls_ttl = 1; /* MPLS TTL */
+};
+
+/* Action structure for OFPAT_PUSH_VLAN/MPLS/PBB. */
+message ofp_action_push {
+ uint32 ethertype = 1; /* Ethertype */
+};
+
+/* Action structure for OFPAT_POP_MPLS. */
+message ofp_action_pop_mpls {
+ uint32 ethertype = 1; /* Ethertype */
+};
+
+/* Action structure for OFPAT_GROUP. */
+message ofp_action_group {
+ uint32 group_id = 1; /* Group identifier. */
+};
+
+/* Action structure for OFPAT_SET_NW_TTL. */
+message ofp_action_nw_ttl {
+ uint32 nw_ttl = 1; /* IP TTL */
+};
+
+/* Action structure for OFPAT_SET_FIELD. */
+message ofp_action_set_field {
+ ofp_oxm_field field = 1;
+};
+
+/* Action header for OFPAT_EXPERIMENTER.
+ * The rest of the body is experimenter-defined. */
+message ofp_action_experimenter {
+ uint32 experimenter = 1; /* Experimenter ID which takes the same
+ form as in struct
+ ofp_experimenter_header. */
+ bytes data = 2;
+};
+
+/* ## ---------------------- ## */
+/* ## OpenFlow Instructions. ## */
+/* ## ---------------------- ## */
+
+enum ofp_instruction_type {
+ OFPIT_INVALID = 0;
+ OFPIT_GOTO_TABLE = 1; /* Setup the next table in the lookup
+ pipeline */
+ OFPIT_WRITE_METADATA = 2; /* Setup the metadata field for use later in
+ pipeline */
+ OFPIT_WRITE_ACTIONS = 3; /* Write the action(s) onto the datapath action
+ set */
+ OFPIT_APPLY_ACTIONS = 4; /* Applies the action(s) immediately */
+ OFPIT_CLEAR_ACTIONS = 5; /* Clears all actions from the datapath
+ action set */
+ OFPIT_METER = 6; /* Apply meter (rate limiter) */
+
+ OFPIT_EXPERIMENTER = 0xFFFF; /* Experimenter instruction */
+};
+
+/* Instruction header that is common to all instructions. The length includes
+ * the header and any padding used to make the instruction 64-bit aligned.
+ * NB: The length of an instruction *must* always be a multiple of eight. */
+message ofp_instruction {
+ uint32 type = 1; /* Instruction type */
+ oneof data {
+ ofp_instruction_goto_table goto_table = 2;
+ ofp_instruction_write_metadata write_metadata = 3;
+ ofp_instruction_actions actions = 4;
+ ofp_instruction_meter meter = 5;
+ ofp_instruction_experimenter experimenter = 6;
+ }
+};
+
+/* Instruction structure for OFPIT_GOTO_TABLE */
+message ofp_instruction_goto_table {
+ uint32 table_id = 1; /* Set next table in the lookup pipeline */
+};
+
+/* Instruction structure for OFPIT_WRITE_METADATA */
+message ofp_instruction_write_metadata {
+ uint64 metadata = 1; /* Metadata value to write */
+ uint64 metadata_mask = 2; /* Metadata write bitmask */
+};
+
+/* Instruction structure for OFPIT_WRITE/APPLY/CLEAR_ACTIONS */
+message ofp_instruction_actions {
+ repeated ofp_action actions = 1; /* 0 or more actions associated
+ with OFPIT_WRITE_ACTIONS and
+ OFPIT_APPLY_ACTIONS */
+};
+
+/* Instruction structure for OFPIT_METER */
+message ofp_instruction_meter {
+ uint32 meter_id = 1; /* Meter instance. */
+};
+
+/* Instruction structure for experimental instructions */
+message ofp_instruction_experimenter {
+ uint32 experimenter = 1; /* Experimenter ID which takes the same form
+ as in struct ofp_experimenter_header. */
+ /* Experimenter-defined arbitrary additional data. */
+ bytes data = 2;
+};
+
+/* ## --------------------------- ## */
+/* ## OpenFlow Flow Modification. ## */
+/* ## --------------------------- ## */
+
+enum ofp_flow_mod_command {
+ OFPFC_ADD = 0; /* New flow. */
+ OFPFC_MODIFY = 1; /* Modify all matching flows. */
+ OFPFC_MODIFY_STRICT = 2; /* Modify entry strictly matching wildcards and
+ priority. */
+ OFPFC_DELETE = 3; /* Delete all matching flows. */
+ OFPFC_DELETE_STRICT = 4; /* Delete entry strictly matching wildcards and
+ priority. */
+};
+
+/* Value used in "idle_timeout" and "hard_timeout" to indicate that the entry
+ * is permanent. */
+//#define OFP_FLOW_PERMANENT 0
+
+/* By default, choose a priority in the middle. */
+//#define OFP_DEFAULT_PRIORITY 0x8000
+
+enum ofp_flow_mod_flags {
+ OFPFF_INVALID = 0;
+ OFPFF_SEND_FLOW_REM = 1; /* Send flow removed message when flow
+ * expires or is deleted. */
+ OFPFF_CHECK_OVERLAP = 2; /* Check for overlapping entries first. */
+ OFPFF_RESET_COUNTS = 4; /* Reset flow packet and byte counts. */
+ OFPFF_NO_PKT_COUNTS = 8; /* Don't keep track of packet count. */
+ OFPFF_NO_BYT_COUNTS = 16; /* Don't keep track of byte count. */
+};
+
+/* Flow setup and teardown (controller -> datapath). */
+message ofp_flow_mod {
+ //ofp_header header;
+ uint64 cookie = 1; /* Opaque controller-issued identifier. */
+ uint64 cookie_mask = 2; /* Mask used to restrict the cookie bits
+ that must match when the command is
+ OFPFC_MODIFY* or OFPFC_DELETE*. A value
+ of 0 indicates no restriction. */
+ uint32 table_id = 3; /* ID of the table to put the flow in.
+ For OFPFC_DELETE_* commands, OFPTT_ALL
+ can also be used to delete matching
+ flows from all tables. */
+ ofp_flow_mod_command command = 4; /* One of OFPFC_*. */
+ uint32 idle_timeout = 5; /* Idle time before discarding (seconds). */
+ uint32 hard_timeout = 6; /* Max time before discarding (seconds). */
+ uint32 priority = 7; /* Priority level of flow entry. */
+ uint32 buffer_id = 8; /* Buffered packet to apply to, or
+ OFP_NO_BUFFER.
+ Not meaningful for OFPFC_DELETE*. */
+ uint32 out_port = 9; /* For OFPFC_DELETE* commands, require
+ matching entries to include this as an
+ output port. A value of OFPP_ANY
+ indicates no restriction. */
+ uint32 out_group = 10; /* For OFPFC_DELETE* commands, require
+ matching entries to include this as an
+ output group. A value of OFPG_ANY
+ indicates no restriction. */
+ uint32 flags = 11; /* Bitmap of OFPFF_* flags. */
+ ofp_match match = 12; /* Fields to match. Variable size. */
+ repeated ofp_instruction instructions = 13; /* 0 or more. */
+};
+
+/* Group numbering. Groups can use any number up to OFPG_MAX. */
+enum ofp_group {
+
+ OFPG_INVALID = 0;
+
+ /* Last usable group number. */
+ OFPG_MAX = 0x7fffff00;
+
+ /* Fake groups. */
+ OFPG_ALL = 0x7ffffffc; /* Represents all groups for group delete
+ commands. */
+ OFPG_ANY = 0x7fffffff; /* Special wildcard: no group specified. */
+};
+
+/* Group commands */
+enum ofp_group_mod_command {
+ OFPGC_ADD = 0; /* New group. */
+ OFPGC_MODIFY = 1; /* Modify all matching groups. */
+ OFPGC_DELETE = 2; /* Delete all matching groups. */
+};
+
+/* Bucket for use in groups. */
+message ofp_bucket {
+ uint32 weight = 1; /* Relative weight of bucket. Only
+ defined for select groups. */
+ uint32 watch_port = 2; /* Port whose state affects whether this
+ bucket is live. Only required for fast
+ failover groups. */
+ uint32 watch_group = 3; /* Group whose state affects whether this
+ bucket is live. Only required for fast
+ failover groups. */
+ repeated ofp_action actions = 4;
+};
+
+/* Group setup and teardown (controller -> datapath). */
+message ofp_group_mod {
+ //ofp_header header;
+ ofp_group_mod_command command = 1; /* One of OFPGC_*. */
+ ofp_group_type type = 2; /* One of OFPGT_*. */
+ uint32 group_id = 3; /* Group identifier. */
+ repeated ofp_bucket buckets = 4;
+};
+
+/* Group types. Values in the range [128; 255] are reserved for experimental
+ * use. */
+enum ofp_group_type {
+ OFPGT_ALL = 0; /* All (multicast/broadcast) group. */
+ OFPGT_SELECT = 1; /* Select group. */
+ OFPGT_INDIRECT = 2; /* Indirect group. */
+ OFPGT_FF = 3; /* Fast failover group. */
+};
+
+/* Special buffer-id to indicate 'no buffer' */
+//#define OFP_NO_BUFFER 0xffffffff
+
+/* Send packet (controller -> datapath). */
+message ofp_packet_out {
+ //ofp_header header;
+ uint32 buffer_id = 1; /* ID assigned by datapath (OFP_NO_BUFFER
+ if none). */
+ uint32 in_port = 2; /* Packet's input port or OFPP_CONTROLLER.*/
+ repeated ofp_action actions = 3; /* Action list - 0 or more. */
+ /* The variable size action list is optionally followed by packet data.
+ * This data is only present and meaningful if buffer_id == -1. */
+ bytes data = 4; /* Packet data. */
+};
+
+/* Why is this packet being sent to the controller? */
+enum ofp_packet_in_reason {
+ OFPR_NO_MATCH = 0; /* No matching flow (table-miss flow entry). */
+ OFPR_ACTION = 1; /* Action explicitly output to controller. */
+ OFPR_INVALID_TTL = 2; /* Packet has invalid TTL */
+};
+
+/* Packet received on port (datapath -> controller). */
+message ofp_packet_in {
+ //ofp_header header;
+ uint32 buffer_id = 1; /* ID assigned by datapath. */
+ ofp_packet_in_reason reason = 2; /* Reason packet is being sent */
+ uint32 table_id = 3; /* ID of the table that was looked up */
+ uint64 cookie = 4; /* Cookie of the flow entry that was looked up. */
+ ofp_match match = 5; /* Packet metadata. Variable size. */
+ bytes data = 6; /* Ethernet frame */
+};
+
+/* Why was this flow removed? */
+enum ofp_flow_removed_reason {
+ OFPRR_IDLE_TIMEOUT = 0; /* Flow idle time exceeded idle_timeout. */
+ OFPRR_HARD_TIMEOUT = 1; /* Time exceeded hard_timeout. */
+ OFPRR_DELETE = 2; /* Evicted by a DELETE flow mod. */
+ OFPRR_GROUP_DELETE = 3; /* Group was removed. */
+ OFPRR_METER_DELETE = 4; /* Meter was removed */
+};
+
+/* Flow removed (datapath -> controller). */
+message ofp_flow_removed {
+ //ofp_header header;
+ uint64 cookie = 1; /* Opaque controller-issued identifier. */
+
+ uint32 priority = 2; /* Priority level of flow entry. */
+ ofp_flow_removed_reason reason = 3; /* One of OFPRR_*. */
+ uint32 table_id = 4; /* ID of the table */
+
+ uint32 duration_sec = 5; /* Time flow was alive in seconds. */
+ uint32 duration_nsec = 6; /* Time flow was alive in nanoseconds beyond
+ duration_sec. */
+ uint32 idle_timeout = 7; /* Idle timeout from original flow mod. */
+ uint32 hard_timeout = 8; /* Hard timeout from original flow mod. */
+ uint64 packet_count = 9;
+ uint64 byte_count = 10;
+ ofp_match match = 121; /* Description of fields. Variable size. */
+};
+
+/* Meter numbering. Flow meters can use any number up to OFPM_MAX. */
+enum ofp_meter {
+ OFPM_ZERO = 0;
+ /* Last usable meter. */
+ OFPM_MAX = 0x7fff0000;
+
+ /* Virtual meters. */
+ OFPM_SLOWPATH = 0x7ffffffd; /* Meter for slow datapath. */
+ OFPM_CONTROLLER = 0x7ffffffe; /* Meter for controller connection. */
+ OFPM_ALL = 0x7fffffff; /* Represents all meters for stat requests
+ commands. */
+};
+
+/* Meter band types */
+enum ofp_meter_band_type {
+ OFPMBT_INVALID = 0;
+ OFPMBT_DROP = 1; /* Drop packet. */
+ OFPMBT_DSCP_REMARK = 2; /* Remark DSCP in the IP header. */
+ OFPMBT_EXPERIMENTER = 0xFFFF; /* Experimenter meter band. */
+};
+
+/* Common header for all meter bands */
+message ofp_meter_band_header {
+ ofp_meter_band_type type = 1; /* One of OFPMBT_*. */
+ uint32 len = 2; /* Length in bytes of this band. */
+ uint32 rate = 3; /* Rate for this band. */
+ uint32 burst_size = 4;/* Size of bursts. */
+};
+
+/* OFPMBT_DROP band - drop packets */
+message ofp_meter_band_drop {
+ uint32 type = 1; /* OFPMBT_DROP. */
+ uint32 len = 2; /* Length in bytes of this band. */
+ uint32 rate = 3; /* Rate for dropping packets. */
+ uint32 burst_size = 4;/* Size of bursts. */
+};
+
+/* OFPMBT_DSCP_REMARK band - Remark DSCP in the IP header */
+message ofp_meter_band_dscp_remark {
+ uint32 type = 1; /* OFPMBT_DSCP_REMARK. */
+ uint32 len = 2; /* Length in bytes of this band. */
+ uint32 rate = 3; /* Rate for remarking packets. */
+ uint32 burst_size = 4; /* Size of bursts. */
+ uint32 prec_level = 5; /* Number of drop precedence level to add. */
+};
+
+/* OFPMBT_EXPERIMENTER band - Experimenter type.
+ * The rest of the band is experimenter-defined. */
+message ofp_meter_band_experimenter {
+ ofp_meter_band_type type = 1; /* One of OFPMBT_*. */
+ uint32 len = 2; /* Length in bytes of this band. */
+ uint32 rate = 3; /* Rate for this band. */
+ uint32 burst_size = 4; /* Size of bursts. */
+ uint32 experimenter = 5;/* Experimenter ID which takes the
+ same form as in struct
+ ofp_experimenter_header. */
+};
+
+/* Meter commands */
+enum ofp_meter_mod_command {
+ OFPMC_ADD = 0; /* New meter. */
+ OFPMC_MODIFY = 1; /* Modify specified meter. */
+ OFPMC_DELETE = 2; /* Delete specified meter. */
+};
+
+/* Meter configuration flags */
+enum ofp_meter_flags {
+ OFPMF_INVALID = 0;
+ OFPMF_KBPS = 1; /* Rate value in kb/s (kilo-bit per second). */
+ OFPMF_PKTPS = 2; /* Rate value in packet/sec. */
+ OFPMF_BURST = 4; /* Do burst size. */
+ OFPMF_STATS = 8; /* Collect statistics. */
+};
+
+/* Meter configuration. OFPT_METER_MOD. */
+message ofp_meter_mod {
+// ofp_header header = 1;
+ ofp_meter_mod_command command = 1; /* One of OFPMC_*. */
+ uint32 flags = 2; /* Bitmap of OFPMF_* flags. */
+ uint32 meter_id = 3; /* Meter instance. */
+ repeated ofp_meter_band_header bands = 4; /* The band list length is
+ inferred from the length field
+ in the header. */
+};
+
+/* Values for 'type' in ofp_error_message. These values are immutable: they
+ * will not change in future versions of the protocol (although new values may
+ * be added). */
+enum ofp_error_type {
+ OFPET_HELLO_FAILED = 0; /* Hello protocol failed. */
+ OFPET_BAD_REQUEST = 1; /* Request was not understood. */
+ OFPET_BAD_ACTION = 2; /* Error in action description. */
+ OFPET_BAD_INSTRUCTION = 3; /* Error in instruction list. */
+ OFPET_BAD_MATCH = 4; /* Error in match. */
+ OFPET_FLOW_MOD_FAILED = 5; /* Problem modifying flow entry. */
+ OFPET_GROUP_MOD_FAILED = 6; /* Problem modifying group entry. */
+ OFPET_PORT_MOD_FAILED = 7; /* Port mod request failed. */
+ OFPET_TABLE_MOD_FAILED = 8; /* Table mod request failed. */
+ OFPET_QUEUE_OP_FAILED = 9; /* Queue operation failed. */
+ OFPET_SWITCH_CONFIG_FAILED = 10; /* Switch config request failed. */
+ OFPET_ROLE_REQUEST_FAILED = 11; /* Controller Role request failed. */
+ OFPET_METER_MOD_FAILED = 12; /* Error in meter. */
+ OFPET_TABLE_FEATURES_FAILED = 13; /* Setting table features failed. */
+ OFPET_EXPERIMENTER = 0xffff; /* Experimenter error messages. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_HELLO_FAILED. 'data' contains an
+ * ASCII text string that may give failure details. */
+enum ofp_hello_failed_code {
+ OFPHFC_INCOMPATIBLE = 0; /* No compatible version. */
+ OFPHFC_EPERM = 1; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_BAD_REQUEST. 'data' contains at least
+ * the first 64 bytes of the failed request. */
+enum ofp_bad_request_code {
+ OFPBRC_BAD_VERSION = 0; /* ofp_header.version not supported. */
+ OFPBRC_BAD_TYPE = 1; /* ofp_header.type not supported. */
+ OFPBRC_BAD_MULTIPART = 2; /* ofp_multipart_request.type not supported.
+ */
+ OFPBRC_BAD_EXPERIMENTER = 3; /* Experimenter id not supported
+ * (in ofp_experimenter_header or
+ * ofp_multipart_request or
+ * ofp_multipart_reply). */
+ OFPBRC_BAD_EXP_TYPE = 4; /* Experimenter type not supported. */
+ OFPBRC_EPERM = 5; /* Permissions error. */
+ OFPBRC_BAD_LEN = 6; /* Wrong request length for type. */
+ OFPBRC_BUFFER_EMPTY = 7; /* Specified buffer has already been used. */
+ OFPBRC_BUFFER_UNKNOWN = 8; /* Specified buffer does not exist. */
+ OFPBRC_BAD_TABLE_ID = 9; /* Specified table-id invalid or does not
+ * exist. */
+ OFPBRC_IS_SLAVE = 10; /* Denied because controller is slave. */
+ OFPBRC_BAD_PORT = 11; /* Invalid port. */
+ OFPBRC_BAD_PACKET = 12; /* Invalid packet in packet-out. */
+ OFPBRC_MULTIPART_BUFFER_OVERFLOW = 13; /* ofp_multipart_request
+ overflowed the assigned buffer. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least
+ * the first 64 bytes of the failed request. */
+enum ofp_bad_action_code {
+ OFPBAC_BAD_TYPE = 0; /* Unknown or unsupported action type. */
+ OFPBAC_BAD_LEN = 1; /* Length problem in actions. */
+ OFPBAC_BAD_EXPERIMENTER = 2; /* Unknown experimenter id specified. */
+ OFPBAC_BAD_EXP_TYPE = 3; /* Unknown action for experimenter id. */
+ OFPBAC_BAD_OUT_PORT = 4; /* Problem validating output port. */
+ OFPBAC_BAD_ARGUMENT = 5; /* Bad action argument. */
+ OFPBAC_EPERM = 6; /* Permissions error. */
+ OFPBAC_TOO_MANY = 7; /* Can't handle this many actions. */
+ OFPBAC_BAD_QUEUE = 8; /* Problem validating output queue. */
+ OFPBAC_BAD_OUT_GROUP = 9; /* Invalid group id in forward action. */
+ OFPBAC_MATCH_INCONSISTENT = 10; /* Action can't apply for this match,
+ or Set-Field missing prerequisite. */
+ OFPBAC_UNSUPPORTED_ORDER = 11; /* Action order is unsupported for the
+ action list in an Apply-Actions instruction */
+ OFPBAC_BAD_TAG = 12; /* Actions uses an unsupported
+ tag/encap. */
+ OFPBAC_BAD_SET_TYPE = 13; /* Unsupported type in SET_FIELD action. */
+ OFPBAC_BAD_SET_LEN = 14; /* Length problem in SET_FIELD action. */
+ OFPBAC_BAD_SET_ARGUMENT = 15; /* Bad argument in SET_FIELD action. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_BAD_INSTRUCTION. 'data' contains at
+ * least the first 64 bytes of the failed request. */
+enum ofp_bad_instruction_code {
+ OFPBIC_UNKNOWN_INST = 0; /* Unknown instruction. */
+ OFPBIC_UNSUP_INST = 1; /* Switch or table does not support the
+ instruction. */
+ OFPBIC_BAD_TABLE_ID = 2; /* Invalid Table-ID specified. */
+ OFPBIC_UNSUP_METADATA = 3; /* Metadata value unsupported by datapath. */
+ OFPBIC_UNSUP_METADATA_MASK = 4; /* Metadata mask value unsupported by
+ datapath. */
+ OFPBIC_BAD_EXPERIMENTER = 5; /* Unknown experimenter id specified. */
+ OFPBIC_BAD_EXP_TYPE = 6; /* Unknown instruction for experimenter id. */
+ OFPBIC_BAD_LEN = 7; /* Length problem in instructions. */
+ OFPBIC_EPERM = 8; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_BAD_MATCH. 'data' contains at least
+ * the first 64 bytes of the failed request. */
+enum ofp_bad_match_code {
+ OFPBMC_BAD_TYPE = 0; /* Unsupported match type specified by the
+ match */
+ OFPBMC_BAD_LEN = 1; /* Length problem in match. */
+ OFPBMC_BAD_TAG = 2; /* Match uses an unsupported tag/encap. */
+ OFPBMC_BAD_DL_ADDR_MASK = 3; /* Unsupported datalink addr mask - switch
+ does not support arbitrary datalink
+ address mask. */
+ OFPBMC_BAD_NW_ADDR_MASK = 4; /* Unsupported network addr mask - switch
+ does not support arbitrary network
+ address mask. */
+ OFPBMC_BAD_WILDCARDS = 5; /* Unsupported combination of fields masked
+ or omitted in the match. */
+ OFPBMC_BAD_FIELD = 6; /* Unsupported field type in the match. */
+ OFPBMC_BAD_VALUE = 7; /* Unsupported value in a match field. */
+ OFPBMC_BAD_MASK = 8; /* Unsupported mask specified in the match,
+ field is not dl-address or nw-address. */
+ OFPBMC_BAD_PREREQ = 9; /* A prerequisite was not met. */
+ OFPBMC_DUP_FIELD = 10; /* A field type was duplicated. */
+ OFPBMC_EPERM = 11; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_flow_mod_failed_code {
+ OFPFMFC_UNKNOWN = 0; /* Unspecified error. */
+ OFPFMFC_TABLE_FULL = 1; /* Flow not added because table was full. */
+ OFPFMFC_BAD_TABLE_ID = 2; /* Table does not exist */
+ OFPFMFC_OVERLAP = 3; /* Attempted to add overlapping flow with
+ CHECK_OVERLAP flag set. */
+ OFPFMFC_EPERM = 4; /* Permissions error. */
+ OFPFMFC_BAD_TIMEOUT = 5; /* Flow not added because of unsupported
+ idle/hard timeout. */
+ OFPFMFC_BAD_COMMAND = 6; /* Unsupported or unknown command. */
+ OFPFMFC_BAD_FLAGS = 7; /* Unsupported or unknown flags. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_GROUP_MOD_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_group_mod_failed_code {
+ OFPGMFC_GROUP_EXISTS = 0; /* Group not added because a group ADD
+ attempted to replace an
+ already-present group. */
+ OFPGMFC_INVALID_GROUP = 1; /* Group not added because Group
+ specified is invalid. */
+ OFPGMFC_WEIGHT_UNSUPPORTED = 2; /* Switch does not support unequal load
+ sharing with select groups. */
+ OFPGMFC_OUT_OF_GROUPS = 3; /* The group table is full. */
+ OFPGMFC_OUT_OF_BUCKETS = 4; /* The maximum number of action buckets
+ for a group has been exceeded. */
+ OFPGMFC_CHAINING_UNSUPPORTED = 5; /* Switch does not support groups that
+ forward to groups. */
+ OFPGMFC_WATCH_UNSUPPORTED = 6; /* This group cannot watch the
+ watch_port or watch_group specified.
+ */
+ OFPGMFC_LOOP = 7; /* Group entry would cause a loop. */
+ OFPGMFC_UNKNOWN_GROUP = 8; /* Group not modified because a group
+ MODIFY attempted to modify a
+ non-existent group. */
+ OFPGMFC_CHAINED_GROUP = 9; /* Group not deleted because another
+ group is forwarding to it. */
+ OFPGMFC_BAD_TYPE = 10; /* Unsupported or unknown group type. */
+ OFPGMFC_BAD_COMMAND = 11; /* Unsupported or unknown command. */
+ OFPGMFC_BAD_BUCKET = 12; /* Error in bucket. */
+ OFPGMFC_BAD_WATCH = 13; /* Error in watch port/group. */
+ OFPGMFC_EPERM = 14; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_port_mod_failed_code {
+ OFPPMFC_BAD_PORT = 0; /* Specified port number does not exist. */
+ OFPPMFC_BAD_HW_ADDR = 1; /* Specified hardware address does not
+ * match the port number. */
+ OFPPMFC_BAD_CONFIG = 2; /* Specified config is invalid. */
+ OFPPMFC_BAD_ADVERTISE = 3; /* Specified advertise is invalid. */
+ OFPPMFC_EPERM = 4; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_TABLE_MOD_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_table_mod_failed_code {
+ OFPTMFC_BAD_TABLE = 0; /* Specified table does not exist. */
+ OFPTMFC_BAD_CONFIG = 1; /* Specified config is invalid. */
+ OFPTMFC_EPERM = 2; /* Permissions error. */
+};
+
+/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request */
+enum ofp_queue_op_failed_code {
+ OFPQOFC_BAD_PORT = 0; /* Invalid port (or port does not exist). */
+ OFPQOFC_BAD_QUEUE = 1; /* Queue does not exist. */
+ OFPQOFC_EPERM = 2; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_SWITCH_CONFIG_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_switch_config_failed_code {
+ OFPSCFC_BAD_FLAGS = 0; /* Specified flags is invalid. */
+ OFPSCFC_BAD_LEN = 1; /* Specified len is invalid. */
+ OFPSCFC_EPERM = 2; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_ROLE_REQUEST_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_role_request_failed_code {
+ OFPRRFC_STALE = 0; /* Stale Message: old generation_id. */
+ OFPRRFC_UNSUP = 1; /* Controller role change unsupported. */
+ OFPRRFC_BAD_ROLE = 2; /* Invalid role. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_METER_MOD_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_meter_mod_failed_code {
+ OFPMMFC_UNKNOWN = 0; /* Unspecified error. */
+ OFPMMFC_METER_EXISTS = 1; /* Meter not added because a Meter ADD
+ * attempted to replace an existing Meter. */
+ OFPMMFC_INVALID_METER = 2; /* Meter not added because Meter specified
+ * is invalid,
+ * or invalid meter in meter action. */
+ OFPMMFC_UNKNOWN_METER = 3; /* Meter not modified because a Meter MODIFY
+ * attempted to modify a non-existent Meter,
+ * or bad meter in meter action. */
+ OFPMMFC_BAD_COMMAND = 4; /* Unsupported or unknown command. */
+ OFPMMFC_BAD_FLAGS = 5; /* Flag configuration unsupported. */
+ OFPMMFC_BAD_RATE = 6; /* Rate unsupported. */
+ OFPMMFC_BAD_BURST = 7; /* Burst size unsupported. */
+ OFPMMFC_BAD_BAND = 8; /* Band unsupported. */
+ OFPMMFC_BAD_BAND_VALUE = 9; /* Band value unsupported. */
+ OFPMMFC_OUT_OF_METERS = 10; /* No more meters available. */
+ OFPMMFC_OUT_OF_BANDS = 11; /* The maximum number of properties
+ * for a meter has been exceeded. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_TABLE_FEATURES_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_table_features_failed_code {
+ OFPTFFC_BAD_TABLE = 0; /* Specified table does not exist. */
+ OFPTFFC_BAD_METADATA = 1; /* Invalid metadata mask. */
+ OFPTFFC_BAD_TYPE = 2; /* Unknown property type. */
+ OFPTFFC_BAD_LEN = 3; /* Length problem in properties. */
+ OFPTFFC_BAD_ARGUMENT = 4; /* Unsupported property value. */
+ OFPTFFC_EPERM = 5; /* Permissions error. */
+};
+
+/* OFPT_ERROR: Error message (datapath -> controller). */
+message ofp_error_msg {
+ //ofp_header header;
+ uint32 type = 1;
+ uint32 code = 2;
+ bytes data = 3; /* Variable-length data. Interpreted based
+ on the type and code. No padding. */
+};
+
+/* OFPET_EXPERIMENTER: Error message (datapath -> controller). */
+message ofp_error_experimenter_msg {
+ //ofp_header header;
+
+ uint32 type = 1; /* OFPET_EXPERIMENTER. */
+ uint32 exp_type = 2; /* Experimenter defined. */
+ uint32 experimenter = 3; /* Experimenter ID which takes the same form
+ as in struct ofp_experimenter_header. */
+ bytes data = 4; /* Variable-length data. Interpreted based
+ on the type and code. No padding. */
+};
+
+enum ofp_multipart_type {
+ /* Description of this OpenFlow switch.
+ * The request body is empty.
+ * The reply body is struct ofp_desc. */
+ OFPMP_DESC = 0;
+
+ /* Individual flow statistics.
+ * The request body is struct ofp_flow_stats_request.
+ * The reply body is an array of struct ofp_flow_stats. */
+ OFPMP_FLOW = 1;
+
+ /* Aggregate flow statistics.
+ * The request body is struct ofp_aggregate_stats_request.
+ * The reply body is struct ofp_aggregate_stats_reply. */
+ OFPMP_AGGREGATE = 2;
+
+ /* Flow table statistics.
+ * The request body is empty.
+ * The reply body is an array of struct ofp_table_stats. */
+ OFPMP_TABLE = 3;
+
+ /* Port statistics.
+ * The request body is struct ofp_port_stats_request.
+ * The reply body is an array of struct ofp_port_stats. */
+ OFPMP_PORT_STATS = 4;
+
+ /* Queue statistics for a port
+ * The request body is struct ofp_queue_stats_request.
+ * The reply body is an array of struct ofp_queue_stats */
+ OFPMP_QUEUE = 5;
+
+ /* Group counter statistics.
+ * The request body is struct ofp_group_stats_request.
+ * The reply is an array of struct ofp_group_stats. */
+ OFPMP_GROUP = 6;
+
+ /* Group description.
+ * The request body is empty.
+ * The reply body is an array of struct ofp_group_desc. */
+ OFPMP_GROUP_DESC = 7;
+
+ /* Group features.
+ * The request body is empty.
+ * The reply body is struct ofp_group_features. */
+ OFPMP_GROUP_FEATURES = 8;
+
+ /* Meter statistics.
+ * The request body is struct ofp_meter_multipart_requests.
+ * The reply body is an array of struct ofp_meter_stats. */
+ OFPMP_METER = 9;
+
+ /* Meter configuration.
+ * The request body is struct ofp_meter_multipart_requests.
+ * The reply body is an array of struct ofp_meter_config. */
+ OFPMP_METER_CONFIG = 10;
+
+ /* Meter features.
+ * The request body is empty.
+ * The reply body is struct ofp_meter_features. */
+ OFPMP_METER_FEATURES = 11;
+
+ /* Table features.
+ * The request body is either empty or contains an array of
+ * struct ofp_table_features containing the controller's
+ * desired view of the switch. If the switch is unable to
+ * set the specified view an error is returned.
+ * The reply body is an array of struct ofp_table_features. */
+ OFPMP_TABLE_FEATURES = 12;
+
+ /* Port description.
+ * The request body is empty.
+ * The reply body is an array of struct ofp_port. */
+ OFPMP_PORT_DESC = 13;
+
+ /* Experimenter extension.
+ * The request and reply bodies begin with
+ * struct ofp_experimenter_multipart_header.
+ * The request and reply bodies are otherwise experimenter-defined. */
+ OFPMP_EXPERIMENTER = 0xffff;
+};
+
+/* Backward compatibility with 1.3.1 - avoid breaking the API. */
+//#define ofp_multipart_types ofp_multipart_type
+
+enum ofp_multipart_request_flags {
+ OFPMPF_REQ_INVALID = 0;
+ OFPMPF_REQ_MORE = 1; /* More requests to follow. */
+};
+
+message ofp_multipart_request {
+ //ofp_header header;
+ ofp_multipart_type type = 1; /* One of the OFPMP_* constants. */
+ uint32 flags = 2; /* OFPMPF_REQ_* flags. */
+ bytes body = 3; /* Body of the request. 0 or more bytes. */
+};
+
+enum ofp_multipart_reply_flags {
+ OFPMPF_REPLY_INVALID = 0;
+ OFPMPF_REPLY_MORE = 1; /* More replies to follow. */
+};
+
+message ofp_multipart_reply {
+ //ofp_header header;
+ ofp_multipart_type type = 1; /* One of the OFPMP_* constants. */
+ uint32 flags = 2; /* OFPMPF_REPLY_* flags. */
+ bytes body = 3; /* Body of the reply. 0 or more bytes. */
+};
+
+//#define DESC_STR_LEN 256
+//#define SERIAL_NUM_LEN 32
+/* Body of reply to OFPMP_DESC request. Each entry is a NULL-terminated
+ * ASCII string. */
+message ofp_desc {
+ string mfr_desc = 1; /* Manufacturer description. */
+ string hw_desc = 2; /* Hardware description. */
+ string sw_desc = 3; /* Software description. */
+ string serial_num = 4; /* Serial number. */
+ string dp_desc = 5; /* Human readable description of datapath. */
+};
+
+/* Body for ofp_multipart_request of type OFPMP_FLOW. */
+message ofp_flow_stats_request {
+ uint32 table_id = 1; /* ID of table to read (from ofp_table_stats),
+ OFPTT_ALL for all tables. */
+ uint32 out_port = 2; /* Require matching entries to include this
+ as an output port. A value of OFPP_ANY
+ indicates no restriction. */
+ uint32 out_group = 3; /* Require matching entries to include this
+ as an output group. A value of OFPG_ANY
+ indicates no restriction. */
+ uint64 cookie = 4; /* Require matching entries to contain this
+ cookie value */
+ uint64 cookie_mask = 5; /* Mask used to restrict the cookie bits that
+ must match. A value of 0 indicates
+ no restriction. */
+ ofp_match match = 6; /* Fields to match. Variable size. */
+};
+
+/* Body of reply to OFPMP_FLOW request. */
+message ofp_flow_stats {
+ uint64 id = 14; /* Unique ID of flow within device. */
+ uint32 table_id = 1; /* ID of table flow came from. */
+ uint32 duration_sec = 2; /* Time flow has been alive in seconds. */
+ uint32 duration_nsec = 3; /* Time flow has been alive in nanoseconds
+ beyond duration_sec. */
+ uint32 priority = 4; /* Priority of the entry. */
+ uint32 idle_timeout = 5; /* Number of seconds idle before expiration. */
+ uint32 hard_timeout = 6; /* Number of seconds before expiration. */
+ uint32 flags = 7; /* Bitmap of OFPFF_* flags. */
+ uint64 cookie = 8; /* Opaque controller-issued identifier. */
+ uint64 packet_count = 9; /* Number of packets in flow. */
+ uint64 byte_count = 10; /* Number of bytes in flow. */
+ ofp_match match = 12; /* Description of fields. Variable size. */
+ repeated ofp_instruction instructions = 13; /* Instruction set
+ (0 or more) */
+};
+
+/* Body for ofp_multipart_request of type OFPMP_AGGREGATE. */
+message ofp_aggregate_stats_request {
+ uint32 table_id = 1; /* ID of table to read (from ofp_table_stats)
+ OFPTT_ALL for all tables. */
+ uint32 out_port = 2; /* Require matching entries to include this
+ as an output port. A value of OFPP_ANY
+ indicates no restriction. */
+ uint32 out_group = 3; /* Require matching entries to include this
+ as an output group. A value of OFPG_ANY
+ indicates no restriction. */
+ uint64 cookie = 4; /* Require matching entries to contain this
+ cookie value */
+ uint64 cookie_mask = 5; /* Mask used to restrict the cookie bits that
+ must match. A value of 0 indicates
+ no restriction. */
+ ofp_match match = 6; /* Fields to match. Variable size. */
+};
+
+/* Body of reply to OFPMP_AGGREGATE request. */
+message ofp_aggregate_stats_reply {
+ uint64 packet_count = 1; /* Number of packets in flows. */
+ uint64 byte_count = 2; /* Number of bytes in flows. */
+ uint32 flow_count = 3; /* Number of flows. */
+};
+
+/* Table Feature property types.
+ * Low order bit cleared indicates a property for a regular Flow Entry.
+ * Low order bit set indicates a property for the Table-Miss Flow Entry.
+ */
+enum ofp_table_feature_prop_type {
+ OFPTFPT_INSTRUCTIONS = 0; /* Instructions property. */
+ OFPTFPT_INSTRUCTIONS_MISS = 1; /* Instructions for table-miss. */
+ OFPTFPT_NEXT_TABLES = 2; /* Next Table property. */
+ OFPTFPT_NEXT_TABLES_MISS = 3; /* Next Table for table-miss. */
+ OFPTFPT_WRITE_ACTIONS = 4; /* Write Actions property. */
+ OFPTFPT_WRITE_ACTIONS_MISS = 5; /* Write Actions for table-miss. */
+ OFPTFPT_APPLY_ACTIONS = 6; /* Apply Actions property. */
+ OFPTFPT_APPLY_ACTIONS_MISS = 7; /* Apply Actions for table-miss. */
+ OFPTFPT_MATCH = 8; /* Match property. */
+ OFPTFPT_WILDCARDS = 10; /* Wildcards property. */
+ OFPTFPT_WRITE_SETFIELD = 12; /* Write Set-Field property. */
+ OFPTFPT_WRITE_SETFIELD_MISS = 13; /* Write Set-Field for table-miss. */
+ OFPTFPT_APPLY_SETFIELD = 14; /* Apply Set-Field property. */
+ OFPTFPT_APPLY_SETFIELD_MISS = 15; /* Apply Set-Field for table-miss. */
+ OFPTFPT_EXPERIMENTER = 0xFFFE; /* Experimenter property. */
+ OFPTFPT_EXPERIMENTER_MISS = 0xFFFF; /* Experimenter for table-miss. */
+};
+
+/* Common header for all Table Feature Properties */
+message ofp_table_feature_property {
+ ofp_table_feature_prop_type type = 1; /* One of OFPTFPT_*. */
+ oneof value {
+ ofp_table_feature_prop_instructions instructions = 2;
+ ofp_table_feature_prop_next_tables next_tables = 3;
+ ofp_table_feature_prop_actions actions = 4;
+ ofp_table_feature_prop_oxm oxm = 5;
+ ofp_table_feature_prop_experimenter experimenter = 6;
+ }
+};
+
+/* Instructions property */
+message ofp_table_feature_prop_instructions {
+ /* One of OFPTFPT_INSTRUCTIONS,
+ OFPTFPT_INSTRUCTIONS_MISS. */
+ repeated ofp_instruction instructions = 1; /* List of instructions */
+};
+
+/* Next Tables property */
+message ofp_table_feature_prop_next_tables {
+ /* One of OFPTFPT_NEXT_TABLES,
+ OFPTFPT_NEXT_TABLES_MISS. */
+ repeated uint32 next_table_ids = 1; /* List of table ids. */
+};
+
+/* Actions property */
+message ofp_table_feature_prop_actions {
+ /* One of OFPTFPT_WRITE_ACTIONS,
+ OFPTFPT_WRITE_ACTIONS_MISS,
+ OFPTFPT_APPLY_ACTIONS,
+ OFPTFPT_APPLY_ACTIONS_MISS. */
+ repeated ofp_action actions = 1; /* List of actions */
+};
+
+/* Match, Wildcard or Set-Field property */
+message ofp_table_feature_prop_oxm {
+ /* One of OFPTFPT_MATCH,
+ OFPTFPT_WILDCARDS,
+ OFPTFPT_WRITE_SETFIELD,
+ OFPTFPT_WRITE_SETFIELD_MISS,
+ OFPTFPT_APPLY_SETFIELD,
+ OFPTFPT_APPLY_SETFIELD_MISS. */
+ /* TODO is this a uint32??? */
+ repeated uint32 oxm_ids = 3; /* Array of OXM headers */
+};
+
+/* Experimenter table feature property */
+message ofp_table_feature_prop_experimenter {
+ /* One of OFPTFPT_EXPERIMENTER,
+ OFPTFPT_EXPERIMENTER_MISS. */
+ uint32 experimenter = 2; /* Experimenter ID which takes the same
+ form as in struct
+ ofp_experimenter_header. */
+ uint32 exp_type = 3; /* Experimenter defined. */
+ repeated uint32 experimenter_data = 4;
+};
+
+/* Body for ofp_multipart_request of type OFPMP_TABLE_FEATURES./
+ * Body of reply to OFPMP_TABLE_FEATURES request. */
+message ofp_table_features {
+ uint32 table_id = 1; /* Identifier of table. Lower numbered tables
+ are consulted first. */
+ string name = 2;
+ uint64 metadata_match = 3; /* Bits of metadata table can match. */
+ uint64 metadata_write = 4; /* Bits of metadata table can write. */
+ uint32 config = 5; /* Bitmap of OFPTC_* values */
+ uint32 max_entries = 6; /* Max number of entries supported. */
+
+ /* Table Feature Property list */
+ repeated ofp_table_feature_property properties = 7;
+};
+
+/* Body of reply to OFPMP_TABLE request. */
+message ofp_table_stats {
+ uint32 table_id = 1; /* Identifier of table. Lower numbered tables
+ are consulted first. */
+ uint32 active_count = 2; /* Number of active entries. */
+ uint64 lookup_count = 3; /* Number of packets looked up in table. */
+ uint64 matched_count = 4; /* Number of packets that hit table. */
+};
+
+/* Body for ofp_multipart_request of type OFPMP_PORT. */
+message ofp_port_stats_request {
+ uint32 port_no = 1; /* OFPMP_PORT message must request statistics
+ * either for a single port (specified in
+ * port_no) or for all ports (if port_no ==
+ * OFPP_ANY). */
+};
+
+/* Body of reply to OFPMP_PORT request. If a counter is unsupported, set
+ * the field to all ones. */
+message ofp_port_stats {
+ uint32 port_no = 1;
+ uint64 rx_packets = 2; /* Number of received packets. */
+ uint64 tx_packets = 3; /* Number of transmitted packets. */
+ uint64 rx_bytes = 4; /* Number of received bytes. */
+ uint64 tx_bytes = 5; /* Number of transmitted bytes. */
+ uint64 rx_dropped = 6; /* Number of packets dropped by RX. */
+ uint64 tx_dropped = 7; /* Number of packets dropped by TX. */
+ uint64 rx_errors = 8; /* Number of receive errors. This is a super-set
+ of more specific receive errors and should be
+ greater than or equal to the sum of all
+ rx_*_err values. */
+ uint64 tx_errors = 9; /* Number of transmit errors. This is a super-set
+ of more specific transmit errors and should be
+ greater than or equal to the sum of all
+ tx_*_err values (none currently defined.) */
+ uint64 rx_frame_err = 10; /* Number of frame alignment errors. */
+ uint64 rx_over_err = 11; /* Number of packets with RX overrun. */
+ uint64 rx_crc_err = 12; /* Number of CRC errors. */
+ uint64 collisions = 13; /* Number of collisions. */
+ uint32 duration_sec = 14; /* Time port has been alive in seconds. */
+ uint32 duration_nsec = 15; /* Time port has been alive in nanoseconds
+ beyond duration_sec. */
+};
+
+/* Body of OFPMP_GROUP request. */
+message ofp_group_stats_request {
+ uint32 group_id = 1; /* All groups if OFPG_ALL. */
+};
+
+/* Used in group stats replies. */
+message ofp_bucket_counter {
+ uint64 packet_count = 1; /* Number of packets processed by bucket. */
+ uint64 byte_count = 2; /* Number of bytes processed by bucket. */
+};
+
+/* Body of reply to OFPMP_GROUP request. */
+message ofp_group_stats {
+ uint32 group_id = 1; /* Group identifier. */
+ uint32 ref_count = 2; /* Number of flows or groups that directly
+ forward to this group. */
+ uint64 packet_count = 3; /* Number of packets processed by group. */
+ uint64 byte_count = 4; /* Number of bytes processed by group. */
+ uint32 duration_sec = 5; /* Time group has been alive in seconds. */
+ uint32 duration_nsec = 6; /* Time group has been alive in nanoseconds
+ beyond duration_sec. */
+ repeated ofp_bucket_counter bucket_stats = 7; /* One counter set per
+ bucket. */
+};
+
+/* Body of reply to OFPMP_GROUP_DESC request. */
+message ofp_group_desc {
+ ofp_group_type type = 1; /* One of OFPGT_*. */
+ uint32 group_id = 2; /* Group identifier. */
+ repeated ofp_bucket buckets = 3; /* List of buckets - 0 or more. */
+};
+
+message ofp_group_entry {
+ ofp_group_type type = 1; /* One of OFPGT_*. */
+ uint32 group_id = 2; /* Group identifier. */
+ repeated ofp_bucket buckets = 3; /* List of buckets - 0 or more. */
+ /* ofp_group_desc desc = 1; */
+ ofp_group_stats stats = 4;
+};
+
+/* Backward compatibility with 1.3.1 - avoid breaking the API. */
+//#define ofp_group_desc_stats ofp_group_desc
+
+/* Group configuration flags */
+enum ofp_group_capabilities {
+ OFPGFC_INVALID = 0;
+ OFPGFC_SELECT_WEIGHT = 1; /* Support weight for select groups */
+ OFPGFC_SELECT_LIVENESS = 2; /* Support liveness for select groups */
+ OFPGFC_CHAINING = 4; /* Support chaining groups */
+ OFPGFC_CHAINING_CHECKS = 8; /* Check chaining for loops and delete */
+};
+
+/* Body of reply to OFPMP_GROUP_FEATURES request. Group features. */
+message ofp_group_features {
+ uint32 types = 1; /* Bitmap of (1 << OFPGT_*) values supported. */
+ uint32 capabilities = 2; /* Bitmap of OFPGFC_* capability supported. */
+ repeated uint32 max_groups = 3; /* Maximum number of groups for each type.
+ */
+ repeated uint32 actions = 4; /* Bitmaps of (1 << OFPAT_*) values
+ supported. */
+};
+
+/* Body of OFPMP_METER and OFPMP_METER_CONFIG requests. */
+message ofp_meter_multipart_request {
+ uint32 meter_id = 1; /* Meter instance, or OFPM_ALL. */
+};
+
+/* Statistics for each meter band */
+message ofp_meter_band_stats {
+ uint64 packet_band_count = 1; /* Number of packets in band. */
+ uint64 byte_band_count = 2; /* Number of bytes in band. */
+};
+
+/* Body of reply to OFPMP_METER request. Meter statistics. */
+message ofp_meter_stats {
+ uint32 meter_id = 1; /* Meter instance. */
+ uint32 flow_count = 2; /* Number of flows bound to meter. */
+ uint64 packet_in_count = 3; /* Number of packets in input. */
+ uint64 byte_in_count = 4; /* Number of bytes in input. */
+ uint32 duration_sec = 5; /* Time meter has been alive in seconds. */
+ uint32 duration_nsec = 6;/* Time meter has been alive in nanoseconds
+ beyond duration_sec. */
+ repeated ofp_meter_band_stats band_stats = 7; /* The band_stats length is
+ inferred from the length field. */
+};
+
+/* Body of reply to OFPMP_METER_CONFIG request. Meter configuration. */
+message ofp_meter_config {
+ uint32 flags = 1; /* All OFPMF_* that apply. */
+ uint32 meter_id = 2; /* Meter instance. */
+ repeated ofp_meter_band_header bands = 3; /* The bands length is
+ inferred from the length field. */
+};
+
+/* Body of reply to OFPMP_METER_FEATURES request. Meter features. */
+message ofp_meter_features {
+ uint32 max_meter = 1; /* Maximum number of meters. */
+ uint32 band_types = 2; /* Bitmaps of (1 << OFPMBT_*) values supported.
+ */
+ uint32 capabilities = 3; /* Bitmaps of "ofp_meter_flags". */
+ uint32 max_bands = 4; /* Maximum bands per meters */
+ uint32 max_color = 5; /* Maximum color value */
+};
+
+/* Body for ofp_multipart_request/reply of type OFPMP_EXPERIMENTER. */
+message ofp_experimenter_multipart_header {
+ uint32 experimenter = 1; /* Experimenter ID which takes the same form
+ as in struct ofp_experimenter_header. */
+ uint32 exp_type = 2; /* Experimenter defined. */
+ bytes data = 3; /* Experimenter-defined arbitrary additional data. */
+};
+
+/* Experimenter extension. */
+message ofp_experimenter_header {
+ //ofp_header header; /* Type OFPT_EXPERIMENTER. */
+ uint32 experimenter = 1; /* Experimenter ID:
+ * - MSB 0: low-order bytes are IEEE OUI.
+ * - MSB != 0: defined by ONF. */
+ uint32 exp_type = 2; /* Experimenter defined. */
+ bytes data = 3; /* Experimenter-defined arbitrary additional data. */
+};
+
+/* All ones is used to indicate all queues in a port (for stats retrieval). */
+//#define OFPQ_ALL 0xffffffff
+
+/* Min rate > 1000 means not configured. */
+//#define OFPQ_MIN_RATE_UNCFG 0xffff
+
+/* Max rate > 1000 means not configured. */
+//#define OFPQ_MAX_RATE_UNCFG 0xffff
+
+enum ofp_queue_properties {
+ OFPQT_INVALID = 0;
+ OFPQT_MIN_RATE = 1; /* Minimum datarate guaranteed. */
+ OFPQT_MAX_RATE = 2; /* Maximum datarate. */
+ OFPQT_EXPERIMENTER = 0xffff; /* Experimenter defined property. */
+};
+
+/* Common description for a queue. */
+message ofp_queue_prop_header {
+ uint32 property = 1; /* One of OFPQT_. */
+ uint32 len = 2; /* Length of property, including this header. */
+};
+
+/* Min-Rate queue property description. */
+message ofp_queue_prop_min_rate {
+ ofp_queue_prop_header prop_header = 1;/* prop: OFPQT_MIN, len: 16. */
+ uint32 rate = 2; /* In 1/10 of a percent = 0;>1000 -> disabled. */
+};
+
+/* Max-Rate queue property description. */
+message ofp_queue_prop_max_rate {
+ ofp_queue_prop_header prop_header = 1;/* prop: OFPQT_MAX, len: 16. */
+ uint32 rate = 2; /* In 1/10 of a percent = 0;>1000 -> disabled. */
+};
+
+/* Experimenter queue property description. */
+message ofp_queue_prop_experimenter {
+ ofp_queue_prop_header prop_header = 1;/* prop: OFPQT_EXPERIMENTER */
+ uint32 experimenter = 2; /* Experimenter ID which takes the same
+ form as in struct
+ ofp_experimenter_header. */
+ bytes data = 3; /* Experimenter defined data. */
+};
+
+/* Full description for a queue. */
+message ofp_packet_queue {
+ uint32 queue_id = 1; /* id for the specific queue. */
+ uint32 port = 2; /* Port this queue is attached to. */
+ repeated ofp_queue_prop_header properties = 4; /* List of properties. */
+};
+
+/* Query for port queue configuration. */
+message ofp_queue_get_config_request {
+ //ofp_header header;
+ uint32 port = 1; /* Port to be queried. Should refer
+ to a valid physical port (i.e. <= OFPP_MAX),
+ or OFPP_ANY to request all configured
+ queues.*/
+};
+
+/* Queue configuration for a given port. */
+message ofp_queue_get_config_reply {
+ //ofp_header header;
+ uint32 port = 1;
+ repeated ofp_packet_queue queues = 2; /* List of configured queues. */
+};
+
+/* OFPAT_SET_QUEUE action struct: send packets to given queue on port. */
+message ofp_action_set_queue {
+ uint32 type = 1; /* OFPAT_SET_QUEUE. */
+ uint32 queue_id = 3; /* Queue id for the packets. */
+};
+
+message ofp_queue_stats_request {
+ uint32 port_no = 1; /* All ports if OFPP_ANY. */
+ uint32 queue_id = 2; /* All queues if OFPQ_ALL. */
+};
+
+message ofp_queue_stats {
+ uint32 port_no = 1;
+ uint32 queue_id = 2; /* Queue i.d */
+ uint64 tx_bytes = 3; /* Number of transmitted bytes. */
+ uint64 tx_packets = 4; /* Number of transmitted packets. */
+ uint64 tx_errors = 5; /* Number of packets dropped due to overrun. */
+ uint32 duration_sec = 6; /* Time queue has been alive in seconds. */
+ uint32 duration_nsec = 7; /* Time queue has been alive in nanoseconds
+ beyond duration_sec. */
+};
+
+/* Configures the "role" of the sending controller. The default role is:
+ *
+ * - Equal (OFPCR_ROLE_EQUAL), which allows the controller access to all
+ * OpenFlow features. All controllers have equal responsibility.
+ *
+ * The other possible roles are a related pair:
+ *
+ * - Master (OFPCR_ROLE_MASTER) is equivalent to Equal, except that there
+ * may be at most one Master controller at a time: when a controller
+ * configures itself as Master, any existing Master is demoted to the
+ * Slave role.
+ *
+ * - Slave (OFPCR_ROLE_SLAVE) allows the controller read-only access to
+ * OpenFlow features. In particular attempts to modify the flow table
+ * will be rejected with an OFPBRC_EPERM error.
+ *
+ * Slave controllers do not receive OFPT_PACKET_IN or OFPT_FLOW_REMOVED
+ * messages, but they do receive OFPT_PORT_STATUS messages.
+ */
+
+/* Controller roles. */
+enum ofp_controller_role {
+ OFPCR_ROLE_NOCHANGE = 0; /* Don't change current role. */
+ OFPCR_ROLE_EQUAL = 1; /* Default role, full access. */
+ OFPCR_ROLE_MASTER = 2; /* Full access, at most one master. */
+ OFPCR_ROLE_SLAVE = 3; /* Read-only access. */
+};
+
+/* Role request and reply message. */
+message ofp_role_request {
+ //ofp_header header; /* Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. */
+ ofp_controller_role role = 1; /* One of OFPCR_ROLE_*. */
+ uint64 generation_id = 2; /* Master Election Generation Id */
+};
+
+/* Asynchronous message configuration. */
+message ofp_async_config {
+ //ofp_header header; /* OFPT_GET_ASYNC_REPLY or OFPT_SET_ASYNC. */
+ repeated uint32 packet_in_mask = 1; /* Bitmasks of OFPR_* values. */
+ repeated uint32 port_status_mask = 2; /* Bitmasks of OFPPR_* values. */
+ repeated uint32 flow_removed_mask = 3;/* Bitmasks of OFPRR_* values. */
+};
+
+
+/* ADDITIONAL VOLTHA SPECIFIC MESSAGE TYPES, AIDING RPC CALLS */
+
+message FlowTableUpdate {
+ string id = 1; // Device.id or LogicalDevice.id
+ ofp_flow_mod flow_mod = 2;
+}
+
+message FlowGroupTableUpdate {
+ string id = 1; // Device.id or LogicalDevice.id
+ ofp_group_mod group_mod = 2;
+}
+
+message Flows {
+ repeated ofp_flow_stats items = 1;
+}
+
+message FlowGroups {
+ repeated ofp_group_entry items = 1;
+}
+
+message PacketIn {
+ string id = 1; // LogicalDevice.id
+ ofp_packet_in packet_in = 2;
+}
+
+message PacketOut {
+ string id = 1; // LogicalDevice.id
+ ofp_packet_out packet_out = 2;
+}
diff --git a/experiments/netconf/proto2yang/openflow_13_orig.proto b/experiments/netconf/proto2yang/openflow_13_orig.proto
new file mode 100644
index 0000000..01b5059
--- /dev/null
+++ b/experiments/netconf/proto2yang/openflow_13_orig.proto
@@ -0,0 +1,2275 @@
+/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
+ * Junior University
+ * Copyright (c) 2011, 2012 Open Networking Foundation
+ *
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
+ */
+
+/* OpenFlow: protocol between controller and datapath. */
+
+/*
+ * This is a relatively straightforward rendering of OpenFlow message
+ * definitions into protocol buffer messages. We preserved the snake
+ * case syntax, and made the following changes:
+ * - all pad fields dropped
+ * - for each enum value above 0x7fffffff the MSB is dropped. For example,
+ * 0xffffffff is now 0x7fffffff.
+ * - '<type> thing[...]' is replaced with 'repeated <type> thing'
+ * - 'char thing[...]' is replaced with 'string thing'
+ * - 'uint8_t data[...]' is replaced with 'bytes data'
+ * - the following systematic changes are done to various integer types:
+ * uint8_t -> uint32
+ * uint16_t -> uint32
+ * uint32_t -> uint32
+ * uint64_t -> uint64
+ * - removed most length, len, size fields where these values can be determined
+ * from the explicitly encoded length of "repeated" protobuf fields.
+ * - explicit use of enum types whereever it is unambigous (and not used as
+ * bitmask/flags value.
+ *
+ */
+syntax = "proto3";
+
+package openflow_13;
+
+
+/* Version number:
+ * OpenFlow versions released: 0x01 = 1.0 ; 0x02 = 1.1 ; 0x03 = 1.2
+ * 0x04 = 1.3
+ */
+/* The most significant bit in the version field is reserved and must
+ * be set to zero.
+ */
+//#define OFP_VERSION 0x04
+//#define PIPELINE_TABLES 64
+//#define OFP_MAX_TABLE_NAME_LEN 32
+//#define OFP_MAX_PORT_NAME_LEN 16
+/* Official IANA registered port for OpenFlow. */
+//#define OFP_TCP_PORT 6653
+//#define OFP_SSL_PORT 6653
+
+//#define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */
+
+/* Port numbering. Ports are numbered starting from 1. */
+enum ofp_port_no {
+ OFPP_INVALID = 0;
+
+ /* Maximum number of physical and logical switch ports. */
+ OFPP_MAX = 0x7fffff00;
+
+ /* Reserved OpenFlow Port (fake output "ports"). */
+ OFPP_IN_PORT = 0x7ffffff8; /* Send the packet out the input port. This
+ reserved port must be explicitly used
+ in order to send back out of the input
+ port. */
+ OFPP_TABLE = 0x7ffffff9; /* Submit the packet to the first flow table
+ NB: This destination port can only be
+ used in packet-out messages. */
+ OFPP_NORMAL = 0x7ffffffa; /* Forward using non-OpenFlow pipeline. */
+ OFPP_FLOOD = 0x7ffffffb; /* Flood using non-OpenFlow pipeline. */
+ OFPP_ALL = 0x7ffffffc; /* All standard ports except input port. */
+ OFPP_CONTROLLER = 0x7ffffffd; /* Send to controller. */
+ OFPP_LOCAL = 0x7ffffffe; /* Local openflow "port". */
+ OFPP_ANY = 0x7fffffff; /* Special value used in some requests when
+ no port is specified (i.e. wildcarded).*/
+};
+
+enum ofp_type {
+
+ /* Immutable messages. */
+ OFPT_HELLO = 0; /* Symmetric message */
+ OFPT_ERROR = 1; /* Symmetric message */
+ OFPT_ECHO_REQUEST = 2; /* Symmetric message */
+ OFPT_ECHO_REPLY = 3; /* Symmetric message */
+ OFPT_EXPERIMENTER = 4; /* Symmetric message */
+
+ /* Switch configuration messages. */
+ OFPT_FEATURES_REQUEST = 5; /* Controller/switch message */
+ OFPT_FEATURES_REPLY = 6; /* Controller/switch message */
+ OFPT_GET_CONFIG_REQUEST = 7; /* Controller/switch message */
+ OFPT_GET_CONFIG_REPLY = 8; /* Controller/switch message */
+ OFPT_SET_CONFIG = 9; /* Controller/switch message */
+
+ /* Asynchronous messages. */
+ OFPT_PACKET_IN = 10; /* Async message */
+ OFPT_FLOW_REMOVED = 11; /* Async message */
+ OFPT_PORT_STATUS = 12; /* Async message */
+
+ /* Controller command messages. */
+ OFPT_PACKET_OUT = 13; /* Controller/switch message */
+ OFPT_FLOW_MOD = 14; /* Controller/switch message */
+ OFPT_GROUP_MOD = 15; /* Controller/switch message */
+ OFPT_PORT_MOD = 16; /* Controller/switch message */
+ OFPT_TABLE_MOD = 17; /* Controller/switch message */
+
+ /* Multipart messages. */
+ OFPT_MULTIPART_REQUEST = 18; /* Controller/switch message */
+ OFPT_MULTIPART_REPLY = 19; /* Controller/switch message */
+
+ /* Barrier messages. */
+ OFPT_BARRIER_REQUEST = 20; /* Controller/switch message */
+ OFPT_BARRIER_REPLY = 21; /* Controller/switch message */
+
+ /* Queue Configuration messages. */
+ OFPT_QUEUE_GET_CONFIG_REQUEST = 22; /* Controller/switch message */
+ OFPT_QUEUE_GET_CONFIG_REPLY = 23; /* Controller/switch message */
+
+ /* Controller role change request messages. */
+ OFPT_ROLE_REQUEST = 24; /* Controller/switch message */
+ OFPT_ROLE_REPLY = 25; /* Controller/switch message */
+
+ /* Asynchronous message configuration. */
+ OFPT_GET_ASYNC_REQUEST = 26; /* Controller/switch message */
+ OFPT_GET_ASYNC_REPLY = 27; /* Controller/switch message */
+ OFPT_SET_ASYNC = 28; /* Controller/switch message */
+
+ /* Meters and rate limiters configuration messages. */
+ OFPT_METER_MOD = 29; /* Controller/switch message */
+};
+
+/* Header on all OpenFlow packets. */
+message ofp_header {
+ uint32 version = 1; /* OFP_VERSION. */
+ ofp_type type = 2; /* One of the OFPT_ constants. */
+ uint32 xid = 3; /* Transaction id associated with this packet.
+ Replies use the same id as was in the request
+ to facilitate pairing. */
+};
+
+/* Hello elements types.
+ */
+enum ofp_hello_elem_type {
+ OFPHET_INVALID = 0;
+ OFPHET_VERSIONBITMAP = 1; /* Bitmap of version supported. */
+};
+
+/* Common header for all Hello Elements */
+message ofp_hello_elem_header {
+ ofp_hello_elem_type type = 1; /* One of OFPHET_*. */
+ oneof element {
+ ofp_hello_elem_versionbitmap versionbitmap = 2;
+ }
+};
+
+/* Version bitmap Hello Element */
+message ofp_hello_elem_versionbitmap {
+ repeated uint32 bitmaps = 2; /* List of bitmaps - supported versions */
+};
+
+/* OFPT_HELLO. This message includes zero or more hello elements having
+ * variable size. Unknown elements types must be ignored/skipped, to allow
+ * for future extensions. */
+message ofp_hello {
+ //ofp_header header;
+ /* Hello element list */
+ repeated ofp_hello_elem_header elements = 1; /* 0 or more */
+};
+
+//#define OFP_DEFAULT_MISS_SEND_LEN 128
+
+enum ofp_config_flags {
+ /* Handling of IP fragments. */
+ OFPC_FRAG_NORMAL = 0; /* No special handling for fragments. */
+ OFPC_FRAG_DROP = 1; /* Drop fragments. */
+ OFPC_FRAG_REASM = 2; /* Reassemble (only if OFPC_IP_REASM set). */
+ OFPC_FRAG_MASK = 3; /* Bitmask of flags dealing with frag. */
+};
+
+/* Switch configuration. */
+message ofp_switch_config {
+ //ofp_header header;
+ uint32 flags = 1; /* Bitmap of OFPC_* flags. */
+ uint32 miss_send_len = 2; /* Max bytes of packet that datapath
+ should send to the controller. See
+ ofp_controller_max_len for valid values.
+ */
+};
+
+/* Flags to configure the table. Reserved for future use. */
+enum ofp_table_config {
+ OFPTC_INVALID = 0;
+ OFPTC_DEPRECATED_MASK = 3; /* Deprecated bits */
+};
+
+/* Table numbering. Tables can use any number up to OFPT_MAX. */
+enum ofp_table {
+
+ OFPTT_INVALID = 0;
+
+ /* Last usable table number. */
+ OFPTT_MAX = 0xfe;
+
+ /* Fake tables. */
+ OFPTT_ALL = 0xff; /* Wildcard table used for table config,
+ flow stats and flow deletes. */
+};
+
+
+/* Configure/Modify behavior of a flow table */
+message ofp_table_mod {
+ //ofp_header header;
+ uint32 table_id = 1; /* ID of the table, OFPTT_ALL indicates all tables */
+ uint32 config = 2; /* Bitmap of OFPTC_* flags */
+};
+
+/* Capabilities supported by the datapath. */
+enum ofp_capabilities {
+ OFPC_INVALID = 0;
+ OFPC_FLOW_STATS = 1; /* Flow statistics. */
+ OFPC_TABLE_STATS = 2; /* Table statistics. */
+ OFPC_PORT_STATS = 4; /* Port statistics. */
+ OFPC_GROUP_STATS = 8; /* Group statistics. */
+ OFPC_IP_REASM = 32; /* Can reassemble IP fragments. */
+ OFPC_QUEUE_STATS = 64; /* Queue statistics. */
+ OFPC_PORT_BLOCKED = 256; /* Switch will block looping ports. */
+};
+
+/* Flags to indicate behavior of the physical port. These flags are
+ * used in ofp_port to describe the current configuration. They are
+ * used in the ofp_port_mod message to configure the port's behavior.
+ */
+enum ofp_port_config {
+ OFPPC_INVALID = 0;
+ OFPPC_PORT_DOWN = 1; /* Port is administratively down. */
+
+ OFPPC_NO_RECV = 4; /* Drop all packets received by port. */
+ OFPPC_NO_FWD = 32; /* Drop packets forwarded to port. */
+ OFPPC_NO_PACKET_IN = 64; /* Do not send packet-in msgs for port. */
+};
+
+/* Current state of the physical port. These are not configurable from
+ * the controller.
+ */
+enum ofp_port_state {
+ OFPPS_INVALID = 0;
+ OFPPS_LINK_DOWN = 1; /* No physical link present. */
+ OFPPS_BLOCKED = 2; /* Port is blocked */
+ OFPPS_LIVE = 4; /* Live for Fast Failover Group. */
+};
+
+/* Features of ports available in a datapath. */
+enum ofp_port_features {
+ OFPPF_INVALID = 0;
+ OFPPF_10MB_HD = 1; /* 10 Mb half-duplex rate support. */
+ OFPPF_10MB_FD = 2; /* 10 Mb full-duplex rate support. */
+ OFPPF_100MB_HD = 4; /* 100 Mb half-duplex rate support. */
+ OFPPF_100MB_FD = 8; /* 100 Mb full-duplex rate support. */
+ OFPPF_1GB_HD = 16; /* 1 Gb half-duplex rate support. */
+ OFPPF_1GB_FD = 32; /* 1 Gb full-duplex rate support. */
+ OFPPF_10GB_FD = 64; /* 10 Gb full-duplex rate support. */
+ OFPPF_40GB_FD = 128; /* 40 Gb full-duplex rate support. */
+ OFPPF_100GB_FD = 256; /* 100 Gb full-duplex rate support. */
+ OFPPF_1TB_FD = 512; /* 1 Tb full-duplex rate support. */
+ OFPPF_OTHER = 1024; /* Other rate, not in the list. */
+ OFPPF_COPPER = 2048; /* Copper medium. */
+ OFPPF_FIBER = 4096; /* Fiber medium. */
+ OFPPF_AUTONEG = 8192; /* Auto-negotiation. */
+ OFPPF_PAUSE = 16384; /* Pause. */
+ OFPPF_PAUSE_ASYM = 32768; /* Asymmetric pause. */
+};
+
+/* Description of a port */
+message ofp_port {
+ uint32 port_no = 1;
+ repeated uint32 hw_addr = 2; // [OFP_ETH_ALEN];
+ string name = 3; /* Null-terminated */
+
+ uint32 config = 4; /* Bitmap of OFPPC_* flags. */
+ uint32 state = 5; /* Bitmap of OFPPS_* flags. */
+
+ /* Bitmaps of OFPPF_* that describe features. All bits zeroed if
+ * unsupported or unavailable. */
+ uint32 curr = 6; /* Current features. */
+ uint32 advertised = 7; /* Features being advertised by the port. */
+ uint32 supported = 8; /* Features supported by the port. */
+ uint32 peer = 9; /* Features advertised by peer. */
+ uint32 curr_speed = 10; /* Current port bitrate in kbps. */
+ uint32 max_speed = 11; /* Max port bitrate in kbps */
+};
+
+/* Switch features. */
+message ofp_switch_features {
+ //ofp_header header;
+ uint64 datapath_id = 1; /* Datapath unique ID. The lower 48-bits are for
+ a MAC address, while the upper 16-bits are
+ implementer-defined. */
+
+ uint32 n_buffers = 2; /* Max packets buffered at once. */
+
+ uint32 n_tables = 3; /* Number of tables supported by datapath. */
+ uint32 auxiliary_id = 4; /* Identify auxiliary connections */
+
+ /* Features. */
+ uint32 capabilities = 5; /* Bitmap of support "ofp_capabilities". */
+};
+
+/* What changed about the physical port */
+enum ofp_port_reason {
+ OFPPR_ADD = 0; /* The port was added. */
+ OFPPR_DELETE = 1; /* The port was removed. */
+ OFPPR_MODIFY = 2; /* Some attribute of the port has changed. */
+};
+
+/* A physical port has changed in the datapath */
+message ofp_port_status {
+ //ofp_header header;
+ ofp_port_reason reason = 1; /* One of OFPPR_*. */
+ ofp_port desc = 2;
+};
+
+/* Modify behavior of the physical port */
+message ofp_port_mod {
+ //ofp_header header;
+ uint32 port_no = 1;
+ repeated uint32 hw_addr = 2; //[OFP_ETH_ALEN];
+ /* The hardware address is not
+ configurable. This is used to
+ sanity-check the request, so it must
+ be the same as returned in an
+ ofp_port struct. */
+ uint32 config = 3; /* Bitmap of OFPPC_* flags. */
+ uint32 mask = 4; /* Bitmap of OFPPC_* flags to be changed. */
+
+ uint32 advertise = 5; /* Bitmap of OFPPF_*. Zero all bits to prevent
+ any action taking place. */
+};
+
+/* ## -------------------------- ## */
+/* ## OpenFlow Extensible Match. ## */
+/* ## -------------------------- ## */
+
+/* The match type indicates the match structure (set of fields that compose the
+ * match) in use. The match type is placed in the type field at the beginning
+ * of all match structures. The "OpenFlow Extensible Match" type corresponds
+ * to OXM TLV format described below and must be supported by all OpenFlow
+ * switches. Extensions that define other match types may be published on the
+ * ONF wiki. Support for extensions is optional.
+ */
+enum ofp_match_type {
+ OFPMT_STANDARD = 0; /* Deprecated. */
+ OFPMT_OXM = 1; /* OpenFlow Extensible Match */
+};
+
+/* Fields to match against flows */
+message ofp_match {
+ ofp_match_type type = 1; /* One of OFPMT_* */
+ repeated ofp_oxm_field oxm_fields = 2; /* 0 or more */
+};
+
+/* Components of a OXM TLV header.
+ * Those macros are not valid for the experimenter class, macros for the
+ * experimenter class will depend on the experimenter header used. */
+//#define OXM_HEADER__(CLASS, FIELD, HASMASK, LENGTH) \
+// (((CLASS) << 16) | ((FIELD) << 9) | ((HASMASK) << 8) | (LENGTH))
+//#define OXM_HEADER(CLASS, FIELD, LENGTH) \
+// OXM_HEADER__(CLASS, FIELD, 0, LENGTH)
+//#define OXM_HEADER_W(CLASS, FIELD, LENGTH) \
+// OXM_HEADER__(CLASS, FIELD, 1, (LENGTH) * 2)
+//#define OXM_CLASS(HEADER) ((HEADER) >> 16)
+//#define OXM_FIELD(HEADER) (((HEADER) >> 9) & 0x7f)
+//#define OXM_TYPE(HEADER) (((HEADER) >> 9) & 0x7fffff)
+//#define OXM_HASMASK(HEADER) (((HEADER) >> 8) & 1)
+//#define OXM_LENGTH(HEADER) ((HEADER) & 0xff)
+//
+//#define OXM_MAKE_WILD_HEADER(HEADER) \
+// OXM_HEADER_W(OXM_CLASS(HEADER), OXM_FIELD(HEADER), OXM_LENGTH(HEADER))
+
+/* OXM Class IDs.
+ * The high order bit differentiate reserved classes from member classes.
+ * Classes 0x0000 to 0x7FFF are member classes, allocated by ONF.
+ * Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation.
+ */
+enum ofp_oxm_class {
+ OFPXMC_NXM_0 = 0x0000; /* Backward compatibility with NXM */
+ OFPXMC_NXM_1 = 0x0001; /* Backward compatibility with NXM */
+ OFPXMC_OPENFLOW_BASIC = 0x8000; /* Basic class for OpenFlow */
+ OFPXMC_EXPERIMENTER = 0xFFFF; /* Experimenter class */
+};
+
+/* OXM Flow field types for OpenFlow basic class. */
+enum oxm_ofb_field_types {
+ OFPXMT_OFB_IN_PORT = 0; /* Switch input port. */
+ OFPXMT_OFB_IN_PHY_PORT = 1; /* Switch physical input port. */
+ OFPXMT_OFB_METADATA = 2; /* Metadata passed between tables. */
+ OFPXMT_OFB_ETH_DST = 3; /* Ethernet destination address. */
+ OFPXMT_OFB_ETH_SRC = 4; /* Ethernet source address. */
+ OFPXMT_OFB_ETH_TYPE = 5; /* Ethernet frame type. */
+ OFPXMT_OFB_VLAN_VID = 6; /* VLAN id. */
+ OFPXMT_OFB_VLAN_PCP = 7; /* VLAN priority. */
+ OFPXMT_OFB_IP_DSCP = 8; /* IP DSCP (6 bits in ToS field). */
+ OFPXMT_OFB_IP_ECN = 9; /* IP ECN (2 bits in ToS field). */
+ OFPXMT_OFB_IP_PROTO = 10; /* IP protocol. */
+ OFPXMT_OFB_IPV4_SRC = 11; /* IPv4 source address. */
+ OFPXMT_OFB_IPV4_DST = 12; /* IPv4 destination address. */
+ OFPXMT_OFB_TCP_SRC = 13; /* TCP source port. */
+ OFPXMT_OFB_TCP_DST = 14; /* TCP destination port. */
+ OFPXMT_OFB_UDP_SRC = 15; /* UDP source port. */
+ OFPXMT_OFB_UDP_DST = 16; /* UDP destination port. */
+ OFPXMT_OFB_SCTP_SRC = 17; /* SCTP source port. */
+ OFPXMT_OFB_SCTP_DST = 18; /* SCTP destination port. */
+ OFPXMT_OFB_ICMPV4_TYPE = 19; /* ICMP type. */
+ OFPXMT_OFB_ICMPV4_CODE = 20; /* ICMP code. */
+ OFPXMT_OFB_ARP_OP = 21; /* ARP opcode. */
+ OFPXMT_OFB_ARP_SPA = 22; /* ARP source IPv4 address. */
+ OFPXMT_OFB_ARP_TPA = 23; /* ARP target IPv4 address. */
+ OFPXMT_OFB_ARP_SHA = 24; /* ARP source hardware address. */
+ OFPXMT_OFB_ARP_THA = 25; /* ARP target hardware address. */
+ OFPXMT_OFB_IPV6_SRC = 26; /* IPv6 source address. */
+ OFPXMT_OFB_IPV6_DST = 27; /* IPv6 destination address. */
+ OFPXMT_OFB_IPV6_FLABEL = 28; /* IPv6 Flow Label */
+ OFPXMT_OFB_ICMPV6_TYPE = 29; /* ICMPv6 type. */
+ OFPXMT_OFB_ICMPV6_CODE = 30; /* ICMPv6 code. */
+ OFPXMT_OFB_IPV6_ND_TARGET = 31; /* Target address for ND. */
+ OFPXMT_OFB_IPV6_ND_SLL = 32; /* Source link-layer for ND. */
+ OFPXMT_OFB_IPV6_ND_TLL = 33; /* Target link-layer for ND. */
+ OFPXMT_OFB_MPLS_LABEL = 34; /* MPLS label. */
+ OFPXMT_OFB_MPLS_TC = 35; /* MPLS TC. */
+ OFPXMT_OFB_MPLS_BOS = 36; /* MPLS BoS bit. */
+ OFPXMT_OFB_PBB_ISID = 37; /* PBB I-SID. */
+ OFPXMT_OFB_TUNNEL_ID = 38; /* Logical Port Metadata. */
+ OFPXMT_OFB_IPV6_EXTHDR = 39; /* IPv6 Extension Header pseudo-field */
+};
+
+/* OXM Flow match fields */
+message ofp_oxm_field {
+ ofp_oxm_class oxm_class = 1;
+ oneof field {
+ /* 2 and 3 reserved for NXM_0 and NXM-1 OXM classes */
+ ofp_oxm_ofb_field ofb_field = 4;
+ ofp_oxm_experimenter_field experimenter_field = 5;
+ }
+}
+
+/* OXM OpenFlow Basic Match Field */
+message ofp_oxm_ofb_field {
+ oxm_ofb_field_types type = 1;
+ bool has_mask = 2;
+ oneof value {
+
+ /* OpenFlow port on which the packet was received.
+ * May be a physical port, a logical port, or the reserved port OFPP_LOCAL
+ *
+ * Prereqs: None.
+ *
+ * Format: 32-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IN_PORT OXM_HEADER (0x8000, OFPXMT_OFB_IN_PORT, 4)
+ uint32 port = 3; /* Used for OFPXMT_OFB_IN_PORT */
+
+ /* Physical port on which the packet was received.
+ *
+ * Consider a packet received on a tunnel interface defined over a link
+ * aggregation group (LAG) with two physical port members. If the tunnel
+ * interface is the logical port bound to OpenFlow. In this case,
+ * OFPXMT_OF_IN_PORT is the tunnel's port number and OFPXMT_OF_IN_PHY_PORT is
+ * the physical port number of the LAG on which the tunnel is configured.
+ *
+ * When a packet is received directly on a physical port and not processed by a
+ * logical port, OFPXMT_OF_IN_PORT and OFPXMT_OF_IN_PHY_PORT have the same
+ * value.
+ *
+ * This field is usually not available in a regular match and only available
+ * in ofp_packet_in messages when it's different from OXM_OF_IN_PORT.
+ *
+ * Prereqs: OXM_OF_IN_PORT must be present.
+ *
+ * Format: 32-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IN_PHY_PORT OXM_HEADER (0x8000, OFPXMT_OFB_IN_PHY_PORT, 4)
+ uint32 physical_port = 4; /* Used for OFPXMT_OF_IN_PHY_PORT */
+
+ /* Table metadata.
+ *
+ * Prereqs: None.
+ *
+ * Format: 64-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks.
+ */
+ //#define OXM_OF_METADATA OXM_HEADER (0x8000, OFPXMT_OFB_METADATA, 8)
+ //#define OXM_OF_METADATA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_METADATA, 8)
+ uint64 table_metadata = 5; /* Used for OFPXMT_OFB_METADATA */
+
+ /* Source or destination address in Ethernet header.
+ *
+ * Prereqs: None.
+ *
+ * Format: 48-bit Ethernet MAC address.
+ *
+ * Masking: Arbitrary masks. */
+ //#define OXM_OF_ETH_DST OXM_HEADER (0x8000, OFPXMT_OFB_ETH_DST, 6)
+ //#define OXM_OF_ETH_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ETH_DST, 6)
+ //#define OXM_OF_ETH_SRC OXM_HEADER (0x8000, OFPXMT_OFB_ETH_SRC, 6)
+ //#define OXM_OF_ETH_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ETH_SRC, 6)
+ bytes eth_dst = 6; /* Used for OFPXMT_OFB_ETH_DST (exactly 6 bytes) */
+ bytes eth_src = 7; /* Used for OFPXMT_OFB_ETH_SRC (exactly 6 bytes) */
+
+ /* Packet's Ethernet type.
+ *
+ * Prereqs: None.
+ *
+ * Format: 16-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_ETH_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ETH_TYPE,2)
+ uint32 eth_type = 8; /* Used for OFPXMT_OFB_ETH_TYPE */
+
+ /* 802.1Q VID.
+ *
+ * For a packet with an 802.1Q header, this is the VLAN-ID (VID) from the
+ * outermost tag, with the CFI bit forced to 1. For a packet with no 802.1Q
+ * header, this has value OFPVID_NONE.
+ *
+ * Prereqs: None.
+ *
+ * Format: 16-bit integer in network byte order with bit 13 indicating
+ * presence of VLAN header and 3 most-significant bits forced to 0.
+ * Only the lower 13 bits have meaning.
+ *
+ * Masking: Arbitrary masks.
+ *
+ * This field can be used in various ways:
+ *
+ * - If it is not constrained at all, the nx_match matches packets without
+ * an 802.1Q header or with an 802.1Q header that has any VID value.
+ *
+ * - Testing for an exact match with 0x0 matches only packets without
+ * an 802.1Q header.
+ *
+ * - Testing for an exact match with a VID value with CFI=1 matches packets
+ * that have an 802.1Q header with a specified VID.
+ *
+ * - Testing for an exact match with a nonzero VID value with CFI=0 does
+ * not make sense. The switch may reject this combination.
+ *
+ * - Testing with nxm_value=0, nxm_mask=0x0fff matches packets with no 802.1Q
+ * header or with an 802.1Q header with a VID of 0.
+ *
+ * - Testing with nxm_value=0x1000, nxm_mask=0x1000 matches packets with
+ * an 802.1Q header that has any VID value.
+ */
+ //#define OXM_OF_VLAN_VID OXM_HEADER (0x8000, OFPXMT_OFB_VLAN_VID, 2)
+ //#define OXM_OF_VLAN_VID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_VLAN_VID, 2)
+ uint32 vlan_vid = 9; /* Used for OFPXMT_OFB_VLAN_VID */
+
+ /* 802.1Q PCP.
+ *
+ * For a packet with an 802.1Q header, this is the VLAN-PCP from the
+ * outermost tag. For a packet with no 802.1Q header, this has value
+ * 0.
+ *
+ * Prereqs: OXM_OF_VLAN_VID must be different from OFPVID_NONE.
+ *
+ * Format: 8-bit integer with 5 most-significant bits forced to 0.
+ * Only the lower 3 bits have meaning.
+ *
+ * Masking: Not maskable.
+ */
+ //#define OXM_OF_VLAN_PCP OXM_HEADER (0x8000, OFPXMT_OFB_VLAN_PCP, 1)
+ uint32 vlan_pcp = 10; /* Used for OFPXMT_OFB_VLAN_PCP */
+
+ /* The Diff Serv Code Point (DSCP) bits of the IP header.
+ * Part of the IPv4 ToS field or the IPv6 Traffic Class field.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+ *
+ * Format: 8-bit integer with 2 most-significant bits forced to 0.
+ * Only the lower 6 bits have meaning.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IP_DSCP OXM_HEADER (0x8000, OFPXMT_OFB_IP_DSCP, 1)
+ uint32 ip_dscp = 11; /* Used for OFPXMT_OFB_IP_DSCP */
+
+ /* The ECN bits of the IP header.
+ * Part of the IPv4 ToS field or the IPv6 Traffic Class field.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+ *
+ * Format: 8-bit integer with 6 most-significant bits forced to 0.
+ * Only the lower 2 bits have meaning.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IP_ECN OXM_HEADER (0x8000, OFPXMT_OFB_IP_ECN, 1)
+ uint32 ip_ecn = 12; /* Used for OFPXMT_OFB_IP_ECN */
+
+ /* The "protocol" byte in the IP header.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+ *
+ * Format: 8-bit integer.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IP_PROTO OXM_HEADER (0x8000, OFPXMT_OFB_IP_PROTO, 1)
+ uint32 ip_proto = 13; /* Used for OFPXMT_OFB_IP_PROTO */
+
+ /* The source or destination address in the IP header.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must match 0x0800 exactly.
+ *
+ * Format: 32-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks.
+ */
+ //#define OXM_OF_IPV4_SRC OXM_HEADER (0x8000, OFPXMT_OFB_IPV4_SRC, 4)
+ //#define OXM_OF_IPV4_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV4_SRC, 4)
+ //#define OXM_OF_IPV4_DST OXM_HEADER (0x8000, OFPXMT_OFB_IPV4_DST, 4)
+ //#define OXM_OF_IPV4_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV4_DST, 4)
+ uint32 ipv4_src = 14; /* Used for OFPXMT_OFB_IPV4_SRC */
+ uint32 ipv4_dst = 15; /* Used for OFPXMT_OFB_IPV4_DST */
+
+ /* The source or destination port in the TCP header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
+ * OXM_OF_IP_PROTO must match 6 exactly.
+ *
+ * Format: 16-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_TCP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_TCP_SRC, 2)
+ //#define OXM_OF_TCP_DST OXM_HEADER (0x8000, OFPXMT_OFB_TCP_DST, 2)
+ uint32 tcp_src = 16; /* Used for OFPXMT_OFB_TCP_SRC */
+ uint32 tcp_dst = 17; /* Used for OFPXMT_OFB_TCP_DST */
+
+ /* The source or destination port in the UDP header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd.
+ * OXM_OF_IP_PROTO must match 17 exactly.
+ *
+ * Format: 16-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_UDP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_UDP_SRC, 2)
+ //#define OXM_OF_UDP_DST OXM_HEADER (0x8000, OFPXMT_OFB_UDP_DST, 2)
+ uint32 udp_src = 18; /* Used for OFPXMT_OFB_UDP_SRC */
+ uint32 udp_dst = 19; /* Used for OFPXMT_OFB_UDP_DST */
+
+ /* The source or destination port in the SCTP header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd.
+ * OXM_OF_IP_PROTO must match 132 exactly.
+ *
+ * Format: 16-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_SCTP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_SCTP_SRC, 2)
+ //#define OXM_OF_SCTP_DST OXM_HEADER (0x8000, OFPXMT_OFB_SCTP_DST, 2)
+ uint32 sctp_src = 20; /* Used for OFPXMT_OFB_SCTP_SRC */
+ uint32 sctp_dst = 21; /* Used for OFPXMT_OFB_SCTP_DST */
+
+ /* The type or code in the ICMP header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x0800 exactly.
+ * OXM_OF_IP_PROTO must match 1 exactly.
+ *
+ * Format: 8-bit integer.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_ICMPV4_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV4_TYPE, 1)
+ //#define OXM_OF_ICMPV4_CODE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV4_CODE, 1)
+ uint32 icmpv4_type = 22; /* Used for OFPXMT_OFB_ICMPV4_TYPE */
+ uint32 icmpv4_code = 23; /* Used for OFPXMT_OFB_ICMPV4_CODE */
+
+ /* ARP opcode.
+ *
+ * For an Ethernet+IP ARP packet, the opcode in the ARP header. Always 0
+ * otherwise.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly.
+ *
+ * Format: 16-bit integer in network byte order.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_ARP_OP OXM_HEADER (0x8000, OFPXMT_OFB_ARP_OP, 2)
+ uint32 arp_op = 24; /* Used for OFPXMT_OFB_ARP_OP */
+
+ /* For an Ethernet+IP ARP packet, the source or target protocol address
+ * in the ARP header. Always 0 otherwise.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly.
+ *
+ * Format: 32-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks.
+ */
+ //#define OXM_OF_ARP_SPA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_SPA, 4)
+ //#define OXM_OF_ARP_SPA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ARP_SPA, 4)
+ //#define OXM_OF_ARP_TPA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_TPA, 4)
+ //#define OXM_OF_ARP_TPA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ARP_TPA, 4)
+ uint32 arp_spa = 25; /* For OFPXMT_OFB_ARP_SPA */
+ uint32 arp_tpa = 26; /* For OFPXMT_OFB_ARP_TPA */
+
+ /* For an Ethernet+IP ARP packet, the source or target hardware address
+ * in the ARP header. Always 0 otherwise.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly.
+ *
+ * Format: 48-bit Ethernet MAC address.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_ARP_SHA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_SHA, 6)
+ //#define OXM_OF_ARP_SHA_W OXM_HEADER_W (0x8000, OFPXMT_OFB_ARP_SHA, 6)
+ //#define OXM_OF_ARP_THA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_THA, 6)
+ //#define OXM_OF_ARP_THA_W OXM_HEADER_W (0x8000, OFPXMT_OFB_ARP_THA, 6)
+ bytes arp_sha = 27; /* For OFPXMT_OFB_ARP_SHA (6 bytes) */
+ bytes arp_tha = 28; /* For OFPXMT_OFB_ARP_THA (6 bytes) */
+
+ /* The source or destination address in the IPv6 header.
+ *
+ * Prereqs: OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ *
+ * Format: 128-bit IPv6 address.
+ *
+ * Masking: Arbitrary masks.
+ */
+ //#define OXM_OF_IPV6_SRC OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_SRC, 16)
+ //#define OXM_OF_IPV6_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_SRC, 16)
+ //#define OXM_OF_IPV6_DST OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_DST, 16)
+ //#define OXM_OF_IPV6_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_DST, 16)
+ bytes ipv6_src = 29; /* For OFPXMT_OFB_IPV6_SRC */
+ bytes ipv6_dst = 30; /* For OFPXMT_OFB_IPV6_DST */
+
+ /* The IPv6 Flow Label
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly
+ *
+ * Format: 32-bit integer with 12 most-significant bits forced to 0.
+ * Only the lower 20 bits have meaning.
+ *
+ * Masking: Arbitrary masks.
+ */
+ //#define OXM_OF_IPV6_FLABEL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_FLABEL, 4)
+ //#define OXM_OF_IPV6_FLABEL_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_FLABEL, 4)
+ uint32 ipv6_flabel = 31; /* For OFPXMT_OFB_IPV6_FLABEL */
+
+ /* The type or code in the ICMPv6 header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ * OXM_OF_IP_PROTO must match 58 exactly.
+ *
+ * Format: 8-bit integer.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_ICMPV6_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV6_TYPE, 1)
+ //#define OXM_OF_ICMPV6_CODE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV6_CODE, 1)
+ uint32 icmpv6_type = 32; /* For OFPXMT_OFB_ICMPV6_TYPE */
+ uint32 icmpv6_code = 33; /* For OFPXMT_OFB_ICMPV6_CODE */
+
+ /* The target address in an IPv6 Neighbor Discovery message.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ * OXM_OF_IP_PROTO must match 58 exactly.
+ * OXM_OF_ICMPV6_TYPE must be either 135 or 136.
+ *
+ * Format: 128-bit IPv6 address.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IPV6_ND_TARGET OXM_HEADER \
+ // (0x8000, OFPXMT_OFB_IPV6_ND_TARGET, 16)
+ bytes ipv6_nd_target = 34; /* For OFPXMT_OFB_IPV6_ND_TARGET */
+
+ /* The source link-layer address option in an IPv6 Neighbor Discovery
+ * message.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ * OXM_OF_IP_PROTO must match 58 exactly.
+ * OXM_OF_ICMPV6_TYPE must be exactly 135.
+ *
+ * Format: 48-bit Ethernet MAC address.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IPV6_ND_SLL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_SLL, 6)
+ bytes ipv6_nd_ssl = 35; /* For OFPXMT_OFB_IPV6_ND_SLL */
+
+ /* The target link-layer address option in an IPv6 Neighbor Discovery
+ * message.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly.
+ * OXM_OF_IP_PROTO must match 58 exactly.
+ * OXM_OF_ICMPV6_TYPE must be exactly 136.
+ *
+ * Format: 48-bit Ethernet MAC address.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_IPV6_ND_TLL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_TLL, 6)
+ bytes ipv6_nd_tll = 36; /* For OFPXMT_OFB_IPV6_ND_TLL */
+
+ /* The LABEL in the first MPLS shim header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly.
+ *
+ * Format: 32-bit integer in network byte order with 12 most-significant
+ * bits forced to 0. Only the lower 20 bits have meaning.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_MPLS_LABEL OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_LABEL, 4)
+ uint32 mpls_label = 37; /* For OFPXMT_OFB_MPLS_LABEL */
+
+ /* The TC in the first MPLS shim header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly.
+ *
+ * Format: 8-bit integer with 5 most-significant bits forced to 0.
+ * Only the lower 3 bits have meaning.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_MPLS_TC OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_TC, 1)
+ uint32 mpls_tc = 38; /* For OFPXMT_OFB_MPLS_TC */
+
+ /* The BoS bit in the first MPLS shim header.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly.
+ *
+ * Format: 8-bit integer with 7 most-significant bits forced to 0.
+ * Only the lowest bit have a meaning.
+ *
+ * Masking: Not maskable. */
+ //#define OXM_OF_MPLS_BOS OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_BOS, 1)
+ uint32 mpls_bos = 39; /* For OFPXMT_OFB_MPLS_BOS */
+
+ /* IEEE 802.1ah I-SID.
+ *
+ * For a packet with a PBB header, this is the I-SID from the
+ * outermost service tag.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x88E7 exactly.
+ *
+ * Format: 24-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks. */
+ //#define OXM_OF_PBB_ISID OXM_HEADER (0x8000, OFPXMT_OFB_PBB_ISID, 3)
+ //#define OXM_OF_PBB_ISID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_PBB_ISID, 3)
+ uint32 pbb_isid = 40; /* For OFPXMT_OFB_PBB_ISID */
+
+ /* Logical Port Metadata.
+ *
+ * Metadata associated with a logical port.
+ * If the logical port performs encapsulation and decapsulation, this
+ * is the demultiplexing field from the encapsulation header.
+ * For example, for a packet received via GRE tunnel including a (32-bit) key,
+ * the key is stored in the low 32-bits and the high bits are zeroed.
+ * For a MPLS logical port, the low 20 bits represent the MPLS Label.
+ * For a VxLAN logical port, the low 24 bits represent the VNI.
+ * If the packet is not received through a logical port, the value is 0.
+ *
+ * Prereqs: None.
+ *
+ * Format: 64-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks. */
+ //#define OXM_OF_TUNNEL_ID OXM_HEADER (0x8000, OFPXMT_OFB_TUNNEL_ID, 8)
+ //#define OXM_OF_TUNNEL_ID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_TUNNEL_ID, 8)
+ uint64 tunnel_id = 41; /* For OFPXMT_OFB_TUNNEL_ID */
+
+ /* The IPv6 Extension Header pseudo-field.
+ *
+ * Prereqs:
+ * OXM_OF_ETH_TYPE must match 0x86dd exactly
+ *
+ * Format: 16-bit integer with 7 most-significant bits forced to 0.
+ * Only the lower 9 bits have meaning.
+ *
+ * Masking: Maskable. */
+ //#define OXM_OF_IPV6_EXTHDR OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_EXTHDR, 2)
+ //#define OXM_OF_IPV6_EXTHDR_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_EXTHDR, 2)
+ uint32 ipv6_exthdr = 42; /* For OFPXMT_OFB_IPV6_EXTHDR */
+
+ }
+
+ /* Optional mask values (must be present when has_mask is true */
+ oneof mask {
+ uint64 table_metadata_mask = 105; /* For OFPXMT_OFB_METADATA */
+
+ bytes eth_dst_mask = 106; /* For OFPXMT_OFB_ETH_DST (exactly 6 bytes)*/
+ bytes eth_src_mask = 107; /* For OFPXMT_OFB_ETH_SRC (exactly 6 bytes)*/
+
+ uint32 vlan_vid_mask = 109; /* For OFPXMT_OFB_VLAN_VID */
+
+ uint32 ipv4_src_mask = 114; /* For OFPXMT_OFB_IPV4_SRC */
+ uint32 ipv4_dst_mask = 115; /* For OFPXMT_OFB_IPV4_DST */
+
+ uint32 arp_spa_mask = 125; /* For OFPXMT_OFB_ARP_SPA */
+ uint32 arp_tpa_mask = 126; /* For OFPXMT_OFB_ARP_TPA */
+
+ bytes ipv6_src_mask = 129; /* For OFPXMT_OFB_IPV6_SRC */
+ bytes ipv6_dst_mask = 130; /* For OFPXMT_OFB_IPV6_DST */
+
+ uint32 ipv6_flabel_mask = 131; /* For OFPXMT_OFB_IPV6_FLABEL */
+
+ uint32 pbb_isid_mask = 140; /* For OFPXMT_OFB_PBB_ISID */
+
+ uint64 tunnel_id_mask = 141; /* For OFPXMT_OFB_TUNNEL_ID */
+
+ uint32 ipv6_exthdr_mask = 142; /* For OFPXMT_OFB_IPV6_EXTHDR */
+ }
+
+}
+//#define OFPXMT_OFB_ALL ((UINT64_C(1) << 40) - 1)
+
+
+/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate
+ * special conditions.
+ */
+enum ofp_vlan_id {
+ OFPVID_NONE = 0x0000; /* No VLAN id was set. */
+ OFPVID_PRESENT = 0x1000; /* Bit that indicate that a VLAN id is set */
+};
+/* Define for compatibility */
+//#define OFP_VLAN_NONE OFPVID_NONE
+
+/* Bit definitions for IPv6 Extension Header pseudo-field. */
+enum ofp_ipv6exthdr_flags {
+ OFPIEH_INVALID = 0;
+ OFPIEH_NONEXT = 1; /* "No next header" encountered. */
+ OFPIEH_ESP = 2; /* Encrypted Sec Payload header present. */
+ OFPIEH_AUTH = 4; /* Authentication header present. */
+ OFPIEH_DEST = 8; /* 1 or 2 dest headers present. */
+ OFPIEH_FRAG = 16; /* Fragment header present. */
+ OFPIEH_ROUTER = 32; /* Router header present. */
+ OFPIEH_HOP = 64; /* Hop-by-hop header present. */
+ OFPIEH_UNREP = 128; /* Unexpected repeats encountered. */
+ OFPIEH_UNSEQ = 256; /* Unexpected sequencing encountered. */
+};
+
+/* Header for OXM experimenter match fields.
+ * The experimenter class should not use OXM_HEADER() macros for defining
+ * fields due to this extra header. */
+message ofp_oxm_experimenter_field {
+ uint32 oxm_header = 1; /* oxm_class = OFPXMC_EXPERIMENTER */
+ uint32 experimenter = 2; /* Experimenter ID which takes the same
+ form as in struct ofp_experimenter_header. */
+};
+
+/* ## ----------------- ## */
+/* ## OpenFlow Actions. ## */
+/* ## ----------------- ## */
+
+enum ofp_action_type {
+ OFPAT_OUTPUT = 0; /* Output to switch port. */
+ OFPAT_COPY_TTL_OUT = 11; /* Copy TTL "outwards" -- from next-to-outermost
+ to outermost */
+ OFPAT_COPY_TTL_IN = 12; /* Copy TTL "inwards" -- from outermost to
+ next-to-outermost */
+ OFPAT_SET_MPLS_TTL = 15; /* MPLS TTL */
+ OFPAT_DEC_MPLS_TTL = 16; /* Decrement MPLS TTL */
+
+ OFPAT_PUSH_VLAN = 17; /* Push a new VLAN tag */
+ OFPAT_POP_VLAN = 18; /* Pop the outer VLAN tag */
+ OFPAT_PUSH_MPLS = 19; /* Push a new MPLS tag */
+ OFPAT_POP_MPLS = 20; /* Pop the outer MPLS tag */
+ OFPAT_SET_QUEUE = 21; /* Set queue id when outputting to a port */
+ OFPAT_GROUP = 22; /* Apply group. */
+ OFPAT_SET_NW_TTL = 23; /* IP TTL. */
+ OFPAT_DEC_NW_TTL = 24; /* Decrement IP TTL. */
+ OFPAT_SET_FIELD = 25; /* Set a header field using OXM TLV format. */
+ OFPAT_PUSH_PBB = 26; /* Push a new PBB service tag (I-TAG) */
+ OFPAT_POP_PBB = 27; /* Pop the outer PBB service tag (I-TAG) */
+ OFPAT_EXPERIMENTER = 0xffff;
+};
+
+/* Action header that is common to all actions. The length includes the
+ * header and any padding used to make the action 64-bit aligned.
+ * NB: The length of an action *must* always be a multiple of eight. */
+message ofp_action {
+ ofp_action_type type = 1; /* One of OFPAT_*. */
+ oneof action {
+ ofp_action_output output = 2;
+ ofp_action_mpls_ttl mpls_ttl = 3;
+ ofp_action_push push = 4;
+ ofp_action_pop_mpls pop_mpls = 5;
+ ofp_action_group group = 6;
+ ofp_action_nw_ttl nw_ttl = 7;
+ ofp_action_set_field set_field = 8;
+ ofp_action_experimenter experimenter = 9;
+ }
+};
+
+enum ofp_controller_max_len {
+ OFPCML_INVALID = 0;
+ OFPCML_MAX = 0xffe5; /* maximum max_len value which can be used
+ to request a specific byte length. */
+ OFPCML_NO_BUFFER = 0xffff; /* indicates that no buffering should be
+ applied and the whole packet is to be
+ sent to the controller. */
+};
+
+/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
+ * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
+ * number of bytes to send. A 'max_len' of zero means no bytes of the
+ * packet should be sent. A 'max_len' of OFPCML_NO_BUFFER means that
+ * the packet is not buffered and the complete packet is to be sent to
+ * the controller. */
+message ofp_action_output {
+ uint32 port = 1; /* Output port. */
+ uint32 max_len = 2; /* Max length to send to controller. */
+};
+
+/* Action structure for OFPAT_SET_MPLS_TTL. */
+message ofp_action_mpls_ttl {
+ uint32 mpls_ttl = 1; /* MPLS TTL */
+};
+
+/* Action structure for OFPAT_PUSH_VLAN/MPLS/PBB. */
+message ofp_action_push {
+ uint32 ethertype = 1; /* Ethertype */
+};
+
+/* Action structure for OFPAT_POP_MPLS. */
+message ofp_action_pop_mpls {
+ uint32 ethertype = 1; /* Ethertype */
+};
+
+/* Action structure for OFPAT_GROUP. */
+message ofp_action_group {
+ uint32 group_id = 1; /* Group identifier. */
+};
+
+/* Action structure for OFPAT_SET_NW_TTL. */
+message ofp_action_nw_ttl {
+ uint32 nw_ttl = 1; /* IP TTL */
+};
+
+/* Action structure for OFPAT_SET_FIELD. */
+message ofp_action_set_field {
+ ofp_oxm_field field = 1;
+};
+
+/* Action header for OFPAT_EXPERIMENTER.
+ * The rest of the body is experimenter-defined. */
+message ofp_action_experimenter {
+ uint32 experimenter = 1; /* Experimenter ID which takes the same
+ form as in struct
+ ofp_experimenter_header. */
+ bytes data = 2;
+};
+
+/* ## ---------------------- ## */
+/* ## OpenFlow Instructions. ## */
+/* ## ---------------------- ## */
+
+enum ofp_instruction_type {
+ OFPIT_INVALID = 0;
+ OFPIT_GOTO_TABLE = 1; /* Setup the next table in the lookup
+ pipeline */
+ OFPIT_WRITE_METADATA = 2; /* Setup the metadata field for use later in
+ pipeline */
+ OFPIT_WRITE_ACTIONS = 3; /* Write the action(s) onto the datapath action
+ set */
+ OFPIT_APPLY_ACTIONS = 4; /* Applies the action(s) immediately */
+ OFPIT_CLEAR_ACTIONS = 5; /* Clears all actions from the datapath
+ action set */
+ OFPIT_METER = 6; /* Apply meter (rate limiter) */
+
+ OFPIT_EXPERIMENTER = 0xFFFF; /* Experimenter instruction */
+};
+
+/* Instruction header that is common to all instructions. The length includes
+ * the header and any padding used to make the instruction 64-bit aligned.
+ * NB: The length of an instruction *must* always be a multiple of eight. */
+message ofp_instruction {
+ uint32 type = 1; /* Instruction type */
+ oneof data {
+ ofp_instruction_goto_table goto_table = 2;
+ ofp_instruction_write_metadata write_metadata = 3;
+ ofp_instruction_actions actions = 4;
+ ofp_instruction_meter meter = 5;
+ ofp_instruction_experimenter experimenter = 6;
+ }
+};
+
+/* Instruction structure for OFPIT_GOTO_TABLE */
+message ofp_instruction_goto_table {
+ uint32 table_id = 1; /* Set next table in the lookup pipeline */
+};
+
+/* Instruction structure for OFPIT_WRITE_METADATA */
+message ofp_instruction_write_metadata {
+ uint64 metadata = 1; /* Metadata value to write */
+ uint64 metadata_mask = 2; /* Metadata write bitmask */
+};
+
+/* Instruction structure for OFPIT_WRITE/APPLY/CLEAR_ACTIONS */
+message ofp_instruction_actions {
+ repeated ofp_action actions = 1; /* 0 or more actions associated
+ with OFPIT_WRITE_ACTIONS and
+ OFPIT_APPLY_ACTIONS */
+};
+
+/* Instruction structure for OFPIT_METER */
+message ofp_instruction_meter {
+ uint32 meter_id = 1; /* Meter instance. */
+};
+
+/* Instruction structure for experimental instructions */
+message ofp_instruction_experimenter {
+ uint32 experimenter = 1; /* Experimenter ID which takes the same form
+ as in struct ofp_experimenter_header. */
+ /* Experimenter-defined arbitrary additional data. */
+ bytes data = 2;
+};
+
+/* ## --------------------------- ## */
+/* ## OpenFlow Flow Modification. ## */
+/* ## --------------------------- ## */
+
+enum ofp_flow_mod_command {
+ OFPFC_ADD = 0; /* New flow. */
+ OFPFC_MODIFY = 1; /* Modify all matching flows. */
+ OFPFC_MODIFY_STRICT = 2; /* Modify entry strictly matching wildcards and
+ priority. */
+ OFPFC_DELETE = 3; /* Delete all matching flows. */
+ OFPFC_DELETE_STRICT = 4; /* Delete entry strictly matching wildcards and
+ priority. */
+};
+
+/* Value used in "idle_timeout" and "hard_timeout" to indicate that the entry
+ * is permanent. */
+//#define OFP_FLOW_PERMANENT 0
+
+/* By default, choose a priority in the middle. */
+//#define OFP_DEFAULT_PRIORITY 0x8000
+
+enum ofp_flow_mod_flags {
+ OFPFF_INVALID = 0;
+ OFPFF_SEND_FLOW_REM = 1; /* Send flow removed message when flow
+ * expires or is deleted. */
+ OFPFF_CHECK_OVERLAP = 2; /* Check for overlapping entries first. */
+ OFPFF_RESET_COUNTS = 4; /* Reset flow packet and byte counts. */
+ OFPFF_NO_PKT_COUNTS = 8; /* Don't keep track of packet count. */
+ OFPFF_NO_BYT_COUNTS = 16; /* Don't keep track of byte count. */
+};
+
+/* Flow setup and teardown (controller -> datapath). */
+message ofp_flow_mod {
+ //ofp_header header;
+ uint64 cookie = 1; /* Opaque controller-issued identifier. */
+ uint64 cookie_mask = 2; /* Mask used to restrict the cookie bits
+ that must match when the command is
+ OFPFC_MODIFY* or OFPFC_DELETE*. A value
+ of 0 indicates no restriction. */
+ uint32 table_id = 3; /* ID of the table to put the flow in.
+ For OFPFC_DELETE_* commands, OFPTT_ALL
+ can also be used to delete matching
+ flows from all tables. */
+ ofp_flow_mod_command command = 4; /* One of OFPFC_*. */
+ uint32 idle_timeout = 5; /* Idle time before discarding (seconds). */
+ uint32 hard_timeout = 6; /* Max time before discarding (seconds). */
+ uint32 priority = 7; /* Priority level of flow entry. */
+ uint32 buffer_id = 8; /* Buffered packet to apply to, or
+ OFP_NO_BUFFER.
+ Not meaningful for OFPFC_DELETE*. */
+ uint32 out_port = 9; /* For OFPFC_DELETE* commands, require
+ matching entries to include this as an
+ output port. A value of OFPP_ANY
+ indicates no restriction. */
+ uint32 out_group = 10; /* For OFPFC_DELETE* commands, require
+ matching entries to include this as an
+ output group. A value of OFPG_ANY
+ indicates no restriction. */
+ uint32 flags = 11; /* Bitmap of OFPFF_* flags. */
+ ofp_match match = 12; /* Fields to match. Variable size. */
+ repeated ofp_instruction instructions = 13; /* 0 or more. */
+};
+
+/* Group numbering. Groups can use any number up to OFPG_MAX. */
+enum ofp_group {
+
+ OFPG_INVALID = 0;
+
+ /* Last usable group number. */
+ OFPG_MAX = 0x7fffff00;
+
+ /* Fake groups. */
+ OFPG_ALL = 0x7ffffffc; /* Represents all groups for group delete
+ commands. */
+ OFPG_ANY = 0x7fffffff; /* Special wildcard: no group specified. */
+};
+
+/* Group commands */
+enum ofp_group_mod_command {
+ OFPGC_ADD = 0; /* New group. */
+ OFPGC_MODIFY = 1; /* Modify all matching groups. */
+ OFPGC_DELETE = 2; /* Delete all matching groups. */
+};
+
+/* Bucket for use in groups. */
+message ofp_bucket {
+ uint32 weight = 1; /* Relative weight of bucket. Only
+ defined for select groups. */
+ uint32 watch_port = 2; /* Port whose state affects whether this
+ bucket is live. Only required for fast
+ failover groups. */
+ uint32 watch_group = 3; /* Group whose state affects whether this
+ bucket is live. Only required for fast
+ failover groups. */
+ repeated ofp_action actions = 4;
+};
+
+/* Group setup and teardown (controller -> datapath). */
+message ofp_group_mod {
+ //ofp_header header;
+ ofp_group_mod_command command = 1; /* One of OFPGC_*. */
+ ofp_group_type type = 2; /* One of OFPGT_*. */
+ uint32 group_id = 3; /* Group identifier. */
+ repeated ofp_bucket buckets = 4;
+};
+
+/* Group types. Values in the range [128; 255] are reserved for experimental
+ * use. */
+enum ofp_group_type {
+ OFPGT_ALL = 0; /* All (multicast/broadcast) group. */
+ OFPGT_SELECT = 1; /* Select group. */
+ OFPGT_INDIRECT = 2; /* Indirect group. */
+ OFPGT_FF = 3; /* Fast failover group. */
+};
+
+/* Special buffer-id to indicate 'no buffer' */
+//#define OFP_NO_BUFFER 0xffffffff
+
+/* Send packet (controller -> datapath). */
+message ofp_packet_out {
+ //ofp_header header;
+ uint32 buffer_id = 1; /* ID assigned by datapath (OFP_NO_BUFFER
+ if none). */
+ uint32 in_port = 2; /* Packet's input port or OFPP_CONTROLLER.*/
+ repeated ofp_action actions = 3; /* Action list - 0 or more. */
+ /* The variable size action list is optionally followed by packet data.
+ * This data is only present and meaningful if buffer_id == -1. */
+ bytes data = 4; /* Packet data. */
+};
+
+/* Why is this packet being sent to the controller? */
+enum ofp_packet_in_reason {
+ OFPR_NO_MATCH = 0; /* No matching flow (table-miss flow entry). */
+ OFPR_ACTION = 1; /* Action explicitly output to controller. */
+ OFPR_INVALID_TTL = 2; /* Packet has invalid TTL */
+};
+
+/* Packet received on port (datapath -> controller). */
+message ofp_packet_in {
+ //ofp_header header;
+ uint32 buffer_id = 1; /* ID assigned by datapath. */
+ ofp_packet_in_reason reason = 2; /* Reason packet is being sent */
+ uint32 table_id = 3; /* ID of the table that was looked up */
+ uint64 cookie = 4; /* Cookie of the flow entry that was looked up. */
+ ofp_match match = 5; /* Packet metadata. Variable size. */
+ bytes data = 6; /* Ethernet frame */
+};
+
+/* Why was this flow removed? */
+enum ofp_flow_removed_reason {
+ OFPRR_IDLE_TIMEOUT = 0; /* Flow idle time exceeded idle_timeout. */
+ OFPRR_HARD_TIMEOUT = 1; /* Time exceeded hard_timeout. */
+ OFPRR_DELETE = 2; /* Evicted by a DELETE flow mod. */
+ OFPRR_GROUP_DELETE = 3; /* Group was removed. */
+ OFPRR_METER_DELETE = 4; /* Meter was removed */
+};
+
+/* Flow removed (datapath -> controller). */
+message ofp_flow_removed {
+ //ofp_header header;
+ uint64 cookie = 1; /* Opaque controller-issued identifier. */
+
+ uint32 priority = 2; /* Priority level of flow entry. */
+ ofp_flow_removed_reason reason = 3; /* One of OFPRR_*. */
+ uint32 table_id = 4; /* ID of the table */
+
+ uint32 duration_sec = 5; /* Time flow was alive in seconds. */
+ uint32 duration_nsec = 6; /* Time flow was alive in nanoseconds beyond
+ duration_sec. */
+ uint32 idle_timeout = 7; /* Idle timeout from original flow mod. */
+ uint32 hard_timeout = 8; /* Hard timeout from original flow mod. */
+ uint64 packet_count = 9;
+ uint64 byte_count = 10;
+ ofp_match match = 121; /* Description of fields. Variable size. */
+};
+
+/* Meter numbering. Flow meters can use any number up to OFPM_MAX. */
+enum ofp_meter {
+ OFPM_ZERO = 0;
+ /* Last usable meter. */
+ OFPM_MAX = 0x7fff0000;
+
+ /* Virtual meters. */
+ OFPM_SLOWPATH = 0x7ffffffd; /* Meter for slow datapath. */
+ OFPM_CONTROLLER = 0x7ffffffe; /* Meter for controller connection. */
+ OFPM_ALL = 0x7fffffff; /* Represents all meters for stat requests
+ commands. */
+};
+
+/* Meter band types */
+enum ofp_meter_band_type {
+ OFPMBT_INVALID = 0;
+ OFPMBT_DROP = 1; /* Drop packet. */
+ OFPMBT_DSCP_REMARK = 2; /* Remark DSCP in the IP header. */
+ OFPMBT_EXPERIMENTER = 0xFFFF; /* Experimenter meter band. */
+};
+
+/* Common header for all meter bands */
+message ofp_meter_band_header {
+ ofp_meter_band_type type = 1; /* One of OFPMBT_*. */
+ uint32 len = 2; /* Length in bytes of this band. */
+ uint32 rate = 3; /* Rate for this band. */
+ uint32 burst_size = 4;/* Size of bursts. */
+};
+
+/* OFPMBT_DROP band - drop packets */
+message ofp_meter_band_drop {
+ uint32 type = 1; /* OFPMBT_DROP. */
+ uint32 len = 2; /* Length in bytes of this band. */
+ uint32 rate = 3; /* Rate for dropping packets. */
+ uint32 burst_size = 4;/* Size of bursts. */
+};
+
+/* OFPMBT_DSCP_REMARK band - Remark DSCP in the IP header */
+message ofp_meter_band_dscp_remark {
+ uint32 type = 1; /* OFPMBT_DSCP_REMARK. */
+ uint32 len = 2; /* Length in bytes of this band. */
+ uint32 rate = 3; /* Rate for remarking packets. */
+ uint32 burst_size = 4; /* Size of bursts. */
+ uint32 prec_level = 5; /* Number of drop precedence level to add. */
+};
+
+/* OFPMBT_EXPERIMENTER band - Experimenter type.
+ * The rest of the band is experimenter-defined. */
+message ofp_meter_band_experimenter {
+ ofp_meter_band_type type = 1; /* One of OFPMBT_*. */
+ uint32 len = 2; /* Length in bytes of this band. */
+ uint32 rate = 3; /* Rate for this band. */
+ uint32 burst_size = 4; /* Size of bursts. */
+ uint32 experimenter = 5;/* Experimenter ID which takes the
+ same form as in struct
+ ofp_experimenter_header. */
+};
+
+/* Meter commands */
+enum ofp_meter_mod_command {
+ OFPMC_ADD = 0; /* New meter. */
+ OFPMC_MODIFY = 1; /* Modify specified meter. */
+ OFPMC_DELETE = 2; /* Delete specified meter. */
+};
+
+/* Meter configuration flags */
+enum ofp_meter_flags {
+ OFPMF_INVALID = 0;
+ OFPMF_KBPS = 1; /* Rate value in kb/s (kilo-bit per second). */
+ OFPMF_PKTPS = 2; /* Rate value in packet/sec. */
+ OFPMF_BURST = 4; /* Do burst size. */
+ OFPMF_STATS = 8; /* Collect statistics. */
+};
+
+/* Meter configuration. OFPT_METER_MOD. */
+message ofp_meter_mod {
+// ofp_header header = 1;
+ ofp_meter_mod_command command = 1; /* One of OFPMC_*. */
+ uint32 flags = 2; /* Bitmap of OFPMF_* flags. */
+ uint32 meter_id = 3; /* Meter instance. */
+ repeated ofp_meter_band_header bands = 4; /* The band list length is
+ inferred from the length field
+ in the header. */
+};
+
+/* Values for 'type' in ofp_error_message. These values are immutable: they
+ * will not change in future versions of the protocol (although new values may
+ * be added). */
+enum ofp_error_type {
+ OFPET_HELLO_FAILED = 0; /* Hello protocol failed. */
+ OFPET_BAD_REQUEST = 1; /* Request was not understood. */
+ OFPET_BAD_ACTION = 2; /* Error in action description. */
+ OFPET_BAD_INSTRUCTION = 3; /* Error in instruction list. */
+ OFPET_BAD_MATCH = 4; /* Error in match. */
+ OFPET_FLOW_MOD_FAILED = 5; /* Problem modifying flow entry. */
+ OFPET_GROUP_MOD_FAILED = 6; /* Problem modifying group entry. */
+ OFPET_PORT_MOD_FAILED = 7; /* Port mod request failed. */
+ OFPET_TABLE_MOD_FAILED = 8; /* Table mod request failed. */
+ OFPET_QUEUE_OP_FAILED = 9; /* Queue operation failed. */
+ OFPET_SWITCH_CONFIG_FAILED = 10; /* Switch config request failed. */
+ OFPET_ROLE_REQUEST_FAILED = 11; /* Controller Role request failed. */
+ OFPET_METER_MOD_FAILED = 12; /* Error in meter. */
+ OFPET_TABLE_FEATURES_FAILED = 13; /* Setting table features failed. */
+ OFPET_EXPERIMENTER = 0xffff; /* Experimenter error messages. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_HELLO_FAILED. 'data' contains an
+ * ASCII text string that may give failure details. */
+enum ofp_hello_failed_code {
+ OFPHFC_INCOMPATIBLE = 0; /* No compatible version. */
+ OFPHFC_EPERM = 1; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_BAD_REQUEST. 'data' contains at least
+ * the first 64 bytes of the failed request. */
+enum ofp_bad_request_code {
+ OFPBRC_BAD_VERSION = 0; /* ofp_header.version not supported. */
+ OFPBRC_BAD_TYPE = 1; /* ofp_header.type not supported. */
+ OFPBRC_BAD_MULTIPART = 2; /* ofp_multipart_request.type not supported.
+ */
+ OFPBRC_BAD_EXPERIMENTER = 3; /* Experimenter id not supported
+ * (in ofp_experimenter_header or
+ * ofp_multipart_request or
+ * ofp_multipart_reply). */
+ OFPBRC_BAD_EXP_TYPE = 4; /* Experimenter type not supported. */
+ OFPBRC_EPERM = 5; /* Permissions error. */
+ OFPBRC_BAD_LEN = 6; /* Wrong request length for type. */
+ OFPBRC_BUFFER_EMPTY = 7; /* Specified buffer has already been used. */
+ OFPBRC_BUFFER_UNKNOWN = 8; /* Specified buffer does not exist. */
+ OFPBRC_BAD_TABLE_ID = 9; /* Specified table-id invalid or does not
+ * exist. */
+ OFPBRC_IS_SLAVE = 10; /* Denied because controller is slave. */
+ OFPBRC_BAD_PORT = 11; /* Invalid port. */
+ OFPBRC_BAD_PACKET = 12; /* Invalid packet in packet-out. */
+ OFPBRC_MULTIPART_BUFFER_OVERFLOW = 13; /* ofp_multipart_request
+ overflowed the assigned buffer. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_BAD_ACTION. 'data' contains at least
+ * the first 64 bytes of the failed request. */
+enum ofp_bad_action_code {
+ OFPBAC_BAD_TYPE = 0; /* Unknown or unsupported action type. */
+ OFPBAC_BAD_LEN = 1; /* Length problem in actions. */
+ OFPBAC_BAD_EXPERIMENTER = 2; /* Unknown experimenter id specified. */
+ OFPBAC_BAD_EXP_TYPE = 3; /* Unknown action for experimenter id. */
+ OFPBAC_BAD_OUT_PORT = 4; /* Problem validating output port. */
+ OFPBAC_BAD_ARGUMENT = 5; /* Bad action argument. */
+ OFPBAC_EPERM = 6; /* Permissions error. */
+ OFPBAC_TOO_MANY = 7; /* Can't handle this many actions. */
+ OFPBAC_BAD_QUEUE = 8; /* Problem validating output queue. */
+ OFPBAC_BAD_OUT_GROUP = 9; /* Invalid group id in forward action. */
+ OFPBAC_MATCH_INCONSISTENT = 10; /* Action can't apply for this match,
+ or Set-Field missing prerequisite. */
+ OFPBAC_UNSUPPORTED_ORDER = 11; /* Action order is unsupported for the
+ action list in an Apply-Actions instruction */
+ OFPBAC_BAD_TAG = 12; /* Actions uses an unsupported
+ tag/encap. */
+ OFPBAC_BAD_SET_TYPE = 13; /* Unsupported type in SET_FIELD action. */
+ OFPBAC_BAD_SET_LEN = 14; /* Length problem in SET_FIELD action. */
+ OFPBAC_BAD_SET_ARGUMENT = 15; /* Bad argument in SET_FIELD action. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_BAD_INSTRUCTION. 'data' contains at
+ * least the first 64 bytes of the failed request. */
+enum ofp_bad_instruction_code {
+ OFPBIC_UNKNOWN_INST = 0; /* Unknown instruction. */
+ OFPBIC_UNSUP_INST = 1; /* Switch or table does not support the
+ instruction. */
+ OFPBIC_BAD_TABLE_ID = 2; /* Invalid Table-ID specified. */
+ OFPBIC_UNSUP_METADATA = 3; /* Metadata value unsupported by datapath. */
+ OFPBIC_UNSUP_METADATA_MASK = 4; /* Metadata mask value unsupported by
+ datapath. */
+ OFPBIC_BAD_EXPERIMENTER = 5; /* Unknown experimenter id specified. */
+ OFPBIC_BAD_EXP_TYPE = 6; /* Unknown instruction for experimenter id. */
+ OFPBIC_BAD_LEN = 7; /* Length problem in instructions. */
+ OFPBIC_EPERM = 8; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_BAD_MATCH. 'data' contains at least
+ * the first 64 bytes of the failed request. */
+enum ofp_bad_match_code {
+ OFPBMC_BAD_TYPE = 0; /* Unsupported match type specified by the
+ match */
+ OFPBMC_BAD_LEN = 1; /* Length problem in match. */
+ OFPBMC_BAD_TAG = 2; /* Match uses an unsupported tag/encap. */
+ OFPBMC_BAD_DL_ADDR_MASK = 3; /* Unsupported datalink addr mask - switch
+ does not support arbitrary datalink
+ address mask. */
+ OFPBMC_BAD_NW_ADDR_MASK = 4; /* Unsupported network addr mask - switch
+ does not support arbitrary network
+ address mask. */
+ OFPBMC_BAD_WILDCARDS = 5; /* Unsupported combination of fields masked
+ or omitted in the match. */
+ OFPBMC_BAD_FIELD = 6; /* Unsupported field type in the match. */
+ OFPBMC_BAD_VALUE = 7; /* Unsupported value in a match field. */
+ OFPBMC_BAD_MASK = 8; /* Unsupported mask specified in the match,
+ field is not dl-address or nw-address. */
+ OFPBMC_BAD_PREREQ = 9; /* A prerequisite was not met. */
+ OFPBMC_DUP_FIELD = 10; /* A field type was duplicated. */
+ OFPBMC_EPERM = 11; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_flow_mod_failed_code {
+ OFPFMFC_UNKNOWN = 0; /* Unspecified error. */
+ OFPFMFC_TABLE_FULL = 1; /* Flow not added because table was full. */
+ OFPFMFC_BAD_TABLE_ID = 2; /* Table does not exist */
+ OFPFMFC_OVERLAP = 3; /* Attempted to add overlapping flow with
+ CHECK_OVERLAP flag set. */
+ OFPFMFC_EPERM = 4; /* Permissions error. */
+ OFPFMFC_BAD_TIMEOUT = 5; /* Flow not added because of unsupported
+ idle/hard timeout. */
+ OFPFMFC_BAD_COMMAND = 6; /* Unsupported or unknown command. */
+ OFPFMFC_BAD_FLAGS = 7; /* Unsupported or unknown flags. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_GROUP_MOD_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_group_mod_failed_code {
+ OFPGMFC_GROUP_EXISTS = 0; /* Group not added because a group ADD
+ attempted to replace an
+ already-present group. */
+ OFPGMFC_INVALID_GROUP = 1; /* Group not added because Group
+ specified is invalid. */
+ OFPGMFC_WEIGHT_UNSUPPORTED = 2; /* Switch does not support unequal load
+ sharing with select groups. */
+ OFPGMFC_OUT_OF_GROUPS = 3; /* The group table is full. */
+ OFPGMFC_OUT_OF_BUCKETS = 4; /* The maximum number of action buckets
+ for a group has been exceeded. */
+ OFPGMFC_CHAINING_UNSUPPORTED = 5; /* Switch does not support groups that
+ forward to groups. */
+ OFPGMFC_WATCH_UNSUPPORTED = 6; /* This group cannot watch the
+ watch_port or watch_group specified.
+ */
+ OFPGMFC_LOOP = 7; /* Group entry would cause a loop. */
+ OFPGMFC_UNKNOWN_GROUP = 8; /* Group not modified because a group
+ MODIFY attempted to modify a
+ non-existent group. */
+ OFPGMFC_CHAINED_GROUP = 9; /* Group not deleted because another
+ group is forwarding to it. */
+ OFPGMFC_BAD_TYPE = 10; /* Unsupported or unknown group type. */
+ OFPGMFC_BAD_COMMAND = 11; /* Unsupported or unknown command. */
+ OFPGMFC_BAD_BUCKET = 12; /* Error in bucket. */
+ OFPGMFC_BAD_WATCH = 13; /* Error in watch port/group. */
+ OFPGMFC_EPERM = 14; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_port_mod_failed_code {
+ OFPPMFC_BAD_PORT = 0; /* Specified port number does not exist. */
+ OFPPMFC_BAD_HW_ADDR = 1; /* Specified hardware address does not
+ * match the port number. */
+ OFPPMFC_BAD_CONFIG = 2; /* Specified config is invalid. */
+ OFPPMFC_BAD_ADVERTISE = 3; /* Specified advertise is invalid. */
+ OFPPMFC_EPERM = 4; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_TABLE_MOD_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_table_mod_failed_code {
+ OFPTMFC_BAD_TABLE = 0; /* Specified table does not exist. */
+ OFPTMFC_BAD_CONFIG = 1; /* Specified config is invalid. */
+ OFPTMFC_EPERM = 2; /* Permissions error. */
+};
+
+/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request */
+enum ofp_queue_op_failed_code {
+ OFPQOFC_BAD_PORT = 0; /* Invalid port (or port does not exist). */
+ OFPQOFC_BAD_QUEUE = 1; /* Queue does not exist. */
+ OFPQOFC_EPERM = 2; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_SWITCH_CONFIG_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_switch_config_failed_code {
+ OFPSCFC_BAD_FLAGS = 0; /* Specified flags is invalid. */
+ OFPSCFC_BAD_LEN = 1; /* Specified len is invalid. */
+ OFPSCFC_EPERM = 2; /* Permissions error. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_ROLE_REQUEST_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_role_request_failed_code {
+ OFPRRFC_STALE = 0; /* Stale Message: old generation_id. */
+ OFPRRFC_UNSUP = 1; /* Controller role change unsupported. */
+ OFPRRFC_BAD_ROLE = 2; /* Invalid role. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_METER_MOD_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_meter_mod_failed_code {
+ OFPMMFC_UNKNOWN = 0; /* Unspecified error. */
+ OFPMMFC_METER_EXISTS = 1; /* Meter not added because a Meter ADD
+ * attempted to replace an existing Meter. */
+ OFPMMFC_INVALID_METER = 2; /* Meter not added because Meter specified
+ * is invalid,
+ * or invalid meter in meter action. */
+ OFPMMFC_UNKNOWN_METER = 3; /* Meter not modified because a Meter MODIFY
+ * attempted to modify a non-existent Meter,
+ * or bad meter in meter action. */
+ OFPMMFC_BAD_COMMAND = 4; /* Unsupported or unknown command. */
+ OFPMMFC_BAD_FLAGS = 5; /* Flag configuration unsupported. */
+ OFPMMFC_BAD_RATE = 6; /* Rate unsupported. */
+ OFPMMFC_BAD_BURST = 7; /* Burst size unsupported. */
+ OFPMMFC_BAD_BAND = 8; /* Band unsupported. */
+ OFPMMFC_BAD_BAND_VALUE = 9; /* Band value unsupported. */
+ OFPMMFC_OUT_OF_METERS = 10; /* No more meters available. */
+ OFPMMFC_OUT_OF_BANDS = 11; /* The maximum number of properties
+ * for a meter has been exceeded. */
+};
+
+/* ofp_error_msg 'code' values for OFPET_TABLE_FEATURES_FAILED. 'data' contains
+ * at least the first 64 bytes of the failed request. */
+enum ofp_table_features_failed_code {
+ OFPTFFC_BAD_TABLE = 0; /* Specified table does not exist. */
+ OFPTFFC_BAD_METADATA = 1; /* Invalid metadata mask. */
+ OFPTFFC_BAD_TYPE = 2; /* Unknown property type. */
+ OFPTFFC_BAD_LEN = 3; /* Length problem in properties. */
+ OFPTFFC_BAD_ARGUMENT = 4; /* Unsupported property value. */
+ OFPTFFC_EPERM = 5; /* Permissions error. */
+};
+
+/* OFPT_ERROR: Error message (datapath -> controller). */
+message ofp_error_msg {
+ //ofp_header header;
+ uint32 type = 1;
+ uint32 code = 2;
+ bytes data = 3; /* Variable-length data. Interpreted based
+ on the type and code. No padding. */
+};
+
+/* OFPET_EXPERIMENTER: Error message (datapath -> controller). */
+message ofp_error_experimenter_msg {
+ //ofp_header header;
+
+ uint32 type = 1; /* OFPET_EXPERIMENTER. */
+ uint32 exp_type = 2; /* Experimenter defined. */
+ uint32 experimenter = 3; /* Experimenter ID which takes the same form
+ as in struct ofp_experimenter_header. */
+ bytes data = 4; /* Variable-length data. Interpreted based
+ on the type and code. No padding. */
+};
+
+enum ofp_multipart_type {
+ /* Description of this OpenFlow switch.
+ * The request body is empty.
+ * The reply body is struct ofp_desc. */
+ OFPMP_DESC = 0;
+
+ /* Individual flow statistics.
+ * The request body is struct ofp_flow_stats_request.
+ * The reply body is an array of struct ofp_flow_stats. */
+ OFPMP_FLOW = 1;
+
+ /* Aggregate flow statistics.
+ * The request body is struct ofp_aggregate_stats_request.
+ * The reply body is struct ofp_aggregate_stats_reply. */
+ OFPMP_AGGREGATE = 2;
+
+ /* Flow table statistics.
+ * The request body is empty.
+ * The reply body is an array of struct ofp_table_stats. */
+ OFPMP_TABLE = 3;
+
+ /* Port statistics.
+ * The request body is struct ofp_port_stats_request.
+ * The reply body is an array of struct ofp_port_stats. */
+ OFPMP_PORT_STATS = 4;
+
+ /* Queue statistics for a port
+ * The request body is struct ofp_queue_stats_request.
+ * The reply body is an array of struct ofp_queue_stats */
+ OFPMP_QUEUE = 5;
+
+ /* Group counter statistics.
+ * The request body is struct ofp_group_stats_request.
+ * The reply is an array of struct ofp_group_stats. */
+ OFPMP_GROUP = 6;
+
+ /* Group description.
+ * The request body is empty.
+ * The reply body is an array of struct ofp_group_desc. */
+ OFPMP_GROUP_DESC = 7;
+
+ /* Group features.
+ * The request body is empty.
+ * The reply body is struct ofp_group_features. */
+ OFPMP_GROUP_FEATURES = 8;
+
+ /* Meter statistics.
+ * The request body is struct ofp_meter_multipart_requests.
+ * The reply body is an array of struct ofp_meter_stats. */
+ OFPMP_METER = 9;
+
+ /* Meter configuration.
+ * The request body is struct ofp_meter_multipart_requests.
+ * The reply body is an array of struct ofp_meter_config. */
+ OFPMP_METER_CONFIG = 10;
+
+ /* Meter features.
+ * The request body is empty.
+ * The reply body is struct ofp_meter_features. */
+ OFPMP_METER_FEATURES = 11;
+
+ /* Table features.
+ * The request body is either empty or contains an array of
+ * struct ofp_table_features containing the controller's
+ * desired view of the switch. If the switch is unable to
+ * set the specified view an error is returned.
+ * The reply body is an array of struct ofp_table_features. */
+ OFPMP_TABLE_FEATURES = 12;
+
+ /* Port description.
+ * The request body is empty.
+ * The reply body is an array of struct ofp_port. */
+ OFPMP_PORT_DESC = 13;
+
+ /* Experimenter extension.
+ * The request and reply bodies begin with
+ * struct ofp_experimenter_multipart_header.
+ * The request and reply bodies are otherwise experimenter-defined. */
+ OFPMP_EXPERIMENTER = 0xffff;
+};
+
+/* Backward compatibility with 1.3.1 - avoid breaking the API. */
+//#define ofp_multipart_types ofp_multipart_type
+
+enum ofp_multipart_request_flags {
+ OFPMPF_REQ_INVALID = 0;
+ OFPMPF_REQ_MORE = 1; /* More requests to follow. */
+};
+
+message ofp_multipart_request {
+ //ofp_header header;
+ ofp_multipart_type type = 1; /* One of the OFPMP_* constants. */
+ uint32 flags = 2; /* OFPMPF_REQ_* flags. */
+ bytes body = 3; /* Body of the request. 0 or more bytes. */
+};
+
+enum ofp_multipart_reply_flags {
+ OFPMPF_REPLY_INVALID = 0;
+ OFPMPF_REPLY_MORE = 1; /* More replies to follow. */
+};
+
+message ofp_multipart_reply {
+ //ofp_header header;
+ ofp_multipart_type type = 1; /* One of the OFPMP_* constants. */
+ uint32 flags = 2; /* OFPMPF_REPLY_* flags. */
+ bytes body = 3; /* Body of the reply. 0 or more bytes. */
+};
+
+//#define DESC_STR_LEN 256
+//#define SERIAL_NUM_LEN 32
+/* Body of reply to OFPMP_DESC request. Each entry is a NULL-terminated
+ * ASCII string. */
+message ofp_desc {
+ string mfr_desc = 1; /* Manufacturer description. */
+ string hw_desc = 2; /* Hardware description. */
+ string sw_desc = 3; /* Software description. */
+ string serial_num = 4; /* Serial number. */
+ string dp_desc = 5; /* Human readable description of datapath. */
+};
+
+/* Body for ofp_multipart_request of type OFPMP_FLOW. */
+message ofp_flow_stats_request {
+ uint32 table_id = 1; /* ID of table to read (from ofp_table_stats),
+ OFPTT_ALL for all tables. */
+ uint32 out_port = 2; /* Require matching entries to include this
+ as an output port. A value of OFPP_ANY
+ indicates no restriction. */
+ uint32 out_group = 3; /* Require matching entries to include this
+ as an output group. A value of OFPG_ANY
+ indicates no restriction. */
+ uint64 cookie = 4; /* Require matching entries to contain this
+ cookie value */
+ uint64 cookie_mask = 5; /* Mask used to restrict the cookie bits that
+ must match. A value of 0 indicates
+ no restriction. */
+ ofp_match match = 6; /* Fields to match. Variable size. */
+};
+
+/* Body of reply to OFPMP_FLOW request. */
+message ofp_flow_stats {
+ uint64 id = 14; /* Unique ID of flow within device. */
+ uint32 table_id = 1; /* ID of table flow came from. */
+ uint32 duration_sec = 2; /* Time flow has been alive in seconds. */
+ uint32 duration_nsec = 3; /* Time flow has been alive in nanoseconds
+ beyond duration_sec. */
+ uint32 priority = 4; /* Priority of the entry. */
+ uint32 idle_timeout = 5; /* Number of seconds idle before expiration. */
+ uint32 hard_timeout = 6; /* Number of seconds before expiration. */
+ uint32 flags = 7; /* Bitmap of OFPFF_* flags. */
+ uint64 cookie = 8; /* Opaque controller-issued identifier. */
+ uint64 packet_count = 9; /* Number of packets in flow. */
+ uint64 byte_count = 10; /* Number of bytes in flow. */
+ ofp_match match = 12; /* Description of fields. Variable size. */
+ repeated ofp_instruction instructions = 13; /* Instruction set
+ (0 or more) */
+};
+
+/* Body for ofp_multipart_request of type OFPMP_AGGREGATE. */
+message ofp_aggregate_stats_request {
+ uint32 table_id = 1; /* ID of table to read (from ofp_table_stats)
+ OFPTT_ALL for all tables. */
+ uint32 out_port = 2; /* Require matching entries to include this
+ as an output port. A value of OFPP_ANY
+ indicates no restriction. */
+ uint32 out_group = 3; /* Require matching entries to include this
+ as an output group. A value of OFPG_ANY
+ indicates no restriction. */
+ uint64 cookie = 4; /* Require matching entries to contain this
+ cookie value */
+ uint64 cookie_mask = 5; /* Mask used to restrict the cookie bits that
+ must match. A value of 0 indicates
+ no restriction. */
+ ofp_match match = 6; /* Fields to match. Variable size. */
+};
+
+/* Body of reply to OFPMP_AGGREGATE request. */
+message ofp_aggregate_stats_reply {
+ uint64 packet_count = 1; /* Number of packets in flows. */
+ uint64 byte_count = 2; /* Number of bytes in flows. */
+ uint32 flow_count = 3; /* Number of flows. */
+};
+
+/* Table Feature property types.
+ * Low order bit cleared indicates a property for a regular Flow Entry.
+ * Low order bit set indicates a property for the Table-Miss Flow Entry.
+ */
+enum ofp_table_feature_prop_type {
+ OFPTFPT_INSTRUCTIONS = 0; /* Instructions property. */
+ OFPTFPT_INSTRUCTIONS_MISS = 1; /* Instructions for table-miss. */
+ OFPTFPT_NEXT_TABLES = 2; /* Next Table property. */
+ OFPTFPT_NEXT_TABLES_MISS = 3; /* Next Table for table-miss. */
+ OFPTFPT_WRITE_ACTIONS = 4; /* Write Actions property. */
+ OFPTFPT_WRITE_ACTIONS_MISS = 5; /* Write Actions for table-miss. */
+ OFPTFPT_APPLY_ACTIONS = 6; /* Apply Actions property. */
+ OFPTFPT_APPLY_ACTIONS_MISS = 7; /* Apply Actions for table-miss. */
+ OFPTFPT_MATCH = 8; /* Match property. */
+ OFPTFPT_WILDCARDS = 10; /* Wildcards property. */
+ OFPTFPT_WRITE_SETFIELD = 12; /* Write Set-Field property. */
+ OFPTFPT_WRITE_SETFIELD_MISS = 13; /* Write Set-Field for table-miss. */
+ OFPTFPT_APPLY_SETFIELD = 14; /* Apply Set-Field property. */
+ OFPTFPT_APPLY_SETFIELD_MISS = 15; /* Apply Set-Field for table-miss. */
+ OFPTFPT_EXPERIMENTER = 0xFFFE; /* Experimenter property. */
+ OFPTFPT_EXPERIMENTER_MISS = 0xFFFF; /* Experimenter for table-miss. */
+};
+
+/* Common header for all Table Feature Properties */
+message ofp_table_feature_property {
+ ofp_table_feature_prop_type type = 1; /* One of OFPTFPT_*. */
+ oneof value {
+ ofp_table_feature_prop_instructions instructions = 2;
+ ofp_table_feature_prop_next_tables next_tables = 3;
+ ofp_table_feature_prop_actions actions = 4;
+ ofp_table_feature_prop_oxm oxm = 5;
+ ofp_table_feature_prop_experimenter experimenter = 6;
+ }
+};
+
+/* Instructions property */
+message ofp_table_feature_prop_instructions {
+ /* One of OFPTFPT_INSTRUCTIONS,
+ OFPTFPT_INSTRUCTIONS_MISS. */
+ repeated ofp_instruction instructions = 1; /* List of instructions */
+};
+
+/* Next Tables property */
+message ofp_table_feature_prop_next_tables {
+ /* One of OFPTFPT_NEXT_TABLES,
+ OFPTFPT_NEXT_TABLES_MISS. */
+ repeated uint32 next_table_ids = 1; /* List of table ids. */
+};
+
+/* Actions property */
+message ofp_table_feature_prop_actions {
+ /* One of OFPTFPT_WRITE_ACTIONS,
+ OFPTFPT_WRITE_ACTIONS_MISS,
+ OFPTFPT_APPLY_ACTIONS,
+ OFPTFPT_APPLY_ACTIONS_MISS. */
+ repeated ofp_action actions = 1; /* List of actions */
+};
+
+/* Match, Wildcard or Set-Field property */
+message ofp_table_feature_prop_oxm {
+ /* One of OFPTFPT_MATCH,
+ OFPTFPT_WILDCARDS,
+ OFPTFPT_WRITE_SETFIELD,
+ OFPTFPT_WRITE_SETFIELD_MISS,
+ OFPTFPT_APPLY_SETFIELD,
+ OFPTFPT_APPLY_SETFIELD_MISS. */
+ /* TODO is this a uint32??? */
+ repeated uint32 oxm_ids = 3; /* Array of OXM headers */
+};
+
+/* Experimenter table feature property */
+message ofp_table_feature_prop_experimenter {
+ /* One of OFPTFPT_EXPERIMENTER,
+ OFPTFPT_EXPERIMENTER_MISS. */
+ uint32 experimenter = 2; /* Experimenter ID which takes the same
+ form as in struct
+ ofp_experimenter_header. */
+ uint32 exp_type = 3; /* Experimenter defined. */
+ repeated uint32 experimenter_data = 4;
+};
+
+/* Body for ofp_multipart_request of type OFPMP_TABLE_FEATURES./
+ * Body of reply to OFPMP_TABLE_FEATURES request. */
+message ofp_table_features {
+ uint32 table_id = 1; /* Identifier of table. Lower numbered tables
+ are consulted first. */
+ string name = 2;
+ uint64 metadata_match = 3; /* Bits of metadata table can match. */
+ uint64 metadata_write = 4; /* Bits of metadata table can write. */
+ uint32 config = 5; /* Bitmap of OFPTC_* values */
+ uint32 max_entries = 6; /* Max number of entries supported. */
+
+ /* Table Feature Property list */
+ repeated ofp_table_feature_property properties = 7;
+};
+
+/* Body of reply to OFPMP_TABLE request. */
+message ofp_table_stats {
+ uint32 table_id = 1; /* Identifier of table. Lower numbered tables
+ are consulted first. */
+ uint32 active_count = 2; /* Number of active entries. */
+ uint64 lookup_count = 3; /* Number of packets looked up in table. */
+ uint64 matched_count = 4; /* Number of packets that hit table. */
+};
+
+/* Body for ofp_multipart_request of type OFPMP_PORT. */
+message ofp_port_stats_request {
+ uint32 port_no = 1; /* OFPMP_PORT message must request statistics
+ * either for a single port (specified in
+ * port_no) or for all ports (if port_no ==
+ * OFPP_ANY). */
+};
+
+/* Body of reply to OFPMP_PORT request. If a counter is unsupported, set
+ * the field to all ones. */
+message ofp_port_stats {
+ uint32 port_no = 1;
+ uint64 rx_packets = 2; /* Number of received packets. */
+ uint64 tx_packets = 3; /* Number of transmitted packets. */
+ uint64 rx_bytes = 4; /* Number of received bytes. */
+ uint64 tx_bytes = 5; /* Number of transmitted bytes. */
+ uint64 rx_dropped = 6; /* Number of packets dropped by RX. */
+ uint64 tx_dropped = 7; /* Number of packets dropped by TX. */
+ uint64 rx_errors = 8; /* Number of receive errors. This is a super-set
+ of more specific receive errors and should be
+ greater than or equal to the sum of all
+ rx_*_err values. */
+ uint64 tx_errors = 9; /* Number of transmit errors. This is a super-set
+ of more specific transmit errors and should be
+ greater than or equal to the sum of all
+ tx_*_err values (none currently defined.) */
+ uint64 rx_frame_err = 10; /* Number of frame alignment errors. */
+ uint64 rx_over_err = 11; /* Number of packets with RX overrun. */
+ uint64 rx_crc_err = 12; /* Number of CRC errors. */
+ uint64 collisions = 13; /* Number of collisions. */
+ uint32 duration_sec = 14; /* Time port has been alive in seconds. */
+ uint32 duration_nsec = 15; /* Time port has been alive in nanoseconds
+ beyond duration_sec. */
+};
+
+/* Body of OFPMP_GROUP request. */
+message ofp_group_stats_request {
+ uint32 group_id = 1; /* All groups if OFPG_ALL. */
+};
+
+/* Used in group stats replies. */
+message ofp_bucket_counter {
+ uint64 packet_count = 1; /* Number of packets processed by bucket. */
+ uint64 byte_count = 2; /* Number of bytes processed by bucket. */
+};
+
+/* Body of reply to OFPMP_GROUP request. */
+message ofp_group_stats {
+ uint32 group_id = 1; /* Group identifier. */
+ uint32 ref_count = 2; /* Number of flows or groups that directly
+ forward to this group. */
+ uint64 packet_count = 3; /* Number of packets processed by group. */
+ uint64 byte_count = 4; /* Number of bytes processed by group. */
+ uint32 duration_sec = 5; /* Time group has been alive in seconds. */
+ uint32 duration_nsec = 6; /* Time group has been alive in nanoseconds
+ beyond duration_sec. */
+ repeated ofp_bucket_counter bucket_stats = 7; /* One counter set per
+ bucket. */
+};
+
+/* Body of reply to OFPMP_GROUP_DESC request. */
+message ofp_group_desc {
+ ofp_group_type type = 1; /* One of OFPGT_*. */
+ uint32 group_id = 2; /* Group identifier. */
+ repeated ofp_bucket buckets = 3; /* List of buckets - 0 or more. */
+};
+
+message ofp_group_entry {
+ ofp_group_desc desc = 1;
+ ofp_group_stats stats = 2;
+};
+
+/* Backward compatibility with 1.3.1 - avoid breaking the API. */
+//#define ofp_group_desc_stats ofp_group_desc
+
+/* Group configuration flags */
+enum ofp_group_capabilities {
+ OFPGFC_INVALID = 0;
+ OFPGFC_SELECT_WEIGHT = 1; /* Support weight for select groups */
+ OFPGFC_SELECT_LIVENESS = 2; /* Support liveness for select groups */
+ OFPGFC_CHAINING = 4; /* Support chaining groups */
+ OFPGFC_CHAINING_CHECKS = 8; /* Check chaining for loops and delete */
+};
+
+/* Body of reply to OFPMP_GROUP_FEATURES request. Group features. */
+message ofp_group_features {
+ uint32 types = 1; /* Bitmap of (1 << OFPGT_*) values supported. */
+ uint32 capabilities = 2; /* Bitmap of OFPGFC_* capability supported. */
+ repeated uint32 max_groups = 3; /* Maximum number of groups for each type.
+ */
+ repeated uint32 actions = 4; /* Bitmaps of (1 << OFPAT_*) values
+ supported. */
+};
+
+/* Body of OFPMP_METER and OFPMP_METER_CONFIG requests. */
+message ofp_meter_multipart_request {
+ uint32 meter_id = 1; /* Meter instance, or OFPM_ALL. */
+};
+
+/* Statistics for each meter band */
+message ofp_meter_band_stats {
+ uint64 packet_band_count = 1; /* Number of packets in band. */
+ uint64 byte_band_count = 2; /* Number of bytes in band. */
+};
+
+/* Body of reply to OFPMP_METER request. Meter statistics. */
+message ofp_meter_stats {
+ uint32 meter_id = 1; /* Meter instance. */
+ uint32 flow_count = 2; /* Number of flows bound to meter. */
+ uint64 packet_in_count = 3; /* Number of packets in input. */
+ uint64 byte_in_count = 4; /* Number of bytes in input. */
+ uint32 duration_sec = 5; /* Time meter has been alive in seconds. */
+ uint32 duration_nsec = 6;/* Time meter has been alive in nanoseconds
+ beyond duration_sec. */
+ repeated ofp_meter_band_stats band_stats = 7; /* The band_stats length is
+ inferred from the length field. */
+};
+
+/* Body of reply to OFPMP_METER_CONFIG request. Meter configuration. */
+message ofp_meter_config {
+ uint32 flags = 1; /* All OFPMF_* that apply. */
+ uint32 meter_id = 2; /* Meter instance. */
+ repeated ofp_meter_band_header bands = 3; /* The bands length is
+ inferred from the length field. */
+};
+
+/* Body of reply to OFPMP_METER_FEATURES request. Meter features. */
+message ofp_meter_features {
+ uint32 max_meter = 1; /* Maximum number of meters. */
+ uint32 band_types = 2; /* Bitmaps of (1 << OFPMBT_*) values supported.
+ */
+ uint32 capabilities = 3; /* Bitmaps of "ofp_meter_flags". */
+ uint32 max_bands = 4; /* Maximum bands per meters */
+ uint32 max_color = 5; /* Maximum color value */
+};
+
+/* Body for ofp_multipart_request/reply of type OFPMP_EXPERIMENTER. */
+message ofp_experimenter_multipart_header {
+ uint32 experimenter = 1; /* Experimenter ID which takes the same form
+ as in struct ofp_experimenter_header. */
+ uint32 exp_type = 2; /* Experimenter defined. */
+ bytes data = 3; /* Experimenter-defined arbitrary additional data. */
+};
+
+/* Experimenter extension. */
+message ofp_experimenter_header {
+ //ofp_header header; /* Type OFPT_EXPERIMENTER. */
+ uint32 experimenter = 1; /* Experimenter ID:
+ * - MSB 0: low-order bytes are IEEE OUI.
+ * - MSB != 0: defined by ONF. */
+ uint32 exp_type = 2; /* Experimenter defined. */
+ bytes data = 3; /* Experimenter-defined arbitrary additional data. */
+};
+
+/* All ones is used to indicate all queues in a port (for stats retrieval). */
+//#define OFPQ_ALL 0xffffffff
+
+/* Min rate > 1000 means not configured. */
+//#define OFPQ_MIN_RATE_UNCFG 0xffff
+
+/* Max rate > 1000 means not configured. */
+//#define OFPQ_MAX_RATE_UNCFG 0xffff
+
+enum ofp_queue_properties {
+ OFPQT_INVALID = 0;
+ OFPQT_MIN_RATE = 1; /* Minimum datarate guaranteed. */
+ OFPQT_MAX_RATE = 2; /* Maximum datarate. */
+ OFPQT_EXPERIMENTER = 0xffff; /* Experimenter defined property. */
+};
+
+/* Common description for a queue. */
+message ofp_queue_prop_header {
+ uint32 property = 1; /* One of OFPQT_. */
+ uint32 len = 2; /* Length of property, including this header. */
+};
+
+/* Min-Rate queue property description. */
+message ofp_queue_prop_min_rate {
+ ofp_queue_prop_header prop_header = 1;/* prop: OFPQT_MIN, len: 16. */
+ uint32 rate = 2; /* In 1/10 of a percent = 0;>1000 -> disabled. */
+};
+
+/* Max-Rate queue property description. */
+message ofp_queue_prop_max_rate {
+ ofp_queue_prop_header prop_header = 1;/* prop: OFPQT_MAX, len: 16. */
+ uint32 rate = 2; /* In 1/10 of a percent = 0;>1000 -> disabled. */
+};
+
+/* Experimenter queue property description. */
+message ofp_queue_prop_experimenter {
+ ofp_queue_prop_header prop_header = 1;/* prop: OFPQT_EXPERIMENTER */
+ uint32 experimenter = 2; /* Experimenter ID which takes the same
+ form as in struct
+ ofp_experimenter_header. */
+ bytes data = 3; /* Experimenter defined data. */
+};
+
+/* Full description for a queue. */
+message ofp_packet_queue {
+ uint32 queue_id = 1; /* id for the specific queue. */
+ uint32 port = 2; /* Port this queue is attached to. */
+ repeated ofp_queue_prop_header properties = 4; /* List of properties. */
+};
+
+/* Query for port queue configuration. */
+message ofp_queue_get_config_request {
+ //ofp_header header;
+ uint32 port = 1; /* Port to be queried. Should refer
+ to a valid physical port (i.e. <= OFPP_MAX),
+ or OFPP_ANY to request all configured
+ queues.*/
+};
+
+/* Queue configuration for a given port. */
+message ofp_queue_get_config_reply {
+ //ofp_header header;
+ uint32 port = 1;
+ repeated ofp_packet_queue queues = 2; /* List of configured queues. */
+};
+
+/* OFPAT_SET_QUEUE action struct: send packets to given queue on port. */
+message ofp_action_set_queue {
+ uint32 type = 1; /* OFPAT_SET_QUEUE. */
+ uint32 queue_id = 3; /* Queue id for the packets. */
+};
+
+message ofp_queue_stats_request {
+ uint32 port_no = 1; /* All ports if OFPP_ANY. */
+ uint32 queue_id = 2; /* All queues if OFPQ_ALL. */
+};
+
+message ofp_queue_stats {
+ uint32 port_no = 1;
+ uint32 queue_id = 2; /* Queue i.d */
+ uint64 tx_bytes = 3; /* Number of transmitted bytes. */
+ uint64 tx_packets = 4; /* Number of transmitted packets. */
+ uint64 tx_errors = 5; /* Number of packets dropped due to overrun. */
+ uint32 duration_sec = 6; /* Time queue has been alive in seconds. */
+ uint32 duration_nsec = 7; /* Time queue has been alive in nanoseconds
+ beyond duration_sec. */
+};
+
+/* Configures the "role" of the sending controller. The default role is:
+ *
+ * - Equal (OFPCR_ROLE_EQUAL), which allows the controller access to all
+ * OpenFlow features. All controllers have equal responsibility.
+ *
+ * The other possible roles are a related pair:
+ *
+ * - Master (OFPCR_ROLE_MASTER) is equivalent to Equal, except that there
+ * may be at most one Master controller at a time: when a controller
+ * configures itself as Master, any existing Master is demoted to the
+ * Slave role.
+ *
+ * - Slave (OFPCR_ROLE_SLAVE) allows the controller read-only access to
+ * OpenFlow features. In particular attempts to modify the flow table
+ * will be rejected with an OFPBRC_EPERM error.
+ *
+ * Slave controllers do not receive OFPT_PACKET_IN or OFPT_FLOW_REMOVED
+ * messages, but they do receive OFPT_PORT_STATUS messages.
+ */
+
+/* Controller roles. */
+enum ofp_controller_role {
+ OFPCR_ROLE_NOCHANGE = 0; /* Don't change current role. */
+ OFPCR_ROLE_EQUAL = 1; /* Default role, full access. */
+ OFPCR_ROLE_MASTER = 2; /* Full access, at most one master. */
+ OFPCR_ROLE_SLAVE = 3; /* Read-only access. */
+};
+
+/* Role request and reply message. */
+message ofp_role_request {
+ //ofp_header header; /* Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. */
+ ofp_controller_role role = 1; /* One of OFPCR_ROLE_*. */
+ uint64 generation_id = 2; /* Master Election Generation Id */
+};
+
+/* Asynchronous message configuration. */
+message ofp_async_config {
+ //ofp_header header; /* OFPT_GET_ASYNC_REPLY or OFPT_SET_ASYNC. */
+ repeated uint32 packet_in_mask = 1; /* Bitmasks of OFPR_* values. */
+ repeated uint32 port_status_mask = 2; /* Bitmasks of OFPPR_* values. */
+ repeated uint32 flow_removed_mask = 3;/* Bitmasks of OFPRR_* values. */
+};
+
+
+/* ADDITIONAL VOLTHA SPECIFIC MESSAGE TYPES, AIDING RPC CALLS */
+
+message FlowTableUpdate {
+ string id = 1; // Device.id or LogicalDevice.id
+ ofp_flow_mod flow_mod = 2;
+}
+
+message FlowGroupTableUpdate {
+ string id = 1; // Device.id or LogicalDevice.id
+ ofp_group_mod group_mod = 2;
+}
+
+message Flows {
+ repeated ofp_flow_stats items = 1;
+}
+
+message FlowGroups {
+ repeated ofp_group_entry items = 1;
+}
+
+message PacketIn {
+ string id = 1; // LogicalDevice.id
+ ofp_packet_in packet_in = 2;
+}
+
+message PacketOut {
+ string id = 1; // LogicalDevice.id
+ ofp_packet_out packet_out = 2;
+}
diff --git a/experiments/netconf/proto2yang/proto2yang.py b/experiments/netconf/proto2yang/proto2yang.py
index 8d9a40b..ae1999e 100755
--- a/experiments/netconf/proto2yang/proto2yang.py
+++ b/experiments/netconf/proto2yang/proto2yang.py
@@ -43,9 +43,27 @@
template_yang = Template("""
module ietf-{{ module.name }} {
- yang-version 1.1;
- namespace "urn:ietf:params:xml:ns:yang:ietf-{{ module.name }}";
- prefix "voltha";
+
+ {% macro set_module_prefix(type) %}
+ {% for t in module.data_types %}
+ {% if t.type == type %}
+ {% if t.module != module.name %} {{ t.module }}:{{ type }};
+ {% else %} {{ type }};
+ {% endif %}
+ {% set found=True %}
+ {% endif %}
+ {% if loop.last %}
+ {% if not found %} {{ type }}; {% endif %}
+ {% endif %}
+ {% endfor %}
+ {% endmacro %}
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-{{ module.name }}";
+ prefix {{ module.name }};
+
+ {% for imp in module.imports %}
+ import ietf-{{ imp.name }} { prefix {{ imp.name }} ; }
+ {% endfor %}
organization "CORD";
contact
@@ -74,7 +92,7 @@
{% endfor %}
{% for message in module.messages recursive %}
- {% if message.name in module.referenced_messages %}
+ {% if message.name in module.referred_messages %}
grouping {{ message.name }} {
{% else %}
container {{ message.name }} {
@@ -84,17 +102,21 @@
{% for field in message.fields %}
{% if field.type_ref %}
{% for dict_item in module.referred_messages_with_keys %}
- {% if dict_item.name == field.type %}
+ {% if dict_item.name == field.type %}
+ {% if not field.repeated %}
+ container {{ field.name }} {
+ {% else %}
list {{ field.name }} {
key "{{ dict_item.key }}";
{% if not field.repeated %}
max-elements 1;
{% endif %}
- uses {{ field.type }};
+ {% endif %}
+ uses {{ set_module_prefix(field.type) }}
description
"{{ field.description }}";
}
- {% endif %}
+ {% endif %}
{% endfor %}
{% elif field.repeated %}
list {{ field.name }} {
@@ -105,7 +127,7 @@
fraction-digits 5;
}
{% else %}
- type {{ field.type }};
+ type {{ set_module_prefix(field.type) }}
{% endif %}
description
"{{ field.description }}";
@@ -120,7 +142,7 @@
fraction-digits 5;
}
{% else %}
- type {{ field.type }};
+ type {{ set_module_prefix(field.type) }}
{% endif %}
description
"{{ field.description }}";
@@ -159,10 +181,10 @@
{% if method.input %}
input {
{% if method.input_ref %}
- uses {{ method.input }};
+ uses {{ set_module_prefix(method.input) }}
{% else %}
leaf {{ method.input }} {
- type {{ method.input }};
+ type {{ set_module_prefix(method.input) }}
}
{% endif %}
}
@@ -170,10 +192,10 @@
{% if method.output %}
output {
{% if method.output_ref %}
- uses {{ method.output }};
+ uses {{ set_module_prefix(method.output) }}
{% else %}
leaf {{ method.output }} {
- type {{ method.output }};
+ type {{ set_module_prefix(method.output) }}
}
{% endif %}
}
@@ -186,6 +208,19 @@
}
""", trim_blocks=True, lstrip_blocks=True)
+# def traverse_dependencies(descriptor):
+# dependencies = []
+# proto_imports = descriptor.get('dependency', [])
+# for proto_import in proto_imports:
+# # If the import file has a directory path to it remove it as it is not
+# # allowed in Yang. The proto extension should be removed as well
+# dependencies.append (
+# {
+# 'name' : proto_import.split('/')[-1][:-len('.proto')]
+# }
+# )
+# return dependencies
+
def traverse_messages(message_types, prefix, referenced_messages):
messages = []
@@ -230,6 +265,9 @@
_type = get_yang_type(field)
if not yang_base_type:
referenced_messages.append(_type)
+ # add to referred messages also if it is an enumeration type
+ if is_enumeration(field['type']):
+ referenced_messages.append(_type)
fields.append(
{
@@ -326,6 +364,7 @@
name = rchop(descriptor.get('name', ''), '.proto')
package = descriptor.get('package', '')
description = descriptor.get('_description', '')
+ # imports=traverse_dependencies(descriptor)
messages = traverse_messages(descriptor.get('message_type', []),
package, referenced_messages)
enums = traverse_enums(descriptor.get('enum_type', []), package)
@@ -333,26 +372,33 @@
referenced_messages)
# extensions = _traverse_extensions(descriptors)
# options = _traverse_options(descriptors)
- set_messages_keys(messages)
- unique_referred_messages_with_keys = []
- for message_name in list(set(referenced_messages)):
- unique_referred_messages_with_keys.append(
- {
- 'name': message_name,
- 'key': get_message_key(message_name, messages)
- }
- )
+ # set_messages_keys(messages)
+ # unique_referred_messages_with_keys = []
+ # for message_name in list(set(referenced_messages)):
+ # unique_referred_messages_with_keys.append(
+ # {
+ # 'name': message_name,
+ # 'key': get_message_key(message_name, messages)
+ # }
+ # )
+
+ # Get a list of type definitions (messages, enums) defined in this
+ # descriptor
+ defined_types = [m['name'].split('/')[-1] for m in messages] + \
+ [e['name'].split('/')[-1] for e in enums]
data = {
- 'name': name,
+ 'name': name.split('/')[-1],
'package': package,
'description': description,
+ # 'imports' : imports,
'messages': messages,
'enums': enums,
'services': services,
+ 'defined_types' : defined_types,
'referenced_messages': list(set(referenced_messages)),
# TODO: simplify for easier jinja2 template use
- 'referred_messages_with_keys': unique_referred_messages_with_keys,
+ # 'referred_messages_with_keys': unique_referred_messages_with_keys,
# 'extensions': extensions,
# 'options': options
}
@@ -361,22 +407,35 @@
def set_messages_keys(messages):
for message in messages:
- message['key'] = _get_message_key(message)
+ message['key'] = _get_message_key(message, messages)
if message['messages']:
set_messages_keys(message['messages'])
-
-def _get_message_key(message):
+def _get_message_key(message, messages):
# assume key is first yang base type field
for field in message['fields']:
if not field['type_ref']:
return field['name']
+ else:
+ # if the field name is a message then loop for the key in that
+ # message
+ ref_message = _get_message(field['type'], messages)
+ if ref_message:
+ return _get_message_key(ref_message, messages)
+
# no key yet - search nested messaged
- if message['messages']:
- return get_message_key(message['messages'])
+ for m in message['messages']:
+ key = _get_message_key(m, messages)
+ if key is not None:
+ return key
else:
return None
+def _get_message(name, messages):
+ for m in messages:
+ if m['name'] == name:
+ return m
+ return None
def get_message_key(message_name, messages):
for message in messages:
@@ -387,30 +446,76 @@
return None
+def update_module_imports(module):
+ used_imports = set()
+ for ref_msg in module['referenced_messages']:
+ for type_dict in module['data_types']:
+ if ref_msg == type_dict['type']:
+ if module['name'] != type_dict['module']:
+ used_imports.add(type_dict['module'])
+ break
+ module['imports'] = [{'name' : i} for i in used_imports]
+
+
def generate_code(request, response):
assert isinstance(request, plugin.CodeGeneratorRequest)
parser = DescriptorParser()
- # idx = 1
+ # First process the proto file with the imports
+ all_defined_types = []
+ all_proto_data = []
+ all_referred_messages = []
+ all_messages = []
for proto_file in request.proto_file:
native_data = parser.parse_file_descriptor(proto_file,
type_tag_name='_type',
fold_comments=True)
- # print native_data
+ # Consolidate the defined types across imports
yang_data = traverse_desc(native_data)
+ for type in yang_data['defined_types']:
+ all_defined_types.append(
+ {
+ 'type' : type,
+ 'module' : yang_data['name']
+ }
+ )
+ all_proto_data.append(
+ {
+ 'file_name': '{}-{}'.format('ietf', proto_file.name.split(
+ '/')[-1].replace('.proto','.yang')),
+ 'module': yang_data
+ }
+ )
+
+ # Consolidate referred messages across imports
+ all_referred_messages = all_referred_messages + yang_data['referenced_messages']
+
+ # consolidate all messages
+ all_messages = all_messages + yang_data['messages']
+
+ # Set the message keys - required for List definitions (repeated label)
+ set_messages_keys(all_messages)
+ unique_referred_messages_with_keys = []
+ for m in all_messages:
+ unique_referred_messages_with_keys.append(
+ {
+ 'name': m['name'],
+ 'key': m['key']
+ }
+ )
+
+ # Create the files
+ for proto_data in all_proto_data:
f = response.file.add()
- # TODO: We should have a separate file for each output. There is an
- # issue reusing the same filename with an incremental suffix. Using
- # a different file name works but not the actual proto file name
- f.name = '{}-{}'.format('ietf', proto_file.name.replace('.proto',
- '.yang'))
- # f.name = '{}_{}{}'.format(_rchop(proto_file.name, '.proto'), idx,
- # '.yang')
- # idx += 1
- f.content = template_yang.render(module=yang_data)
+ f.name = proto_data['file_name']
+ proto_data['module']['data_types'] = all_defined_types
+ proto_data['module']['referred_messages'] = all_referred_messages
+ proto_data['module']['referred_messages_with_keys'] = unique_referred_messages_with_keys
+ update_module_imports(proto_data['module'])
+ f.content = template_yang.render(module=proto_data['module'])
def get_yang_type(field):
@@ -426,6 +531,11 @@
else:
return type
+def is_enumeration(type):
+ if type in YANG_TYPE_MAP.keys():
+ _type, _ = YANG_TYPE_MAP[type]
+ return _type in ['enumeration']
+ return False
def is_base_type(type):
# check numeric value of the type first
@@ -435,7 +545,8 @@
else:
# proto name of the type
result = [_format for (_, _format) in YANG_TYPE_MAP.values() if
- _format == type and _format not in ['message', 'group']]
+ _format == type and _format not in ['message',
+ 'group']]
return len(result) > 0
diff --git a/experiments/netconf/proto2yang/schema.proto b/experiments/netconf/proto2yang/schema.proto
new file mode 100644
index 0000000..e75f696
--- /dev/null
+++ b/experiments/netconf/proto2yang/schema.proto
@@ -0,0 +1,36 @@
+syntax = "proto3";
+
+package schema;
+
+import "google/api/annotations.proto";
+import "google/protobuf/empty.proto";
+
+// Contains the name and content of a *.proto file
+message ProtoFile {
+ string file_name = 1; // name of proto file
+ string proto = 2; // content of proto file
+ bytes descriptor = 3; // compiled descriptor for proto (zlib compressed)
+}
+
+// Proto files and compiled descriptors for this interface
+message Schemas {
+
+ // Proto files
+ repeated ProtoFile protos = 1;
+
+ // Proto file name from which swagger.json shall be generated
+ string swagger_from = 2;
+
+}
+
+// Schema services
+service SchemaService {
+
+ // Return active grpc schemas
+ rpc GetSchema(google.protobuf.Empty) returns (Schemas) {
+ option (google.api.http) = {
+ get: "/schema"
+ };
+ }
+
+}
diff --git a/experiments/netconf/proto2yang/test.proto b/experiments/netconf/proto2yang/test.proto
new file mode 100644
index 0000000..802ae0d
--- /dev/null
+++ b/experiments/netconf/proto2yang/test.proto
@@ -0,0 +1,19 @@
+// See README.txt for information and build instructions.
+
+syntax = "proto3";
+
+package voltha;
+
+import public "common.proto";
+
+option java_package = "com.example.tutorial";
+option java_outer_classname = "AddressBookProtos";
+option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
+
+message Person {
+ string name = 1;
+ int32 id = 2; // Unique ID number for this person.
+ string email = 3;
+
+ LogLevel.LogLevel log_level = 4;
+}
diff --git a/experiments/netconf/proto2yang/voltha.proto b/experiments/netconf/proto2yang/voltha.proto
new file mode 100644
index 0000000..b76d903
--- /dev/null
+++ b/experiments/netconf/proto2yang/voltha.proto
@@ -0,0 +1,421 @@
+/*
+ * Top-level Voltha API definition
+ *
+ * For details, see individual definition files.
+ */
+
+syntax = "proto3";
+
+package voltha;
+
+import "google/protobuf/empty.proto";
+import "google/api/annotations.proto";
+
+import public "meta.proto";
+import public "common.proto";
+import public "health.proto";
+import public "logical_device.proto";
+import public "device.proto";
+import public "adapter.proto";
+import public "openflow_13.proto";
+
+option java_package = "org.opencord.voltha";
+option java_outer_classname = "VolthaProtos";
+option csharp_namespace = "Opencord.Voltha.Voltha";
+
+message DeviceGroup {
+
+ string id = 1 [(access) = READ_ONLY];
+
+ repeated LogicalDevice logical_devices = 2 [(child_node) = {key: "id"}];
+
+ repeated Device devices = 3 [(child_node) = {key: "id"}];
+}
+
+message DeviceGroups {
+ repeated DeviceGroup items = 1;
+}
+
+// Top-level (root) node for a Voltha Instance
+message VolthaInstance {
+
+ string instance_id = 1 [(access) = READ_ONLY];
+
+ string version = 2 [(access) = READ_ONLY];
+
+ LogLevel log_level = 3;
+
+ HealthStatus health = 10 [(child_node) = {}];
+
+ repeated Adapter adapters = 11 [(child_node) = {key: "id" }];
+
+ repeated LogicalDevice logical_devices = 12 [(child_node) = {key: "id"}];
+
+ repeated Device devices = 13 [(child_node) = {key: "id"}];
+
+ repeated DeviceType device_types = 14 [(child_node) = {key: "id"}];
+
+ repeated DeviceGroup device_groups = 15 [(child_node) = {key: "id"}];
+}
+
+message VolthaInstances {
+ repeated string items = 1;
+}
+
+// Voltha representing the entire Voltha cluster
+message Voltha {
+
+ string version = 1 [(access) = READ_ONLY];
+
+ LogLevel log_level = 2;
+
+ repeated VolthaInstance instances = 3 [(child_node) = {key: "instance_id"}];
+
+ repeated Adapter adapters = 11 [(child_node) = {key: "id"}];
+
+ repeated LogicalDevice logical_devices = 12 [(child_node) = {key: "id"}];
+
+ repeated Device devices = 13 [(child_node) = {key: "id"}];
+
+ repeated DeviceGroup device_groups = 15 [(child_node) = {key: "id"}];
+
+}
+
+
+/*
+ * Cluster-wide Voltha APIs
+ *
+ * These APIs are potentially dispatched to the leader of the Voltha cluster,
+ * to a specific Voltha instance which owns the given device or logical device.
+ *
+ */
+service VolthaGlobalService {
+
+ // Get high level information on the Voltha cluster
+ rpc GetVoltha(google.protobuf.Empty) returns(Voltha) {
+ option (google.api.http) = {
+ get: "/api/v1"
+ };
+ }
+
+ // List all Voltha cluster instances
+ rpc ListVolthaInstances(google.protobuf.Empty) returns(VolthaInstances) {
+ option (google.api.http) = {
+ get: "/api/v1/instances"
+ };
+ }
+
+ // Get details on a Voltha cluster instance
+ rpc GetVolthaInstance(ID) returns(VolthaInstance) {
+ option (google.api.http) = {
+ get: "/api/v1/instances/{id}"
+ };
+ }
+
+ // List all logical devices managed by the Voltha cluster
+ rpc ListLogicalDevices(google.protobuf.Empty) returns(LogicalDevices) {
+ option (google.api.http) = {
+ get: "/api/v1/logical_devices"
+ };
+ }
+
+ // Get additional information on a given logical device
+ rpc GetLogicalDevice(ID) returns(LogicalDevice) {
+ option (google.api.http) = {
+ get: "/api/v1/logical_devices/{id}"
+ };
+ }
+
+ // List ports of a logical device
+ rpc ListLogicalDevicePorts(ID) returns(LogicalPorts) {
+ option (google.api.http) = {
+ get: "/api/v1/logical_devices/{id}/ports"
+ };
+ }
+
+ // List all flows of a logical device
+ rpc ListLogicalDeviceFlows(ID) returns(openflow_13.Flows) {
+ option (google.api.http) = {
+ get: "/api/v1/logical_devices/{id}/flows"
+ };
+ }
+
+ // Update flow table for logical device
+ rpc UpdateLogicalDeviceFlowTable(openflow_13.FlowTableUpdate)
+ returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/logical_devices/{id}/flows"
+ body: "*"
+ };
+ }
+
+ // List all flow groups of a logical device
+ rpc ListLogicalDeviceFlowGroups(ID) returns(openflow_13.FlowGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/logical_devices/{id}/flow_groups"
+ };
+ }
+
+ // Update group table for device
+ rpc UpdateLogicalDeviceFlowGroupTable(openflow_13.FlowGroupTableUpdate)
+ returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/logical_devices/{id}/flow_groups"
+ body: "*"
+ };
+ }
+
+ // List all physical devices controlled by the Voltha cluster
+ rpc ListDevices(google.protobuf.Empty) returns(Devices) {
+ option (google.api.http) = {
+ get: "/api/v1/devices"
+ };
+ }
+
+ // Get more information on a given physical device
+ rpc GetDevice(ID) returns(Device) {
+ option (google.api.http) = {
+ get: "/api/v1/devices/{id}"
+ };
+ }
+
+ // Pre-provision a new physical device
+ rpc CreateDevice(Device) returns(Device) {
+ option (google.api.http) = {
+ post: "/api/v1/devices"
+ body: "*"
+ };
+ }
+
+ // Activate a pre-provisioned device
+ rpc ActivateDevice(ID) returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/devices/{id}/activate"
+ };
+ }
+
+ // List ports of a device
+ rpc ListDevicePorts(ID) returns(Ports) {
+ option (google.api.http) = {
+ get: "/api/v1/devices/{id}/ports"
+ };
+ }
+
+ // List all flows of a device
+ rpc ListDeviceFlows(ID) returns(openflow_13.Flows) {
+ option (google.api.http) = {
+ get: "/api/v1/devices/{id}/flows"
+ };
+ }
+
+ // List all flow groups of a device
+ rpc ListDeviceFlowGroups(ID) returns(openflow_13.FlowGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/devices/{id}/flow_groups"
+ };
+ }
+
+ // List device types known to Voltha
+ rpc ListDeviceTypes(google.protobuf.Empty) returns(DeviceTypes) {
+ option (google.api.http) = {
+ get: "/api/v1/device_types"
+ };
+ }
+
+ // Get additional information on a device type
+ rpc GetDeviceType(ID) returns(DeviceType) {
+ option (google.api.http) = {
+ get: "/api/v1/device_types/{id}"
+ };
+ }
+
+ // List all device sharding groups
+ rpc ListDeviceGroups(google.protobuf.Empty) returns(DeviceGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/device_groups"
+ };
+ }
+
+ // Get additional information on a device group
+ rpc GetDeviceGroup(ID) returns(DeviceGroup) {
+ option (google.api.http) = {
+ get: "/api/v1/device_groups/{id}"
+ };
+ }
+
+}
+
+/*
+ * Per-instance APIs
+ *
+ * These APIs are always served locally by the Voltha instance on which the
+ * call is made.
+ */
+service VolthaLocalService {
+
+ // Get information on this Voltha instance
+ rpc GetVolthaInstance(google.protobuf.Empty) returns(VolthaInstance) {
+ option (google.api.http) = {
+ get: "/api/v1/local"
+ };
+ }
+
+ // Get the health state of the Voltha instance
+ rpc GetHealth(google.protobuf.Empty) returns(HealthStatus) {
+ option (google.api.http) = {
+ get: "/api/v1/local/health"
+ };
+ }
+
+ // List all active adapters (plugins) in this Voltha instance
+ rpc ListAdapters(google.protobuf.Empty) returns(Adapters) {
+ option (google.api.http) = {
+ get: "/api/v1/local/adapters"
+ };
+ }
+
+ // List all logical devices managed by this Voltha instance
+ rpc ListLogicalDevices(google.protobuf.Empty) returns(LogicalDevices) {
+ option (google.api.http) = {
+ get: "/api/v1/local/logical_devices"
+ };
+ }
+
+ // Get additional information on given logical device
+ rpc GetLogicalDevice(ID) returns(LogicalDevice) {
+ option (google.api.http) = {
+ get: "/api/v1/local/logical_devices/{id}"
+ };
+ }
+
+ // List ports of a logical device
+ rpc ListLogicalDevicePorts(ID) returns(LogicalPorts) {
+ option (google.api.http) = {
+ get: "/api/v1/local/logical_devices/{id}/ports"
+ };
+ }
+
+ // List all flows of a logical device
+ rpc ListLogicalDeviceFlows(ID) returns(openflow_13.Flows) {
+ option (google.api.http) = {
+ get: "/api/v1/local/logical_devices/{id}/flows"
+ };
+ }
+
+ // Update flow table for logical device
+ rpc UpdateLogicalDeviceFlowTable(openflow_13.FlowTableUpdate)
+ returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/local/logical_devices/{id}/flows"
+ body: "*"
+ };
+ }
+
+ // List all flow groups of a logical device
+ rpc ListLogicalDeviceFlowGroups(ID) returns(openflow_13.FlowGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/local/logical_devices/{id}/flow_groups"
+ };
+ }
+
+ // Update group table for logical device
+ rpc UpdateLogicalDeviceFlowGroupTable(openflow_13.FlowGroupTableUpdate)
+ returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/local/logical_devices/{id}/flow_groups"
+ body: "*"
+ };
+ }
+
+ // List all physical devices managed by this Voltha instance
+ rpc ListDevices(google.protobuf.Empty) returns(Devices) {
+ option (google.api.http) = {
+ get: "/api/v1/local/devices"
+ };
+ }
+
+ // Get additional information on this device
+ rpc GetDevice(ID) returns(Device) {
+ option (google.api.http) = {
+ get: "/api/v1/local/devices/{id}"
+ };
+ }
+
+ // Pre-provision a new physical device
+ rpc CreateDevice(Device) returns(Device) {
+ option (google.api.http) = {
+ post: "/api/v1/local/devices"
+ body: "*"
+ };
+ }
+
+ // Activate a pre-provisioned device
+ rpc ActivateDevice(ID) returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/local/devices/{id}/activate"
+ body: "{}"
+ };
+ }
+
+ // List ports of a device
+ rpc ListDevicePorts(ID) returns(Ports) {
+ option (google.api.http) = {
+ get: "/api/v1/local/devices/{id}/ports"
+ };
+ }
+
+ // List all flows of a device
+ rpc ListDeviceFlows(ID) returns(openflow_13.Flows) {
+ option (google.api.http) = {
+ get: "/api/v1/local/devices/{id}/flows"
+ };
+ }
+
+ // List all flow groups of a device
+ rpc ListDeviceFlowGroups(ID) returns(openflow_13.FlowGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/local/devices/{id}/flow_groups"
+ };
+ }
+
+ // List device types know to Voltha instance
+ rpc ListDeviceTypes(google.protobuf.Empty) returns(DeviceTypes) {
+ option (google.api.http) = {
+ get: "/api/v1/local/device_types"
+ };
+ }
+
+ // Get additional information on given device type
+ rpc GetDeviceType(ID) returns(DeviceType) {
+ option (google.api.http) = {
+ get: "/api/v1/local/device_types/{id}"
+ };
+ }
+
+ // List device sharding groups managed by this Voltha instance
+ rpc ListDeviceGroups(google.protobuf.Empty) returns(DeviceGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/local/device_groups"
+ };
+ }
+
+ // Get more information on given device shard
+ rpc GetDeviceGroup(ID) returns(DeviceGroup) {
+ option (google.api.http) = {
+ get: "/api/v1/local/device_groups/{id}"
+ };
+ }
+
+ // Stream control packets to the dataplane
+ rpc StreamPacketsOut(stream openflow_13.PacketOut)
+ returns(google.protobuf.Empty) {
+ // This does not have an HTTP representation
+ }
+
+ // Receive control packet stream
+ rpc ReceivePacketsIn(google.protobuf.Empty)
+ returns(stream openflow_13.PacketIn) {
+ // This does not have an HTTP representation
+ }
+
+}
diff --git a/experiments/netconf/proto2yang/voltha_orig.proto b/experiments/netconf/proto2yang/voltha_orig.proto
new file mode 100644
index 0000000..f0d9aff
--- /dev/null
+++ b/experiments/netconf/proto2yang/voltha_orig.proto
@@ -0,0 +1,421 @@
+/*
+ * Top-level Voltha API definition
+ *
+ * For details, see individual definition files.
+ */
+
+syntax = "proto3";
+
+package voltha;
+
+import "google/protobuf/empty.proto";
+import "google/api/annotations.proto";
+
+import public "meta.proto";
+import public "common.proto";
+import public "health.proto";
+import public "logical_device.proto";
+import public "device.proto";
+import public "adapter.proto";
+import public "openflow_13.proto";
+
+option java_package = "org.opencord.voltha";
+option java_outer_classname = "VolthaProtos";
+option csharp_namespace = "Opencord.Voltha.Voltha";
+
+message DeviceGroup {
+
+ string id = 1 [(access) = READ_ONLY];
+
+ repeated LogicalDevice logical_devices = 2 [(child_node) = {key: "id"}];
+
+ repeated Device devices = 3 [(child_node) = {key: "id"}];
+}
+
+message DeviceGroups {
+ repeated DeviceGroup items = 1;
+}
+
+// Top-level (root) node for a Voltha Instance
+message VolthaInstance {
+
+ string instance_id = 1 [(access) = READ_ONLY];
+
+ string version = 2 [(access) = READ_ONLY];
+
+ LogLevel.LogLevel log_level = 3;
+
+ HealthStatus health = 10 [(child_node) = {}];
+
+ repeated Adapter adapters = 11 [(child_node) = {key: "id" }];
+
+ repeated LogicalDevice logical_devices = 12 [(child_node) = {key: "id"}];
+
+ repeated Device devices = 13 [(child_node) = {key: "id"}];
+
+ repeated DeviceType device_types = 14 [(child_node) = {key: "id"}];
+
+ repeated DeviceGroup device_groups = 15 [(child_node) = {key: "id"}];
+}
+
+message VolthaInstances {
+ repeated string items = 1;
+}
+
+// Voltha representing the entire Voltha cluster
+message Voltha {
+
+ string version = 1 [(access) = READ_ONLY];
+
+ LogLevel.LogLevel log_level = 2;
+
+ repeated VolthaInstance instances = 3 [(child_node) = {key: "instance_id"}];
+
+ repeated Adapter adapters = 11 [(child_node) = {key: "id"}];
+
+ repeated LogicalDevice logical_devices = 12 [(child_node) = {key: "id"}];
+
+ repeated Device devices = 13 [(child_node) = {key: "id"}];
+
+ repeated DeviceGroup device_groups = 15 [(child_node) = {key: "id"}];
+
+}
+
+
+/*
+ * Cluster-wide Voltha APIs
+ *
+ * These APIs are potentially dispatched to the leader of the Voltha cluster,
+ * to a specific Voltha instance which owns the given device or logical device.
+ *
+ */
+service VolthaGlobalService {
+
+ // Get high level information on the Voltha cluster
+ rpc GetVoltha(google.protobuf.Empty) returns(Voltha) {
+ option (google.api.http) = {
+ get: "/api/v1"
+ };
+ }
+
+ // List all Voltha cluster instances
+ rpc ListVolthaInstances(google.protobuf.Empty) returns(VolthaInstances) {
+ option (google.api.http) = {
+ get: "/api/v1/instances"
+ };
+ }
+
+ // Get details on a Voltha cluster instance
+ rpc GetVolthaInstance(ID) returns(VolthaInstance) {
+ option (google.api.http) = {
+ get: "/api/v1/instances/{id}"
+ };
+ }
+
+ // List all logical devices managed by the Voltha cluster
+ rpc ListLogicalDevices(google.protobuf.Empty) returns(LogicalDevices) {
+ option (google.api.http) = {
+ get: "/api/v1/logical_devices"
+ };
+ }
+
+ // Get additional information on a given logical device
+ rpc GetLogicalDevice(ID) returns(LogicalDevice) {
+ option (google.api.http) = {
+ get: "/api/v1/logical_devices/{id}"
+ };
+ }
+
+ // List ports of a logical device
+ rpc ListLogicalDevicePorts(ID) returns(LogicalPorts) {
+ option (google.api.http) = {
+ get: "/api/v1/logical_devices/{id}/ports"
+ };
+ }
+
+ // List all flows of a logical device
+ rpc ListLogicalDeviceFlows(ID) returns(openflow_13.Flows) {
+ option (google.api.http) = {
+ get: "/api/v1/logical_devices/{id}/flows"
+ };
+ }
+
+ // Update flow table for logical device
+ rpc UpdateLogicalDeviceFlowTable(openflow_13.FlowTableUpdate)
+ returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/logical_devices/{id}/flows"
+ body: "*"
+ };
+ }
+
+ // List all flow groups of a logical device
+ rpc ListLogicalDeviceFlowGroups(ID) returns(openflow_13.FlowGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/logical_devices/{id}/flow_groups"
+ };
+ }
+
+ // Update group table for device
+ rpc UpdateLogicalDeviceFlowGroupTable(openflow_13.FlowGroupTableUpdate)
+ returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/logical_devices/{id}/flow_groups"
+ body: "*"
+ };
+ }
+
+ // List all physical devices controlled by the Voltha cluster
+ rpc ListDevices(google.protobuf.Empty) returns(Devices) {
+ option (google.api.http) = {
+ get: "/api/v1/devices"
+ };
+ }
+
+ // Get more information on a given physical device
+ rpc GetDevice(ID) returns(Device) {
+ option (google.api.http) = {
+ get: "/api/v1/devices/{id}"
+ };
+ }
+
+ // Pre-provision a new physical device
+ rpc CreateDevice(Device) returns(Device) {
+ option (google.api.http) = {
+ post: "/api/v1/devices"
+ body: "*"
+ };
+ }
+
+ // Activate a pre-provisioned device
+ rpc ActivateDevice(ID) returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/devices/{id}/activate"
+ };
+ }
+
+ // List ports of a device
+ rpc ListDevicePorts(ID) returns(Ports) {
+ option (google.api.http) = {
+ get: "/api/v1/devices/{id}/ports"
+ };
+ }
+
+ // List all flows of a device
+ rpc ListDeviceFlows(ID) returns(openflow_13.Flows) {
+ option (google.api.http) = {
+ get: "/api/v1/devices/{id}/flows"
+ };
+ }
+
+ // List all flow groups of a device
+ rpc ListDeviceFlowGroups(ID) returns(openflow_13.FlowGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/devices/{id}/flow_groups"
+ };
+ }
+
+ // List device types known to Voltha
+ rpc ListDeviceTypes(google.protobuf.Empty) returns(DeviceTypes) {
+ option (google.api.http) = {
+ get: "/api/v1/device_types"
+ };
+ }
+
+ // Get additional information on a device type
+ rpc GetDeviceType(ID) returns(DeviceType) {
+ option (google.api.http) = {
+ get: "/api/v1/device_types/{id}"
+ };
+ }
+
+ // List all device sharding groups
+ rpc ListDeviceGroups(google.protobuf.Empty) returns(DeviceGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/device_groups"
+ };
+ }
+
+ // Get additional information on a device group
+ rpc GetDeviceGroup(ID) returns(DeviceGroup) {
+ option (google.api.http) = {
+ get: "/api/v1/device_groups/{id}"
+ };
+ }
+
+}
+
+/*
+ * Per-instance APIs
+ *
+ * These APIs are always served locally by the Voltha instance on which the
+ * call is made.
+ */
+service VolthaLocalService {
+
+ // Get information on this Voltha instance
+ rpc GetVolthaInstance(google.protobuf.Empty) returns(VolthaInstance) {
+ option (google.api.http) = {
+ get: "/api/v1/local"
+ };
+ }
+
+ // Get the health state of the Voltha instance
+ rpc GetHealth(google.protobuf.Empty) returns(HealthStatus) {
+ option (google.api.http) = {
+ get: "/api/v1/local/health"
+ };
+ }
+
+ // List all active adapters (plugins) in this Voltha instance
+ rpc ListAdapters(google.protobuf.Empty) returns(Adapters) {
+ option (google.api.http) = {
+ get: "/api/v1/local/adapters"
+ };
+ }
+
+ // List all logical devices managed by this Voltha instance
+ rpc ListLogicalDevices(google.protobuf.Empty) returns(LogicalDevices) {
+ option (google.api.http) = {
+ get: "/api/v1/local/logical_devices"
+ };
+ }
+
+ // Get additional information on given logical device
+ rpc GetLogicalDevice(ID) returns(LogicalDevice) {
+ option (google.api.http) = {
+ get: "/api/v1/local/logical_devices/{id}"
+ };
+ }
+
+ // List ports of a logical device
+ rpc ListLogicalDevicePorts(ID) returns(LogicalPorts) {
+ option (google.api.http) = {
+ get: "/api/v1/local/logical_devices/{id}/ports"
+ };
+ }
+
+ // List all flows of a logical device
+ rpc ListLogicalDeviceFlows(ID) returns(openflow_13.Flows) {
+ option (google.api.http) = {
+ get: "/api/v1/local/logical_devices/{id}/flows"
+ };
+ }
+
+ // Update flow table for logical device
+ rpc UpdateLogicalDeviceFlowTable(openflow_13.FlowTableUpdate)
+ returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/local/logical_devices/{id}/flows"
+ body: "*"
+ };
+ }
+
+ // List all flow groups of a logical device
+ rpc ListLogicalDeviceFlowGroups(ID) returns(openflow_13.FlowGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/local/logical_devices/{id}/flow_groups"
+ };
+ }
+
+ // Update group table for logical device
+ rpc UpdateLogicalDeviceFlowGroupTable(openflow_13.FlowGroupTableUpdate)
+ returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/local/logical_devices/{id}/flow_groups"
+ body: "*"
+ };
+ }
+
+ // List all physical devices managed by this Voltha instance
+ rpc ListDevices(google.protobuf.Empty) returns(Devices) {
+ option (google.api.http) = {
+ get: "/api/v1/local/devices"
+ };
+ }
+
+ // Get additional information on this device
+ rpc GetDevice(ID) returns(Device) {
+ option (google.api.http) = {
+ get: "/api/v1/local/devices/{id}"
+ };
+ }
+
+ // Pre-provision a new physical device
+ rpc CreateDevice(Device) returns(Device) {
+ option (google.api.http) = {
+ post: "/api/v1/local/devices"
+ body: "*"
+ };
+ }
+
+ // Activate a pre-provisioned device
+ rpc ActivateDevice(ID) returns(google.protobuf.Empty) {
+ option (google.api.http) = {
+ post: "/api/v1/local/devices/{id}/activate"
+ body: "{}"
+ };
+ }
+
+ // List ports of a device
+ rpc ListDevicePorts(ID) returns(Ports) {
+ option (google.api.http) = {
+ get: "/api/v1/local/devices/{id}/ports"
+ };
+ }
+
+ // List all flows of a device
+ rpc ListDeviceFlows(ID) returns(openflow_13.Flows) {
+ option (google.api.http) = {
+ get: "/api/v1/local/devices/{id}/flows"
+ };
+ }
+
+ // List all flow groups of a device
+ rpc ListDeviceFlowGroups(ID) returns(openflow_13.FlowGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/local/devices/{id}/flow_groups"
+ };
+ }
+
+ // List device types know to Voltha instance
+ rpc ListDeviceTypes(google.protobuf.Empty) returns(DeviceTypes) {
+ option (google.api.http) = {
+ get: "/api/v1/local/device_types"
+ };
+ }
+
+ // Get additional information on given device type
+ rpc GetDeviceType(ID) returns(DeviceType) {
+ option (google.api.http) = {
+ get: "/api/v1/local/device_types/{id}"
+ };
+ }
+
+ // List device sharding groups managed by this Voltha instance
+ rpc ListDeviceGroups(google.protobuf.Empty) returns(DeviceGroups) {
+ option (google.api.http) = {
+ get: "/api/v1/local/device_groups"
+ };
+ }
+
+ // Get more information on given device shard
+ rpc GetDeviceGroup(ID) returns(DeviceGroup) {
+ option (google.api.http) = {
+ get: "/api/v1/local/device_groups/{id}"
+ };
+ }
+
+ // Stream control packets to the dataplane
+ rpc StreamPacketsOut(stream openflow_13.PacketOut)
+ returns(google.protobuf.Empty) {
+ // This does not have an HTTP representation
+ }
+
+ // Receive control packet stream
+ rpc ReceivePacketsIn(google.protobuf.Empty)
+ returns(stream openflow_13.PacketIn) {
+ // This does not have an HTTP representation
+ }
+
+}
diff --git a/netconf/capabilities.py b/netconf/capabilities.py
index 86873f8..f7c2c5a 100755
--- a/netconf/capabilities.py
+++ b/netconf/capabilities.py
@@ -19,9 +19,143 @@
class Capabilities:
def __init__(self):
- self.server_caps = (C.NETCONF_BASE_10, C.NETCONF_BASE_11)
+ self.server_caps = self._get_server_capabilities()
self.client_caps = set()
def add_client_capability(self, cap):
self.client_caps.add(cap)
+ #TODO: This will be automatically generated from the voltha proto files
+ def _get_server_capabilities(self):
+ return (
+ C.NETCONF_BASE_10,
+ C.NETCONF_BASE_11,
+ "urn:opencord:params:xml:ns:voltha:ietf-voltha",
+ "urn:opencord:params:xml:ns:voltha:ietf-openflow_13",
+ "urn:opencord:params:xml:ns:voltha:ietf-meta",
+ "urn:opencord:params:xml:ns:voltha:ietf-logical_device",
+ "urn:opencord:params:xml:ns:voltha:ietf-health",
+ "urn:opencord:params:xml:ns:voltha:ietf-device",
+ "urn:opencord:params:xml:ns:voltha:ietf-empty",
+ "urn:opencord:params:xml:ns:voltha:ietf-common",
+ "urn:opencord:params:xml:ns:voltha:ietf-any",
+ "urn:opencord:params:xml:ns:voltha:ietf-adapter"
+ )
+
+ #TODO: A schema exchange will also need to happen
+
+ description = """
+
+ Option 1: Client already have the yang model for voltha and adapters:
+ <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <capabilities>
+ <capability>
+ urn:ietf:params:netconf:base:1.1
+ </capability>
+ <capability>
+ urn:cord:voltha:1.0
+ </capability>
+ <capability>
+ urn:cord:voltha:adpater_x:1.0
+ </capability>
+
+
+ Option 2: NETCONF-MONITORING - schema exchanges
+
+ server expose capabilities
+
+ <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <capabilities>
+ <capability>
+ urn:ietf:params:netconf:base:1.1
+ </capability>
+ <capability>
+ urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04
+ </capability>
+
+ client request schemas
+
+ <rpc message-id="101"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.1">
+ <get>
+ <filter type="subtree">
+ <netconf-state xmlns=
+ "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+ <schemas/>
+ </netconf-state>
+ </filter>
+ </get>
+ </rpc>
+
+ server sends back schemas
+
+ <rpc-reply message-id="101"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.1">
+ <data>
+ <netconf-state
+ xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+ <schemas>
+ <schema>
+ <identifier>voltha</identifier>
+ <version>1.0</version>
+ <format>yang</format>
+ <namespace>urn:cord:voltha</namespace>
+ <location>NETCONF</location>
+ </schema>
+ <schema>
+ <identifier>adapter_x</identifier>
+ <version>x_release</version>
+ <format>yang</format>
+ <namespace>urn:cord:voltha:adapter_x</namespace>
+ <location>NETCONF</location>
+ </schema>
+ </schemas>
+ </netconf-state>
+ </data>
+ </rpc-reply>
+
+
+ client requests each schema instance
+
+ <rpc message-id="102"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.1">
+ <get-schema
+ xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+ <identifer>voltha</identifer>
+ <version>1.0</version>
+ </get-schema>
+ </rpc>
+
+ <rpc-reply message-id="102"
+ xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <data
+ xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+ module voltha {
+ //default format (yang) returned
+ //voltha version 0.1 yang module
+ //contents here ...
+ }
+ </data>
+ </rpc-reply>
+
+
+ GETTING DATA
+
+ Use filter:
+ 1) namespace filter
+ <filter type="subtree">
+ <top xmlns="http://example.com/schema/1.2/config"/>
+ </filter>
+
+ 2) <filter type="subtree">
+ <adapters xmlns="urn:cord:voltha:adapter_x">
+ <adapter>
+ <id>uuid</id>
+ <config/>
+ </adapter>
+ </adapters>
+ </filter>
+
+ /voltha/adapters/<adapter>/[<id>, <vendor>, <version>, <config>, <additonal_desc>]
+
+ """
\ No newline at end of file
diff --git a/netconf/grpc_client.py b/netconf/grpc_client.py
deleted file mode 100644
index ebb74eb..0000000
--- a/netconf/grpc_client.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env python
-#
-# 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.
-#
-"""
-The gRPC client layer for the Netconf agent
-"""
-from Queue import Queue, Empty
-from structlog import get_logger
-from twisted.internet.defer import inlineCallbacks, returnValue, DeferredQueue
-
-
-log = get_logger()
-
-
-class GrpcClient(object):
-
- def __init__(self, connection_manager, channel):
-
- self.connection_manager = connection_manager
- self.channel = channel
- self.logical_stub = None
-
- self.stopped = False
-
- self.packet_out_queue = Queue() # queue to send out PacketOut msgs
- self.packet_in_queue = DeferredQueue() # queue to receive PacketIn
-
diff --git a/netconf/grpc_client/__init__.py b/netconf/grpc_client/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/netconf/grpc_client/__init__.py
diff --git a/netconf/grpc_client/grpc_client.py b/netconf/grpc_client/grpc_client.py
new file mode 100644
index 0000000..ae19067
--- /dev/null
+++ b/netconf/grpc_client/grpc_client.py
@@ -0,0 +1,288 @@
+#
+# 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.
+#
+
+"""
+gRPC client meant to connect to a gRPC server endpoint, and query the
+end-point's schema by calling SchemaService.Schema(Empty) and all of its
+semantics are derived from the recovered schema.
+"""
+
+import os
+import sys
+from random import randint
+from zlib import decompress
+
+import grpc
+from consul import Consul
+from grpc._channel import _Rendezvous
+from structlog import get_logger
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks, returnValue
+from werkzeug.exceptions import ServiceUnavailable
+
+from common.utils.asleep import asleep
+from netconf.protos import third_party
+from netconf.protos.schema_pb2 import SchemaServiceStub
+from google.protobuf.empty_pb2 import Empty
+from common.utils.consulhelpers import get_endpoint_from_consul
+from netconf.protos.voltha_pb2 import VolthaLocalServiceStub
+from twisted.internet import threads
+from google.protobuf import empty_pb2
+from google.protobuf.json_format import MessageToDict, ParseDict
+from simplejson import dumps, load
+
+log = get_logger()
+
+
+class GrpcClient(object):
+ """
+ Connect to a gRPC server, fetch its schema, and process the downloaded
+ proto schema files. The goal is to convert the proto schemas into yang
+ schemas which would be exposed to the Netconf client.
+ """
+ RETRY_BACKOFF = [0.05, 0.1, 0.2, 0.5, 1, 2, 5]
+
+ def __init__(self, consul_endpoint, work_dir,
+ grpc_endpoint='localhost:50055',
+ reconnect_callback=None,
+ on_start_callback=None):
+ self.consul_endpoint = consul_endpoint
+ self.grpc_endpoint = grpc_endpoint
+ self.work_dir = work_dir
+ self.reconnect_callback = reconnect_callback
+ self.on_start_callback = on_start_callback
+
+ self.plugin_dir = os.path.abspath(os.path.join(
+ os.path.dirname(__file__), '../protoc_plugins'))
+
+ self.channel = None
+ self.local_stub = None
+ self.schema = None
+ self.retries = 0
+ self.shutting_down = False
+ self.connected = False
+
+ def start(self):
+ log.debug('starting')
+ if not self.connected:
+ reactor.callLater(0, self.connect)
+ log.info('started')
+ return self
+
+ def stop(self):
+ log.debug('stopping')
+ if self.shutting_down:
+ return
+ self.shutting_down = True
+ log.info('stopped')
+
+
+ def set_on_start_callback(self, on_start_callback):
+ self.on_start_callback = on_start_callback
+ return self
+
+
+ def set_reconnect_callback(self, reconnect_callback):
+ self.reconnect_callback = reconnect_callback
+ return self
+
+
+ def resolve_endpoint(self, endpoint):
+ ip_port_endpoint = endpoint
+ if endpoint.startswith('@'):
+ try:
+ ip_port_endpoint = get_endpoint_from_consul(
+ self.consul_endpoint, endpoint[1:])
+ log.info('endpoint-found',
+ endpoint=endpoint, ip_port=ip_port_endpoint)
+ except Exception as e:
+ log.error('service-not-found-in-consul', endpoint=endpoint,
+ exception=repr(e))
+ return None, None
+ if ip_port_endpoint:
+ host, port = ip_port_endpoint.split(':', 2)
+ return host, int(port)
+
+
+ @inlineCallbacks
+ def connect(self):
+ """
+ (Re-)Connect to end-point
+ """
+ if self.shutting_down or self.connected:
+ return
+
+ try:
+ host, port = self.resolve_endpoint(self.grpc_endpoint)
+
+ # If host and port is not set then we will retry
+ if host and port:
+ log.info('grpc-endpoint-connecting', host=host, port=port)
+ self.channel = grpc.insecure_channel('{}:{}'.format(host, port))
+
+ yang_from = self._retrieve_schema()
+ log.info('proto-to-yang-schema', file=yang_from)
+ self._compile_proto_files(yang_from)
+ self._clear_backoff()
+
+ if self.on_start_callback is not None:
+ reactor.callLater(0, self.on_start_callback)
+
+ self.connected = True
+ if self.reconnect_callback is not None:
+ reactor.callLater(0, self.reconnect_callback)
+
+ self.local_stub = VolthaLocalServiceStub(self.channel)
+
+ return
+
+ except _Rendezvous, e:
+ if e.code() == grpc.StatusCode.UNAVAILABLE:
+ log.info('grpc-endpoint-not-available')
+ else:
+ log.exception(e)
+ yield self._backoff('not-available')
+
+ except Exception, e:
+ if not self.shutting_down:
+ log.exception('cannot-connect', endpoint=_endpoint)
+ yield self._backoff('unknown-error')
+
+ reactor.callLater(0, self.connect)
+
+ def _backoff(self, msg):
+ wait_time = self.RETRY_BACKOFF[min(self.retries,
+ len(self.RETRY_BACKOFF) - 1)]
+ self.retries += 1
+ log.error(msg, retry_in=wait_time)
+ return asleep(wait_time)
+
+ def _clear_backoff(self):
+ if self.retries:
+ log.info('reconnected', after_retries=self.retries)
+ self.retries = 0
+
+ def _retrieve_schema(self):
+ """
+ Retrieve schema from gRPC end-point, and save all *.proto files in
+ the work directory.
+ """
+ assert isinstance(self.channel, grpc.Channel)
+ stub = SchemaServiceStub(self.channel)
+ # try:
+ schemas = stub.GetSchema(Empty())
+ # except _Rendezvous, e:
+ # if e.code == grpc.StatusCode.UNAVAILABLE:
+ #
+ # else:
+ # raise e
+
+ os.system('mkdir -p %s' % self.work_dir)
+ os.system('rm -fr /tmp/%s/*' %
+ self.work_dir.replace('/tmp/', '')) # safer
+
+ for proto_file in schemas.protos:
+ proto_fname = proto_file.file_name
+ # TODO: Do we need to process a set of files using a prefix
+ # instead of just one?
+ proto_content = proto_file.proto
+ log.info('saving-proto', fname=proto_fname, dir=self.work_dir,
+ length=len(proto_content))
+ with open(os.path.join(self.work_dir, proto_fname), 'w') as f:
+ f.write(proto_content)
+
+ desc_content = decompress(proto_file.descriptor)
+ desc_fname = proto_fname.replace('.proto', '.desc')
+ log.info('saving-descriptor', fname=desc_fname, dir=self.work_dir,
+ length=len(desc_content))
+ with open(os.path.join(self.work_dir, desc_fname), 'wb') as f:
+ f.write(desc_content)
+ return schemas.yang_from
+
+ def _compile_proto_files(self, yang_from):
+ """
+ For each *.proto file in the work directory, compile the proto
+ file into the respective *_pb2.py file as well as generate the
+ corresponding yang schema.
+ :return: None
+ """
+ log.info('start')
+ google_api_dir = os.path.abspath(os.path.join(
+ os.path.dirname(__file__), '../protos/third_party'
+ ))
+
+ log.info('google-api', api_dir=google_api_dir)
+
+ netconf_base_dir = os.path.abspath(os.path.join(
+ os.path.dirname(__file__), '../..'
+ ))
+ log.info('netconf-dir', dir=netconf_base_dir)
+
+
+ for fname in [f for f in os.listdir(self.work_dir)
+ if f.endswith('.proto')]:
+ log.info('filename', file=fname)
+
+ need_yang = fname == yang_from
+ log.debug('compiling',
+ file=fname,
+ yang_schema_required=need_yang)
+ cmd = (
+ 'cd %s && '
+ 'env PATH=%s PYTHONPATH=%s '
+ 'python -m grpc.tools.protoc '
+ '-I. '
+ '-I%s '
+ '--python_out=. '
+ '--grpc_python_out=. '
+ '--plugin=protoc-gen-custom=%s/proto2yang.py '
+ '%s'
+ '%s' % (
+ self.work_dir,
+ ':'.join([os.environ['PATH'], self.plugin_dir]),
+ ':'.join([google_api_dir, netconf_base_dir]),
+ google_api_dir,
+ self.plugin_dir,
+ '--custom_out=. ' if need_yang else '',
+ fname)
+ )
+ log.debug('executing', cmd=cmd, file=fname)
+ os.system(cmd)
+ log.info('compiled', file=fname)
+
+ # # test-load each _pb2 file to see all is right
+ # if self.work_dir not in sys.path:
+ # sys.path.insert(0, self.work_dir)
+ #
+ # for fname in [f for f in os.listdir(self.work_dir)
+ # if f.endswith('_pb2.py')]:
+ # modname = fname[:-len('.py')]
+ # log.debug('test-import', modname=modname)
+ # _ = __import__(modname)
+
+ #TODO: find a different way to test the generated yang files
+
+ @inlineCallbacks
+ def get_voltha_instance(self):
+ try:
+ res = yield threads.deferToThread(
+ self.local_stub.GetVolthaInstance, empty_pb2.Empty())
+
+ out_data = MessageToDict(res, True, True)
+ returnValue(out_data)
+ except Exception, e:
+ log.error('failure', exception=repr(e))
+
diff --git a/netconf/main.py b/netconf/main.py
index 06edfe4..e049433 100755
--- a/netconf/main.py
+++ b/netconf/main.py
@@ -16,15 +16,20 @@
#
import argparse
import os
-
+import sys
import yaml
from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks
+base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+sys.path.append(base_dir)
+sys.path.append(os.path.join(base_dir, '/netconf/protos/third_party'))
+
from common.structlog_setup import setup_logging
from common.utils.dockerhelpers import get_my_containers_name
from common.utils.nethelpers import get_my_primary_local_ipv4
-from connection_mgr import ConnectionManager
+from netconf.grpc_client.grpc_client import GrpcClient
+from netconf.nc_server import NCServer
defs = dict(
config=os.environ.get('CONFIG', './netconf.yml'),
@@ -247,7 +252,10 @@
fluentd=args.fluentd)
# components
- self.connection_manager = None
+ self.nc_server = None
+ self.grpc_client = None # single, shared gRPC client to Voltha
+
+ self.netconf_server_started = False
self.exiting = False
@@ -261,25 +269,53 @@
@inlineCallbacks
def startup_components(self):
- self.log.info('starting-netconf-server')
+ self.log.info('starting')
args = self.args
- self.connection_manager = yield ConnectionManager(
- args.consul,
- args.grpc_endpoint,
- args.netconf_port,
- args.server_private_key_file,
- args.server_public_key_file,
- args.client_public_keys_file,
- args.client_passwords_file).start()
- self.log.info('started-netconf-server')
+
+ self.grpc_client = yield \
+ GrpcClient(args.consul, args.work_dir, args.grpc_endpoint)
+
+ self.nc_server = yield \
+ NCServer(args.netconf_port,
+ args.server_private_key_file,
+ args.server_public_key_file,
+ args.client_public_keys_file,
+ args.client_passwords_file,
+ self.grpc_client)
+
+ # set on start callback
+ self.grpc_client.set_on_start_callback(self._start_netconf_server)
+
+ # set the callback if there is a reconnect with voltha.
+ self.grpc_client.set_reconnect_callback(self.nc_server.reload_capabilities)
+
+ # start grpc client
+ self.grpc_client.start()
+
+ self.log.info('started')
+
+ @inlineCallbacks
+ def _start_netconf_server(self):
+ if not self.netconf_server_started:
+ self.log.info('starting')
+ yield self.nc_server.start()
+ self.netconf_server_started = True
+ self.log.info('started')
+ else:
+ self.log.info('server-already-started')
@inlineCallbacks
def shutdown_components(self):
"""Execute before the reactor is shut down"""
self.log.info('exiting-on-keyboard-interrupt')
self.exiting = True
- if self.connection_manager is not None:
- yield self.connection_manager.stop()
+
+ if self.grpc_client is not None:
+ yield self.grpc_client.stop()
+
+ if self.nc_server is not None:
+ yield self.nc_server.stop()
+
def start_reactor(self):
reactor.callWhenRunning(
diff --git a/netconf/nc_rpc/base/close_session.py b/netconf/nc_rpc/base/close_session.py
index 43babb8..ce187cd 100644
--- a/netconf/nc_rpc/base/close_session.py
+++ b/netconf/nc_rpc/base/close_session.py
@@ -24,8 +24,9 @@
class CloseSession(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(CloseSession, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(CloseSession, self).__init__(rpc_request, rpc_method,
+ grpc_client, session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/commit.py b/netconf/nc_rpc/base/commit.py
index 61b7604..8933dc3 100644
--- a/netconf/nc_rpc/base/commit.py
+++ b/netconf/nc_rpc/base/commit.py
@@ -24,8 +24,9 @@
class Commit(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(Commit, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(Commit, self).__init__(rpc_request, rpc_method, grpc_client,
+ session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/copy_config.py b/netconf/nc_rpc/base/copy_config.py
index cf2fc82..e287770 100644
--- a/netconf/nc_rpc/base/copy_config.py
+++ b/netconf/nc_rpc/base/copy_config.py
@@ -23,8 +23,9 @@
class CopyConfig(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(CopyConfig, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(CopyConfig, self).__init__(rpc_request, rpc_method,
+ grpc_client, session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/delete_config.py b/netconf/nc_rpc/base/delete_config.py
index 7163ee6..e267807 100644
--- a/netconf/nc_rpc/base/delete_config.py
+++ b/netconf/nc_rpc/base/delete_config.py
@@ -23,8 +23,9 @@
class DeleteConfig(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(DeleteConfig, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(DeleteConfig, self).__init__(rpc_request, rpc_method,
+ grpc_client, session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/discard_changes.py b/netconf/nc_rpc/base/discard_changes.py
index c41d32e..57bdfed 100644
--- a/netconf/nc_rpc/base/discard_changes.py
+++ b/netconf/nc_rpc/base/discard_changes.py
@@ -23,8 +23,9 @@
class DiscardChanges(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(DiscardChanges, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(DiscardChanges, self).__init__(rpc_request, rpc_method,
+ grpc_client, session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/edit_config.py b/netconf/nc_rpc/base/edit_config.py
index 5c7599a..469e957 100644
--- a/netconf/nc_rpc/base/edit_config.py
+++ b/netconf/nc_rpc/base/edit_config.py
@@ -23,8 +23,9 @@
class EditConfig(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(EditConfig, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(EditConfig, self).__init__(rpc_request, rpc_method,
+ grpc_client, session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/get.py b/netconf/nc_rpc/base/get.py
index c6cdfab..39e095c 100644
--- a/netconf/nc_rpc/base/get.py
+++ b/netconf/nc_rpc/base/get.py
@@ -25,8 +25,9 @@
class Get(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(Get, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(Get, self).__init__(rpc_request, rpc_method, grpc_client,
+ session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/get_config.py b/netconf/nc_rpc/base/get_config.py
index dffe0d6..09f90b4 100644
--- a/netconf/nc_rpc/base/get_config.py
+++ b/netconf/nc_rpc/base/get_config.py
@@ -26,8 +26,9 @@
class GetConfig(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(GetConfig, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(GetConfig, self).__init__(rpc_request, rpc_method,
+ grpc_client, session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/kill_session.py b/netconf/nc_rpc/base/kill_session.py
index 08a2e7a..c9a3352 100644
--- a/netconf/nc_rpc/base/kill_session.py
+++ b/netconf/nc_rpc/base/kill_session.py
@@ -25,8 +25,9 @@
class KillSession(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(KillSession, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(KillSession, self).__init__(rpc_request, rpc_method,
+ grpc_client, session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/lock.py b/netconf/nc_rpc/base/lock.py
index fc74e83..2f0130d 100644
--- a/netconf/nc_rpc/base/lock.py
+++ b/netconf/nc_rpc/base/lock.py
@@ -23,8 +23,9 @@
class Lock(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(Lock, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(Lock, self).__init__(rpc_request, rpc_method, grpc_client,
+ session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/unlock.py b/netconf/nc_rpc/base/unlock.py
index 78c59f1..f9ef062 100644
--- a/netconf/nc_rpc/base/unlock.py
+++ b/netconf/nc_rpc/base/unlock.py
@@ -23,8 +23,9 @@
class UnLock(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(UnLock, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(UnLock, self).__init__(rpc_request, rpc_method, grpc_client,
+ session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/base/validate.py b/netconf/nc_rpc/base/validate.py
index 1cb84af..93faf60 100644
--- a/netconf/nc_rpc/base/validate.py
+++ b/netconf/nc_rpc/base/validate.py
@@ -23,8 +23,9 @@
class Validate(Rpc):
- def __init__(self, rpc_request, rpc_method, session):
- super(Validate, self).__init__(rpc_request, rpc_method, session)
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(Validate, self).__init__(rpc_request, rpc_method,
+ grpc_client, session)
self._validate_parameters()
def execute(self):
diff --git a/netconf/nc_rpc/ext/__init__.py b/netconf/nc_rpc/ext/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/netconf/nc_rpc/ext/__init__.py
diff --git a/netconf/nc_rpc/ext/get_voltha.py b/netconf/nc_rpc/ext/get_voltha.py
new file mode 100644
index 0000000..a619875
--- /dev/null
+++ b/netconf/nc_rpc/ext/get_voltha.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+from lxml import etree
+import structlog
+from netconf.nc_rpc.rpc import Rpc
+import netconf.nc_common.error as ncerror
+from netconf.constants import Constants as C
+from netconf.utils import filter_tag_match
+from twisted.internet.defer import inlineCallbacks, returnValue
+import dicttoxml
+from simplejson import dumps, load
+
+log = structlog.get_logger()
+
+
+class GetVoltha(Rpc):
+ def __init__(self, rpc_request, rpc_method, grpc_client, session):
+ super(GetVoltha, self).__init__(rpc_request, rpc_method,
+ grpc_client, session)
+ self._validate_parameters()
+
+ @inlineCallbacks
+ def execute(self):
+ log.info('get-voltha-request', session=self.session.session_id)
+ if self.rpc_response.is_error:
+ returnValue(self.rpc_response)
+
+ # Invoke voltha via the grpc client
+ res_dict = yield self.grpc_client.get_voltha_instance()
+
+ # convert dict to xml
+ xml = dicttoxml.dicttoxml(res_dict)
+ log.info('voltha-info', res=res_dict, xml=xml)
+
+ self.rpc_response.node = self.get_root_element(xml)
+ self.rpc_response.is_error = False
+
+ returnValue(self.rpc_response)
+
+
+ def _validate_parameters(self):
+ log.info('validate-parameters', session=self.session.session_id)
+ self.params = self.rpc_method.getchildren()
+ if len(self.params) > 1:
+ self.rpc_response.is_error = True
+ self.rpc_response.node = ncerror.BadMsg(self.rpc_request)
+ return
+
+ if self.params and not filter_tag_match(self.params[0], C.NC_FILTER):
+ self.rpc_response.is_error = True
+ self.rpc_response.node = ncerror.UnknownElement(
+ self.rpc_request, self.params[0])
+ return
+
+ if not self.params:
+ self.params = [None]
diff --git a/netconf/nc_rpc/rpc.py b/netconf/nc_rpc/rpc.py
index 3dd2f17..ff9b303 100644
--- a/netconf/nc_rpc/rpc.py
+++ b/netconf/nc_rpc/rpc.py
@@ -18,12 +18,15 @@
#
from rpc_response import RpcResponse
+from lxml import etree
+import io
class Rpc(object):
- def __init__(self,rpc_request, rpc_method, session):
+ def __init__(self,rpc_request, rpc_method, grpc_client, session):
self.rpc_request = rpc_request
self.rpc_method = rpc_method
self.rpc_response = RpcResponse()
+ self.grpc_client = grpc_client
self.session = session
def execute(self):
@@ -36,3 +39,8 @@
def _validate_parameters(self, rpc_request):
"""Sets and validates the node as well"""
pass
+
+ def get_root_element(self, xml_msg):
+ tree = etree.parse(io.BytesIO(xml_msg))
+ return tree.getroot()
+
diff --git a/netconf/nc_rpc/rpc_factory.py b/netconf/nc_rpc/rpc_factory.py
index f3ec0cc..eb13b8d 100644
--- a/netconf/nc_rpc/rpc_factory.py
+++ b/netconf/nc_rpc/rpc_factory.py
@@ -28,6 +28,7 @@
from base.unlock import UnLock
from base.close_session import CloseSession
from base.kill_session import KillSession
+from ext.get_voltha import GetVoltha
from netconf import NSMAP, qmap
import netconf.nc_common.error as ncerror
log = structlog.get_logger()
@@ -36,7 +37,7 @@
instance = None
- def get_rpc_handler(self, rpc_node, msg, session):
+ def get_rpc_handler(self, rpc_node, msg, grpc_channel, session):
try:
msg_id = rpc_node.get('message-id')
log.info("Received-rpc-message-id", msg_id=msg_id)
@@ -59,12 +60,13 @@
class_handler = self.rpc_class_handlers.get(rpc_name, None)
if class_handler is not None:
- return class_handler(rpc_node, rpc_method, session)
+ return class_handler(rpc_node, rpc_method, grpc_channel, session)
log.error("rpc-not-implemented", rpc=rpc_name)
rpc_class_handlers = {
+ 'getvoltha' : GetVoltha,
'get-config': GetConfig,
'get': Get,
'edit-config': EditConfig,
@@ -83,3 +85,8 @@
RpcFactory.instance = RpcFactory()
return RpcFactory.instance
+
+if __name__ == '__main__':
+ fac = get_rpc_factory_instance()
+ rpc = fac.rpc_class_handlers.get('getvoltha', None)
+ print rpc(None,None,None)
\ No newline at end of file
diff --git a/netconf/nc_server.py b/netconf/nc_server.py
index 3b22290..6c43194 100644
--- a/netconf/nc_server.py
+++ b/netconf/nc_server.py
@@ -16,6 +16,7 @@
import structlog
import sys
+import os
from twisted.conch import avatar
from twisted.cred import portal
from twisted.conch.checkers import SSHPublicKeyChecker, InMemorySSHKeyDB
@@ -32,6 +33,7 @@
from session.session_mgr import get_session_manager_instance
from constants import Constants as C
+dir_path = os.path.dirname(os.path.realpath(__file__))
# logp.startLogging(sys.stderr)
@@ -40,17 +42,17 @@
# @implementer(conchinterfaces.ISession)
class NetconfAvatar(avatar.ConchUser):
- def __init__(self, username, nc_server, grpc_stub):
+ def __init__(self, username, nc_server, grpc_client):
avatar.ConchUser.__init__(self)
self.username = username
self.nc_server = nc_server
- self.grpc_stub = grpc_stub
+ self.grpc_client = grpc_client
self.channelLookup.update({'session': session.SSHSession})
self.subsystemLookup.update(
{b"netconf": NetconfConnection})
- def get_grpc_stub(self):
- return self.grpc_stub
+ def get_grpc_client(self):
+ return self.grpc_client
def get_nc_server(self):
return self.nc_server
@@ -64,12 +66,12 @@
@implementer(portal.IRealm)
class NetconfRealm(object):
- def __init__(self, nc_server, grpc_stub):
- self.grpc_stub = grpc_stub
+ def __init__(self, nc_server, grpc_client):
+ self.grpc_client = grpc_client
self.nc_server = nc_server
def requestAvatar(self, avatarId, mind, *interfaces):
- user = NetconfAvatar(avatarId, self.nc_server, self.grpc_stub)
+ user = NetconfAvatar(avatarId, self.nc_server, self.grpc_client)
return interfaces[0], user, user.logout
@@ -86,7 +88,7 @@
server_public_key_file,
client_public_keys_file,
client_passwords_file,
- grpc_stub):
+ grpc_client):
self.netconf_port = netconf_port
self.server_private_key_file = server_private_key_file
@@ -94,7 +96,7 @@
self.client_public_keys_file = client_public_keys_file
self.client_passwords_file = client_passwords_file
self.session_mgr = get_session_manager_instance()
- self.grpc_stub = grpc_stub
+ self.grpc_client = grpc_client
self.connector = None
self.nc_client_map = {}
self.running = False
@@ -116,6 +118,12 @@
self.d_stopped.callback(None)
log.info('stopped')
+ def reload_capabilities(self):
+ # TODO: Called when there is a reconnect to voltha
+ # If there are new device types then the new
+ # capabilities will be exposed for subsequent client connections to use
+ pass
+
def client_disconnected(self, result, handler, reason):
assert isinstance(handler, NetconfProtocolHandler)
@@ -131,30 +139,33 @@
#create a session
session = self.session_mgr.create_session(client_conn.avatar.get_user())
handler = NetconfProtocolHandler(self, client_conn,
- session, self.grpc_stub)
+ session, self.grpc_client)
client_conn.proto_handler = handler
reactor.callLater(0, handler.start)
def setup_secure_access(self):
try:
from twisted.cred import portal
- portal = portal.Portal(NetconfRealm(self, self.grpc_stub))
+ portal = portal.Portal(NetconfRealm(self, self.grpc_client))
# setup userid-password access
- password_file = '{}/{}'.format(C.CLIENT_CRED_DIRECTORY,
- self.client_passwords_file)
+ password_file = '{}/{}/{}'.format(dir_path,
+ C.CLIENT_CRED_DIRECTORY,
+ self.client_passwords_file)
portal.registerChecker(FilePasswordDB(password_file))
# setup access when client uses keys
- keys_file = '{}/{}'.format(C.CLIENT_CRED_DIRECTORY,
- self.client_public_keys_file)
+ keys_file = '{}/{}/{}'.format(dir_path,
+ C.CLIENT_CRED_DIRECTORY,
+ self.client_public_keys_file)
with open(keys_file) as f:
users = [line.rstrip('\n') for line in f]
users_dict = {}
for user in users:
users_dict[user.split(':')[0]] = [
- keys.Key.fromFile('{}/{}'.format(C.CLIENT_CRED_DIRECTORY,
- user.split(':')[1]))]
+ keys.Key.fromFile('{}/{}/{}'.format(dir_path,
+ C.CLIENT_CRED_DIRECTORY,
+ user.split(':')[1]))]
sshDB = SSHPublicKeyChecker(InMemorySSHKeyDB(users_dict))
portal.registerChecker(sshDB)
return portal
@@ -182,8 +193,9 @@
return SSHServerTransport()
def getPublicKeys(self):
- key_file_name = '{}/{}'.format(C.KEYS_DIRECTORY,
- self.server_public_key_file)
+ key_file_name = '{}/{}/{}'.format(dir_path,
+ C.KEYS_DIRECTORY,
+ self.server_public_key_file)
try:
publicKeys = {
'ssh-rsa': keys.Key.fromFile(key_file_name)
@@ -194,8 +206,9 @@
filename=key_file_name, exception=repr(e))
def getPrivateKeys(self):
- key_file_name = '{}/{}'.format(C.KEYS_DIRECTORY,
- self.server_private_key_file)
+ key_file_name = '{}/{}/{}'.format(dir_path,
+ C.KEYS_DIRECTORY,
+ self.server_private_key_file)
try:
privateKeys = {
'ssh-rsa': keys.Key.fromFile(key_file_name)
diff --git a/netconf/protoc_plugins/addressbook.proto b/netconf/protoc_plugins/addressbook.proto
new file mode 100644
index 0000000..fc1a10f
--- /dev/null
+++ b/netconf/protoc_plugins/addressbook.proto
@@ -0,0 +1,34 @@
+// See README.txt for information and build instructions.
+
+syntax = "proto3";
+
+package tutorial;
+
+option java_package = "com.example.tutorial";
+option java_outer_classname = "AddressBookProtos";
+option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
+
+message Person {
+ string name = 1;
+ int32 id = 2; // Unique ID number for this person.
+ string email = 3;
+
+ enum PhoneType {
+ MOBILE = 0;
+ HOME = 1;
+ WORK = 2;
+ }
+
+ message PhoneNumber {
+ string number = 1;
+ PhoneType type = 2;
+ }
+
+ repeated PhoneNumber phones = 4;
+ repeated string khen = 5;
+}
+
+// Our address book file is just one of these.
+message AddressBook {
+ repeated Person people = 1;
+}
diff --git a/netconf/protoc_plugins/descriptor.desc b/netconf/protoc_plugins/descriptor.desc
new file mode 100644
index 0000000..ac12c36
--- /dev/null
+++ b/netconf/protoc_plugins/descriptor.desc
Binary files differ
diff --git a/netconf/protoc_plugins/descriptor_parser.py b/netconf/protoc_plugins/descriptor_parser.py
new file mode 100644
index 0000000..c23f497
--- /dev/null
+++ b/netconf/protoc_plugins/descriptor_parser.py
@@ -0,0 +1,164 @@
+#
+# 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 os
+from collections import OrderedDict
+
+from google.protobuf import descriptor_pb2
+from google.protobuf.descriptor import FieldDescriptor, Descriptor
+from google.protobuf.message import Message
+
+
+class InvalidDescriptorError(Exception): pass
+
+
+class DescriptorParser(object):
+ """
+ Used to parse protobuf FileDescriptor objects into native Python
+ data structures (nested dict/list/intrinsic values. Two of the typical
+ sources of FileDescriptor objects are:
+ 1. CodeGeneratorRequest, used as binary input to any protoc plugin,
+ contains a list of these FileDescriptor objects (under the
+ proto_file attribute)
+ 2. FileDescriptorSet, as saved by protoc when using the -o option.
+
+ An important feature of the parser is that it can process the source
+ code annotations and can fold comments into the relevant defintions
+ present in the proto file.
+
+ Usage (in a protoc plugin):
+ >>> request = plugin.CodeGeneratorRequest()
+ >>> request.ParseFromString(sys.stdin.read())
+ >>> parser = DescriptorParser()
+ >>> for proto_file in request.proto_file:
+ >>> parsed_data = parser.parse_file_descriptor()
+ >>> print json.dumps(parsed_data, indent=4)
+ """
+
+ meta = None
+
+ def __init__(self):
+ if DescriptorParser.meta is None:
+ DescriptorParser.meta = self.load_meta_descriptor()
+
+ def load_meta_descriptor(self):
+ """
+ Load the protobuf version of descriptor.proto to use it in
+ decoding protobuf paths.
+ """
+ fpath = os.path.abspath(os.path.join(os.path.dirname(__file__),
+ 'descriptor.desc'))
+ with open(fpath, 'r') as f:
+ blob = f.read()
+ proto = descriptor_pb2.FileDescriptorSet()
+ proto.ParseFromString(blob)
+ assert len(proto.file) == 1
+ return proto.file[0]
+
+ parser_table = {
+ unicode: lambda x: x,
+ int: lambda x: x,
+ bool: lambda x: x,
+ }
+
+ def parse(self, o, type_tag_name=None):
+ if isinstance(o, Message):
+ return self.parse_message(o, type_tag_name)
+ else:
+ return self.parser_table[type(o)](o)
+
+ def parse_message(self, m, type_tag_name=None):
+ assert isinstance(m, Message)
+ d = OrderedDict()
+ for field, value in m.ListFields():
+ assert isinstance(field, FieldDescriptor)
+ if field.label in (1, 2):
+ d[field.name] = self.parse(value, type_tag_name)
+ elif field.label == 3:
+ d[field.name] = [self.parse(x, type_tag_name) for x in
+ value]
+ else:
+ raise InvalidDescriptorError()
+
+ if type_tag_name is not None:
+ d[type_tag_name] = m.DESCRIPTOR.full_name.strip('.')
+
+ return d
+
+ def parse_file_descriptor(self, descriptor,
+ type_tag_name=None,
+ fold_comments=False):
+
+ d = self.parse(descriptor, type_tag_name=type_tag_name)
+
+ if fold_comments:
+ locations = d.get('source_code_info', {}).get('location', [])
+ for location in locations:
+ path = location.get('path', [])
+ comments = ''.join([
+ location.get('leading_comments', '').strip(' '),
+ location.get('trailing_comments', '').strip(' '),
+ ''.join(block.strip(' ') for block
+ in
+ location.get('leading_detached_comments', ''))
+ ]).strip()
+
+ # ignore locations with no comments
+ if not comments:
+ continue
+
+ # we ignore path with odd number of entries, since these do
+ # not address our schema nodes, but rather the meta schema
+ if (len(path) % 2 == 0):
+ node = self.find_node_by_path(
+ path, self.meta.DESCRIPTOR, d)
+ assert isinstance(node, dict)
+ node['_description'] = comments
+
+ # remove source_code_info
+ del d['source_code_info']
+
+ return d
+
+ def parse_file_descriptors(self, descriptors,
+ type_tag_name=None,
+ fold_comments=False):
+ return [self.parse_file_descriptor(descriptor,
+ type_tag_name=type_tag_name,
+ fold_comments=fold_comments)
+ for descriptor in descriptors]
+
+ def find_node_by_path(self, path, meta, o):
+ # stop recursion when path is empty
+ if not path:
+ return o
+
+ # sanity check
+ assert len(path) >= 2
+ assert isinstance(meta, Descriptor)
+ assert isinstance(o, dict)
+
+ # find field name, then actual field
+ field_number = path.pop(0)
+ field_def = meta.fields_by_number[field_number]
+ field = o[field_def.name]
+
+ # field must be a list, extract entry with given index
+ assert isinstance(field, list) # expected to be a list field
+ index = path.pop(0)
+ child_o = field[index]
+
+ child_meta = field_def.message_type
+ return self.find_node_by_path(path, child_meta, child_o)
diff --git a/netconf/protoc_plugins/proto2yang.py b/netconf/protoc_plugins/proto2yang.py
new file mode 100755
index 0000000..ae1999e
--- /dev/null
+++ b/netconf/protoc_plugins/proto2yang.py
@@ -0,0 +1,605 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+"""protoc plugin to convert a protobuf schema to a yang schema
+
+ - basic support for message, fields. enumeration, service, method
+
+ - yang semantic rules needs to be implemented
+
+ - to run this plugin :
+
+ $ python -m grpc.tools.protoc -I.
+ --plugin=protoc-gen-custom=./proto2yang.py --custom_out=. <proto file>.proto
+
+ - the above will produce a ietf-<proto file>.yang file formatted for yang
+
+ - two examples of proto that can be used in the same directory are
+ yang.proto and addressbook.proto
+
+"""
+
+import sys
+
+from jinja2 import Template
+from google.protobuf.compiler import plugin_pb2 as plugin
+from descriptor_parser import DescriptorParser
+
+from google.protobuf.descriptor import FieldDescriptor
+
+template_yang = Template("""
+module ietf-{{ module.name }} {
+
+ {% macro set_module_prefix(type) %}
+ {% for t in module.data_types %}
+ {% if t.type == type %}
+ {% if t.module != module.name %} {{ t.module }}:{{ type }};
+ {% else %} {{ type }};
+ {% endif %}
+ {% set found=True %}
+ {% endif %}
+ {% if loop.last %}
+ {% if not found %} {{ type }}; {% endif %}
+ {% endif %}
+ {% endfor %}
+ {% endmacro %}
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-{{ module.name }}";
+ prefix {{ module.name }};
+
+ {% for imp in module.imports %}
+ import ietf-{{ imp.name }} { prefix {{ imp.name }} ; }
+ {% endfor %}
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "{{ module.description }}";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+ {% for enum in module.enums %}
+ typedef {{ enum.name }} {
+ type enumeration {
+ {% for v in enum.value %}
+ enum {{ v.name }} {
+ description "{{ v.description }}";
+ }
+ {% endfor %}
+ }
+ description
+ "{{ enum.description }}";
+ }
+ {% endfor %}
+
+ {% for message in module.messages recursive %}
+ {% if message.name in module.referred_messages %}
+ grouping {{ message.name }} {
+ {% else %}
+ container {{ message.name }} {
+ {% endif %}
+ description
+ "{{ message.description }}";
+ {% for field in message.fields %}
+ {% if field.type_ref %}
+ {% for dict_item in module.referred_messages_with_keys %}
+ {% if dict_item.name == field.type %}
+ {% if not field.repeated %}
+ container {{ field.name }} {
+ {% else %}
+ list {{ field.name }} {
+ key "{{ dict_item.key }}";
+ {% if not field.repeated %}
+ max-elements 1;
+ {% endif %}
+ {% endif %}
+ uses {{ set_module_prefix(field.type) }}
+ description
+ "{{ field.description }}";
+ }
+ {% endif %}
+ {% endfor %}
+ {% elif field.repeated %}
+ list {{ field.name }} {
+ key "{{ field.name }}";
+ leaf {{ field.name }} {
+ {% if field.type == "decimal64" %}
+ type {{ field.type }} {
+ fraction-digits 5;
+ }
+ {% else %}
+ type {{ set_module_prefix(field.type) }}
+ {% endif %}
+ description
+ "{{ field.description }}";
+ }
+ description
+ "{{ field.description }}";
+ }
+ {% else %}
+ leaf {{ field.name }} {
+ {% if field.type == "decimal64" %}
+ type {{ field.type }} {
+ fraction-digits 5;
+ }
+ {% else %}
+ type {{ set_module_prefix(field.type) }}
+ {% endif %}
+ description
+ "{{ field.description }}";
+ }
+ {% endif %}
+
+ {% endfor %}
+ {% for enum_type in message.enums %}
+ typedef {{ enum_type.name }} {
+ type enumeration {
+ {% for v in enum_type.value %}
+ enum {{ v.name }} {
+ description "{{ v.description }}";
+ }
+ {% endfor %}
+ }
+ description
+ "{{ enum_type.description }}";
+ }
+
+ {% endfor %}
+ {% if message.messages %}
+ {{ loop (message.messages)|indent(4, false) }}
+ {% endif %}
+ }
+
+ {% endfor %}
+ {% for service in module.services %}
+ {% if service.description %}
+ /* {{ service.description }}" */
+ {% endif %}
+ {% for method in service.methods %}
+ rpc {{ service.service }}-{{ method.method }} {
+ description
+ "{{ method.description }}";
+ {% if method.input %}
+ input {
+ {% if method.input_ref %}
+ uses {{ set_module_prefix(method.input) }}
+ {% else %}
+ leaf {{ method.input }} {
+ type {{ set_module_prefix(method.input) }}
+ }
+ {% endif %}
+ }
+ {% endif %}
+ {% if method.output %}
+ output {
+ {% if method.output_ref %}
+ uses {{ set_module_prefix(method.output) }}
+ {% else %}
+ leaf {{ method.output }} {
+ type {{ set_module_prefix(method.output) }}
+ }
+ {% endif %}
+ }
+ {% endif %}
+ }
+
+ {% endfor %}
+
+ {% endfor %}
+}
+""", trim_blocks=True, lstrip_blocks=True)
+
+# def traverse_dependencies(descriptor):
+# dependencies = []
+# proto_imports = descriptor.get('dependency', [])
+# for proto_import in proto_imports:
+# # If the import file has a directory path to it remove it as it is not
+# # allowed in Yang. The proto extension should be removed as well
+# dependencies.append (
+# {
+# 'name' : proto_import.split('/')[-1][:-len('.proto')]
+# }
+# )
+# return dependencies
+
+
+def traverse_messages(message_types, prefix, referenced_messages):
+ messages = []
+ for message_type in message_types:
+ assert message_type['_type'] == 'google.protobuf.DescriptorProto'
+
+ # full_name = prefix + '-' + message_type['name']
+ full_name = message_type['name']
+
+ # parse the fields
+ fields = traverse_fields(message_type.get('field', []), full_name,
+ referenced_messages)
+
+ # parse the enums
+ enums = traverse_enums(message_type.get('enum_type', []), full_name)
+
+ # parse nested messages
+ nested = message_type.get('nested_type', [])
+ nested_messages = traverse_messages(nested, full_name,
+ referenced_messages)
+ messages.append(
+ {
+ 'name': full_name,
+ 'fields': fields,
+ 'enums': enums,
+ # 'extensions': extensions,
+ 'messages': nested_messages,
+ 'description': remove_unsupported_characters(
+ message_type.get('_description', '')),
+ # 'extension_ranges': extension_ranges,
+ # 'oneof': oneof
+ }
+ )
+ return messages
+
+
+def traverse_fields(fields_desc, prefix, referenced_messages):
+ fields = []
+ for field in fields_desc:
+ assert field['_type'] == 'google.protobuf.FieldDescriptorProto'
+ yang_base_type = is_base_type(field['type'])
+ _type = get_yang_type(field)
+ if not yang_base_type:
+ referenced_messages.append(_type)
+ # add to referred messages also if it is an enumeration type
+ if is_enumeration(field['type']):
+ referenced_messages.append(_type)
+
+ fields.append(
+ {
+ # 'name': prefix + '-' + field.get('name', ''),
+ 'name': field.get('name', ''),
+ 'label': field.get('label', ''),
+ 'repeated': field['label'] == FieldDescriptor.LABEL_REPEATED,
+ 'number': field.get('number', ''),
+ 'options': field.get('options', ''),
+ 'type_name': field.get('type_name', ''),
+ 'type': _type,
+ 'type_ref': not yang_base_type,
+ 'description': remove_unsupported_characters(field.get(
+ '_description', ''))
+ }
+ )
+ return fields
+
+
+def traverse_enums(enums_desc, prefix):
+ enums = []
+ for enum in enums_desc:
+ assert enum['_type'] == 'google.protobuf.EnumDescriptorProto'
+ # full_name = prefix + '-' + enum.get('name', '')
+ full_name = enum.get('name', '')
+ enums.append(
+ {
+ 'name': full_name,
+ 'value': enum.get('value', ''),
+ 'description': remove_unsupported_characters(enum.get(
+ '_description', ''))
+ }
+ )
+ return enums
+
+
+def traverse_services(service_desc, referenced_messages):
+ services = []
+ for service in service_desc:
+ methods = []
+ for method in service.get('method', []):
+ assert method['_type'] == 'google.protobuf.MethodDescriptorProto'
+
+ input_name = method.get('input_type')
+ input_ref = False
+ if not is_base_type(input_name):
+ input_name = remove_first_character_if_match(input_name, '.')
+ # input_name = input_name.replace(".", "-")
+ input_name = input_name.split('.')[-1]
+ referenced_messages.append(input_name)
+ input_ref = True
+
+ output_name = method.get('output_type')
+ output_ref = False
+ if not is_base_type(output_name):
+ output_name = remove_first_character_if_match(output_name, '.')
+ # output_name = output_name.replace(".", "-")
+ output_name = output_name.split('.')[-1]
+ referenced_messages.append(output_name)
+ output_ref = True
+
+ methods.append(
+ {
+ 'method': method.get('name', ''),
+ 'input': input_name,
+ 'input_ref': input_ref,
+ 'output': output_name,
+ 'output_ref': output_ref,
+ 'description': remove_unsupported_characters(method.get(
+ '_description', '')),
+ 'server_streaming': method.get('server_streaming',
+ False) == True
+ }
+ )
+ services.append(
+ {
+ 'service': service.get('name', ''),
+ 'methods': methods,
+ 'description': remove_unsupported_characters(service.get(
+ '_description', '')),
+ }
+ )
+ return services
+
+
+def rchop(thestring, ending):
+ if thestring.endswith(ending):
+ return thestring[:-len(ending)]
+ return thestring
+
+
+def traverse_desc(descriptor):
+ referenced_messages = []
+ name = rchop(descriptor.get('name', ''), '.proto')
+ package = descriptor.get('package', '')
+ description = descriptor.get('_description', '')
+ # imports=traverse_dependencies(descriptor)
+ messages = traverse_messages(descriptor.get('message_type', []),
+ package, referenced_messages)
+ enums = traverse_enums(descriptor.get('enum_type', []), package)
+ services = traverse_services(descriptor.get('service', []),
+ referenced_messages)
+ # extensions = _traverse_extensions(descriptors)
+ # options = _traverse_options(descriptors)
+ # set_messages_keys(messages)
+ # unique_referred_messages_with_keys = []
+ # for message_name in list(set(referenced_messages)):
+ # unique_referred_messages_with_keys.append(
+ # {
+ # 'name': message_name,
+ # 'key': get_message_key(message_name, messages)
+ # }
+ # )
+
+ # Get a list of type definitions (messages, enums) defined in this
+ # descriptor
+ defined_types = [m['name'].split('/')[-1] for m in messages] + \
+ [e['name'].split('/')[-1] for e in enums]
+
+ data = {
+ 'name': name.split('/')[-1],
+ 'package': package,
+ 'description': description,
+ # 'imports' : imports,
+ 'messages': messages,
+ 'enums': enums,
+ 'services': services,
+ 'defined_types' : defined_types,
+ 'referenced_messages': list(set(referenced_messages)),
+ # TODO: simplify for easier jinja2 template use
+ # 'referred_messages_with_keys': unique_referred_messages_with_keys,
+ # 'extensions': extensions,
+ # 'options': options
+ }
+ return data
+
+
+def set_messages_keys(messages):
+ for message in messages:
+ message['key'] = _get_message_key(message, messages)
+ if message['messages']:
+ set_messages_keys(message['messages'])
+
+def _get_message_key(message, messages):
+ # assume key is first yang base type field
+ for field in message['fields']:
+ if not field['type_ref']:
+ return field['name']
+ else:
+ # if the field name is a message then loop for the key in that
+ # message
+ ref_message = _get_message(field['type'], messages)
+ if ref_message:
+ return _get_message_key(ref_message, messages)
+
+ # no key yet - search nested messaged
+ for m in message['messages']:
+ key = _get_message_key(m, messages)
+ if key is not None:
+ return key
+ else:
+ return None
+
+def _get_message(name, messages):
+ for m in messages:
+ if m['name'] == name:
+ return m
+ return None
+
+def get_message_key(message_name, messages):
+ for message in messages:
+ if message_name == message['name']:
+ return message['key']
+ if message['messages']:
+ return get_message_key(message_name, message['messages'])
+ return None
+
+
+def update_module_imports(module):
+ used_imports = set()
+ for ref_msg in module['referenced_messages']:
+ for type_dict in module['data_types']:
+ if ref_msg == type_dict['type']:
+ if module['name'] != type_dict['module']:
+ used_imports.add(type_dict['module'])
+ break
+ module['imports'] = [{'name' : i} for i in used_imports]
+
+
+def generate_code(request, response):
+ assert isinstance(request, plugin.CodeGeneratorRequest)
+
+ parser = DescriptorParser()
+
+ # First process the proto file with the imports
+ all_defined_types = []
+ all_proto_data = []
+ all_referred_messages = []
+ all_messages = []
+ for proto_file in request.proto_file:
+ native_data = parser.parse_file_descriptor(proto_file,
+ type_tag_name='_type',
+ fold_comments=True)
+
+ # Consolidate the defined types across imports
+ yang_data = traverse_desc(native_data)
+ for type in yang_data['defined_types']:
+ all_defined_types.append(
+ {
+ 'type' : type,
+ 'module' : yang_data['name']
+ }
+ )
+
+ all_proto_data.append(
+ {
+ 'file_name': '{}-{}'.format('ietf', proto_file.name.split(
+ '/')[-1].replace('.proto','.yang')),
+ 'module': yang_data
+ }
+ )
+
+ # Consolidate referred messages across imports
+ all_referred_messages = all_referred_messages + yang_data['referenced_messages']
+
+ # consolidate all messages
+ all_messages = all_messages + yang_data['messages']
+
+ # Set the message keys - required for List definitions (repeated label)
+ set_messages_keys(all_messages)
+ unique_referred_messages_with_keys = []
+ for m in all_messages:
+ unique_referred_messages_with_keys.append(
+ {
+ 'name': m['name'],
+ 'key': m['key']
+ }
+ )
+
+ # Create the files
+ for proto_data in all_proto_data:
+ f = response.file.add()
+ f.name = proto_data['file_name']
+ proto_data['module']['data_types'] = all_defined_types
+ proto_data['module']['referred_messages'] = all_referred_messages
+ proto_data['module']['referred_messages_with_keys'] = unique_referred_messages_with_keys
+ update_module_imports(proto_data['module'])
+ f.content = template_yang.render(module=proto_data['module'])
+
+
+def get_yang_type(field):
+ type = field['type']
+ if type in YANG_TYPE_MAP.keys():
+ _type, _ = YANG_TYPE_MAP[type]
+ if _type in ['enumeration', 'message', 'group']:
+ return field['type_name'].split('.')[-1]
+ # return remove_first_character_if_match(field['type_name'],
+ # '.').replace('.', '-')
+ else:
+ return _type
+ else:
+ return type
+
+def is_enumeration(type):
+ if type in YANG_TYPE_MAP.keys():
+ _type, _ = YANG_TYPE_MAP[type]
+ return _type in ['enumeration']
+ return False
+
+def is_base_type(type):
+ # check numeric value of the type first
+ if type in YANG_TYPE_MAP.keys():
+ _type, _ = YANG_TYPE_MAP[type]
+ return _type not in ['message', 'group']
+ else:
+ # proto name of the type
+ result = [_format for (_, _format) in YANG_TYPE_MAP.values() if
+ _format == type and _format not in ['message',
+ 'group']]
+ return len(result) > 0
+
+
+def remove_unsupported_characters(text):
+ unsupported_characters = ["{", "}", "[", "]", "\"", "\\", "*", "/"]
+ return ''.join([i if i not in unsupported_characters else ' ' for i in
+ text])
+
+
+def remove_first_character_if_match(str, char):
+ if str.startswith(char):
+ return str[1:]
+ return str
+
+
+YANG_TYPE_MAP = {
+ FieldDescriptor.TYPE_BOOL: ('boolean', 'boolean'),
+ FieldDescriptor.TYPE_BYTES: ('binary', 'byte'),
+ FieldDescriptor.TYPE_DOUBLE: ('decimal64', 'double'),
+ FieldDescriptor.TYPE_ENUM: ('enumeration', 'enum'),
+ FieldDescriptor.TYPE_FIXED32: ('int32', 'int64'),
+ FieldDescriptor.TYPE_FIXED64: ('int64', 'uint64'),
+ FieldDescriptor.TYPE_FLOAT: ('decimal64', 'float'),
+ FieldDescriptor.TYPE_INT32: ('int32', 'int32'),
+ FieldDescriptor.TYPE_INT64: ('int64', 'int64'),
+ FieldDescriptor.TYPE_SFIXED32: ('int32', 'int32'),
+ FieldDescriptor.TYPE_SFIXED64: ('int64', 'int64'),
+ FieldDescriptor.TYPE_STRING: ('string', 'string'),
+ FieldDescriptor.TYPE_SINT32: ('int32', 'int32'),
+ FieldDescriptor.TYPE_SINT64: ('int64', 'int64'),
+ FieldDescriptor.TYPE_UINT32: ('uint32', 'int64'),
+ FieldDescriptor.TYPE_UINT64: ('uint64', 'uint64'),
+ FieldDescriptor.TYPE_MESSAGE: ('message', 'message'),
+ FieldDescriptor.TYPE_GROUP: ('group', 'group')
+}
+
+if __name__ == '__main__':
+ # Read request message from stdin
+ data = sys.stdin.read()
+
+ # Parse request
+ request = plugin.CodeGeneratorRequest()
+ request.ParseFromString(data)
+
+ # Create response
+ response = plugin.CodeGeneratorResponse()
+
+ # Generate code
+ generate_code(request, response)
+
+ # Serialise response message
+ output = response.SerializeToString()
+
+ # Write to stdout
+ sys.stdout.write(output)
+ # print is_base_type(9)
diff --git a/netconf/protoc_plugins/proto2yang_work_latest.py b/netconf/protoc_plugins/proto2yang_work_latest.py
new file mode 100755
index 0000000..6a2a3e7
--- /dev/null
+++ b/netconf/protoc_plugins/proto2yang_work_latest.py
@@ -0,0 +1,601 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+"""protoc plugin to convert a protobuf schema to a yang schema
+
+ - basic support for message, fields. enumeration, service, method
+
+ - yang semantic rules needs to be implemented
+
+ - to run this plugin :
+
+ $ python -m grpc.tools.protoc -I.
+ --plugin=protoc-gen-custom=./proto2yang.py --custom_out=. <proto file>.proto
+
+ - the above will produce a ietf-<proto file>.yang file formatted for yang
+
+ - two examples of proto that can be used in the same directory are
+ yang.proto and addressbook.proto
+
+"""
+
+import sys
+
+from jinja2 import Template
+from google.protobuf.compiler import plugin_pb2 as plugin
+from descriptor_parser import DescriptorParser
+
+from google.protobuf.descriptor import FieldDescriptor
+
+template_yang = Template("""
+module ietf-{{ module.name }} {
+
+ {% macro set_module_prefix(type) %}
+ {% for t in module.data_types %}
+ {% if t.type == type %}
+ {% if t.module != module.name %} {{ t.module }}:{{ type }};
+ {% else %} {{ type }};
+ {% endif %}
+ {% set found=True %}
+ {% endif %}
+ {% if loop.last %}
+ {% if not found %} {{ type }}; {% endif %}
+ {% endif %}
+ {% endfor %}
+ {% endmacro %}
+
+ namespace "urn:opencord:params:xml:ns:voltha:ietf-{{ module.name }}";
+ prefix {{ module.name }};
+
+ {% for imp in module.imports %}
+ import ietf-{{ imp.name }} { prefix {{ imp.name }} ; }
+ {% endfor %}
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "{{ module.description }}";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+ {% for enum in module.enums %}
+ typedef {{ enum.name }} {
+ type enumeration {
+ {% for v in enum.value %}
+ enum {{ v.name }} {
+ description "{{ v.description }}";
+ }
+ {% endfor %}
+ }
+ description
+ "{{ enum.description }}";
+ }
+ {% endfor %}
+
+ {% for message in module.messages recursive %}
+ {% if message.name in module.referred_messages %}
+ grouping {{ message.name }} {
+ {% else %}
+ container {{ message.name }} {
+ {% endif %}
+ description
+ "{{ message.description }}";
+ {% for field in message.fields %}
+ {% if field.type_ref %}
+ {% for dict_item in module.referred_messages_with_keys %}
+ {% if dict_item.name == field.type %}
+ {% if not field.repeated %}
+ container {{ field.name }} {
+ {% else %}
+ list {{ field.name }} {
+ key "{{ dict_item.key }}";
+ {% if not field.repeated %}
+ max-elements 1;
+ {% endif %}
+ {% endif %}
+ uses {{ set_module_prefix(field.type) }}
+ description
+ "{{ field.description }}";
+ }
+ {% endif %}
+ {% endfor %}
+ {% elif field.repeated %}
+ list {{ field.name }} {
+ key "{{ field.name }}";
+ leaf {{ field.name }} {
+ {% if field.type == "decimal64" %}
+ type {{ field.type }} {
+ fraction-digits 5;
+ }
+ {% else %}
+ type {{ set_module_prefix(field.type) }}
+ {% endif %}
+ description
+ "{{ field.description }}";
+ }
+ description
+ "{{ field.description }}";
+ }
+ {% else %}
+ leaf {{ field.name }} {
+ {% if field.type == "decimal64" %}
+ type {{ field.type }} {
+ fraction-digits 5;
+ }
+ {% else %}
+ type {{ set_module_prefix(field.type) }}
+ {% endif %}
+ description
+ "{{ field.description }}";
+ }
+ {% endif %}
+
+ {% endfor %}
+ {% for enum_type in message.enums %}
+ typedef {{ enum_type.name }} {
+ type enumeration {
+ {% for v in enum_type.value %}
+ enum {{ v.name }} {
+ description "{{ v.description }}";
+ }
+ {% endfor %}
+ }
+ description
+ "{{ enum_type.description }}";
+ }
+
+ {% endfor %}
+ {% if message.messages %}
+ {{ loop (message.messages)|indent(4, false) }}
+ {% endif %}
+ }
+
+ {% endfor %}
+ {% for service in module.services %}
+ {% if service.description %}
+ /* {{ service.description }}" */
+ {% endif %}
+ {% for method in service.methods %}
+ rpc {{ service.service }}-{{ method.method }} {
+ description
+ "{{ method.description }}";
+ {% if method.input %}
+ input {
+ {% if method.input_ref %}
+ uses {{ set_module_prefix(method.input) }}
+ {% else %}
+ leaf {{ method.input }} {
+ type {{ set_module_prefix(method.input) }}
+ }
+ {% endif %}
+ }
+ {% endif %}
+ {% if method.output %}
+ output {
+ {% if method.output_ref %}
+ uses {{ set_module_prefix(method.output) }}
+ {% else %}
+ leaf {{ method.output }} {
+ type {{ set_module_prefix(method.output) }}
+ }
+ {% endif %}
+ }
+ {% endif %}
+ }
+
+ {% endfor %}
+
+ {% endfor %}
+}
+""", trim_blocks=True, lstrip_blocks=True)
+
+def traverse_dependencies(descriptor):
+ dependencies = []
+ proto_imports = descriptor.get('dependency', [])
+ for proto_import in proto_imports:
+ # If the import file has a directory path to it remove it as it is not
+ # allowed in Yang. The proto extension should be removed as well
+ dependencies.append (
+ {
+ 'name' : proto_import.split('/')[-1][:-len('.proto')]
+ }
+ )
+ return dependencies
+
+
+def traverse_messages(message_types, prefix, referenced_messages):
+ messages = []
+ for message_type in message_types:
+ assert message_type['_type'] == 'google.protobuf.DescriptorProto'
+
+ # full_name = prefix + '-' + message_type['name']
+ full_name = message_type['name']
+
+ # parse the fields
+ fields = traverse_fields(message_type.get('field', []), full_name,
+ referenced_messages)
+
+ # parse the enums
+ enums = traverse_enums(message_type.get('enum_type', []), full_name)
+
+ # parse nested messages
+ nested = message_type.get('nested_type', [])
+ nested_messages = traverse_messages(nested, full_name,
+ referenced_messages)
+ messages.append(
+ {
+ 'name': full_name,
+ 'fields': fields,
+ 'enums': enums,
+ # 'extensions': extensions,
+ 'messages': nested_messages,
+ 'description': remove_unsupported_characters(
+ message_type.get('_description', '')),
+ # 'extension_ranges': extension_ranges,
+ # 'oneof': oneof
+ }
+ )
+ return messages
+
+
+def traverse_fields(fields_desc, prefix, referenced_messages):
+ fields = []
+ for field in fields_desc:
+ assert field['_type'] == 'google.protobuf.FieldDescriptorProto'
+ yang_base_type = is_base_type(field['type'])
+ _type = get_yang_type(field)
+ if not yang_base_type:
+ referenced_messages.append(_type)
+
+ fields.append(
+ {
+ # 'name': prefix + '-' + field.get('name', ''),
+ 'name': field.get('name', ''),
+ 'label': field.get('label', ''),
+ 'repeated': field['label'] == FieldDescriptor.LABEL_REPEATED,
+ 'number': field.get('number', ''),
+ 'options': field.get('options', ''),
+ 'type_name': field.get('type_name', ''),
+ 'type': _type,
+ 'type_ref': not yang_base_type,
+ 'description': remove_unsupported_characters(field.get(
+ '_description', ''))
+ }
+ )
+ return fields
+
+
+def traverse_enums(enums_desc, prefix):
+ enums = []
+ for enum in enums_desc:
+ assert enum['_type'] == 'google.protobuf.EnumDescriptorProto'
+ # full_name = prefix + '-' + enum.get('name', '')
+ full_name = enum.get('name', '')
+ enums.append(
+ {
+ 'name': full_name,
+ 'value': enum.get('value', ''),
+ 'description': remove_unsupported_characters(enum.get(
+ '_description', ''))
+ }
+ )
+ return enums
+
+
+def traverse_services(service_desc, referenced_messages):
+ services = []
+ for service in service_desc:
+ methods = []
+ for method in service.get('method', []):
+ assert method['_type'] == 'google.protobuf.MethodDescriptorProto'
+
+ input_name = method.get('input_type')
+ input_ref = False
+ if not is_base_type(input_name):
+ input_name = remove_first_character_if_match(input_name, '.')
+ # input_name = input_name.replace(".", "-")
+ input_name = input_name.split('.')[-1]
+ referenced_messages.append(input_name)
+ input_ref = True
+
+ output_name = method.get('output_type')
+ output_ref = False
+ if not is_base_type(output_name):
+ output_name = remove_first_character_if_match(output_name, '.')
+ # output_name = output_name.replace(".", "-")
+ output_name = output_name.split('.')[-1]
+ referenced_messages.append(output_name)
+ output_ref = True
+
+ methods.append(
+ {
+ 'method': method.get('name', ''),
+ 'input': input_name,
+ 'input_ref': input_ref,
+ 'output': output_name,
+ 'output_ref': output_ref,
+ 'description': remove_unsupported_characters(method.get(
+ '_description', '')),
+ 'server_streaming': method.get('server_streaming',
+ False) == True
+ }
+ )
+ services.append(
+ {
+ 'service': service.get('name', ''),
+ 'methods': methods,
+ 'description': remove_unsupported_characters(service.get(
+ '_description', '')),
+ }
+ )
+ return services
+
+
+def rchop(thestring, ending):
+ if thestring.endswith(ending):
+ return thestring[:-len(ending)]
+ return thestring
+
+
+def traverse_desc(descriptor):
+ referenced_messages = []
+ name = rchop(descriptor.get('name', ''), '.proto')
+ package = descriptor.get('package', '')
+ description = descriptor.get('_description', '')
+ # imports=traverse_dependencies(descriptor)
+ messages = traverse_messages(descriptor.get('message_type', []),
+ package, referenced_messages)
+ enums = traverse_enums(descriptor.get('enum_type', []), package)
+ services = traverse_services(descriptor.get('service', []),
+ referenced_messages)
+ # extensions = _traverse_extensions(descriptors)
+ # options = _traverse_options(descriptors)
+ # set_messages_keys(messages)
+ # unique_referred_messages_with_keys = []
+ # for message_name in list(set(referenced_messages)):
+ # unique_referred_messages_with_keys.append(
+ # {
+ # 'name': message_name,
+ # 'key': get_message_key(message_name, messages)
+ # }
+ # )
+
+ # Get a list of type definitions (messages, enums) defined in this
+ # descriptor
+ defined_types = [m['name'].split('/')[-1] for m in messages] + \
+ [e['name'].split('/')[-1] for e in enums]
+
+ data = {
+ 'name': name.split('/')[-1],
+ 'package': package,
+ 'description': description,
+ # 'imports' : imports,
+ 'messages': messages,
+ 'enums': enums,
+ 'services': services,
+ 'defined_types' : defined_types,
+ 'referenced_messages': list(set(referenced_messages)),
+ # TODO: simplify for easier jinja2 template use
+ # 'referred_messages_with_keys': unique_referred_messages_with_keys,
+ # 'extensions': extensions,
+ # 'options': options
+ }
+ return data
+
+
+def set_messages_keys(messages):
+ for message in messages:
+ message['key'] = _get_message_key(message, messages)
+ if message['messages']:
+ set_messages_keys(message['messages'])
+
+def _get_message_key(message, messages):
+ # assume key is first yang base type field
+ for field in message['fields']:
+ if not field['type_ref']:
+ return field['name']
+ else:
+ # if the field name is a message then loop for the key in that
+ # message
+ ref_message = _get_message(field['type'], messages)
+ if ref_message:
+ return _get_message_key(ref_message, messages)
+
+ # no key yet - search nested messaged
+ for m in message['messages']:
+ key = _get_message_key(m, messages)
+ if key is not None:
+ return key
+ else:
+ return None
+
+def _get_message(name, messages):
+ for m in messages:
+ if m['name'] == name:
+ return m
+ return None
+
+def get_message_key(message_name, messages):
+ for message in messages:
+ if message_name == message['name']:
+ return message['key']
+ if message['messages']:
+ return get_message_key(message_name, message['messages'])
+ return None
+
+
+def update_module_imports(module):
+ used_imports = []
+ for ref_msg in module['referenced_messages']:
+ for type_dict in module['data_types']:
+ if ref_msg == type_dict['type']:
+ if module['name'] != type_dict['module']:
+ print '{}++++{}'.format(module['name'], type_dict[
+ 'module'])
+ used_imports.append(
+ {
+ 'name' : type_dict['module']
+ }
+ )
+ break
+ module['imports'] = used_imports
+
+def generate_code(request, response):
+ assert isinstance(request, plugin.CodeGeneratorRequest)
+
+ parser = DescriptorParser()
+
+ # First process the proto file with the imports
+ all_defined_types = []
+ all_proto_data = []
+ all_referred_messages = []
+ all_messages = []
+ for proto_file in request.proto_file:
+ native_data = parser.parse_file_descriptor(proto_file,
+ type_tag_name='_type',
+ fold_comments=True)
+
+ # Consolidate the defined types across imports
+ yang_data = traverse_desc(native_data)
+ for type in yang_data['defined_types']:
+ all_defined_types.append(
+ {
+ 'type' : type,
+ 'module' : yang_data['name']
+ }
+ )
+
+ all_proto_data.append(
+ {
+ 'file_name': '{}-{}'.format('ietf', proto_file.name.split(
+ '/')[-1].replace('.proto','.yang')),
+ 'module': yang_data
+ }
+ )
+
+ # Consolidate referred messages across imports
+ all_referred_messages = all_referred_messages + yang_data['referenced_messages']
+
+ # consolidate all messages
+ all_messages = all_messages + yang_data['messages']
+
+ # Set the message keys - required for List definitions (repeated label)
+ set_messages_keys(all_messages)
+ unique_referred_messages_with_keys = []
+ for m in all_messages:
+ unique_referred_messages_with_keys.append(
+ {
+ 'name': m['name'],
+ 'key': m['key']
+ }
+ )
+
+ # Create the files
+ for proto_data in all_proto_data:
+ f = response.file.add()
+ f.name = proto_data['file_name']
+ proto_data['module']['data_types'] = all_defined_types
+ proto_data['module']['referred_messages'] = all_referred_messages
+ proto_data['module']['referred_messages_with_keys'] = unique_referred_messages_with_keys
+ update_module_imports(proto_data['module'])
+ f.content = template_yang.render(module=proto_data['module'])
+
+
+def get_yang_type(field):
+ type = field['type']
+ if type in YANG_TYPE_MAP.keys():
+ _type, _ = YANG_TYPE_MAP[type]
+ if _type in ['enumeration', 'message', 'group']:
+ return field['type_name'].split('.')[-1]
+ # return remove_first_character_if_match(field['type_name'],
+ # '.').replace('.', '-')
+ else:
+ return _type
+ else:
+ return type
+
+
+def is_base_type(type):
+ # check numeric value of the type first
+ if type in YANG_TYPE_MAP.keys():
+ _type, _ = YANG_TYPE_MAP[type]
+ return _type not in ['message', 'group']
+ else:
+ # proto name of the type
+ result = [_format for (_, _format) in YANG_TYPE_MAP.values() if
+ _format == type and _format not in ['message', 'group']]
+ return len(result) > 0
+
+
+def remove_unsupported_characters(text):
+ unsupported_characters = ["{", "}", "[", "]", "\"", "\\", "*", "/"]
+ return ''.join([i if i not in unsupported_characters else ' ' for i in
+ text])
+
+
+def remove_first_character_if_match(str, char):
+ if str.startswith(char):
+ return str[1:]
+ return str
+
+
+YANG_TYPE_MAP = {
+ FieldDescriptor.TYPE_BOOL: ('boolean', 'boolean'),
+ FieldDescriptor.TYPE_BYTES: ('binary', 'byte'),
+ FieldDescriptor.TYPE_DOUBLE: ('decimal64', 'double'),
+ FieldDescriptor.TYPE_ENUM: ('enumeration', 'enum'),
+ FieldDescriptor.TYPE_FIXED32: ('int32', 'int64'),
+ FieldDescriptor.TYPE_FIXED64: ('int64', 'uint64'),
+ FieldDescriptor.TYPE_FLOAT: ('decimal64', 'float'),
+ FieldDescriptor.TYPE_INT32: ('int32', 'int32'),
+ FieldDescriptor.TYPE_INT64: ('int64', 'int64'),
+ FieldDescriptor.TYPE_SFIXED32: ('int32', 'int32'),
+ FieldDescriptor.TYPE_SFIXED64: ('int64', 'int64'),
+ FieldDescriptor.TYPE_STRING: ('string', 'string'),
+ FieldDescriptor.TYPE_SINT32: ('int32', 'int32'),
+ FieldDescriptor.TYPE_SINT64: ('int64', 'int64'),
+ FieldDescriptor.TYPE_UINT32: ('uint32', 'int64'),
+ FieldDescriptor.TYPE_UINT64: ('uint64', 'uint64'),
+ FieldDescriptor.TYPE_MESSAGE: ('message', 'message'),
+ FieldDescriptor.TYPE_GROUP: ('group', 'group')
+}
+
+if __name__ == '__main__':
+ # Read request message from stdin
+ data = sys.stdin.read()
+
+ # Parse request
+ request = plugin.CodeGeneratorRequest()
+ request.ParseFromString(data)
+
+ # Create response
+ response = plugin.CodeGeneratorResponse()
+
+ # Generate code
+ generate_code(request, response)
+
+ # Serialise response message
+ output = response.SerializeToString()
+
+ # Write to stdout
+ sys.stdout.write(output)
+ # print is_base_type(9)
diff --git a/netconf/protoc_plugins/proto2yang_work_list.py b/netconf/protoc_plugins/proto2yang_work_list.py
new file mode 100755
index 0000000..eba8924
--- /dev/null
+++ b/netconf/protoc_plugins/proto2yang_work_list.py
@@ -0,0 +1,552 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+"""protoc plugin to convert a protobuf schema to a yang schema
+
+ - basic support for message, fields. enumeration, service, method
+
+ - yang semantic rules needs to be implemented
+
+ - to run this plugin :
+
+ $ python -m grpc.tools.protoc -I.
+ --plugin=protoc-gen-custom=./proto2yang.py --custom_out=. <proto file>.proto
+
+ - the above will produce a ietf-<proto file>.yang file formatted for yang
+
+ - two examples of proto that can be used in the same directory are
+ yang.proto and addressbook.proto
+
+"""
+
+import sys
+
+from jinja2 import Template
+from google.protobuf.compiler import plugin_pb2 as plugin
+from descriptor_parser import DescriptorParser
+
+from google.protobuf.descriptor import FieldDescriptor
+
+template_yang = Template("""
+module ietf-{{ module.name }} {
+
+ {% macro set_module_prefix(type) %}
+ {% for t in module.data_types %}
+ {% if t.type == type %}
+ {% if t.module != module.name %} {{ t.module }}:{{ type }};
+ {% else %} {{ type }};
+ {% endif %}
+ {% set found=True %}
+ {% endif %}
+ {% if loop.last %}
+ {% if not found %} {{ type }}; {% endif %}
+ {% endif %}
+ {% endfor %}
+ {% endmacro %}
+
+ yang-version 1.1;
+ namespace "urn:ietf:params:xml:ns:yang:ietf-{{ module.name }}";
+ prefix {{ module.name }};
+
+ {% for imp in module.imports %}
+ import ietf-{{ imp.name }} { prefix {{ imp.name }} ; }
+ {% endfor %}
+
+ organization "CORD";
+ contact
+ " Any name";
+
+ description
+ "{{ module.description }}";
+
+ revision "2016-11-15" {
+ description "Initial revision.";
+ reference "reference";
+ }
+
+ {% for enum in module.enums %}
+ typedef {{ enum.name }} {
+ type enumeration {
+ {% for v in enum.value %}
+ enum {{ v.name }} {
+ description "{{ v.description }}";
+ }
+ {% endfor %}
+ }
+ description
+ "{{ enum.description }}";
+ }
+ {% endfor %}
+
+ {% for message in module.messages recursive %}
+ {% if message.name in module.referred_messages %}
+ grouping {{ message.name }} {
+ {% else %}
+ container {{ message.name }} {
+ {% endif %}
+ description
+ "{{ message.description }}";
+ {% for field in message.fields %}
+ {% if field.type_ref %}
+ {% for dict_item in module.referred_messages_with_keys %}
+ {% if dict_item.name == field.type %}
+ list {{ field.name }} {
+ key "{{ dict_item.key }}";
+ {% if not field.repeated %}
+ max-elements 1;
+ {% endif %}
+ uses {{ set_module_prefix(field.type) }}
+ description
+ "{{ field.description }}";
+ }
+ {% endif %}
+ {% endfor %}
+ {% elif field.repeated %}
+ list {{ field.name }} {
+ key "{{ field.name }}";
+ leaf {{ field.name }} {
+ {% if field.type == "decimal64" %}
+ type {{ field.type }} {
+ fraction-digits 5;
+ }
+ {% else %}
+ type {{ set_module_prefix(field.type) }}
+ {% endif %}
+ description
+ "{{ field.description }}";
+ }
+ description
+ "{{ field.description }}";
+ }
+ {% else %}
+ leaf {{ field.name }} {
+ {% if field.type == "decimal64" %}
+ type {{ field.type }} {
+ fraction-digits 5;
+ }
+ {% else %}
+ type {{ set_module_prefix(field.type) }}
+ {% endif %}
+ description
+ "{{ field.description }}";
+ }
+ {% endif %}
+
+ {% endfor %}
+ {% for enum_type in message.enums %}
+ typedef {{ enum_type.name }} {
+ type enumeration {
+ {% for v in enum_type.value %}
+ enum {{ v.name }} {
+ description "{{ v.description }}";
+ }
+ {% endfor %}
+ }
+ description
+ "{{ enum_type.description }}";
+ }
+
+ {% endfor %}
+ {% if message.messages %}
+ {{ loop (message.messages)|indent(4, false) }}
+ {% endif %}
+ }
+
+ {% endfor %}
+ {% for service in module.services %}
+ {% if service.description %}
+ /* {{ service.description }}" */
+ {% endif %}
+ {% for method in service.methods %}
+ rpc {{ service.service }}-{{ method.method }} {
+ description
+ "{{ method.description }}";
+ {% if method.input %}
+ input {
+ {% if method.input_ref %}
+ uses {{ set_module_prefix(method.input) }}
+ {% else %}
+ leaf {{ method.input }} {
+ type {{ set_module_prefix(method.input) }}
+ }
+ {% endif %}
+ }
+ {% endif %}
+ {% if method.output %}
+ output {
+ {% if method.output_ref %}
+ uses {{ set_module_prefix(method.output) }}
+ {% else %}
+ leaf {{ method.output }} {
+ type {{ set_module_prefix(method.output) }}
+ }
+ {% endif %}
+ }
+ {% endif %}
+ }
+
+ {% endfor %}
+
+ {% endfor %}
+}
+""", trim_blocks=True, lstrip_blocks=True)
+
+def traverse_dependencies(descriptor):
+ dependencies = []
+ proto_imports = descriptor.get('dependency', [])
+ for proto_import in proto_imports:
+ # If the import file has a directory path to it remove it as it is not
+ # allowed in Yang. The proto extension should be removed as well
+ dependencies.append (
+ {
+ 'name' : proto_import.split('/')[-1][:-len('.proto')]
+ }
+ )
+ return dependencies
+
+
+def traverse_messages(message_types, prefix, referenced_messages):
+ messages = []
+ for message_type in message_types:
+ assert message_type['_type'] == 'google.protobuf.DescriptorProto'
+
+ # full_name = prefix + '-' + message_type['name']
+ full_name = message_type['name']
+
+ # parse the fields
+ fields = traverse_fields(message_type.get('field', []), full_name,
+ referenced_messages)
+
+ # parse the enums
+ enums = traverse_enums(message_type.get('enum_type', []), full_name)
+
+ # parse nested messages
+ nested = message_type.get('nested_type', [])
+ nested_messages = traverse_messages(nested, full_name,
+ referenced_messages)
+ messages.append(
+ {
+ 'name': full_name,
+ 'fields': fields,
+ 'enums': enums,
+ # 'extensions': extensions,
+ 'messages': nested_messages,
+ 'description': remove_unsupported_characters(
+ message_type.get('_description', '')),
+ # 'extension_ranges': extension_ranges,
+ # 'oneof': oneof
+ }
+ )
+ return messages
+
+
+def traverse_fields(fields_desc, prefix, referenced_messages):
+ fields = []
+ for field in fields_desc:
+ assert field['_type'] == 'google.protobuf.FieldDescriptorProto'
+ yang_base_type = is_base_type(field['type'])
+ _type = get_yang_type(field)
+ if not yang_base_type:
+ referenced_messages.append(_type)
+
+ fields.append(
+ {
+ # 'name': prefix + '-' + field.get('name', ''),
+ 'name': field.get('name', ''),
+ 'label': field.get('label', ''),
+ 'repeated': field['label'] == FieldDescriptor.LABEL_REPEATED,
+ 'number': field.get('number', ''),
+ 'options': field.get('options', ''),
+ 'type_name': field.get('type_name', ''),
+ 'type': _type,
+ 'type_ref': not yang_base_type,
+ 'description': remove_unsupported_characters(field.get(
+ '_description', ''))
+ }
+ )
+ return fields
+
+
+def traverse_enums(enums_desc, prefix):
+ enums = []
+ for enum in enums_desc:
+ assert enum['_type'] == 'google.protobuf.EnumDescriptorProto'
+ # full_name = prefix + '-' + enum.get('name', '')
+ full_name = enum.get('name', '')
+ enums.append(
+ {
+ 'name': full_name,
+ 'value': enum.get('value', ''),
+ 'description': remove_unsupported_characters(enum.get(
+ '_description', ''))
+ }
+ )
+ return enums
+
+
+def traverse_services(service_desc, referenced_messages):
+ services = []
+ for service in service_desc:
+ methods = []
+ for method in service.get('method', []):
+ assert method['_type'] == 'google.protobuf.MethodDescriptorProto'
+
+ input_name = method.get('input_type')
+ input_ref = False
+ if not is_base_type(input_name):
+ input_name = remove_first_character_if_match(input_name, '.')
+ # input_name = input_name.replace(".", "-")
+ input_name = input_name.split('.')[-1]
+ referenced_messages.append(input_name)
+ input_ref = True
+
+ output_name = method.get('output_type')
+ output_ref = False
+ if not is_base_type(output_name):
+ output_name = remove_first_character_if_match(output_name, '.')
+ # output_name = output_name.replace(".", "-")
+ output_name = output_name.split('.')[-1]
+ referenced_messages.append(output_name)
+ output_ref = True
+
+ methods.append(
+ {
+ 'method': method.get('name', ''),
+ 'input': input_name,
+ 'input_ref': input_ref,
+ 'output': output_name,
+ 'output_ref': output_ref,
+ 'description': remove_unsupported_characters(method.get(
+ '_description', '')),
+ 'server_streaming': method.get('server_streaming',
+ False) == True
+ }
+ )
+ services.append(
+ {
+ 'service': service.get('name', ''),
+ 'methods': methods,
+ 'description': remove_unsupported_characters(service.get(
+ '_description', '')),
+ }
+ )
+ return services
+
+
+def rchop(thestring, ending):
+ if thestring.endswith(ending):
+ return thestring[:-len(ending)]
+ return thestring
+
+
+def traverse_desc(descriptor):
+ referenced_messages = []
+ name = rchop(descriptor.get('name', ''), '.proto')
+ package = descriptor.get('package', '')
+ description = descriptor.get('_description', '')
+ imports=traverse_dependencies(descriptor)
+ messages = traverse_messages(descriptor.get('message_type', []),
+ package, referenced_messages)
+ enums = traverse_enums(descriptor.get('enum_type', []), package)
+ services = traverse_services(descriptor.get('service', []),
+ referenced_messages)
+ # extensions = _traverse_extensions(descriptors)
+ # options = _traverse_options(descriptors)
+ set_messages_keys(messages)
+ unique_referred_messages_with_keys = []
+ for message_name in list(set(referenced_messages)):
+ unique_referred_messages_with_keys.append(
+ {
+ 'name': message_name,
+ 'key': get_message_key(message_name, messages)
+ }
+ )
+
+ # Get a list of type definitions (messages, enums) defined in this
+ # descriptor
+ defined_types = [m['name'].split('/')[-1] for m in messages] + \
+ [e['name'].split('/')[-1] for e in enums]
+
+ data = {
+ 'name': name.split('/')[-1],
+ 'package': package,
+ 'description': description,
+ 'imports' : imports,
+ 'messages': messages,
+ 'enums': enums,
+ 'services': services,
+ 'defined_types' : defined_types,
+ 'referenced_messages': list(set(referenced_messages)),
+ # TODO: simplify for easier jinja2 template use
+ 'referred_messages_with_keys': unique_referred_messages_with_keys,
+ # 'extensions': extensions,
+ # 'options': options
+ }
+ return data
+
+
+def set_messages_keys(messages):
+ for message in messages:
+ message['key'] = _get_message_key(message)
+ if message['messages']:
+ set_messages_keys(message['messages'])
+
+
+def _get_message_key(message):
+ # assume key is first yang base type field
+ for field in message['fields']:
+ if not field['type_ref']:
+ return field['name']
+ # no key yet - search nested messaged
+ if message['messages']:
+ return get_message_key(message['name'], message['messages'])
+ else:
+ return None
+
+
+def get_message_key(message_name, messages):
+ for message in messages:
+ if message_name == message['name']:
+ return message['key']
+ if message['messages']:
+ return get_message_key(message_name, message['messages'])
+ return None
+
+
+def generate_code(request, response):
+ assert isinstance(request, plugin.CodeGeneratorRequest)
+
+ parser = DescriptorParser()
+
+ # First process the proto file with the imports
+ all_defined_types = []
+ all_proto_data = []
+ all_referred_messages = []
+ for proto_file in request.proto_file:
+ native_data = parser.parse_file_descriptor(proto_file,
+ type_tag_name='_type',
+ fold_comments=True)
+
+ # Consolidate the defined types across imports
+ yang_data = traverse_desc(native_data)
+ for type in yang_data['defined_types']:
+ all_defined_types.append(
+ {
+ 'type' : type,
+ 'module' : yang_data['name']
+ }
+ )
+
+ all_proto_data.append(
+ {
+ 'file_name': '{}-{}'.format('ietf', proto_file.name.split(
+ '/')[-1].replace('.proto','.yang')),
+ 'module': yang_data
+ }
+ )
+
+ # Consolidate referred messages across imports
+ all_referred_messages = all_referred_messages + yang_data['referenced_messages']
+
+ # Create the files
+ for proto_data in all_proto_data:
+ f = response.file.add()
+ f.name = proto_data['file_name']
+ proto_data['module']['data_types'] = all_defined_types
+ proto_data['module']['referred_messages'] = all_referred_messages
+ f.content = template_yang.render(module=proto_data['module'])
+
+
+def get_yang_type(field):
+ type = field['type']
+ if type in YANG_TYPE_MAP.keys():
+ _type, _ = YANG_TYPE_MAP[type]
+ if _type in ['enumeration', 'message', 'group']:
+ return field['type_name'].split('.')[-1]
+ # return remove_first_character_if_match(field['type_name'],
+ # '.').replace('.', '-')
+ else:
+ return _type
+ else:
+ return type
+
+
+def is_base_type(type):
+ # check numeric value of the type first
+ if type in YANG_TYPE_MAP.keys():
+ _type, _ = YANG_TYPE_MAP[type]
+ return _type not in ['message', 'group']
+ else:
+ # proto name of the type
+ result = [_format for (_, _format) in YANG_TYPE_MAP.values() if
+ _format == type and _format not in ['message', 'group']]
+ return len(result) > 0
+
+
+def remove_unsupported_characters(text):
+ unsupported_characters = ["{", "}", "[", "]", "\"", "\\", "*", "/"]
+ return ''.join([i if i not in unsupported_characters else ' ' for i in
+ text])
+
+
+def remove_first_character_if_match(str, char):
+ if str.startswith(char):
+ return str[1:]
+ return str
+
+
+YANG_TYPE_MAP = {
+ FieldDescriptor.TYPE_BOOL: ('boolean', 'boolean'),
+ FieldDescriptor.TYPE_BYTES: ('binary', 'byte'),
+ FieldDescriptor.TYPE_DOUBLE: ('decimal64', 'double'),
+ FieldDescriptor.TYPE_ENUM: ('enumeration', 'enum'),
+ FieldDescriptor.TYPE_FIXED32: ('int32', 'int64'),
+ FieldDescriptor.TYPE_FIXED64: ('int64', 'uint64'),
+ FieldDescriptor.TYPE_FLOAT: ('decimal64', 'float'),
+ FieldDescriptor.TYPE_INT32: ('int32', 'int32'),
+ FieldDescriptor.TYPE_INT64: ('int64', 'int64'),
+ FieldDescriptor.TYPE_SFIXED32: ('int32', 'int32'),
+ FieldDescriptor.TYPE_SFIXED64: ('int64', 'int64'),
+ FieldDescriptor.TYPE_STRING: ('string', 'string'),
+ FieldDescriptor.TYPE_SINT32: ('int32', 'int32'),
+ FieldDescriptor.TYPE_SINT64: ('int64', 'int64'),
+ FieldDescriptor.TYPE_UINT32: ('uint32', 'int64'),
+ FieldDescriptor.TYPE_UINT64: ('uint64', 'uint64'),
+ FieldDescriptor.TYPE_MESSAGE: ('message', 'message'),
+ FieldDescriptor.TYPE_GROUP: ('group', 'group')
+}
+
+if __name__ == '__main__':
+ # Read request message from stdin
+ data = sys.stdin.read()
+
+ # Parse request
+ request = plugin.CodeGeneratorRequest()
+ request.ParseFromString(data)
+
+ # Create response
+ response = plugin.CodeGeneratorResponse()
+
+ # Generate code
+ generate_code(request, response)
+
+ # Serialise response message
+ output = response.SerializeToString()
+
+ # Write to stdout
+ sys.stdout.write(output)
+ # print is_base_type(9)
diff --git a/netconf/protoc_plugins/yang.proto b/netconf/protoc_plugins/yang.proto
new file mode 100644
index 0000000..718951c
--- /dev/null
+++ b/netconf/protoc_plugins/yang.proto
@@ -0,0 +1,64 @@
+syntax = "proto3";
+
+package experiment;
+
+message AsyncEvent {
+ int32 seq = 1;
+ enum EventType {
+ BIG_BANG = 0; // just a big bang
+ SMALL_BANG = 1; // so small bang
+ NO_BANG = 2;
+ }
+ EventType type = 2;
+ string details = 3;
+}
+
+enum SimpleEnum {
+ APPLE = 0;
+ BANANA = 1;
+ ORANGE = 2;
+}
+
+message Packet {
+ int32 source = 1;
+ bytes content = 2;
+ message InnerPacket {
+ string url = 1;
+ string title = 2;
+ repeated string snippets = 3;
+ message InnerInnerPacket {
+ string input = 1;
+ string desc = 2;
+ }
+ repeated InnerInnerPacket inner_inner_packet = 4;
+ }
+ repeated InnerPacket inner_packets = 3;
+}
+
+message Echo {
+ string msg = 1;
+ float delay = 2;
+}
+
+message testMessage{
+ oneof oneOfTest {
+ string test2 = 1;
+ int32 test3 = 2;
+ }
+}
+
+service ExperimentalService {
+
+ rpc GetEcho(Echo) returns(Echo);
+
+ // For server to send async stream to client
+ rpc ReceiveStreamedEvents(Packet)
+ returns(stream AsyncEvent);
+
+ // For server to send async packets to client
+ rpc ReceivePackets(Echo) returns(stream Packet);
+
+ // For client to send async packets to server
+ rpc SendPackets(stream Packet) returns(Echo);
+
+}
\ No newline at end of file
diff --git a/netconf/protos/Makefile b/netconf/protos/Makefile
index 2d9c069..008a531 100644
--- a/netconf/protos/Makefile
+++ b/netconf/protos/Makefile
@@ -20,14 +20,12 @@
$(error To get started, please source the env.sh file from Voltha top level directory)
endif
-# This makefile is used only to copy relevant *_pb2.py files from Voltha
-# to allow ofagent to function properly.
+default: build
PB2_FILES := \
- voltha_pb2.py \
- openflow_13_pb2.py
+ voltha_pb2.py
-TARGET_PROTO_DIR := $(VOLTHA_BASE)/ofagent/protos
+TARGET_PROTO_DIR := $(VOLTHA_BASE)/netconf/protos
SOURCE_PROTO_DIR := $(VOLTHA_BASE)/voltha/protos
build: copyfiles
@@ -35,3 +33,25 @@
copyfiles:
rsync -av --include '*/' --exclude='third_party/__init__.py' --include '*.py' --exclude='*' $(SOURCE_PROTO_DIR)/ $(TARGET_PROTO_DIR)
+
+PROTO_FILES := $(wildcard *.proto) $(wildcard third_party/google/api/*proto)
+PROTO_PB2_FILES := $(foreach f,$(PROTO_FILES),$(subst .proto,_pb2.py,$(f)))
+PROTO_DESC_FILES := $(foreach f,$(PROTO_FILES),$(subst .proto,.desc,$(f)))
+
+PROTOC_PREFIX := /usr/local
+PROTOC_LIBDIR := $(PROTOC_PREFIX)/lib
+
+build: $(PROTO_PB2_FILES)
+
+%_pb2.py: %.proto Makefile
+ @echo "Building protocol buffer artifacts from $<"
+ env LD_LIBRARY_PATH=$(PROTOC_LIBDIR) python -m grpc.tools.protoc \
+ -I. \
+ -I./third_party \
+ --python_out=. \
+ --grpc_python_out=. \
+ $<
+
+clean:
+ rm -f $(PROTO_PB2_FILES) $(PROTO_DESC_FILES)
+
diff --git a/netconf/protos/__init__.py b/netconf/protos/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/netconf/protos/__init__.py
diff --git a/netconf/protos/schema.proto b/netconf/protos/schema.proto
new file mode 100644
index 0000000..5114208
--- /dev/null
+++ b/netconf/protos/schema.proto
@@ -0,0 +1,34 @@
+syntax = "proto3";
+
+package schema;
+
+import "google/protobuf/empty.proto";
+
+// Contains the name and content of a *.proto file
+message ProtoFile {
+ string file_name = 1; // name of proto file
+ string proto = 2; // content of proto file
+ bytes descriptor = 3; // compiled descriptor for proto (zlib compressed)
+}
+
+// Proto files and compiled descriptors for this interface
+message Schemas {
+
+ // Proto files
+ repeated ProtoFile protos = 1;
+
+ // Name of proto file to generae swagger.json from
+ string swagger_from = 2;
+
+ // Prefix of proto files which would require a yang file generated for it
+ string yang_from = 3;
+
+}
+
+// Schema services
+service SchemaService {
+
+ // Return active grpc schemas
+ rpc GetSchema(google.protobuf.Empty) returns (Schemas) {}
+
+}
diff --git a/netconf/protos/third_party/__init__.py b/netconf/protos/third_party/__init__.py
index 6dab4e7..e53147b 100644
--- a/netconf/protos/third_party/__init__.py
+++ b/netconf/protos/third_party/__init__.py
@@ -38,7 +38,7 @@
def load_module(self, name):
if name in sys.modules:
return sys.modules[name]
- full_name = 'ofagent.protos.third_party.' + name
+ full_name = 'netconf.protos.third_party.' + name
import_module(full_name)
module = sys.modules[full_name]
sys.modules[name] = module
diff --git a/netconf/protos/third_party/google/api/annotations.proto b/netconf/protos/third_party/google/api/annotations.proto
new file mode 100644
index 0000000..cbd18b8
--- /dev/null
+++ b/netconf/protos/third_party/google/api/annotations.proto
@@ -0,0 +1,29 @@
+// Copyright (c) 2015, Google Inc.
+//
+// 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.
+
+syntax = "proto3";
+
+package google.api;
+
+import "google/api/http.proto";
+import "google/protobuf/descriptor.proto";
+
+option java_multiple_files = true;
+option java_outer_classname = "AnnotationsProto";
+option java_package = "com.google.api";
+
+extend google.protobuf.MethodOptions {
+ // See `HttpRule`.
+ HttpRule http = 72295728;
+}
diff --git a/netconf/protos/third_party/google/api/http.proto b/netconf/protos/third_party/google/api/http.proto
new file mode 100644
index 0000000..ce07aa1
--- /dev/null
+++ b/netconf/protos/third_party/google/api/http.proto
@@ -0,0 +1,127 @@
+// Copyright (c) 2015, Google Inc.
+//
+// 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.
+
+syntax = "proto3";
+
+package google.api;
+
+option java_multiple_files = true;
+option java_outer_classname = "HttpProto";
+option java_package = "com.google.api";
+
+
+// `HttpRule` defines the mapping of an RPC method to one or more HTTP REST API
+// methods. The mapping determines what portions of the request message are
+// populated from the path, query parameters, or body of the HTTP request. The
+// mapping is typically specified as an `google.api.http` annotation, see
+// "google/api/annotations.proto" for details.
+//
+// The mapping consists of a mandatory field specifying a path template and an
+// optional `body` field specifying what data is represented in the HTTP request
+// body. The field name for the path indicates the HTTP method. Example:
+//
+// ```
+// package google.storage.v2;
+//
+// import "google/api/annotations.proto";
+//
+// service Storage {
+// rpc CreateObject(CreateObjectRequest) returns (Object) {
+// option (google.api.http) {
+// post: "/v2/{bucket_name=buckets/*}/objects"
+// body: "object"
+// };
+// };
+// }
+// ```
+//
+// Here `bucket_name` and `object` bind to fields of the request message
+// `CreateObjectRequest`.
+//
+// The rules for mapping HTTP path, query parameters, and body fields
+// to the request message are as follows:
+//
+// 1. The `body` field specifies either `*` or a field path, or is
+// omitted. If omitted, it assumes there is no HTTP body.
+// 2. Leaf fields (recursive expansion of nested messages in the
+// request) can be classified into three types:
+// (a) Matched in the URL template.
+// (b) Covered by body (if body is `*`, everything except (a) fields;
+// else everything under the body field)
+// (c) All other fields.
+// 3. URL query parameters found in the HTTP request are mapped to (c) fields.
+// 4. Any body sent with an HTTP request can contain only (b) fields.
+//
+// The syntax of the path template is as follows:
+//
+// Template = "/" Segments [ Verb ] ;
+// Segments = Segment { "/" Segment } ;
+// Segment = "*" | "**" | LITERAL | Variable ;
+// Variable = "{" FieldPath [ "=" Segments ] "}" ;
+// FieldPath = IDENT { "." IDENT } ;
+// Verb = ":" LITERAL ;
+//
+// `*` matches a single path component, `**` zero or more path components, and
+// `LITERAL` a constant. A `Variable` can match an entire path as specified
+// again by a template; this nested template must not contain further variables.
+// If no template is given with a variable, it matches a single path component.
+// The notation `{var}` is henceforth equivalent to `{var=*}`.
+//
+// Use CustomHttpPattern to specify any HTTP method that is not included in the
+// pattern field, such as HEAD, or "*" to leave the HTTP method unspecified for
+// a given URL path rule. The wild-card rule is useful for services that provide
+// content to Web (HTML) clients.
+message HttpRule {
+
+ // Determines the URL pattern is matched by this rules. This pattern can be
+ // used with any of the {get|put|post|delete|patch} methods. A custom method
+ // can be defined using the 'custom' field.
+ oneof pattern {
+ // Used for listing and getting information about resources.
+ string get = 2;
+
+ // Used for updating a resource.
+ string put = 3;
+
+ // Used for creating a resource.
+ string post = 4;
+
+ // Used for deleting a resource.
+ string delete = 5;
+
+ // Used for updating a resource.
+ string patch = 6;
+
+ // Custom pattern is used for defining custom verbs.
+ CustomHttpPattern custom = 8;
+ }
+
+ // The name of the request field whose value is mapped to the HTTP body, or
+ // `*` for mapping all fields not captured by the path pattern to the HTTP
+ // body.
+ string body = 7;
+
+ // Additional HTTP bindings for the selector. Nested bindings must not
+ // specify a selector and must not contain additional bindings.
+ repeated HttpRule additional_bindings = 11;
+}
+
+// A custom pattern is used for defining custom HTTP verb.
+message CustomHttpPattern {
+ // The name of this custom HTTP verb.
+ string kind = 1;
+
+ // The path matched by this custom verb.
+ string path = 2;
+}
diff --git a/netconf/session/nc_protocol_handler.py b/netconf/session/nc_protocol_handler.py
index e0a4baf..a08ea37 100644
--- a/netconf/session/nc_protocol_handler.py
+++ b/netconf/session/nc_protocol_handler.py
@@ -33,11 +33,11 @@
class NetconfProtocolHandler:
- def __init__(self, nc_server, nc_conn, session, grpc_stub):
+ def __init__(self, nc_server, nc_conn, session, grpc_client):
self.started = True
self.conn = nc_conn
self.nc_server = nc_server
- self.grpc_stub = grpc_stub
+ self.grpc_client = grpc_client
self.new_framing = False
self.capabilities = Capabilities()
self.session = session
@@ -171,6 +171,7 @@
# Get a rpc handler
rpc_handler = rpc_factory.get_rpc_handler(rpc,
msg,
+ self.grpc_client,
self.session)
if rpc_handler:
# set the parameters for this handler
@@ -206,21 +207,6 @@
error = ncerror.ServerException(rpc, ex)
self.send_message(error.get_reply_msg())
- # @inlineCallbacks
- # def invoke_method(self, rpcname, rpc, params):
- # try:
- # # Handle any namespaces or prefixes in the tag, other than
- # # "nc" which was removed above. Of course, this does not handle
- # # namespace collisions, but that seems reasonable for now.
- # rpcname = rpcname.rpartition("}")[-1]
- # method_name = "rpc_" + rpcname.replace('-', '_')
- # method = getattr(self.methods, method_name,
- # self._rpc_not_implemented)
- # log.info("invoking-method", method=method_name)
- # reply = yield method(self, rpc, *params)
- # returnValue(reply)
- # except NotImplementedError:
- # raise ncerror.NotImpl(rpc)
def stop(self, reason):
if not self.exiting:
diff --git a/requirements.txt b/requirements.txt
index 3c660d7..80291fe 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -38,6 +38,8 @@
Twisted>=13.2.0
urllib3>=1.7.1
pyang>=1.7
+lxml
+dicttoxml
# python-consul>=0.6.1 we need the pre-released version for now, because 0.6.1 does not
# yet support Twisted. Once this is released, it will be the 0.6.2 version
diff --git a/voltha/northbound/grpc/grpc_server.py b/voltha/northbound/grpc/grpc_server.py
index 86dca34..778d547 100644
--- a/voltha/northbound/grpc/grpc_server.py
+++ b/voltha/northbound/grpc/grpc_server.py
@@ -43,7 +43,8 @@
self.thread_pool = thread_pool
protos = self._load_schema()
self.schemas = schema_pb2.Schemas(protos=protos,
- swagger_from='voltha.proto')
+ swagger_from='voltha.proto',
+ yang_from='voltha.proto')
def stop(self):
pass
diff --git a/voltha/protos/schema.proto b/voltha/protos/schema.proto
index e75f696..1023f1a 100644
--- a/voltha/protos/schema.proto
+++ b/voltha/protos/schema.proto
@@ -21,6 +21,8 @@
// Proto file name from which swagger.json shall be generated
string swagger_from = 2;
+ // Proto file name from which yang schemas shall be generated
+ string yang_from = 3;
}
// Schema services