eef1b147fafa93e077b475805595173bd6aa1598
[onosfw.git] /
1 /*
2  * Copyright 2014-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;
17
18 import com.google.common.collect.Lists;
19 import org.onlab.packet.Ip4Address;
20 import org.onlab.packet.Ip4Prefix;
21 import org.onlab.packet.MacAddress;
22 import org.onosproject.incubator.net.config.basics.ConfigException;
23 import org.onosproject.incubator.net.config.basics.InterfaceConfig;
24 import org.onosproject.incubator.net.intf.Interface;
25 import org.onosproject.net.ConnectPoint;
26 import org.onosproject.net.config.NetworkConfigRegistry;
27 import org.onosproject.net.host.InterfaceIpAddress;
28 import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
29 import org.onosproject.segmentrouting.config.SegmentRoutingConfig.AdjacencySid;
30 import org.onosproject.segmentrouting.grouphandler.DeviceProperties;
31 import org.onosproject.net.DeviceId;
32 import org.onosproject.net.PortNumber;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Set;
41
42 /**
43  * Segment Routing configuration component that reads the
44  * segment routing related configuration from Network Configuration Manager
45  * component and organizes in more accessible formats.
46  *
47  * TODO: Merge multiple Segment Routing configuration wrapper classes into one.
48  */
49 public class DeviceConfiguration implements DeviceProperties {
50
51     private static final Logger log = LoggerFactory
52             .getLogger(DeviceConfiguration.class);
53     private final List<Integer> allSegmentIds = new ArrayList<>();
54     private final HashMap<DeviceId, SegmentRouterInfo> deviceConfigMap = new HashMap<>();
55
56     private class SegmentRouterInfo {
57         int nodeSid;
58         DeviceId deviceId;
59         Ip4Address ip;
60         MacAddress mac;
61         boolean isEdge;
62         HashMap<PortNumber, Ip4Address> gatewayIps;
63         HashMap<PortNumber, Ip4Prefix> subnets;
64         List<AdjacencySid> adjacencySids;
65
66         public SegmentRouterInfo() {
67             this.gatewayIps = new HashMap<>();
68             this.subnets = new HashMap<>();
69         }
70     }
71
72     /**
73      * Constructor. Reads all the configuration for all devices of type
74      * Segment Router and organizes into various maps for easier access.
75      *
76      * @param cfgService config service
77      */
78     public DeviceConfiguration(NetworkConfigRegistry cfgService) {
79         // Read config from device subject, excluding gatewayIps and subnets.
80         Set<DeviceId> deviceSubjects =
81                 cfgService.getSubjects(DeviceId.class, SegmentRoutingConfig.class);
82         deviceSubjects.forEach(subject -> {
83             SegmentRoutingConfig config =
84                 cfgService.getConfig(subject, SegmentRoutingConfig.class);
85             SegmentRouterInfo info = new SegmentRouterInfo();
86             info.deviceId = subject;
87             info.nodeSid = config.getSid();
88             info.ip = config.getIp();
89             info.mac = config.getMac();
90             info.isEdge = config.isEdgeRouter();
91             info.adjacencySids = config.getAdjacencySids();
92
93             this.deviceConfigMap.put(info.deviceId, info);
94             this.allSegmentIds.add(info.nodeSid);
95         });
96
97         // Read gatewayIps and subnets from port subject.
98         Set<ConnectPoint> portSubjects =
99             cfgService.getSubjects(ConnectPoint.class, InterfaceConfig.class);
100         portSubjects.forEach(subject -> {
101             InterfaceConfig config =
102                     cfgService.getConfig(subject, InterfaceConfig.class);
103             Set<Interface> networkInterfaces;
104             try {
105                 networkInterfaces = config.getInterfaces();
106             } catch (ConfigException e) {
107                 log.error("Error loading port configuration");
108                 return;
109             }
110             networkInterfaces.forEach(networkInterface -> {
111                 DeviceId dpid = networkInterface.connectPoint().deviceId();
112                 PortNumber port = networkInterface.connectPoint().port();
113                 SegmentRouterInfo info = this.deviceConfigMap.get(dpid);
114
115                 // skip if there is no corresponding device for this ConenctPoint
116                 if (info != null) {
117                     Set<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddresses();
118                     interfaceAddresses.forEach(interfaceAddress -> {
119                         info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address());
120                         info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix());
121                     });
122                 }
123             });
124
125         });
126     }
127
128     /**
129      * Returns the segment id of a segment router.
130      *
131      * @param deviceId device identifier
132      * @return segment id
133      */
134     @Override
135     public int getSegmentId(DeviceId deviceId) {
136         if (deviceConfigMap.get(deviceId) != null) {
137             log.debug("getSegmentId for device{} is {}",
138                     deviceId,
139                     deviceConfigMap.get(deviceId).nodeSid);
140             return deviceConfigMap.get(deviceId).nodeSid;
141         } else {
142             log.warn("getSegmentId for device {} "
143                     + "throwing IllegalStateException "
144                     + "because device does not exist in config", deviceId);
145             throw new IllegalStateException();
146         }
147     }
148
149     /**
150      * Returns the segment id of a segment router given its mac address.
151      *
152      * @param routerMac router mac address
153      * @return segment id
154      */
155     public int getSegmentId(MacAddress routerMac) {
156         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
157                     deviceConfigMap.entrySet()) {
158             if (entry.getValue().mac.equals(routerMac)) {
159                 return entry.getValue().nodeSid;
160             }
161         }
162
163         return -1;
164     }
165
166     /**
167      * Returns the segment id of a segment router given its router ip address.
168      *
169      * @param routerAddress router ip address
170      * @return segment id
171      */
172     public int getSegmentId(Ip4Address routerAddress) {
173         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
174             deviceConfigMap.entrySet()) {
175             if (entry.getValue().ip.equals(routerAddress)) {
176                 return entry.getValue().nodeSid;
177             }
178         }
179
180         return -1;
181     }
182
183     /**
184      * Returns the router mac of a segment router.
185      *
186      * @param deviceId device identifier
187      * @return router mac address
188      */
189     @Override
190     public MacAddress getDeviceMac(DeviceId deviceId) {
191         if (deviceConfigMap.get(deviceId) != null) {
192             log.debug("getDeviceMac for device{} is {}",
193                     deviceId,
194                     deviceConfigMap.get(deviceId).mac);
195             return deviceConfigMap.get(deviceId).mac;
196         } else {
197             log.warn("getDeviceMac for device {} "
198                     + "throwing IllegalStateException "
199                     + "because device does not exist in config", deviceId);
200             throw new IllegalStateException();
201         }
202     }
203
204     /**
205      * Returns the router ip address of a segment router.
206      *
207      * @param deviceId device identifier
208      * @return router ip address
209      */
210     public Ip4Address getRouterIp(DeviceId deviceId) {
211         if (deviceConfigMap.get(deviceId) != null) {
212             log.debug("getDeviceIp for device{} is {}",
213                     deviceId,
214                     deviceConfigMap.get(deviceId).ip);
215             return deviceConfigMap.get(deviceId).ip;
216         } else {
217             log.warn("getRouterIp for device {} "
218                     + "throwing IllegalStateException "
219                     + "because device does not exist in config", deviceId);
220             throw new IllegalStateException();
221         }
222     }
223
224     /**
225      * Indicates if the segment router is a edge router or
226      * a transit/back bone router.
227      *
228      * @param deviceId device identifier
229      * @return boolean
230      */
231     @Override
232     public boolean isEdgeDevice(DeviceId deviceId) {
233         if (deviceConfigMap.get(deviceId) != null) {
234             log.debug("isEdgeDevice for device{} is {}",
235                     deviceId,
236                     deviceConfigMap.get(deviceId).isEdge);
237             return deviceConfigMap.get(deviceId).isEdge;
238         } else {
239             log.warn("isEdgeDevice for device {} "
240                     + "throwing IllegalStateException "
241                     + "because device does not exist in config", deviceId);
242             throw new IllegalStateException();
243         }
244     }
245
246     /**
247      * Returns the segment ids of all configured segment routers.
248      *
249      * @return list of segment ids
250      */
251     @Override
252     public List<Integer> getAllDeviceSegmentIds() {
253         return allSegmentIds;
254     }
255
256     /**
257      * Returns the device identifier or data plane identifier (dpid)
258      * of a segment router given its segment id.
259      *
260      * @param sid segment id
261      * @return deviceId device identifier
262      */
263     public DeviceId getDeviceId(int sid) {
264         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
265             deviceConfigMap.entrySet()) {
266             if (entry.getValue().nodeSid == sid) {
267                 return entry.getValue().deviceId;
268             }
269         }
270
271         return null;
272     }
273
274     /**
275      * Returns the device identifier or data plane identifier (dpid)
276      * of a segment router given its router ip address.
277      *
278      * @param ipAddress router ip address
279      * @return deviceId device identifier
280      */
281     public DeviceId getDeviceId(Ip4Address ipAddress) {
282         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
283             deviceConfigMap.entrySet()) {
284             if (entry.getValue().ip.equals(ipAddress)) {
285                 return entry.getValue().deviceId;
286             }
287         }
288
289         return null;
290     }
291
292     /**
293      * Returns the configured subnet gateway ip addresses for a segment router.
294      *
295      * @param deviceId device identifier
296      * @return list of ip addresses
297      */
298     public List<Ip4Address> getSubnetGatewayIps(DeviceId deviceId) {
299         if (deviceConfigMap.get(deviceId) != null) {
300             log.debug("getSubnetGatewayIps for device{} is {}",
301                     deviceId,
302                     deviceConfigMap.get(deviceId).gatewayIps.values());
303             return new ArrayList<>(deviceConfigMap.get(deviceId).gatewayIps.values());
304         } else {
305             return null;
306         }
307     }
308
309     /**
310      * Returns the configured subnet prefixes for a segment router.
311      *
312      * @param deviceId device identifier
313      * @return list of ip prefixes
314      */
315     public List<Ip4Prefix> getSubnets(DeviceId deviceId) {
316         if (deviceConfigMap.get(deviceId) != null) {
317             log.debug("getSubnets for device{} is {}",
318                     deviceId,
319                     deviceConfigMap.get(deviceId).subnets.values());
320             return new ArrayList<>(deviceConfigMap.get(deviceId).subnets.values());
321         } else {
322             return null;
323         }
324     }
325
326     /**
327      * Returns the router ip address of segment router that has the
328      * specified ip address in its subnets.
329      *
330      * @param destIpAddress target ip address
331      * @return router ip address
332      */
333     public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
334         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
335                     deviceConfigMap.entrySet()) {
336             for (Ip4Prefix prefix:entry.getValue().subnets.values()) {
337                 if (prefix.contains(destIpAddress)) {
338                     return entry.getValue().ip;
339                 }
340             }
341         }
342
343         log.debug("No router was found for {}", destIpAddress);
344         return null;
345     }
346
347     /**
348      * Returns the router mac address of segment router that has the
349      * specified ip address as one of its subnet gateway ip address.
350      *
351      * @param gatewayIpAddress router gateway ip address
352      * @return router mac address
353      */
354     public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) {
355         for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
356                 deviceConfigMap.entrySet()) {
357             if (entry.getValue().gatewayIps.
358                     values().contains(gatewayIpAddress)) {
359                 return entry.getValue().mac;
360             }
361         }
362
363         log.debug("Cannot find a router for {}", gatewayIpAddress);
364         return null;
365     }
366
367
368     /**
369      * Checks if the host is in the subnet defined in the router with the
370      * device ID given.
371      *
372      * @param deviceId device identification of the router
373      * @param hostIp   host IP address to check
374      * @return true if the host is within the subnet of the router,
375      * false if no subnet is defined under the router or if the host is not
376      * within the subnet defined in the router
377      */
378     public boolean inSameSubnet(DeviceId deviceId, Ip4Address hostIp) {
379
380         List<Ip4Prefix> subnets = getSubnets(deviceId);
381         if (subnets == null) {
382             return false;
383         }
384
385         for (Ip4Prefix subnet: subnets) {
386             if (subnet.contains(hostIp)) {
387                 return true;
388             }
389         }
390
391         return false;
392     }
393
394     /**
395      * Returns the ports corresponding to the adjacency Sid given.
396      *
397      * @param deviceId device identification of the router
398      * @param sid adjacency Sid
399      * @return list of port numbers
400      */
401     public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
402         if (deviceConfigMap.get(deviceId) != null) {
403             for (AdjacencySid asid : deviceConfigMap.get(deviceId).adjacencySids) {
404                 if (asid.getAsid() == sid) {
405                     return asid.getPorts();
406                 }
407             }
408         }
409
410         return Lists.newArrayList();
411     }
412
413     /**
414      * Check if the Sid given is whether adjacency Sid of the router device or not.
415      *
416      * @param deviceId device identification of the router
417      * @param sid Sid to check
418      * @return true if the Sid given is the adjacency Sid of the device,
419      * otherwise false
420      */
421     public boolean isAdjacencySid(DeviceId deviceId, int sid) {
422         if (deviceConfigMap.get(deviceId) != null) {
423             if (deviceConfigMap.get(deviceId).adjacencySids.isEmpty()) {
424                 return false;
425             } else {
426                 for (AdjacencySid asid:
427                         deviceConfigMap.get(deviceId).adjacencySids) {
428                     if (asid.getAsid() == sid) {
429                         return true;
430                     }
431                 }
432                 return false;
433             }
434         }
435
436         return false;
437     }
438 }