Murat Parlakisik
Committed by Gerrit Code Review

ONOS-4374 Enable installing flows with hard_timeout

Change-Id: I4e60e93aad44c7e8f8913fa4dd3ed5a2565d7034
......@@ -46,6 +46,8 @@ public class DefaultFlowRule implements FlowRule {
private final int timeout;
private final boolean permanent;
private final int hardTimeout;
private final FlowRemoveReason reason;
private final GroupId groupId;
private final Integer tableId;
......@@ -60,6 +62,8 @@ public class DefaultFlowRule implements FlowRule {
this.groupId = rule.groupId();
this.id = rule.id();
this.timeout = rule.timeout();
this.hardTimeout = rule.hardTimeout();
this.reason = rule.reason();
this.permanent = rule.isPermanent();
this.created = System.currentTimeMillis();
this.tableId = rule.tableId();
......@@ -68,8 +72,8 @@ public class DefaultFlowRule implements FlowRule {
private DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
TrafficTreatment treatment, Integer priority,
FlowId flowId, Boolean permanent, Integer timeout,
Integer tableId) {
FlowId flowId, Boolean permanent, Integer timeout, Integer hardTimeout,
FlowRemoveReason reason, Integer tableId) {
this.deviceId = deviceId;
this.selector = selector;
......@@ -79,6 +83,8 @@ public class DefaultFlowRule implements FlowRule {
this.id = flowId;
this.permanent = permanent;
this.timeout = timeout;
this.hardTimeout = hardTimeout;
this.reason = reason;
this.tableId = tableId;
this.created = System.currentTimeMillis();
......@@ -88,6 +94,8 @@ public class DefaultFlowRule implements FlowRule {
this.payLoad = null;
}
/**
* Support for the third party flow rule. Creates a flow rule of flow table.
*
......@@ -105,6 +113,28 @@ public class DefaultFlowRule implements FlowRule {
TrafficTreatment treatment, int priority,
ApplicationId appId, int timeout, boolean permanent,
FlowRuleExtPayLoad payLoad) {
this(deviceId, selector, treatment, priority, appId, timeout, 0, permanent, payLoad);
}
/**
* Support for the third party flow rule. Creates a flow rule of flow table.
*
* @param deviceId the identity of the device where this rule applies
* @param selector the traffic selector that identifies what traffic this
* rule
* @param treatment the traffic treatment that applies to selected traffic
* @param priority the flow rule priority given in natural order
* @param appId the application id of this flow
* @param timeout the timeout for this flow requested by an application
* @param hardTimeout the hard timeout located switch's flow table for this flow requested by an application
* @param permanent whether the flow is permanent i.e. does not time out
* @param payLoad 3rd-party origin private flow
*/
public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
TrafficTreatment treatment, int priority,
ApplicationId appId, int timeout, int hardTimeout, boolean permanent,
FlowRuleExtPayLoad payLoad) {
checkArgument(priority >= MIN_PRIORITY, "Priority cannot be less than " +
MIN_PRIORITY);
......@@ -118,6 +148,8 @@ public class DefaultFlowRule implements FlowRule {
this.appId = appId.id();
this.groupId = new DefaultGroupId(0);
this.timeout = timeout;
this.reason = FlowRemoveReason.NO_REASON;
this.hardTimeout = hardTimeout;
this.permanent = permanent;
this.tableId = 0;
this.created = System.currentTimeMillis();
......@@ -152,6 +184,30 @@ public class DefaultFlowRule implements FlowRule {
TrafficTreatment treatment, int priority,
ApplicationId appId, GroupId groupId, int timeout,
boolean permanent, FlowRuleExtPayLoad payLoad) {
this(deviceId, selector, treatment, priority, appId, groupId, timeout, 0, permanent, payLoad);
}
/**
* Support for the third party flow rule. Creates a flow rule of group
* table.
*
* @param deviceId the identity of the device where this rule applies
* @param selector the traffic selector that identifies what traffic this
* rule
* @param treatment the traffic treatment that applies to selected traffic
* @param priority the flow rule priority given in natural order
* @param appId the application id of this flow
* @param groupId the group id of this flow
* @param timeout the timeout for this flow requested by an application
* @param hardTimeout the hard timeout located switch's flow table for this flow requested by an application
* @param permanent whether the flow is permanent i.e. does not time out
* @param payLoad 3rd-party origin private flow
*
*/
public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
TrafficTreatment treatment, int priority,
ApplicationId appId, GroupId groupId, int timeout, int hardTimeout,
boolean permanent, FlowRuleExtPayLoad payLoad) {
checkArgument(priority >= MIN_PRIORITY, "Priority cannot be less than " +
MIN_PRIORITY);
......@@ -165,6 +221,8 @@ public class DefaultFlowRule implements FlowRule {
this.appId = appId.id();
this.groupId = groupId;
this.timeout = timeout;
this.reason = FlowRemoveReason.NO_REASON;
this.hardTimeout = hardTimeout;
this.permanent = permanent;
this.created = System.currentTimeMillis();
this.tableId = 0;
......@@ -280,6 +338,18 @@ public class DefaultFlowRule implements FlowRule {
return timeout;
}
@Override
public int hardTimeout() {
return hardTimeout;
}
@Override
public FlowRemoveReason reason() {
return reason;
}
@Override
public boolean isPermanent() {
return permanent;
......@@ -310,6 +380,8 @@ public class DefaultFlowRule implements FlowRule {
private TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
private Integer timeout;
private Boolean permanent;
private Integer hardTimeout = 0;
private FlowRemoveReason reason = FlowRemoveReason.NO_REASON;
@Override
public FlowRule.Builder withCookie(long cookie) {
......@@ -368,6 +440,20 @@ public class DefaultFlowRule implements FlowRule {
}
@Override
public FlowRule.Builder withHardTimeout(int timeout) {
this.permanent = false;
this.hardTimeout = timeout;
this.timeout = timeout;
return this;
}
@Override
public FlowRule.Builder withReason(FlowRemoveReason reason) {
this.reason = reason;
return this;
}
@Override
public FlowRule build() {
FlowId localFlowId;
checkArgument((flowId != null) ^ (appId != null), "Either an application" +
......@@ -390,7 +476,7 @@ public class DefaultFlowRule implements FlowRule {
}
return new DefaultFlowRule(deviceId, selector, treatment, priority,
localFlowId, permanent, timeout, tableId);
localFlowId, permanent, timeout, hardTimeout, reason, tableId);
}
private FlowId computeFlowId(ApplicationId appId) {
......
......@@ -30,6 +30,28 @@ public interface FlowRule {
int MAX_PRIORITY = 65535;
/**
* Reason for flow parameter received from switches.
* Used to check reason parameter in flows.
*/
enum FlowRemoveReason {
NO_REASON,
IDLE_TIMEOUT,
HARD_TIMEOUT;
public static FlowRemoveReason parseShort(short reason) {
switch (reason) {
case -1 :
return NO_REASON;
case 0:
return IDLE_TIMEOUT;
case 1:
return HARD_TIMEOUT;
default :
return NO_REASON;
}
}
}
/**
* Returns the ID of this flow.
*
* @return the flow ID
......@@ -88,6 +110,21 @@ public interface FlowRule {
int timeout();
/**
* Returns the hard timeout for this flow requested by an application.
* This paremeter configure switch's flow hard timeout.
* In case of controller-switch connection lost, this variable can be useful.
* @return integer value of the hard Timeout
*/
int hardTimeout();
/**
* Returns the reason for the flow received from switches.
*
* @return FlowRemoveReason value of reason
*/
FlowRemoveReason reason();
/**
* Returns whether the flow is permanent i.e. does not time out.
*
* @return true if the flow is permanent, otherwise false
......@@ -212,6 +249,20 @@ public interface FlowRule {
Builder makeTemporary(int timeout);
/**
* Sets hard timeout parameter in flow table.
* @param timeout an integer
* @return this
*/
Builder withHardTimeout(int timeout);
/**
* Sets reason parameter received from switches .
* @param reason a short
* @return this
*/
Builder withReason(FlowRemoveReason reason);
/**
* Builds a flow rule object.
*
* @return a flow rule.
......
......@@ -26,6 +26,7 @@ import org.onosproject.net.Link;
import org.onosproject.net.NetTestTools;
import org.onosproject.net.NetworkResource;
import org.onosproject.net.Path;
import org.onosproject.net.flow.FlowRule.FlowRemoveReason;
import org.onosproject.net.flow.FlowId;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleExtPayLoad;
......@@ -330,6 +331,16 @@ public class IntentTestsMocks {
}
@Override
public int hardTimeout() {
return 0;
}
@Override
public FlowRemoveReason reason() {
return FlowRemoveReason.NO_REASON;
}
@Override
public boolean isPermanent() {
return false;
}
......
......@@ -313,8 +313,10 @@ public class FlowRuleManager
extends AbstractProviderService<FlowRuleProvider>
implements FlowRuleProviderService {
final Map<FlowEntry, Long> firstSeen = Maps.newConcurrentMap();
final Map<FlowEntry, Long> lastSeen = Maps.newConcurrentMap();
protected InternalFlowRuleProviderService(FlowRuleProvider provider) {
super(provider);
}
......@@ -324,11 +326,15 @@ public class FlowRuleManager
checkNotNull(flowEntry, FLOW_RULE_NULL);
checkValidity();
lastSeen.remove(flowEntry);
firstSeen.remove(flowEntry);
FlowEntry stored = store.getFlowEntry(flowEntry);
if (stored == null) {
log.debug("Rule already evicted from store: {}", flowEntry);
return;
}
if (flowEntry.reason() == FlowEntry.FlowRemoveReason.HARD_TIMEOUT) {
((DefaultFlowEntry) stored).setState(FlowEntry.FlowEntryState.REMOVED);
}
Device device = deviceService.getDevice(flowEntry.deviceId());
FlowRuleProvider frp = getProvider(device.providerId());
FlowRuleEvent event = null;
......@@ -422,6 +428,21 @@ public class FlowRuleManager
final long timeout = storedRule.timeout() * 1000;
final long currentTime = System.currentTimeMillis();
// Checking flow with hardTimeout
if (storedRule.hardTimeout() != 0) {
if (!firstSeen.containsKey(storedRule)) {
// First time rule adding
firstSeen.put(storedRule, currentTime);
} else {
Long first = firstSeen.get(storedRule);
final long hardTimeout = storedRule.hardTimeout() * 1000;
if ((currentTime - first) > hardTimeout) {
return false;
}
}
}
if (storedRule.packets() != swRule.packets()) {
lastSeen.put(storedRule, currentTime);
return true;
......
......@@ -101,6 +101,7 @@ import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowId;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleBatchEntry;
import org.onosproject.net.flow.FlowRuleBatchEvent;
import org.onosproject.net.flow.FlowRuleBatchOperation;
......@@ -349,6 +350,7 @@ public final class KryoNamespaces {
DefaultFlowEntry.class,
StoredFlowEntry.class,
DefaultFlowRule.class,
FlowRule.FlowRemoveReason.class,
DefaultPacketRequest.class,
PacketPriority.class,
FlowEntry.FlowEntryState.class,
......
......@@ -95,6 +95,7 @@ public class FlowModBuilderVer10 extends FlowModBuilder {
.setMatch(match)
.setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
.setPriority(flowRule().priority())
.setHardTimeout(flowRule().hardTimeout())
.build();
return fm;
......@@ -115,6 +116,7 @@ public class FlowModBuilderVer10 extends FlowModBuilder {
.setMatch(match)
.setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
.setPriority(flowRule().priority())
.setHardTimeout(flowRule().hardTimeout())
.build();
return fm;
......@@ -133,6 +135,7 @@ public class FlowModBuilderVer10 extends FlowModBuilder {
.setMatch(match)
.setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
.setPriority(flowRule().priority())
.setHardTimeout(flowRule().hardTimeout())
.build();
return fm;
......
......@@ -158,6 +158,7 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
.setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
.setPriority(flowRule().priority())
.setTableId(TableId.of(flowRule().tableId()))
.setHardTimeout(flowRule().hardTimeout())
.build();
return fm;
......@@ -201,6 +202,7 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
.setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
.setPriority(flowRule().priority())
.setTableId(TableId.of(flowRule().tableId()))
.setHardTimeout(flowRule().hardTimeout())
.build();
return fm;
......@@ -220,6 +222,7 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
.setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
.setPriority(flowRule().priority())
.setTableId(TableId.of(flowRule().tableId()))
.setHardTimeout(flowRule().hardTimeout())
.build();
return fm;
......
......@@ -182,7 +182,9 @@ public class FlowEntryBuilder {
.withSelector(buildSelector())
.withPriority(removed.getPriority())
.makeTemporary(removed.getIdleTimeout())
.withCookie(removed.getCookie().getValue());
.withCookie(removed.getCookie().getValue())
.withReason(FlowRule.FlowRemoveReason.parseShort(removed.getReason()));
if (removed.getVersion() != OFVersion.OF_10) {
builder.forTable(removed.getTableId().getValue());
}
......
......@@ -46,6 +46,7 @@ import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowId;
import org.onosproject.net.flow.FlowRule.FlowRemoveReason;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleExtPayLoad;
import org.onosproject.net.flow.FlowRuleService;
......@@ -218,6 +219,16 @@ public class FlowsResourceTest extends ResourceTest {
}
@Override
public int hardTimeout() {
return 0;
}
@Override
public FlowRemoveReason reason() {
return FlowRemoveReason.NO_REASON;
}
@Override
public boolean isPermanent() {
return false;
}
......@@ -295,6 +306,16 @@ public class FlowsResourceTest extends ResourceTest {
}
@Override
public int hardTimeout() {
return 0;
}
@Override
public FlowRemoveReason reason() {
return FlowRemoveReason.NO_REASON;
}
@Override
public boolean isPermanent() {
return false;
}
......