CORD-906 Support trunk and native VLAN
- Include trunk L2IG in L2F
- Populate bridging rules for trunk vlan
- Extend populateVlanMacFilters to generate filtering obj for trunk port
- Extend host handler to check vlan mismatch between host and interface
(Temporarily disabled for now. Check TODOs in the code for detail.)
- Extend getForwardingObjectiveBuilder in RoutingRulePopulator to support tagged host
Change-Id: Id168a02015f58b0957ba43ad7c52798029d895bc
diff --git a/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index dae8a71..06a9dbc 100644
--- a/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -25,7 +25,6 @@
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
-import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.flowobjective.DefaultObjectiveContext;
import org.onosproject.net.flowobjective.Objective;
@@ -61,7 +60,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.packet.Ethernet.TYPE_ARP;
@@ -115,16 +113,16 @@
* @param deviceId device ID of the device that next hop attaches to
* @param prefix IP prefix of the route
* @param hostMac MAC address of the next hop
+ * @param hostVlanId Vlan ID of the nexthop
* @param outPort port where the next hop attaches to
*/
public void populateRoute(DeviceId deviceId, IpPrefix prefix,
- MacAddress hostMac, PortNumber outPort) {
+ MacAddress hostMac, VlanId hostVlanId, PortNumber outPort) {
log.debug("Populate IP table entry for route {} at {}:{}",
prefix, deviceId, outPort);
ForwardingObjective.Builder fwdBuilder;
try {
- fwdBuilder = routingFwdObjBuilder(
- deviceId, prefix, hostMac, outPort);
+ fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac, hostVlanId, outPort);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting populateIpRuleForHost.");
return;
@@ -148,16 +146,16 @@
* @param deviceId device ID of the device that next hop attaches to
* @param prefix IP prefix of the route
* @param hostMac MAC address of the next hop
+ * @param hostVlanId Vlan ID of the nexthop
* @param outPort port that next hop attaches to
*/
public void revokeRoute(DeviceId deviceId, IpPrefix prefix,
- MacAddress hostMac, PortNumber outPort) {
+ MacAddress hostMac, VlanId hostVlanId, PortNumber outPort) {
log.debug("Revoke IP table entry for route {} at {}:{}",
prefix, deviceId, outPort);
ForwardingObjective.Builder fwdBuilder;
try {
- fwdBuilder = routingFwdObjBuilder(
- deviceId, prefix, hostMac, outPort);
+ fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac, hostVlanId, outPort);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting revokeIpRuleForHost.");
return;
@@ -183,42 +181,69 @@
* @param deviceId device ID
* @param prefix prefix that need to be routed
* @param hostMac MAC address of the nexthop
+ * @param hostVlanId Vlan ID of the nexthop
* @param outPort port where the nexthop attaches to
* @return forwarding objective builder
* @throws DeviceConfigNotFoundException if given device is not configured
*/
private ForwardingObjective.Builder routingFwdObjBuilder(
DeviceId deviceId, IpPrefix prefix,
- MacAddress hostMac, PortNumber outPort)
+ MacAddress hostMac, VlanId hostVlanId, PortNumber outPort)
throws DeviceConfigNotFoundException {
MacAddress deviceMac;
deviceMac = config.getDeviceMac(deviceId);
- TrafficSelector.Builder sbuilder = buildIpSelectorFromIpPrefix(prefix);
- TrafficSelector selector = sbuilder.build();
+ ConnectPoint connectPoint = new ConnectPoint(deviceId, outPort);
+ VlanId untaggedVlan = srManager.getUntaggedVlanId(connectPoint);
+ Set<VlanId> taggedVlans = srManager.getTaggedVlanId(connectPoint);
+ VlanId nativeVlan = srManager.getNativeVlanId(connectPoint);
+ // Create route selector
+ TrafficSelector.Builder sbuilder = buildIpSelectorFromIpPrefix(prefix);
+
+ // Create route treatment
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
tbuilder.deferred()
.setEthDst(hostMac)
.setEthSrc(deviceMac)
.setOutput(outPort);
- TrafficTreatment treatment = tbuilder.build();
- // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
- // for switch pipelines that need it, provide outgoing vlan as metadata
- VlanId untaggedVlan = srManager.getUntaggedVlanId(new ConnectPoint(deviceId, outPort));
- VlanId outvlan = (untaggedVlan != null) ? untaggedVlan : INTERNAL_VLAN;
+ // Create route meta
+ TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
- TrafficSelector meta = DefaultTrafficSelector.builder()
- .matchVlanId(outvlan).build();
- int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outPort,
- treatment, meta);
- if (portNextObjId == -1) {
- // warning log will come from getPortNextObjective method
+ // Adjust the meta according to VLAN configuration
+ if (taggedVlans.contains(hostVlanId)) {
+ tbuilder.setVlanId(hostVlanId);
+ } else if (hostVlanId.equals(VlanId.NONE)) {
+ if (untaggedVlan != null) {
+ mbuilder.matchVlanId(untaggedVlan);
+ } else if (nativeVlan != null) {
+ mbuilder.matchVlanId(nativeVlan);
+ } else {
+ // TODO: This check is turned off for now since vRouter still assumes that
+ // hosts are internally tagged with INTERNAL_VLAN.
+ // We should turn this back on when we move forward to the bridging CPR approach.
+ //
+ //log.warn("Untagged nexthop {}/{} is not allowed on {} without untagged or native vlan",
+ // hostMac, hostVlanId, connectPoint);
+ //return null;
+ mbuilder.matchVlanId(INTERNAL_VLAN);
+ }
+ } else {
+ log.warn("Tagged nexthop {}/{} is not allowed on {} without VLAN listed in tagged vlan",
+ hostMac, hostVlanId, connectPoint);
return null;
}
+
+ int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outPort,
+ tbuilder.build(), mbuilder.build());
+ if (portNextObjId == -1) {
+ // Warning log will come from getPortNextObjective method
+ return null;
+ }
+
return DefaultForwardingObjective.builder()
- .withSelector(selector)
+ .withSelector(sbuilder.build())
.nextStep(portNextObjId)
.fromApp(srManager.appId).makePermanent()
.withPriority(getPriorityFromPrefix(prefix))
@@ -638,7 +663,40 @@
* @return true if no errors occurred during the build of the filtering objective
*/
public boolean populateSinglePortFilters(DeviceId deviceId, PortNumber portnum) {
- FilteringObjective.Builder fob = buildFilteringObjective(deviceId, portnum);
+ ConnectPoint connectPoint = new ConnectPoint(deviceId, portnum);
+ VlanId untaggedVlan = srManager.getUntaggedVlanId(connectPoint);
+ Set<VlanId> taggedVlans = srManager.getTaggedVlanId(connectPoint);
+ VlanId nativeVlan = srManager.getNativeVlanId(connectPoint);
+
+ if (taggedVlans.size() != 0) {
+ // Filter for tagged vlans
+ if (!srManager.getTaggedVlanId(connectPoint).stream().allMatch(taggedVlanId ->
+ populateSinglePortFiltersInternal(deviceId, portnum, false, taggedVlanId))) {
+ return false;
+ }
+ if (nativeVlan != null) {
+ // Filter for native vlan
+ if (!populateSinglePortFiltersInternal(deviceId, portnum, true, nativeVlan)) {
+ return false;
+ }
+ }
+ } else if (untaggedVlan != null) {
+ // Filter for untagged vlan
+ if (!populateSinglePortFiltersInternal(deviceId, portnum, true, untaggedVlan)) {
+ return false;
+ }
+ } else {
+ // Unconfigure port, use INTERNAL_VLAN
+ if (!populateSinglePortFiltersInternal(deviceId, portnum, true, INTERNAL_VLAN)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean populateSinglePortFiltersInternal(DeviceId deviceId, PortNumber portnum,
+ boolean pushVlan, VlanId vlanId) {
+ FilteringObjective.Builder fob = buildFilteringObjective(deviceId, portnum, pushVlan, vlanId);
if (fob == null) {
// error encountered during build
return false;
@@ -659,12 +717,43 @@
*
* @param deviceId device identifier
* @param portnum port identifier
+ * @return true if no errors occurred during the destruction of the filtering objective
*/
- public void revokeSinglePortFilters(DeviceId deviceId, PortNumber portnum) {
- FilteringObjective.Builder fob = buildFilteringObjective(deviceId, portnum);
+ public boolean revokeSinglePortFilters(DeviceId deviceId, PortNumber portnum) {
+ ConnectPoint connectPoint = new ConnectPoint(deviceId, portnum);
+ VlanId untaggedVlan = srManager.getUntaggedVlanId(connectPoint);
+ Set<VlanId> taggedVlans = srManager.getTaggedVlanId(connectPoint);
+ VlanId nativeVlan = srManager.getNativeVlanId(connectPoint);
+
+ if (taggedVlans.size() != 0) {
+ // Filter for tagged vlans
+ if (!srManager.getTaggedVlanId(connectPoint).stream().allMatch(taggedVlanId ->
+ revokeSinglePortFiltersInternal(deviceId, portnum, false, taggedVlanId))) {
+ return false;
+ }
+ // Filter for native vlan
+ if (nativeVlan == null ||
+ !revokeSinglePortFiltersInternal(deviceId, portnum, true, nativeVlan)) {
+ return false;
+ }
+ // Filter for untagged vlan
+ } else if (untaggedVlan == null ||
+ !revokeSinglePortFiltersInternal(deviceId, portnum, true, untaggedVlan)) {
+ return false;
+ // Unconfigure port, use INTERNAL_VLAN
+ } else if (!revokeSinglePortFiltersInternal(deviceId, portnum, true, INTERNAL_VLAN)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean revokeSinglePortFiltersInternal(DeviceId deviceId, PortNumber portnum,
+ boolean pushVlan, VlanId vlanId) {
+ FilteringObjective.Builder fob = buildFilteringObjective(deviceId, portnum, pushVlan, vlanId);
if (fob == null) {
// error encountered during build
- return;
+ return false;
}
log.info("Removing filtering objectives for dev/port:{}/{}", deviceId, portnum);
ObjectiveContext context = new DefaultObjectiveContext(
@@ -673,11 +762,11 @@
log.warn("Failed to remove filter for {}/{}: {}",
deviceId, portnum, error));
srManager.flowObjectiveService.filter(deviceId, fob.remove(context));
- return;
+ return true;
}
- private FilteringObjective.Builder buildFilteringObjective(DeviceId deviceId,
- PortNumber portnum) {
+ private FilteringObjective.Builder buildFilteringObjective(DeviceId deviceId, PortNumber portnum,
+ boolean pushVlan, VlanId vlanId) {
MacAddress deviceMac;
try {
deviceMac = config.getDeviceMac(deviceId);
@@ -688,17 +777,20 @@
// suppressed ports still have filtering rules pushed by SR using default vlan
ConnectPoint connectPoint = new ConnectPoint(deviceId, portnum);
- VlanId untaggedVlan = srManager.getUntaggedVlanId(connectPoint);
- VlanId assignedVlan = (untaggedVlan != null) ? untaggedVlan : INTERNAL_VLAN;
-
FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
fob.withKey(Criteria.matchInPort(portnum))
.addCondition(Criteria.matchEthDst(deviceMac))
- .addCondition(Criteria.matchVlanId(VlanId.NONE))
.withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
- TrafficTreatment tt = DefaultTrafficTreatment.builder()
- .pushVlan().setVlanId(assignedVlan).build();
- fob.withMeta(tt);
+
+ if (pushVlan) {
+ fob.addCondition(Criteria.matchVlanId(VlanId.NONE));
+ TrafficTreatment tt = DefaultTrafficTreatment.builder()
+ .pushVlan().setVlanId(vlanId).build();
+ fob.withMeta(tt);
+ } else {
+ fob.addCondition(Criteria.matchVlanId(vlanId));
+ }
+
fob.permit().fromApp(srManager.appId);
return fob;
}
@@ -852,15 +944,7 @@
* @param deviceId switch ID to set the rules
*/
public void populateSubnetBroadcastRule(DeviceId deviceId) {
- Set<Interface> interfaces = srManager.interfaceService.getInterfaces();
- Set<VlanId> vlans =
- interfaces.stream()
- .filter(intf -> intf.connectPoint().deviceId().equals(deviceId) &&
- !intf.vlanUntagged().equals(VlanId.NONE))
- .map(Interface::vlanUntagged)
- .collect(Collectors.toSet());
-
- vlans.forEach(vlanId -> {
+ srManager.getVlanPortMap(deviceId).asMap().forEach((vlanId, ports) -> {
int nextId = srManager.getVlanNextObjectiveId(deviceId, vlanId);
if (nextId < 0) {