1 package org.onosproject.segmentrouting.config;
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.Iterator;
7 import java.util.Map.Entry;
9 import java.util.concurrent.ConcurrentHashMap;
11 import org.onosproject.net.DeviceId;
12 import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
16 import com.fasterxml.jackson.core.JsonProcessingException;
17 import com.fasterxml.jackson.databind.JsonNode;
18 import com.fasterxml.jackson.databind.ObjectMapper;
21 * Manages additional configuration for switches configured as Segment Routers.
23 public class SegmentRouterConfig extends SwitchConfig {
24 protected static final Logger log = LoggerFactory
25 .getLogger(SegmentRouterConfig.class);
26 private String routerIp;
27 private String routerMac;
29 private boolean isEdgeRouter;
30 private List<AdjacencySid> adjacencySids;
31 private List<Subnet> subnets;
33 public static final String ROUTER_IP = "routerIp";
34 public static final String ROUTER_MAC = "routerMac";
35 public static final String NODE_SID = "nodeSid";
36 public static final String ADJACENCY_SIDS = "adjacencySids";
37 public static final String SUBNETS = "subnets";
38 public static final String ISEDGE = "isEdgeRouter";
39 private static final int SRGB_MAX = 1000;
42 * Parses and validates the additional configuration parameters applicable
45 * @param swc switch configuration
47 public SegmentRouterConfig(SwitchConfig swc) {
48 this.setName(swc.getName());
49 this.setDpid(swc.getDpid());
50 this.setType(swc.getType());
51 this.setLatitude(swc.getLatitude());
52 this.setLongitude(swc.getLongitude());
53 this.setParams(swc.getParams());
54 this.setAllowed(swc.isAllowed());
55 publishAttributes = new ConcurrentHashMap<String, String>();
56 adjacencySids = new ArrayList<AdjacencySid>();
57 subnets = new ArrayList<Subnet>();
60 setPublishAttributes();
64 * Returns the configured segment router IP address.
66 * @return ip address in string format
68 public String getRouterIp() {
72 public void setRouterIp(String routerIp) {
73 this.routerIp = routerIp;
77 * Returns the configured segment router mac address.
79 * @return mac address in string format
81 public String getRouterMac() {
85 public void setRouterMac(String routerMac) {
86 this.routerMac = routerMac;
90 * Returns the configured sID for a segment router.
92 * @return segment identifier
94 public int getNodeSid() {
98 public void setNodeSid(int nodeSid) {
99 this.nodeSid = nodeSid;
103 * Returns the flag that indicates the configured segment router
104 * is edge or backbone router.
108 public boolean isEdgeRouter() {
112 public void setIsEdgeRouter(boolean isEdge) {
113 this.isEdgeRouter = isEdge;
117 * Class representing segment router adjacency identifier.
119 public static class AdjacencySid {
121 private List<Integer> ports;
123 public AdjacencySid(int adjSid, List<Integer> ports) {
125 this.adjSid = adjSid;
129 * Returns the list of ports part of a segment
130 * router adjacency identifier.
132 * @return list of integers
134 public List<Integer> getPorts() {
138 public void setPorts(List<Integer> ports) {
143 * Returns the configured adjacency id of a segment router.
147 public int getAdjSid() {
151 public void setAdjSid(int adjSid) {
152 this.adjSid = adjSid;
157 * Returns the configured adjacent segment IDs for a segment router.
159 * @return list of adjacency identifier
161 public List<AdjacencySid> getAdjacencySids() {
162 return adjacencySids;
165 public void setAdjacencySids(List<AdjacencySid> adjacencySids) {
166 this.adjacencySids = adjacencySids;
170 * Class representing a subnet attached to a segment router.
172 public static class Subnet {
174 private String subnetIp;
176 public Subnet(int portNo, String subnetIp) {
177 this.portNo = portNo;
178 this.subnetIp = subnetIp;
182 * Returns the port number of segment router on
183 * which subnet is attached.
187 public int getPortNo() {
191 public void setPortNo(int portNo) {
192 this.portNo = portNo;
196 * Returns the configured subnet address.
198 * @return subnet ip address in string format
200 public String getSubnetIp() {
204 public void setSubnetIp(String subnetIp) {
205 this.subnetIp = subnetIp;
210 * Returns the configured subnets for a segment router.
212 * @return list of subnets
214 public List<Subnet> getSubnets() {
218 public void setSubnets(List<Subnet> subnets) {
219 this.subnets = subnets;
222 // ********************
224 // ********************
226 private void parseParams() {
227 if (params == null) {
228 throw new NetworkConfigException.ParamsNotSpecified(name);
231 Set<Entry<String, JsonNode>> m = params.entrySet();
232 for (Entry<String, JsonNode> e : m) {
233 String key = e.getKey();
234 JsonNode j = e.getValue();
235 if (key.equals("routerIp")) {
236 setRouterIp(j.asText());
237 } else if (key.equals("routerMac")) {
238 setRouterMac(j.asText());
239 } else if (key.equals("nodeSid")) {
240 setNodeSid(j.asInt());
241 } else if (key.equals("isEdgeRouter")) {
242 setIsEdgeRouter(j.asBoolean());
243 } else if (key.equals("adjacencySids") || key.equals("subnets")) {
244 getInnerParams(j, key);
246 throw new UnknownSegmentRouterConfig(key, dpid);
251 private void getInnerParams(JsonNode j, String innerParam) {
252 Iterator<JsonNode> innerList = j.elements();
253 while (innerList.hasNext()) {
254 Iterator<Entry<String, JsonNode>> f = innerList.next().fields();
257 String subnetIp = null;
258 List<Integer> ports = null;
259 while (f.hasNext()) {
260 Entry<String, JsonNode> fe = f.next();
261 if (fe.getKey().equals("portNo")) {
262 portNo = fe.getValue().asInt();
263 } else if (fe.getKey().equals("adjSid")) {
264 adjSid = fe.getValue().asInt();
265 } else if (fe.getKey().equals("subnetIp")) {
266 subnetIp = fe.getValue().asText();
267 } else if (fe.getKey().equals("ports")) {
268 if (fe.getValue().isArray()) {
269 Iterator<JsonNode> i = fe.getValue().elements();
270 ports = new ArrayList<Integer>();
271 while (i.hasNext()) {
272 ports.add(i.next().asInt());
276 throw new UnknownSegmentRouterConfig(fe.getKey(), dpid);
279 if (innerParam.equals("adjacencySids")) {
280 AdjacencySid ads = new AdjacencySid(adjSid, ports);
281 adjacencySids.add(ads);
283 Subnet sip = new Subnet(portNo, subnetIp);
289 private void validateParams() {
290 if (routerIp == null) {
291 throw new IpNotSpecified(dpid);
293 if (routerMac == null) {
294 throw new MacNotSpecified(dpid);
296 if (isEdgeRouter && subnets.isEmpty()) {
297 throw new SubnetNotSpecifiedInEdgeRouter(dpid);
299 if (!isEdgeRouter && !subnets.isEmpty()) {
300 throw new SubnetSpecifiedInBackboneRouter(dpid);
302 if (nodeSid > SRGB_MAX) {
303 throw new NodeLabelNotInSRGB(nodeSid, dpid);
305 for (AdjacencySid as : adjacencySids) {
306 int label = as.getAdjSid();
307 List<Integer> plist = as.getPorts();
308 if (label <= SRGB_MAX) {
309 throw new AdjacencyLabelInSRGB(label, dpid);
311 if (plist.size() <= 1) {
312 throw new AdjacencyLabelNotEnoughPorts(label, dpid);
317 // TODO more validations
321 * Setting publishAttributes implies that this is the configuration that
322 * will be added to Topology.Switch object before it is published on the
323 * channel to other controller instances.
325 private void setPublishAttributes() {
326 publishAttributes.put(ROUTER_IP, routerIp);
327 publishAttributes.put(ROUTER_MAC, routerMac);
328 publishAttributes.put(NODE_SID, String.valueOf(nodeSid));
329 publishAttributes.put(ISEDGE, String.valueOf(isEdgeRouter));
330 ObjectMapper mapper = new ObjectMapper();
332 publishAttributes.put(ADJACENCY_SIDS,
333 mapper.writeValueAsString(adjacencySids));
334 publishAttributes.put(SUBNETS,
335 mapper.writeValueAsString(subnets));
336 } catch (JsonProcessingException e) {
337 log.error("Error while writing SR config: {}", e.getCause());
338 } catch (IOException e) {
339 log.error("Error while writing SR config: {}", e.getCause());
343 // ********************
345 // ********************
347 public static class IpNotSpecified extends RuntimeException {
348 private static final long serialVersionUID = -3001502553646331686L;
350 public IpNotSpecified(DeviceId dpid) {
352 log.error("Router IP address not specified for SR config dpid:{}",
357 public static class MacNotSpecified extends RuntimeException {
358 private static final long serialVersionUID = -5850132094884129179L;
360 public MacNotSpecified(DeviceId dpid) {
362 log.error("Router Mac address not specified for SR config dpid:{}",
367 public static class UnknownSegmentRouterConfig extends RuntimeException {
368 private static final long serialVersionUID = -5750132094884129179L;
370 public UnknownSegmentRouterConfig(String key, DeviceId dpid) {
372 log.error("Unknown Segment Router config {} in dpid: {}", key,
377 public static class SubnetNotSpecifiedInEdgeRouter extends RuntimeException {
378 private static final long serialVersionUID = -5855458472668581268L;
380 public SubnetNotSpecifiedInEdgeRouter(DeviceId dpid) {
382 log.error("Subnet was not specified for edge router in dpid: {}",
387 public static class SubnetSpecifiedInBackboneRouter extends RuntimeException {
388 private static final long serialVersionUID = 1L;
390 public SubnetSpecifiedInBackboneRouter(DeviceId dpid) {
392 log.error("Subnet was specified in backbone router in dpid: {}",
397 public static class NodeLabelNotInSRGB extends RuntimeException {
398 private static final long serialVersionUID = -8482670903748519526L;
400 public NodeLabelNotInSRGB(int label, DeviceId dpid) {
402 log.error("Node sif {} specified in not in global label-base "
403 + "in dpid: {}", label,
408 public static class AdjacencyLabelInSRGB extends RuntimeException {
409 private static final long serialVersionUID = -8482670903748519526L;
411 public AdjacencyLabelInSRGB(int label, DeviceId dpid) {
413 log.error("Adjaceny label {} specified from global label-base "
414 + "in dpid: {}", label,
419 public static class AdjacencyLabelNotEnoughPorts extends RuntimeException {
420 private static final long serialVersionUID = -8482670903748519526L;
422 public AdjacencyLabelNotEnoughPorts(int label, DeviceId dpid) {
424 log.error("Adjaceny label {} must be specified for at least 2 ports. "
425 + "Adjacency labels for single ports are auto-generated "
426 + "in dpid: {}", label,