blob: dd5c4d6e3d6ee81850007ee02d3d397b0db64bd9 [file] [log] [blame]
/*
* 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.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);
}
}
}