Implement REST API of policy

Change-Id: I46f5a3cd6d66cf7a3a90a5d153b3878fdf5cbd31
diff --git a/web/src/main/java/org/onosproject/segmentrouting/web/PolicyCodec.java b/web/src/main/java/org/onosproject/segmentrouting/web/PolicyCodec.java
deleted file mode 100644
index 0dedc7c..0000000
--- a/web/src/main/java/org/onosproject/segmentrouting/web/PolicyCodec.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2015-present Open Networking Foundation
- *
- * 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.
- */
-package org.onosproject.segmentrouting.web;
-
-import org.onosproject.codec.CodecContext;
-import org.onosproject.codec.JsonCodec;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import org.onosproject.segmentrouting.Policy;
-import org.onosproject.segmentrouting.TunnelPolicy;
-
-/**
- * Codec of Policy class.
- */
-public final class PolicyCodec extends JsonCodec<Policy> {
-
-    // JSON field names
-    private static final String POLICY_ID = "policy_id";
-    private static final String PRIORITY = "priority";
-    private static final String TYPE = "policy_type";
-    private static final String TUNNEL_ID = "tunnel_id";
-    private static final String DST_IP = "dst_ip";
-    private static final String SRC_IP = "src_ip";
-    private static final String PROTO_TYPE = "proto_type";
-    private static final String SRC_PORT = "src_tp_port";
-    private static final String DST_PORT = "dst_tp_port";
-
-    @Override
-    public ObjectNode encode(Policy policy, CodecContext context) {
-        final ObjectNode result = context.mapper().createObjectNode()
-                .put(POLICY_ID, policy.id());
-
-        result.put(PRIORITY, policy.priority());
-        result.put(TYPE, policy.type().toString());
-
-        if (policy.dstIp() != null) {
-            result.put(DST_IP, policy.dstIp());
-        }
-        if (policy.srcIp() != null) {
-            result.put(SRC_IP, policy.srcIp());
-        }
-        if (policy.ipProto() != null) {
-            result.put(PROTO_TYPE, policy.ipProto());
-        }
-
-        int srcPort = policy.srcPort() & 0xffff;
-        if (policy.srcPort() != 0) {
-            result.put(SRC_PORT, srcPort);
-        }
-        int dstPort = policy.dstPort() & 0xffff;
-        if (policy.dstPort() != 0) {
-            result.put(DST_PORT, dstPort);
-        }
-        if (policy.type() == Policy.Type.TUNNEL_FLOW) {
-            result.put(TUNNEL_ID, ((TunnelPolicy) policy).tunnelId());
-        }
-
-        return result;
-    }
-
-    @Override
-    public Policy decode(ObjectNode json, CodecContext context) {
-
-        String pid = json.path(POLICY_ID).asText();
-        String type = json.path(TYPE).asText();
-        int priority = json.path(PRIORITY).asInt();
-        String dstIp = json.path(DST_IP).asText();
-        String srcIp = json.path(SRC_IP).asText();
-        String tunnelId = json.path(TUNNEL_ID).asText();
-        String protoType = json.path(PROTO_TYPE).asText();
-        short srcPort = json.path(SRC_PORT).shortValue();
-        short dstPort = json.path(DST_PORT).shortValue();
-
-        if (json.path(POLICY_ID).isMissingNode() || pid == null) {
-            // TODO: handle errors
-            return null;
-        }
-
-        TunnelPolicy.Builder tpb = TunnelPolicy.builder().setPolicyId(pid);
-        if (!json.path(TYPE).isMissingNode() && type != null &&
-                Policy.Type.valueOf(type).equals(Policy.Type.TUNNEL_FLOW)) {
-
-            if (json.path(TUNNEL_ID).isMissingNode() || tunnelId == null) {
-                return null;
-            }
-
-            tpb.setTunnelId(tunnelId);
-            tpb.setType(Policy.Type.valueOf(type));
-
-            if (!json.path(PRIORITY).isMissingNode()) {
-                tpb.setPriority(priority);
-            }
-            if (dstIp != null) {
-                tpb.setDstIp(dstIp);
-            }
-            if (srcIp != null) {
-                tpb.setSrcIp(srcIp);
-            }
-            if (protoType != null) {
-                tpb.setIpProto(protoType);
-            }
-            if (dstPort != 0) {
-                tpb.setDstPort(dstPort);
-            }
-            if (srcPort != 0) {
-                tpb.setSrcPort(srcPort);
-            }
-        }
-
-        return tpb.build();
-    }
-
-}
diff --git a/web/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java b/web/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java
index 08663e4..5a24ca5 100644
--- a/web/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java
+++ b/web/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * Copyright 2021-present Open Networking Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,92 +15,264 @@
  */
 package org.onosproject.segmentrouting.web;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-
