Charles Chan
Committed by Gerrit Code Review

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
Showing 21 changed files with 827 additions and 144 deletions
......@@ -97,6 +97,14 @@
<artifactId>onlab-junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-api</artifactId>
<version>${project.version}</version>
<scope>test</scope>
<classifier>tests</classifier>
</dependency>
</dependencies>
<build>
......
......@@ -168,7 +168,7 @@ public class IcmpHandler {
treatment, ByteBuffer.wrap(payload.serialize()));
srManager.packetService.emit(packet);
} else {
log.warn("Send a MPLS packet as a ICMP response");
log.info("Send a MPLS packet as a ICMP response");
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(outport.port())
.build();
......
package org.onosproject.segmentrouting;
import com.google.common.collect.ImmutableSet;
import org.onlab.packet.MacAddress;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flowobjective.DefaultFilteringObjective;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
/**
* Handles network config events.
*/
public class NetworkConfigEventHandler {
private static final Logger log = LoggerFactory.getLogger(NetworkConfigEventHandler.class);
private final SegmentRoutingManager srManager;
private final DeviceService deviceService;
/**
* Constructs Network Config Event Handler.
*
* @param srManager instance of {@link SegmentRoutingManager}
*/
public NetworkConfigEventHandler(SegmentRoutingManager srManager) {
this.srManager = srManager;
this.deviceService = srManager.deviceService;
}
/**
* Processes vRouter config added event.
*
* @param event network config added event
*/
protected void processVRouterConfigAdded(NetworkConfigEvent event) {
log.info("Processing vRouter CONFIG_ADDED");
SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get();
deviceService.getAvailableDevices().forEach(device -> {
populateVRouter(device.id(), getMacAddresses(config));
});
}
/**
* Processes vRouter config updated event.
*
* @param event network config updated event
*/
protected void processVRouterConfigUpdated(NetworkConfigEvent event) {
log.info("Processing vRouter CONFIG_UPDATED");
SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get();
SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get();
deviceService.getAvailableDevices().forEach(device -> {
Set<MacAddress> macAddresses = getMacAddresses(config);
Set<MacAddress> prevMacAddresses = getMacAddresses(prevConfig);
// Avoid removing and re-adding unchanged MAC addresses since
// FlowObjective does not guarantee the execution order.
Set<MacAddress> sameMacAddresses = new HashSet<>(macAddresses);
sameMacAddresses.retainAll(prevMacAddresses);
macAddresses.removeAll(sameMacAddresses);
prevMacAddresses.removeAll(sameMacAddresses);
revokeVRouter(device.id(), prevMacAddresses);
populateVRouter(device.id(), macAddresses);
});
}
/**
* Processes vRouter config removed event.
*
* @param event network config removed event
*/
protected void processVRouterConfigRemoved(NetworkConfigEvent event) {
log.info("Processing vRouter CONFIG_REMOVED");
SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get();
deviceService.getAvailableDevices().forEach(device -> {
revokeVRouter(device.id(), getMacAddresses(prevConfig));
});
}
/**
* Populates initial vRouter rules.
*
* @param deviceId device ID
*/
public void initVRouters(DeviceId deviceId) {
SegmentRoutingAppConfig config =
srManager.cfgService.getConfig(srManager.appId, SegmentRoutingAppConfig.class);
populateVRouter(deviceId, getMacAddresses(config));
}
private void populateVRouter(DeviceId deviceId, Set<MacAddress> pendingAdd) {
if (!isEdge(deviceId)) {
return;
}
getVRouterFlowObjBuilders(pendingAdd).forEach(foBuilder -> {
srManager.flowObjectiveService.
filter(deviceId, foBuilder.add(new SRObjectiveContext(deviceId,
SRObjectiveContext.ObjectiveType.FILTER)));
});
}
private void revokeVRouter(DeviceId deviceId, Set<MacAddress> pendingRemove) {
if (!isEdge(deviceId)) {
return;
}
getVRouterFlowObjBuilders(pendingRemove).forEach(foBuilder -> {
srManager.flowObjectiveService.
filter(deviceId, foBuilder.remove(new SRObjectiveContext(deviceId,
SRObjectiveContext.ObjectiveType.FILTER)));
});
}
private Set<FilteringObjective.Builder> getVRouterFlowObjBuilders(Set<MacAddress> macAddresses) {
ImmutableSet.Builder<FilteringObjective.Builder> setBuilder = ImmutableSet.builder();
macAddresses.forEach(macAddress -> {
FilteringObjective.Builder fobuilder = DefaultFilteringObjective.builder();
fobuilder.withKey(Criteria.matchInPort(PortNumber.ANY))
.addCondition(Criteria.matchEthDst(macAddress))
.permit()
.withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
.fromApp(srManager.appId);
setBuilder.add(fobuilder);
});
return setBuilder.build();
}
private Set<MacAddress> getMacAddresses(SegmentRoutingAppConfig config) {
if (config == null) {
return ImmutableSet.of();
}
HashSet<MacAddress> macAddresses = new HashSet<>();
config.vRouterMacs().forEach(mac -> {
macAddresses.add(mac);
});
return ImmutableSet.copyOf(macAddresses);
}
private boolean isEdge(DeviceId deviceId) {
try {
if (srManager.deviceConfiguration.isEdgeDevice(deviceId)) {
return true;
}
} catch (DeviceConfigNotFoundException e) { }
return false;
}
}
......@@ -39,11 +39,8 @@ import org.onosproject.net.flowobjective.DefaultFilteringObjective;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.flowobjective.ForwardingObjective.Builder;
import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
import org.onosproject.net.flowobjective.ObjectiveContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -67,14 +64,6 @@ public class RoutingRulePopulator {
private SegmentRoutingManager srManager;
private DeviceConfiguration config;
private static final int HIGHEST_PRIORITY = 0xffff;
//
private static final int XCONNECT_PRIORITY = 1000;
private static final int DEFAULT_PRIORITY = 100;
private static final int FLOOD_PRIORITY = 5;
private static final long OFPP_MAX = 0xffffff00L;
/**
* Creates a RoutingRulePopulator object.
*
......@@ -160,12 +149,21 @@ public class RoutingRulePopulator {
throws DeviceConfigNotFoundException {
MacAddress deviceMac;
deviceMac = config.getDeviceMac(deviceId);
int priority;
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
sbuilder.matchEthType(Ethernet.TYPE_IPV4);
sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH));
// Special case for default route
if (hostIp.isZero()) {
sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 0));
priority = SegmentRoutingService.MIN_IP_PRIORITY;
} else {
Ip4Prefix hostIpPrefix = Ip4Prefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH);
sbuilder.matchIPDst(hostIpPrefix);
priority = getPriorityFromPrefix(hostIpPrefix);
}
TrafficSelector selector = sbuilder.build();
tbuilder.deferred()
......@@ -192,7 +190,8 @@ public class RoutingRulePopulator {
.withSelector(selector)
.nextStep(portNextObjId)
.fromApp(srManager.appId).makePermanent()
.withPriority(DEFAULT_PRIORITY).withFlag(ForwardingObjective.Flag.SPECIFIC);
.withPriority(priority)
.withFlag(ForwardingObjective.Flag.SPECIFIC);
}
/**
......@@ -277,7 +276,7 @@ public class RoutingRulePopulator {
.makePermanent()
.nextStep(nextId)
.withSelector(selector)
.withPriority(2000 * ipPrefix.prefixLength())
.withPriority(getPriorityFromPrefix(ipPrefix))
.withFlag(ForwardingObjective.Flag.SPECIFIC);
if (treatment != null) {
fwdBuilder.withTreatment(treatment);
......@@ -386,7 +385,7 @@ public class RoutingRulePopulator {
for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
.makePermanent()).withSelector(selector)
.withPriority(DEFAULT_PRIORITY))
.withPriority(SegmentRoutingService.DEFAULT_PRIORITY))
.withFlag(ForwardingObjective.Flag.SPECIFIC);
srManager.flowObjectiveService.
forward(deviceId,
......@@ -472,7 +471,9 @@ public class RoutingRulePopulator {
}
for (Port port : srManager.deviceService.getPorts(deviceId)) {
if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
if (port.number().toLong() > 0 &&
port.number().toLong() < SegmentRoutingService.OFPP_MAX &&
port.isEnabled()) {
Ip4Prefix portSubnet = config.getPortSubnet(deviceId, port.number());
VlanId assignedVlan = (portSubnet == null)
? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET)
......@@ -482,7 +483,7 @@ public class RoutingRulePopulator {
fob.withKey(Criteria.matchInPort(port.number()))
.addCondition(Criteria.matchEthDst(deviceMac))
.addCondition(Criteria.matchVlanId(VlanId.NONE))
.withPriority(DEFAULT_PRIORITY);
.withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
// vlan assignment is valid only if this instance is master
if (srManager.mastershipService.isLocalMaster(deviceId)) {
TrafficTreatment tt = DefaultTrafficTreatment.builder()
......@@ -520,7 +521,7 @@ public class RoutingRulePopulator {
return;
}
ForwardingObjective.Builder puntIp = DefaultForwardingObjective.builder();
Set<Ip4Address> allIps = new HashSet<Ip4Address>(config.getPortIPs(deviceId));
Set<Ip4Address> allIps = new HashSet<>(config.getPortIPs(deviceId));
allIps.add(routerIp);
for (Ip4Address ipaddr : allIps) {
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
......@@ -532,7 +533,7 @@ public class RoutingRulePopulator {
puntIp.withSelector(sbuilder.build());
puntIp.withTreatment(tbuilder.build());
puntIp.withFlag(Flag.VERSATILE)
.withPriority(HIGHEST_PRIORITY)
.withPriority(SegmentRoutingService.HIGHEST_PRIORITY)
.makePermanent()
.fromApp(srManager.appId);
log.debug("Installing forwarding objective to punt port IP addresses");
......@@ -576,7 +577,7 @@ public class RoutingRulePopulator {
fob.withFlag(Flag.SPECIFIC)
.withSelector(sbuilder.build())
.nextStep(nextId)
.withPriority(FLOOD_PRIORITY)
.withPriority(SegmentRoutingService.FLOOD_PRIORITY)
.fromApp(srManager.appId)
.makePermanent();
......@@ -611,7 +612,7 @@ public class RoutingRulePopulator {
fob.withKey(Criteria.matchInPort(connectPoint.port()))
.addCondition(Criteria.matchVlanId(vlanId))
.addCondition(Criteria.matchEthDst(MacAddress.NONE))
.withPriority(XCONNECT_PRIORITY);
.withPriority(SegmentRoutingService.XCONNECT_PRIORITY);
fob.permit().fromApp(srManager.appId);
srManager.flowObjectiveService
......@@ -657,7 +658,7 @@ public class RoutingRulePopulator {
fob.withFlag(Flag.SPECIFIC)
.withSelector(sbuilder.build())
.nextStep(nextId)
.withPriority(DEFAULT_PRIORITY)
.withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
.fromApp(srManager.appId)
.makePermanent();
......@@ -671,29 +672,9 @@ public class RoutingRulePopulator {
});
}
private static class SRObjectiveContext implements ObjectiveContext {
enum ObjectiveType {
FILTER,
FORWARDING
}
final DeviceId deviceId;
final ObjectiveType type;
SRObjectiveContext(DeviceId deviceId, ObjectiveType type) {
this.deviceId = deviceId;
this.type = type;
}
@Override
public void onSuccess(Objective objective) {
log.debug("{} objective operation successful in device {}",
type.name(), deviceId);
}
@Override
public void onError(Objective objective, ObjectiveError error) {
log.warn("{} objective {} operation failed with error: {} in device {}",
type.name(), objective, error, deviceId);
}
private int getPriorityFromPrefix(IpPrefix prefix) {
return (prefix.isIp4()) ?
2000 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY :
500 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY;
}
}
......
package org.onosproject.segmentrouting;
import org.onosproject.net.DeviceId;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveContext;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Segment Routing Flow Objective Context.
*/
public class SRObjectiveContext implements ObjectiveContext {
enum ObjectiveType {
FILTER,
FORWARDING
}
private final DeviceId deviceId;
private final ObjectiveType type;
private static final Logger log = LoggerFactory
.getLogger(SegmentRoutingManager.class);
SRObjectiveContext(DeviceId deviceId, ObjectiveType type) {
this.deviceId = deviceId;
this.type = type;
}
@Override
public void onSuccess(Objective objective) {
log.debug("{} objective operation successful in device {}",
type.name(), deviceId);
}
@Override
public void onError(Objective objective, ObjectiveError error) {
log.warn("{} objective {} operation failed with error: {} in device {}",
type.name(), objective, error, deviceId);
}
}
......@@ -54,7 +54,8 @@ import org.onosproject.net.host.HostListener;
import org.onosproject.net.packet.PacketPriority;
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
import org.onosproject.segmentrouting.config.DeviceConfiguration;
import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
import org.onosproject.segmentrouting.grouphandler.NeighborSet;
import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
......@@ -130,6 +131,12 @@ public class SegmentRoutingManager implements SegmentRoutingService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MastershipService mastershipService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry cfgService;
protected ArpHandler arpHandler = null;
protected IcmpHandler icmpHandler = null;
protected IpHandler ipHandler = null;
......@@ -143,7 +150,9 @@ public class SegmentRoutingManager implements SegmentRoutingService {
private InternalPacketProcessor processor = null;
private InternalLinkListener linkListener = null;
private InternalDeviceListener deviceListener = null;
private NetworkConfigEventHandler netcfgHandler = null;
private InternalEventHandler eventHandler = new InternalEventHandler();
private final InternalHostListener hostListener = new InternalHostListener();
private ScheduledExecutorService executorService = Executors
.newScheduledThreadPool(1);
......@@ -181,27 +190,28 @@ public class SegmentRoutingManager implements SegmentRoutingService {
private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
private EventuallyConsistentMap<String, Policy> policyStore = null;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry cfgService;
private final InternalConfigListener cfgListener =
new InternalConfigListener(this);
@SuppressWarnings({ "unchecked", "rawtypes" })
private final ConfigFactory cfgFactory =
new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
SegmentRoutingConfig.class,
private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> cfgDeviceFactory =
new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
SegmentRoutingDeviceConfig.class,
"segmentrouting") {
@Override
public SegmentRoutingConfig createConfig() {
return new SegmentRoutingConfig();
public SegmentRoutingDeviceConfig createConfig() {
return new SegmentRoutingDeviceConfig();
}
};
private final InternalHostListener hostListener = new InternalHostListener();
private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> cfgAppFactory =
new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
SegmentRoutingAppConfig.class,
"segmentrouting") {
@Override
public SegmentRoutingAppConfig createConfig() {
return new SegmentRoutingAppConfig();
}
};
private Object threadSchedulerLock = new Object();
private static int numOfEventsQueued = 0;
......@@ -223,7 +233,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
@Activate
protected void activate() {
appId = coreService
.registerApplication("org.onosproject.segmentrouting");
.registerApplication(SR_APP_ID);
kryoBuilder = new KryoNamespace.Builder()
.register(NeighborSetNextObjectiveStoreKey.class,
......@@ -309,14 +319,15 @@ public class SegmentRoutingManager implements SegmentRoutingService {
.build();
cfgService.addListener(cfgListener);
cfgService.registerConfigFactory(cfgFactory);
hostService.addListener(hostListener);
cfgService.registerConfigFactory(cfgDeviceFactory);
cfgService.registerConfigFactory(cfgAppFactory);
processor = new InternalPacketProcessor();
linkListener = new InternalLinkListener();
deviceListener = new InternalDeviceListener();
netcfgHandler = new NetworkConfigEventHandler(this);
hostService.addListener(hostListener);
packetService.addProcessor(processor, PacketProcessor.director(2));
linkService.addListener(linkListener);
deviceService.addListener(deviceListener);
......@@ -334,7 +345,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
@Deactivate
protected void deactivate() {
cfgService.removeListener(cfgListener);
cfgService.unregisterConfigFactory(cfgFactory);
cfgService.unregisterConfigFactory(cfgDeviceFactory);
cfgService.unregisterConfigFactory(cfgAppFactory);
// Withdraw ARP packet-in
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
......@@ -456,10 +468,17 @@ public class SegmentRoutingManager implements SegmentRoutingService {
nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
}
for (Ip4Prefix unsub : unassignedSubnets) {
subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
VlanId.vlanId(nextAssignedVlan--));
log.info("Assigned vlan: {} to subnet: {} on device: {}",
nextAssignedVlan + 1, unsub, deviceId);
// Special case for default route. Assign default VLAN ID to /32 and /0 subnets
if (unsub.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
unsub.prefixLength() == 0) {
subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET));
} else {
subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
VlanId.vlanId(nextAssignedVlan--));
log.info("Assigned vlan: {} to subnet: {} on device: {}",
nextAssignedVlan + 1, unsub, deviceId);
}
}
return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
......@@ -766,6 +785,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
groupHandler.createGroupsForXConnect(device.id());
routingRulePopulator.populateXConnectBroadcastRule(device.id());
}
netcfgHandler.initVRouters(device.id());
}
private void processPortRemoved(Device device, Port port) {
......@@ -851,14 +872,33 @@ public class SegmentRoutingManager implements SegmentRoutingService {
@Override
public void event(NetworkConfigEvent event) {
if (event.configClass().equals(SegmentRoutingConfig.class)) {
if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
log.info("Network configuration added.");
configureNetwork();
// TODO move this part to NetworkConfigEventHandler
if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
switch (event.type()) {
case CONFIG_ADDED:
log.info("Segment Routing Config added.");
configureNetwork();
break;
case CONFIG_UPDATED:
log.info("Segment Routing Config updated.");
// TODO support dynamic configuration
break;
default:
break;
}
if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
log.info("Network configuration updated.");
// TODO support dynamic configuration
} else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
switch (event.type()) {
case CONFIG_ADDED:
netcfgHandler.processVRouterConfigAdded(event);
break;
case CONFIG_UPDATED:
netcfgHandler.processVRouterConfigUpdated(event);
break;
case CONFIG_REMOVED:
netcfgHandler.processVRouterConfigRemoved(event);
break;
default:
break;
}
}
}
......
......@@ -21,6 +21,40 @@ import java.util.List;
* Segment Routing Service for REST API.
*/
public interface SegmentRoutingService {
/**
* Segment Routing App ID.
*/
String SR_APP_ID = "org.onosproject.segmentrouting";
/**
* Highest flow priority.
*/
int HIGHEST_PRIORITY = 0xffff;
/**
* VLAN cross-connect priority.
*/
int XCONNECT_PRIORITY = 1000;
/**
* Default flow priority.
*/
int DEFAULT_PRIORITY = 100;
/**
* Minimum IP priority.
*
* Should > 0 such that priority of /0 will not conflict with lowest
* priority default entries.
*/
int MIN_IP_PRIORITY = 10;
/**
* Subnet flooding flow priority.
*/
int FLOOD_PRIORITY = 5;
long OFPP_MAX = 0xffffff00L;
/**
* Returns all tunnels.
......
......@@ -15,9 +15,12 @@
*/
package org.onosproject.segmentrouting.config;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.incubator.net.config.basics.ConfigException;
......@@ -37,6 +40,7 @@ import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
......@@ -59,13 +63,13 @@ public class DeviceConfiguration implements DeviceProperties {
Ip4Address ip;
MacAddress mac;
boolean isEdge;
HashMap<PortNumber, Ip4Address> gatewayIps;
HashMap<PortNumber, Ip4Prefix> subnets;
Map<PortNumber, Ip4Address> gatewayIps;
SetMultimap<PortNumber, Ip4Prefix> subnets;
Map<Integer, Set<Integer>> adjacencySids;
public SegmentRouterInfo() {
gatewayIps = new HashMap<>();
subnets = new HashMap<>();
subnets = HashMultimap.create();
}
}
......@@ -78,10 +82,10 @@ public class DeviceConfiguration implements DeviceProperties {
public DeviceConfiguration(NetworkConfigRegistry cfgService) {
// Read config from device subject, excluding gatewayIps and subnets.
Set<DeviceId> deviceSubjects =
cfgService.getSubjects(DeviceId.class, SegmentRoutingConfig.class);
cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
deviceSubjects.forEach(subject -> {
SegmentRoutingConfig config =
cfgService.getConfig(subject, SegmentRoutingConfig.class);
SegmentRoutingDeviceConfig config =
cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
SegmentRouterInfo info = new SegmentRouterInfo();
info.deviceId = subject;
info.nodeSid = config.nodeSid();
......@@ -119,7 +123,11 @@ public class DeviceConfiguration implements DeviceProperties {
// Extract subnet information
Set<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddresses();
interfaceAddresses.forEach(interfaceAddress -> {
info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address());
// Do not add /0 and /32 to gateway IP list
int prefixLength = interfaceAddress.subnetAddress().prefixLength();
if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address());
}
info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix());
});
......@@ -247,9 +255,13 @@ public class DeviceConfiguration implements DeviceProperties {
Map<Ip4Prefix, List<PortNumber>> subnetPortMap = new HashMap<>();
// Construct subnet-port mapping from port-subnet mapping
Map<PortNumber, Ip4Prefix> portSubnetMap =
SetMultimap<PortNumber, Ip4Prefix> portSubnetMap =
this.deviceConfigMap.get(deviceId).subnets;
portSubnetMap.forEach((port, subnet) -> {
portSubnetMap.entries().forEach(entry -> {
PortNumber port = entry.getKey();
Ip4Prefix subnet = entry.getValue();
if (subnetPortMap.containsKey(subnet)) {
subnetPortMap.get(subnet).add(port);
} else {
......@@ -258,7 +270,6 @@ public class DeviceConfiguration implements DeviceProperties {
subnetPortMap.put(subnet, ports);
}
});
return subnetPortMap;
}
......@@ -322,21 +333,6 @@ public class DeviceConfiguration implements DeviceProperties {
}
/**
* Returns the configured IP addresses per port
* for a segment router.
*
* @param deviceId device identifier
* @return map of port to gateway IP addresses or null if not found
*/
public Map<PortNumber, Ip4Address> getPortIPMap(DeviceId deviceId) {
SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
if (srinfo != null) {
return srinfo.gatewayIps;
}
return null;
}
/**
* Returns the configured subnet prefixes for a segment router.
*
* @param deviceId device identifier
......@@ -353,8 +349,8 @@ public class DeviceConfiguration implements DeviceProperties {
}
/**
* Returns the configured subnet on the given port, or null if no
* subnet has been configured on the port.
* Returns the configured non-/32 and non-/0 subnet on the given port,
* or null if no subnet has been configured on the port.
*
* @param deviceId device identifier
* @param pnum port identifier
......@@ -363,7 +359,12 @@ public class DeviceConfiguration implements DeviceProperties {
public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber pnum) {
SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
if (srinfo != null) {
return srinfo.subnets.get(pnum);
Optional<Ip4Prefix> result = srinfo.subnets.get(pnum).stream()
.filter(subnet ->
subnet.getIp4Prefix().prefixLength() != IpPrefix.MAX_INET_MASK_LENGTH &&
subnet.getIp4Prefix().prefixLength() != 0)
.findFirst();
return (result.isPresent()) ? result.get() : null;
}
return null;
}
......@@ -378,7 +379,7 @@ public class DeviceConfiguration implements DeviceProperties {
public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
deviceConfigMap.entrySet()) {
for (Ip4Prefix prefix:entry.getValue().subnets.values()) {
for (Ip4Prefix prefix : entry.getValue().subnets.values()) {
if (prefix.contains(destIpAddress)) {
return entry.getValue().ip;
}
......@@ -428,7 +429,8 @@ public class DeviceConfiguration implements DeviceProperties {
}
for (Ip4Prefix subnet: subnets) {
if (subnet.contains(hostIp)) {
// Exclude /0 since it is a special case used for default route
if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
return true;
}
}
......
/*
* Copyright 2016 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.config;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.ImmutableSet;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.config.Config;
import java.util.Set;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
* App configuration object for Segment Routing.
*/
public class SegmentRoutingAppConfig extends Config<ApplicationId> {
private static final String VROUTER_MACS = "vRouterMacs";
@Override
public boolean isValid() {
return hasOnlyFields(VROUTER_MACS) && vRouterMacs() != null;
}
/**
* Gets vRouters from the config.
*
* @return a set of vRouter MAC addresses
*/
public Set<MacAddress> vRouterMacs() {
if (!object.has(VROUTER_MACS)) {
return null;
}
ImmutableSet.Builder<MacAddress> builder = ImmutableSet.builder();
ArrayNode arrayNode = (ArrayNode) object.path(VROUTER_MACS);
for (JsonNode jsonNode : arrayNode) {
MacAddress mac;
String macStr = jsonNode.asText(null);
if (macStr == null) {
return null;
}
try {
mac = MacAddress.valueOf(macStr);
} catch (IllegalArgumentException e) {
return null;
}
builder.add(mac);
}
return builder.build();
}
/**
* Sets vRouters to the config.
*
* @param vRouterMacs a set of vRouter MAC addresses
* @return this {@link SegmentRoutingAppConfig}
*/
public SegmentRoutingAppConfig setVRouterMacs(Set<MacAddress> vRouterMacs) {
if (vRouterMacs == null) {
object.remove(VROUTER_MACS);
} else {
ArrayNode arrayNode = mapper.createArrayNode();
vRouterMacs.forEach(mac -> {
arrayNode.add(mac.toString());
});
object.set(VROUTER_MACS, arrayNode);
}
return this;
}
@Override
public String toString() {
return toStringHelper(this)
.add("vRouterMacs", vRouterMacs())
.toString();
}
}
......@@ -34,7 +34,7 @@ import java.util.Set;
/**
* Configuration object for Segment Routing Application.
*/
public class SegmentRoutingConfig extends Config<DeviceId> {
public class SegmentRoutingDeviceConfig extends Config<DeviceId> {
private static final String NAME = "name";
private static final String IP = "routerIp";
private static final String MAC = "routerMac";
......@@ -71,8 +71,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
* @param name name of the router.
* @return the config of the router.
*/
public SegmentRoutingConfig setName(String name) {
return (SegmentRoutingConfig) setOrClear(NAME, name);
public SegmentRoutingDeviceConfig setName(String name) {
return (SegmentRoutingDeviceConfig) setOrClear(NAME, name);
}
/**
......@@ -91,8 +91,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
* @param ip IP address of the router.
* @return the config of the router.
*/
public SegmentRoutingConfig setRouterIp(String ip) {
return (SegmentRoutingConfig) setOrClear(IP, ip);
public SegmentRoutingDeviceConfig setRouterIp(String ip) {
return (SegmentRoutingDeviceConfig) setOrClear(IP, ip);
}
/**
......@@ -111,8 +111,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
* @param mac MAC address of the router.
* @return the config of the router.
*/
public SegmentRoutingConfig setRouterMac(String mac) {
return (SegmentRoutingConfig) setOrClear(MAC, mac);
public SegmentRoutingDeviceConfig setRouterMac(String mac) {
return (SegmentRoutingDeviceConfig) setOrClear(MAC, mac);
}
/**
......@@ -130,8 +130,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
* @param sid node SID of the router.
* @return the config of the router.
*/
public SegmentRoutingConfig setNodeSid(int sid) {
return (SegmentRoutingConfig) setOrClear(SID, sid);
public SegmentRoutingDeviceConfig setNodeSid(int sid) {
return (SegmentRoutingDeviceConfig) setOrClear(SID, sid);
}
/**
......@@ -154,8 +154,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
* @param isEdgeRouter true if the router is an edge router.
* @return the config of the router.
*/
public SegmentRoutingConfig setIsEdgeRouter(boolean isEdgeRouter) {
return (SegmentRoutingConfig) setOrClear(EDGE, isEdgeRouter);
public SegmentRoutingDeviceConfig setIsEdgeRouter(boolean isEdgeRouter) {
return (SegmentRoutingDeviceConfig) setOrClear(EDGE, isEdgeRouter);
}
/**
......@@ -197,7 +197,7 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
* @param adjacencySids adjacency SIDs of the router.
* @return the config of the router.
*/
public SegmentRoutingConfig setAdjacencySids(Map<Integer, Set<Integer>> adjacencySids) {
public SegmentRoutingDeviceConfig setAdjacencySids(Map<Integer, Set<Integer>> adjacencySids) {
if (adjacencySids == null) {
object.remove(ADJSIDS);
} else {
......
/*
* Copyright 2016 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.config;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableSet;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.TestApplicationId;
import org.onosproject.net.config.Config;
import org.onosproject.net.config.ConfigApplyDelegate;
import org.onosproject.segmentrouting.SegmentRoutingService;
import java.util.Set;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* Tests for class {@link SegmentRoutingAppConfig}.
*/
public class SegmentRoutingAppConfigTest {
private static final ApplicationId APP_ID =
new TestApplicationId(SegmentRoutingService.SR_APP_ID);
private SegmentRoutingAppConfig config;
private MacAddress routerMac1;
private MacAddress routerMac2;
private MacAddress routerMac3;
/**
* Initialize test related variables.
*
* @throws Exception
*/
@Before
public void setUp() throws Exception {
String jsonString = "{" +
"\"vRouterMacs\" : [" +
" \"00:00:00:00:00:01\"," +
" \"00:00:00:00:00:02\"" +
"]}";
routerMac1 = MacAddress.valueOf("00:00:00:00:00:01");
routerMac2 = MacAddress.valueOf("00:00:00:00:00:02");
routerMac3 = MacAddress.valueOf("00:00:00:00:00:03");
ApplicationId subject = APP_ID;
String key = SegmentRoutingService.SR_APP_ID;
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(jsonString);
ConfigApplyDelegate delegate = new MockDelegate();
config = new SegmentRoutingAppConfig();
config.init(subject, key, jsonNode, mapper, delegate);
}
/**
* Tests vRouters getter.
*
* @throws Exception
*/
@Test
public void testVRouters() throws Exception {
assertTrue(config.isValid());
Set<MacAddress> vRouters = config.vRouterMacs();
assertThat(vRouters.size(), is(2));
assertTrue(vRouters.contains(routerMac1));
assertTrue(vRouters.contains(routerMac2));
}
/**
* Tests vRouters setter.
*
* @throws Exception
*/
@Test
public void testSetVRouters() throws Exception {
ImmutableSet.Builder<MacAddress> builder = ImmutableSet.builder();
builder.add(routerMac3);
config.setVRouterMacs(builder.build());
Set<MacAddress> macs = config.vRouterMacs();
assertThat(macs.size(), is(1));
assertTrue(macs.contains(routerMac3));
}
private class MockDelegate implements ConfigApplyDelegate {
@Override
public void onApply(Config config) {
}
}
}
\ No newline at end of file
......@@ -36,10 +36,10 @@ import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertTrue;
/**
* Tests for class {@link SegmentRoutingConfig}.
* Tests for class {@link SegmentRoutingDeviceConfig}.
*/
public class SegmentRoutingConfigTest {
private SegmentRoutingConfig config;
public class SegmentRoutingDeviceConfigTest {
private SegmentRoutingDeviceConfig config;
private Map<Integer, Set<Integer>> adjacencySids1;
private Map<Integer, Set<Integer>> adjacencySids2;
......@@ -72,12 +72,12 @@ public class SegmentRoutingConfigTest {
adjacencySids2.put(300, ports3);
DeviceId subject = DeviceId.deviceId("of:0000000000000001");
String key = "org.onosproject.segmentrouting";
String key = "segmentrouting";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(jsonString);
ConfigApplyDelegate delegate = new MockDelegate();
config = new SegmentRoutingConfig();
config = new SegmentRoutingDeviceConfig();
config.init(subject, key, jsonNode, mapper, delegate);
}
......
......@@ -44,8 +44,9 @@ public final class PortNumber {
static final long NORMAL_NUMBER = -6L;
static final long FLOOD_NUMBER = -5L;
static final long ALL_NUMBER = -4L;
static final long LOCAL_NUMBER = -2L;
static final long CONTROLLER_NUMBER = -3L;
static final long LOCAL_NUMBER = -2L;
static final long ANY_NUMBER = -1L;
/**
* Logical PortNumbers.
......@@ -57,7 +58,8 @@ public final class PortNumber {
FLOOD(FLOOD_NUMBER),
ALL(ALL_NUMBER),
LOCAL(LOCAL_NUMBER),
CONTROLLER(CONTROLLER_NUMBER);
CONTROLLER(CONTROLLER_NUMBER),
ANY(ANY_NUMBER);
private final long number;
private final PortNumber instance;
......@@ -88,6 +90,7 @@ public final class PortNumber {
public static final PortNumber ALL = new PortNumber(ALL_NUMBER);
public static final PortNumber LOCAL = new PortNumber(LOCAL_NUMBER);
public static final PortNumber CONTROLLER = new PortNumber(CONTROLLER_NUMBER);
public static final PortNumber ANY = new PortNumber(ANY_NUMBER);
// lazily populated Logical port number to PortNumber
static final Supplier<Map<Long, Logical>> LOGICAL = Suppliers.memoize(() -> {
......
......@@ -25,6 +25,7 @@ import java.util.List;
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 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
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 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
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 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
log.warn("Cannot process instruction in versatile fwd {}", ins);
}
}
ttBuilder.wipeDeferred();
}
if (fwd.nextId() != null) {
// overide case
......
......@@ -78,6 +78,11 @@ public class CpqdOFDPA2VlanPipeline extends CpqdOFDPA2Pipeline {
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);
......
......@@ -6,6 +6,7 @@ import com.google.common.cache.CacheBuilder;
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 @@ public class OFDPA2GroupHandler {
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 @@ public class OFDPA2GroupHandler {
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 @@ public class OFDPA2GroupHandler {
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 @@ public class OFDPA2GroupHandler {
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(
......
......@@ -27,6 +27,7 @@ import java.util.Objects;
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 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
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 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
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:
......
......@@ -23,6 +23,7 @@ import com.google.common.cache.CacheBuilder;
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 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
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 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
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 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
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,
......
{
"ports" : {
"of:0000000000000001/3" : {
"interfaces" : [
{
"ips" : [ "10.0.1.254/24" ],
"vlan" : "-1"
}
]
},
"of:0000000000000001/4" : {
"interfaces" : [
{
"ips" : [ "10.0.1.254/24", "200.0.0.200/32" ],
"vlan" : "-1"
}
]
},
"of:0000000000000002/3" : {
"interfaces" : [
{
"ips" : [ "10.0.2.254/24" ],
"vlan" : "-1"
}
]
},
"of:0000000000000002/4" : {
"interfaces" : [
{
"ips" : [ "10.0.2.254/24", "0.0.0.0/0" ],
"vlan" : "-1"
}
]
}
},
"devices" : {
"of:0000000000000001" : {
"segmentrouting" : {
"name" : "Leaf-R1",
"nodeSid" : 101,
"routerIp" : "10.0.1.254",
"routerMac" : "00:00:00:00:01:80",
"isEdgeRouter" : true,
"adjacencySids" : []
}
},
"of:0000000000000002" : {
"segmentrouting" : {
"name" : "Leaf-R2",
"nodeSid" : 102,
"routerIp" : "10.0.2.254",
"routerMac" : "00:00:00:00:02:80",
"isEdgeRouter" : true,
"adjacencySids" : []
}
},
"of:0000000000000191" : {
"segmentrouting" : {
"name" : "Spine-R1",
"nodeSid" : 103,
"routerIp" : "192.168.0.11",
"routerMac" : "00:00:01:00:11:80",
"isEdgeRouter" : false,
"adjacencySids" : []
}
},
"of:0000000000000192" : {
"segmentrouting" : {
"name" : "Spine-R2",
"nodeSid" : 104,
"routerIp" : "192.168.0.22",
"routerMac" : "00:00:01:00:22:80",
"isEdgeRouter" : false,
"adjacencySids" : []
}
}
},
"hosts" : {
"00:00:00:00:00:01/-1" : {
"basic": {
"ips": ["10.0.1.1"],
"location": "of:0000000000000001/3"
}
},
"00:00:00:00:00:02/-1" : {
"basic": {
"ips": ["10.0.1.2"],
"location": "of:0000000000000001/4"
}
},
"00:00:00:00:00:03/-1" : {
"basic": {
"ips": ["10.0.2.1"],
"location": "of:0000000000000002/3"
}
},
"00:00:00:00:00:04/-1" : {
"basic": {
"ips": ["10.0.2.2"],
"location": "of:0000000000000002/4"
}
},
"00:00:00:aa:00:01/-1" : {
"basic": {
"ips": ["200.0.0.200"],
"location": "of:0000000000000001/4"
}
}
},
"apps" : {
"org.onosproject.segmentrouting" : {
"segmentrouting" : {
"vRouterMacs" : [
"00:00:00:aa:00:02"
]
}
}
}
}
......@@ -86,25 +86,25 @@
}
},
"hosts" : {
"00:00:00:00:00:01/4093" : {
"00:00:00:00:00:01/-1" : {
"basic": {
"ips": ["10.0.1.1"],
"location": "of:0000000000000001/3"
}
},
"00:00:00:00:00:02/4093" : {
"00:00:00:00:00:02/-1" : {
"basic": {
"ips": ["10.0.1.2"],
"location": "of:0000000000000001/4"
}
},
"00:00:00:00:00:03/4093" : {
"00:00:00:00:00:03/-1" : {
"basic": {
"ips": ["10.0.2.1"],
"location": "of:0000000000000002/3"
}
},
"00:00:00:00:00:04/4093" : {
"00:00:00:00:00:04/-1" : {
"basic": {
"ips": ["10.0.2.2"],
"location": "of:0000000000000002/4"
......
......@@ -148,49 +148,49 @@
}
},
"hosts" : {
"00:00:00:00:00:01/4093" : {
"00:00:00:00:00:01/-1" : {
"basic": {
"ips": ["10.0.1.1"],
"location": "of:0000000000000001/5"
}
},
"00:00:00:00:00:02/4093" : {
"00:00:00:00:00:02/-1" : {
"basic": {
"ips": ["10.0.1.2"],
"location": "of:0000000000000001/6"
}
},
"00:00:00:00:00:03/4093" : {
"00:00:00:00:00:03/-1" : {
"basic": {
"ips": ["10.0.2.1"],
"location": "of:0000000000000002/5"
}
},
"00:00:00:00:00:04/4093" : {
"00:00:00:00:00:04/-1" : {
"basic": {
"ips": ["10.0.2.2"],
"location": "of:0000000000000002/6"
}
},
"00:00:00:00:00:05/4093" : {
"00:00:00:00:00:05/-1" : {
"basic": {
"ips": ["10.0.3.1"],
"location": "of:0000000000000003/5"
}
},
"00:00:00:00:00:06/4093" : {
"00:00:00:00:00:06/-1" : {
"basic": {
"ips": ["10.0.3.2"],
"location": "of:0000000000000003/6"
}
},
"00:00:00:00:00:07/4093" : {
"00:00:00:00:00:07/-1" : {
"basic": {
"ips": ["10.0.4.1"],
"location": "of:0000000000000004/5"
}
},
"00:00:00:00:00:08/4093" : {
"00:00:00:00:00:08/-1" : {
"basic": {
"ips": ["10.0.4.2"],
"location": "of:0000000000000004/6"
......