Charles Chan

CORD-60 Support dynamic vSG creation/deletion

We no longer need to configure /32 IP in interfaces.
SR will push a per-host route when discovering a host
with IP address(es) that does not belong to configured subnet.

Also includes:
- HostHandler refactoring

Change-Id: Ic1ad42d1ccdfee32be85f49e6fc94d9026000ffc
......@@ -15,11 +15,13 @@
*/
package org.onosproject.segmentrouting;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpPrefix;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
......@@ -45,9 +47,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
* routing rule population.
*/
public class DefaultRoutingHandler {
private static Logger log = LoggerFactory
.getLogger(DefaultRoutingHandler.class);
private static final int MAX_RETRY_ATTEMPTS = 5;
private static final String ECMPSPG_MISSING = "ECMP shortest path graph not found";
private static Logger log = LoggerFactory.getLogger(DefaultRoutingHandler.class);
private SegmentRoutingManager srManager;
private RoutingRulePopulator rulePopulator;
......@@ -56,7 +58,6 @@ public class DefaultRoutingHandler {
private DeviceConfiguration config;
private final Lock statusLock = new ReentrantLock();
private volatile Status populationStatus;
private static final int MAX_RETRY_ATTEMPTS = 5;
private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
/**
......@@ -113,7 +114,7 @@ public class DefaultRoutingHandler {
}
EcmpShortestPathGraph ecmpSpg = new EcmpShortestPathGraph(sw.id(), srManager);
if (!populateEcmpRoutingRules(sw.id(), ecmpSpg)) {
if (!populateEcmpRoutingRules(sw.id(), ecmpSpg, ImmutableSet.of())) {
log.debug("populateAllRoutingRules: populationStatus is ABORTED");
populationStatus = Status.ABORTED;
log.debug("Abort routing rule population");
......@@ -210,7 +211,7 @@ public class DefaultRoutingHandler {
if (link.size() == 1) {
log.trace("repopulateRoutingRulesForRoutes: running ECMP graph for device {}", link.get(0));
EcmpShortestPathGraph ecmpSpg = new EcmpShortestPathGraph(link.get(0), srManager);
if (populateEcmpRoutingRules(link.get(0), ecmpSpg)) {
if (populateEcmpRoutingRules(link.get(0), ecmpSpg, ImmutableSet.of())) {
log.debug("Populating flow rules from {} to all is successful",
link.get(0));
currentEcmpSpgMap.put(link.get(0), ecmpSpg);
......@@ -255,7 +256,8 @@ public class DefaultRoutingHandler {
nextHops.add(via.get(0));
}
}
if (!populateEcmpRoutingRulePartial(targetSw, dst, nextHops)) {
if (!populateEcmpRoutingRulePartial(targetSw, dst,
nextHops, ImmutableSet.of())) {
return false;
}
log.debug("Populating flow rules from {} to {} is successful",
......@@ -422,8 +424,17 @@ public class DefaultRoutingHandler {
return subLinks;
}
/**
* Populate ECMP rules for subnets from all switches to destination.
*
* @param destSw Device ID of destination switch
* @param ecmpSPG ECMP shortest path graph
* @param subnets Subnets to be populated. If empty, populate all configured subnets.
* @return true if succeed
*/
private boolean populateEcmpRoutingRules(DeviceId destSw,
EcmpShortestPathGraph ecmpSPG) {
EcmpShortestPathGraph ecmpSPG,
Set<Ip4Prefix> subnets) {
HashMap<Integer, HashMap<DeviceId, ArrayList<ArrayList<DeviceId>>>> switchVia = ecmpSPG
.getAllLearnedSwitchesAndVia();
......@@ -440,7 +451,7 @@ public class DefaultRoutingHandler {
nextHops.add(via.get(0));
}
}
if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops)) {
if (!populateEcmpRoutingRulePartial(targetSw, destSw, nextHops, subnets)) {
return false;
}
}
......@@ -449,9 +460,19 @@ public class DefaultRoutingHandler {
return true;
}
/**
* Populate ECMP rules for subnets from target to destination via nexthops.
*
* @param targetSw Device ID of target switch
* @param destSw Device ID of destination switch
* @param nextHops List of next hops
* @param subnets Subnets to be populated. If empty, populate all configured subnets.
* @return true if succeed
*/
private boolean populateEcmpRoutingRulePartial(DeviceId targetSw,
DeviceId destSw,
Set<DeviceId> nextHops) {
Set<DeviceId> nextHops,
Set<Ip4Prefix> subnets) {
boolean result;
if (nextHops.isEmpty()) {
......@@ -473,13 +494,11 @@ public class DefaultRoutingHandler {
}
if (targetIsEdge && destIsEdge) {
Set<Ip4Prefix> subnets = config.getSubnets(destSw);
subnets = (subnets != null && !subnets.isEmpty()) ? subnets : config.getSubnets(destSw);
log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}",
targetSw, destSw, subnets);
result = rulePopulator.populateIpRuleForSubnet(targetSw,
subnets,
destSw,
nextHops);
result = rulePopulator.populateIpRuleForSubnet(targetSw, subnets,
destSw, nextHops);
if (!result) {
return false;
}
......@@ -575,18 +594,54 @@ public class DefaultRoutingHandler {
}
}
public void purgeEcmpGraph(DeviceId deviceId) {
/**
* Populate rules of given subnet at given location.
*
* @param cp connect point of the subnet being added
* @param subnets subnet being added
* @return true if succeed
*/
protected boolean populateSubnet(ConnectPoint cp, Set<Ip4Prefix> subnets) {
statusLock.lock();
try {
EcmpShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(cp.deviceId());
if (ecmpSpg == null) {
log.warn("Fail to populating subnet {}: {}", subnets, ECMPSPG_MISSING);
return false;
}
return populateEcmpRoutingRules(cp.deviceId(), ecmpSpg, subnets);
} finally {
statusLock.unlock();
}
}
/**
* Revoke rules of given subnet at given location.
*
* @param subnets subnet being removed
* @return true if succeed
*/
protected boolean revokeSubnet(Set<Ip4Prefix> subnets) {
statusLock.lock();
try {
return srManager.routingRulePopulator.revokeIpRuleForSubnet(subnets);
} finally {
statusLock.unlock();
}
}
protected void purgeEcmpGraph(DeviceId deviceId) {
currentEcmpSpgMap.remove(deviceId);
if (updatedEcmpSpgMap != null) {
updatedEcmpSpgMap.remove(deviceId);
}
}
private class RetryFilters implements Runnable {
private final class RetryFilters implements Runnable {
int attempts = MAX_RETRY_ATTEMPTS;
DeviceId devId;
public RetryFilters(DeviceId deviceId) {
private RetryFilters(DeviceId deviceId) {
devId = deviceId;
}
......
......@@ -16,13 +16,15 @@
package org.onosproject.segmentrouting;
import com.google.common.collect.ImmutableSet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.CoreService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
......@@ -46,7 +48,6 @@ import java.util.Set;
public class HostHandler {
private static final Logger log = LoggerFactory.getLogger(HostHandler.class);
private final SegmentRoutingManager srManager;
private CoreService coreService;
private HostService hostService;
private FlowObjectiveService flowObjectiveService;
......@@ -57,7 +58,6 @@ public class HostHandler {
*/
public HostHandler(SegmentRoutingManager srManager) {
this.srManager = srManager;
coreService = srManager.coreService;
hostService = srManager.hostService;
flowObjectiveService = srManager.flowObjectiveService;
}
......@@ -65,116 +65,46 @@ public class HostHandler {
protected void readInitialHosts(DeviceId devId) {
hostService.getHosts().forEach(host -> {
DeviceId deviceId = host.location().deviceId();
// The host does not attach to this device
if (!deviceId.equals(devId)) {
// not an attached host to this device
return;
}
MacAddress mac = host.mac();
VlanId vlanId = host.vlan();
PortNumber port = host.location().port();
Set<IpAddress> ips = host.ipAddresses();
log.debug("Attached Host {}/{} is added at {}:{}", mac, vlanId,
deviceId, port);
// Populate bridging table entry
ForwardingObjective.Builder fob =
getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
if (fob == null) {
log.warn("Aborting host bridging & routing table entries due "
+ "to error for dev:{} host:{}", deviceId, host);
return;
}
ObjectiveContext context = new DefaultObjectiveContext(
(objective) -> log.debug("Host rule for {} populated", host),
(objective, error) ->
log.warn("Failed to populate host rule for {}: {}", host, error));
flowObjectiveService.forward(deviceId, fob.add(context));
// Populate IP table entry
ips.forEach(ip -> {
if (ip.isIp4()) {
srManager.routingRulePopulator.populateIpRuleForHost(
deviceId, ip.getIp4Address(), mac, port);
}
});
processHostAddedEventInternal(host.mac(), host.vlan(),
host.location(), host.ipAddresses());
});
}
private ForwardingObjective.Builder getForwardingObjectiveBuilder(
DeviceId deviceId, MacAddress mac, VlanId vlanId,
PortNumber outport) {
// Get assigned VLAN for the subnet
VlanId outvlan = null;
Ip4Prefix subnet = srManager.deviceConfiguration.getPortSubnet(deviceId, outport);
if (subnet == null) {
outvlan = VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET);
} else {
outvlan = srManager.getSubnetAssignedVlanId(deviceId, subnet);
}
// match rule
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
sbuilder.matchEthDst(mac);
/*
* Note: for untagged packets, match on the assigned VLAN.
* for tagged packets, match on its incoming VLAN.
*/
if (vlanId.equals(VlanId.NONE)) {
sbuilder.matchVlanId(outvlan);
} else {
sbuilder.matchVlanId(vlanId);
}
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
tbuilder.immediate().popVlan();
tbuilder.immediate().setOutput(outport);
// for switch pipelines that need it, provide outgoing vlan as metadata
TrafficSelector meta = DefaultTrafficSelector.builder()
.matchVlanId(outvlan).build();
// All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outport,
tbuilder.build(),
meta);
if (portNextObjId == -1) {
// warning log will come from getPortNextObjective method
return null;
}
return DefaultForwardingObjective.builder()
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.withSelector(sbuilder.build())
.nextStep(portNextObjId)
.withPriority(100)
.fromApp(srManager.appId)
.makePermanent();
protected void processHostAddedEvent(HostEvent event) {
processHostAddedEventInternal(event.subject().mac(), event.subject().vlan(),
event.subject().location(), event.subject().ipAddresses());
}
protected void processHostAddedEvent(HostEvent event) {
MacAddress mac = event.subject().mac();
VlanId vlanId = event.subject().vlan();
DeviceId deviceId = event.subject().location().deviceId();
PortNumber port = event.subject().location().port();
Set<IpAddress> ips = event.subject().ipAddresses();
private void processHostAddedEventInternal(MacAddress mac, VlanId vlanId,
HostLocation location, Set<IpAddress> ips) {
DeviceId deviceId = location.deviceId();
PortNumber port = location.port();
log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
if (!srManager.deviceConfiguration.suppressHost()
.contains(new ConnectPoint(deviceId, port))) {
if (!srManager.deviceConfiguration.suppressHost().contains(location)) {
// Populate bridging table entry
log.debug("Populate L2 table entry for host {} at {}:{}",
mac, deviceId, port);
ForwardingObjective.Builder fob =
getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
hostFwdObjBuilder(deviceId, mac, vlanId, port);
if (fob == null) {
log.warn("Fail to create fwd obj for host {}/{}. Abort.", mac, vlanId);
return;
}
ObjectiveContext context = new DefaultObjectiveContext(
(objective) -> log.debug("Host rule for {} populated", event.subject()),
(objective) -> log.debug("Host rule for {}/{} populated", mac, vlanId),
(objective, error) ->
log.warn("Failed to populate host rule for {}: {}", event.subject(), error));
log.warn("Failed to populate host rule for {}/{}: {}", mac, vlanId, error));
flowObjectiveService.forward(deviceId, fob.add(context));
// Populate IP table entry
ips.forEach(ip -> {
// Populate IP table entry
if (ip.isIp4()) {
addPerHostRoute(location, ip.getIp4Address());
srManager.routingRulePopulator.populateIpRuleForHost(
deviceId, ip.getIp4Address(), mac, port);
}
......@@ -185,8 +115,9 @@ public class HostHandler {
protected void processHostRemoveEvent(HostEvent event) {
MacAddress mac = event.subject().mac();
VlanId vlanId = event.subject().vlan();
DeviceId deviceId = event.subject().location().deviceId();
PortNumber port = event.subject().location().port();
HostLocation location = event.subject().location();
DeviceId deviceId = location.deviceId();
PortNumber port = location.port();
Set<IpAddress> ips = event.subject().ipAddresses();
log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
......@@ -194,7 +125,11 @@ public class HostHandler {
.contains(new ConnectPoint(deviceId, port))) {
// Revoke bridging table entry
ForwardingObjective.Builder fob =
getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
hostFwdObjBuilder(deviceId, mac, vlanId, port);
if (fob == null) {
log.warn("Fail to create fwd obj for host {}/{}. Abort.", mac, vlanId);
return;
}
ObjectiveContext context = new DefaultObjectiveContext(
(objective) -> log.debug("Host rule for {} revoked", event.subject()),
(objective, error) ->
......@@ -204,6 +139,7 @@ public class HostHandler {
// Revoke IP table entry
ips.forEach(ip -> {
if (ip.isIp4()) {
removePerHostRoute(location, ip.getIp4Address());
srManager.routingRulePopulator.revokeIpRuleForHost(
deviceId, ip.getIp4Address(), mac, port);
}
......@@ -214,11 +150,13 @@ public class HostHandler {
protected void processHostMovedEvent(HostEvent event) {
MacAddress mac = event.subject().mac();
VlanId vlanId = event.subject().vlan();
DeviceId prevDeviceId = event.prevSubject().location().deviceId();
PortNumber prevPort = event.prevSubject().location().port();
HostLocation prevLocation = event.prevSubject().location();
DeviceId prevDeviceId = prevLocation.deviceId();
PortNumber prevPort = prevLocation.port();
Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
DeviceId newDeviceId = event.subject().location().deviceId();
PortNumber newPort = event.subject().location().port();
HostLocation newLocation = event.subject().location();
DeviceId newDeviceId = newLocation.deviceId();
PortNumber newPort = newLocation.port();
Set<IpAddress> newIps = event.subject().ipAddresses();
log.debug("Host {}/{} is moved from {}:{} to {}:{}",
mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
......@@ -227,7 +165,11 @@ public class HostHandler {
.contains(new ConnectPoint(prevDeviceId, prevPort))) {
// Revoke previous bridging table entry
ForwardingObjective.Builder prevFob =
getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
hostFwdObjBuilder(prevDeviceId, mac, vlanId, prevPort);
if (prevFob == null) {
log.warn("Fail to create fwd obj for host {}/{}. Abort.", mac, vlanId);
return;
}
ObjectiveContext context = new DefaultObjectiveContext(
(objective) -> log.debug("Host rule for {} revoked", event.subject()),
(objective, error) ->
......@@ -237,6 +179,7 @@ public class HostHandler {
// Revoke previous IP table entry
prevIps.forEach(ip -> {
if (ip.isIp4()) {
removePerHostRoute(prevLocation, ip.getIp4Address());
srManager.routingRulePopulator.revokeIpRuleForHost(
prevDeviceId, ip.getIp4Address(), mac, prevPort);
}
......@@ -247,7 +190,11 @@ public class HostHandler {
.contains(new ConnectPoint(newDeviceId, newPort))) {
// Populate new bridging table entry
ForwardingObjective.Builder newFob =
getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
hostFwdObjBuilder(newDeviceId, mac, vlanId, newPort);
if (newFob == null) {
log.warn("Fail to create fwd obj for host {}/{}. Abort.", mac, vlanId);
return;
}
ObjectiveContext context = new DefaultObjectiveContext(
(objective) -> log.debug("Host rule for {} populated", event.subject()),
(objective, error) ->
......@@ -257,6 +204,7 @@ public class HostHandler {
// Populate new IP table entry
newIps.forEach(ip -> {
if (ip.isIp4()) {
addPerHostRoute(newLocation, ip.getIp4Address());
srManager.routingRulePopulator.populateIpRuleForHost(
newDeviceId, ip.getIp4Address(), mac, newPort);
}
......@@ -267,11 +215,13 @@ public class HostHandler {
protected void processHostUpdatedEvent(HostEvent event) {
MacAddress mac = event.subject().mac();
VlanId vlanId = event.subject().vlan();
DeviceId prevDeviceId = event.prevSubject().location().deviceId();
PortNumber prevPort = event.prevSubject().location().port();
HostLocation prevLocation = event.prevSubject().location();
DeviceId prevDeviceId = prevLocation.deviceId();
PortNumber prevPort = prevLocation.port();
Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
DeviceId newDeviceId = event.subject().location().deviceId();
PortNumber newPort = event.subject().location().port();
HostLocation newLocation = event.subject().location();
DeviceId newDeviceId = newLocation.deviceId();
PortNumber newPort = newLocation.port();
Set<IpAddress> newIps = event.subject().ipAddresses();
log.debug("Host {}/{} is updated", mac, vlanId);
......@@ -280,6 +230,7 @@ public class HostHandler {
// Revoke previous IP table entry
prevIps.forEach(ip -> {
if (ip.isIp4()) {
removePerHostRoute(prevLocation, ip.getIp4Address());
srManager.routingRulePopulator.revokeIpRuleForHost(
prevDeviceId, ip.getIp4Address(), mac, prevPort);
}
......@@ -291,10 +242,106 @@ public class HostHandler {
// Populate new IP table entry
newIps.forEach(ip -> {
if (ip.isIp4()) {
addPerHostRoute(newLocation, ip.getIp4Address());
srManager.routingRulePopulator.populateIpRuleForHost(
newDeviceId, ip.getIp4Address(), mac, newPort);
}
});
}
}
/**
* Generates the forwarding objective builder for the host rules.
*
* @param deviceId Device that host attaches to
* @param mac MAC address of the host
* @param vlanId VLAN ID of the host
* @param outport Port that host attaches to
* @return Forwarding objective builder
*/
private ForwardingObjective.Builder hostFwdObjBuilder(
DeviceId deviceId, MacAddress mac, VlanId vlanId,
PortNumber outport) {
// Get assigned VLAN for the subnets
VlanId outvlan = null;
Ip4Prefix subnet = srManager.deviceConfiguration.getPortSubnet(deviceId, outport);
if (subnet == null) {
outvlan = VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET);
} else {
outvlan = srManager.getSubnetAssignedVlanId(deviceId, subnet);
}
// match rule
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
sbuilder.matchEthDst(mac);
/*
* Note: for untagged packets, match on the assigned VLAN.
* for tagged packets, match on its incoming VLAN.
*/
if (vlanId.equals(VlanId.NONE)) {
sbuilder.matchVlanId(outvlan);
} else {
sbuilder.matchVlanId(vlanId);
}
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
tbuilder.immediate().popVlan();
tbuilder.immediate().setOutput(outport);
// for switch pipelines that need it, provide outgoing vlan as metadata
TrafficSelector meta = DefaultTrafficSelector.builder()
.matchVlanId(outvlan).build();
// All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outport,
tbuilder.build(),
meta);
if (portNextObjId == -1) {
// warning log will come from getPortNextObjective method
return null;
}
return DefaultForwardingObjective.builder()
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.withSelector(sbuilder.build())
.nextStep(portNextObjId)
.withPriority(100)
.fromApp(srManager.appId)
.makePermanent();
}
/**
* Add per host route to subnet list and populate the flow rule if the host
* does not belong to the configured subnet.
*
* @param location location of the host being added
* @param ip IP address of the host being added
*/
private void addPerHostRoute(ConnectPoint location, Ip4Address ip) {
Ip4Prefix portSubnet = srManager.deviceConfiguration.getPortSubnet(
location.deviceId(), location.port());
if (portSubnet != null && !portSubnet.contains(ip)) {
Ip4Prefix ip4Prefix = ip.toIpPrefix().getIp4Prefix();
srManager.deviceConfiguration.addSubnet(location, ip4Prefix);
srManager.defaultRoutingHandler.populateSubnet(location,
ImmutableSet.of(ip4Prefix));
}
}
/**
* Remove per host route from subnet list and revoke the flow rule if the
* host does not belong to the configured subnet.
*
* @param location location of the host being removed
* @param ip IP address of the host being removed
*/
private void removePerHostRoute(ConnectPoint location, Ip4Address ip) {
Ip4Prefix portSubnet = srManager.deviceConfiguration.getPortSubnet(
location.deviceId(), location.port());
if (portSubnet != null && !portSubnet.contains(ip)) {
Ip4Prefix ip4Prefix = ip.toIpPrefix().getIp4Prefix();
srManager.deviceConfiguration.removeSubnet(location, ip4Prefix);
srManager.defaultRoutingHandler.revokeSubnet(ImmutableSet.of(ip4Prefix));
}
}
}
......
......@@ -212,22 +212,33 @@ public class RoutingRulePopulator {
* Populates IP flow rules for the subnets of the destination router.
*
* @param deviceId switch ID to set the rules
* @param subnets subnet information
* @param subnets subnet being added
* @param destSw destination switch ID
* @param nextHops next hop switch ID list
* @return true if all rules are set successfully, false otherwise
*/
public boolean populateIpRuleForSubnet(DeviceId deviceId,
Set<Ip4Prefix> subnets,
DeviceId destSw,
Set<DeviceId> nextHops) {
public boolean populateIpRuleForSubnet(DeviceId deviceId, Set<Ip4Prefix> subnets,
DeviceId destSw, Set<DeviceId> nextHops) {
for (IpPrefix subnet : subnets) {
if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
return false;
}
}
return true;
}
/**
* Revokes IP flow rules for the subnets.
*
* @param subnets subnet being removed
* @return true if all rules are removed successfully, false otherwise
*/
public boolean revokeIpRuleForSubnet(Set<Ip4Prefix> subnets) {
for (IpPrefix subnet : subnets) {
if (!revokeIpRuleForRouter(subnet)) {
return false;
}
}
return true;
}
......@@ -310,6 +321,40 @@ public class RoutingRulePopulator {
}
/**
* Revokes IP flow rules for the router IP address.
*
* @param ipPrefix the IP address of the destination router
* @return true if all rules are removed successfully, false otherwise
*/
public boolean revokeIpRuleForRouter(IpPrefix ipPrefix) {
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
sbuilder.matchIPDst(ipPrefix);
sbuilder.matchEthType(Ethernet.TYPE_IPV4);
TrafficSelector selector = sbuilder.build();
TrafficTreatment dummyTreatment = DefaultTrafficTreatment.builder().build();
ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
.builder()
.fromApp(srManager.appId)
.makePermanent()
.withSelector(selector)
.withTreatment(dummyTreatment)
.withPriority(getPriorityFromPrefix(ipPrefix))
.withFlag(ForwardingObjective.Flag.SPECIFIC);
ObjectiveContext context = new DefaultObjectiveContext(
(objective) -> log.debug("IP rule for router {} revoked", ipPrefix),
(objective, error) ->
log.warn("Failed to revoke IP rule for router {}: {}", ipPrefix, error));
srManager.deviceService.getAvailableDevices().forEach(device -> {
srManager.flowObjectiveService.forward(device.id(), fwdBuilder.remove(context));
});
return true;
}
/**
* Populates MPLS flow rules to all routers.
*
* @param deviceId target device ID of the switch to set the rules
......@@ -471,6 +516,7 @@ public class RoutingRulePopulator {
* that drivers can obtain other information (like Router MAC and IP).
*
* @param deviceId the switch dpid for the router
* @return true if operation succeeds
*/
public boolean populateRouterMacVlanFilters(DeviceId deviceId) {
log.debug("Installing per-port filtering objective for untagged "
......
......@@ -153,7 +153,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
protected ApplicationId appId;
protected DeviceConfiguration deviceConfiguration = null;
private DefaultRoutingHandler defaultRoutingHandler = null;
protected DefaultRoutingHandler defaultRoutingHandler = null;
private TunnelHandler tunnelHandler = null;
private PolicyHandler policyHandler = null;
private InternalPacketProcessor processor = null;
......
......@@ -46,6 +46,8 @@ import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Segment Routing configuration component that reads the
* segment routing related configuration from Network Configuration Manager
......@@ -167,7 +169,6 @@ public class DeviceConfiguration implements DeviceProperties {
}
}
});
});
}
......@@ -517,4 +518,38 @@ public class DeviceConfiguration implements DeviceProperties {
cfgService.getConfig(appId, SegmentRoutingAppConfig.class);
return (appConfig != null) ? appConfig.suppressHost() : ImmutableSet.of();
}
/**
* Add subnet to specific connect point.
*
* @param cp connect point
* @param ip4Prefix subnet being added to the device
*/
public void addSubnet(ConnectPoint cp, Ip4Prefix ip4Prefix) {
checkNotNull(cp);
checkNotNull(ip4Prefix);
SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
if (srinfo == null) {
log.warn("Device {} is not configured. Abort.", cp.deviceId());
return;
}
srinfo.subnets.put(cp.port(), ip4Prefix);
}
/**
* Remove subnet from specific connect point.
*
* @param cp connect point
* @param ip4Prefix subnet being removed to the device
*/
public void removeSubnet(ConnectPoint cp, Ip4Prefix ip4Prefix) {
checkNotNull(cp);
checkNotNull(ip4Prefix);
SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
if (srinfo == null) {
log.warn("Device {} is not configured. Abort.", cp.deviceId());
return;
}
srinfo.subnets.remove(cp.port(), ip4Prefix);
}
}
......
......@@ -18,10 +18,10 @@
span.s1 {font-kerning: none}
span.s2 {font-kerning: none; color: #0433ff; -webkit-text-stroke: 0px #0433ff}
span.s3 {font-kerning: none; color: #000000; -webkit-text-stroke: 0px #000000}
span.s4 {font-kerning: none; color: #ff40ff; -webkit-text-stroke: 0px #ff40ff}
span.s5 {font-kerning: none; color: #ff9300; -webkit-text-stroke: 0px #ff9300}
span.s6 {font-kerning: none; color: #77bb41; -webkit-text-stroke: 0px #77bb41}
span.s7 {font-kerning: none; color: #00c7fc; -webkit-text-stroke: 0px #00c7fc}
span.s4 {font-kerning: none; color: #ff9300; -webkit-text-stroke: 0px #ff9300}
span.s5 {font-kerning: none; color: #77bb41; -webkit-text-stroke: 0px #77bb41}
span.s6 {font-kerning: none; color: #00c7fc; -webkit-text-stroke: 0px #00c7fc}
span.s7 {font-kerning: none; color: #ff40ff; -webkit-text-stroke: 0px #ff40ff}
span.s8 {font-kerning: none; color: #ff2600; -webkit-text-stroke: 0px #ff2600}
span.s9 {font-kerning: none; color: #000000}
span.s10 {font-kerning: none; color: #669c35; -webkit-text-stroke: 0px #669c35}
......@@ -49,12 +49,6 @@
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>{</span></p>
<p class="p2"><span class="s3"><span class="Apple-converted-space">                </span>"vlan" : "222" </span><span class="s1">// cross-connect s-tag 222 to PMC OLT</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>{</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips" : [ "A.A.A.A/32" ] </span><span class="s4">// vSG1 public IP address /32</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>{</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips" : [ "B.B.B.B/32" ] </span><span class="s4">// vSG2 public IP address /32</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>]</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>},</span></p>
......@@ -65,25 +59,18 @@
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>]</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>},</span></p>
<p class="p3"><span class="s3"><span class="Apple-converted-space">    </span>"of:0000000000000001/30" : { </span><span class="s1">// connect to vSG3 directly without OLT (temporary)</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"interfaces" : [</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>{</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips" : [ "C.C.C.C/32" ] </span><span class="s4">// vSG3 /32 public IP address</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>]</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>"of:0000000000000001/65" : { </span><span class="s5">// connect to Fujitsu OLT</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>"of:0000000000000001/65" : { </span><span class="s4">// connect to Fujitsu OLT</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"interfaces" : [</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>{</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"name" : "fujitsu-olt", </span><span class="s5">// unused</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"name" : "fujitsu-olt", </span><span class="s4">// unused</span></p>
<p class="p2"><span class="s3"><span class="Apple-converted-space">                </span>"vlan" : "69" </span><span class="s1">// cross-connect s-tag 69<span class="Apple-converted-space">  </span>to vSG</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>]</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>"of:0000000000000001/73" : { </span><span class="s5">// connect to PMC OLT</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>"of:0000000000000001/73" : { </span><span class="s4">// connect to PMC OLT</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"interfaces" : [</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>{</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"name" : "pmc-olt", </span><span class="s5">// unused</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"name" : "pmc-olt", </span><span class="s4">// unused</span></p>
<p class="p2"><span class="s3"><span class="Apple-converted-space">                </span>"vlan" : "222" </span><span class="s1">// cross-connect s-tag 222 to vSG</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>]</span></p>
......@@ -95,16 +82,16 @@
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>]</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>"of:0000000000000002/32" : { </span><span class="s6">// connect to Internet router</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>"of:0000000000000002/32" : { </span><span class="s5">// connect to Internet router</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"interfaces" : [</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>{</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"name" : "external-quagga", </span><span class="s6">// Internet router interface name</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips" : [ "10.231.254.202/30", "10.231.254.223/32" ], </span><span class="s6">// Quagga IP addresses</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"mac" : "00:16:3e:56:2b:48" </span><span class="s6">// Quagga WAN MAC</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"name" : "external-quagga", </span><span class="s5">// Internet router interface name</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips" : [ "10.231.254.202/30", "10.231.254.223/32" ], </span><span class="s5">// Quagga IP addresses</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"mac" : "00:16:3e:56:2b:48" </span><span class="s5">// Quagga WAN MAC</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>],</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"pimInterface" : { </span><span class="s7">// PIM configuration</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"interfaceName" : "external-quagga", </span><span class="s7">// port that faces the Internet router</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"pimInterface" : { </span><span class="s6">// PIM configuration</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"interfaceName" : "external-quagga", </span><span class="s6">// port that faces the Internet router</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"enabled" : true,</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"helloInterval" : 1,</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"holdTime" : 3,</span></p>
......@@ -162,15 +149,15 @@
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"location": "of:0000000000000001/5" </span><span class="s2">// node 1 location</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"02:42:cf:8d:c0:82/-1" : { </span><span class="s4">// vSG1</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"02:42:cf:8d:c0:82/-1" : { </span><span class="s7">// vSG1</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"basic": {</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips": ["A.A.A.A"], </span><span class="s4">// vSG1 public IP address</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips": ["A.A.A.A"], </span><span class="s7">// vSG1 public IP address</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"location": "of:0000000000000001/5"</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"02:42:cf:8d:c0:83/-1" : { </span><span class="s4">// vSG2</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"02:42:cf:8d:c0:83/-1" : { </span><span class="s7">// vSG2</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"basic": {</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips": ["B.B.B.B"], </span><span class="s4">// vSG2 public IP address</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips": ["B.B.B.B"], </span><span class="s7">// vSG2 public IP address</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"location": "of:0000000000000001/5"</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>},</span></p>
......@@ -180,9 +167,9 @@
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"location": "of:0000000000000001/7"</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"74:44:01:74:61:92/-1" : { </span><span class="s4">// vSG3</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"74:44:01:74:61:92/-1" : { </span><span class="s7">// vSG3</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"basic": {</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips": ["C.C.C.C"], </span><span class="s4">// vSG3 public IP address</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ips": ["C.C.C.C"], </span><span class="s7">// vSG3 public IP address</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"location": "of:0000000000000001/30"</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>},</span></p>
......@@ -234,7 +221,7 @@
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"vRouterMacs" : [</span></p>
<p class="p3"><span class="s3"><span class="Apple-converted-space">                    </span>"a4:23:05:34:56:78" </span><span class="s1">// vRouter LAN MAC (vSG’s default gateway)</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>],</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"vRouterId" : "of:0000000000000002", </span><span class="s4">// vRouter DPID (0/0 is replaced by this)</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"vRouterId" : "of:0000000000000002", </span><span class="s7">// vRouter DPID (0/0 is replaced by this)</span></p>
<p class="p4"><span class="s3"><span class="Apple-converted-space">                 </span>"suppressSubnet" : [ </span><span class="s1">// Do not push subnet rules for these ports</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                    </span>"of:0000000000000002/31", "of:0000000000000002/32"</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>],</span></p>
......@@ -246,10 +233,10 @@
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>},</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>"org.onosproject.router" : {</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>"router" : {</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"controlPlaneConnectPoint" : "of:0000000000000002/31", </span><span class="s6">// location of Quagga</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ospfEnabled" : "true", </span><span class="s6">// enable OSPF</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"pimEnabled" : "true", </span><span class="s7">// enable PIM</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"interfaces" : [ "external-quagga" ] </span><span class="s10">// </span><span class="s6">VR only handles peers on these ports</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"controlPlaneConnectPoint" : "of:0000000000000002/31", </span><span class="s5">// location of Quagga</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"ospfEnabled" : "true", </span><span class="s5">// enable OSPF</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"pimEnabled" : "true", </span><span class="s6">// enable PIM</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">                </span>"interfaces" : [ "external-quagga" ] </span><span class="s10">// </span><span class="s5">VR only handles peers on these ports</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">            </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">        </span>}</span></p>
<p class="p7"><span class="s1"><span class="Apple-converted-space">    </span>}</span></p>
......
......@@ -13,12 +13,6 @@
},
{
"vlan" : "222"
},
{
"ips" : [
"A.A.A.146/32", "A.A.A.147/32", "A.A.A.148/32", "A.A.A.149/32",
"A.A.A.150/32", "A.A.A.151/32", "A.A.A.152/32", "A.A.A.153/32"
]
}
]
},
......@@ -52,9 +46,6 @@
"interfaces" : [
{
"ips" : [ "10.0.2.254/24" ]
},
{
"ips" : [ "A.A.A.130/32", "A.A.A.131/32" ]
}
]
},
......