+import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.rest.AbstractWebResource;
-import org.onosproject.segmentrouting.Policy;
-import org.onosproject.segmentrouting.SegmentRoutingService;
+import org.onosproject.segmentrouting.policy.api.DropPolicy;
+import org.onosproject.segmentrouting.policy.api.Policy;
+import org.onosproject.segmentrouting.policy.api.Policy.PolicyType;
+import org.onosproject.segmentrouting.policy.api.PolicyData;
+import org.onosproject.segmentrouting.policy.api.PolicyId;
+import org.onosproject.segmentrouting.policy.api.PolicyService;
+import org.onosproject.segmentrouting.policy.api.RedirectPolicy;
+import org.onosproject.segmentrouting.policy.api.TrafficMatch;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchData;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
+import javax.ws.rs.Path;
 import javax.ws.rs.POST;
+import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.List;
+import java.util.Set;
 
 import static org.onlab.util.Tools.readTreeFromStream;
 
 /**
- * Query, create and remove segment routing plicies.
+ * Query, create and remove Policies and Traffic Matches.
  */
-// @Path("policy")
+@Path("policy")
 public class PolicyWebResource extends AbstractWebResource {
+    private static Logger log = LoggerFactory.getLogger(PolicyWebResource.class);
 
-    private static final PolicyCodec POLICY_CODEC = new PolicyCodec();
+    private static final String EMPTY_TRAFFIC_SELECTOR =
+            "Empty traffic selector is not allowed";
+    private static final String POLICY = "policy";
+    private static final String POLICY_ID = "policy_id";
+    private static final String TRAFFIC_MATCH = "trafficMatch";
+    private static final String TRAFFIC_MATCH_ID = "traffic_match_id";
 
     /**
-     * Get all segment routing policies.
-     * Returns an array of segment routing policies.
+     * Get all Policies.
      *
-     * @return status of OK
+     * @return 200 OK will a collection of Policies
      */
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    public Response getPolicy() {
-        SegmentRoutingService srService = get(SegmentRoutingService.class);
-        List<Policy> policies = srService.getPolicies();
-        ObjectNode result = new ObjectMapper().createObjectNode();
-        result.set("policy", new PolicyCodec().encode(policies, this));
+    public Response getPolicies() {
+        PolicyService policyService = get(PolicyService.class);
+        ObjectNode root = mapper().createObjectNode();
+        ArrayNode policiesArr = root.putArray(POLICY);
 
-        return ok(result.toString()).build();
+        //Create a filter set contains all PolicyType
+        Set<PolicyType> policyTypes = Set.of(PolicyType.values());
+
+        for (PolicyData policyData : policyService.policies(policyTypes)) {
+            Policy policy = policyData.policy();
+            switch (policy.policyType()) {
+                case DROP:
+                    policiesArr.add(codec(DropPolicy.class).encode((DropPolicy) policy, this));
+                    break;
+                case REDIRECT:
+                    policiesArr.add(codec(RedirectPolicy.class).encode((RedirectPolicy) policy, this));
+                    break;
+                default:
+                    continue;
+            }
+        }
+
+        return Response.ok(root).build();
     }
 
     /**
-     * Create a new segment routing policy.
+     * Get all Drop Policies.
      *
-     * @param input JSON stream for policy to create
-     * @return status of the request - OK if the policy is created,
-     * @throws IOException if JSON processing fails
+     * @return 200 OK will a collection of Dop Policies
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("drop")
+    public Response getDropPolicies() {
+        PolicyService policyService = get(PolicyService.class);
+        ObjectNode root = mapper().createObjectNode();
+        ArrayNode policiesArr = root.putArray(POLICY);
+
+        Set<PolicyType> policyTypes = Set.of(PolicyType.DROP);
+
+        for (PolicyData policyData : policyService.policies(policyTypes)) {
+            Policy policy = policyData.policy();
+            policiesArr.add(codec(DropPolicy.class).encode((DropPolicy) policy, this));
+        }
+
+        return Response.ok(root).build();
+    }
+
+    /**
+     * Create a new Drop Policy.
+     *
+     * @return 200 OK and policyId
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
-    public Response createPolicy(InputStream input) throws IOException {
-        ObjectMapper mapper = new ObjectMapper();
-        ObjectNode policyJson = readTreeFromStream(mapper, input);
-        SegmentRoutingService srService = get(SegmentRoutingService.class);
-        Policy policyInfo = POLICY_CODEC.decode(policyJson, this);
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("drop")
+    public Response createDropPolicy() {
+        PolicyService policyService = get(PolicyService.class);
+        ObjectNode root = mapper().createObjectNode();
 
-        if (policyInfo.type() == Policy.Type.TUNNEL_FLOW) {
-            srService.createPolicy(policyInfo);
-            return Response.ok().build();
-        } else {
-            return Response.serverError().build();
-        }
+        DropPolicy dropPolicy = new DropPolicy();
+        policyService.addOrUpdatePolicy(dropPolicy);
+
+        root.put(POLICY_ID, dropPolicy.policyId().toString());
+
+        return Response.ok(root).build();
     }
 
     /**
-     * Delete a segment routing policy.
+     * Get all Redirect Policies.
      *
-     * @param input JSON stream for policy to delete
-     * @return 204 NO CONTENT if the policy is removed
-     * @throws IOException if JSON is invalid
+     * @return 200 OK will a collection of Redirect Policies
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("redirect")
+    public Response getRedirectPolicies() {
+        PolicyService policyService = get(PolicyService.class);
+        ObjectNode root = mapper().createObjectNode();
+        ArrayNode policiesArr = root.putArray(POLICY);
+
+        Set<PolicyType> policyTypes = Set.of(PolicyType.REDIRECT);
+
+        for (PolicyData policyData : policyService.policies(policyTypes)) {
+            Policy policy = policyData.policy();
+            policiesArr.add(codec(RedirectPolicy.class).encode((RedirectPolicy) policy, this));
+        }
+
+        return Response.ok(root).build();
+    }
+
+    /**
+     * Create a new Redirect Policy.
+     *
+     * @param input Json for the Redirect Policy
+     * @return 200 OK and policyId
+     * @onos.rsModel RedirectPolicyCreate
+     */
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("redirect")
+    public Response createRedirectPolicy(InputStream input) {
+        PolicyService policyService = get(PolicyService.class);
+        ObjectNode root = mapper().createObjectNode();
+
+        try {
+            ObjectNode jsonTree = readTreeFromStream(mapper(), input);
+            RedirectPolicy redirectPolicy = codec(RedirectPolicy.class).
+                    decode(jsonTree, this);
+            policyService.addOrUpdatePolicy(redirectPolicy);
+            root.put(POLICY_ID, redirectPolicy.policyId().toString());
+        } catch (IOException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+
+        return Response.ok(root).build();
+    }
+
+    /**
+     * Delete a Policy by policyId.
+     *
+     * @param policyId Policy identifier
+     * @return 204 NO CONTENT
      */
     @DELETE
-    @Consumes(MediaType.APPLICATION_JSON)
-    public Response removePolicy(InputStream input) throws IOException {
-        ObjectMapper mapper = new ObjectMapper();
-        ObjectNode policyJson = readTreeFromStream(mapper, input);
-        SegmentRoutingService srService = get(SegmentRoutingService.class);
-        Policy policyInfo = POLICY_CODEC.decode(policyJson, this);
-        // TODO: Check the result
-        srService.removePolicy(policyInfo);
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("{policyId}")
+    public Response deletePolicy(@PathParam("policyId") String policyId) {
+        PolicyService policyService = get(PolicyService.class);
+
+        policyService.removePolicy(PolicyId.of(policyId));
 
         return Response.noContent().build();
     }
 
+    /**
+     * Get all Traffic Matches.
+     *
+     * @return 200 OK will a collection of Traffic Matches
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("trafficmatch")
+    public Response getTrafficMatches() {
+        PolicyService policyService = get(PolicyService.class);
+        ObjectNode root = mapper().createObjectNode();
+        ArrayNode trafficMatchArr = root.putArray(TRAFFIC_MATCH);
+
+        for (TrafficMatchData trafficMatchData : policyService.trafficMatches()) {
+            TrafficMatch trafficMatch = trafficMatchData.trafficMatch();
+            trafficMatchArr.add(codec(TrafficMatch.class).encode(trafficMatch, this));
+        }
+
+        return Response.ok(root).build();
+    }
+
+    /**
+     * Create a new Traffic Match.
+     *
+     * @param input Json for the Traffic Match
+     * @return status of the request - CREATED and TrafficMatchId if the JSON is correct,
+     * BAD_REQUEST if the JSON is invalid
+     * @onos.rsModel TrafficMatchCreate
+     */
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("trafficmatch")
+    public Response createTrafficMatch(InputStream input) {
+        PolicyService policyService = get(PolicyService.class);
+        ObjectNode root = mapper().createObjectNode();
+
+        try {
+            ObjectNode jsonTree = readTreeFromStream(mapper(), input);
+            TrafficMatch trafficMatch = codec(TrafficMatch.class).
+                    decode(jsonTree, this);
+            if (trafficMatch.trafficSelector()
+                    .equals(DefaultTrafficSelector.emptySelector())) {
+                throw new IllegalArgumentException(EMPTY_TRAFFIC_SELECTOR);
+            }
+            policyService.addOrUpdateTrafficMatch(trafficMatch);
+            root.put(TRAFFIC_MATCH_ID, trafficMatch.trafficMatchId().toString());
+        } catch (IOException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+
+        return Response.ok(root).build();
+    }
+
+    /**
+     * Delete a Traffic Match by trafficMatchId.
+     *
+     * @param trafficMatchId Traffic Match identifier
+     * @return 204 NO CONTENT
+     */
+    @DELETE
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("trafficmatch/{trafficMatchId}")
+    public Response deleteTrafficMatch(@PathParam("trafficMatchId") String trafficMatchId) {
+        PolicyService policyService = get(PolicyService.class);
+
+        policyService.removeTrafficMatch(TrafficMatchId.of(trafficMatchId));
+
+        return Response.noContent().build();
+    }
 }
diff --git a/web/src/main/java/org/onosproject/segmentrouting/web/SegmentRoutingWebApplication.java b/web/src/main/java/org/onosproject/segmentrouting/web/SegmentRoutingWebApplication.java
index 6704030..e62bf90 100644
--- a/web/src/main/java/org/onosproject/segmentrouting/web/SegmentRoutingWebApplication.java
+++ b/web/src/main/java/org/onosproject/segmentrouting/web/SegmentRoutingWebApplication.java
@@ -29,7 +29,8 @@
         return getClasses(
                 PseudowireWebResource.class,
                 McastWebResource.class,
-                XconnectWebResource.class
+                XconnectWebResource.class,
+                PolicyWebResource.class
         );
     }
 }
diff --git a/web/src/main/resources/definitions/RedirectPolicyCreate.json b/web/src/main/resources/definitions/RedirectPolicyCreate.json
new file mode 100644
index 0000000..cade149
--- /dev/null
+++ b/web/src/main/resources/definitions/RedirectPolicyCreate.json
@@ -0,0 +1,32 @@
+{
+  "type": "object",
+  "title": "redirect-policy-creation",
+  "required": [
+    "spinesToEnforce"
+  ],
+  "properties": {
+    "spinesToEnforce": {
+      "type": "object",
+      "title": "spinesToEnforce",
+      "required": [
+        "deviceId"
+      ],
+      "properties": {
+        "deviceId": {
+          "type": "array",
+          "xml": {
+            "name": "deviceId",
+            "wrapped": true
+          },
+          "items": {
+            "type": "string",
+            "title": "deviceId",
+            "example": "of:0000000000000001",
+            "description": "deviceId of spines to enforce"
+          },
+          "description": "Array of deviceId"
+        }
+      }
+    }
+  }
+}
diff --git a/web/src/main/resources/definitions/TrafficMatchCreate.json b/web/src/main/resources/definitions/TrafficMatchCreate.json
new file mode 100644
index 0000000..3ab1022
--- /dev/null
+++ b/web/src/main/resources/definitions/TrafficMatchCreate.json
@@ -0,0 +1,245 @@
+{
+  "type": "object",
+  "title": "traffic-match-creation",
+  "required": [
+    "policy_id",
+    "selector"
+  ],
+  "properties": {
+    "policy_id": {
+      "type": "string",
+      "example": "DROP",
+      "description": "ID of associated policy"
+    },
+    "selector": {
+      "type": "object",
+      "title": "selector",
+      "required": [
+        "criteria"
+      ],
+      "properties": {
+        "criteria": {
+          "type": "array",
+          "xml": {
+            "name": "criteria",
+            "wrapped": true
+          },
+          "items": {
+            "type": "object",
+            "title": "criteria",
+            "properties": {
+              "type": {
+                "type": "string",
+                "description": "Ethernet field name",
+                "example": "ETH_TYPE"
+              },
+              "ethType": {
+                "type": "int64",
+                "format": "int64",
+                "example": "0x88cc",
+                "description": "Ethernet frame type"
+              },
+              "mac": {
+                "type": "string",
+                "example": "00:00:11:00:00:01"
+              },
+              "port": {
+                "type": "int64",
+                "format": "int64",
+                "example": 1,
+                "description": "Match port"
+              },
+              "metadata": {
+                "type": "Hex16",
+                "format": "Hex16",
+                "example": "0xabcdL",
+                "description": "Metadata passed between tables"
+              },
+              "vlanId": {
+                "type": "uint16",
+                "format": "uint16",
+                "example": "0x1000"
+              },
+              "priority": {
+                "type": "int64",
+                "format": "int64",
+                "example": 1,
+                "description": "VLAN priority."
+              },
+              "ipDscp": {
+                "type": "byte",
+                "format": "byte",
+                "description": "IP DSCP (6 bits in ToS field)"
+              },
+              "ipEcn": {
+                "type": "byte",
+                "format": "byte",
+                "description": "IP ECN (2 bits in ToS field)."
+              },
+              "protocol": {
+                "type": "uint16",
+                "format": "uint16",
+                "example": 1,
+                "description": "IP protocol"
+              },
+              "ip": {
+                "type": "string",
+                "example": "10.1.1.0/24",
+                "description": "IP source address"
+              },
+              "tcpPort": {
+                "type": "integer",
+                "format": "uint16",
+                "example": 1,
+                "description": "TCP source address"
+              },
+              "udpPort": {
+                "type": "uint16",
+                "format": "uint16",
+                "example": 1,
+                "description": "UDP source address"
+              },
+              "sctpPort": {
+                "type": "uint16",
+                "format": "uint16",
+                "example": 1,
+                "description": "SCTP source address"
+              },
+              "icmpType": {
+                "type": "uint16",
+                "format": "uint16",
+                "example": 1,
+                "description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
+              },
+              "icmpCode": {
+                "type": "uint16",
+                "format": "uint16",
+                "example": 1,
+                "description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
+              },
+              "flowLabel": {
+                "type": "Hex16",
+                "format": "Hex16",
+                "example": "0xffffe",
+                "description": "IPv6 Flow Label (RFC 6437)"
+              },
+              "icmpv6Type": {
+                "type": "uint16",
+                "format": "uint16",
+                "example": 1,
+                "description": "Internet Control Message Protocol for IPV6 type (RFC2463)"
+              },
+              "icmpv6Code": {
+                "type": "uint16",
+                "format": "uint16",
+                "example": 1,
+                "description": "Internet Control Message Protocol for IPV6 code (RFC2463)"
+              },
+              "targetAddress": {
+                "type": "String",
+                "example": "10.1.1.0/24",
+                "description": "IPv6 Neighbor discovery target address"
+              },
+              "label": {
+                "type": "int32",
+                "format": "int32",
+                "example": 1,
+                "description": "MPLS label"
+              },
+              "exthdrFlags": {
+                "type": "int64",
+                "format": "int64",
+                "example": 1,
+                "description": "IPv6 extension header pseudo-field"
+              },
+              "lambda": {
+                "type": "int64",
+                "format": "int64",
+                "example": 1,
+                "description": "wavelength abstraction"
+              },
+              "gridType": {
+                "type": "String",
+                "example": "DWDM",
+                "description": "Type of wavelength grid"
+              },
+              "channelSpacing": {
+                "type": "int64",
+                "format": "int64",
+                "example": 100,
+                "description": "Optical channel spacing"
+              },
+              "spacingMultiplier": {
+                "type": "integer",
+                "format": "int64",
+                "example": 4,
+                "description": "Optical channel spacing multiplier"
+              },
+              "slotGranularity": {
+                "type": "int64",
+                "format": "int64",
+                "example": 8
+              },
+              "ochSignalId": {
+                "type": "integer",
+                "format": "int64",
+                "example": 1,
+                "description": "Optical channel signal ID"
+              },
+              "tunnelId": {
+                "type": "int64",
+                "format": "int64",
+                "example": 5,
+                "description": "Tunnel ID"
+              },
+              "ochSignalType": {
+                "type": "int64",
+                "format": "int64",
+                "example": 1,
+                "description": "Optical channel signal type"
+              },
+              "oduSignalId": {
+                "type": "int64",
+                "format": "int64",
+                "example": 1,
+                "description": "ODU (Optical channel Data Unit) signal ID."
+              },
+              "tributaryPortNumber": {
+                "type": "int64",
+                "format": "int64",
+                "example": 11,
+                "description": "OPU (Optical channel Payload Unit) port number."
+              },
+              "tributarySlotLen": {
+                "type": "int64",
+                "format": "int64",
+                "example": 80,
+                "description": "OPU (Optical channel Payload Unit) slot length."
+              },
+              "tributarySlotBitmap": {
+                "type": "array",
+                "title": "tributarySlotBitmap",
+                "description": "OPU (Optical channel Payload Unit) slot bitmap.",
+                "required": [
+                  "byte",
+                  "port"
+                ],
+                "items": {
+                  "type": "byte",
+                  "title": "byte",
+                  "example": 1
+                }
+              },
+              "oduSignalType": {
+                "type": "int64",
+                "format": "int64",
+                "example": 4,
+                "description": "ODU (Optical channel Data Unit) signal type."
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}