Srikanth Vavilapalli
Committed by Gerrit Code Review

ONOS-685: Network Configuration Manager support for Segment Routing application

Change-Id: Ia15bfd24559dd5542633c8b76d500b2d31362340
Showing 25 changed files with 2077 additions and 486 deletions
/*
* Copyright 2015 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.grouphandler;
import static org.slf4j.LoggerFactory.getLogger;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.MacAddress;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.group.GroupService;
import org.onosproject.net.link.LinkEvent;
import org.onosproject.net.link.LinkListener;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.topology.TopologyService;
import org.slf4j.Logger;
/**
* Sample application to verify group subsystem end to end.
* This application expects a network of maximum of six connected
* devices for the test to work. For every device in the network,
* this test application launches a default group handler function
* that creates ECMP groups for every neighbor the device is
* connected to.
*/
@Component(immediate = true)
public class DefaultGroupHandlerApp {
private final Logger log = getLogger(getClass());
private final DeviceProperties config = new DeviceConfiguration();
private ApplicationId appId;
private HashMap<DeviceId, DefaultGroupHandler> dghMap =
new HashMap<DeviceId, DefaultGroupHandler>();
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkService linkService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected GroupService groupService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MastershipService mastershipService;
private DeviceListener deviceListener = new InternalDeviceListener();
private LinkListener linkListener = new InternalLinkListener();
protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
.register(URI.class)
.register(HashSet.class)
.register(DeviceId.class)
.register(NeighborSet.class);
@Activate
public void activate() {
appId = coreService.registerApplication("org.onosproject.defaultgrouphandler");
log.info("DefaultGroupHandlerApp Activating");
deviceService.addListener(deviceListener);
linkService.addListener(linkListener);
for (Device device: deviceService.getDevices()) {
if (mastershipService.
getLocalRole(device.id()) == MastershipRole.MASTER) {
log.debug("Initiating default group handling for {}", device.id());
DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler(device.id(),
appId,
config,
linkService,
groupService);
dgh.createGroups();
dghMap.put(device.id(), dgh);
} else {
log.debug("Activate: Local role {} "
+ "is not MASTER for device {}",
mastershipService.
getLocalRole(device.id()),
device.id());
}
}
log.info("Activated");
}
@Deactivate
public void deactivate() {
dghMap.clear();
}
public class DeviceConfiguration implements DeviceProperties {
private final List<Integer> allSegmentIds =
Arrays.asList(101, 102, 103, 104, 105, 106);
private HashMap<DeviceId, Integer> deviceSegmentIdMap =
new HashMap<DeviceId, Integer>() {
{
put(DeviceId.deviceId("of:0000000000000001"), 101);
put(DeviceId.deviceId("of:0000000000000002"), 102);
put(DeviceId.deviceId("of:0000000000000003"), 103);
put(DeviceId.deviceId("of:0000000000000004"), 104);
put(DeviceId.deviceId("of:0000000000000005"), 105);
put(DeviceId.deviceId("of:0000000000000006"), 106);
}
};
private final HashMap<DeviceId, MacAddress> deviceMacMap =
new HashMap<DeviceId, MacAddress>() {
{
put(DeviceId.deviceId("of:0000000000000001"),
MacAddress.valueOf("00:00:00:00:00:01"));
put(DeviceId.deviceId("of:0000000000000002"),
MacAddress.valueOf("00:00:00:00:00:02"));
put(DeviceId.deviceId("of:0000000000000003"),
MacAddress.valueOf("00:00:00:00:00:03"));
put(DeviceId.deviceId("of:0000000000000004"),
MacAddress.valueOf("00:00:00:00:00:04"));
put(DeviceId.deviceId("of:0000000000000005"),
MacAddress.valueOf("00:00:00:00:00:05"));
put(DeviceId.deviceId("of:0000000000000006"),
MacAddress.valueOf("00:00:00:00:00:06"));
}
};
@Override
public int getSegmentId(DeviceId deviceId) {
if (deviceSegmentIdMap.get(deviceId) != null) {
log.debug("getSegmentId for device{} is {}",
deviceId,
deviceSegmentIdMap.get(deviceId));
return deviceSegmentIdMap.get(deviceId);
} else {
throw new IllegalStateException();
}
}
@Override
public MacAddress getDeviceMac(DeviceId deviceId) {
if (deviceMacMap.get(deviceId) != null) {
log.debug("getDeviceMac for device{} is {}",
deviceId,
deviceMacMap.get(deviceId));
return deviceMacMap.get(deviceId);
} else {
throw new IllegalStateException();
}
}
@Override
public boolean isEdgeDevice(DeviceId deviceId) {
return true;
}
@Override
public List<Integer> getAllDeviceSegmentIds() {
return allSegmentIds;
}
}
private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
if (mastershipService.
getLocalRole(event.subject().id()) != MastershipRole.MASTER) {
log.debug("Local role {} is not MASTER for device {}",
mastershipService.
getLocalRole(event.subject().id()),
event.subject().id());
return;
}
switch (event.type()) {
case DEVICE_ADDED:
log.debug("Initiating default group handling for {}", event.subject().id());
DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler(
event.subject().id(),
appId,
config,
linkService,
groupService);
dgh.createGroups();
dghMap.put(event.subject().id(), dgh);
break;
case PORT_REMOVED:
if (dghMap.get(event.subject().id()) != null) {
dghMap.get(event.subject().id()).portDown(event.port().number());
}
break;
default:
break;
}
}
}
private class InternalLinkListener implements LinkListener {
@Override
public void event(LinkEvent event) {
if (mastershipService.
getLocalRole(event.subject().src().deviceId()) !=
MastershipRole.MASTER) {
log.debug("InternalLinkListener: Local role {} "
+ "is not MASTER for device {}",
mastershipService.
getLocalRole(event.subject().src().deviceId()),
event.subject().src().deviceId());
return;
}
switch (event.type()) {
case LINK_ADDED:
if (dghMap.get(event.subject().src().deviceId()) != null) {
dghMap.get(event.subject().src().deviceId()).linkUp(event.subject());
}
break;
default:
break;
}
}
}
}
\ No newline at end of file
......@@ -45,7 +45,6 @@
<module>reactive-routing</module>
<module>bgprouter</module>
<module>test</module>
<module>grouphandler</module>
<module>segmentrouting</module>
</modules>
......
......@@ -19,7 +19,6 @@ import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
......@@ -36,7 +35,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
public class ArpHandler {
......@@ -112,11 +111,11 @@ public class ArpHandler {
private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) {
Ip4Address gatewayIpAddress = config.getGatewayIpAddress(deviceId);
if (gatewayIpAddress != null) {
List<Ip4Address> gatewayIpAddresses = config.getGatewayIpAddress(deviceId);
if (gatewayIpAddresses != null) {
Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest
.getTargetProtocolAddress());
if (gatewayIpAddress.equals(targetProtocolAddress)) {
if (gatewayIpAddresses.contains(targetProtocolAddress)) {
return true;
}
}
......@@ -124,15 +123,11 @@ public class ArpHandler {
}
private boolean isArpReqForSubnet(DeviceId deviceId, ARP arpRequest) {
String subnetInfo = config.getSubnetInfo(deviceId);
if (subnetInfo != null) {
IpPrefix prefix = IpPrefix.valueOf(subnetInfo);
if (prefix.contains(Ip4Address.valueOf(arpRequest.getTargetProtocolAddress()))) {
return true;
}
}
return false;
return config.getSubnetInfo(deviceId).stream()
.anyMatch((prefix)->
prefix.contains(Ip4Address.
valueOf(arpRequest.
getTargetProtocolAddress())));
}
/**
......
......@@ -15,6 +15,7 @@
*/
package org.onosproject.segmentrouting;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpPrefix;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
......@@ -26,6 +27,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -139,8 +141,11 @@ public class DefaultRoutingHandler {
// If both target switch and dest switch are edge routers, then set IP rule
// for both subnet and router IP.
if (config.isEdgeRouter(targetSw) && config.isEdgeRouter(destSw)) {
String subnets = config.getSubnetInfo(destSw);
result = rulePopulator.populateIpRuleForSubnet(targetSw, subnets, destSw, nextHops);
List<Ip4Prefix> subnets = config.getSubnetInfo(destSw);
result = rulePopulator.populateIpRuleForSubnet(targetSw,
subnets,
destSw,
nextHops);
if (!result) {
return false;
}
......
package org.onosproject.segmentrouting;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.grouphandler.DeviceProperties;
import org.onosproject.segmentrouting.grouphandler.DeviceProperties;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
import org.onosproject.segmentrouting.config.NetworkConfigManager;
import org.onosproject.segmentrouting.config.SegmentRouterConfig;
import org.onosproject.segmentrouting.config.SegmentRouterConfig.Subnet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Segment Routing configuration component that reads the
* segment routing related configuration from Network Configuration Manager
* component and organizes in more accessible formats.
*
* TODO: Merge multiple Segment Routing configuration wrapper classes into one.
*/
public class DeviceConfiguration implements DeviceProperties {
private static final Logger log = LoggerFactory
.getLogger(DeviceConfiguration.class);
private final List<Integer> allSegmentIds =
Arrays.asList(101, 102, 103, 104, 105, 106);
private HashMap<DeviceId, Integer> deviceSegmentIdMap =
new HashMap<DeviceId, Integer>() {
{
put(DeviceId.deviceId("of:0000000000000001"), 101);
put(DeviceId.deviceId("of:0000000000000002"), 102);
put(DeviceId.deviceId("of:0000000000000003"), 103);
put(DeviceId.deviceId("of:0000000000000004"), 104);
put(DeviceId.deviceId("of:0000000000000005"), 105);
put(DeviceId.deviceId("of:0000000000000006"), 106);
}
};
private final HashMap<DeviceId, MacAddress> deviceMacMap =
new HashMap<DeviceId, MacAddress>() {
{
put(DeviceId.deviceId("of:0000000000000001"),
MacAddress.valueOf("00:00:00:00:00:01"));
put(DeviceId.deviceId("of:0000000000000002"),
MacAddress.valueOf("00:00:00:00:00:02"));
put(DeviceId.deviceId("of:0000000000000003"),
MacAddress.valueOf("00:00:00:00:00:03"));
put(DeviceId.deviceId("of:0000000000000004"),
MacAddress.valueOf("00:00:00:00:00:04"));
put(DeviceId.deviceId("of:0000000000000005"),
MacAddress.valueOf("00:00:00:00:00:05"));
put(DeviceId.deviceId("of:0000000000000006"),
MacAddress.valueOf("00:00:00:00:00:06"));
}
};
private final HashMap<DeviceId, Ip4Address> deviceIpMap =
new HashMap<DeviceId, Ip4Address>() {
{
put(DeviceId.deviceId("of:0000000000000001"),
Ip4Address.valueOf("192.168.0.1"));
put(DeviceId.deviceId("of:0000000000000002"),
Ip4Address.valueOf("192.168.0.2"));
put(DeviceId.deviceId("of:0000000000000003"),
Ip4Address.valueOf("192.168.0.3"));
put(DeviceId.deviceId("of:0000000000000004"),
Ip4Address.valueOf("192.168.0.4"));
put(DeviceId.deviceId("of:0000000000000005"),
Ip4Address.valueOf("192.168.0.5"));
put(DeviceId.deviceId("of:0000000000000006"),
Ip4Address.valueOf("192.168.0.6"));
}
};
private final List<Integer> allSegmentIds = new ArrayList<Integer>();
private final HashMap<DeviceId, SegmentRouterInfo> deviceConfigMap = new HashMap<>();
private final NetworkConfigManager configService;
private class SegmentRouterInfo {
int nodeSid;
DeviceId deviceId;
Ip4Address ip;
MacAddress mac;
boolean isEdge;
HashMap<PortNumber, Ip4Address> gatewayIps;
HashMap<PortNumber, Ip4Prefix> subnets;
}
/**
* Constructor. Reads all the configuration for all devices of type
* Segment Router and organizes into various maps for easier access.
*
* @param configService handle to network configuration manager
* component from where the relevant configuration is retrieved.
*/
public DeviceConfiguration(NetworkConfigManager configService) {
this.configService = checkNotNull(configService);
List<SwitchConfig> allSwitchCfg =
this.configService.getConfiguredAllowedSwitches();
for (SwitchConfig cfg : allSwitchCfg) {
if (!(cfg instanceof SegmentRouterConfig)) {
continue;
}
SegmentRouterInfo info = new SegmentRouterInfo();
info.nodeSid = ((SegmentRouterConfig) cfg).getNodeSid();
info.deviceId = ((SegmentRouterConfig) cfg).getDpid();
info.mac = MacAddress.valueOf(((
SegmentRouterConfig) cfg).getRouterMac());
String routerIp = ((SegmentRouterConfig) cfg).getRouterIp();
Ip4Prefix prefix = checkNotNull(IpPrefix.valueOf(routerIp).getIp4Prefix());
info.ip = prefix.address();
info.isEdge = ((SegmentRouterConfig) cfg).isEdgeRouter();
info.subnets = new HashMap<>();
info.gatewayIps = new HashMap<PortNumber, Ip4Address>();
for (Subnet s: ((SegmentRouterConfig) cfg).getSubnets()) {
info.subnets.put(PortNumber.portNumber(s.getPortNo()),
Ip4Prefix.valueOf(s.getSubnetIp()));
String gatewayIp = s.getSubnetIp().
substring(0, s.getSubnetIp().indexOf('/'));
info.gatewayIps.put(PortNumber.portNumber(s.getPortNo()),
Ip4Address.valueOf(gatewayIp));
}
this.deviceConfigMap.put(info.deviceId, info);
this.allSegmentIds.add(info.nodeSid);
}
}
/**
* Returns the segment id of a segment router.
*
* @param deviceId device identifier
* @return segment id
*/
@Override
public int getSegmentId(DeviceId deviceId) {
if (deviceSegmentIdMap.get(deviceId) != null) {
if (deviceConfigMap.get(deviceId) != null) {
log.debug("getSegmentId for device{} is {}",
deviceId,
deviceSegmentIdMap.get(deviceId));
return deviceSegmentIdMap.get(deviceId);
deviceConfigMap.get(deviceId).nodeSid);
return deviceConfigMap.get(deviceId).nodeSid;
} else {
throw new IllegalStateException();
}
}
/**
* Returns the segment id of a segment router given its mac address.
*
* @param routerMac router mac address
* @return segment id
*/
public int getSegmentId(MacAddress routerMac) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
deviceConfigMap.entrySet()) {
if (entry.getValue().mac.equals(routerMac)) {
return entry.getValue().nodeSid;
}
}
return -1;
}
/**
* Returns the segment id of a segment router given its router ip address.
*
* @param routerAddress router ip address
* @return segment id
*/
public int getSegmentId(Ip4Address routerAddress) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
deviceConfigMap.entrySet()) {
if (entry.getValue().ip.equals(routerAddress)) {
return entry.getValue().nodeSid;
}
}
return -1;
}
/**
* Returns the router mac of a segment router.
*
* @param deviceId device identifier
* @return router mac address
*/
@Override
public MacAddress getDeviceMac(DeviceId deviceId) {
if (deviceMacMap.get(deviceId) != null) {
if (deviceConfigMap.get(deviceId) != null) {
log.debug("getDeviceMac for device{} is {}",
deviceId,
deviceMacMap.get(deviceId));
return deviceMacMap.get(deviceId);
deviceConfigMap.get(deviceId).mac);
return deviceConfigMap.get(deviceId).mac;
} else {
throw new IllegalStateException();
}
}
/**
* Returns the router ip address of a segment router.
*
* @param deviceId device identifier
* @return router ip address
*/
public Ip4Address getRouterIp(DeviceId deviceId) {
if (deviceConfigMap.get(deviceId) != null) {
log.debug("getDeviceIp for device{} is {}",
deviceId,
deviceConfigMap.get(deviceId).ip);
return deviceConfigMap.get(deviceId).ip;
} else {
throw new IllegalStateException();
}
}
/**
* Indicates if the segment router is a edge router or
* a transit/back bone router.
*
* @param deviceId device identifier
* @return boolean
*/
@Override
public boolean isEdgeDevice(DeviceId deviceId) {
if (deviceId.equals(DeviceId.deviceId("of:0000000000000001"))
|| deviceId.equals(DeviceId.deviceId("of:0000000000000006"))) {
return true;
if (deviceConfigMap.get(deviceId) != null) {
log.debug("isEdgeDevice for device{} is {}",
deviceId,
deviceConfigMap.get(deviceId).isEdge);
return deviceConfigMap.get(deviceId).isEdge;
} else {
throw new IllegalStateException();
}
return false;
}
/**
* Returns the segment ids of all configured segment routers.
*
* @return list of segment ids
*/
@Override
public List<Integer> getAllDeviceSegmentIds() {
return allSegmentIds;
}
/**
* Returns Segment ID for the router with the MAC address given.
* Returns the device identifier or data plane identifier (dpid)
* of a segment router given its segment id.
*
* @param targetMac Mac address for the router
* @return Segment ID for the router with the MAC address
* @param sid segment id
* @return deviceId device identifier
*/
public int getSegmentId(MacAddress targetMac) {
for (Map.Entry<DeviceId, MacAddress> entry: deviceMacMap.entrySet()) {
if (entry.getValue().equals(targetMac)) {
return deviceSegmentIdMap.get(entry.getKey());
public DeviceId getDeviceId(int sid) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
deviceConfigMap.entrySet()) {
if (entry.getValue().nodeSid == sid) {
return entry.getValue().deviceId;
}
}
return -1;
return null;
}
/**
* Returns Segment ID for the router withe IP address given.
* Returns the device identifier or data plane identifier (dpid)
* of a segment router given its router ip address.
*
* @param targetAddress IP address of the router
* @return Segment ID for the router with the IP address
* @param ipAddress router ip address
* @return deviceId device identifier
*/
public int getSegmentId(Ip4Address targetAddress) {
for (Map.Entry<DeviceId, Ip4Address> entry: deviceIpMap.entrySet()) {
if (entry.getValue().equals(targetAddress)) {
return deviceSegmentIdMap.get(entry.getKey());
public DeviceId getDeviceId(Ip4Address ipAddress) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
deviceConfigMap.entrySet()) {
if (entry.getValue().ip.equals(ipAddress)) {
return entry.getValue().deviceId;
}
}
return -1;
return null;
}
/**
* Returns Router IP address for the router with the device ID given.
* Returns the configured subnet gateway ip addresses for a segment router.
*
* @param deviceId device ID of the router
* @return IP address of the router
* @param deviceId device identifier
* @return list of ip addresses
*/
public Ip4Address getRouterIp(DeviceId deviceId) {
if (deviceIpMap.get(deviceId) != null) {
log.debug("getDeviceIp for device{} is {}",
public List<Ip4Address> getSubnetGatewayIps(DeviceId deviceId) {
if (deviceConfigMap.get(deviceId) != null) {
log.debug("getSubnetGatewayIps for device{} is {}",
deviceId,
deviceIpMap.get(deviceId));
return deviceIpMap.get(deviceId);
deviceConfigMap.get(deviceId).gatewayIps.values());
return new ArrayList<Ip4Address>(deviceConfigMap.
get(deviceId).gatewayIps.values());
} else {
throw new IllegalStateException();
return null;
}
}
/**
* Returns the Device ID of the router with the Segment ID given.
* Returns the configured subnet prefixes for a segment router.
*
* @param sid Segment ID of the router
* @return Device ID of the router
* @param deviceId device identifier
* @return list of ip prefixes
*/
public DeviceId getDeviceId(int sid) {
for (Map.Entry<DeviceId, Integer> entry: deviceSegmentIdMap.entrySet()) {
if (entry.getValue() == sid) {
return entry.getKey();
public List<Ip4Prefix> getSubnets(DeviceId deviceId) {
if (deviceConfigMap.get(deviceId) != null) {
log.debug("getSubnets for device{} is {}",
deviceId,
deviceConfigMap.get(deviceId).subnets.values());
return new ArrayList<Ip4Prefix>(deviceConfigMap.
get(deviceId).subnets.values());
} else {
return null;
}
}
/**
* Returns the router ip address of segment router that has the
* specified ip address in its subnets.
*
* @param destIpAddress target ip address
* @return router ip address
*/
public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
deviceConfigMap.entrySet()) {
for (Ip4Prefix prefix:entry.getValue().subnets.values()) {
if (prefix.contains(destIpAddress)) {
return entry.getValue().ip;
}
}
}
log.debug("No router was found for {}", destIpAddress);
return null;
}
/**
* Returns the Device ID of the router with the IP address given.
* Returns the router mac address of segment router that has the
* specified ip address as one of its subnet gateway ip address.
*
* @param ipAddress IP address of the router
* @return Device ID of the router
* @param gatewayIpAddress router gateway ip address
* @return router mac address
*/
public DeviceId getDeviceId(Ip4Address ipAddress) {
for (Map.Entry<DeviceId, Ip4Address> entry: deviceIpMap.entrySet()) {
if (entry.getValue().equals(ipAddress)) {
return entry.getKey();
public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) {
for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
deviceConfigMap.entrySet()) {
if (entry.getValue().gatewayIps.
values().contains(gatewayIpAddress)) {
return entry.getValue().mac;
}
}
log.debug("Cannot find a router for {}", gatewayIpAddress);
return null;
}
}
......
......@@ -16,7 +16,7 @@
package org.onosproject.segmentrouting;
import java.nio.ByteBuffer;
import java.util.List;
import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP;
import org.onlab.packet.IPv4;
......@@ -69,14 +69,14 @@ public class IcmpHandler {
DeviceId deviceId = connectPoint.deviceId();
Ip4Address destinationAddress =
Ip4Address.valueOf(ipv4.getDestinationAddress());
Ip4Address gatewayIpAddress = config.getGatewayIpAddress(deviceId);
List<Ip4Address> gatewayIpAddresses = config.getGatewayIpAddress(deviceId);
IpPrefix routerIpPrefix = config.getRouterIpAddress(deviceId);
Ip4Address routerIpAddress = routerIpPrefix.getIp4Prefix().address();
// ICMP to the router IP or gateway IP
if (((ICMP) ipv4.getPayload()).getIcmpType() == ICMP.TYPE_ECHO_REQUEST &&
(destinationAddress.equals(routerIpAddress) ||
gatewayIpAddress.equals(destinationAddress))) {
gatewayIpAddresses.contains(destinationAddress))) {
sendICMPResponse(ethernet, connectPoint);
// TODO: do we need to set the flow rule again ??
......
......@@ -16,6 +16,7 @@
package org.onosproject.segmentrouting;
import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpPrefix;
......@@ -26,39 +27,33 @@ import org.onosproject.net.PortNumber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.util.List;
import java.util.Set;
/**
* This class is temporary class and used only for test.
* It will be replaced with "real" Network Config Manager.
*
* TODO: Knock off this wrapper and directly use DeviceConfiguration class
*/
public class NetworkConfigHandler {
private static Logger log = LoggerFactory.getLogger(NetworkConfigHandler.class);
private SegmentRoutingManager srManager;
private DeviceConfiguration deviceConfig = new DeviceConfiguration();
private DeviceConfiguration deviceConfig;
public NetworkConfigHandler(SegmentRoutingManager srManager) {
public NetworkConfigHandler(SegmentRoutingManager srManager,
DeviceConfiguration deviceConfig) {
this.srManager = srManager;
this.deviceConfig = deviceConfig;
}
public Ip4Address getGatewayIpAddress(DeviceId deviceId) {
if (deviceId.uri().equals(URI.create("of:0000000000000001"))) {
return Ip4Address.valueOf("10.0.1.128");
} else if (deviceId.uri().equals(URI.create("of:0000000000000006"))) {
return Ip4Address.valueOf("7.7.7.128");
}
log.warn("No gateway Ip address was found for {}", deviceId);
return Ip4Address.valueOf("0.0.0.0");
public List<Ip4Address> getGatewayIpAddress(DeviceId deviceId) {
return this.deviceConfig.getSubnetGatewayIps(deviceId);
}
public IpPrefix getRouterIpAddress(DeviceId deviceId) {
return IpPrefix.valueOf(deviceConfig.getRouterIp(deviceId), 32);
}
......@@ -68,17 +63,13 @@ public class NetworkConfigHandler {
public boolean inSameSubnet(DeviceId deviceId, Ip4Address destIp) {
String subnetInfo = getSubnetInfo(deviceId);
if (subnetInfo == null) {
List<Ip4Prefix> subnets = getSubnetInfo(deviceId);
if (subnets == null) {
return false;
}
IpPrefix prefix = IpPrefix.valueOf(subnetInfo);
if (prefix.contains(destIp)) {
return true;
}
return false;
return subnets.stream()
.anyMatch((subnet) -> subnet.contains(destIp));
}
public boolean inSameSubnet(Ip4Address address, int sid) {
......@@ -88,43 +79,23 @@ public class NetworkConfigHandler {
return false;
}
String subnetInfo = getSubnetInfo(deviceId);
if (subnetInfo == null) {
log.warn("Cannot find the subnet info for {}", deviceId);
return false;
return inSameSubnet(deviceId, address);
}
Ip4Prefix subnet = Ip4Prefix.valueOf(subnetInfo);
if (subnet.contains(address)) {
return true;
}
return false;
}
public String getSubnetInfo(DeviceId deviceId) {
// TODO : supports multiple subnet
if (deviceId.uri().equals(URI.create("of:0000000000000001"))) {
return "10.0.1.1/24";
} else if (deviceId.uri().equals(URI.create("of:0000000000000006"))) {
return "7.7.7.7/24";
} else {
log.error("Switch {} is not an edge router", deviceId);
return null;
}
public List<Ip4Prefix> getSubnetInfo(DeviceId deviceId) {
return deviceConfig.getSubnets(deviceId);
}
public int getMplsId(DeviceId deviceId) {
return deviceConfig.getSegmentId(deviceId);
}
public int getMplsId(MacAddress mac) {
return deviceConfig.getSegmentId(mac);
public int getMplsId(MacAddress routerMac) {
return deviceConfig.getSegmentId(routerMac);
}
public int getMplsId(Ip4Address address) {
return deviceConfig.getSegmentId(address);
public int getMplsId(Ip4Address routerIpAddress) {
return deviceConfig.getSegmentId(routerIpAddress);
}
public boolean isEcmpNotSupportedInTransit(DeviceId deviceId) {
......@@ -132,17 +103,12 @@ public class NetworkConfigHandler {
}
public boolean isTransitRouter(DeviceId deviceId) {
return true;
return !(deviceConfig.isEdgeDevice(deviceId));
}
public boolean isEdgeRouter(DeviceId deviceId) {
if (deviceId.uri().equals(URI.create("of:0000000000000001"))
|| deviceId.uri().equals(URI.create("of:0000000000000006"))) {
return true;
}
return false;
return deviceConfig.isEdgeDevice(deviceId);
}
private List<PortNumber> getPortsToNeighbors(DeviceId deviceId, List<DeviceId> fwdSws) {
......@@ -177,16 +143,7 @@ public class NetworkConfigHandler {
public Ip4Address getDestinationRouterAddress(Ip4Address destIpAddress) {
// TODO: need to check the subnet info
if (destIpAddress.toString().equals("10.0.1.1")) {
return Ip4Address.valueOf("192.168.0.1");
} else if (destIpAddress.toString().equals("7.7.7.7")) {
return Ip4Address.valueOf("192.168.0.6");
} else {
log.warn("No router was found for {}", destIpAddress);
return null;
}
return deviceConfig.getRouterIpAddressForASubnetHost(destIpAddress);
}
public DeviceId getDeviceId(Ip4Address ip4Address) {
......@@ -194,13 +151,6 @@ public class NetworkConfigHandler {
}
public MacAddress getRouterMac(Ip4Address targetAddress) {
if (targetAddress.toString().equals("10.0.1.128")) {
return MacAddress.valueOf("00:00:00:00:00:01");
} else if (targetAddress.toString().equals("7.7.7.128")) {
return MacAddress.valueOf("00:00:00:00:00:06");
} else {
log.warn("Cannot find a router for {}", targetAddress);
return null;
}
return deviceConfig.getRouterMacForAGatewayIp(targetAddress);
}
}
......
......@@ -17,11 +17,11 @@ package org.onosproject.segmentrouting;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onosproject.grouphandler.NeighborSet;
import org.onosproject.segmentrouting.grouphandler.NeighborSet;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.PortNumber;
......@@ -94,15 +94,15 @@ public class RoutingRulePopulator {
* Populates IP flow rules for the subnets of the destination router.
*
* @param deviceId switch ID to set the rules
* @param subnetInfo subnet information
* @param subnets subnet information
* @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, String subnetInfo,
public boolean populateIpRuleForSubnet(DeviceId deviceId, List<Ip4Prefix> subnets,
DeviceId destSw, Set<DeviceId> nextHops) {
List<IpPrefix> subnets = extractSubnet(subnetInfo);
//List<IpPrefix> subnets = extractSubnet(subnetInfo);
for (IpPrefix subnet: subnets) {
if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
return false;
......@@ -371,21 +371,6 @@ public class RoutingRulePopulator {
}
private List<IpPrefix> extractSubnet(String subnetInfo) {
List<IpPrefix> subnetIpPrefixes = new ArrayList<>();
// TODO: refactoring required depending on the format of the subnet info
IpPrefix prefix = IpPrefix.valueOf(subnetInfo);
if (prefix == null) {
log.error("Wrong ip prefix type {}", subnetInfo);
} else {
subnetIpPrefixes.add(prefix);
}
return subnetIpPrefixes;
}
private Link selectOneLink(DeviceId srcId, Set<DeviceId> destIds) {
Set<Link> links = srManager.linkService.getDeviceEgressLinks(srcId);
......
......@@ -25,8 +25,8 @@ import org.onlab.packet.IPv4;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.event.Event;
import org.onosproject.grouphandler.DefaultGroupHandler;
import org.onosproject.grouphandler.NeighborSet;
import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
import org.onosproject.segmentrouting.grouphandler.NeighborSet;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
......@@ -52,6 +52,7 @@ import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.net.topology.TopologyService;
import org.onosproject.segmentrouting.config.NetworkConfigManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -98,16 +99,15 @@ public class SegmentRoutingManager {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MastershipService mastershipService;
protected NetworkConfigHandler networkConfigHandler = new NetworkConfigHandler(this);
protected ArpHandler arpHandler = new ArpHandler(this);
protected IcmpHandler icmpHandler = new IcmpHandler(this);
protected IpHandler ipHandler = new IpHandler(this);
protected RoutingRulePopulator routingRulePopulator = new RoutingRulePopulator(this);
protected NetworkConfigHandler networkConfigHandler = null;
protected ArpHandler arpHandler = null;
protected IcmpHandler icmpHandler = null;
protected IpHandler ipHandler = null;
protected RoutingRulePopulator routingRulePopulator = null;
protected ApplicationId appId;
private DefaultRoutingHandler defaultRoutingHandler = new DefaultRoutingHandler(this);
private DeviceConfiguration deviceConfiguration = new DeviceConfiguration();
private DefaultRoutingHandler defaultRoutingHandler = null;
private DeviceConfiguration deviceConfiguration = null;
private InternalPacketProcessor processor = new InternalPacketProcessor();
private InternalEventHandler eventHandler = new InternalEventHandler();
......@@ -118,6 +118,8 @@ public class SegmentRoutingManager {
private Map<DeviceId, DefaultGroupHandler> groupHandlerMap
= new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
private NetworkConfigManager networkConfigService = new NetworkConfigManager();;
private static int numOfEvents = 0;
private static int numOfHandlerExecution = 0;
private static int numOfHandlerScheduled = 0;
......@@ -125,6 +127,16 @@ public class SegmentRoutingManager {
@Activate
protected void activate() {
appId = coreService.registerApplication("org.onosproject.segmentrouting");
networkConfigService.init();
deviceConfiguration = new DeviceConfiguration(networkConfigService);
networkConfigHandler = new NetworkConfigHandler(this,
deviceConfiguration);
arpHandler = new ArpHandler(this);
icmpHandler = new IcmpHandler(this);
ipHandler = new IpHandler(this);
routingRulePopulator = new RoutingRulePopulator(this);
defaultRoutingHandler = new DefaultRoutingHandler(this);
packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
linkService.addListener(new InternalLinkListener());
groupService.addListener(new InternalGroupListener());
......@@ -271,6 +283,7 @@ public class SegmentRoutingManager {
private class InternalEventHandler implements Runnable {
@Override
public void run() {
numOfHandlerExecution++;
while (!eventQueue.isEmpty()) {
......@@ -326,7 +339,11 @@ public class SegmentRoutingManager {
log.debug("A new device with ID {} was added", device.id());
defaultRoutingHandler.populateTtpRules(device.id());
DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler(
device.id(), appId, new DeviceConfiguration(), linkService, groupService);
device.id(),
appId,
deviceConfiguration,
linkService,
groupService);
dgh.createGroups();
groupHandlerMap.put(device.id(), dgh);
}
......
package org.onosproject.segmentrouting.config;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.onosproject.net.DeviceId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
/**
* Public class corresponding to JSON described data model. Defines the network
* configuration at startup.
*/
public class NetworkConfig {
protected static final Logger log = LoggerFactory.getLogger(NetworkConfig.class);
@SuppressWarnings("unused")
private String comment;
private Boolean restrictSwitches;
private Boolean restrictLinks;
private List<SwitchConfig> switches;
private List<LinkConfig> links;
/**
* Default constructor.
*/
public NetworkConfig() {
switches = new ArrayList<SwitchConfig>();
links = new ArrayList<LinkConfig>();
}
@JsonProperty("comment")
public void setComment(String c) {
log.trace("NetworkConfig: comment={}", c);
comment = c;
}
@JsonProperty("restrictSwitches")
public void setRestrictSwitches(boolean rs) {
log.trace("NetworkConfig: restrictSwitches={}", rs);
restrictSwitches = rs;
}
/**
* Returns default restrict configuration for switches.
*
* @return boolean
*/
public Boolean getRestrictSwitches() {
return restrictSwitches;
}
@JsonProperty("restrictLinks")
public void setRestrictLinks(boolean rl) {
log.trace("NetworkConfig: restrictLinks={}", rl);
restrictLinks = rl;
}
/**
* Returns default restrict configuration for links.
*
* @return boolean
*/
public Boolean getRestrictLinks() {
return restrictLinks;
}
/**
* Returns configuration for switches.
*
* @return list of switch configuration
*/
public List<SwitchConfig> getSwitchConfig() {
return switches;
}
@JsonProperty("switchConfig")
public void setSwitchConfig(List<SwitchConfig> switches2) {
log.trace("NetworkConfig: switchConfig={}", switches2);
this.switches = switches2;
}
/**
* Java class corresponding to JSON described switch
* configuration data model.
*/
public static class SwitchConfig {
protected String nodeDpid;
protected String name;
protected String type;
protected boolean allowed;
protected double latitude;
protected double longitude;
protected Map<String, JsonNode> params;
protected Map<String, String> publishAttributes;
protected DeviceId dpid;
/**
* Returns the configured "name" of a switch.
*
* @return string
*/
public String getName() {
return name;
}
@JsonProperty("name")
public void setName(String name) {
log.trace("SwitchConfig: name={}", name);
this.name = name;
}
/**
* Returns the data plane identifier of a switch.
*
* @return ONOS device identifier
*/
public DeviceId getDpid() {
return dpid;
}
public void setDpid(DeviceId dpid) {
this.dpid = dpid;
this.nodeDpid = dpid.toString();
}
/**
* Returns the data plane identifier of a switch.
*
* @return string
*/
public String getNodeDpid() {
return nodeDpid;
}
// mapper sets both DeviceId and string fields for dpid
@JsonProperty("nodeDpid")
public void setNodeDpid(String nodeDpid) {
log.trace("SwitchConfig: nodeDpid={}", nodeDpid);
this.nodeDpid = nodeDpid;
this.dpid = DeviceId.deviceId(nodeDpid);
}
/**
* Returns the type of a switch.
*
* @return string
*/
public String getType() {
return type;
}
@JsonProperty("type")
public void setType(String type) {
log.trace("SwitchConfig: type={}", type);
this.type = type;
}
/**
* Returns the latitude of a switch.
*
* @return double
*/
public double getLatitude() {
return latitude;
}
@JsonProperty("latitude")
public void setLatitude(double latitude) {
log.trace("SwitchConfig: latitude={}", latitude);
this.latitude = latitude;
}
/**
* Returns the longitude of a switch.
*
* @return double
*/
public double getLongitude() {
return longitude;
}
@JsonProperty("longitude")
public void setLongitude(double longitude) {
log.trace("SwitchConfig: longitude={}", longitude);
this.longitude = longitude;
}
/**
* Returns the allowed flag for a switch.
*
* @return boolean
*/
public boolean isAllowed() {
return allowed;
}
@JsonProperty("allowed")
public void setAllowed(boolean allowed) {
this.allowed = allowed;
}
/**
* Returns the additional configured parameters of a switch.
*
* @return key value map
*/
public Map<String, JsonNode> getParams() {
return params;
}
@JsonProperty("params")
public void setParams(Map<String, JsonNode> params) {
this.params = params;
}
/**
* Reserved for future use.
*
* @return key value map
*/
public Map<String, String> getPublishAttributes() {
return publishAttributes;
}
@JsonProperty("publishAttributes")
public void setPublishAttributes(Map<String, String> publishAttributes) {
this.publishAttributes = publishAttributes;
}
}
@JsonProperty("linkConfig")
public void setLinkConfig(List<LinkConfig> links2) {
this.links = links2;
}
/**
* Reserved for future use.
*
* @return list of configured link configuration
*/
public List<LinkConfig> getLinkConfig() {
return links;
}
/**
* Reserved for future use.
*/
public static class LinkConfig {
protected String type;
protected Boolean allowed;
protected DeviceId dpid1;
protected DeviceId dpid2;
protected String nodeDpid1;
protected String nodeDpid2;
protected Map<String, JsonNode> params;
protected Map<String, String> publishAttributes;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Boolean isAllowed() {
return allowed;
}
public void setAllowed(Boolean allowed) {
this.allowed = allowed;
}
public String getNodeDpid1() {
return nodeDpid1;
}
// mapper sets both long and string fields for dpid
public void setNodeDpid1(String nodeDpid1) {
this.nodeDpid1 = nodeDpid1;
this.dpid1 = DeviceId.deviceId(nodeDpid1);
}
public String getNodeDpid2() {
return nodeDpid2;
}
// mapper sets both long and string fields for dpid
public void setNodeDpid2(String nodeDpid2) {
this.nodeDpid2 = nodeDpid2;
this.dpid2 = DeviceId.deviceId(nodeDpid2);
}
public DeviceId getDpid1() {
return dpid1;
}
public void setDpid1(DeviceId dpid1) {
this.dpid1 = dpid1;
this.nodeDpid1 = dpid1.toString();
}
public DeviceId getDpid2() {
return dpid2;
}
public void setDpid2(DeviceId dpid2) {
this.dpid2 = dpid2;
this.nodeDpid2 = dpid2.toString();
}
public Map<String, JsonNode> getParams() {
return params;
}
public void setParams(Map<String, JsonNode> params) {
this.params = params;
}
public Map<String, String> getPublishAttributes() {
return publishAttributes;
}
public void setPublishAttributes(Map<String, String> publishAttributes) {
this.publishAttributes = publishAttributes;
}
}
}
package org.onosproject.segmentrouting.config;
import org.onosproject.net.DeviceId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* NetworkConfigExceptions specifies a set of unchecked runtime exceptions that
* can be thrown by the {@link NetworkConfigManager}. It indicates errors that
* must be fixed in the config file before controller execution can proceed.
*/
public class NetworkConfigException extends RuntimeException {
private static final long serialVersionUID = 4959684709803000652L;
protected static final Logger log = LoggerFactory
.getLogger(NetworkConfigException.class);
/**
* Exception for duplicate device identifier configuration.
*/
public static class DuplicateDpid extends RuntimeException {
private static final long serialVersionUID = 5491113234592145335L;
public DuplicateDpid(DeviceId dpid) {
super();
log.error("Duplicate dpid found in switch-config Dpid:{}",
dpid);
}
}
/**
* Exception for duplicate device name configuration.
*/
public static class DuplicateName extends RuntimeException {
private static final long serialVersionUID = -4090171438031376129L;
public DuplicateName(String name) {
super();
log.error("Duplicate name found in switch-config name:{}", name);
}
}
/**
* Exception for unspecified device identifier for a switch.
*/
public static class DpidNotSpecified extends RuntimeException {
private static final long serialVersionUID = -8494418855597117254L;
public DpidNotSpecified(String name) {
super();
log.error("Dpid not specified for switch-config name:{}", name);
}
}
/**
* Exception for unspecified device name for a switch.
*/
public static class NameNotSpecified extends RuntimeException {
private static final long serialVersionUID = -3518881744110422891L;
public NameNotSpecified(DeviceId dpid) {
super();
log.error("Name not specified for switch-config dpid:{}",
dpid);
}
}
/**
* Exception for unspecified device type for a switch.
*/
public static class SwitchTypeNotSpecified extends RuntimeException {
private static final long serialVersionUID = 2527453336226053753L;
public SwitchTypeNotSpecified(DeviceId dpid) {
super();
log.error("Switch type not specified for switch-config dpid:{}",
dpid);
}
}
/**
* Exception for unknown device type configured for a switch.
*/
public static class UnknownSwitchType extends RuntimeException {
private static final long serialVersionUID = 7758418165512249170L;
public UnknownSwitchType(String type, String name) {
super();
log.error("Unknown switch type {} for switch name:{}", type, name);
}
}
/**
* Exception for missing required parameter configuration for a switch.
*/
public static class ParamsNotSpecified extends RuntimeException {
private static final long serialVersionUID = 6247582323691265513L;
public ParamsNotSpecified(String name) {
super();
log.error("Params required - not specified for switch:{}", name);
}
}
/**
* Reserved for future use.
*/
public static class LinkTypeNotSpecified extends RuntimeException {
private static final long serialVersionUID = -2089470389588542215L;
public LinkTypeNotSpecified(String dpid1, String dpid2) {
super();
log.error("Link type not specified for link-config between "
+ "dpid1:{} and dpid2:{}", dpid1, dpid2);
}
}
/**
* Reserved for future use.
*/
public static class LinkDpidNotSpecified extends RuntimeException {
private static final long serialVersionUID = -5701825916378616004L;
public LinkDpidNotSpecified(String dpid1, String dpid2) {
super();
if (dpid1 == null) {
log.error("nodeDpid1 not specified for link-config ");
}
if (dpid2 == null) {
log.error("nodeDpid2 not specified for link-config ");
}
}
}
/**
* Reserved for future use.
*/
public static class LinkForUnknownSwitchConfig extends RuntimeException {
private static final long serialVersionUID = -2910458439881964094L;
public LinkForUnknownSwitchConfig(String dpid) {
super();
log.error("Link configuration was specified for a switch-dpid {} "
+ "that has not been configured", dpid);
}
}
/**
* Reserved for future use.
*/
public static class UnknownLinkType extends RuntimeException {
private static final long serialVersionUID = -5505376193106542305L;
public UnknownLinkType(String linktype, String dpid1, String dpid2) {
super();
log.error("unknown link type {} for links between dpid1:{} "
+ "and dpid2:{}", linktype, dpid1, dpid2);
}
}
/**
* Exception for generic configuration errors.
*/
public static class ErrorConfig extends RuntimeException {
private static final long serialVersionUID = -2827406314700193147L;
public ErrorConfig(String errorMsg) {
super();
log.error(errorMsg);
}
}
/**
* Reserved for future use.
*/
public static class SwitchDpidNotConverted extends RuntimeException {
private static final long serialVersionUID = 5640347104590170426L;
public SwitchDpidNotConverted(String name) {
super();
log.error("Switch dpid specified as a HexString {} does not match "
+ "with long value", name);
}
}
/**
* Reserved for future use.
*/
public static class LinkDpidNotConverted extends RuntimeException {
private static final long serialVersionUID = 2397245646094080774L;
public LinkDpidNotConverted(String dpid1, String dpid2) {
log.error("Dpids expressed as HexStrings for links between dpid1:{} "
+ "and dpid2:{} do not match with long values", dpid1, dpid2);
}
}
}
package org.onosproject.segmentrouting.config;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.segmentrouting.config.NetworkConfig.LinkConfig;
import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* NetworkConfigManager manages all network configuration for switches, links
* and any other state that needs to be configured for correct network
* operation.
*
*/
public class NetworkConfigManager implements NetworkConfigService {
protected static final Logger log = LoggerFactory
.getLogger(NetworkConfigManager.class);
private static final String CONFIG_DIR = "../config";
private static final String DEFAULT_CONFIG_FILE = "segmentrouting.conf";
private final String configFileName = DEFAULT_CONFIG_FILE;
/**
* JSON Config file needs to use one of the following types for defining the
* kind of switch or link it wishes to configure.
*/
public static final String SEGMENT_ROUTER = "Router_SR";
public static final String PKT_LINK = "pktLink";
NetworkConfig networkConfig;
private ConcurrentMap<DeviceId, SwitchConfig> configuredSwitches;
private ConcurrentMap<Link, LinkConfig> configuredLinks;
private Map<String, DeviceId> nameToDpid;
@Override
public SwitchConfigStatus checkSwitchConfig(DeviceId dpid) {
SwitchConfig swc = configuredSwitches.get(dpid);
if (networkConfig.getRestrictSwitches()) {
// default deny behavior
if (swc == null) {
// switch is not configured - we deny this switch
return new SwitchConfigStatus(NetworkConfigState.DENY, null,
"Switch not configured, in network denying switches by default.");
}
if (swc.isAllowed()) {
// switch is allowed in config, return configured attributes
return new SwitchConfigStatus(NetworkConfigState.ACCEPT_ADD, swc);
} else {
// switch has been configured off (administratively down)
return new SwitchConfigStatus(NetworkConfigState.DENY, null,
"Switch configured down (allowed=false).");
}
} else {
// default allow behavior
if (swc == null) {
// no config to add
return new SwitchConfigStatus(NetworkConfigState.ACCEPT, null);
}
if (swc.isAllowed()) {
// switch is allowed in config, return configured attributes
return new SwitchConfigStatus(NetworkConfigState.ACCEPT_ADD, swc);
} else {
// switch has been configured off (administratively down)
return new SwitchConfigStatus(NetworkConfigState.DENY, null,
"Switch configured down (allowed=false).");
}
}
}
@Override
public LinkConfigStatus checkLinkConfig(Link linkTuple) {
LinkConfig lkc = getConfiguredLink(linkTuple);
// links are always disallowed if any one of the nodes that make up the
// link are disallowed
DeviceId linkNode1 = linkTuple.src().deviceId();
SwitchConfigStatus scs1 = checkSwitchConfig(linkNode1);
if (scs1.getConfigState() == NetworkConfigState.DENY) {
return new LinkConfigStatus(NetworkConfigState.DENY, null,
"Link-node: " + linkNode1 + " denied by config: " + scs1.getMsg());
}
DeviceId linkNode2 = linkTuple.dst().deviceId();
SwitchConfigStatus scs2 = checkSwitchConfig(linkNode2);
if (scs2.getConfigState() == NetworkConfigState.DENY) {
return new LinkConfigStatus(NetworkConfigState.DENY, null,
"Link-node: " + linkNode2 + " denied by config: " + scs2.getMsg());
}
if (networkConfig.getRestrictLinks()) {
// default deny behavior
if (lkc == null) {
// link is not configured - we deny this link
return new LinkConfigStatus(NetworkConfigState.DENY, null,
"Link not configured, in network denying links by default.");
}
if (lkc.isAllowed()) {
// link is allowed in config, return configured attributes
return new LinkConfigStatus(NetworkConfigState.ACCEPT_ADD, lkc);
} else {
// link has been configured off (administratively down)
return new LinkConfigStatus(NetworkConfigState.DENY, null,
"Link configured down (allowed=false).");
}
} else {
// default allow behavior
if (lkc == null) {
// no config to add
return new LinkConfigStatus(NetworkConfigState.ACCEPT, null);
}
if (lkc.isAllowed()) {
// link is allowed in config, return configured attributes
return new LinkConfigStatus(NetworkConfigState.ACCEPT_ADD, lkc);
} else {
// link has been configured off (administratively down)
return new LinkConfigStatus(NetworkConfigState.DENY, null,
"Link configured down (allowed=false).");
}
}
}
@Override
public List<SwitchConfig> getConfiguredAllowedSwitches() {
List<SwitchConfig> allowed = new ArrayList<SwitchConfig>();
for (SwitchConfig swc : configuredSwitches.values()) {
if (swc.isAllowed()) {
allowed.add(swc);
}
}
return allowed;
}
@Override
public List<LinkConfig> getConfiguredAllowedLinks() {
List<LinkConfig> allowed = new ArrayList<LinkConfig>();
for (LinkConfig lkc : configuredLinks.values()) {
if (lkc.isAllowed()) {
allowed.add(lkc);
}
}
return allowed;
}
@Override
public DeviceId getDpidForName(String name) {
if (nameToDpid.get(name) != null) {
return nameToDpid.get(name);
}
return null;
}
// **************
// Private methods
// **************
private void loadNetworkConfig() {
File configFile = new File(CONFIG_DIR, configFileName);
ObjectMapper mapper = new ObjectMapper();
networkConfig = new NetworkConfig();
try {
networkConfig = mapper.readValue(configFile,
NetworkConfig.class);
} catch (JsonParseException e) {
String err = String.format("JsonParseException while loading network "
+ "config from file: %s: %s", configFileName,
e.getMessage());
throw new NetworkConfigException.ErrorConfig(err);
} catch (JsonMappingException e) {
String err = String.format(
"JsonMappingException while loading network config "
+ "from file: %s: %s",
configFileName,
e.getMessage());
throw new NetworkConfigException.ErrorConfig(err);
} catch (IOException e) {
String err = String.format("IOException while loading network config "
+ "from file: %s %s", configFileName, e.getMessage());
throw new NetworkConfigException.ErrorConfig(err);
}
log.info("Network config specifies: {} switches and {} links",
(networkConfig.getRestrictSwitches())
? networkConfig.getSwitchConfig().size() : "default allow",
(networkConfig.getRestrictLinks())
? networkConfig.getLinkConfig().size() : "default allow");
}
private void parseNetworkConfig() {
List<SwitchConfig> swConfList = networkConfig.getSwitchConfig();
List<LinkConfig> lkConfList = networkConfig.getLinkConfig();
validateSwitchConfig(swConfList);
createTypeSpecificSwitchConfig(swConfList);
validateLinkConfig(lkConfList);
createTypeSpecificLinkConfig(lkConfList);
// TODO validate reachability matrix 'names' for configured dpids
}
private void createTypeSpecificSwitchConfig(List<SwitchConfig> swConfList) {
for (SwitchConfig swc : swConfList) {
nameToDpid.put(swc.getName(), swc.getDpid());
String swtype = swc.getType();
switch (swtype) {
case SEGMENT_ROUTER:
SwitchConfig sr = new SegmentRouterConfig(swc);
configuredSwitches.put(sr.getDpid(), sr);
break;
default:
throw new NetworkConfigException.UnknownSwitchType(swtype,
swc.getName());
}
}
}
private void createTypeSpecificLinkConfig(List<LinkConfig> lkConfList) {
for (LinkConfig lkc : lkConfList) {
String lktype = lkc.getType();
switch (lktype) {
case PKT_LINK:
PktLinkConfig pk = new PktLinkConfig(lkc);
for (Link lt : pk.getLinkTupleList()) {
configuredLinks.put(lt, pk);
}
break;
default:
throw new NetworkConfigException.UnknownLinkType(lktype,
lkc.getNodeDpid1(), lkc.getNodeDpid2());
}
}
}
private void validateSwitchConfig(List<SwitchConfig> swConfList) {
Set<DeviceId> swDpids = new HashSet<DeviceId>();
Set<String> swNames = new HashSet<String>();
for (SwitchConfig swc : swConfList) {
if (swc.getNodeDpid() == null || swc.getDpid() == null) {
throw new NetworkConfigException.DpidNotSpecified(swc.getName());
}
// ensure both String and DeviceId values of dpid are set
if (!swc.getDpid().equals(DeviceId.deviceId(swc.getNodeDpid()))) {
throw new NetworkConfigException.SwitchDpidNotConverted(
swc.getName());
}
if (swc.getName() == null) {
throw new NetworkConfigException.NameNotSpecified(swc.getDpid());
}
if (swc.getType() == null) {
throw new NetworkConfigException.SwitchTypeNotSpecified(
swc.getDpid());
}
if (!swDpids.add(swc.getDpid())) {
throw new NetworkConfigException.DuplicateDpid(swc.getDpid());
}
if (!swNames.add(swc.getName())) {
throw new NetworkConfigException.DuplicateName(swc.getName());
}
// TODO Add more validations
}
}
private void validateLinkConfig(List<LinkConfig> lkConfList) {
for (LinkConfig lkc : lkConfList) {
if (lkc.getNodeDpid1() == null || lkc.getNodeDpid2() == null) {
throw new NetworkConfigException.LinkDpidNotSpecified(
lkc.getNodeDpid1(), lkc.getNodeDpid2());
}
// ensure both String and Long values are set
if (!lkc.getDpid1().equals(DeviceId.deviceId(lkc.getNodeDpid1())) ||
!lkc.getDpid2().equals(DeviceId.deviceId(lkc.getNodeDpid2()))) {
throw new NetworkConfigException.LinkDpidNotConverted(
lkc.getNodeDpid1(), lkc.getNodeDpid2());
}
if (lkc.getType() == null) {
throw new NetworkConfigException.LinkTypeNotSpecified(
lkc.getNodeDpid1(), lkc.getNodeDpid2());
}
if (configuredSwitches.get(lkc.getDpid1()) == null) {
throw new NetworkConfigException.LinkForUnknownSwitchConfig(
lkc.getNodeDpid1());
}
if (configuredSwitches.get(lkc.getDpid2()) == null) {
throw new NetworkConfigException.LinkForUnknownSwitchConfig(
lkc.getNodeDpid2());
}
// TODO add more validations
}
}
private LinkConfig getConfiguredLink(Link linkTuple) {
LinkConfig lkc = null;
// first try the unidirectional link with the ports assigned
lkc = configuredLinks.get(linkTuple);
return lkc;
}
/**
* Initializes the network configuration manager module by
* loading and parsing the network configuration file.
*/
public void init() {
loadNetworkConfig();
configuredSwitches = new ConcurrentHashMap<DeviceId, SwitchConfig>();
configuredLinks = new ConcurrentHashMap<Link, LinkConfig>();
nameToDpid = new HashMap<String, DeviceId>();
parseNetworkConfig();
}
}
package org.onosproject.segmentrouting.config;
import java.util.List;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.segmentrouting.config.NetworkConfig.LinkConfig;
import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
/**
* Exposes methods to retrieve network configuration.
*
* TODO: currently only startup-configuration is exposed and such configuration
* cannot be changed at runtime. Need to add runtime support for changes to
* configuration (via REST/CLI) in future releases.
*
* TODO: return immutable objects or defensive copies of network config so that
* users of this API do not inadvertently or maliciously change network config.
*/
public interface NetworkConfigService {
/**
* Suggests the action to be taken by the caller given the configuration
* associated with the queried network-object (eg. switch, link etc.).
*/
public enum NetworkConfigState {
/**
* Associated network object has been configured to not be allowed in
* the network.
*/
DENY,
/**
* Associated network object has been configured to be allowed in the
* network.
*/
ACCEPT,
/**
* Associated network object has been configured to be allowed in the
* network. In addition, there are configured parameters that should be
* added to the object.
*/
ACCEPT_ADD,
}
/**
* Returns the configuration outcome (accept, deny etc.), and any configured
* parameters to the caller, in response to a query for the configuration
* associated with a switch.
*/
public class SwitchConfigStatus {
private NetworkConfigState configState;
private SwitchConfig switchConfig;
private String msg;
SwitchConfigStatus(NetworkConfigState configState,
SwitchConfig switchConfig, String msg) {
this.configState = configState;
this.switchConfig = switchConfig;
this.msg = msg;
}
SwitchConfigStatus(NetworkConfigState configState,
SwitchConfig switchConfig) {
this.configState = configState;
this.switchConfig = switchConfig;
this.msg = "";
}
/**
* Returns the configuration state for the switch.
*
* @return non-null NetworkConfigState
*/
public NetworkConfigState getConfigState() {
return configState;
}
/**
* Returns the switch configuration, which may be null if no
* configuration exists, or if the configuration state disallows the
* switch.
*
* @return SwitchConfig, the switch configuration, or null
*/
public SwitchConfig getSwitchConfig() {
return switchConfig;
}
/**
* User readable string typically used to specify the reason why a
* switch is being disallowed.
*
* @return A non-null but possibly empty String
*/
public String getMsg() {
return msg;
}
}
/**
* Reserved for future use.
*
* Returns the configuration outcome (accept, deny etc.), and any configured
* parameters to the caller, in response to a query for the configuration
* associated with a link.
*/
public class LinkConfigStatus {
private NetworkConfigState configState;
private LinkConfig linkConfig;
private String msg;
LinkConfigStatus(NetworkConfigState configState,
LinkConfig linkConfig, String msg) {
this.configState = configState;
this.linkConfig = linkConfig;
this.msg = msg;
}
LinkConfigStatus(NetworkConfigState configState,
LinkConfig linkConfig) {
this.configState = configState;
this.linkConfig = linkConfig;
this.msg = "";
}
/**
* Returns the configuration state for the link.
*
* @return non-null NetworkConfigState
*/
public NetworkConfigState getConfigState() {
return configState;
}
/**
* Returns the link configuration, which may be null if no configuration
* exists, or if the configuration state disallows the link.
*
* @return SwitchConfig, the switch configuration, or null
*/
public LinkConfig getLinkConfig() {
return linkConfig;
}
/**
* User readable string typically used to specify the reason why a link
* is being disallowed.
*
* @return msg A non-null but possibly empty String
*/
public String getMsg() {
return msg;
}
}
/**
* Checks the switch configuration (if any) associated with the 'dpid'.
* Determines if the switch should be allowed or denied according to
* configuration rules.
*
* The method always returns a non-null SwitchConfigStatus. The enclosed
* ConfigState contains the result of the check. The enclosed SwitchConfig
* may or may not be null, depending on the outcome of the check.
*
* @param dpid device id of the switch to be queried
* @return SwitchConfigStatus with outcome of check and associated config.
*/
public SwitchConfigStatus checkSwitchConfig(DeviceId dpid);
/**
* Reserved for future use.
*
* Checks the link configuration (if any) associated with the 'link'.
* Determines if the link should be allowed or denied according to
* configuration rules. Note that the 'link' is a unidirectional link which
* checked against configuration that is typically defined for a
* bidirectional link. The caller may make a second call if it wishes to
* check the 'reverse' direction.
*
* Also note that the configuration may not specify ports for a given
* bidirectional link. In such cases, the configuration applies to all links
* between the two switches. This method will check the given 'link' against
* such configuration.
* The method always returns a non-null LinkConfigStatus. The enclosed
* ConfigState contains the result of the check. The enclosed LinkConfig may
* or may not be null, depending on the outcome of the check.
*
* @param linkTuple unidirectional link to be queried
* @return LinkConfigStatus with outcome of check and associated config.
*/
public LinkConfigStatus checkLinkConfig(Link linkTuple);
/**
* Retrieves a list of switches that have been configured, and have been
* determined to be 'allowed' in the network, according to configuration
* rules.
*
* Note that it is possible that there are other switches that are allowed
* in the network that have NOT been configured. Such switches will not be a
* part of the returned list.
*
* Also note that it is possible that some switches will not be discovered
* and the only way the controller can know about these switches is via
* configuration. Such switches will be included in this list. It is up to
* the caller to determine which SwitchConfig applies to non-discovered
* switches.
*
* @return a non-null List of SwitchConfig which may be empty
*/
public List<SwitchConfig> getConfiguredAllowedSwitches();
/**
* Reserved for future use.
*
* Retrieves a list of links that have been configured, and have been
* determined to be 'allowed' in the network, according to configuration
* rules.
*
* Note that it is possible that there are other links that are allowed in
* the network that have NOT been configured. Such links will not be a part
* of the returned list.
*
* Also note that it is possible that some links will not be discovered and
* the only way the controller can know about these links is via
* configuration. Such links will be included in this list. It is up to the
* caller to determine which LinkConfig applies to non-discovered links.
*
* In addition, note that the LinkConfig applies to the configured
* bi-directional link, which may or may not have declared ports. The
* associated unidirectional LinkTuple can be retrieved from the
* getLinkTupleList() method in the LinkConfig object.
*
* @return a non-null List of LinkConfig which may be empty
*/
public List<LinkConfig> getConfiguredAllowedLinks();
/**
* Retrieves the Dpid associated with a 'name' for a configured switch
* object. This method does not check of the switches are 'allowed' by
* config.
*
* @param name device name
* @return the Dpid corresponding to a given 'name', or null if no
* configured switch was found for the given 'name'.
*/
public DeviceId getDpidForName(String name);
}
package org.onosproject.segmentrouting.config;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.onosproject.net.Link;
import org.onosproject.segmentrouting.config.NetworkConfig.LinkConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
/**
* Reserved for future use.
* Configuration for a link between two packet-switches.
*/
public class PktLinkConfig extends LinkConfig {
protected static final Logger log = LoggerFactory
.getLogger(PktLinkConfig.class);
private int port1;
private int port2;
private String nodeName1;
private String nodeName2;
private List<Link> linkTupleList;
public PktLinkConfig(LinkConfig lkc) {
nodeDpid1 = lkc.getNodeDpid1();
nodeDpid2 = lkc.getNodeDpid2();
dpid1 = lkc.getDpid1();
dpid2 = lkc.getDpid2();
type = lkc.getType();
allowed = lkc.isAllowed();
params = lkc.getParams();
publishAttributes = new ConcurrentHashMap<String, String>();
parseParams();
validateParams();
setPublishAttributes();
}
// ********************
// Packet Link Configuration
// ********************
public int getPort1() {
return port1;
}
public void setPort1(int port1) {
this.port1 = port1;
}
public int getPort2() {
return port2;
}
public void setPort2(int port2) {
this.port2 = port2;
}
public String getNodeName1() {
return nodeName1;
}
public void setNodeName1(String nodeName1) {
this.nodeName1 = nodeName1;
}
public String getNodeName2() {
return nodeName2;
}
public void setNodeName2(String nodeName2) {
this.nodeName2 = nodeName2;
}
/**
* Returns the two unidirectional links corresponding to the packet-link
* configuration. It is possible that the ports in the LinkTuple have
* portnumber '0', implying that the configuration applies to all links
* between the two switches.
*
* @return a list of LinkTuple with exactly 2 unidirectional links
*/
public List<Link> getLinkTupleList() {
return linkTupleList;
}
private void setPublishAttributes() {
}
private void parseParams() {
if (params == null) {
throw new PktLinkParamsNotSpecified(nodeDpid1, nodeDpid2);
}
Set<Entry<String, JsonNode>> m = params.entrySet();
for (Entry<String, JsonNode> e : m) {
String key = e.getKey();
JsonNode j = e.getValue();
if (key.equals("nodeName1")) {
setNodeName1(j.asText());
} else if (key.equals("nodeName2")) {
setNodeName2(j.asText());
} else if (key.equals("port1")) {
setPort1(j.asInt());
} else if (key.equals("port2")) {
setPort2(j.asInt());
} else {
throw new UnknownPktLinkConfig(key, nodeDpid1, nodeDpid2);
}
}
}
private void validateParams() {
// TODO - wrong-names, duplicate links,
// duplicate use of port, is switch-allowed for which link is allowed?
// valid port numbers
}
public static class PktLinkParamsNotSpecified extends RuntimeException {
private static final long serialVersionUID = 6247582323691265513L;
public PktLinkParamsNotSpecified(String dpidA, String dpidB) {
super();
log.error("Params required for packet link - not specified "
+ "for link between switch1:{} and switch2:{}",
dpidA, dpidB);
}
}
public static class UnknownPktLinkConfig extends RuntimeException {
private static final long serialVersionUID = -5750132094884129179L;
public UnknownPktLinkConfig(String key, String dpidA, String dpidB) {
super();
log.error("Unknown packet-link config {} for link between"
+ " dpid1: {} and dpid2: {}", key,
dpidA, dpidB);
}
}
}
package org.onosproject.segmentrouting.config;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.onosproject.net.DeviceId;
import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Manages additional configuration for switches configured as Segment Routers.
*/
public class SegmentRouterConfig extends SwitchConfig {
protected static final Logger log = LoggerFactory
.getLogger(SegmentRouterConfig.class);
private String routerIp;
private String routerMac;
private int nodeSid;
private boolean isEdgeRouter;
private List<AdjacencySid> adjacencySids;
private List<Subnet> subnets;
public static final String ROUTER_IP = "routerIp";
public static final String ROUTER_MAC = "routerMac";
public static final String NODE_SID = "nodeSid";
public static final String ADJACENCY_SIDS = "adjacencySids";
public static final String SUBNETS = "subnets";
public static final String ISEDGE = "isEdgeRouter";
private static final int SRGB_MAX = 1000;
/**
* Parses and validates the additional configuration parameters applicable
* to segment routers.
*
* @param swc switch configuration
*/
public SegmentRouterConfig(SwitchConfig swc) {
this.setName(swc.getName());
this.setDpid(swc.getDpid());
this.setType(swc.getType());
this.setLatitude(swc.getLatitude());
this.setLongitude(swc.getLongitude());
this.setParams(swc.getParams());
this.setAllowed(swc.isAllowed());
publishAttributes = new ConcurrentHashMap<String, String>();
adjacencySids = new ArrayList<AdjacencySid>();
subnets = new ArrayList<Subnet>();
parseParams();
validateParams();
setPublishAttributes();
}
/**
* Returns the configured segment router IP address.
*
* @return ip address in string format
*/
public String getRouterIp() {
return routerIp;
}
public void setRouterIp(String routerIp) {
this.routerIp = routerIp;
}
/**
* Returns the configured segment router mac address.
*
* @return mac address in string format
*/
public String getRouterMac() {
return routerMac;
}
public void setRouterMac(String routerMac) {
this.routerMac = routerMac;
}
/**
* Returns the configured sID for a segment router.
*
* @return segment identifier
*/
public int getNodeSid() {
return nodeSid;
}
public void setNodeSid(int nodeSid) {
this.nodeSid = nodeSid;
}
/**
* Returns the flag that indicates the configured segment router
* is edge or backbone router.
*
* @return boolean
*/
public boolean isEdgeRouter() {
return isEdgeRouter;
}
public void setIsEdgeRouter(boolean isEdge) {
this.isEdgeRouter = isEdge;
}
/**
* Class representing segment router adjacency identifier.
*/
public static class AdjacencySid {
private int adjSid;
private List<Integer> ports;
public AdjacencySid(int adjSid, List<Integer> ports) {
this.ports = ports;
this.adjSid = adjSid;
}
/**
* Returns the list of ports part of a segment
* router adjacency identifier.
*
* @return list of integers
*/
public List<Integer> getPorts() {
return ports;
}
public void setPorts(List<Integer> ports) {
this.ports = ports;
}
/**
* Returns the configured adjacency id of a segment router.
*
* @return integer
*/
public int getAdjSid() {
return adjSid;
}
public void setAdjSid(int adjSid) {
this.adjSid = adjSid;
}
}
/**
* Returns the configured adjacent segment IDs for a segment router.
*
* @return list of adjacency identifier
*/
public List<AdjacencySid> getAdjacencySids() {
return adjacencySids;
}
public void setAdjacencySids(List<AdjacencySid> adjacencySids) {
this.adjacencySids = adjacencySids;
}
/**
* Class representing a subnet attached to a segment router.
*/
public static class Subnet {
private int portNo;
private String subnetIp;
public Subnet(int portNo, String subnetIp) {
this.portNo = portNo;
this.subnetIp = subnetIp;
}
/**
* Returns the port number of segment router on
* which subnet is attached.
*
* @return integer
*/
public int getPortNo() {
return portNo;
}
public void setPortNo(int portNo) {
this.portNo = portNo;
}
/**
* Returns the configured subnet address.
*
* @return subnet ip address in string format
*/
public String getSubnetIp() {
return subnetIp;
}
public void setSubnetIp(String subnetIp) {
this.subnetIp = subnetIp;
}
}
/**
* Returns the configured subnets for a segment router.
*
* @return list of subnets
*/
public List<Subnet> getSubnets() {
return subnets;
}
public void setSubnets(List<Subnet> subnets) {
this.subnets = subnets;
}
// ********************
// Helper methods
// ********************
private void parseParams() {
if (params == null) {
throw new NetworkConfigException.ParamsNotSpecified(name);
}
Set<Entry<String, JsonNode>> m = params.entrySet();
for (Entry<String, JsonNode> e : m) {
String key = e.getKey();
JsonNode j = e.getValue();
if (key.equals("routerIp")) {
setRouterIp(j.asText());
} else if (key.equals("routerMac")) {
setRouterMac(j.asText());
} else if (key.equals("nodeSid")) {
setNodeSid(j.asInt());
} else if (key.equals("isEdgeRouter")) {
setIsEdgeRouter(j.asBoolean());
} else if (key.equals("adjacencySids") || key.equals("subnets")) {
getInnerParams(j, key);
} else {
throw new UnknownSegmentRouterConfig(key, dpid);
}
}
}
private void getInnerParams(JsonNode j, String innerParam) {
Iterator<JsonNode> innerList = j.elements();
while (innerList.hasNext()) {
Iterator<Entry<String, JsonNode>> f = innerList.next().fields();
int portNo = -1;
int adjSid = -1;
String subnetIp = null;
List<Integer> ports = null;
while (f.hasNext()) {
Entry<String, JsonNode> fe = f.next();
if (fe.getKey().equals("portNo")) {
portNo = fe.getValue().asInt();
} else if (fe.getKey().equals("adjSid")) {
adjSid = fe.getValue().asInt();
} else if (fe.getKey().equals("subnetIp")) {
subnetIp = fe.getValue().asText();
} else if (fe.getKey().equals("ports")) {
if (fe.getValue().isArray()) {
Iterator<JsonNode> i = fe.getValue().elements();
ports = new ArrayList<Integer>();
while (i.hasNext()) {
ports.add(i.next().asInt());
}
}
} else {
throw new UnknownSegmentRouterConfig(fe.getKey(), dpid);
}
}
if (innerParam.equals("adjacencySids")) {
AdjacencySid ads = new AdjacencySid(adjSid, ports);
adjacencySids.add(ads);
} else {
Subnet sip = new Subnet(portNo, subnetIp);
subnets.add(sip);
}
}
}
private void validateParams() {
if (routerIp == null) {
throw new IpNotSpecified(dpid);
}
if (routerMac == null) {
throw new MacNotSpecified(dpid);
}
if (isEdgeRouter && subnets.isEmpty()) {
throw new SubnetNotSpecifiedInEdgeRouter(dpid);
}
if (!isEdgeRouter && !subnets.isEmpty()) {
throw new SubnetSpecifiedInBackboneRouter(dpid);
}
if (nodeSid > SRGB_MAX) {
throw new NodeLabelNotInSRGB(nodeSid, dpid);
}
for (AdjacencySid as : adjacencySids) {
int label = as.getAdjSid();
List<Integer> plist = as.getPorts();
if (label <= SRGB_MAX) {
throw new AdjacencyLabelInSRGB(label, dpid);
}
if (plist.size() <= 1) {
throw new AdjacencyLabelNotEnoughPorts(label, dpid);
}
}
// TODO more validations
}
/**
* Setting publishAttributes implies that this is the configuration that
* will be added to Topology.Switch object before it is published on the
* channel to other controller instances.
*/
private void setPublishAttributes() {
publishAttributes.put(ROUTER_IP, routerIp);
publishAttributes.put(ROUTER_MAC, routerMac);
publishAttributes.put(NODE_SID, String.valueOf(nodeSid));
publishAttributes.put(ISEDGE, String.valueOf(isEdgeRouter));
ObjectMapper mapper = new ObjectMapper();
try {
publishAttributes.put(ADJACENCY_SIDS,
mapper.writeValueAsString(adjacencySids));
publishAttributes.put(SUBNETS,
mapper.writeValueAsString(subnets));
} catch (JsonProcessingException e) {
log.error("Error while writing SR config: {}", e.getCause());
} catch (IOException e) {
log.error("Error while writing SR config: {}", e.getCause());
}
}
// ********************
// Exceptions
// ********************
public static class IpNotSpecified extends RuntimeException {
private static final long serialVersionUID = -3001502553646331686L;
public IpNotSpecified(DeviceId dpid) {
super();
log.error("Router IP address not specified for SR config dpid:{}",
dpid);
}
}
public static class MacNotSpecified extends RuntimeException {
private static final long serialVersionUID = -5850132094884129179L;
public MacNotSpecified(DeviceId dpid) {
super();
log.error("Router Mac address not specified for SR config dpid:{}",
dpid);
}
}
public static class UnknownSegmentRouterConfig extends RuntimeException {
private static final long serialVersionUID = -5750132094884129179L;
public UnknownSegmentRouterConfig(String key, DeviceId dpid) {
super();
log.error("Unknown Segment Router config {} in dpid: {}", key,
dpid);
}
}
public static class SubnetNotSpecifiedInEdgeRouter extends RuntimeException {
private static final long serialVersionUID = -5855458472668581268L;
public SubnetNotSpecifiedInEdgeRouter(DeviceId dpid) {
super();
log.error("Subnet was not specified for edge router in dpid: {}",
dpid);
}
}
public static class SubnetSpecifiedInBackboneRouter extends RuntimeException {
private static final long serialVersionUID = 1L;
public SubnetSpecifiedInBackboneRouter(DeviceId dpid) {
super();
log.error("Subnet was specified in backbone router in dpid: {}",
dpid);
}
}
public static class NodeLabelNotInSRGB extends RuntimeException {
private static final long serialVersionUID = -8482670903748519526L;
public NodeLabelNotInSRGB(int label, DeviceId dpid) {
super();
log.error("Node sif {} specified in not in global label-base "
+ "in dpid: {}", label,
dpid);
}
}
public static class AdjacencyLabelInSRGB extends RuntimeException {
private static final long serialVersionUID = -8482670903748519526L;
public AdjacencyLabelInSRGB(int label, DeviceId dpid) {
super();
log.error("Adjaceny label {} specified from global label-base "
+ "in dpid: {}", label,
dpid);
}
}
public static class AdjacencyLabelNotEnoughPorts extends RuntimeException {
private static final long serialVersionUID = -8482670903748519526L;
public AdjacencyLabelNotEnoughPorts(int label, DeviceId dpid) {
super();
log.error("Adjaceny label {} must be specified for at least 2 ports. "
+ "Adjacency labels for single ports are auto-generated "
+ "in dpid: {}", label,
dpid);
}
}
}
......@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.grouphandler;
package org.onosproject.segmentrouting.grouphandler;
import java.util.Arrays;
import java.util.HashSet;
......
......@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.grouphandler;
package org.onosproject.segmentrouting.grouphandler;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
......
......@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.grouphandler;
package org.onosproject.segmentrouting.grouphandler;
import java.util.Arrays;
import java.util.HashSet;
......
......@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.grouphandler;
package org.onosproject.segmentrouting.grouphandler;
import java.util.List;
......
......@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.grouphandler;
package org.onosproject.segmentrouting.grouphandler;
import static com.google.common.base.Preconditions.checkNotNull;
......
......@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.onosproject.grouphandler;
package org.onosproject.segmentrouting.grouphandler;
import static com.google.common.base.Preconditions.checkNotNull;
......
......@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.grouphandler;
package org.onosproject.segmentrouting.grouphandler;
import static org.slf4j.LoggerFactory.getLogger;
......@@ -26,7 +26,7 @@ import java.util.List;
import org.onlab.packet.MplsLabel;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.GroupId;
import org.onosproject.grouphandler.GroupBucketIdentifier.BucketOutputType;
import org.onosproject.segmentrouting.grouphandler.GroupBucketIdentifier.BucketOutputType;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
......
......@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.grouphandler;
package org.onosproject.segmentrouting.grouphandler;
import java.util.List;
......
......@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.grouphandler;
package org.onosproject.segmentrouting.grouphandler;
import static com.google.common.base.Preconditions.checkNotNull;
......
{
"comment": " Multilayer topology description and configuration",
"restrictSwitches": true,
"restrictLinks": true,
"switchConfig":
[
{ "nodeDpid" : "of:0000000000000001", "name": "Dallas-R1", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "192.168.0.1/32",
"routerMac": "00:00:01:01:01:80",
"nodeSid": 101,
"isEdgeRouter" : true,
"adjacencySids": [
{ "ports": [ 4, 5 ], "adjSid": 10234 },
{ "ports": [ 6, 7 ], "adjSid": 29019 }
],
"subnets": [
{ "portNo": 1, "subnetIp": "10.0.1.128/24" }
]
}
},
{ "nodeDpid": "of:0000000000000002", "name": "Dallas-R2", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "192.168.0.2/32",
"routerMac": "00:00:02:02:02:80",
"nodeSid": 102,
"isEdgeRouter" : false,
"adjacencySids": [
{ "ports": [ 1, 2 ], "adjSid": 12453 },
{ "ports": [ 2, 3 ], "adjSid": 23333 },
{ "ports": [ 3, 1 ], "adjSid": 22233 }
]
}
},
{ "nodeDpid": "of:0000000000000003", "name": "Dallas-R3", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "192.168.0.3/32",
"routerMac": "00:00:03:03:03:80",
"nodeSid": 103,
"isEdgeRouter" : false
}
},
{ "nodeDpid": "of:0000000000000004", "name": "Dallas-R4", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "192.168.0.4/32",
"routerMac": "00:00:04:04:04:80",
"nodeSid": 104,
"isEdgeRouter" : false
}
},
{ "nodeDpid": "of:0000000000000005", "name": "Dallas-R5", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "192.168.0.5/32",
"routerMac": "00:00:05:05:05:80",
"nodeSid": 105,
"isEdgeRouter" : false
}
},
{ "nodeDpid": "of:0000000000000006", "name": "Dallas-R6", "type": "Router_SR", "allowed": true,
"latitude": 80.80, "longitude": 90.10,
"params": { "routerIp": "192.168.0.6/32",
"routerMac": "00:00:07:07:07:80",
"nodeSid": 106,
"isEdgeRouter" : true,
"subnets": [
{ "portNo": 1, "subnetIp": "7.7.7.128/24" }
]
}
}
]
}