4775c77fecd388d0f9e4f6591b48c1f720184cc4
[onosfw.git] /
1 package org.onosproject.segmentrouting.config;
2
3 import java.io.IOException;
4 import java.util.ArrayList;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Map.Entry;
8 import java.util.Set;
9 import java.util.concurrent.ConcurrentHashMap;
10
11 import org.onosproject.net.DeviceId;
12 import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
16 import com.fasterxml.jackson.core.JsonProcessingException;
17 import com.fasterxml.jackson.databind.JsonNode;
18 import com.fasterxml.jackson.databind.ObjectMapper;
19
20 /**
21  * Manages additional configuration for switches configured as Segment Routers.
22  */
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;
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 }