Charles Chan
Committed by Gerrit Code Review

[CORD-200] Improves Segment Routing using Network Configuration Subsystem

The missing part of gerrit #5533

Change-Id: I0830aa80f9be0e9933a99e0c12518aef67008a53
......@@ -19,7 +19,12 @@ import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
import org.onosproject.incubator.net.config.basics.ConfigException;
import org.onosproject.incubator.net.config.basics.InterfaceConfig;
import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
import org.onosproject.segmentrouting.config.SegmentRoutingConfig.AdjacencySid;
import org.onosproject.segmentrouting.grouphandler.DeviceProperties;
......@@ -28,8 +33,6 @@ import org.onosproject.net.PortNumber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
......@@ -49,7 +52,6 @@ public class DeviceConfiguration implements DeviceProperties {
.getLogger(DeviceConfiguration.class);
private final List<Integer> allSegmentIds = new ArrayList<>();
private final HashMap<DeviceId, SegmentRouterInfo> deviceConfigMap = new HashMap<>();
private final NetworkConfigRegistry configService;
private class SegmentRouterInfo {
int nodeSid;
......@@ -65,33 +67,54 @@ public class DeviceConfiguration implements DeviceProperties {
/**
* Constructor. Reads all the configuration for all devices of type
* Segment Router and organizes into various maps for easier access.
*
* @param cfgService handle to network configuration manager
* component from where the relevant configuration is retrieved.
*/
public DeviceConfiguration(NetworkConfigRegistry cfgService) {
this.configService = checkNotNull(cfgService);
Set<DeviceId> subjectSet =
// Read config from device subject, excluding gatewayIps and subnets.
Set<DeviceId> deviceSubjects =
cfgService.getSubjects(DeviceId.class, SegmentRoutingConfig.class);
subjectSet.forEach(subject -> {
deviceSubjects.forEach(subject -> {
SegmentRoutingConfig config =
cfgService.getConfig(subject, SegmentRoutingConfig.class);
SegmentRouterInfo info = new SegmentRouterInfo();
info.nodeSid = config.getSid();
info.deviceId = subject;
info.nodeSid = config.getSid();
info.ip = config.getIp();
info.mac = config.getMac();
info.isEdge = config.isEdgeRouter();
// TODO fecth subnet and gateway information via port subject
info.adjacencySids = config.getAdjacencySids();
info.gatewayIps = new HashMap<>();
info.subnets = new HashMap<>();
info.adjacencySids = config.getAdjacencySids();
this.deviceConfigMap.put(info.deviceId, info);
this.allSegmentIds.add(info.nodeSid);
});
// Read gatewayIps and subnets from port subject.
Set<ConnectPoint> portSubjects =
cfgService.getSubjects(ConnectPoint.class, InterfaceConfig.class);
portSubjects.forEach(subject -> {
InterfaceConfig config =
cfgService.getConfig(subject, InterfaceConfig.class);
Set<Interface> networkInterfaces;
try {
networkInterfaces = config.getInterfaces();
} catch (ConfigException e) {
log.error("Error loading port configuration");
return;
}
networkInterfaces.forEach(networkInterface -> {
DeviceId dpid = networkInterface.connectPoint().deviceId();
PortNumber port = networkInterface.connectPoint().port();
SegmentRouterInfo info = this.deviceConfigMap.get(dpid);
Set<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddresses();
interfaceAddresses.forEach(interfaceAddress -> {
info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address());
info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix());
});
});
});
}
/**
......@@ -370,7 +393,7 @@ public class DeviceConfiguration implements DeviceProperties {
public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
if (deviceConfigMap.get(deviceId) != null) {
for (AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) {
if (asid.getSid() == sid) {
if (asid.getAsid() == sid) {
return asid.getPorts();
}
}
......@@ -394,7 +417,7 @@ public class DeviceConfiguration implements DeviceProperties {
} else {
for (AdjacencySid asid:
deviceConfigMap.get(deviceId).adjacencySids) {
if (asid.getSid() == sid) {
if (asid.getAsid() == sid) {
return true;
}
}
......
......@@ -141,7 +141,9 @@ public class SegmentRoutingManager implements SegmentRoutingService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry cfgService;
private final InternalConfigListener cfgListener = new InternalConfigListener();
private final InternalConfigListener cfgListener =
new InternalConfigListener(this);
private final ConfigFactory cfgFactory =
new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
SegmentRoutingConfig.class,
......@@ -211,40 +213,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
cfgService.addListener(cfgListener);
cfgService.registerConfigFactory(cfgFactory);
deviceConfiguration = new DeviceConfiguration(cfgService);
arpHandler = new ArpHandler(this);
icmpHandler = new IcmpHandler(this);
ipHandler = new IpHandler(this);
routingRulePopulator = new RoutingRulePopulator(this);
defaultRoutingHandler = new DefaultRoutingHandler(this);
tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
groupHandlerMap, tunnelStore);
policyHandler = new PolicyHandler(appId, deviceConfiguration,
flowObjectiveService, tunnelHandler, policyStore);
packetService.addProcessor(processor, PacketProcessor.director(2));
linkService.addListener(new InternalLinkListener());
deviceService.addListener(new InternalDeviceListener());
for (Device device : deviceService.getDevices()) {
//Irrespective whether the local is a MASTER or not for this device,
//create group handler instance and push default TTP flow rules.
//Because in a multi-instance setup, instances can initiate
//groups for any devices. Also the default TTP rules are needed
//to be pushed before inserting any IP table entries for any device
DefaultGroupHandler groupHandler = DefaultGroupHandler
.createGroupHandler(device.id(), appId,
deviceConfiguration, linkService,
flowObjectiveService,
nsNextObjStore);
groupHandlerMap.put(device.id(), groupHandler);
defaultRoutingHandler.populateTtpRules(device.id());
}
defaultRoutingHandler.startPopulationProcess();
log.info("Started");
}
@Deactivate
......@@ -535,12 +505,56 @@ public class SegmentRoutingManager implements SegmentRoutingService {
}
private class InternalConfigListener implements NetworkConfigListener {
SegmentRoutingManager segmentRoutingManager;
public InternalConfigListener(SegmentRoutingManager srMgr) {
this.segmentRoutingManager = srMgr;
}
public void configureNetwork() {
deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
arpHandler = new ArpHandler(segmentRoutingManager);
icmpHandler = new IcmpHandler(segmentRoutingManager);
ipHandler = new IpHandler(segmentRoutingManager);
routingRulePopulator = new RoutingRulePopulator(segmentRoutingManager);
defaultRoutingHandler = new DefaultRoutingHandler(segmentRoutingManager);
tunnelHandler = new TunnelHandler(linkService, deviceConfiguration,
groupHandlerMap, tunnelStore);
policyHandler = new PolicyHandler(appId, deviceConfiguration,
flowObjectiveService,
tunnelHandler, policyStore);
packetService.addProcessor(processor, PacketProcessor.director(2));
linkService.addListener(new InternalLinkListener());
deviceService.addListener(new InternalDeviceListener());
for (Device device : deviceService.getDevices()) {
//Irrespective whether the local is a MASTER or not for this device,
//create group handler instance and push default TTP flow rules.
//Because in a multi-instance setup, instances can initiate
//groups for any devices. Also the default TTP rules are needed
//to be pushed before inserting any IP table entries for any device
DefaultGroupHandler groupHandler = DefaultGroupHandler
.createGroupHandler(device.id(), appId,
deviceConfiguration, linkService,
flowObjectiveService,
nsNextObjStore);
groupHandlerMap.put(device.id(), groupHandler);
defaultRoutingHandler.populateTtpRules(device.id());
}
defaultRoutingHandler.startPopulationProcess();
}
@Override
public void event(NetworkConfigEvent event) {
if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
event.configClass().equals(SegmentRoutingConfig.class)) {
// TODO Support dynamic configuration in the future
log.info("Network configuration change detected. (Re)Configuring...");
configureNetwork();
return;
}
}
......
......@@ -16,6 +16,7 @@
package org.onosproject.segmentrouting.config;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onosproject.net.DeviceId;
......@@ -35,6 +36,7 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
private static final String MAC = "routerMac";
private static final String SID = "nodeSid";
private static final String EDGE = "isEdgeRouter";
private static final String ADJSID = "adjacencySids";
public Optional<String> getName() {
String name = get(NAME, null);
......@@ -79,22 +81,44 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
return (BasicElementConfig) setOrClear(EDGE, isEdgeRouter);
}
// TODO extract array from JsonNode
public List<AdjacencySid> getAdjacencySids() {
return new ArrayList<AdjacencySid>();
ArrayList<AdjacencySid> adjacencySids = new ArrayList<>();
if (!object.has(ADJSID)) {
return adjacencySids;
}
ArrayNode adjacencySidNodes = (ArrayNode) object.path(ADJSID);
adjacencySidNodes.forEach(adjacencySidNode -> {
int asid = adjacencySidNode.path(AdjacencySid.ASID).asInt();
ArrayList<Integer> ports = new ArrayList<Integer>();
ArrayNode portsNodes = (ArrayNode) adjacencySidNode.path(AdjacencySid.PORTS);
portsNodes.forEach(portNode -> {
ports.add(portNode.asInt());
});
AdjacencySid adjacencySid = new AdjacencySid(asid, ports);
adjacencySids.add(adjacencySid);
});
return adjacencySids;
}
public class AdjacencySid {
int sid;
private static final String ASID = "adjSid";
private static final String PORTS = "ports";
int asid;
List<Integer> ports;
public AdjacencySid(int sid, List<Integer> ports) {
this.sid = sid;
public AdjacencySid(int asid, List<Integer> ports) {
this.asid = asid;
this.ports = ports;
}
public int getSid() {
return sid;
public int getAsid() {
return asid;
}
public List<Integer> getPorts() {
......
......@@ -19,6 +19,30 @@
]
}
},
"devices" : {
"of:0000000000000002" : {
"segmentrouting" : {
"name" : "Leaf-R1",
"nodeSid" : 101,
"routerIp" : "10.0.1.254",
"routerMac" : "00:00:00:00:01:80",
"isEdgeRouter" : true,
"adjacencySids" : [
{ "sid" : 100, "port" : [2, 3] },
{ "sid" : 200, "port" : [4, 5] }
]
}
},
"of:0000000000000191" : {
"segmentrouting" : {
"name" : "Spine-R1",
"nodeSid" : 105,
"routerIp" : "192.168.0.11",
"routerMac" : "00:00:01:00:11:80",
"isEdgeRouter" : false
}
}
},
"apps" : {
"org.onosproject.router" : {
"bgp" : {
......
{
"comment": "Configuration for a 4X4 leaf-spine fabric",
"restrictSwitches": true,
"restrictLinks": true,
"switchConfig":
[
{ "nodeDpid" : "of:0000000000000001", "name": "Leaf-R1", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "10.0.1.254/32",
"routerMac": "00:00:00:00:01:80",
"nodeSid": 101,
"isEdgeRouter" : true,
"subnets": [
{ "portNo": 1, "subnetIp": "10.0.1.254/24" }
]
}
},
{ "nodeDpid": "of:0000000000000002", "name": "Leaf-R2", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "10.0.2.254/32",
"routerMac": "00:00:00:00:02:80",
"nodeSid": 102,
"isEdgeRouter" : true,
"subnets": [
{ "portNo": 1, "subnetIp": "10.0.2.254/24" }
]
}
},
{ "nodeDpid": "of:0000000000000003", "name": "Leaf-R3", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "10.0.3.101/32",
"routerMac": "00:00:00:00:03:80",
"nodeSid": 103,
"isEdgeRouter" : true,
"subnets": [
{ "portNo": 1, "subnetIp": "10.0.3.254/24" }
]
}
},
{ "nodeDpid": "of:0000000000000004", "name": "Leaf-R4", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "10.0.4.101/32",
"routerMac": "00:00:00:00:04:80",
"nodeSid": 104,
"isEdgeRouter" : true,
"subnets": [
{ "portNo": 1, "subnetIp": "10.0.4.254/24" }
]
}
},
{ "nodeDpid": "of:0000000000000191", "name": "Spine-R1", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "192.168.0.11/32",
"routerMac": "00:00:01:00:11:80",
"nodeSid": 105,
"isEdgeRouter" : false
}
},
{ "nodeDpid": "of:0000000000000192", "name": "Spine-R2", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "192.168.0.22/32",
"routerMac": "00:00:01:00:22:80",
"nodeSid": 106,
"isEdgeRouter" : false
}
},
{ "nodeDpid": "of:0000000000000193", "name": "Spine-R3", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "192.168.0.33/32",
"routerMac": "00:00:01:00:33:80",
"nodeSid": 107,
"isEdgeRouter" : false
}
},
{ "nodeDpid": "of:0000000000000194", "name": "Spine-R4", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "192.168.0.44/32",
"routerMac": "00:00:01:00:44:80",
"nodeSid": 108,
"isEdgeRouter" : false
}
}
]
}