blob: fb6eeadc65b77d3c6c2de82c91bce90034ea2f20 [file] [log] [blame]
/*
* Copyright 2018-present Open Networking Foundation
*
* 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.
* This work was partially supported by EC H2020 project METRO-HAUL (761727).
*/
package org.onosproject.drivers.odtn.openconfig;
import org.onosproject.net.OchSignal;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.OchSignalCriterion;
import org.onosproject.net.flow.criteria.OchSignalTypeCriterion;
import org.onosproject.net.flow.criteria.PortCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.flow.instructions.L0ModificationInstruction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
public class TerminalDeviceFlowRule extends DefaultFlowRule {
private static final Logger log = LoggerFactory.getLogger(TerminalDeviceFlowRule.class);
public enum Type {
CLIENT_INGRESS,
CLIENT_EGRESS,
LINE_INGRESS,
LINE_EGRESS
}
//As generated by the OpticalConnectivityIntentCompiler
private static final int NUM_CRITERIA_LINE_EGRESS_RULE = 3;
private static final int NUM_INSTRUCTIONS_LINE_EGRESS_RULE = 1;
private static final int NUM_CRITERIA_LINE_INGRESS_RULE = 1;
private static final int NUM_INSTRUCTIONS_LINE_INGRESS_RULE = 2;
//As generated by the OpticalCoircuitIntentCompiler
private static final int NUM_CRITERIA_CLIENT_RULES = 1;
private static final int NUM_INSTRUCTIONS_CLIENT_RULES = 1;
public Type type;
private PortNumber inPortNumber;
private PortNumber outPortNumber;
private OchSignal ochSignal;
private String connectionName;
public TerminalDeviceFlowRule(FlowRule rule, List<PortNumber> linePorts) {
super(rule);
Set<Criterion> criteria = rule.selector().criteria();
List<Instruction> instructions = rule.treatment().immediate();
/*Rules for TerminalDevice are generated in OpticalPathIntentCompiler with two types of intents
--- OpticalConnectivity intent compilation generates following flow rules
OPTICAL LINE level at INGRESS node -- criteria: input port; output port, OChSignal;
OPTICAL LINE level at EGRESS node -- criteria: input port, OChSignal and OCh type; instruction: output port
--- OpticalCircuit intent compilation generates following flow rules
CLIENT PORT at INGRESS node -- criteria: input port (OduClt); instruction output port (Och)
CLIENT PORT at EGRESS node -- criteria: input port (Och); instruction output port (OduClt)*/
checkArgument((criteria.size() == NUM_CRITERIA_LINE_EGRESS_RULE) ||
(criteria.size() == NUM_CRITERIA_LINE_INGRESS_RULE) ||
(criteria.size() == NUM_CRITERIA_CLIENT_RULES),
"Wrong size of flow rule criteria for TerminalDevice size" + criteria.size());
checkArgument((instructions.size() == NUM_INSTRUCTIONS_LINE_EGRESS_RULE) ||
(instructions.size() == NUM_INSTRUCTIONS_LINE_INGRESS_RULE) ||
(instructions.size() == NUM_INSTRUCTIONS_CLIENT_RULES),
"Wrong size of flow rule instructions for TerminalDevice size " + instructions.size());
//This is EGRESS rule on the LINE side
if ((criteria.size() == NUM_CRITERIA_LINE_EGRESS_RULE) &&
(instructions.size() == NUM_INSTRUCTIONS_LINE_EGRESS_RULE)) {
log.debug("Building the TerminalDeviceFlowRule for LINE_EGRESS");
type = Type.LINE_EGRESS;
criteria.forEach(
c -> checkArgument(c instanceof OchSignalCriterion ||
c instanceof OchSignalTypeCriterion ||
c instanceof PortCriterion,
"Incompatible flow rule criteria for ADD TerminalDevice: " + criteria
)
);
instructions.forEach(
c -> checkArgument(c instanceof Instructions.OutputInstruction,
"Incompatible flow rule instruction for ADD TerminalDevice: " + instructions
)
);
ochSignal = criteria.stream()
.filter(c -> c instanceof OchSignalCriterion)
.map(c -> ((OchSignalCriterion) c).lambda())
.findAny()
.orElse(null);
inPortNumber = criteria.stream()
.filter(c -> c instanceof PortCriterion)
.map(c -> ((PortCriterion) c).port())
.findAny()
.orElse(null);
outPortNumber = ((Instructions.OutputInstruction) instructions.get(0)).port();
checkArgument(linePorts.contains(outPortNumber),
"Incompatible output port for DROP TerminalDevice");
}
//This is INGRESS rule on the LINE side
if ((criteria.size() == NUM_CRITERIA_LINE_INGRESS_RULE) &&
(instructions.size() == NUM_INSTRUCTIONS_LINE_INGRESS_RULE)) {
log.debug("Building the TerminalDeviceFlowRule LINE_INGRESS");
type = Type.LINE_INGRESS;
criteria.forEach(
c -> checkArgument(
c instanceof PortCriterion,
"Incompatible flow rule criteria for ADD TerminalDevice: " + criteria
)
);
instructions.forEach(
c -> checkArgument(c.type() == Instruction.Type.L0MODIFICATION ||
c.type() == Instruction.Type.OUTPUT,
"Incompatible flow rule instruction for ADD TerminalDevice: " + instructions
)
);
inPortNumber = criteria.stream()
.filter(c -> c instanceof PortCriterion)
.map(c -> ((PortCriterion) c).port())
.findAny()
.orElse(null);
checkArgument(linePorts.contains(inPortNumber),
"Incompatible input port for DROP TerminalDevice");
ochSignal = instructions.stream()
.filter(c -> c.type() == Instruction.Type.L0MODIFICATION)
.map(c -> ((L0ModificationInstruction.ModOchSignalInstruction) c).lambda())
.findAny()
.orElse(null);
outPortNumber = instructions.stream()
.filter(c -> c.type() == Instruction.Type.OUTPUT)
.map(c -> ((Instructions.OutputInstruction) c).port())
.findAny()
.orElse(null);
}
//This is INGRESS or EGRESS rule on the CLIENT side
if ((criteria.size() == NUM_CRITERIA_CLIENT_RULES) &&
(instructions.size() == NUM_INSTRUCTIONS_CLIENT_RULES)) {
criteria.forEach(
c -> checkArgument(
c instanceof PortCriterion,
"Incompatible flow rule criteria for ADD TerminalDevice: " + criteria
)
);
instructions.forEach(
c -> checkArgument(c.type() == Instruction.Type.OUTPUT,
"Incompatible flow rule instruction for ADD TerminalDevice: " + instructions
)
);
inPortNumber = criteria.stream()
.filter(c -> c instanceof PortCriterion)
.map(c -> ((PortCriterion) c).port())
.findAny()
.orElse(null);
outPortNumber = instructions.stream()
.filter(c -> c.type() == Instruction.Type.OUTPUT)
.map(c -> ((Instructions.OutputInstruction) c).port())
.findAny()
.orElse(null);
ochSignal = null;
if (linePorts.contains(outPortNumber)) {
type = Type.CLIENT_INGRESS;
} else {
type = Type.CLIENT_EGRESS;
}
}
if (type == Type.LINE_EGRESS) {
connectionName = "LineEgress-LinePort-" + inPortNumber.toString()
+ "-ochSig-" + ochSignal.centralFrequency().toString();
}
if (type == Type.LINE_INGRESS) {
connectionName = "LineIngress-LinePort-" + outPortNumber.toString()
+ "-ochSig-" + ochSignal.centralFrequency().toString();
}
if (type == Type.CLIENT_EGRESS) {
connectionName = "ClientEgress-LinePort-" + inPortNumber.toString()
+ "-ClientPort-" + outPortNumber.toString();
}
if (type == Type.CLIENT_INGRESS) {
connectionName = "ClientIngress-ClientPort-" + inPortNumber.toString()
+ "-LinePort-" + outPortNumber.toString();
}
log.info("TerminalFlowRule built with name {}", connectionName);
}
public PortNumber inPort() {
return inPortNumber;
}
public PortNumber outPort() {
return outPortNumber;
}
public OchSignal ochSignal() {
return ochSignal;
}
public String connectionName() {
return connectionName;
}
}