blob: 4775c77fecd388d0f9e4f6591b48c1f720184cc4 [file] [log] [blame]
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -07001package org.onosproject.segmentrouting.config;
2
3import java.io.IOException;
4import java.util.ArrayList;
5import java.util.Iterator;
6import java.util.List;
7import java.util.Map.Entry;
8import java.util.Set;
9import java.util.concurrent.ConcurrentHashMap;
10
11import org.onosproject.net.DeviceId;
12import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
13import org.slf4j.Logger;
14import org.slf4j.LoggerFactory;
15
16import com.fasterxml.jackson.core.JsonProcessingException;
17import com.fasterxml.jackson.databind.JsonNode;
18import com.fasterxml.jackson.databind.ObjectMapper;
19
20/**
21 * Manages additional configuration for switches configured as Segment Routers.
22 */
23public class SegmentRouterConfig extends SwitchConfig {
24 protected static final Logger log = LoggerFactory
25 .getLogger(SegmentRouterConfig.class);
26 private String routerIp;
27 private String routerMac;
28 private int nodeSid;
29 private boolean isEdgeRouter;
30 private List<AdjacencySid> adjacencySids;
31 private List<Subnet> subnets;
32
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;
40
41 /**
42 * Parses and validates the additional configuration parameters applicable
43 * to segment routers.
44 *
45 * @param swc switch configuration
46 */
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>();
58 parseParams();
59 validateParams();
60 setPublishAttributes();
61 }
62
63 /**
64 * Returns the configured segment router IP address.
65 *
66 * @return ip address in string format
67 */
68 public String getRouterIp() {
69 return routerIp;
70 }
71
72 public void setRouterIp(String routerIp) {
73 this.routerIp = routerIp;
74 }
75
76 /**
77 * Returns the configured segment router mac address.
78 *
79 * @return mac address in string format
80 */
81 public String getRouterMac() {
82 return routerMac;
83 }
84
85 public void setRouterMac(String routerMac) {
86 this.routerMac = routerMac;
87 }
88
89 /**
90 * Returns the configured sID for a segment router.
91 *
92 * @return segment identifier
93 */
94 public int getNodeSid() {
95 return nodeSid;
96 }
97
98 public void setNodeSid(int nodeSid) {
99 this.nodeSid = nodeSid;
100 }
101
102 /**
103 * Returns the flag that indicates the configured segment router
104 * is edge or backbone router.
105 *
106 * @return boolean
107 */
108 public boolean isEdgeRouter() {
109 return isEdgeRouter;
110 }
111
112 public void setIsEdgeRouter(boolean isEdge) {
113 this.isEdgeRouter = isEdge;
114 }
115
116 /**
117 * Class representing segment router adjacency identifier.
118 */
119 public static class AdjacencySid {
120 private int adjSid;
121 private List<Integer> ports;
122
123 public AdjacencySid(int adjSid, List<Integer> ports) {
124 this.ports = ports;
125 this.adjSid = adjSid;
126 }
127
128 /**
129 * Returns the list of ports part of a segment
130 * router adjacency identifier.
131 *
132 * @return list of integers
133 */
134 public List<Integer> getPorts() {
135 return ports;
136 }
137
138 public void setPorts(List<Integer> ports) {
139 this.ports = ports;
140 }
141
142 /**
143 * Returns the configured adjacency id of a segment router.
144 *
145 * @return integer
146 */
147 public int getAdjSid() {
148 return adjSid;
149 }
150
151 public void setAdjSid(int adjSid) {
152 this.adjSid = adjSid;
153 }
154 }
155
156 /**
157 * Returns the configured adjacent segment IDs for a segment router.
158 *
159 * @return list of adjacency identifier
160 */
161 public List<AdjacencySid> getAdjacencySids() {
162 return adjacencySids;
163 }
164
165 public void setAdjacencySids(List<AdjacencySid> adjacencySids) {
166 this.adjacencySids = adjacencySids;
167 }
168
169 /**
170 * Class representing a subnet attached to a segment router.
171 */
172 public static class Subnet {
173 private int portNo;
174 private String subnetIp;
175
176 public Subnet(int portNo, String subnetIp) {
177 this.portNo = portNo;
178 this.subnetIp = subnetIp;
179 }
180
181 /**
182 * Returns the port number of segment router on
183 * which subnet is attached.
184 *
185 * @return integer
186 */
187 public int getPortNo() {
188 return portNo;
189 }
190
191 public void setPortNo(int portNo) {
192 this.portNo = portNo;
193 }
194
195 /**
196 * Returns the configured subnet address.
197 *
198 * @return subnet ip address in string format
199 */
200 public String getSubnetIp() {
201 return subnetIp;
202 }
203
204 public void setSubnetIp(String subnetIp) {
205 this.subnetIp = subnetIp;
206 }
207 }
208
209 /**
210 * Returns the configured subnets for a segment router.
211 *
212 * @return list of subnets
213 */
214 public List<Subnet> getSubnets() {
215 return subnets;
216 }
217
218 public void setSubnets(List<Subnet> subnets) {
219 this.subnets = subnets;
220 }
221
222 // ********************
223 // Helper methods
224 // ********************
225
226 private void parseParams() {
227 if (params == null) {
228 throw new NetworkConfigException.ParamsNotSpecified(name);
229 }
230
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);
245 } else {
246 throw new UnknownSegmentRouterConfig(key, dpid);
247 }
248 }
249 }
250
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();
255 int portNo = -1;
256 int adjSid = -1;
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());
273 }
274 }
275 } else {
276 throw new UnknownSegmentRouterConfig(fe.getKey(), dpid);
277 }
278 }
279 if (innerParam.equals("adjacencySids")) {
280 AdjacencySid ads = new AdjacencySid(adjSid, ports);
281 adjacencySids.add(ads);
282 } else {
283 Subnet sip = new Subnet(portNo, subnetIp);
284 subnets.add(sip);
285 }
286 }
287 }
288
289 private void validateParams() {
290 if (routerIp == null) {
291 throw new IpNotSpecified(dpid);
292 }
293 if (routerMac == null) {
294 throw new MacNotSpecified(dpid);
295 }
296 if (isEdgeRouter && subnets.isEmpty()) {
297 throw new SubnetNotSpecifiedInEdgeRouter(dpid);
298 }
299 if (!isEdgeRouter && !subnets.isEmpty()) {
300 throw new SubnetSpecifiedInBackboneRouter(dpid);
301 }
302 if (nodeSid > SRGB_MAX) {
303 throw new NodeLabelNotInSRGB(nodeSid, dpid);
304 }
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);
310 }
311 if (plist.size() <= 1) {
312 throw new AdjacencyLabelNotEnoughPorts(label, dpid);
313 }
314 }
315
316
317 // TODO more validations
318 }
319
320 /**
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.
324 */
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();
331 try {
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());
340 }
341 }
342
343 // ********************
344 // Exceptions
345 // ********************
346
347 public static class IpNotSpecified extends RuntimeException {
348 private static final long serialVersionUID = -3001502553646331686L;
349
350 public IpNotSpecified(DeviceId dpid) {
351 super();
352 log.error("Router IP address not specified for SR config dpid:{}",
353 dpid);
354 }
355 }
356
357 public static class MacNotSpecified extends RuntimeException {
358 private static final long serialVersionUID = -5850132094884129179L;
359
360 public MacNotSpecified(DeviceId dpid) {
361 super();
362 log.error("Router Mac address not specified for SR config dpid:{}",
363 dpid);
364 }
365 }
366
367 public static class UnknownSegmentRouterConfig extends RuntimeException {
368 private static final long serialVersionUID = -5750132094884129179L;
369
370 public UnknownSegmentRouterConfig(String key, DeviceId dpid) {
371 super();
372 log.error("Unknown Segment Router config {} in dpid: {}", key,
373 dpid);
374 }
375 }
376
377 public static class SubnetNotSpecifiedInEdgeRouter extends RuntimeException {
378 private static final long serialVersionUID = -5855458472668581268L;
379
380 public SubnetNotSpecifiedInEdgeRouter(DeviceId dpid) {
381 super();
382 log.error("Subnet was not specified for edge router in dpid: {}",
383 dpid);
384 }
385 }
386
387 public static class SubnetSpecifiedInBackboneRouter extends RuntimeException {
388 private static final long serialVersionUID = 1L;
389
390 public SubnetSpecifiedInBackboneRouter(DeviceId dpid) {
391 super();
392 log.error("Subnet was specified in backbone router in dpid: {}",
393 dpid);
394 }
395 }
396
397 public static class NodeLabelNotInSRGB extends RuntimeException {
398 private static final long serialVersionUID = -8482670903748519526L;
399
400 public NodeLabelNotInSRGB(int label, DeviceId dpid) {
401 super();
402 log.error("Node sif {} specified in not in global label-base "
403 + "in dpid: {}", label,
404 dpid);
405 }
406 }
407
408 public static class AdjacencyLabelInSRGB extends RuntimeException {
409 private static final long serialVersionUID = -8482670903748519526L;
410
411 public AdjacencyLabelInSRGB(int label, DeviceId dpid) {
412 super();
413 log.error("Adjaceny label {} specified from global label-base "
414 + "in dpid: {}", label,
415 dpid);
416 }
417 }
418
419 public static class AdjacencyLabelNotEnoughPorts extends RuntimeException {
420 private static final long serialVersionUID = -8482670903748519526L;
421
422 public AdjacencyLabelNotEnoughPorts(int label, DeviceId dpid) {
423 super();
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,
427 dpid);
428 }
429 }
430}