CORD-512 Support vSG <-> vRouter default route
- Support multiple subnets per port. getIpPort() will only return the first non-/32 and non-/0 subnet
/32 is used as vSG subnet
/0 is used as default gateway
- Support multiple L3 unicast group on a single port
Change the way to generate the group ID and group key
- Special case for 0.0.0.0 host. Push a /0 to IP table instead of /32
- Implement vRouterConfig
Put VR MAC to TMAC table of all leaves when config added
When processEthDst see PortNumber.ANY in key, match ETH_DST only
- For OFDPA, wipe existing instruction before sending to controller
So packet that misses L3 unicast table won't be sent to controller twice
- For SpringOpenTTP, pop VLAN before sending to controller
- Move several constant definitions to SegmentRoutingService
- Add minimum priority for IP rules such that /0 won't collide with zero priority default rules
- Update the config sample
Use VLAN=-1 for hosts
Add example for default route
Change-Id: Id751697ce36a7e5c13b3859350ff21b585c38525
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java
index 9889967..1fafabc 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2Pipeline.java
@@ -25,6 +25,7 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import com.google.common.collect.ImmutableList;
import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
import org.onlab.packet.IpPrefix;
@@ -288,6 +289,11 @@
VlanIdCriterion vidCriterion,
VlanId assignedVlan,
ApplicationId applicationId) {
+ // Consider PortNumber.ANY as wildcard. Match ETH_DST only
+ if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
+ return processEthDstOnlyFilter(ethCriterion, applicationId);
+ }
+
//handling untagged packets via assigned VLAN
if (vidCriterion.vlanId() == VlanId.NONE) {
vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
@@ -354,6 +360,32 @@
return rules;
}
+ @Override
+ protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
+ ApplicationId applicationId) {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchEthDst(ethCriterion.mac());
+ /*
+ * Note: CpqD switches do not handle MPLS-related operation properly
+ * for a packet with VLAN tag. We pop VLAN here as a workaround.
+ * Side effect: HostService learns redundant hosts with same MAC but
+ * different VLAN. No known side effect on the network reachability.
+ */
+ treatment.popVlan();
+ treatment.transition(UNICAST_ROUTING_TABLE);
+ FlowRule rule = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(selector.build())
+ .withTreatment(treatment.build())
+ .withPriority(DEFAULT_PRIORITY)
+ .fromApp(applicationId)
+ .makePermanent()
+ .forTable(TMAC_TABLE).build();
+ return ImmutableList.<FlowRule>builder().add(rule).build();
+ }
+
/*
* Cpqd emulation allows MPLS ecmp.
*
@@ -600,6 +632,7 @@
log.warn("Cannot process instruction in versatile fwd {}", ins);
}
}
+ ttBuilder.wipeDeferred();
}
if (fwd.nextId() != null) {
// overide case
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2VlanPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2VlanPipeline.java
index cfeb14c..6b43a2a 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2VlanPipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOFDPA2VlanPipeline.java
@@ -78,6 +78,11 @@
VlanIdCriterion vidCriterion,
VlanId assignedVlan,
ApplicationId applicationId) {
+ // Consider PortNumber.ANY as wildcard. Match ETH_DST only
+ if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
+ return processEthDstOnlyFilter(ethCriterion, applicationId);
+ }
+
//handling untagged packets via assigned VLAN
if (vidCriterion.vlanId() == VlanId.NONE) {
vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2GroupHandler.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2GroupHandler.java
index 828b778..883182b 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2GroupHandler.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2GroupHandler.java
@@ -6,6 +6,7 @@
import com.google.common.cache.RemovalCause;
import com.google.common.cache.RemovalNotification;
import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
@@ -95,7 +96,7 @@
Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", "ofdpa2-%d"));
// index number for group creation
- private AtomicInteger l3vpnindex = new AtomicInteger(0);
+ private AtomicInteger l3VpnIndex = new AtomicInteger(0);
// local stores for port-vlan mapping
protected Map<PortNumber, VlanId> port2Vlan = new ConcurrentHashMap<>();
@@ -332,12 +333,14 @@
VlanId vlanid = null;
long portNum = 0;
boolean setVlan = false, popVlan = false;
+ MacAddress dstMac = MacAddress.ZERO;
for (Instruction ins : treatment.allInstructions()) {
if (ins.type() == Instruction.Type.L2MODIFICATION) {
L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
switch (l2ins.subtype()) {
case ETH_DST:
- outerTtb.setEthDst(((L2ModificationInstruction.ModEtherInstruction) l2ins).mac());
+ dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
+ outerTtb.setEthDst(dstMac);
break;
case ETH_SRC:
outerTtb.setEthSrc(((L2ModificationInstruction.ModEtherInstruction) l2ins).mac());
@@ -430,8 +433,11 @@
mplsgroupkey, nextId);
} else {
// outer group is L3Unicast
- int l3groupId = L3_UNICAST_TYPE | (int) portNum;
- int l3gk = L3_UNICAST_TYPE | (TYPE_MASK & (deviceId.hashCode() << 8 | (int) portNum));
+ int l3groupId = L3_UNICAST_TYPE |
+ (TYPE_MASK & (int) (dstMac.toLong() & 0xffff) << 6 | (int) portNum);
+ int l3gk = L3_UNICAST_TYPE |
+ (TYPE_MASK & (deviceId.hashCode() << 22 |
+ (int) (dstMac.toLong() & 0xffff) << 6 | (int) portNum));
final GroupKey l3groupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3gk));
outerTtb.group(new DefaultGroupId(l2groupId));
// create the l3unicast group description to wait for the
@@ -734,8 +740,8 @@
onelabelGroupInfo.outerGrpDesc.givenGroupId()));
GroupBucket l3vpnGrpBkt =
DefaultGroupBucket.createIndirectGroupBucket(l3vpnTtb.build());
- int l3vpngroupId = MPLS_L3VPN_SUBTYPE | l3vpnindex.incrementAndGet();
- int l3vpngk = MPLS_L3VPN_SUBTYPE | nextObj.id() << 12 | l3vpnindex.get();
+ int l3vpngroupId = MPLS_L3VPN_SUBTYPE | l3VpnIndex.incrementAndGet();
+ int l3vpngk = MPLS_L3VPN_SUBTYPE | nextObj.id() << 12 | l3VpnIndex.get();
GroupKey l3vpngroupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3vpngk));
GroupDescription l3vpnGroupDesc =
new DefaultGroupDescription(
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java
index 9f52ac0..382d978 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java
@@ -27,6 +27,7 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import com.google.common.collect.ImmutableList;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpPrefix;
@@ -553,6 +554,11 @@
VlanIdCriterion vidCriterion,
VlanId assignedVlan,
ApplicationId applicationId) {
+ // Consider PortNumber.ANY as wildcard. Match ETH_DST only
+ if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
+ return processEthDstOnlyFilter(ethCriterion, applicationId);
+ }
+
//handling untagged packets via assigned VLAN
if (vidCriterion.vlanId() == VlanId.NONE) {
vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
@@ -611,6 +617,24 @@
return rules;
}
+ protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
+ ApplicationId applicationId) {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchEthDst(ethCriterion.mac());
+ treatment.transition(UNICAST_ROUTING_TABLE);
+ FlowRule rule = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(selector.build())
+ .withTreatment(treatment.build())
+ .withPriority(DEFAULT_PRIORITY)
+ .fromApp(applicationId)
+ .makePermanent()
+ .forTable(TMAC_TABLE).build();
+ return ImmutableList.<FlowRule>builder().add(rule).build();
+ }
+
private Collection<FlowRule> processForward(ForwardingObjective fwd) {
switch (fwd.flag()) {
case SPECIFIC:
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
index 5c65e11..50b439f 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
@@ -23,6 +23,7 @@
import com.google.common.cache.RemovalCause;
import com.google.common.cache.RemovalNotification;
+import com.google.common.collect.ImmutableList;
import org.onlab.osgi.ServiceDirectory;
import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
@@ -504,6 +505,7 @@
fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
if (o.port() == PortNumber.CONTROLLER) {
+ treatmentBuilder.popVlan();
treatmentBuilder.punt();
} else {
treatmentBuilder.add(o);
@@ -780,6 +782,10 @@
FilteringObjective filt,
VlanId assignedVlan,
ApplicationId applicationId) {
+ if (vlanIdCriterion == null) {
+ return processEthDstOnlyFilter(ethCriterion, applicationId, filt.priority());
+ }
+
//handling untagged packets via assigned VLAN
if (vlanIdCriterion.vlanId() == VlanId.NONE) {
vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
@@ -823,6 +829,24 @@
return rules;
}
+ protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
+ ApplicationId applicationId, int priority) {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchEthDst(ethCriterion.mac());
+ treatment.transition(TABLE_IPV4_UNICAST);
+ FlowRule rule = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(selector.build())
+ .withTreatment(treatment.build())
+ .withPriority(priority)
+ .fromApp(applicationId)
+ .makePermanent()
+ .forTable(TABLE_TMAC).build();
+ return ImmutableList.<FlowRule>builder().add(rule).build();
+ }
+
protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion,
FilteringObjective filt,
VlanId assignedVlan,