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