blob: dd5c4d6e3d6ee81850007ee02d3d397b0db64bd9 [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070016package org.onosproject.segmentrouting.config;
17
18import java.io.IOException;
19import java.util.ArrayList;
20import java.util.Iterator;
21import java.util.List;
22import java.util.Map.Entry;
23import java.util.Set;
24import java.util.concurrent.ConcurrentHashMap;
25
26import org.onosproject.net.DeviceId;
27import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
28import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
30
31import com.fasterxml.jackson.core.JsonProcessingException;
32import com.fasterxml.jackson.databind.JsonNode;
33import com.fasterxml.jackson.databind.ObjectMapper;
34
35/**
36 * Manages additional configuration for switches configured as Segment Routers.
37 */
38public class SegmentRouterConfig extends SwitchConfig {
39 protected static final Logger log = LoggerFactory
40 .getLogger(SegmentRouterConfig.class);
41 private String routerIp;
42 private String routerMac;
43 private int nodeSid;
44 private boolean isEdgeRouter;
45 private List<AdjacencySid> adjacencySids;
46 private List<Subnet> subnets;
47
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;
55
56 /**
57 * Parses and validates the additional configuration parameters applicable
58 * to segment routers.
59 *
60 * @param swc switch configuration
61 */
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<String, String>();
71 adjacencySids = new ArrayList<AdjacencySid>();
72 subnets = new ArrayList<Subnet>();
73 parseParams();
74 validateParams();
75 setPublishAttributes();
76 }
77
78 /**
79 * Returns the configured segment router IP address.
80 *
81 * @return ip address in string format
82 */
83 public String getRouterIp() {
84 return routerIp;
85 }
86
87 public void setRouterIp(String routerIp) {
88 this.routerIp = routerIp;
89 }
90
91 /**
92 * Returns the configured segment router mac address.
93 *
94 * @return mac address in string format
95 */
96 public String getRouterMac() {
97 return routerMac;
98 }
99
100 public void setRouterMac(String routerMac) {
101 this.routerMac = routerMac;
102 }
103
104 /**
105 * Returns the configured sID for a segment router.
106 *
107 * @return segment identifier
108 */
109 public int getNodeSid() {
110 return nodeSid;
111 }
112
113 public void setNodeSid(int nodeSid) {
114 this.nodeSid = nodeSid;
115 }
116
117 /**
118 * Returns the flag that indicates the configured segment router
119 * is edge or backbone router.
120 *
121 * @return boolean
122 */
123 public boolean isEdgeRouter() {
124 return isEdgeRouter;
125 }
126
127 public void setIsEdgeRouter(boolean isEdge) {
128 this.isEdgeRouter = isEdge;
129 }
130
131 /**
132 * Class representing segment router adjacency identifier.
133 */
134 public static class AdjacencySid {
135 private int adjSid;
136 private List<Integer> ports;
137
138 public AdjacencySid(int adjSid, List<Integer> ports) {
139 this.ports = ports;
140 this.adjSid = adjSid;
141 }
142
143 /**
144 * Returns the list of ports part of a segment
145 * router adjacency identifier.
146 *
147 * @return list of integers
148 */
149 public List<Integer> getPorts() {
150 return ports;
151 }
152
153 public void setPorts(List<Integer> ports) {
154 this.ports = ports;
155 }
156
157 /**
158 * Returns the configured adjacency id of a segment router.
159 *
160 * @return integer
161 */
162 public int getAdjSid() {
163 return adjSid;
164 }
165
166 public void setAdjSid(int adjSid) {
167 this.adjSid = adjSid;
168 }
169 }
170
171 /**
172 * Returns the configured adjacent segment IDs for a segment router.
173 *
174 * @return list of adjacency identifier
175 */
176 public List<AdjacencySid> getAdjacencySids() {
177 return adjacencySids;
178 }
179
180 public void setAdjacencySids(List<AdjacencySid> adjacencySids) {
181 this.adjacencySids = adjacencySids;
182 }
183
184 /**
185 * Class representing a subnet attached to a segment router.
186 */
187 public static class Subnet {
188 private int portNo;
189 private String subnetIp;
190
191 public Subnet(int portNo, String subnetIp) {
192 this.portNo = portNo;
193 this.subnetIp = subnetIp;
194 }
195
196 /**
197 * Returns the port number of segment router on
198 * which subnet is attached.
199 *
200 * @return integer
201 */
202 public int getPortNo() {
203 return portNo;
204 }
205
206 public void setPortNo(int portNo) {
207 this.portNo = portNo;
208 }
209
210 /**
211 * Returns the configured subnet address.
212 *
213 * @return subnet ip address in string format
214 */
215 public String getSubnetIp() {
216 return subnetIp;
217 }
218
219 public void setSubnetIp(String subnetIp) {
220 this.subnetIp = subnetIp;
221 }
222 }
223
224 /**
225 * Returns the configured subnets for a segment router.
226 *
227 * @return list of subnets
228 */
229 public List<Subnet> getSubnets() {
230 return subnets;
231 }
232
233 public void setSubnets(List<Subnet> subnets) {
234 this.subnets = subnets;
235 }
236
237 // ********************
238 // Helper methods
239 // ********************
240
241 private void parseParams() {
242 if (params == null) {
243 throw new NetworkConfigException.ParamsNotSpecified(name);
244 }
245
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);
260 } else {
261 throw new UnknownSegmentRouterConfig(key, dpid);
262 }
263 }
264 }
265
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();
270 int portNo = -1;
271 int adjSid = -1;
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<Integer>();
286 while (i.hasNext()) {
287 ports.add(i.next().asInt());
288 }
289 }
290 } else {
291 throw new UnknownSegmentRouterConfig(fe.getKey(), dpid);
292 }
293 }
294 if (innerParam.equals("adjacencySids")) {
295 AdjacencySid ads = new AdjacencySid(adjSid, ports);
296 adjacencySids.add(ads);
297 } else {
298 Subnet sip = new Subnet(portNo, subnetIp);
299 subnets.add(sip);
300 }
301 }
302 }
303
304 private void validateParams() {
305 if (routerIp == null) {
306 throw new IpNotSpecified(dpid);
307 }
308 if (routerMac == null) {
309 throw new MacNotSpecified(dpid);
310 }
311 if (isEdgeRouter && subnets.isEmpty()) {
312 throw new SubnetNotSpecifiedInEdgeRouter(dpid);
313 }
314 if (!isEdgeRouter && !subnets.isEmpty()) {
315 throw new SubnetSpecifiedInBackboneRouter(dpid);
316 }
317 if (nodeSid > SRGB_MAX) {
318 throw new NodeLabelNotInSRGB(nodeSid, dpid);
319 }
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);
325 }
326 if (plist.size() <= 1) {
327 throw new AdjacencyLabelNotEnoughPorts(label, dpid);
328 }
329 }
330
331
332 // TODO more validations
333 }
334
335 /**
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.
339 */
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();
346 try {
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());
355 }
356 }
357
358 // ********************
359 // Exceptions
360 // ********************
361
362 public static class IpNotSpecified extends RuntimeException {
363 private static final long serialVersionUID = -3001502553646331686L;
364
365 public IpNotSpecified(DeviceId dpid) {
366 super();
367 log.error("Router IP address not specified for SR config dpid:{}",
368 dpid);
369 }
370 }
371
372 public static class MacNotSpecified extends RuntimeException {
373 private static final long serialVersionUID = -5850132094884129179L;
374
375 public MacNotSpecified(DeviceId dpid) {
376 super();
377 log.error("Router Mac address not specified for SR config dpid:{}",
378 dpid);
379 }
380 }
381
382 public static class UnknownSegmentRouterConfig extends RuntimeException {
383 private static final long serialVersionUID = -5750132094884129179L;
384
385 public UnknownSegmentRouterConfig(String key, DeviceId dpid) {
386 super();
387 log.error("Unknown Segment Router config {} in dpid: {}", key,
388 dpid);
389 }
390 }
391
392 public static class SubnetNotSpecifiedInEdgeRouter extends RuntimeException {
393 private static final long serialVersionUID = -5855458472668581268L;
394
395 public SubnetNotSpecifiedInEdgeRouter(DeviceId dpid) {
396 super();
397 log.error("Subnet was not specified for edge router in dpid: {}",
398 dpid);
399 }
400 }
401
402 public static class SubnetSpecifiedInBackboneRouter extends RuntimeException {
403 private static final long serialVersionUID = 1L;
404
405 public SubnetSpecifiedInBackboneRouter(DeviceId dpid) {
406 super();
407 log.error("Subnet was specified in backbone router in dpid: {}",
408 dpid);
409 }
410 }
411
412 public static class NodeLabelNotInSRGB extends RuntimeException {
413 private static final long serialVersionUID = -8482670903748519526L;
414
415 public NodeLabelNotInSRGB(int label, DeviceId dpid) {
416 super();
417 log.error("Node sif {} specified in not in global label-base "
418 + "in dpid: {}", label,
419 dpid);
420 }
421 }
422
423 public static class AdjacencyLabelInSRGB extends RuntimeException {
424 private static final long serialVersionUID = -8482670903748519526L;
425
426 public AdjacencyLabelInSRGB(int label, DeviceId dpid) {
427 super();
428 log.error("Adjaceny label {} specified from global label-base "
429 + "in dpid: {}", label,
430 dpid);
431 }
432 }
433
434 public static class AdjacencyLabelNotEnoughPorts extends RuntimeException {
435 private static final long serialVersionUID = -8482670903748519526L;
436
437 public AdjacencyLabelNotEnoughPorts(int label, DeviceId dpid) {
438 super();
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,
442 dpid);
443 }
444 }
445}