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