BGP Route policy distribution and flow spec
Change-Id: I8903efd225a24db6ccc85a4a3148a4dd6076e042
diff --git a/apps/bgpflowspec/bgpweb/BUCK b/apps/bgpflowspec/bgpweb/BUCK
new file mode 100755
index 0000000..a5ef9e7
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/BUCK
@@ -0,0 +1,12 @@
+COMPILE_DEPS = [
+ '//lib:CORE_DEPS',
+ '//lib:javax.ws.rs-api',
+ '//utils/rest:onlab-rest',
+ '//apps/bgpflowspec/flowapi:onos-apps-bgpflowspec-flowapi',
+ '//apps/bgpflowspec/flowmgr:onos-apps-bgpflowspec-flowmgr',
+]
+
+osgi_jar_with_tests (
+ name = 'onos-apps-bgpflowspec-web',
+ deps = COMPILE_DEPS,
+)
diff --git a/apps/bgpflowspec/bgpweb/pom.xml b/apps/bgpflowspec/bgpweb/pom.xml
new file mode 100755
index 0000000..036a7d1
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/pom.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2016-present Open Networking Laboratory
+ ~
+ ~ 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.
+ -->
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-bgpflow</artifactId>
+ <version>1.6.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>onos-app-bgp-web</artifactId>
+ <packaging>bundle</packaging>
+ <properties>
+ <web.context>/onos/bgp</web.context>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>javax.ws.rs-api</artifactId>
+ <version>2.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-app-bgp-flowmgr</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-rest</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava-testlib</artifactId>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <_wab>src/main/webapp/</_wab>
+ <Bundle-SymbolicName>
+ ${project.groupId}.${project.artifactId}
+ </Bundle-SymbolicName>
+ <Import-Package>
+ *,org.glassfish.jersey.servlet
+ </Import-Package>
+ <Web-ContextPath>${web.context}</Web-ContextPath>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/resources/BgpFlowWebResource.java b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/resources/BgpFlowWebResource.java
new file mode 100755
index 0000000..44ba4a4
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/resources/BgpFlowWebResource.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.bgpweb.resources;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.flow.manager.BgpFlowService;
+import org.onosproject.flowapi.DefaultExtWideCommunityInt;
+import org.onosproject.flowapi.ExtFlowContainer;
+import org.onosproject.flowapi.ExtFlowTypes;
+import org.onosproject.flowapi.ExtTrafficAction;
+import org.onosproject.flowapi.ExtWideCommunityInt;
+import org.onosproject.rest.AbstractWebResource;
+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.POST;
+import javax.ws.rs.Path;
+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.ListIterator;
+
+import static javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE;
+import static javax.ws.rs.core.Response.Status.OK;
+
+/**
+ * Bgp flow web resource.
+ */
+
+@Path("flow")
+public class BgpFlowWebResource extends AbstractWebResource {
+
+ private BgpFlowService flowService = get(BgpFlowService.class);
+ protected static final String BGPFLOW = "bgp_flow";
+ protected static final String DEVICEID = "deviceId";
+ protected static final int LOCAL_PERF = 20;
+ private final Logger log = LoggerFactory.getLogger(BgpFlowWebResource.class);
+
+ /**
+ * Get the Bgp flow.
+ *
+ * @return 200 OK
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getBgpFlow() {
+ Boolean result = true;
+ //TODO
+ return ok(result.toString()).build();
+ }
+
+ /**
+ * Push the the Bgp flow spec.
+ *
+ * @param stream bgp flow spec in JSON
+ * @return status of the request - CREATED if the JSON is correct,
+ * BAD_REQUEST if the JSON is invalid
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createBgpFlow(InputStream stream) {
+ try {
+ ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+ JsonNode flow = jsonTree.get(BGPFLOW);
+ String devId = jsonTree.get(DEVICEID).asText();
+ boolean status;
+
+ List<ExtFlowTypes> list;
+ ExtFlowContainer container;
+
+ list = codec(ExtFlowTypes.class).decode((ArrayNode) flow, this);
+
+ if (!validateRpd(list)) {
+ return Response.status(NOT_ACCEPTABLE).entity(Boolean.FALSE.toString()).build();
+ }
+
+ container = new ExtFlowContainer(list);
+ container.setDeviceId(devId);
+
+
+ status = flowService.onBgpFlowCreated(container);
+ Boolean isSuccess = Boolean.valueOf(status);
+ if (!status) {
+ return Response.status(NOT_ACCEPTABLE).entity(isSuccess.toString()).build();
+ }
+
+ return Response.status(OK).entity(isSuccess.toString()).build();
+ } catch (IOException e) {
+ log.error("Exception while parsing bgp flow.", e.toString());
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Validates the rpd and flow spec classes.
+ *
+ * @param list list of types
+ * @return a true if the validation succeeds else false
+ */
+ boolean validateRpd(List<ExtFlowTypes> list) {
+ ListIterator<ExtFlowTypes> iterator = list.listIterator();
+ ExtFlowTypes flow;
+ boolean key = false;
+ boolean rpd = false;
+ boolean nonRpd = false;
+ ExtTrafficAction flowAction = null;
+ boolean dstPfx = false;
+ boolean wcFlg = false;
+ boolean wcHop = false;
+ boolean wcWc = false;
+ boolean wcCAs = false;
+ boolean wcLAs = false;
+ boolean wcTarget = false;
+ boolean wcETarget = false;
+ boolean wcParm = false;
+
+ while (iterator.hasNext()) {
+ flow = iterator.next();
+ switch (flow.type()) {
+ case EXT_FLOW_RULE_KEY:
+ key = true;
+ break;
+ case IPV4_DST_PFX:
+ dstPfx = true;
+ break;
+ case IPV4_SRC_PFX:
+ nonRpd = true;
+ break;
+ case IP_PROTO_LIST:
+ nonRpd = true;
+ break;
+ case IN_PORT_LIST:
+ nonRpd = true;
+ break;
+ case DST_PORT_LIST:
+ nonRpd = true;
+ break;
+ case SRC_PORT_LIST:
+ nonRpd = true;
+ break;
+ case ICMP_TYPE_LIST:
+ nonRpd = true;
+ break;
+ case ICMP_CODE_LIST:
+ nonRpd = true;
+ break;
+ case TCP_FLAG_LIST:
+ nonRpd = true;
+ break;
+ case PACKET_LENGTH_LIST:
+ nonRpd = true;
+ break;
+ case DSCP_VALUE_LIST:
+ nonRpd = true;
+ break;
+ case FRAGMENT_LIST:
+ nonRpd = true;
+ break;
+ case TRAFFIC_ACTION:
+ flowAction = (ExtTrafficAction) flow;
+ if (flowAction.rpd()) {
+ rpd = true;
+ }
+ break;
+ case TRAFFIC_RATE:
+ nonRpd = true;
+ break;
+ case TRAFFIC_REDIRECT:
+ nonRpd = true;
+ break;
+ case TRAFFIC_MARKING:
+ nonRpd = true;
+ break;
+ case WIDE_COMM_FLAGS:
+ wcFlg = true;
+ break;
+ case WIDE_COMM_HOP_COUNT:
+ wcHop = true;
+ break;
+ case WIDE_COMM_COMMUNITY:
+ wcWc = true;
+ break;
+ case WIDE_COMM_CONTEXT_AS:
+ wcCAs = true;
+ break;
+ case WIDE_COMM_LOCAL_AS:
+ wcLAs = true;
+ break;
+ case WIDE_COMM_TARGET:
+ wcTarget = true;
+ break;
+ case WIDE_COMM_EXT_TARGET:
+ wcETarget = true;
+ break;
+ case WIDE_COMM_PARAMETER:
+ wcParm = true;
+ break;
+ default:
+ log.error("error: this type is not supported");
+ break;
+ }
+ }
+
+ if (!key) {
+ return false;
+ }
+
+ /** checking for non Rpd. */
+ if (!rpd) {
+ if (wcFlg || wcHop || wcWc
+ || wcCAs || wcLAs || wcParm) {
+ return false;
+ }
+ }
+
+ /** checking for Rpd. */
+ if (nonRpd || !dstPfx || !wcFlg || !wcHop
+ || !wcWc || !wcCAs || !wcLAs || !wcParm) {
+ return false;
+ }
+
+ /** If it is rpd then either of these two or both should be present.*/
+ if (!wcTarget && !wcETarget) {
+ rpd = false;
+ }
+
+ if (!handleRpdLocalPerf(list)) {
+ return false;
+ }
+
+ return rpd;
+ }
+
+ /**
+ * Validate and format the rpd local perf.
+ *
+ * @param list list of types
+ * @return a true if the validation succeeds else false
+ */
+ boolean handleRpdLocalPerf(List<ExtFlowTypes> list) {
+ ListIterator<ExtFlowTypes> iterator = list.listIterator();
+ ExtFlowTypes flow;
+
+ ExtWideCommunityInt wcComm = null;
+ ExtWideCommunityInt wcParam = null;
+ ListIterator<Integer> wcInt = null;
+ int community = 0;
+ int param = 0;
+
+ while (iterator.hasNext()) {
+ flow = iterator.next();
+ switch (flow.type()) {
+ case WIDE_COMM_COMMUNITY:
+ wcComm = (ExtWideCommunityInt) flow;
+ wcInt = wcComm.communityInt().listIterator();
+ community = wcInt.next().intValue();
+ break;
+
+ case WIDE_COMM_PARAMETER:
+ wcParam = (ExtWideCommunityInt) flow;
+ wcInt = wcParam.communityInt().listIterator();
+ param = wcInt.next().intValue();
+ break;
+ default:
+ log.error("error: this type is not supported");
+ break;
+ }
+ }
+
+ if (community == LOCAL_PERF) {
+ if (param > 127 || param < -127) {
+ return false;
+ }
+
+ /** if -ve then make it 1 bye value and set it, if it is positive then no issue.*/
+ if (param < 0) {
+ param = ~param + 129;
+ list.remove(wcParam);
+ ExtWideCommunityInt.Builder resultBuilder = new DefaultExtWideCommunityInt.Builder();
+ resultBuilder.setwCommInt(Integer.valueOf(param));
+ resultBuilder.setType(ExtFlowTypes.ExtType.WIDE_COMM_PARAMETER);
+ list.add(resultBuilder.build());
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Delete the the Bgp flow spec.
+ *
+ * @param stream bgp flow spec in JSON
+ * @return status of the request - CREATED if the JSON is correct,
+ * BAD_REQUEST if the JSON is invalid
+ */
+ @DELETE
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response deleteBgpFlow(InputStream stream) {
+ try {
+ ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+ JsonNode flow = jsonTree.get(BGPFLOW);
+ String devId = jsonTree.get(DEVICEID).asText();
+ boolean status;
+
+ List<ExtFlowTypes> list;
+ ExtFlowContainer container;
+
+ list = codec(ExtFlowTypes.class).decode((ArrayNode) flow, this);
+
+ if (!validateRpd(list)) {
+ return Response.status(NOT_ACCEPTABLE).entity(Boolean.FALSE.toString()).build();
+ }
+
+ container = new ExtFlowContainer(list);
+ container.setDeviceId(devId);
+
+
+ status = flowService.onBgpFlowDeleted(container);
+ Boolean isSuccess = Boolean.valueOf(status);
+ if (!status) {
+ return Response.status(NOT_ACCEPTABLE).entity(isSuccess.toString()).build();
+ }
+ return Response.status(OK).entity(isSuccess.toString()).build();
+ } catch (IOException e) {
+ log.error("Exception while parsing bgp flow.", e.toString());
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/resources/BgpWebApplication.java b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/resources/BgpWebApplication.java
new file mode 100755
index 0000000..4ab7777
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/resources/BgpWebApplication.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.bgpweb.resources;
+
+import org.onlab.rest.AbstractWebApplication;
+import java.util.Set;
+
+/**
+ * BGP REST API web application.
+ */
+public class BgpWebApplication extends AbstractWebApplication {
+ @Override
+ public Set<Class<?>> getClasses() {
+ return getClasses(BgpFlowWebResource.class);
+ }
+}
+
diff --git a/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/resources/package-info.java b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/resources/package-info.java
new file mode 100755
index 0000000..09c5210
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/resources/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * BGP web that used rest to create BGP resources.
+ */
+package org.onosproject.bgpweb.resources;
diff --git a/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/BgpCodecRegistrator.java b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/BgpCodecRegistrator.java
new file mode 100755
index 0000000..1140fda
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/BgpCodecRegistrator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.bgpweb.web;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.codec.CodecService;
+import org.onosproject.flowapi.ExtFlowTypes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of the JSON codec brokering service for BGP app.
+ */
+@Component(immediate = true)
+public class BgpCodecRegistrator {
+
+ private static Logger log = LoggerFactory.getLogger(BgpCodecRegistrator.class);
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CodecService codecService;
+
+ @Activate
+ public void activate() {
+ codecService.registerCodec(ExtFlowTypes.class, new BgpFlowExtensionCodec());
+ System.out.print("BgpCodecRegistrator started");
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopped");
+ }
+}
diff --git a/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/BgpFlowExtensionCodec.java b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/BgpFlowExtensionCodec.java
new file mode 100755
index 0000000..5c6f250
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/BgpFlowExtensionCodec.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.bgpweb.web;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.flowapi.ExtFlowTypes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class BgpFlowExtensionCodec extends JsonCodec<ExtFlowTypes> {
+
+ protected static final Logger log =
+ LoggerFactory.getLogger(BgpFlowExtensionCodec.class);
+
+ protected static final String TYPE = "type";
+ protected static final String NAME = "name";
+ protected static final String PREFIX = "prefix";
+ protected static final String PROTOCOLS = "protocols";
+ protected static final String PORT = "port";
+ protected static final String DST_PORT = "destinationPort";
+ protected static final String SRC_PORT = "sourcePort";
+ protected static final String ICMP_TYPE = "icmpType";
+ protected static final String ICMP_CODE = "icmpCode";
+ protected static final String TCP_FLAG = "tcpFlag";
+ protected static final String PACKET_LENGTH = "packetLength";
+ protected static final String DSCP_VALUE = "dscpValue";
+ protected static final String FRAGMENT = "fragment";
+
+ protected static final String TRAFFIC_RATE = "trafficRate";
+ protected static final String TRAFFIC_ACTION = "trafficAction";
+ protected static final String TRAFFIC_REDIRECTION = "trafficRedirection";
+ protected static final String TRAFFIC_MARKING = "trafficMarking";
+
+ protected static final String TRAFFIC_RATE_ASN = "asn";
+ protected static final String TRAFFIC_RATE_RATE = "rate";
+ protected static final String TRAFFIC_ACTION_TERMINAL = "terminal";
+ protected static final String TRAFFIC_ACTION_SAMPLE = "sample";
+ protected static final String TRAFFIC_ACTION_RPD = "rpd";
+
+ protected static final String WIDE_COMM_FLAGS = "widecommunityFlags";
+ protected static final String WIDE_COMM_HOP_COUNT = "widecommunityHopCount";
+ protected static final String WIDE_COMM_COMMUNITY = "widecommunityCommunity";
+ protected static final String WIDE_COMM_CONTEXT_AS = "widecommunityContextAs";
+ protected static final String WIDE_COMM_LOCAL_AS = "widecommunityLocalAs";
+ protected static final String WIDE_COMM_TARGET = "widecommunityTarget";
+ protected static final String WIDE_COMM_EXT_TARGET = "widecommunityExtTarget";
+ protected static final String WIDE_COMM_PARAMETER = "widecommunityParameter";
+
+ protected static final String WIDE_COMM_TGT_LOCAL_SP = "localSpeaker";
+ protected static final String WIDE_COMM_TGT_REMOTE_SP = "remoteSpeaker";
+
+ @Override
+ public ObjectNode encode(ExtFlowTypes flowTypes, CodecContext context) {
+ return null;
+ }
+
+ @Override
+ public ExtFlowTypes decode(ObjectNode json, CodecContext context) {
+ DecodeBgpFlowExtnCodecHelper decoder = new DecodeBgpFlowExtnCodecHelper(json);
+ return decoder.decode();
+ }
+}
diff --git a/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/BgpParseAttributes.java b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/BgpParseAttributes.java
new file mode 100755
index 0000000..464b388
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/BgpParseAttributes.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.bgpweb.web;
+
+import org.onosproject.flowapi.ExtOperatorValue;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+public class BgpParseAttributes {
+
+ private final Logger log = getLogger(getClass());
+
+ /** Bits as per flow spec rfc 5575.*/
+ final byte endBit = (byte) 0x80;
+ final byte andBit = 0x40;
+ final byte twoByteLen = (byte) (0x01 << 4);
+ final byte fourByteLen = (byte) (0x02 << 4);
+ final byte lessThan = 0x04;
+ final byte greaterThan = 0x02;
+ final byte equal = 0x01;
+
+ /** Protocol types.*/
+ protected static final byte ICMP = 1;
+ protected static final byte IGMP = 2;
+ protected static final byte TCP = 6;
+ protected static final byte UDP = 17;
+ protected static final byte IPV4 = 4;
+ protected static final byte IPV6 = 41;
+
+ /** TCP Flags.*/
+ static final byte FIN = (1 << 0);
+ static final byte SYN = (1 << 1);
+ static final byte RST = (1 << 2);
+ static final byte PSH = (1 << 3);
+ static final byte ACK = (1 << 4);
+ static final byte URG = (1 << 5);
+
+ final byte notBit = 0x02;
+ final byte matchBit = 0x01;
+
+ /** Fragment Flags.*/
+ static final byte DF = (1 << 0);
+ static final byte IF = (1 << 1);
+ static final byte FF = (1 << 2);
+ static final byte LF = (1 << 3);
+
+ List<ExtOperatorValue> parsePort(String string) {
+ List<ExtOperatorValue> operatorValue = null;
+
+ operatorValue = createOperatorValue(string);
+
+ return operatorValue;
+ }
+
+ List<ExtOperatorValue> parseIpProtocol(String string) {
+ List<ExtOperatorValue> operatorValue = null;
+
+ string = string.replaceAll("ICMP", Byte.valueOf(ICMP).toString());
+ string = string.replaceAll("icmp", Byte.valueOf(ICMP).toString());
+ string = string.replaceAll("IPv4", Byte.valueOf(IPV4).toString());
+ string = string.replaceAll("ipv4", Byte.valueOf(IPV4).toString());
+ string = string.replaceAll("TCP", Byte.valueOf(TCP).toString());
+ string = string.replaceAll("tcp", Byte.valueOf(TCP).toString());
+ string = string.replaceAll("UDP", Byte.valueOf(UDP).toString());
+ string = string.replaceAll("udp", Byte.valueOf(UDP).toString());
+ string = string.replaceAll("IPv6", Byte.valueOf(IPV6).toString());
+ string = string.replaceAll("ipv6", Byte.valueOf(IPV6).toString());
+ string = string.replaceAll("igmp", Byte.valueOf(IGMP).toString());
+ string = string.replaceAll("IGMP", Byte.valueOf(IGMP).toString());
+
+ operatorValue = createOperatorValue(string);
+
+ return operatorValue;
+ }
+
+ List<ExtOperatorValue> parseIcmpType(String string) {
+ List<ExtOperatorValue> operatorValue = null;
+
+ operatorValue = createOperatorValue(string);
+
+ return operatorValue;
+ }
+
+ List<ExtOperatorValue> parseIcmpCode(String string) {
+ List<ExtOperatorValue> operatorValue = null;
+
+ operatorValue = createOperatorValue(string);
+
+ return operatorValue;
+ }
+
+
+ List<ExtOperatorValue> parseTcpFlags(String string) {
+ List<ExtOperatorValue> operatorValue = new ArrayList<>();
+ Token token;
+ int index = 0;
+
+ string = string.replaceAll("FIN", Byte.valueOf(FIN).toString());
+ string = string.replaceAll("fin", Byte.valueOf(FIN).toString());
+ string = string.replaceAll("SYN", Byte.valueOf(SYN).toString());
+ string = string.replaceAll("syn", Byte.valueOf(SYN).toString());
+ string = string.replaceAll("RST", Byte.valueOf(RST).toString());
+ string = string.replaceAll("rst", Byte.valueOf(RST).toString());
+ string = string.replaceAll("PSH", Byte.valueOf(PSH).toString());
+ string = string.replaceAll("psh", Byte.valueOf(PSH).toString());
+ string = string.replaceAll("ACK", Byte.valueOf(ACK).toString());
+ string = string.replaceAll("ack", Byte.valueOf(ACK).toString());
+ string = string.replaceAll("URG", Byte.valueOf(URG).toString());
+ string = string.replaceAll("urg", Byte.valueOf(URG).toString());
+
+ do {
+ token = parseTcpTokenValue(string, index);
+ if (token.error) {
+ log.error("Error in parsing the TCP value list");
+ return null;
+ }
+ operatorValue.add(new ExtOperatorValue(token.operator, token.value));
+ index = token.index;
+ } while ((token.operator & endBit) != endBit);
+
+ return operatorValue;
+ }
+
+ List<ExtOperatorValue> parsePacketLength(String string) {
+ List<ExtOperatorValue> operatorValue = null;
+ operatorValue = createOperatorValue(string);
+
+ return operatorValue;
+ }
+
+ List<ExtOperatorValue> parseDscp(String string) {
+ List<ExtOperatorValue> operatorValue = null;
+
+ operatorValue = createOperatorValue(string);
+
+ return operatorValue;
+ }
+
+ List<ExtOperatorValue> parseFragment(String string) {
+
+ List<ExtOperatorValue> operatorValue = null;
+
+ string = string.replaceAll("DF", Byte.valueOf(DF).toString());
+ string = string.replaceAll("df", Byte.valueOf(DF).toString());
+ string = string.replaceAll("IF", Byte.valueOf(IF).toString());
+ string = string.replaceAll("if", Byte.valueOf(IF).toString());
+ string = string.replaceAll("FF", Byte.valueOf(FF).toString());
+ string = string.replaceAll("ff", Byte.valueOf(FF).toString());
+ string = string.replaceAll("LF", Byte.valueOf(LF).toString());
+ string = string.replaceAll("lf", Byte.valueOf(LF).toString());
+
+ operatorValue = createOperatorValue(string);
+ return operatorValue;
+ }
+
+ private class Token {
+ byte operator;
+ byte[] value;
+ int index;
+ boolean error;
+ }
+
+ List<ExtOperatorValue> createOperatorValue(String string) {
+ List<ExtOperatorValue> operatorValue = new ArrayList<>();
+ Token token;
+ int index = 0;
+
+ do {
+ token = parseMultiTokenValue(string, index);
+ if (token.error) {
+ log.error("Error in parsing the operator value list");
+ return null;
+ }
+ operatorValue.add(new ExtOperatorValue(token.operator, token.value));
+ index = token.index;
+ } while ((token.operator & endBit) != endBit);
+
+ return operatorValue;
+ }
+
+
+ Token parseMultiTokenValue(String str, int index) {
+ Token token = new Token();
+ token.error = true;
+ int number = 0;
+ int cur = 0;
+ byte operator = 0;
+ boolean prevNumber = false;
+ boolean bLess = false;
+ boolean bGreater = false;
+ boolean bAnd = false;
+ boolean bEqual = false;
+
+ while (str.length() > index) {
+
+ switch (str.charAt(index)) {
+ case '=':
+ if (bEqual) {
+ return token;
+ }
+ bEqual = true;
+ if (prevNumber) {
+ return windUp(str, index, number, operator);
+ }
+ operator = (byte) (operator | equal);
+ break;
+ case '>':
+ if (bGreater) {
+ return token;
+ }
+ bGreater = true;
+ if (prevNumber) {
+ return windUp(str, index, number, operator);
+ }
+ operator = (byte) (operator | greaterThan);
+ break;
+ case '<':
+ if (bLess) {
+ return token;
+ }
+ bLess = true;
+ if (prevNumber) {
+ return windUp(str, index, number, operator);
+ }
+ operator = (byte) (operator | lessThan);
+ break;
+ case '&':
+ if (bAnd) {
+ return token;
+ }
+ bAnd = true;
+ if (prevNumber) {
+ return windUp(str, index, number, operator);
+ }
+ operator = (byte) (operator | andBit);
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ prevNumber = true;
+ bLess = false;
+ bGreater = false;
+ bAnd = false;
+ bEqual = false;
+ cur = str.charAt(index);
+ number = (number * 10) + cur - '0';
+ break;
+
+ default:
+ log.error("Error in parsing the token character" + str.charAt(index));
+ return token;
+ }
+ index++;
+ }
+
+ if (prevNumber) {
+ return windUp(str, index, number, operator);
+ }
+
+ return token;
+ }
+
+ Token windUp(String str, int index, int number, byte operator) {
+ Token token = new Token();
+ byte[] array = new byte[1];
+
+ if (str.length() == index) {
+ operator = (byte) (operator | endBit);
+ }
+
+ if (number <= 255) {
+ array[0] = (byte) number;
+ } else if (number > 255 && number <= Short.MAX_VALUE) {
+ operator = (byte) (operator | twoByteLen);
+ array = shortToByteStream((short) number);
+ } else if (number > Short.MAX_VALUE) {
+ operator = (byte) (operator | fourByteLen);
+ array = intToByteStream(number);
+ }
+
+ token.value = array;
+ token.operator = operator;
+ token.index = index;
+ token.error = false;
+ return token;
+ }
+
+ byte[] intToByteStream(int val) {
+ return new byte[] {
+ (byte) (val >>> 24),
+ (byte) (val >>> 16),
+ (byte) (val >>> 8),
+ (byte) val};
+ }
+
+ byte[] shortToByteStream(short val) {
+ return new byte[] {
+ (byte) (val >>> 8),
+ (byte) val};
+ }
+
+ Token parseTcpTokenValue(String str, int index) {
+ Token token = new Token();
+ token.error = true;
+ int number = 0;
+ int cur = 0;
+ byte operator = 0;
+ boolean prevNumber = false;
+
+ boolean bNotBit = false;
+ boolean bAnd = false;
+ boolean bMatchBit = false;
+
+ while (str.length() > index) {
+
+ switch (str.charAt(index)) {
+ case '=':
+ if (bMatchBit) {
+ return token;
+ }
+ bMatchBit = true;
+ if (prevNumber) {
+ return windUp(str, index, number, operator);
+ }
+ operator = (byte) (operator | matchBit);
+ break;
+ case '!':
+ if (bNotBit) {
+ return token;
+ }
+ bNotBit = true;
+ if (prevNumber) {
+ return windUp(str, index, number, operator);
+ }
+ operator = (byte) (operator | notBit);
+ break;
+ case '&':
+ if (bAnd) {
+ return token;
+ }
+ bAnd = true;
+ if (prevNumber) {
+ return windUp(str, index, number, operator);
+ }
+ operator = (byte) (operator | andBit);
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ prevNumber = true;
+ bNotBit = false;
+ bAnd = false;
+ bMatchBit = false;
+ cur = str.charAt(index);
+ number = (number * 10) + cur - '0';
+ break;
+
+ default:
+ log.error("Error in parsing the TCP token character" + str.charAt(index));
+ return token;
+ }
+ index++;
+ }
+
+ if (prevNumber) {
+ return windUp(str, index, number, operator);
+ }
+
+ return token;
+ }
+}
diff --git a/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/DecodeBgpFlowExtnCodecHelper.java b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/DecodeBgpFlowExtnCodecHelper.java
new file mode 100755
index 0000000..3aafde1
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/DecodeBgpFlowExtnCodecHelper.java
@@ -0,0 +1,721 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.bgpweb.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.flowapi.DefaultExtDscpValue;
+import org.onosproject.flowapi.DefaultExtFragment;
+import org.onosproject.flowapi.DefaultExtIcmpCode;
+import org.onosproject.flowapi.DefaultExtIcmpType;
+import org.onosproject.flowapi.DefaultExtIpProtocol;
+import org.onosproject.flowapi.DefaultExtKeyName;
+import org.onosproject.flowapi.DefaultExtPacketLength;
+import org.onosproject.flowapi.DefaultExtPort;
+import org.onosproject.flowapi.DefaultExtPrefix;
+import org.onosproject.flowapi.DefaultExtTarget;
+import org.onosproject.flowapi.DefaultExtTcpFlag;
+import org.onosproject.flowapi.DefaultExtTrafficAction;
+import org.onosproject.flowapi.DefaultExtTrafficMarking;
+import org.onosproject.flowapi.DefaultExtTrafficRate;
+import org.onosproject.flowapi.DefaultExtTrafficRedirect;
+import org.onosproject.flowapi.DefaultExtWideCommunityInt;
+import org.onosproject.flowapi.ExtDscpValue;
+import org.onosproject.flowapi.ExtFlowTypes;
+import org.onosproject.flowapi.ExtFragment;
+import org.onosproject.flowapi.ExtIcmpCode;
+import org.onosproject.flowapi.ExtIcmpType;
+import org.onosproject.flowapi.ExtIpProtocol;
+import org.onosproject.flowapi.ExtKeyName;
+import org.onosproject.flowapi.ExtPacketLength;
+import org.onosproject.flowapi.ExtPort;
+import org.onosproject.flowapi.ExtPrefix;
+import org.onosproject.flowapi.ExtTarget;
+import org.onosproject.flowapi.ExtTcpFlag;
+import org.onosproject.flowapi.ExtTrafficAction;
+import org.onosproject.flowapi.ExtTrafficMarking;
+import org.onosproject.flowapi.ExtTrafficRate;
+import org.onosproject.flowapi.ExtTrafficRedirect;
+import org.onosproject.flowapi.ExtWideCommunityInt;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * Decode the Ext extension codec.
+ */
+public final class DecodeBgpFlowExtnCodecHelper {
+
+ private final ObjectNode json;
+
+ protected static final String MISSING_MEMBER_MESSAGE =
+ " member is required in ExtTypes";
+
+ protected static final String MALFORMED_MEMBER_MESSAGE =
+ " member is malformed";
+
+ private interface ExtensionDecoder {
+ ExtFlowTypes decodeExtension(ObjectNode json);
+ }
+
+ private final Map<String, ExtensionDecoder> decoderMap;
+
+ BgpParseAttributes parse = new BgpParseAttributes();
+
+ /**
+ * Creates a decode extension codec object.
+ * Initializes the lookup map for Bgp extension types.
+ *
+ * @param json JSON object to decode
+ */
+ public DecodeBgpFlowExtnCodecHelper(ObjectNode json) {
+ this.json = json;
+ decoderMap = new HashMap<>();
+
+ decoderMap.put(ExtFlowTypes.ExtType.IPV4_SRC_PFX.name(), new BgpSourcePrefixDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.IPV4_DST_PFX.name(), new BgpDestinationPrefixDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.EXT_FLOW_RULE_KEY.name(), new BgpFlowRuleKeyDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.IP_PROTO_LIST.name(), new BgpIpProtocolDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.IN_PORT_LIST.name(), new BgpInPortDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.DST_PORT_LIST.name(), new BgpDestinationPortDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.SRC_PORT_LIST.name(), new BgpSourcePortDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.ICMP_TYPE_LIST.name(), new BgpIcmpTypeDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.ICMP_CODE_LIST.name(), new BgpIcmpCodeDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.TCP_FLAG_LIST.name(), new BgpTcpFlagDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.PACKET_LENGTH_LIST.name(), new BgpPacketLengthDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.DSCP_VALUE_LIST.name(), new BgpDscpValueDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.FRAGMENT_LIST.name(), new BgpFragmentDecode());
+
+ decoderMap.put(ExtFlowTypes.ExtType.TRAFFIC_RATE.name(), new BgpTrafficRateDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.TRAFFIC_ACTION.name(), new BgpTrafficActionDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.TRAFFIC_REDIRECT.name(), new BgpTrafficRedirectDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.TRAFFIC_MARKING.name(), new BgpTrafficMarkingDecode());
+
+ decoderMap.put(ExtFlowTypes.ExtType.WIDE_COMM_FLAGS.name(), new BgpWcommFlagsDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.WIDE_COMM_HOP_COUNT.name(), new BgpWcommHopCountDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.WIDE_COMM_COMMUNITY.name(), new BgpWcommCommunityDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.WIDE_COMM_CONTEXT_AS.name(), new BgpWcommContextAsDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.WIDE_COMM_LOCAL_AS.name(), new BgpWcommLocalAsDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.WIDE_COMM_TARGET.name(), new BgpWcommTargetDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.WIDE_COMM_EXT_TARGET.name(), new BgpWcommExtTargetDecode());
+ decoderMap.put(ExtFlowTypes.ExtType.WIDE_COMM_PARAMETER.name(), new BgpWcommParameterDecode());
+ }
+
+ /** Source prefix decoder.*/
+ private class BgpSourcePrefixDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtPrefix.Builder resultBuilder = new DefaultExtPrefix.Builder();
+
+ String ip = nullIsIllegal(json.get(BgpFlowExtensionCodec.PREFIX),
+ BgpFlowExtensionCodec.PREFIX + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setPrefix(IpPrefix.valueOf(ip));
+ resultBuilder.setType(ExtFlowTypes.ExtType.IPV4_SRC_PFX);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Destination prefix decoder.*/
+ private class BgpDestinationPrefixDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtPrefix.Builder resultBuilder = new DefaultExtPrefix.Builder();
+
+ String ip = nullIsIllegal(json.get(BgpFlowExtensionCodec.PREFIX),
+ BgpFlowExtensionCodec.PREFIX + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setPrefix(IpPrefix.valueOf(ip));
+ resultBuilder.setType(ExtFlowTypes.ExtType.IPV4_DST_PFX);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Flow rule key decoder.*/
+ private class BgpFlowRuleKeyDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtKeyName.Builder resultBuilder = new DefaultExtKeyName.Builder();
+
+ String name = nullIsIllegal(json.get(BgpFlowExtensionCodec.NAME),
+ BgpFlowExtensionCodec.NAME + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setKeyName(name);
+ resultBuilder.setType(ExtFlowTypes.ExtType.EXT_FLOW_RULE_KEY);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Ip protocol decoder.*/
+ private class BgpIpProtocolDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtIpProtocol.Builder resultBuilder = new DefaultExtIpProtocol.Builder();
+
+ String protocols = nullIsIllegal(json.get(BgpFlowExtensionCodec.PROTOCOLS),
+ BgpFlowExtensionCodec.PROTOCOLS + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setIpProtocol(parse.parseIpProtocol(protocols));
+ resultBuilder.setType(ExtFlowTypes.ExtType.IP_PROTO_LIST);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** In port decoder.*/
+ private class BgpInPortDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtPort.Builder resultBuilder = new DefaultExtPort.Builder();
+
+ String portList = nullIsIllegal(json.get(BgpFlowExtensionCodec.PORT),
+ BgpFlowExtensionCodec.PORT + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setPort(parse.parsePort(portList));
+ resultBuilder.setType(ExtFlowTypes.ExtType.IN_PORT_LIST);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Destination decoder.*/
+ private class BgpDestinationPortDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtPort.Builder resultBuilder = new DefaultExtPort.Builder();
+
+ String portList = nullIsIllegal(json.get(BgpFlowExtensionCodec.DST_PORT),
+ BgpFlowExtensionCodec.DST_PORT + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setPort(parse.parsePort(portList));
+ resultBuilder.setType(ExtFlowTypes.ExtType.DST_PORT_LIST);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Source decoder.*/
+ private class BgpSourcePortDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtPort.Builder resultBuilder = new DefaultExtPort.Builder();
+
+ String portList = nullIsIllegal(json.get(BgpFlowExtensionCodec.SRC_PORT),
+ BgpFlowExtensionCodec.SRC_PORT + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setPort(parse.parsePort(portList));
+ resultBuilder.setType(ExtFlowTypes.ExtType.SRC_PORT_LIST);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Icmp type decoder.*/
+ private class BgpIcmpTypeDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtIcmpType.Builder resultBuilder = new DefaultExtIcmpType.Builder();
+
+ String icmpType = nullIsIllegal(json.get(BgpFlowExtensionCodec.ICMP_TYPE),
+ BgpFlowExtensionCodec.ICMP_TYPE + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setIcmpType(parse.parseIcmpType(icmpType));
+ resultBuilder.setType(ExtFlowTypes.ExtType.ICMP_TYPE_LIST);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Icmp code decoder.*/
+ private class BgpIcmpCodeDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtIcmpCode.Builder resultBuilder = new DefaultExtIcmpCode.Builder();
+
+ String icmpCode = nullIsIllegal(json.get(BgpFlowExtensionCodec.ICMP_CODE),
+ BgpFlowExtensionCodec.ICMP_CODE + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setIcmpCode(parse.parseIcmpCode(icmpCode));
+ resultBuilder.setType(ExtFlowTypes.ExtType.ICMP_CODE_LIST);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Tcp flag decoder.*/
+ private class BgpTcpFlagDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtTcpFlag.Builder resultBuilder = new DefaultExtTcpFlag.Builder();
+
+ String tcpFlag = nullIsIllegal(json.get(BgpFlowExtensionCodec.TCP_FLAG),
+ BgpFlowExtensionCodec.TCP_FLAG + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setTcpFlag(parse.parseTcpFlags(tcpFlag));
+ resultBuilder.setType(ExtFlowTypes.ExtType.TCP_FLAG_LIST);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Packet length decoder.*/
+ private class BgpPacketLengthDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtPacketLength.Builder resultBuilder = new DefaultExtPacketLength.Builder();
+
+ String packetLength = nullIsIllegal(json.get(BgpFlowExtensionCodec.PACKET_LENGTH),
+ BgpFlowExtensionCodec.PACKET_LENGTH + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setPacketLength(parse.parsePacketLength(packetLength));
+ resultBuilder.setType(ExtFlowTypes.ExtType.PACKET_LENGTH_LIST);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Dscp value decoder.*/
+ private class BgpDscpValueDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtDscpValue.Builder resultBuilder = new DefaultExtDscpValue.Builder();
+
+ String dscpValue = nullIsIllegal(json.get(BgpFlowExtensionCodec.DSCP_VALUE),
+ BgpFlowExtensionCodec.DSCP_VALUE + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setDscpValue(parse.parseDscp(dscpValue));
+ resultBuilder.setType(ExtFlowTypes.ExtType.DSCP_VALUE_LIST);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Fragment decoder.*/
+ private class BgpFragmentDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtFragment.Builder resultBuilder = new DefaultExtFragment.Builder();
+
+ String fragment = nullIsIllegal(json.get(BgpFlowExtensionCodec.FRAGMENT),
+ BgpFlowExtensionCodec.FRAGMENT + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setFragment(parse.parseFragment(fragment));
+ resultBuilder.setType(ExtFlowTypes.ExtType.FRAGMENT_LIST);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Traffic rate decoder.*/
+ private class BgpTrafficRateDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtTrafficRate.Builder resultBuilder = new DefaultExtTrafficRate.Builder();
+
+ String rate = nullIsIllegal(json.get(BgpFlowExtensionCodec.TRAFFIC_RATE),
+ BgpFlowExtensionCodec.TRAFFIC_RATE + MISSING_MEMBER_MESSAGE).asText();
+
+ String[] commaPart = rate.split(",");
+ String[] valuePart = commaPart[0].split("=");
+
+ if (valuePart[0].matches(BgpFlowExtensionCodec.TRAFFIC_RATE_ASN)) {
+ short s = Short.decode(valuePart[1].trim()).shortValue();
+ resultBuilder.setAsn(s);
+ } else {
+ nullIsIllegal(valuePart[0], BgpFlowExtensionCodec.TRAFFIC_RATE + MALFORMED_MEMBER_MESSAGE);
+ }
+
+ valuePart = commaPart[1].split("=");
+ if (valuePart[0].matches(BgpFlowExtensionCodec.TRAFFIC_RATE_RATE)) {
+ float f = Float.parseFloat(valuePart[1].trim());
+ resultBuilder.setRate(f);
+ } else {
+ nullIsIllegal(valuePart[0], BgpFlowExtensionCodec.TRAFFIC_RATE + MALFORMED_MEMBER_MESSAGE);
+ }
+
+ resultBuilder.setType(ExtFlowTypes.ExtType.TRAFFIC_RATE);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Traffic action decoder.*/
+ private class BgpTrafficActionDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtTrafficAction.Builder resultBuilder = new DefaultExtTrafficAction.Builder();
+
+ String rate = nullIsIllegal(json.get(BgpFlowExtensionCodec.TRAFFIC_ACTION),
+ BgpFlowExtensionCodec.TRAFFIC_ACTION + MISSING_MEMBER_MESSAGE).asText();
+
+ String[] commaPart = rate.split(",");
+ String[] valuePart = commaPart[0].split("=");
+
+ if (valuePart[0].matches(BgpFlowExtensionCodec.TRAFFIC_ACTION_TERMINAL)) {
+ boolean terminal = Boolean.parseBoolean(valuePart[1].trim());
+ resultBuilder.setTerminal(terminal);
+ } else {
+ nullIsIllegal(valuePart[0], BgpFlowExtensionCodec.TRAFFIC_ACTION_TERMINAL + MISSING_MEMBER_MESSAGE);
+ }
+
+ valuePart = commaPart[1].split("=");
+ if (valuePart[0].matches(BgpFlowExtensionCodec.TRAFFIC_ACTION_SAMPLE)) {
+ boolean sample = Boolean.parseBoolean(valuePart[1].trim());
+ resultBuilder.setSample(sample);
+ } else {
+ nullIsIllegal(valuePart[0], BgpFlowExtensionCodec.TRAFFIC_ACTION_SAMPLE + MISSING_MEMBER_MESSAGE);
+ }
+
+ valuePart = commaPart[2].split("=");
+ if (valuePart[0].matches(BgpFlowExtensionCodec.TRAFFIC_ACTION_RPD)) {
+ boolean rpd = Boolean.parseBoolean(valuePart[1].trim());
+ resultBuilder.setRpd(rpd);
+ } else {
+ nullIsIllegal(valuePart[0], BgpFlowExtensionCodec.TRAFFIC_ACTION_RPD + MISSING_MEMBER_MESSAGE);
+ }
+
+ resultBuilder.setType(ExtFlowTypes.ExtType.TRAFFIC_ACTION);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Traffic redirect decoder.*/
+ private class BgpTrafficRedirectDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtTrafficRedirect.Builder resultBuilder = new DefaultExtTrafficRedirect.Builder();
+
+ String action = nullIsIllegal(json.get(BgpFlowExtensionCodec.TRAFFIC_REDIRECTION),
+ BgpFlowExtensionCodec.TRAFFIC_REDIRECTION + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setRedirect(action);
+ resultBuilder.setType(ExtFlowTypes.ExtType.TRAFFIC_REDIRECT);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Traffic marking decoder.*/
+ private class BgpTrafficMarkingDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtTrafficMarking.Builder resultBuilder = new DefaultExtTrafficMarking.Builder();
+
+ String action = nullIsIllegal(json.get(BgpFlowExtensionCodec.TRAFFIC_MARKING),
+ BgpFlowExtensionCodec.TRAFFIC_MARKING + MISSING_MEMBER_MESSAGE).asText();
+
+ if ((action.length() != 1) || action.isEmpty()) {
+ nullIsIllegal(action, BgpFlowExtensionCodec.TRAFFIC_MARKING + MALFORMED_MEMBER_MESSAGE);
+ }
+
+ resultBuilder.setMarking((byte) action.charAt(0));
+ resultBuilder.setType(ExtFlowTypes.ExtType.TRAFFIC_MARKING);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Wide community flag decoder.*/
+ private class BgpWcommFlagsDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtWideCommunityInt.Builder resultBuilder = new DefaultExtWideCommunityInt.Builder();
+
+ String wideComm = nullIsIllegal(json.get(BgpFlowExtensionCodec.WIDE_COMM_FLAGS),
+ BgpFlowExtensionCodec.WIDE_COMM_FLAGS + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setwCommInt(Integer.valueOf(wideComm));
+ resultBuilder.setType(ExtFlowTypes.ExtType.WIDE_COMM_FLAGS);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Wide community hop count decoder.*/
+ private class BgpWcommHopCountDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtWideCommunityInt.Builder resultBuilder = new DefaultExtWideCommunityInt.Builder();
+
+ String wideComm = nullIsIllegal(json.get(BgpFlowExtensionCodec.WIDE_COMM_HOP_COUNT),
+ BgpFlowExtensionCodec.WIDE_COMM_HOP_COUNT + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setwCommInt(Integer.valueOf(wideComm));
+ resultBuilder.setType(ExtFlowTypes.ExtType.WIDE_COMM_HOP_COUNT);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Wide community decoder.*/
+ private class BgpWcommCommunityDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtWideCommunityInt.Builder resultBuilder = new DefaultExtWideCommunityInt.Builder();
+
+ String wideComm = nullIsIllegal(json.get(BgpFlowExtensionCodec.WIDE_COMM_COMMUNITY),
+ BgpFlowExtensionCodec.WIDE_COMM_COMMUNITY + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setwCommInt(Integer.valueOf(wideComm));
+ resultBuilder.setType(ExtFlowTypes.ExtType.WIDE_COMM_COMMUNITY);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Wide community context AS decoder.*/
+ private class BgpWcommContextAsDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtWideCommunityInt.Builder resultBuilder = new DefaultExtWideCommunityInt.Builder();
+
+ String wideComm = nullIsIllegal(json.get(BgpFlowExtensionCodec.WIDE_COMM_CONTEXT_AS),
+ BgpFlowExtensionCodec.WIDE_COMM_CONTEXT_AS + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setwCommInt(Integer.valueOf(wideComm));
+ resultBuilder.setType(ExtFlowTypes.ExtType.WIDE_COMM_CONTEXT_AS);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Wide community local AS decoder.*/
+ private class BgpWcommLocalAsDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtWideCommunityInt.Builder resultBuilder = new DefaultExtWideCommunityInt.Builder();
+
+ String wideComm = nullIsIllegal(json.get(BgpFlowExtensionCodec.WIDE_COMM_LOCAL_AS),
+ BgpFlowExtensionCodec.WIDE_COMM_LOCAL_AS + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setwCommInt(Integer.valueOf(wideComm));
+ resultBuilder.setType(ExtFlowTypes.ExtType.WIDE_COMM_LOCAL_AS);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Wide community parameter decoder.*/
+ private class BgpWcommParameterDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtWideCommunityInt.Builder resultBuilder = new DefaultExtWideCommunityInt.Builder();
+
+ String wideComm = nullIsIllegal(json.get(BgpFlowExtensionCodec.WIDE_COMM_PARAMETER),
+ BgpFlowExtensionCodec.WIDE_COMM_PARAMETER + MISSING_MEMBER_MESSAGE).asText();
+ resultBuilder.setwCommInt(Integer.valueOf(wideComm));
+ resultBuilder.setType(ExtFlowTypes.ExtType.WIDE_COMM_PARAMETER);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Wide community target decoder.*/
+ private class BgpWcommTargetDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtTarget.Builder resultBuilder = new DefaultExtTarget.Builder();
+
+ JsonNode jsonNodes = json.get(BgpFlowExtensionCodec.WIDE_COMM_TARGET);
+ if (jsonNodes == null) {
+ nullIsIllegal(json.get(BgpFlowExtensionCodec.WIDE_COMM_TARGET),
+ BgpFlowExtensionCodec.WIDE_COMM_TARGET + MISSING_MEMBER_MESSAGE).asText();
+ }
+
+ JsonNode array = jsonNodes.path(BgpFlowExtensionCodec.WIDE_COMM_TGT_LOCAL_SP);
+ if (array == null) {
+ nullIsIllegal(array, BgpFlowExtensionCodec.WIDE_COMM_TGT_LOCAL_SP + MISSING_MEMBER_MESSAGE).asText();
+ }
+
+ ExtPrefix.Builder resultBuilderPfx = parseIpArrayToPrefix(array);
+ resultBuilderPfx.setType(ExtFlowTypes.ExtType.IPV4_SRC_PFX);
+ resultBuilder.setLocalSpeaker(resultBuilderPfx.build());
+
+ array = jsonNodes.path(BgpFlowExtensionCodec.WIDE_COMM_TGT_REMOTE_SP);
+ if (array == null) {
+ nullIsIllegal(array, BgpFlowExtensionCodec.WIDE_COMM_TGT_REMOTE_SP + MISSING_MEMBER_MESSAGE).asText();
+ }
+
+ resultBuilderPfx = parseIpArrayToPrefix(array);
+ resultBuilderPfx.setType(ExtFlowTypes.ExtType.IPV4_DST_PFX);
+ resultBuilder.setRemoteSpeaker(resultBuilderPfx.build());
+ resultBuilder.setType(ExtFlowTypes.ExtType.WIDE_COMM_TARGET);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Wide community extended target decoder.*/
+ private class BgpWcommExtTargetDecode implements ExtensionDecoder {
+ @Override
+ public ExtFlowTypes decodeExtension(ObjectNode json) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ ExtTarget.Builder resultBuilder = new DefaultExtTarget.Builder();
+
+ JsonNode jsonNodes = json.get(BgpFlowExtensionCodec.WIDE_COMM_EXT_TARGET);
+ if (jsonNodes == null) {
+ nullIsIllegal(json.get(BgpFlowExtensionCodec.WIDE_COMM_EXT_TARGET),
+ BgpFlowExtensionCodec.WIDE_COMM_EXT_TARGET + MISSING_MEMBER_MESSAGE).asText();
+ }
+
+ JsonNode array = jsonNodes.path(BgpFlowExtensionCodec.WIDE_COMM_TGT_LOCAL_SP);
+ if (array == null) {
+ nullIsIllegal(array, BgpFlowExtensionCodec.WIDE_COMM_TGT_LOCAL_SP + MISSING_MEMBER_MESSAGE).asText();
+ }
+
+ ExtPrefix.Builder resultBuilderPfx = parseIpArrayToPrefix(array);
+ resultBuilderPfx.setType(ExtFlowTypes.ExtType.IPV4_SRC_PFX);
+ resultBuilder.setLocalSpeaker(resultBuilderPfx.build());
+
+ array = jsonNodes.path(BgpFlowExtensionCodec.WIDE_COMM_TGT_REMOTE_SP);
+ if (array == null) {
+ nullIsIllegal(array, BgpFlowExtensionCodec.WIDE_COMM_TGT_REMOTE_SP + MISSING_MEMBER_MESSAGE).asText();
+ }
+
+ resultBuilderPfx = parseIpArrayToPrefix(array);
+ resultBuilderPfx.setType(ExtFlowTypes.ExtType.IPV4_DST_PFX);
+ resultBuilder.setRemoteSpeaker(resultBuilderPfx.build());
+ resultBuilder.setType(ExtFlowTypes.ExtType.WIDE_COMM_EXT_TARGET);
+
+ return resultBuilder.build();
+ }
+ }
+
+ /** Ip address parser decoder.*/
+ public ExtPrefix.Builder parseIpArrayToPrefix(JsonNode array) {
+
+ ExtPrefix.Builder resultBuilder = new DefaultExtPrefix.Builder();
+ String ip;
+ IpPrefix prefix;
+ IpAddress ipAddr;
+
+ Iterator<JsonNode> itr = array.iterator();
+ while (itr.hasNext()) {
+ ip = itr.next().asText();
+ ipAddr = IpAddress.valueOf(ip);
+ prefix = IpPrefix.valueOf(ipAddr, 32);
+ resultBuilder.setPrefix(prefix);
+ }
+
+ return resultBuilder;
+ }
+
+ /**
+ * Decodes the JSON into a BgpFlowType extension object.
+ *
+ * @return ExtFlowTypes object
+ * @throws IllegalArgumentException if the JSON is invalid
+ */
+ public ExtFlowTypes decode() {
+ String type = json.get(BgpFlowExtensionCodec.TYPE).asText();
+
+ ExtensionDecoder decoder = decoderMap.get(type);
+ if (decoder != null) {
+ return decoder.decodeExtension(json);
+ }
+
+ throw new IllegalArgumentException("Type " + type + " is unknown");
+ }
+}
diff --git a/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/package-info.java b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/package-info.java
new file mode 100755
index 0000000..2f6d844
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/src/main/java/org/onosproject/bgpweb/web/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-prensent Open Networking Laboratory
+ *
+ * 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.
+ */
+
+/**
+ * Codec for bgp flow.
+ */
+package org.onosproject.bgpweb.web;
diff --git a/apps/bgpflowspec/bgpweb/src/main/webapp/WEB-INF/web.xml b/apps/bgpflowspec/bgpweb/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..2a13327
--- /dev/null
+++ b/apps/bgpflowspec/bgpweb/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2016-present Open Networking Laboratory
+ ~
+ ~ 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.
+ -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ id="ONOS" version="2.5">
+ <display-name>BGP REST API v1.0</display-name>
+
+
+ <servlet>
+ <servlet-name>JAX-RS Service</servlet-name>
+ <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.onosproject.bgpweb.resources.BgpWebApplication</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>JAX-RS Service</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+</web-app>