sangho
Committed by Gerrit Code Review

ONOS-688 (ONOS-1835,1836,1837) :

 - Implements features to create and remove tunnels and tunnel flow policies.
 - Implements REST API to create/show/delete tunnels and policies.
 - Supports only single instance for now.
 - Fix "apply" actions to "write" actions of all flow rules
Change-Id: I3740ed82fed8eab4ab8b03839192da72d3e223f1
Showing 20 changed files with 1539 additions and 17 deletions
......@@ -32,6 +32,96 @@
<properties>
<onos.app.name>org.onosproject.segmentrouting</onos.app.name>
<web.context>/onos/segmentrouting</web.context>
</properties>
<dependencies>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-cli</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.console</artifactId>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-rest</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onlab-rest</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</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.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<_wab>src/main/webapp/</_wab>
<Bundle-SymbolicName>
${project.groupId}.${project.artifactId}
</Bundle-SymbolicName>
<Import-Package>
org.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,
com.fasterxml.jackson.core,
org.apache.karaf.shell.commands,
org.apache.commons.lang.math.*,
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>
......
/*
* 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.segmentrouting;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.segmentrouting.grouphandler.NeighborSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Tunnel class.
*/
public class DefaultTunnel implements Tunnel {
private static final Logger log = LoggerFactory
.getLogger(DefaultTunnel.class);
private final String tunnelId;
private final List<Integer> labelIds;
private final SegmentRoutingManager srManager;
private final DeviceConfiguration config;
private int groupId;
/**
* Creates a Tunnel reference.
*
* @param srm SegmentRoutingManager object
* @param tid Tunnel ID
* @param labelIds Label stack of the tunnel
*/
public DefaultTunnel(SegmentRoutingManager srm, String tid,
List<Integer> labelIds) {
this.srManager = checkNotNull(srm);
this.tunnelId = checkNotNull(tid);
this.labelIds = Collections.unmodifiableList(labelIds);
this.config = srManager.deviceConfiguration;
this.groupId = -1;
}
/**
* Creates a Tunnel reference.
*
* @param tid Tunnel ID
* @param labelIds Label stack of the tunnel
*/
public DefaultTunnel(String tid, List<Integer> labelIds) {
this.srManager = null;
this.tunnelId = checkNotNull(tid);
this.labelIds = Collections.unmodifiableList(labelIds);
this.config = null;
this.groupId = -1;
}
/**
* Creates a new DefaultTunnel reference using the tunnel reference.
*
* @param tunnel DefaultTunnel reference
*/
public DefaultTunnel(DefaultTunnel tunnel) {
this.srManager = tunnel.srManager;
this.tunnelId = tunnel.tunnelId;
this.labelIds = tunnel.labelIds;
this.config = tunnel.config;
this.groupId = tunnel.groupId;
}
@Override
public String id() {
return this.tunnelId;
}
@Override
public List<Integer> labelIds() {
return this.labelIds;
}
@Override
public boolean create() {
if (labelIds.isEmpty() || labelIds.size() < 3) {
log.error("More than one router needs to specified to created a tunnel");
return false;
}
groupId = createGroupsForTunnel();
if (groupId < 0) {
log.error("Failed to create groups for the tunnel");
return false;
}
return true;
}
@Override
public boolean remove() {
DeviceId deviceId = config.getDeviceId(labelIds.get(0));
srManager.removeNextObjective(deviceId, groupId);
return true;
}
@Override
public int groupId() {
return this.groupId;
}
@Override
public DeviceId source() {
return config.getDeviceId(labelIds.get(0));
}
private int createGroupsForTunnel() {
List<Integer> portNumbers;
int groupId;
DeviceId deviceId = config.getDeviceId(labelIds.get(0));
if (deviceId == null) {
log.warn("No device found for SID {}", labelIds.get(0));
return -1;
}
Set<DeviceId> deviceIds = new HashSet<>();
int sid = labelIds.get(1);
if (config.isAdjacencySid(deviceId, sid)) {
portNumbers = config.getPortsForAdjacencySid(deviceId, sid);
for (Link link: srManager.linkService.getDeviceEgressLinks(deviceId)) {
for (Integer port: portNumbers) {
if (link.src().port().toLong() == port) {
deviceIds.add(link.dst().deviceId());
}
}
}
} else {
deviceIds.add(config.getDeviceId(sid));
}
NeighborSet ns = new NeighborSet(deviceIds, labelIds.get(2));
groupId = srManager.getNextObjectiveId(deviceId, ns);
return groupId;
}
}
package org.onosproject.segmentrouting;
import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpPrefix;
......@@ -44,6 +45,7 @@ public class DeviceConfiguration implements DeviceProperties {
boolean isEdge;
HashMap<PortNumber, Ip4Address> gatewayIps;
HashMap<PortNumber, Ip4Prefix> subnets;
List<SegmentRouterConfig.AdjacencySid> adjacencySids;
}
/**
......@@ -80,8 +82,10 @@ public class DeviceConfiguration implements DeviceProperties {
info.gatewayIps.put(PortNumber.portNumber(s.getPortNo()),
Ip4Address.valueOf(gatewayIp));
}
info.adjacencySids = ((SegmentRouterConfig) cfg).getAdjacencySids();
this.deviceConfigMap.put(info.deviceId, info);
this.allSegmentIds.add(info.nodeSid);
}
}
......@@ -352,4 +356,49 @@ public class DeviceConfiguration implements DeviceProperties {
return false;
}
/**
* Returns the ports corresponding to the adjacency Sid given.
*
* @param deviceId device identification of the router
* @param sid adjacency Sid
* @return list of port numbers
*/
public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
if (deviceConfigMap.get(deviceId) != null) {
for (SegmentRouterConfig.AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) {
if (asid.getAdjSid() == sid) {
return asid.getPorts();
}
}
}
return Lists.newArrayList();
}
/**
* Check if the Sid given is whether adjacency Sid of the router device or not.
*
* @param deviceId device identification of the router
* @param sid Sid to check
* @return true if the Sid given is the adjacency Sid of the device,
* otherwise false
*/
public boolean isAdjacencySid(DeviceId deviceId, int sid) {
if (deviceConfigMap.get(deviceId) != null) {
if (deviceConfigMap.get(deviceId).adjacencySids.isEmpty()) {
return false;
} else {
for (SegmentRouterConfig.AdjacencySid asid:
deviceConfigMap.get(deviceId).adjacencySids) {
if (asid.getAdjSid() == sid) {
return true;
}
}
return false;
}
}
return false;
}
}
......
/*
* 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.segmentrouting;
import org.onosproject.net.flow.TrafficSelector;
/**
* Interface for Segment Routing Policy.
*/
public interface Policy {
/**
* Enums for policy type.
*/
enum Type {
// Tunnel flow policy type
TUNNEL_FLOW,
// Load balancing policy type
LOADBALANCE,
// policy to avoid specific routers or links
AVOID,
// Access Control policy type
DENY
}
/**
* Returns the policy ID.
*
* @return policy ID
*/
String id();
/**
* Returns the traffic selector object.
*
* @return TrafficSelector object
*/
TrafficSelector selector();
/**
* Returns the priority of the policy.
*
* @return priority
*/
int priority();
/**
* Returns the policy type.
*
* @return policy type
*/
Type type();
/**
* Creates a policy.
*
* @return true if succeeds, false otherwise
*/
boolean create();
/**
* Removes the policy.
*
* @return true if succeeds, false otherwise
*/
boolean remove();
}
/*
* 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.segmentrouting;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Segment Routing Policy Handler.
*/
public class PolicyHandler {
protected final Logger log = getLogger(getClass());
private final HashMap<String, Policy> policyMap;
/**
* Creates a reference.
*/
public PolicyHandler() {
policyMap = new HashMap<>();
}
/**
* Returns the policies.
*
* @return policy list
*/
public List<Policy> getPolicies() {
List<Policy> policies = new ArrayList<>();
policyMap.values().forEach(policy -> policies.add(
new TunnelPolicy((TunnelPolicy) policy)));
return policies;
}
/**
* Creates a policy using the policy information given.
*
* @param policy policy reference to create
*/
public void createPolicy(Policy policy) {
policy.create();
policyMap.put(policy.id(), policy);
}
/**
* Removes the policy given.
*
* @param policyInfo policy information to remove
*/
public void removePolicy(Policy policyInfo) {
if (policyMap.get(policyInfo.id()) != null) {
if (policyMap.get(policyInfo.id()).remove()) {
policyMap.remove(policyInfo.id());
} else {
log.error("Failed to remove the policy {}", policyInfo.id());
}
} else {
log.warn("Policy {} was not found", policyInfo.id());
}
}
}
......@@ -98,7 +98,8 @@ public class RoutingRulePopulator {
sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 32));
sbuilder.matchEthType(Ethernet.TYPE_IPV4);
tbuilder.setEthDst(hostMac)
tbuilder.deferred()
.setEthDst(hostMac)
.setEthSrc(config.getDeviceMac(deviceId))
.setOutput(outPort);
......@@ -163,10 +164,10 @@ public class RoutingRulePopulator {
// If the next hop is the same as the final destination, then MPLS label
// is not set.
if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
tbuilder.decNwTtl();
tbuilder.deferred().decNwTtl();
ns = new NeighborSet(nextHops);
} else {
tbuilder.copyTtlOut();
tbuilder.deferred().copyTtlOut();
ns = new NeighborSet(nextHops, config.getSegmentId(destSw));
}
......@@ -295,15 +296,15 @@ public class RoutingRulePopulator {
if (phpRequired) {
log.debug("getMplsForwardingObjective: php required");
tbuilder.copyTtlIn();
tbuilder.deferred().copyTtlIn();
if (isBos) {
tbuilder.popMpls(Ethernet.TYPE_IPV4).decNwTtl();
tbuilder.deferred().popMpls(Ethernet.TYPE_IPV4).decNwTtl();
} else {
tbuilder.popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
tbuilder.deferred().popMpls(Ethernet.MPLS_UNICAST).decMplsTtl();
}
} else {
log.debug("getMplsForwardingObjective: php not required");
tbuilder.decMplsTtl();
tbuilder.deferred().decMplsTtl();
}
if (!isECMPSupportedInTransitRouter() && !config.isEdgeDevice(deviceId)) {
......@@ -313,7 +314,8 @@ public class RoutingRulePopulator {
log.warn("No link from {} to {}", deviceId, nextHops);
return null;
}
tbuilder.setEthSrc(config.getDeviceMac(deviceId))
tbuilder.deferred()
.setEthSrc(config.getDeviceMac(deviceId))
.setEthDst(config.getDeviceMac(nextHop))
.setOutput(port);
fwdBuilder.withTreatment(tbuilder.build());
......
......@@ -20,6 +20,7 @@ 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.apache.felix.scr.annotations.Service;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.util.KryoNamespace;
......@@ -60,6 +61,7 @@ import org.slf4j.LoggerFactory;
import java.net.URI;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
......@@ -69,8 +71,9 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("ALL")
@Service
@Component(immediate = true)
public class SegmentRoutingManager {
public class SegmentRoutingManager implements SegmentRoutingService {
private static Logger log = LoggerFactory
.getLogger(SegmentRoutingManager.class);
......@@ -101,6 +104,7 @@ public class SegmentRoutingManager {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MastershipService mastershipService;
protected ArpHandler arpHandler = null;
protected IcmpHandler icmpHandler = null;
protected IpHandler ipHandler = null;
......@@ -108,7 +112,10 @@ public class SegmentRoutingManager {
protected ApplicationId appId;
protected DeviceConfiguration deviceConfiguration = null;
private DefaultRoutingHandler defaultRoutingHandler = null;
private TunnelHandler tunnelHandler = null;
private PolicyHandler policyHandler = null;
private InternalPacketProcessor processor = new InternalPacketProcessor();
private InternalEventHandler eventHandler = new InternalEventHandler();
......@@ -165,6 +172,8 @@ public class SegmentRoutingManager {
ipHandler = new IpHandler(this);
routingRulePopulator = new RoutingRulePopulator(this);
defaultRoutingHandler = new DefaultRoutingHandler(this);
tunnelHandler = new TunnelHandler();
policyHandler = new PolicyHandler();
packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
linkService.addListener(new InternalLinkListener());
......@@ -187,6 +196,7 @@ public class SegmentRoutingManager {
defaultRoutingHandler.startPopulationProcess();
log.info("Started");
}
@Deactivate
......@@ -196,6 +206,51 @@ public class SegmentRoutingManager {
log.info("Stopped");
}
@Override
public List<Tunnel> getTunnels() {
return tunnelHandler.getTunnels();
}
@Override
public void createTunnel(Tunnel tunnel) {
tunnelHandler.createTunnel(tunnel);
}
@Override
public void removeTunnel(Tunnel tunnel) {
for (Policy policy: policyHandler.getPolicies()) {
if (policy.type() == Policy.Type.TUNNEL_FLOW) {
TunnelPolicy tunnelPolicy = (TunnelPolicy) policy;
if (tunnelPolicy.tunnelId().equals(tunnel.id())) {
log.warn("Cannot remove the tunnel used by a policy");
return;
}
}
}
tunnelHandler.removeTunnel(tunnel);
}
@Override
public void removePolicy(Policy policy) {
policyHandler.removePolicy(policy);
}
@Override
public void createPolicy(Policy policy) {
policyHandler.createPolicy(policy);
}
@Override
public List<Policy> getPolicies() {
return policyHandler.getPolicies();
}
public Tunnel getTunnel(String tunnelId) {
return tunnelHandler.getTunnel(tunnelId);
}
/**
* Returns the GrouopKey object for the device and the NighborSet given.
*
......@@ -211,6 +266,12 @@ public class SegmentRoutingManager {
return null;
}
/**
*
* @param deviceId
* @param ns
* @return
*/
public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) {
if (groupHandlerMap.get(deviceId) != null) {
......@@ -223,6 +284,16 @@ public class SegmentRoutingManager {
}
}
/**
*
* @param deviceId
* @param objectiveId
* @return
*/
public boolean removeNextObjective(DeviceId deviceId, int objectiveId) {
return groupHandlerMap.get(deviceId).removeGroup(objectiveId);
}
private class InternalPacketProcessor implements PacketProcessor {
@Override
......@@ -403,4 +474,7 @@ public class SegmentRoutingManager {
groupHandler.portDown(port.number());
}
}
}
......
/*
* 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.segmentrouting;
import java.util.List;
/**
* Segment Routing Service for REST API.
*/
public interface SegmentRoutingService {
/**
* Returns all tunnels.
*
* @return list of tunnels
*/
List<Tunnel> getTunnels();
/**
* Creates a tunnel.
*
* @param tunnel tunnel reference to create
*/
void createTunnel(Tunnel tunnel);
/**
* Returns all policies.
*
* @return list of policy
*/
List<Policy> getPolicies();
/**
* Creates a policy.
*
* @param policy policy reference to create
*/
void createPolicy(Policy policy);
/**
* Removes a tunnel.
*
* @param tunnel tunnel reference to remove
*/
void removeTunnel(Tunnel tunnel);
/**
* Removes a policy.
*
* @param policy policy reference to remove
*/
void removePolicy(Policy policy);
}
/*
* 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.segmentrouting;
import org.onosproject.net.DeviceId;
import java.util.List;
/**
* Tunnel interface.
*/
public interface Tunnel {
/**
* Returns the tunnel ID.
*
* @return tunnel ID
*/
String id();
/**
* Returns Segment IDs for the tunnel including source and destination.
*
* @return List of Node ID
*/
List<Integer> labelIds();
/**
* Creates a tunnel.
*
* @return true if succeeds, false otherwise
*/
boolean create();
/**
* Removes the tunnel.
*
* @return true if succeeds, false otherwise.
*/
boolean remove();
/**
* Returns the group ID for the tunnel.
*
* @return group ID
*/
int groupId();
/**
* Returns the source device Id of the tunnel.
*
* @return source device Id
*/
DeviceId source();
}
/*
* 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.segmentrouting;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Tunnel Handler.
*/
public class TunnelHandler {
protected final Logger log = getLogger(getClass());
private final HashMap<String, Tunnel> tunnelMap;
public TunnelHandler() {
tunnelMap = new HashMap<>();
}
/**
* Creates a tunnel.
*
* @param tunnel tunnel reference to create a tunnel
*/
public void createTunnel(Tunnel tunnel) {
tunnel.create();
tunnelMap.put(tunnel.id(), tunnel);
}
/**
* Removes the tunnel with the tunnel ID given.
*
* @param tunnelInfo tunnel information to delete tunnels
*/
public void removeTunnel(Tunnel tunnelInfo) {
Tunnel tunnel = tunnelMap.get(tunnelInfo.id());
if (tunnel != null) {
tunnel.remove();
tunnelMap.remove(tunnel.id());
} else {
log.warn("No tunnel found for tunnel ID {}", tunnelInfo.id());
}
}
/**
* Returns the tunnel with the tunnel ID given.
*
* @param tid Tunnel ID
* @return Tunnel reference
*/
public Tunnel getTunnel(String tid) {
return tunnelMap.get(tid);
}
/**
* Returns all tunnels.
*
* @return list of Tunnels
*/
public List<Tunnel> getTunnels() {
List<Tunnel> tunnels = new ArrayList<>();
tunnelMap.values().forEach(tunnel -> tunnels.add(
new DefaultTunnel((DefaultTunnel) tunnel)));
return tunnels;
}
}
/*
* 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.segmentrouting;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Tunnel Policy.
*/
public final class TunnelPolicy implements Policy {
private final SegmentRoutingManager srManager;
private final Type type;
private final String id;
private final TrafficSelector selector;
private final int priority;
private final String tunnelId;
private TunnelPolicy(SegmentRoutingManager srm, String policyId, Type type,
TrafficSelector selector, int priority, String tunnelId) {
this.srManager = srm;
this.id = checkNotNull(policyId);
this.type = type;
this.tunnelId = tunnelId;
this.priority = priority;
this.selector = selector;
}
/**
* Creates a TunnelPolicy reference.
*
* @param p TunnelPolicy reference
*/
public TunnelPolicy(TunnelPolicy p) {
this.srManager = p.srManager;
this.id = p.id;
this.type = p.type;
this.tunnelId = p.tunnelId;
this.priority = p.priority;
this.selector = p.selector;
}
/**
* Creates a TunnelPolicy reference.
*
* @param p TunnelPolicy reference
*/
public TunnelPolicy(SegmentRoutingManager srm, TunnelPolicy p) {
this.srManager = srm;
this.id = p.id;
this.type = p.type;
this.tunnelId = p.tunnelId;
this.priority = p.priority;
this.selector = p.selector;
}
/**
* Returns the TunnelPolicy builder reference.
*
* @return TunnelPolicy builder
*/
public static TunnelPolicy.Builder builder() {
return new Builder();
}
@Override
public String id() {
return this.id;
}
@Override
public TrafficSelector selector() {
return selector;
}
@Override
public int priority() {
return priority;
}
@Override
public Type type() {
return type;
}
@Override
public boolean create() {
Tunnel tunnel = srManager.getTunnel(tunnelId);
ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
.builder()
.fromApp(srManager.appId)
.makePermanent()
.nextStep(tunnel.groupId())
.withPriority(priority)
.withSelector(selector)
.withFlag(ForwardingObjective.Flag.VERSATILE);
srManager.flowObjectiveService.forward(tunnel.source(), fwdBuilder.add());
return true;
}
@Override
public boolean remove() {
Tunnel tunnel = srManager.getTunnel(tunnelId);
ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
.builder()
.fromApp(srManager.appId)
.makePermanent()
.withSelector(selector)
.withPriority(priority)
.nextStep(tunnel.groupId())
.withFlag(ForwardingObjective.Flag.VERSATILE);
srManager.flowObjectiveService.forward(tunnel.source(), fwdBuilder.remove());
return true;
}
/**
* Returns the tunnel ID of the policy.
*
* @return Tunnel ID
*/
public String tunnelId() {
return this.tunnelId;
}
/**
* Tunnel Policy Builder.
*/
public static final class Builder {
private SegmentRoutingManager srManager;
private String id;
private Type type;
private TrafficSelector selector;
private int priority;
private String tunnelId;
/**
* Sets the policy Id.
*
* @param id policy Id
* @return Builder object
*/
public Builder setPolicyId(String id) {
this.id = id;
return this;
}
/**
* Sets the policy type.
*
* @param type policy type
* @return Builder object
*/
public Builder setType(Type type) {
this.type = type;
return this;
}
/**
* Sets the TrafficSelector.
*
* @param selector TrafficSelector
* @return Builder object
*/
public Builder setSelector(TrafficSelector selector) {
this.selector = selector;
return this;
}
/**
* Sets the priority of the policy.
*
* @param p priority
* @return Builder object
*/
public Builder setPriority(int p) {
this.priority = p;
return this;
}
/**
* Sets the tunnel Id.
*
* @param tunnelId tunnel Id
* @return Builder object
*/
public Builder setTunnelId(String tunnelId) {
this.tunnelId = tunnelId;
return this;
}
/**
* Sets the Segment Routing Manager reference.
*
* @param srm Segment Routing Manager reference
* @return Builder object
*/
public Builder setManager(SegmentRoutingManager srm) {
this.srManager = srm;
return this;
}
/**
* Builds the policy.
*
* @return Tunnel Policy reference
*/
public Policy build() {
return new TunnelPolicy(srManager, id, type, selector, priority, tunnelId);
}
}
}
......@@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
......@@ -418,7 +419,12 @@ public class DefaultGroupHandler {
return nsSegmentIds;
}
protected void createGroupsFromNeighborsets(Set<NeighborSet> nsSet) {
/**
* Creates Groups from a set of NeighborSet given.
*
* @param nsSet a set of NeighborSet
*/
public void createGroupsFromNeighborsets(Set<NeighborSet> nsSet) {
for (NeighborSet ns : nsSet) {
int nextId = flowObjectiveService.allocateNextId();
NextObjective.Builder nextObjBuilder = DefaultNextObjective
......@@ -462,4 +468,29 @@ public class DefaultGroupHandler {
return new DefaultGroupKey(kryo.build().serialize(obj));
}
/**
* Removes groups for the next objective ID given.
*
* @param objectiveId next objective ID to remove
* @return true if succeeds, false otherwise
*/
public boolean removeGroup(int objectiveId) {
if (nsNextObjStore.containsValue(objectiveId)) {
NextObjective.Builder nextObjBuilder = DefaultNextObjective
.builder().withId(objectiveId)
.withType(NextObjective.Type.HASHED).fromApp(appId);
NextObjective nextObjective = nextObjBuilder.remove();
flowObjectiveService.next(deviceId, nextObjective);
for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry: nsNextObjStore.entrySet()) {
if (entry.getValue().equals(objectiveId)) {
nsNextObjStore.remove(entry.getKey());
break;
}
}
}
return false;
}
}
......
/*
* 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.segmentrouting.web;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpPrefix;
import org.onosproject.cli.net.IpProtocol;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.criteria.IPProtocolCriterion;
import org.onosproject.segmentrouting.Policy;
import org.onosproject.segmentrouting.TunnelPolicy;
public final class PolicyCodec extends JsonCodec<Policy> {
// JSON field names
private static final String POLICY_ID = "policy_id";
private static final String PRIORITY = "priority";
private static final String TYPE = "policy_type";
private static final String TUNNEL_ID = "tunnel_id";
private static final String DST_IP = "dst_ip";
private static final String SRC_IP = "src_ip";
private static final String PROTO_TYPE = "proto_type";
@Override
public ObjectNode encode(Policy policy, CodecContext context) {
final ObjectNode result = context.mapper().createObjectNode()
.put(POLICY_ID, policy.id());
result.put(PRIORITY, policy.priority());
result.put(TYPE, policy.type().toString());
if (policy.selector().getCriterion(Criterion.Type.IPV4_DST) != null) {
IPCriterion criterion = (IPCriterion) policy.selector().getCriterion(
Criterion.Type.IPV4_DST);
result.put(DST_IP, criterion.ip().toString());
}
if (policy.selector().getCriterion(Criterion.Type.IPV4_SRC) != null) {
IPCriterion criterion = (IPCriterion) policy.selector().getCriterion(
Criterion.Type.IPV4_SRC);
result.put(SRC_IP, criterion.ip().toString());
}
if (policy.selector().getCriterion(Criterion.Type.IP_PROTO) != null) {
IPProtocolCriterion protocolCriterion =
(IPProtocolCriterion) policy.selector().getCriterion(Criterion.Type.IP_PROTO);
result.put(PROTO_TYPE, protocolCriterion.toString());
}
if (policy.type() == Policy.Type.TUNNEL_FLOW) {
result.put(TUNNEL_ID, ((TunnelPolicy) policy).tunnelId());
}
return result;
}
@Override
public Policy decode(ObjectNode json, CodecContext context) {
String pid = json.path(POLICY_ID).asText();
String type = json.path(TYPE).asText();
int priority = json.path(PRIORITY).asInt();
String dstIp = json.path(DST_IP).asText();
String srcIp = json.path(SRC_IP).asText();
String tunnelId = json.path(TUNNEL_ID).asText();
String protoType = json.path(PROTO_TYPE).asText();
if (tunnelId != null) {
TrafficSelector.Builder tsb = DefaultTrafficSelector.builder();
tsb.matchEthType(Ethernet.TYPE_IPV4);
if (dstIp != null && !dstIp.isEmpty()) {
tsb.matchIPDst(IpPrefix.valueOf(dstIp));
}
if (srcIp != null && !srcIp.isEmpty()) {
tsb.matchIPSrc(IpPrefix.valueOf(srcIp));
}
if (protoType != null && !protoType.isEmpty()) {
Short ipProto = Short.valueOf(IpProtocol.valueOf(protoType).value());
tsb.matchIPProtocol(ipProto.byteValue());
}
TunnelPolicy.Builder tpb = TunnelPolicy.builder().setPolicyId(pid);
if (tunnelId != null) {
tpb.setTunnelId(tunnelId);
}
if (!json.path(PRIORITY).isMissingNode()) {
tpb.setPriority(priority);
}
if (!json.path(TYPE).isMissingNode()) {
tpb.setType(Policy.Type.valueOf(type));
}
tpb.setSelector(tsb.build());
return tpb.build();
} else {
// TODO: handle more policy types
return null;
}
}
}
/*
* 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.segmentrouting.web;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.rest.AbstractWebResource;
import org.onosproject.segmentrouting.Policy;
import org.onosproject.segmentrouting.SegmentRoutingManager;
import org.onosproject.segmentrouting.SegmentRoutingService;
import org.onosproject.segmentrouting.TunnelPolicy;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@Path("policy")
public class PolicyWebResource extends AbstractWebResource {
private static final PolicyCodec POLICY_CODEC = new PolicyCodec();
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getPolicy() {
SegmentRoutingService srService = get(SegmentRoutingService.class);
List<Policy> policies = srService.getPolicies();
ObjectNode result = new ObjectMapper().createObjectNode();
result.set("policy", new PolicyCodec().encode(policies, this));
return ok(result.toString()).build();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createPolicy(InputStream input) throws IOException {
ObjectMapper mapper = new ObjectMapper();
ObjectNode policyJson = (ObjectNode) mapper.readTree(input);
SegmentRoutingService srService = get(SegmentRoutingService.class);
Policy policyInfo = POLICY_CODEC.decode(policyJson, this);
if (policyInfo.type() == Policy.Type.TUNNEL_FLOW) {
TunnelPolicy policy = new TunnelPolicy((SegmentRoutingManager) srService, (TunnelPolicy) policyInfo);
srService.createPolicy(policy);
return Response.ok().build();
} else {
return Response.serverError().build();
}
}
@DELETE
@Consumes(MediaType.APPLICATION_JSON)
public Response removePolicy(InputStream input) throws IOException {
ObjectMapper mapper = new ObjectMapper();
ObjectNode policyJson = (ObjectNode) mapper.readTree(input);
SegmentRoutingService srService = get(SegmentRoutingService.class);
Policy policyInfo = POLICY_CODEC.decode(policyJson, this);
// TODO: Check the result
srService.removePolicy(policyInfo);
return Response.ok().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.
*/
package org.onosproject.segmentrouting.web;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.segmentrouting.DefaultTunnel;
import org.onosproject.segmentrouting.Tunnel;
import java.util.ArrayList;
import java.util.List;
public final class TunnelCodec extends JsonCodec<Tunnel> {
// JSON field names
private static final String TUNNEL_ID = "tunnel_id";
private static final String GROUP_ID = "group_id";
private static final String LABEL_PATH = "label_path";
@Override
public ObjectNode encode(Tunnel tunnel, CodecContext context) {
final ObjectNode result = context.mapper().createObjectNode()
.put(TUNNEL_ID, tunnel.id());
result.put(GROUP_ID, tunnel.groupId());
final ArrayNode jsonLabelIds = result.putArray(LABEL_PATH);
tunnel.labelIds().forEach(label -> jsonLabelIds.add(label.intValue()));
return result;
}
@Override
public DefaultTunnel decode(ObjectNode json, CodecContext context) {
String tid = json.path(TUNNEL_ID).asText();
List<Integer> labels = new ArrayList<>();
if (!json.path(LABEL_PATH).isMissingNode()) {
ArrayNode labelArray = (ArrayNode) json.path(LABEL_PATH);
for (JsonNode o : labelArray) {
labels.add(o.asInt());
}
}
return new DefaultTunnel(tid, labels);
}
}
/*
* 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.segmentrouting.web;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.rest.AbstractWebResource;
import org.onosproject.segmentrouting.DefaultTunnel;
import org.onosproject.segmentrouting.SegmentRoutingManager;
import org.onosproject.segmentrouting.SegmentRoutingService;
import org.onosproject.segmentrouting.Tunnel;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@Path("tunnel")
public class TunnelWebResource extends AbstractWebResource {
private static final TunnelCodec TUNNEL_CODEC = new TunnelCodec();
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getTunnel() {
SegmentRoutingService srService = get(SegmentRoutingService.class);
List<Tunnel> tunnels = srService.getTunnels();
ObjectNode result = new ObjectMapper().createObjectNode();
result.set("tunnel", new TunnelCodec().encode(tunnels, this));
return ok(result.toString()).build();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createTunnel(InputStream input) throws IOException {
ObjectMapper mapper = new ObjectMapper();
ObjectNode tunnelJson = (ObjectNode) mapper.readTree(input);
SegmentRoutingService srService = get(SegmentRoutingService.class);
Tunnel tunnelInfo = TUNNEL_CODEC.decode(tunnelJson, this);
Tunnel tunnel = new DefaultTunnel((SegmentRoutingManager) srService,
tunnelInfo.id(), tunnelInfo.labelIds());
srService.createTunnel(tunnel);
return Response.ok().build();
}
@DELETE
@Consumes(MediaType.APPLICATION_JSON)
public Response removeTunnel(InputStream input) throws IOException {
ObjectMapper mapper = new ObjectMapper();
ObjectNode tunnelJson = (ObjectNode) mapper.readTree(input);
SegmentRoutingService srService = get(SegmentRoutingService.class);
Tunnel tunnelInfo = TUNNEL_CODEC.decode(tunnelJson, this);
srService.removeTunnel(tunnelInfo);
return Response.ok().build();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<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>Segment Routing REST API v1.0</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.segmentrouting.web.TunnelWebResource,
org.onosproject.segmentrouting.web.PolicyWebResource
</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>
......@@ -195,7 +195,6 @@ public final class DefaultNextObjective implements NextObjective {
checkNotNull(appId, "Must supply an application id");
checkNotNull(id, "id cannot be null");
checkNotNull(type, "The type cannot be null");
checkArgument(!treatments.isEmpty(), "Must have at least one treatment");
return new DefaultNextObjective(id, treatments, appId, type, Operation.REMOVE);
}
......
......@@ -49,6 +49,7 @@ import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.EthCriterion;
import org.onosproject.net.flow.criteria.EthTypeCriterion;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.criteria.IPProtocolCriterion;
import org.onosproject.net.flow.criteria.MplsCriterion;
import org.onosproject.net.flow.criteria.PortCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
......@@ -215,7 +216,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
public void next(NextObjective nextObjective) {
if (nextObjective.op() == Objective.Operation.REMOVE) {
if (nextObjective.next() == null) {
if (nextObjective.next().isEmpty()) {
removeGroup(nextObjective);
} else {
removeBucketFromGroup(nextObjective);
......@@ -369,10 +370,91 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
}
private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
fail(fwd, ObjectiveError.UNSUPPORTED);
log.debug("Processing versatile forwarding objective");
TrafficSelector selector = fwd.selector();
EthTypeCriterion ethType =
(EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
if (ethType == null) {
log.error("Versatile forwarding objective must include ethType");
fail(fwd, ObjectiveError.UNKNOWN);
return Collections.emptySet();
}
TrafficSelector.Builder filteredSelectorBuilder =
DefaultTrafficSelector.builder();
if (ethType.ethType() == Ethernet.TYPE_IPV4) {
IPCriterion ipSrc = (IPCriterion) selector
.getCriterion(Criterion.Type.IPV4_SRC);
IPCriterion ipDst = (IPCriterion) selector
.getCriterion(Criterion.Type.IPV4_DST);
IPProtocolCriterion ipProto = (IPProtocolCriterion) selector
.getCriterion(Criterion.Type.IP_PROTO);
filteredSelectorBuilder
.matchEthType(Ethernet.TYPE_IPV4);
if (ipSrc != null) {
filteredSelectorBuilder.matchIPSrc(ipSrc.ip());
}
if (ipDst != null) {
filteredSelectorBuilder.matchIPDst(ipDst.ip());
}
if (ipProto != null) {
filteredSelectorBuilder.matchIPProtocol(
Short.valueOf(ipProto.protocol()).byteValue());
}
log.debug("processing IPv4 specific forwarding objective");
} else {
log.warn("VERSATILE forwarding objective does not support {} yet.",
ethType.ethType());
return Collections.emptySet();
}
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
.builder();
treatmentBuilder.wipeDeferred();
if (fwd.nextId() != null) {
NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
if (next != null) {
GroupKey key = appKryo.deserialize(next.data());
Group group = groupService.getGroup(deviceId, key);
if (group == null) {
log.warn("The group left!");
fail(fwd, ObjectiveError.GROUPMISSING);
return Collections.emptySet();
}
treatmentBuilder.deferred().group(group.id());
log.debug("Adding OUTGROUP action");
}
} else {
log.warn("VERSATILE forwarding objective need next objective ID.");
return Collections.emptySet();
}
TrafficSelector filteredSelector = filteredSelectorBuilder.build();
TrafficTreatment treatment = treatmentBuilder.build();
FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
.fromApp(fwd.appId()).withPriority(fwd.priority())
.forDevice(deviceId).withSelector(filteredSelector)
.withTreatment(treatment);
if (fwd.permanent()) {
ruleBuilder.makePermanent();
} else {
ruleBuilder.makeTemporary(fwd.timeout());
}
ruleBuilder.forTable(aclTableId);
return Collections.singletonList(ruleBuilder.build());
}
protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
log.debug("Processing specific");
TrafficSelector selector = fwd.selector();
......@@ -434,7 +516,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
fail(fwd, ObjectiveError.GROUPMISSING);
return Collections.emptySet();
}
treatmentBuilder.group(group.id());
treatmentBuilder.deferred().group(group.id());
log.debug("Adding OUTGROUP action");
} else {
log.warn("processSpecific: No associated next objective object");
......
......@@ -104,12 +104,12 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
List<OFInstruction> instructions = Lists.newLinkedList();
if (immediateActions.size() > 0) {
instructions.add(factory().instructions().applyActions(immediateActions));
}
if (treatment.clearedDeferred()) {
instructions.add(factory().instructions().clearActions());
}
if (immediateActions.size() > 0) {
instructions.add(factory().instructions().applyActions(immediateActions));
}
if (deferredActions.size() > 0) {
instructions.add(factory().instructions().writeActions(deferredActions));
}
......