c8d4a54aadfefe06b783d96c8b9257449a81dd4d
[onosfw.git] /
1 /*
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  */
16 package org.onosproject.segmentrouting.config;
17
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;
23 import java.util.Set;
24 import java.util.concurrent.ConcurrentHashMap;
25
26 import org.onosproject.net.DeviceId;
27 import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 import com.fasterxml.jackson.core.JsonProcessingException;
32 import com.fasterxml.jackson.databind.JsonNode;
33 import com.fasterxml.jackson.databind.ObjectMapper;
34
35 /**
36  * Manages additional configuration for switches configured as Segment Routers.
37  */
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;
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<>();
71         adjacencySids = new ArrayList<>();
72         subnets = new ArrayList<>();
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<>();
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 }