2 * Copyright 2015 Open Networking Laboratory
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.onosproject.segmentrouting.config;
18 import java.io.IOException;
19 import java.util.ArrayList;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map.Entry;
24 import java.util.concurrent.ConcurrentHashMap;
26 import org.onosproject.net.DeviceId;
27 import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
31 import com.fasterxml.jackson.core.JsonProcessingException;
32 import com.fasterxml.jackson.databind.JsonNode;
33 import com.fasterxml.jackson.databind.ObjectMapper;
36 * Manages additional configuration for switches configured as Segment Routers.
38 public class SegmentRouterConfig extends SwitchConfig {
39 protected static final Logger log = LoggerFactory
40 .getLogger(SegmentRouterConfig.class);
41 private String routerIp;
42 private String routerMac;
44 private boolean isEdgeRouter;
45 private List<AdjacencySid> adjacencySids;
46 private List<Subnet> subnets;
48 public static final String ROUTER_IP = "routerIp";
49 public static final String ROUTER_MAC = "routerMac";
50 public static final String NODE_SID = "nodeSid";
51 public static final String ADJACENCY_SIDS = "adjacencySids";
52 public static final String SUBNETS = "subnets";
53 public static final String ISEDGE = "isEdgeRouter";
54 private static final int SRGB_MAX = 1000;
57 * Parses and validates the additional configuration parameters applicable
60 * @param swc switch configuration
62 public SegmentRouterConfig(SwitchConfig swc) {
63 this.setName(swc.getName());
64 this.setDpid(swc.getDpid());
65 this.setType(swc.getType());
66 this.setLatitude(swc.getLatitude());
67 this.setLongitude(swc.getLongitude());
68 this.setParams(swc.getParams());
69 this.setAllowed(swc.isAllowed());
70 publishAttributes = new ConcurrentHashMap<>();
71 adjacencySids = new ArrayList<>();
72 subnets = new ArrayList<>();
75 setPublishAttributes();
79 * Returns the configured segment router IP address.
81 * @return ip address in string format
83 public String getRouterIp() {
87 public void setRouterIp(String routerIp) {
88 this.routerIp = routerIp;
92 * Returns the configured segment router mac address.
94 * @return mac address in string format
96 public String getRouterMac() {
100 public void setRouterMac(String routerMac) {
101 this.routerMac = routerMac;
105 * Returns the configured sID for a segment router.
107 * @return segment identifier
109 public int getNodeSid() {
113 public void setNodeSid(int nodeSid) {
114 this.nodeSid = nodeSid;
118 * Returns the flag that indicates the configured segment router
119 * is edge or backbone router.
123 public boolean isEdgeRouter() {
127 public void setIsEdgeRouter(boolean isEdge) {
128 this.isEdgeRouter = isEdge;
132 * Class representing segment router adjacency identifier.
134 public static class AdjacencySid {
136 private List<Integer> ports;
138 public AdjacencySid(int adjSid, List<Integer> ports) {
140 this.adjSid = adjSid;
144 * Returns the list of ports part of a segment
145 * router adjacency identifier.
147 * @return list of integers
149 public List<Integer> getPorts() {
153 public void setPorts(List<Integer> ports) {
158 * Returns the configured adjacency id of a segment router.
162 public int getAdjSid() {
166 public void setAdjSid(int adjSid) {
167 this.adjSid = adjSid;
172 * Returns the configured adjacent segment IDs for a segment router.
174 * @return list of adjacency identifier
176 public List<AdjacencySid> getAdjacencySids() {
177 return adjacencySids;
180 public void setAdjacencySids(List<AdjacencySid> adjacencySids) {
181 this.adjacencySids = adjacencySids;
185 * Class representing a subnet attached to a segment router.
187 public static class Subnet {
189 private String subnetIp;
191 public Subnet(int portNo, String subnetIp) {
192 this.portNo = portNo;
193 this.subnetIp = subnetIp;
197 * Returns the port number of segment router on
198 * which subnet is attached.
202 public int getPortNo() {
206 public void setPortNo(int portNo) {
207 this.portNo = portNo;
211 * Returns the configured subnet address.
213 * @return subnet ip address in string format
215 public String getSubnetIp() {
219 public void setSubnetIp(String subnetIp) {
220 this.subnetIp = subnetIp;
225 * Returns the configured subnets for a segment router.
227 * @return list of subnets
229 public List<Subnet> getSubnets() {
233 public void setSubnets(List<Subnet> subnets) {
234 this.subnets = subnets;
237 // ********************
239 // ********************
241 private void parseParams() {
242 if (params == null) {
243 throw new NetworkConfigException.ParamsNotSpecified(name);
246 Set<Entry<String, JsonNode>> m = params.entrySet();
247 for (Entry<String, JsonNode> e : m) {
248 String key = e.getKey();
249 JsonNode j = e.getValue();
250 if (key.equals("routerIp")) {
251 setRouterIp(j.asText());
252 } else if (key.equals("routerMac")) {
253 setRouterMac(j.asText());
254 } else if (key.equals("nodeSid")) {
255 setNodeSid(j.asInt());
256 } else if (key.equals("isEdgeRouter")) {
257 setIsEdgeRouter(j.asBoolean());
258 } else if (key.equals("adjacencySids") || key.equals("subnets")) {
259 getInnerParams(j, key);
261 throw new UnknownSegmentRouterConfig(key, dpid);
266 private void getInnerParams(JsonNode j, String innerParam) {
267 Iterator<JsonNode> innerList = j.elements();
268 while (innerList.hasNext()) {
269 Iterator<Entry<String, JsonNode>> f = innerList.next().fields();
272 String subnetIp = null;
273 List<Integer> ports = null;
274 while (f.hasNext()) {
275 Entry<String, JsonNode> fe = f.next();
276 if (fe.getKey().equals("portNo")) {
277 portNo = fe.getValue().asInt();
278 } else if (fe.getKey().equals("adjSid")) {
279 adjSid = fe.getValue().asInt();
280 } else if (fe.getKey().equals("subnetIp")) {
281 subnetIp = fe.getValue().asText();
282 } else if (fe.getKey().equals("ports")) {
283 if (fe.getValue().isArray()) {
284 Iterator<JsonNode> i = fe.getValue().elements();
285 ports = new ArrayList<>();
286 while (i.hasNext()) {
287 ports.add(i.next().asInt());
291 throw new UnknownSegmentRouterConfig(fe.getKey(), dpid);
294 if (innerParam.equals("adjacencySids")) {
295 AdjacencySid ads = new AdjacencySid(adjSid, ports);
296 adjacencySids.add(ads);
298 Subnet sip = new Subnet(portNo, subnetIp);
304 private void validateParams() {
305 if (routerIp == null) {
306 throw new IpNotSpecified(dpid);
308 if (routerMac == null) {
309 throw new MacNotSpecified(dpid);
311 if (isEdgeRouter && subnets.isEmpty()) {
312 throw new SubnetNotSpecifiedInEdgeRouter(dpid);
314 if (!isEdgeRouter && !subnets.isEmpty()) {
315 throw new SubnetSpecifiedInBackboneRouter(dpid);
317 if (nodeSid > SRGB_MAX) {
318 throw new NodeLabelNotInSRGB(nodeSid, dpid);
320 for (AdjacencySid as : adjacencySids) {
321 int label = as.getAdjSid();
322 List<Integer> plist = as.getPorts();
323 if (label <= SRGB_MAX) {
324 throw new AdjacencyLabelInSRGB(label, dpid);
326 if (plist.size() <= 1) {
327 throw new AdjacencyLabelNotEnoughPorts(label, dpid);
332 // TODO more validations
336 * Setting publishAttributes implies that this is the configuration that
337 * will be added to Topology.Switch object before it is published on the
338 * channel to other controller instances.
340 private void setPublishAttributes() {
341 publishAttributes.put(ROUTER_IP, routerIp);
342 publishAttributes.put(ROUTER_MAC, routerMac);
343 publishAttributes.put(NODE_SID, String.valueOf(nodeSid));
344 publishAttributes.put(ISEDGE, String.valueOf(isEdgeRouter));
345 ObjectMapper mapper = new ObjectMapper();
347 publishAttributes.put(ADJACENCY_SIDS,
348 mapper.writeValueAsString(adjacencySids));
349 publishAttributes.put(SUBNETS,
350 mapper.writeValueAsString(subnets));
351 } catch (JsonProcessingException e) {
352 log.error("Error while writing SR config: {}", e.getCause());
353 } catch (IOException e) {
354 log.error("Error while writing SR config: {}", e.getCause());
358 // ********************
360 // ********************
362 public static class IpNotSpecified extends RuntimeException {
363 private static final long serialVersionUID = -3001502553646331686L;
365 public IpNotSpecified(DeviceId dpid) {
367 log.error("Router IP address not specified for SR config dpid:{}",
372 public static class MacNotSpecified extends RuntimeException {
373 private static final long serialVersionUID = -5850132094884129179L;
375 public MacNotSpecified(DeviceId dpid) {
377 log.error("Router Mac address not specified for SR config dpid:{}",
382 public static class UnknownSegmentRouterConfig extends RuntimeException {
383 private static final long serialVersionUID = -5750132094884129179L;
385 public UnknownSegmentRouterConfig(String key, DeviceId dpid) {
387 log.error("Unknown Segment Router config {} in dpid: {}", key,
392 public static class SubnetNotSpecifiedInEdgeRouter extends RuntimeException {
393 private static final long serialVersionUID = -5855458472668581268L;
395 public SubnetNotSpecifiedInEdgeRouter(DeviceId dpid) {
397 log.error("Subnet was not specified for edge router in dpid: {}",
402 public static class SubnetSpecifiedInBackboneRouter extends RuntimeException {
403 private static final long serialVersionUID = 1L;
405 public SubnetSpecifiedInBackboneRouter(DeviceId dpid) {
407 log.error("Subnet was specified in backbone router in dpid: {}",
412 public static class NodeLabelNotInSRGB extends RuntimeException {
413 private static final long serialVersionUID = -8482670903748519526L;
415 public NodeLabelNotInSRGB(int label, DeviceId dpid) {
417 log.error("Node sif {} specified in not in global label-base "
418 + "in dpid: {}", label,
423 public static class AdjacencyLabelInSRGB extends RuntimeException {
424 private static final long serialVersionUID = -8482670903748519526L;
426 public AdjacencyLabelInSRGB(int label, DeviceId dpid) {
428 log.error("Adjaceny label {} specified from global label-base "
429 + "in dpid: {}", label,
434 public static class AdjacencyLabelNotEnoughPorts extends RuntimeException {
435 private static final long serialVersionUID = -8482670903748519526L;
437 public AdjacencyLabelNotEnoughPorts(int label, DeviceId dpid) {
439 log.error("Adjaceny label {} must be specified for at least 2 ports. "
440 + "Adjacency labels for single ports are auto-generated "
441 + "in dpid: {}", label,