Julian Lawrence
Committed by Gerrit Code Review

Refactored Mfwd to use new mcastroutemanager

Change-Id: I7aca7f118221ed505aeb7fcace0ef9dccb468a34
......@@ -22,7 +22,7 @@
<parent>
<groupId>org.onosproject</groupId>
<artifactId>onos-apps</artifactId>
<version>1.5.0-SNAPSHOT</version>
<version>1.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
......
......@@ -15,10 +15,15 @@
*/
package org.onosproject.mfwd.cli;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
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;
import org.onosproject.mfwd.impl.McastForwarding;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.mcast.McastRoute;
import org.onosproject.net.mcast.MulticastRouteService;
/**
* Deletes a multicast route.
......@@ -27,6 +32,9 @@ import org.onosproject.mfwd.impl.McastRouteTable;
description = "Delete a multicast route flow")
public class McastDeleteCommand extends AbstractShellCommand {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
MulticastRouteService mcastRouteManager = AbstractShellCommand.get(MulticastRouteService.class);
@Argument(index = 0, name = "sAddr",
description = "IP Address of the multicast source. '*' can be used for any source (*, G) entry",
required = true, multiValued = false)
......@@ -46,23 +54,16 @@ public class McastDeleteCommand extends AbstractShellCommand {
@Override
protected void execute() {
boolean deleted = false;
McastRouteTable mrib = McastRouteTable.getInstance();
McastRoute mRoute = McastForwarding.createStaticRoute(sAddr, gAddr);
if (egressList == null) {
mrib.removeRoute(sAddr, gAddr);
deleted = true;
mcastRouteManager.remove(mRoute);
} else {
// check list for validity before we begin to delete.
for (String egress : egressList) {
deleted = mrib.removeEgress(sAddr, gAddr, egress);
ConnectPoint eCp = ConnectPoint.deviceConnectPoint(egress);
mcastRouteManager.removeSink(mRoute, eCp);
}
}
if (deleted) {
print("Successful delete");
} else {
print("Failed to delete");
}
}
}
......
......@@ -15,13 +15,15 @@
*/
package org.onosproject.mfwd.cli;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
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;
import org.onosproject.mfwd.impl.McastForwarding;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.mcast.McastRoute;
import org.onosproject.net.mcast.MulticastRouteService;
/**
* Installs a source, multicast group flow.
......@@ -30,6 +32,9 @@ import org.onosproject.mfwd.impl.McastRouteTable;
description = "Installs a source, multicast group flow")
public class McastJoinCommand extends AbstractShellCommand {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
MulticastRouteService mcastRouteManager = AbstractShellCommand.get(MulticastRouteService.class);
@Argument(index = 0, name = "sAddr",
description = "IP Address of the multicast source. '*' can be used for any source (*, G) entry",
required = true, multiValued = false)
......@@ -41,31 +46,29 @@ public class McastJoinCommand extends AbstractShellCommand {
String gAddr = null;
@Argument(index = 2, name = "ingressPort",
description = "Ingress port and Egress ports",
description = "Ingress port of:XXXXXXXXXX/XX",
required = false, multiValued = false)
String ingressPort = null;
@Argument(index = 3, name = "ports",
description = "Ingress port and Egress ports",
description = "Egress ports of:XXXXXXXXXX/XX...",
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);
}
McastRoute mRoute = McastForwarding.createStaticRoute(sAddr, gAddr);
mcastRouteManager.add(mRoute);
for (int i = 0; i < ports.length; i++) {
String egCP = ports[i];
ConnectPoint ingress = ConnectPoint.deviceConnectPoint(ingressPort);
mcastRouteManager.addSource(mRoute, ingress);
for (String egCP : ports) {
log.debug("Egress port provided: " + egCP);
mr.addEgressPoint(egCP, McastConnectPoint.JoinSource.STATIC);
ConnectPoint egress = ConnectPoint.deviceConnectPoint(egCP);
mcastRouteManager.addSink(mRoute, egress);
}
print("Added the mcast route");
}
......
......@@ -15,15 +15,13 @@
*/
package org.onosproject.mfwd.cli;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
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.onosproject.net.mcast.MulticastRouteService;
import org.slf4j.Logger;
import static org.slf4j.LoggerFactory.getLogger;
......@@ -33,30 +31,15 @@ import static org.slf4j.LoggerFactory.getLogger;
@Command(scope = "onos", name = "mcast-show", description = "Displays the source, multicast group flows")
public class McastShowCommand extends AbstractShellCommand {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
MulticastRouteService mcastRouteManager = AbstractShellCommand.get(MulticastRouteService.class);
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);
}
//TODO
}
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());
}
}
......
/*
* 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;
}
}
/*
* 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;
}
}
......@@ -15,6 +15,7 @@
*/
package org.onosproject.mfwd.impl;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
import org.apache.felix.scr.annotations.Activate;
......@@ -35,6 +36,8 @@ 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.mcast.MulticastRouteService;
import org.onosproject.net.mcast.McastRoute;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
......@@ -44,8 +47,12 @@ import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.slf4j.Logger;
import java.util.ArrayList;
/**
* WORK-IN-PROGRESS: The multicast forwarding application using intent framework.
* The multicast forwarding component. This component is responsible for
* handling live multicast traffic by modifying multicast state and forwarding
* packets that do not yet have state installed.
*/
@Component(immediate = true)
public class McastForwarding {
......@@ -59,8 +66,12 @@ public class McastForwarding {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MulticastRouteService mcastRouteManager;
private ReactivePacketProcessor processor = new ReactivePacketProcessor();
private McastRouteTable mrib;
private static ApplicationId appId;
/**
......@@ -76,9 +87,9 @@ public class McastForwarding {
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");
}
......@@ -137,8 +148,8 @@ public class McastForwarding {
}
IPv4 ip = (IPv4) ethPkt.getPayload();
IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
log.debug("Packet ({}, {}) has been punted\n" +
"\tingress port: {}\n",
......@@ -146,70 +157,37 @@ public class McastForwarding {
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
// Don't allow PIM/IGMP packets to be handled here.
byte proto = ip.getProtocol();
if (proto == IPv4.PROTOCOL_PIM || proto == IPv4.PROTOCOL_IGMP) {
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().address().isZero()) {
/*
* Create an entry that we can fast drop.
*/
entry = mrib.addRoute(spfx, gpfx);
entry.addIngressPoint(context.inPacket().receivedFrom());
}
// TODO do we want to add a type for Mcast?
McastRoute mRoute = new McastRoute(spfx, gpfx, McastRoute.Type.STATIC);
/*
* 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;
}
ConnectPoint ingress = mcastRouteManager.fetchSource(mRoute);
if (entry.getEgressPoints().isEmpty()) {
// An ingress port already exists. Log error.
if (ingress != null) {
log.error(McastForwarding.class.getSimpleName() + " received packet which already has a route.");
return;
} else {
//add ingress port
mcastRouteManager.addSource(mRoute, pkt.receivedFrom());
}
/*
* 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) {
ArrayList<ConnectPoint> egressList = (ArrayList<ConnectPoint>) mcastRouteManager.fetchSinks(mRoute);
//If there are no egress ports set return, otherwise forward the packets to their expected port.
if (egressList.size() == 0) {
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);
forwardPacketToDst(context, egressList);
}
}
......@@ -217,12 +195,12 @@ public class McastForwarding {
* Forward the packet to it's multicast destinations.
*
* @param context The packet context
* @param entry The multicast route entry matching this packet
* @param egressList The list of egress ports which the multicast packet is intended for.
*/
private void forwardPacketToDst(PacketContext context, McastRoute entry) {
private void forwardPacketToDst(PacketContext context, ArrayList<ConnectPoint> egressList) {
// Send the pack out each of the respective egress ports
for (ConnectPoint egress : entry.getEgressConnectPoints()) {
for (ConnectPoint egress : egressList) {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(egress.port()).build();
......@@ -234,4 +212,19 @@ public class McastForwarding {
packetService.emit(packet);
}
}
public static McastRoute createStaticRoute(String source, String group) {
checkNotNull(source, "Must provide a source");
checkNotNull(group, "Must provide a group");
IpPrefix ipSource = IpPrefix.valueOf(source);
IpPrefix ipGroup = IpPrefix.valueOf(group);
return createStaticcreateRoute(ipSource, ipGroup);
}
public static McastRoute createStaticcreateRoute(IpPrefix source, IpPrefix group) {
checkNotNull(source, "Must provide a source");
checkNotNull(group, "Must provide a group");
McastRoute.Type type = McastRoute.Type.STATIC;
return new McastRoute(source, group, type);
}
}
......
/*
* 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) {
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.Builder builder = SinglePointToMultiPointIntent.builder()
.appId(McastForwarding.getAppId())
.selector(selector.build())
.treatment(treatment)
.ingressPoint(mroute.getIngressPoint().getConnectPoint());
// allowing intent to be pushed without egress points means we can drop packets.
if (!mroute.getEgressPoints().isEmpty()) {
builder.egressPoints(mroute.getEgressConnectPoints());
}
SinglePointToMultiPointIntent intent = builder.build();
intentService.submit(intent);
mroute.setDirty(false);
return intent;
}
/**
* Withdraw the intent represented by this route.
*
* @param mroute the mcast route whose intent we want to remove
*/
public void withdrawIntent(McastRoute mroute) {
Intent intent = intentService.getIntent(mroute.getIntentKey());
intentService.withdraw(intent);
mroute.setDirty(false);
}
/**
* 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);
}
}
}
/*
* 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();
/**
* Get the dirty state.
*
* @return whether this route is dirty or not.
*/
public boolean getDirty();
/**
* 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);
/**
* 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
/*
* 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());
}
}
}
/*
* 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
/*
* 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();
}
}
/*
* 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.
*/
/**
* REST API for multicase forwarding.
*/
package org.onosproject.mfwd.rest;