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