diff options
author | Ashlee Young <ashlee@onosfw.com> | 2015-10-09 18:32:44 -0700 |
---|---|---|
committer | Ashlee Young <ashlee@onosfw.com> | 2015-10-09 18:32:44 -0700 |
commit | 6a07d2d622eaa06953f3353e39c080984076e8de (patch) | |
tree | bfb50a2090fce186c2cc545a400c969bf2ea702b /framework/src/onos/apps/mfwd | |
parent | e6d71622143ff9b2421a1abbe8434b954b5b1099 (diff) |
Updated master to commit id 6ee8aa3e67ce89908a8c93aa9445c6f71a18f986
Change-Id: I94b055ee2f298daf71e2ec794fd0f2495bd8081f
Diffstat (limited to 'framework/src/onos/apps/mfwd')
18 files changed, 2319 insertions, 0 deletions
diff --git a/framework/src/onos/apps/mfwd/pom.xml b/framework/src/onos/apps/mfwd/pom.xml new file mode 100644 index 00000000..835de836 --- /dev/null +++ b/framework/src/onos/apps/mfwd/pom.xml @@ -0,0 +1,142 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright 2014 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 xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos-apps</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-app-mfwd</artifactId> + <packaging>bundle</packaging> + + <description>Multicast forwarding application</description> + + <properties> + <onos.app.name>org.onosproject.mfwd</onos.app.name> + </properties> + + <dependencies> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-cli</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty</artifactId> + <version>3.9.0.Final</version> + </dependency> + + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.karaf.shell</groupId> + <artifactId>org.apache.karaf.shell.console</artifactId> + </dependency> + + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + </dependency> + + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onlab-rest</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-rest</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-servlet</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + </dependency> + + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onlab-junit</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <scope>test</scope> + </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.slf4j, + org.osgi.framework, + javax.ws.rs,javax.ws.rs.core, + com.sun.jersey.api.core, + com.sun.jersey.spi.container.servlet, + com.sun.jersey.server.impl.container.servlet, + com.fasterxml.jackson.databind, + com.fasterxml.jackson.databind.node, + org.apache.commons.lang.math.*, + org.apache.karaf.shell.commands, + org.apache.karaf.shell.console, + com.google.common.*, + org.onlab.packet.*, + org.onlab.rest.*, + org.onosproject.*, + org.onlab.util.*, + org.jboss.netty.util.* + </Import-Package> + <Web-ContextPath>${web.context}</Web-ContextPath> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + +</project> + diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastDeleteCommand.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastDeleteCommand.java new file mode 100644 index 00000000..ae5d9e93 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastDeleteCommand.java @@ -0,0 +1,45 @@ +/* + * Copyright 2015 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.mfwd.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.mfwd.impl.McastRouteTable; + +/** + * Deletes a multicast route. + */ +@Command(scope = "onos", name = "mcast-delete", + description = "Delete a multicast route flow") +public class McastDeleteCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "sAddr", + description = "IP Address of the multicast source. '*' can be used for any source (*, G) entry", + required = true, multiValued = false) + String sAddr = null; + + @Argument(index = 1, name = "gAddr", + description = "IP Address of the multicast group", + required = true, multiValued = false) + String gAddr = null; + + @Override + protected void execute() { + McastRouteTable mrib = McastRouteTable.getInstance(); + mrib.removeRoute(sAddr, gAddr); + } +}
\ No newline at end of file diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java new file mode 100644 index 00000000..7260fde5 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastJoinCommand.java @@ -0,0 +1,72 @@ +/*
+ * Copyright 2014-2015 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.mfwd.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+
+import org.onosproject.mfwd.impl.McastConnectPoint;
+import org.onosproject.mfwd.impl.McastRouteBase;
+import org.onosproject.mfwd.impl.McastRouteTable;
+
+/**
+ * Installs a source, multicast group flow.
+ */
+@Command(scope = "onos", name = "mcast-join",
+ description = "Installs a source, multicast group flow")
+public class McastJoinCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "sAddr",
+ description = "IP Address of the multicast source. '*' can be used for any source (*, G) entry",
+ required = true, multiValued = false)
+ String sAddr = null;
+
+ @Argument(index = 1, name = "gAddr",
+ description = "IP Address of the multicast group",
+ required = true, multiValued = false)
+ String gAddr = null;
+
+ @Argument(index = 2, name = "ingressPort",
+ description = "Ingress port and Egress ports",
+ required = false, multiValued = false)
+ String ingressPort = null;
+
+ @Argument(index = 3, name = "ports",
+ description = "Ingress port and Egress ports",
+ required = false, multiValued = true)
+ String[] ports = null;
+
+ @Override
+ protected void execute() {
+ McastRouteTable mrib = McastRouteTable.getInstance();
+ McastRouteBase mr = mrib.addRoute(sAddr, gAddr);
+
+ // Port format "of:0000000000000023/4"
+ if (ingressPort != null) {
+ String inCP = ingressPort;
+ log.debug("Ingress port provided: " + inCP);
+ mr.addIngressPoint(inCP);
+ }
+
+ for (int i = 0; i < ports.length; i++) {
+ String egCP = ports[i];
+ log.debug("Egress port provided: " + egCP);
+ mr.addEgressPoint(egCP, McastConnectPoint.JoinSource.STATIC);
+ }
+ print("Added the mcast route");
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java new file mode 100644 index 00000000..7fa3a13a --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/McastShowCommand.java @@ -0,0 +1,62 @@ +/* + * Copyright 2014-2015 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.mfwd.cli; + +import org.apache.karaf.shell.commands.Command; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.JsonNode; + +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.mfwd.impl.McastRouteTable; +import org.onosproject.mfwd.impl.MRibCodec; + +import org.slf4j.Logger; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Displays the source, multicast group flows entries. + */ +@Command(scope = "onos", name = "mcast-show", description = "Displays the source, multicast group flows") +public class McastShowCommand extends AbstractShellCommand { + + private final Logger log = getLogger(getClass()); + private static final String MCAST_GROUP = "mcastgroup"; + + @Override + protected void execute() { + McastRouteTable mrt = McastRouteTable.getInstance(); + if (outputJson()) { + print("%s", json(mrt)); + } else { + printMrib4(mrt); + } + } + + public JsonNode json(McastRouteTable mrt) { + ObjectNode pushContent = new MRibCodec().encode(mrt , this); + return pushContent; + } + + /** + * Displays multicast route table entries. + * + * @param mrt Mutlicast Route Table + */ + protected void printMrib4(McastRouteTable mrt) { + print(mrt.printMcastRouteTable()); + } +} diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/package-info.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/package-info.java new file mode 100644 index 00000000..7b5ed39a --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/cli/package-info.java @@ -0,0 +1,5 @@ +/**
+ * Sample Multicast forwarding framework using intents.
+ */
+package org.onosproject.mfwd.cli;
+
diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/MRibCodec.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/MRibCodec.java new file mode 100644 index 00000000..c4f18527 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/MRibCodec.java @@ -0,0 +1,211 @@ +/* + * Copyright 2015 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.mfwd.impl; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; + +import org.onlab.packet.IpPrefix; + +import java.util.Set; +import java.util.Map; +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; + +import org.slf4j.Logger; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Encode and Decode the Multicast Route Table in JSON for CLI and REST commands. + */ +public class MRibCodec extends JsonCodec<McastRouteTable> { + + private final Logger log = getLogger(getClass()); + private static final String SOURCE_ADDRESS = "sourceAddress"; + private static final String GROUP_ADDRESS = "groupAddress"; + private static final String INGRESS_POINT = "ingressPoint"; + private static final String EGRESS_POINT = "egressPoint"; + private static final String MCASTCONNECTPOINT = "McastConnectPoint"; + private static final String ELEMENTID = "elementId"; + private static final String PORTNUMBER = "portNumber"; + private static final String MCAST_GROUP = "mcastGroup"; + + /** + * Encode the MRIB into json format. + * + * @param mcastRouteTable McastRouteTable + * @param context CodecContext + * @return result ObjectNode + */ + @Override + public ObjectNode encode(McastRouteTable mcastRouteTable, CodecContext context) { + + final JsonNodeFactory nodeFactory = JsonNodeFactory.instance; + final ObjectNode macastRouteTabNode = nodeFactory.objectNode(); + ArrayNode mcastGroupNode = context.mapper().createArrayNode(); + Optional<McastRouteTable> mcastRouteTabOpt = Optional.ofNullable(mcastRouteTable); + + //checking whether the McastRouteTable is present. + if (mcastRouteTabOpt.isPresent()) { + Map<IpPrefix, McastRouteGroup> mrib4 = mcastRouteTabOpt.get().getMrib4(); + Optional<Map<IpPrefix, McastRouteGroup>> mrib4Opt = Optional.ofNullable(mrib4); + + //checking whether the mrib4 is present. + if (mrib4Opt.isPresent()) { + + for (McastRouteGroup mg : mrib4Opt.get().values()) { + Collection<McastRouteSource> mcastRoute = mg.getSources().values(); + Optional<Collection<McastRouteSource>> mcastRouteOpt = Optional.ofNullable(mcastRoute); + + //checking whether the McastRouteSource List is present. + if (mcastRouteOpt.isPresent()) { + for (McastRouteSource mcastRouteSource : mcastRouteOpt.get()) { + mcastGroupNode.add(createMcastGroupNode(mcastRouteSource, context)); + } + macastRouteTabNode.put(MCAST_GROUP, mcastGroupNode); + } + } + } + } + return macastRouteTabNode; + } + /** + * Method for creating the McastGroup object node. + * + * @param mcastRouteSource McastRouteSource + */ + private ObjectNode createMcastGroupNode(McastRouteSource mcastRouteSource, CodecContext context) { + + final ObjectNode mcastGroupNode = context.mapper().createObjectNode(); + final ObjectNode ingressNode = context.mapper().createObjectNode(); + final ObjectNode egressNode = context.mapper().createObjectNode(); + final ArrayNode jsonLabelIds = context.mapper().createArrayNode(); + final String sAddr = mcastRouteSource.getSaddr().toString(); + final String gAddr = mcastRouteSource.getGaddr().toString(); + + Optional<String> saddrOpt = Optional.ofNullable(sAddr); + Optional<String> gaddrOpt = Optional.ofNullable(gAddr); + + //checking source address and group address are present. + if (saddrOpt.isPresent() && gaddrOpt.isPresent()) { + mcastGroupNode.put(SOURCE_ADDRESS, saddrOpt.get().toString()); + mcastGroupNode.put(GROUP_ADDRESS, gaddrOpt.get().toString()); + McastConnectPoint mcastIngCP = mcastRouteSource.getIngressPoint(); + Optional<McastConnectPoint> mcastIngCPOpt = Optional.ofNullable(mcastIngCP); + + //checking whether the ingress connection point is present. + if (mcastIngCPOpt.isPresent()) { + ingressNode.put(MCASTCONNECTPOINT, mcastConnectPoint(mcastIngCPOpt.get(), context)); + } + + mcastGroupNode.put(INGRESS_POINT , ingressNode); + Set<McastConnectPoint> mcastEgCPSet = mcastRouteSource.getEgressPoints(); + Optional<Set<McastConnectPoint>> mcastEgCPOpt = Optional.ofNullable(mcastEgCPSet); + + //checking whether the egress connection points are present. + if (mcastEgCPOpt.isPresent()) { + for (final McastConnectPoint mcastConnectPoint : mcastEgCPOpt.get()) { + jsonLabelIds.add(mcastConnectPoint(mcastConnectPoint, context)); + } + } + + egressNode.put(MCASTCONNECTPOINT , jsonLabelIds); + mcastGroupNode.put(EGRESS_POINT , egressNode); + } + return mcastGroupNode; + } + + /** + * Method for creating the McastConnectPoint object node. + * + * @param mcastConnectPoint McastConnectPoint + * @param context CodecContext + * @return mcastCpNode ObjectNode + */ + private ObjectNode mcastConnectPoint(McastConnectPoint mcastConnectPoint, CodecContext context) { + final ObjectNode mcastCpNode = context.mapper().createObjectNode(); + mcastCpNode.put(ELEMENTID , mcastConnectPoint.getConnectPoint().elementId().toString()); + mcastCpNode.put(PORTNUMBER , mcastConnectPoint.getConnectPoint().port().toLong()); + return mcastCpNode; + } + + /** + * Decode json format and insert into the flow table. + * + * @param json ObjectNode + * @param context CodecContext + * @return mr McastRouteBase + */ + @Override + public McastRouteTable decode(ObjectNode json, CodecContext context) { + + String macAddr = null; + String portNo = null; + String sAddr = json.path(SOURCE_ADDRESS).asText(); + String gAddr = json.path(GROUP_ADDRESS).asText(); + JsonNode inPntObjNode = (JsonNode) json.path(INGRESS_POINT); + JsonNode egPntArrNode = (JsonNode) json.path(EGRESS_POINT); + + log.debug("sAddr :" + sAddr + " gAddr :" + gAddr + " inPntObjNode :" + inPntObjNode); + log.debug("egPntArrNode :" + egPntArrNode.toString()); + + McastRouteTable mrib = McastRouteTable.getInstance(); + McastRouteBase mr = mrib.addRoute(sAddr, gAddr); + Optional<JsonNode> inPntOpt = Optional.ofNullable(inPntObjNode); + + if (inPntOpt.isPresent()) { + + JsonNode inMcastCP = inPntOpt.get().path(MCASTCONNECTPOINT); + Optional<JsonNode> inCpOpt = Optional.ofNullable(inMcastCP); + + if (inCpOpt.isPresent()) { + macAddr = inCpOpt.get().path(ELEMENTID).asText(); + portNo = inCpOpt.get().path(PORTNUMBER).asText(); + mr.addIngressPoint(macAddr + "/" + Long.parseLong(portNo)); + } + } + + Optional<JsonNode> egPntOpt = Optional.ofNullable(egPntArrNode); + + if (egPntOpt.isPresent()) { + JsonNode egMcastCP = egPntOpt.get().path(MCASTCONNECTPOINT); + Optional<JsonNode> egMcCpOpt = Optional.ofNullable(egMcastCP); + + if (egMcCpOpt.isPresent()) { + Iterator<JsonNode> egCpIt = egMcCpOpt.get().elements(); + + while (egCpIt.hasNext()) { + + JsonNode egMcastCPObj = egCpIt.next(); + Optional<JsonNode> egMcCpObOpt = Optional.ofNullable(egMcastCPObj); + if (egMcCpObOpt.isPresent()) { + macAddr = egMcCpObOpt.get().path(ELEMENTID).asText(); + portNo = egMcCpObOpt.get().path(PORTNUMBER).asText(); + log.debug("macAddr egPort : " + macAddr + " portNo egPort :" + portNo); + mr.addEgressPoint(macAddr + "/" + Long.parseLong(portNo), McastConnectPoint.JoinSource.STATIC); + } + } + } + } + return mrib; + } +} diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastConnectPoint.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastConnectPoint.java new file mode 100644 index 00000000..e2a6ff0d --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastConnectPoint.java @@ -0,0 +1,68 @@ +/* + * Copyright 2015 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.mfwd.impl; + +import org.onosproject.net.ConnectPoint; +import java.util.EnumSet; +import java.util.Set; + +/** + * Mulitcast ConnectPoint adds a variable to track the usage + * of these multicast endpoints. + */ +public class McastConnectPoint { + + private ConnectPoint connectPoint; + + public enum JoinSource { + STATIC, IGMP, PIM; + } + + public EnumSet<JoinSource> interest = EnumSet.noneOf(JoinSource.class); + + public McastConnectPoint(ConnectPoint cp) { + this.connectPoint = cp; + } + + public McastConnectPoint(ConnectPoint cp, JoinSource src) { + this.connectPoint = cp; + interest.add(src); + } + + public McastConnectPoint(String connectPoint, JoinSource src) { + ConnectPoint cp = ConnectPoint.deviceConnectPoint(connectPoint); + this.connectPoint = cp; + this.interest.add(src); + } + + /** + * Get the connect point. + * + * @return connectPoint + */ + public ConnectPoint getConnectPoint() { + return connectPoint; + } + + /** + * Get the sources of interest for this egressPoint. + * + * @return interest flags + */ + public Set<JoinSource> getInterest() { + return interest; + } +} diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java new file mode 100644 index 00000000..f5bd1e01 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastForwarding.java @@ -0,0 +1,237 @@ +/* + * Copyright 2015 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.mfwd.impl; + +import static org.slf4j.LoggerFactory.getLogger; + +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.onlab.packet.Ethernet; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.IpAddress; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.IPv4; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.packet.DefaultOutboundPacket; +import org.onosproject.net.packet.InboundPacket; +import org.onosproject.net.packet.OutboundPacket; +import org.onosproject.net.packet.PacketContext; +import org.onosproject.net.packet.PacketPriority; +import org.onosproject.net.packet.PacketProcessor; +import org.onosproject.net.packet.PacketService; +import org.slf4j.Logger; + +/** + * WORK-IN-PROGRESS: The multicast forwarding application using intent framework. + */ +@Component(immediate = true) +public class McastForwarding { + + private final Logger log = getLogger(getClass()); + private final IpPrefix mcast = IpPrefix.valueOf("224.0.0.0/4"); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PacketService packetService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + private ReactivePacketProcessor processor = new ReactivePacketProcessor(); + private McastRouteTable mrib; + private static ApplicationId appId; + + /** + * Active MulticastForwardingIntent. + */ + @Activate + public void activate() { + appId = coreService.registerApplication("org.onosproject.mfwd"); + + packetService.addProcessor(processor, PacketProcessor.director(2)); + + // Build a traffic selector for all multicast traffic + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchEthType(Ethernet.TYPE_IPV4); + selector.matchIPDst(mcast); + packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId); + + mrib = McastRouteTable.getInstance(); + log.info("Started"); + } + + /** + * Deactivate Multicast Forwarding Intent. + */ + @Deactivate + public void deactivate() { + packetService.removeProcessor(processor); + processor = null; + log.info("Stopped"); + } + + /** + * Get the application ID, used by the McastIntentManager. + * + * @return the application ID + */ + public static ApplicationId getAppId() { + return appId; + } + + /** + * Packet processor responsible for forwarding packets along their paths. + */ + private class ReactivePacketProcessor implements PacketProcessor { + + /** + * Process incoming packets. + * + * @param context packet processing context + */ + @Override + public void process(PacketContext context) { + // Stop processing if the packet has been handled, since we + // can't do any more to it. + if (context.isHandled()) { + return; + } + + InboundPacket pkt = context.inPacket(); + Ethernet ethPkt = pkt.parsed(); + + if (ethPkt == null) { + return; + } + + if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4 && + ethPkt.getEtherType() != Ethernet.TYPE_IPV6) { + return; + } + + if (ethPkt.getEtherType() == Ethernet.TYPE_IPV6) { + // Ignore ipv6 at the moment. + return; + } + + IPv4 ip = (IPv4) ethPkt.getPayload(); + IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress()); + IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress()); + + log.debug("Packet ({}, {}) has been punted\n" + + "\tingress port: {}\n", + saddr.toString(), + gaddr.toString(), + context.inPacket().receivedFrom().toString()); + + if (!mcast.contains(gaddr)) { + // Yikes, this is a bad group address + return; + } + + if (mcast.contains(saddr)) { + // Yikes, the source address is multicast + return; + } + + IpPrefix spfx = IpPrefix.valueOf(saddr, 32); + IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32); + + /* + * Do a best match lookup on the (s, g) of the packet. If an entry does + * not exist create one and store it's incoming connect point. + * + * The connect point is deviceId / portId that the packet entered + * the SDN network. This differs from traditional mcast where the + * ingress port would be a specific device. + */ + McastRoute entry = mrib.findBestMatch(spfx, gpfx); + if (entry == null || entry.getSaddr().equals(IPv4.fromIPv4Address(0))) { + + /* + * Create an entry that we can fast drop. + */ + entry = mrib.addRoute(spfx, gpfx); + entry.addIngressPoint(context.inPacket().receivedFrom()); + } + + /* + * TODO: If we do not have an ingress or any egress connect points we + * should set up a fast drop entry. + */ + if (entry.getIngressPoint() == null) { + return; + } + + if (entry.getEgressPoints().isEmpty()) { + return; + } + + /* + * This is odd, we should not have received a punted packet if an + * intent was installed unless the intent was not installed + * correctly. However, we are seeing packets get punted after + * the intent has been installed. + * + * Therefore we are going to forward the packets even if they + * should have already been forwarded by the intent fabric. + */ + if (entry.getIntentKey() != null) { + return; + } + + entry.setIntent(); + McastIntentManager im = McastIntentManager.getInstance(); + im.setIntent(entry); + + entry.incrementPuntCount(); + + // Send the pack out each of the egress devices & port + forwardPacketToDst(context, entry); + } + } + + /** + * Forward the packet to it's multicast destinations. + * + * @param context The packet context + * @param entry The multicast route entry matching this packet + */ + private void forwardPacketToDst(PacketContext context, McastRoute entry) { + + // Send the pack out each of the respective egress ports + for (ConnectPoint egress : entry.getEgressConnectPoints()) { + TrafficTreatment treatment = DefaultTrafficTreatment.builder() + .setOutput(egress.port()).build(); + + OutboundPacket packet = new DefaultOutboundPacket( + egress.deviceId(), + treatment, + context.inPacket().unparsed()); + + packetService.emit(packet); + } + } +} diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java new file mode 100644 index 00000000..90f65c94 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastIntentManager.java @@ -0,0 +1,133 @@ +/* + * Copyright 2015 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.mfwd.impl; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onlab.packet.Ethernet; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.SinglePointToMultiPointIntent; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +@Component(immediate = true) +@Service(value = org.onosproject.mfwd.impl.McastIntentManager.class) +public class McastIntentManager { + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentService intentService; + + private static McastIntentManager instance; + + public McastIntentManager() { + instance = this; + } + + /** + * Active this component. + */ + @Activate + public void activate() { } + + /** + * Deactivate this component. + */ + @Deactivate + public void deactivate() { + withdrawAllIntents(); + } + + /** + * Get instance of this intentManager. + * + * @return the instance of this intent manager. + */ + public static McastIntentManager getInstance() { + if (instance == null) { + instance = new McastIntentManager(); + } + return instance; + } + + /** + * Install the PointToMultipoint forwarding intent. + * + * @param mroute multicast route entry + * @return the intent that has been set or null otherwise + */ + public SinglePointToMultiPointIntent setIntent(McastRoute mroute) { + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); + + if (mroute.getIngressPoint() == null || + mroute.getEgressPoints().isEmpty()) { + return null; + } + + /* + * Match the group AND source addresses. We will also check ether type to + * determine if we are doing ipv4 or ipv6. + * + * If we really wanted to be pendantic we could put in a + * condition to make sure the ethernet MAC address was also + * mcast. + */ + selector.matchEthType(Ethernet.TYPE_IPV4) + .matchIPDst(mroute.getGaddr()) + .matchIPSrc(mroute.getSaddr()); + + SinglePointToMultiPointIntent intent = + SinglePointToMultiPointIntent.builder() + .appId(McastForwarding.getAppId()) + .selector(selector.build()) + .treatment(treatment) + .ingressPoint(mroute.getIngressPoint().getConnectPoint()) + .egressPoints(mroute.getEgressConnectPoints()). + build(); + + intentService.submit(intent); + return intent; + } + + /** + * Withdraw the intent represented by this route. + * + * @param mroute the mcast route whose intent we want to remove + */ + public void withdrawIntent(McastRouteBase mroute) { + Intent intent = intentService.getIntent(mroute.getIntentKey()); + intentService.withdraw(intent); + } + + /** + * Withdraw all intents. + * + * This will be called from the deactivate method so we don't leave + * a mess behind us after we leave. + */ + public void withdrawAllIntents() { + for (Intent intent : intentService.getIntents()) { + intentService.withdraw(intent); + } + } +} diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java new file mode 100644 index 00000000..12b7e6d4 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRoute.java @@ -0,0 +1,190 @@ +/* + * Copyright 2015 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.mfwd.impl; + +import org.onlab.packet.IpPrefix; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.intent.Key; +import org.onosproject.net.intent.SinglePointToMultiPointIntent; + +import java.util.Set; + +/** + * This McastRouteBase interface is implemented by the McastRouteBase class which + * in turn acts as the base class for both the McastRouteGroup and McastRouteSource. + */ +interface McastRoute { + + /** + * Gets the group addresses. + * + * @return group address + */ + public IpPrefix getGaddr(); + + /** + * Gets the source address. + * + * @return the source address + */ + public IpPrefix getSaddr(); + + /** + * Determines if this is an IPv4 multicast route. + * + * @return true if it is an IPv4 route + */ + public boolean isIp4(); + + /** + * Determines if this is an IPv6 multicast route. + * + * @return true if it is an IPv6 route + */ + public boolean isIp6(); + + /** + * Add the ingress ConnectPoint. + * + * @param cpstr string representing a ConnectPoint + * @return whether ingress has been added, only add if ingressPoint is null + */ + public boolean addIngressPoint(String cpstr); + + /** + * Add the ingress ConnectPoint. + * + * @param cp the ConnectPoint of incoming traffic. + * @return whether ingress has been added, only add if ingressPoint is null + */ + public boolean addIngressPoint(ConnectPoint cp); + + /** + * Get the ingress connect point. + * + * @return the ingress connect point + */ + public McastConnectPoint getIngressPoint(); + + /** + * Add an egress connect point. + * + * @param cp the egress McastConnectPoint to be added + * @return return the McastConnectPoint + */ + public McastConnectPoint addEgressPoint(ConnectPoint cp); + + /** + * Add an egress connect point. + * + * @param connectPoint deviceId/portNum + * @return return the McastConnectPoint + */ + public McastConnectPoint addEgressPoint(String connectPoint); + + /** + * Add an egress connect point. + * + * @param cp the egress McastConnectPoint to be added + * @param interest the protocol that has shown interest in this route + * @return return the McastConnectPoint + */ + public McastConnectPoint addEgressPoint(ConnectPoint cp, McastConnectPoint.JoinSource interest); + + /** + * Add an egress connect point. + * + * @param connectPoint deviceId/portNum + * @param interest the protocol that has shown interest in this route + * @return return the McastConnectPoint + */ + public McastConnectPoint addEgressPoint(String connectPoint, McastConnectPoint.JoinSource interest); + + /** + * Get the egress connect points. + * + * @return a set of egress connect points + */ + public Set<McastConnectPoint> getEgressPoints(); + + /** + * Get the egress connect points. + * + * @return a set of egress connect points + */ + public Set<ConnectPoint> getEgressConnectPoints(); + + /** + * Find the egress connect point if it exists. + * + * @param cp ConnectPoint to search for + * @return the connect point when found, null otherwise. + */ + public McastConnectPoint findEgressConnectPoint(ConnectPoint cp); + + /** + * remove Interest from a McastConnectPoint. + * + * @param mcp connect point. + * @param interest the protocol interested in this multicast stream + * @return whether or not interest was removed + */ + public boolean removeInterest(McastConnectPoint mcp, McastConnectPoint.JoinSource interest); + + /** + * Increment the punt count. + */ + public void incrementPuntCount(); + + /** + * Get the punt count. + * + * @return the punt count + */ + public int getPuntCount(); + + /** + * Have the McastIntentManager create an intent, attempt to + * install the intent and then save the key. + */ + public void setIntent(); + + /** + * Set the Intent key. + * + * @param intent intent + */ + public void setIntent(SinglePointToMultiPointIntent intent); + + /** + * Withdraw the intent if it has been installed. + */ + public void withdrawIntent(); + + /** + * Get the intent key. + * + * @return the intentKey + */ + public Key getIntentKey(); + + /** + * Pretty print the the route. + * + * @return a pretty string + */ + public String toString(); +}
\ No newline at end of file diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java new file mode 100644 index 00000000..730acfa7 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteBase.java @@ -0,0 +1,431 @@ +/* + * Copyright 2015 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.mfwd.impl; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.apache.commons.collections.set.ListOrderedSet; +import org.onlab.packet.IpPrefix; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.intent.SinglePointToMultiPointIntent; +import org.onosproject.net.intent.Key; + +import java.util.Set; +import java.util.HashSet; + +/** + * McastRouteBase base class for McastRouteGroup and McastRouteSource. + */ +public class McastRouteBase implements McastRoute { + protected final IpPrefix gaddr; + protected final IpPrefix saddr; + + protected McastConnectPoint ingressPoint; + protected Set<McastConnectPoint> egressPoints; + + protected boolean isGroup = false; + + protected boolean dirty = false; + + /** + * How may times has this packet been punted. + */ + private int puntCount = 0; + + /** + * If the intentKey is null that means no intent has + * been installed. + */ + protected Key intentKey = null; + + /** + * Create a multicast route. This is the parent class for both the Group + * and the source. + * + * @param saddr source address + * @param gaddr multicast group address + */ + public McastRouteBase(String saddr, String gaddr) { + this.gaddr = IpPrefix.valueOf(checkNotNull(gaddr)); + if (saddr == null || saddr.equals("*")) { + this.saddr = IpPrefix.valueOf(0, 0); + } else { + this.saddr = IpPrefix.valueOf(checkNotNull(gaddr)); + } + this.init(); + } + + /** + * Create a multicast group table entry. + * @param gaddr multicast group address + */ + public McastRouteBase(String gaddr) { + this("*", gaddr); + } + + /** + * Set the source and group address value of a (*, G) group. + * + * @param gpfx the group prefix address + */ + public McastRouteBase(IpPrefix gpfx) { + this(IpPrefix.valueOf(0, 0), gpfx); + } + + /** + * Create a multicast route constructor. + * + * @param saddr source address + * @param gaddr group address + */ + public McastRouteBase(IpPrefix saddr, IpPrefix gaddr) { + this.saddr = checkNotNull(saddr); + this.gaddr = checkNotNull(gaddr); + + this.init(); + } + + private void init() { + this.isGroup = (this.saddr.prefixLength() == 0); + this.ingressPoint = null; + this.egressPoints = new HashSet(); + } + + /** + * Get the multicast group address. + * + * @return the multicast group address + */ + @Override + public IpPrefix getGaddr() { + return gaddr; + } + + /** + * Get the multicast source address. + * + * @return the multicast source address + */ + @Override + public IpPrefix getSaddr() { + return saddr; + } + + /** + * Is this an IPv4 multicast route. + * + * @return true if it is an IPv4 route + */ + @Override + public boolean isIp4() { + return gaddr.isIp4(); + } + + /** + * Is this an IPv6 multicast route. + * + * @return true if it is an IPv6 route + */ + @Override + public boolean isIp6() { + return gaddr.isIp6(); + } + + /** + * Is this a multicast group route? + * + * @return true if it is a multicast group route. + */ + public boolean isGroup() { + return isGroup; + } + + /** + * @return true if this is (S, G) false if it (*, G). + */ + public boolean isSource() { + return (!isGroup); + } + + /** + * Get the dirty state. + * + * @return whether this route is dirty or not. + */ + public boolean getDirty() { + return this.dirty; + } + + /** + * Set the dirty state to indicate that something changed. + * This may require an update to the flow tables (intents). + * + * @param dirty set the dirty bit + */ + public void setDirty(boolean dirty) { + this.dirty = dirty; + } + + /** + * Add an ingress point to this route. + * + * @param ingress incoming connect point + * @return whether ingress has been added, only add if ingressPoint is null + */ + public boolean addIngressPoint(ConnectPoint ingress) { + + // Do NOT add the ingressPoint if it is not null. + if (this.ingressPoint != null) { + // TODO: Log an warning. + return false; + } + this.ingressPoint = new McastConnectPoint(checkNotNull(ingress)); + setDirty(true); + return true; + } + + /** + * Add or modify the ingress connect point. + * + * @param connectPoint string switch device Id + * @return whether ingress has been added, only add if ingressPoint is null + */ + public boolean addIngressPoint(String connectPoint) { + + if (this.ingressPoint != null) { + // TODO: log a warning. + return false; + } + ConnectPoint cp = ConnectPoint.deviceConnectPoint(checkNotNull(connectPoint)); + return this.addIngressPoint(cp); + } + + /** + * Get the ingress McastConnectPoint. + * + * @return the ingress McastConnectPoint + */ + public McastConnectPoint getIngressPoint() { + return this.ingressPoint; + } + + /** + * Add an egress McastConnectPoint. + * + * @param cp egress connect point + * @return return the McastConnectPoint + */ + public McastConnectPoint addEgressPoint(ConnectPoint cp) { + McastConnectPoint mcp = this.findEgressConnectPoint(cp); + if (mcp == null) { + mcp = new McastConnectPoint(checkNotNull(cp)); + egressPoints.add(mcp); + setDirty(true); + } + return mcp; + } + + /** + * Add an egress connect point from a string. + * + * @param connectPoint string representing a connect point + * @return the MulticastConnectPoint + */ + public McastConnectPoint addEgressPoint(String connectPoint) { + checkNotNull(connectPoint); + return this.addEgressPoint(ConnectPoint.deviceConnectPoint(connectPoint)); + } + + /** + * Add an egress McastConnectPoint. + * + * @param cp the egress connect point + * @param interest the source of interest for mcast traffic + */ + public McastConnectPoint addEgressPoint(ConnectPoint cp, McastConnectPoint.JoinSource interest) { + checkNotNull(cp); + checkNotNull(interest); + McastConnectPoint mcp = this.addEgressPoint(cp); + if (mcp != null) { + mcp.interest.add(interest); + setDirty(true); + } + return mcp; + } + + /** + * Add an egress McastConnectPoint. + * + * @param cpstr deviceId/port of the connect point + */ + public McastConnectPoint addEgressPoint(String cpstr, McastConnectPoint.JoinSource interest) { + checkNotNull(cpstr); + checkNotNull(interest); + return this.addEgressPoint(ConnectPoint.deviceConnectPoint(cpstr), interest); + } + + /** + * Get egress connect points for the route. + * + * @return Set of egress connect points + */ + public Set<McastConnectPoint> getEgressPoints() { + return egressPoints; + } + + /** + * Get egress McastConnectPoints points as ConnectPoints for intent system. + * + * @return Set of egress ConnectPoints + */ + public Set<ConnectPoint> getEgressConnectPoints() { + Set<ConnectPoint> cps = new ListOrderedSet(); + + for (McastConnectPoint mcp : egressPoints) { + cps.add(mcp.getConnectPoint()); + } + return cps; + } + + /** + * Find the Multicast Connect Point that contains the ConnectPoint. + * + * @param cp the regular ConnectPoint to match + * @return the McastConnectPoint that contains cp or null if not found. + */ + public McastConnectPoint findEgressConnectPoint(ConnectPoint cp) { + for (McastConnectPoint mcp : this.egressPoints) { + if (mcp.getConnectPoint().equals(cp)) { + return mcp; + } + } + return null; + } + + /** + * Remove specified interest from the given ConnectPoint. + * + * @param mcp connect point. + * @param interest the protocol interested in this multicast stream + * @return true if removed, false otherwise + */ + public boolean removeInterest(McastConnectPoint mcp, McastConnectPoint.JoinSource interest) { + checkNotNull(mcp); + if (mcp.interest.contains(interest)) { + mcp.interest.remove(interest); + setDirty(true); + return true; + } + return false; + } + + /** + * Get the number of times the packet has been punted. + * + * @return the punt count + */ + @Override + public int getPuntCount() { + return puntCount; + } + + /** + * Increment the punt count. + * + * TODO: we need to handle wrapping. + */ + @Override + public void incrementPuntCount() { + puntCount++; + } + + /** + * Have the McastIntentManager create and set the intent, then save the intent key. + * + * If we already have an intent, we will first withdraw the existing intent and + * replace it with a new one. This will support the case where the ingress connectPoint + * or group of egress connectPoints change. + */ + @Override + public void setIntent() { + if (this.intentKey != null) { + this.withdrawIntent(); + } + McastIntentManager im = McastIntentManager.getInstance(); + SinglePointToMultiPointIntent intent = im.setIntent(this); + this.intentKey = intent.key(); + } + + /** + * Set the Intent key. + * + * @param intent the multicast intent + */ + @Override + public void setIntent(SinglePointToMultiPointIntent intent) { + intentKey = intent.key(); + } + + /** + * Get the intent key represented by this route. + * + * @return intentKey + */ + @Override + public Key getIntentKey() { + return this.intentKey; + } + + + /** + * Withdraw the intent and set the key to null. + */ + @Override + public void withdrawIntent() { + if (intentKey == null) { + // nothing to withdraw + return; + } + McastIntentManager im = McastIntentManager.getInstance(); + im.withdrawIntent(this); + this.intentKey = null; + } + + /** + * Pretty Print this Multicast Route. Works for McastRouteSource and McastRouteGroup. + * + * @return pretty string of the multicast route + */ + @Override + public String toString() { + String out = String.format("(%s, %s)\n\t", + saddr.toString(), gaddr.toString()); + + out += "intent: "; + out += (intentKey == null) ? "not installed" : this.intentKey.toString(); + out += "\n\tingress: "; + out += (ingressPoint == null) ? "NULL" : ingressPoint.toString(); + out += "\n\tegress: {\n"; + if (egressPoints != null && !egressPoints.isEmpty()) { + for (McastConnectPoint eg : egressPoints) { + out += "\t\t" + eg.getConnectPoint().toString() + "\n"; + } + } + out += ("\t}\n"); + out += ("\tpunted: " + this.getPuntCount() + "\n"); + return out; + } +} diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteGroup.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteGroup.java new file mode 100644 index 00000000..4a58e1b1 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteGroup.java @@ -0,0 +1,110 @@ +/* + * Copyright 2015 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.mfwd.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import java.util.HashMap; +import org.onlab.packet.IpPrefix; + +/** + * The McastRouteGroup extends the McastRouteBase class and serves two purposes: + * first it represents a (*, G) multicast route entry. Second it serves + * as a container for all (S, G) multicast route entries that belong + * to the same group address. + */ +public class McastRouteGroup extends McastRouteBase { + private HashMap<IpPrefix, McastRouteSource> sources; + + /** + * Class constructor. + * + * @param gaddr - String representation of group address. + */ + public McastRouteGroup(String gaddr) { + super(checkNotNull(gaddr)); + this.init(); + } + + /** + * Create a multicast group. + * + * @param gpfx - Group address + */ + public McastRouteGroup(IpPrefix gpfx) { + super(checkNotNull(gpfx)); + this.init(); + } + + /** + * Common initialization used by constructors. + */ + private void init() { + this.sources = new HashMap(); + super.isGroup = true; + } + + /** + * Find a specific multicast source address for this group. + * + * @param saddr the source address + * @return the multicast source route or null if it does not exist + */ + public McastRouteSource findSource(IpPrefix saddr) { + return this.sources.get(checkNotNull(saddr)); + } + + /** + * Return the entire set of multicast sources for this group. + * + * @return the set of multicast sources + */ + public HashMap<IpPrefix, McastRouteSource> getSources() { + return this.sources; + } + + /** + * Add a new McastRouteSource to this group. + * + * @param src the multicast source + */ + public void addSource(McastRouteSource src) { + checkNotNull(src); + this.sources.put(src.getSaddr(), src); + } + + /** + * Remove the source with this specific IpPrefix from this group entry. + * + * @param spfx IP Prefix of the source to be removed + * @return the source route that was just removed + */ + public McastRouteSource removeSource(IpPrefix spfx) { + McastRouteSource src = this.sources.remove(spfx); + src.withdrawIntent(); + return src; + } + + /** + * Remove all sources from this. + */ + public void removeSources() { + for (McastRouteSource src : this.sources.values()) { + src.withdrawIntent(); + this.sources.remove(src.getSaddr()); + } + } + +} diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteSource.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteSource.java new file mode 100644 index 00000000..68edc2e0 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteSource.java @@ -0,0 +1,48 @@ +/* + * Copyright 2015 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.mfwd.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import org.onlab.packet.IpPrefix; + +/** + * This class represents and specific multicast senders source address. Objects from + * this class will belong to the sources collection of the multicast group. + */ +public class McastRouteSource extends McastRouteBase { + + // A reference to our parent group + private McastRouteGroup group; + + /** + * Create a multicast source with IpPrefixes. + * + * @param source the source address + * @param group the group address + */ + public McastRouteSource(IpPrefix source, IpPrefix group) { + super(checkNotNull(source), checkNotNull(group)); + } + + /** + * Set our parent multicast group. + * + * @param group the group this source belongs to + */ + public void setGroup(McastRouteGroup group) { + this.group = group; + } +}
\ No newline at end of file diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java new file mode 100644 index 00000000..5a07bec7 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/McastRouteTable.java @@ -0,0 +1,338 @@ +/* + * Copyright 2015 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.mfwd.impl; + +import org.apache.felix.scr.annotations.Service; +import org.onlab.packet.IpPrefix; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The Mcast Route Table holds all multicast state for the controller. + * + * State for IPv4 and IPv6 are maintained. The tables are sets of McastRouteGroup + * structures that represent (*, G) state with a series of egress ConnectPoints. + * Each (*, G) may also have a set of (S, G) that may have there own set of + * ingress and egress ConnectPoints. + * + * TODO: perhaps should probably create two separate singleton for IPv4 and IPv6 respectively. + */ +@Service(value = org.onosproject.mfwd.impl.McastRouteTable.class) +public final class McastRouteTable { + + /* + * Create a map of the McastGroups indexed by the multicast group prefix. + * We may choose to change the map data structure in to some form a radix trie + * depending on the type of real world usage we see. + */ + private final Map<IpPrefix, McastRouteGroup> mrib4; + private final Map<IpPrefix, McastRouteGroup> mrib6; + private static McastRouteTable instance = null; + + private Boolean ipv6Enabled = false; + + /** + * Create the two v4 & v6 tables. + */ + private McastRouteTable() { + mrib4 = new ConcurrentHashMap<IpPrefix, McastRouteGroup>(); + if (ipv6Enabled) { + mrib6 = new ConcurrentHashMap<IpPrefix, McastRouteGroup>(); + } else { + mrib6 = null; + } + } + + /** + * Get the single instance of this multicast group address. + * + * @return the multicast route table + */ + public static McastRouteTable getInstance() { + if (instance == null) { + instance = new McastRouteTable(); + } + return instance; + } + + /** + * Get the IPv4 MRIB. + * + * @return the IPv4 MRIB + */ + public Map<IpPrefix, McastRouteGroup> getMrib4() { + return mrib4; + } + + /** + * Get the IPv6 MRIB. + * + * @return Return the set of prefix keyed McastGroups + */ + public Map<IpPrefix, McastRouteGroup> getMrib6() { + return mrib6; + } + + /** + * Save the McastRouteGroup in the address family appropriate mrib. + * + * @param group The McastRouteGroup to save + */ + private void storeGroup(McastRouteGroup group) { + if (group.isIp4()) { + mrib4.put(group.getGaddr(), group); + } else if (group.isIp6() && ipv6Enabled) { + mrib6.put(group.getGaddr(), group); + } + } + + /** + * Remove the group. + * + * @param group the group to be removed + */ + private void removeGroup(McastRouteGroup group) { + IpPrefix gpfx = group.getGaddr(); + if (gpfx.isIp4()) { + mrib4.remove(gpfx); + } else if (gpfx.isIp6() && ipv6Enabled) { + mrib6.remove(gpfx); + } + } + + /** + * Add a multicast route to the MRIB. This function will. + * + * @param saddr source address * or x.x.x.x or x.x.x.x/y + * @param gaddr group address x.x.x.x or x.x.x.x/y + * @return the multicast route + */ + public McastRouteBase addRoute(String saddr, String gaddr) { + IpPrefix gpfx = IpPrefix.valueOf(gaddr); + IpPrefix spfx = IpPrefix.valueOf(0, 0); + if (saddr != null && !saddr.equals("*")) { + spfx = IpPrefix.valueOf(saddr); + } + return addRoute(spfx, gpfx); + } + + /** + * Add a multicast route to the MRIB. This function will store either + * (S, G) or (*, G) in the mrib if an entry does not already exist. If + * an entry does exist it is returned to the caller. + * + * Every (S, G) is stored as part of it's parent group entry which also represents + * (*, G) routes. In the case of a (S, G) we will also create the (*, G) entry if needed + * then save the (S, G) to the (*, G). + * + * @param spfx the source prefix + * @param gpfx the group prefix + * @return the resulting McastRouteSource or McastRouteGroup accordingly. + */ + public McastRouteBase addRoute(IpPrefix spfx, IpPrefix gpfx) { + + /** + * If a group route (*, g) does not exist we will need to make so we + * can start attaching our sources to the group entry. + */ + McastRouteGroup group = findMcastGroup(gpfx); + if (group == null) { + group = new McastRouteGroup(gpfx); + + // Save it for later + if (gpfx.isIp4()) { + this.mrib4.put(gpfx, group); + } else if (gpfx.isIp6() && ipv6Enabled) { + this.mrib6.put(gpfx, group); + } + } + + /** + * If the source prefix length is 0 then we have our (*, g) entry, we can + * just return now. + */ + if (spfx.prefixLength() == 0) { + return group; + } + + // See if the source already exists. If so just return it. + McastRouteSource source = group.findSource(spfx); + if (source != null) { + return source; + } + + /** + * We have the group but no source. We need to create the source then add it + * to the group. + */ + source = new McastRouteSource(spfx, gpfx); + + // Have the source save it's parent + source.setGroup(group); + + // Save this source as part of this group + group.addSource(source); + + return source; + } + + /** + * Delete a multicast route from the MRIB. + * + * @param saddr source address * or x.x.x.x or x.x.x.x/y + * @param gaddr group address x.x.x.x or x.x.x.x/y + */ + public void removeRoute(String saddr, String gaddr) { + IpPrefix gpfx = IpPrefix.valueOf(gaddr); + IpPrefix spfx = IpPrefix.valueOf(0, 0); + if (saddr != null && !saddr.equals("*")) { + spfx = IpPrefix.valueOf(saddr); + } + removeRoute(spfx, gpfx); + } + + /** + * Remove a multicast route. + * + * @param spfx the source prefix + * @param gpfx the group prefix + */ + public void removeRoute(IpPrefix spfx, IpPrefix gpfx) { + + /** + * If a group route (*, g) does not exist we will need to make so we + * can start attaching our sources to the group entry. + */ + McastRouteGroup group = findMcastGroup(gpfx); + if (group == null) { + // The group does not exist, we can't remove it. + return; + } + + /** + * If the source prefix length is 0 then we have a (*, g) entry, which + * means we will remove this group and all of it's sources. We will + * also withdraw it's intent if need be. + */ + if (spfx.prefixLength() > 0) { + group.removeSource(spfx); + + /* + * Now a little house keeping. If this group has no more sources + * nor egress connectPoints git rid of it. + */ + if (group.getSources().size() == 0 && + group.getEgressPoints().size() == 0) { + removeGroup(group); + } + + } else { + // Group remove has been explicitly requested. + group.removeSources(); + group.withdrawIntent(); + removeGroup(group); + } + } + + /** + * Find the specific multicast group entry. + * + * @param group the group address + * @return McastRouteGroup the multicast (*, G) group route + */ + public McastRouteGroup findMcastGroup(IpPrefix group) { + McastRouteGroup g = null; + if (group.isIp4()) { + g = mrib4.get(group); + } else if (group.isIp6() && ipv6Enabled) { + g = mrib6.get(group); + } + return g; + } + + /** + * Find the multicast (S, G) entry if it exists. + * + * @param saddr the source address + * @param gaddr the group address + * @return The multicast source route entry if it exists, null if it does not. + */ + public McastRouteSource findMcastSource(IpPrefix saddr, IpPrefix gaddr) { + McastRouteGroup grp = findMcastGroup(checkNotNull(gaddr)); + if (grp == null) { + return null; + } + return grp.findSource(saddr); + } + + /** + * This will first look up a Group entry. If no group entry was found null will + * be returned. If the group entry has been found we will then look up the (s, g) entry. + * If the (s, g) entry has been found, that will be returned. If no (s, g) was found + * the (*, g) group entry will be returned. + * + * @param saddr the source address + * @param gaddr the group address + * @return return the best matching McastRouteSource or McastRouteGroup + */ + public McastRoute findBestMatch(IpPrefix saddr, IpPrefix gaddr) { + McastRouteGroup grp = this.findMcastGroup(checkNotNull(gaddr)); + if (grp == null) { + return null; + } + + // Found a group now look for a source + McastRouteSource src = grp.findSource(checkNotNull(saddr)); + if (src == null) { + return grp; + } + + return src; + } + + /** + * Print out the multicast route table in it's entirety. + * + * TODO: Eventually we will have to implement paging and how to handle large tables. + * @return String + */ + public String printMcastRouteTable() { + String out = this.toString() + "\n"; + + for (McastRouteGroup grp : mrib4.values()) { + out += grp.toString() + "\n"; + for (McastRouteSource src : grp.getSources().values()) { + out += src.toString() + "\n"; + } + } + return out; + } + + /** + * Print out a summary of groups in the MRIB. + * + * @return String + */ + public String toString() { + String out = "Mcast Route Table: "; + out += mrib4.size() + " IPv4 Multicast Groups\n"; + if (ipv6Enabled) { + out += mrib6.size() + " IPv6 Multicast Groups\n"; + } + return out; + } +} diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/package-info.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/package-info.java new file mode 100644 index 00000000..eaef5fcf --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/impl/package-info.java @@ -0,0 +1,4 @@ +/** + * Sample Multicast forwarding framework using intents. + */ +package org.onosproject.mfwd.impl; diff --git a/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/McastResource.java b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/McastResource.java new file mode 100644 index 00000000..608e0447 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/java/org/onosproject/mfwd/rest/McastResource.java @@ -0,0 +1,149 @@ +/*
+ * Copyright 2015 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.mfwd.rest;
+
+import java.io.IOException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.onosproject.mfwd.impl.McastConnectPoint;
+import org.onosproject.mfwd.impl.McastRouteTable;
+import org.onosproject.mfwd.impl.McastRouteBase;
+import org.onosproject.mfwd.impl.MRibCodec;
+import org.onosproject.rest.AbstractWebResource;
+
+import org.slf4j.Logger;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Rest API for Multicast Forwarding.
+ */
+@Path("mcast")
+public class McastResource extends AbstractWebResource {
+
+ private final Logger log = getLogger(getClass());
+ private static final String SOURCE_ADDRESS = "sourceAddress";
+ private static final String GROUP_ADDRESS = "groupAddress";
+ private static final String INGRESS_POINT = "ingressPoint";
+ private static final String EGRESS_POINT = "egressPoint";
+ private static final String MCAST_GROUP = "mcastGroup";
+
+ /**
+ * Retrieve the multicast route table.
+ *
+ * @return the multicast route table.
+ * @throws IOException if an error occurs
+ */
+ @Path("show")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response showAll() throws IOException {
+ McastRouteTable mrt = McastRouteTable.getInstance();
+ ObjectNode pushContent = new MRibCodec().encode(mrt , this);
+ return ok(pushContent.toString()).build();
+ }
+
+ /**
+ * Static join a multicast flow.
+ *
+ * @param sAddr source address to join
+ * @param gAddr group address to join
+ * @param ports ingress and egress ConnectPoints to join
+ * @return the Result of the join
+ * @throws IOException if something failed with the join command
+ */
+ @Path("/join")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response join(@QueryParam("src") String sAddr,
+ @QueryParam("grp") String gAddr,
+ @DefaultValue("") @QueryParam("ports") String ports)
+ throws IOException {
+
+ ObjectMapper mapper = new ObjectMapper();
+ log.debug("Source IP Address: " + sAddr);
+ log.debug("Destination IP Address: " + gAddr);
+ log.debug("Ingress and Egress ports: " + ports);
+
+ String output = "Insertion Faild";
+ if (sAddr != null && gAddr != null && ports != null) {
+
+ String[] portArr = ports.split(",");
+ log.debug("Port Array Length: " + portArr.length);
+ McastRouteTable mrt = McastRouteTable.getInstance();
+ McastRouteBase mr = mrt.addRoute(sAddr, gAddr);
+
+ // Port format "of:0000000000000023/4"
+ log.debug("checking inside outer if: " + portArr.length);
+
+ if (mr != null && portArr != null && portArr.length > 0) {
+
+ String inCP = portArr[0];
+ log.debug("Ingress port provided: " + inCP);
+ mr.addIngressPoint(inCP);
+
+ for (int i = 1; i < portArr.length; i++) {
+ String egCP = portArr[i];
+ log.debug("Egress port provided: " + egCP);
+ mr.addEgressPoint(egCP, McastConnectPoint.JoinSource.STATIC);
+ }
+ mrt.printMcastRouteTable();
+ output = "Successfully Inserted";
+ }
+ } else {
+ output = "Please Insert the rest uri correctly";
+ }
+ return Response.ok(output).build();
+ }
+
+ /**
+ * Delete multicast state.
+ *
+ * @param src address to be deleted
+ * @param grp address to be deleted
+ * @return status of delete if successful
+ */
+ @Path("/delete")
+ @DELETE
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response removeMcastFlow(@QueryParam("src") String src,
+ @QueryParam("grp") String grp) {
+
+ String resp = "Failed to delete";
+ log.info("Source IP Address to delete: " + src);
+ log.info("Destination IP Address to delete: " + grp);
+ McastRouteTable mrt = McastRouteTable.getInstance();
+ if (src != null && grp != null) {
+ mrt.removeRoute(src, grp);
+ resp = "Deleted flow for src " + src + " and grp " + grp;
+ }
+
+ return Response.ok(resp).build();
+ }
+}
diff --git a/framework/src/onos/apps/mfwd/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/mfwd/src/main/resources/OSGI-INF/blueprint/shell-config.xml new file mode 100644 index 00000000..966cb4f2 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -0,0 +1,30 @@ +<!--
+ ~ Copyright 2014 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.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.mfwd.cli.McastJoinCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.mfwd.cli.McastDeleteCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.mfwd.cli.McastShowCommand"/>
+ </command>
+ </command-bundle>
+
+</blueprint>
diff --git a/framework/src/onos/apps/mfwd/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/mfwd/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..c4c4f459 --- /dev/null +++ b/framework/src/onos/apps/mfwd/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +~ Copyright 2014 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>ONOS APP MFWD</display-name> + + <servlet> + <servlet-name>JAX-RS Service</servlet-name> + <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> + <init-param> + <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name> + <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value> + </init-param> + <init-param> + <param-name>com.sun.jersey.config.property.classnames</param-name> + <param-value> + org.onosproject.mfwd.rest.McastResource + </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> |