blob: a7544b750d1b3abe97cbfb75219a77955e7d00b9 [file] [log] [blame]
Thomas Vachuska8fd25052015-09-10 16:15:33 -07001/*
Brian O'Connor43b53542016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska8fd25052015-09-10 16:15:33 -07003 *
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 */
Charles Chan319d1a22015-11-03 10:42:14 -080016package org.onosproject.segmentrouting.config;
sangho80f11cb2015-04-01 13:05:26 -070017
Charles Chan82ab1932016-01-30 23:22:37 -080018import com.google.common.collect.HashMultimap;
Charles Chanc6ad7752015-10-29 14:58:10 -070019import com.google.common.collect.ImmutableSet;
Charles Chan82ab1932016-01-30 23:22:37 -080020import com.google.common.collect.SetMultimap;
sangho80f11cb2015-04-01 13:05:26 -070021import org.onlab.packet.Ip4Address;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070022import org.onlab.packet.Ip4Prefix;
Pier Ventreadb4ae62016-11-23 09:57:42 -080023import org.onlab.packet.Ip6Address;
Pier Ventreb6a7f342016-11-26 21:05:22 -080024import org.onlab.packet.Ip6Prefix;
Charles Chandebfea32016-10-24 14:52:01 -070025import org.onlab.packet.IpAddress;
Charles Chan82ab1932016-01-30 23:22:37 -080026import org.onlab.packet.IpPrefix;
sangho80f11cb2015-04-01 13:05:26 -070027import org.onlab.packet.MacAddress;
Charles Chanb7f75ac2016-01-11 18:28:54 -080028import org.onlab.packet.VlanId;
Charles Chane7c61022015-10-07 14:21:45 -070029import org.onosproject.incubator.net.config.basics.ConfigException;
30import org.onosproject.incubator.net.config.basics.InterfaceConfig;
31import org.onosproject.incubator.net.intf.Interface;
32import org.onosproject.net.ConnectPoint;
Charles Chane7c61022015-10-07 14:21:45 -070033import org.onosproject.net.host.InterfaceIpAddress;
sangho80f11cb2015-04-01 13:05:26 -070034import org.onosproject.net.DeviceId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070035import org.onosproject.net.PortNumber;
Charles Chan46fdfaf2016-11-09 20:51:44 -080036import org.onosproject.segmentrouting.SegmentRoutingManager;
sangho80f11cb2015-04-01 13:05:26 -070037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070040import java.util.ArrayList;
Pier Ventreb6a7f342016-11-26 21:05:22 -080041import java.util.Collections;
sangho80f11cb2015-04-01 13:05:26 -070042import java.util.HashMap;
Charles Chan9bec8a32015-12-01 10:00:51 -080043import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070044import java.util.List;
45import java.util.Map;
Charles Chan72f556a2015-10-05 17:50:33 -070046import java.util.Set;
Saurav Das7c305372015-10-28 12:39:42 -070047import java.util.concurrent.ConcurrentHashMap;
Charles Chan46fdfaf2016-11-09 20:51:44 -080048import java.util.stream.Collectors;
sangho80f11cb2015-04-01 13:05:26 -070049
Charles Chanc22cef32016-04-29 14:38:22 -070050import static com.google.common.base.Preconditions.checkNotNull;
51
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070052/**
53 * Segment Routing configuration component that reads the
54 * segment routing related configuration from Network Configuration Manager
55 * component and organizes in more accessible formats.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070056 */
sangho80f11cb2015-04-01 13:05:26 -070057public class DeviceConfiguration implements DeviceProperties {
58
Charles Chan46fdfaf2016-11-09 20:51:44 -080059 private static final String ERROR_CONFIG = "Configuration error.";
Charles Chan46fdfaf2016-11-09 20:51:44 -080060 private static final String NO_SUBNET = "No subnet configured on {}";
61
Charles Chan43547ca2016-02-10 20:46:58 -080062 private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -070063 private final List<Integer> allSegmentIds = new ArrayList<>();
Charles Chanb7f75ac2016-01-11 18:28:54 -080064 private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
Charles Chan46fdfaf2016-11-09 20:51:44 -080065 private SegmentRoutingManager srManager;
sangho80f11cb2015-04-01 13:05:26 -070066
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070067 private class SegmentRouterInfo {
Pier Ventreadb4ae62016-11-23 09:57:42 -080068 int ipv4NodeSid;
69 int ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070070 DeviceId deviceId;
Pier Ventreadb4ae62016-11-23 09:57:42 -080071 Ip4Address ipv4Loopback;
72 Ip6Address ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070073 MacAddress mac;
74 boolean isEdge;
Pier Ventreb6a7f342016-11-26 21:05:22 -080075 SetMultimap<PortNumber, IpAddress> gatewayIps;
76 SetMultimap<PortNumber, IpPrefix> subnets;
Charles Chan9bec8a32015-12-01 10:00:51 -080077 Map<Integer, Set<Integer>> adjacencySids;
Charles Chan2b078ae2015-10-14 11:24:40 -070078
79 public SegmentRouterInfo() {
Pier Ventreb6a7f342016-11-26 21:05:22 -080080 gatewayIps = HashMultimap.create();
Charles Chan82ab1932016-01-30 23:22:37 -080081 subnets = HashMultimap.create();
Charles Chan2b078ae2015-10-14 11:24:40 -070082 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070083 }
sangho80f11cb2015-04-01 13:05:26 -070084
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070085 /**
Charles Chanb7f75ac2016-01-11 18:28:54 -080086 * Constructs device configuration for all Segment Router devices,
87 * organizing the data into various maps for easier access.
Brian O'Connor65eeb572015-10-09 17:03:44 -070088 *
Charles Chan46fdfaf2016-11-09 20:51:44 -080089 * @param srManager Segment Routing Manager
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070090 */
Charles Chan46fdfaf2016-11-09 20:51:44 -080091 public DeviceConfiguration(SegmentRoutingManager srManager) {
92 this.srManager = srManager;
Charles Chan57bd98c2016-02-22 19:27:29 -080093
Charles Chane7c61022015-10-07 14:21:45 -070094 // Read config from device subject, excluding gatewayIps and subnets.
95 Set<DeviceId> deviceSubjects =
Charles Chan46fdfaf2016-11-09 20:51:44 -080096 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -070097 deviceSubjects.forEach(subject -> {
Charles Chan82ab1932016-01-30 23:22:37 -080098 SegmentRoutingDeviceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -080099 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700100 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chan72f556a2015-10-05 17:50:33 -0700101 info.deviceId = subject;
Pier Ventreadb4ae62016-11-23 09:57:42 -0800102 info.ipv4NodeSid = config.nodeSidIPv4();
103 info.ipv6NodeSid = config.nodeSidIPv6();
104 info.ipv4Loopback = config.routerIpv4();
105 info.ipv6Loopback = config.routerIpv6();
Charles Chan9bec8a32015-12-01 10:00:51 -0800106 info.mac = config.routerMac();
Charles Chan72f556a2015-10-05 17:50:33 -0700107 info.isEdge = config.isEdgeRouter();
Charles Chan9bec8a32015-12-01 10:00:51 -0800108 info.adjacencySids = config.adjacencySids();
Charles Chanb7f75ac2016-01-11 18:28:54 -0800109 deviceConfigMap.put(info.deviceId, info);
Charles Chan68363b12017-06-26 15:25:09 -0700110 log.debug("Read device config for device: {}", info.deviceId);
Pier Ventreadb4ae62016-11-23 09:57:42 -0800111 /*
112 * IPv6 sid is not inserted. this part of the code is not used for now.
113 */
114 allSegmentIds.add(info.ipv4NodeSid);
Charles Chan72f556a2015-10-05 17:50:33 -0700115 });
Charles Chane7c61022015-10-07 14:21:45 -0700116
Charles Chan46fdfaf2016-11-09 20:51:44 -0800117 // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
118 Set<ConnectPoint> portSubjects = srManager.cfgService
119 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
120 portSubjects.stream().filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chane7c61022015-10-07 14:21:45 -0700121 InterfaceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800122 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700123 Set<Interface> networkInterfaces;
124 try {
125 networkInterfaces = config.getInterfaces();
126 } catch (ConfigException e) {
127 log.error("Error loading port configuration");
128 return;
129 }
130 networkInterfaces.forEach(networkInterface -> {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800131 VlanId vlanId = networkInterface.vlan();
132 ConnectPoint connectPoint = networkInterface.connectPoint();
133 DeviceId dpid = connectPoint.deviceId();
134 PortNumber port = connectPoint.port();
135 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chane7c61022015-10-07 14:21:45 -0700136
Charles Chan2b078ae2015-10-14 11:24:40 -0700137 // skip if there is no corresponding device for this ConenctPoint
138 if (info != null) {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800139 // Extract subnet information
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800140 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chan2b078ae2015-10-14 11:24:40 -0700141 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800142 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan82ab1932016-01-30 23:22:37 -0800143 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800144 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
145 if (ipPrefix.isIp4()) {
146 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
147 info.gatewayIps.put(port, interfaceAddress.ipAddress());
148 }
149 info.subnets.put(port, interfaceAddress.subnetAddress());
150 } else {
151 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
152 info.gatewayIps.put(port, interfaceAddress.ipAddress());
153 }
154 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan82ab1932016-01-30 23:22:37 -0800155 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700156 });
157 }
Charles Chane7c61022015-10-07 14:21:45 -0700158 });
Pier Luigi6a2643a2017-01-31 09:35:05 -0800159 // We register the connect point with the NRS.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800160 srManager.registerConnectPoint(subject);
Charles Chane7c61022015-10-07 14:21:45 -0700161 });
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700162 }
163
sangho80f11cb2015-04-01 13:05:26 -0700164 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800165 public boolean isConfigured(DeviceId deviceId) {
166 return deviceConfigMap.get(deviceId) != null;
167 }
168
169 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800170 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700171 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
172 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800173 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
174 return srinfo.ipv4NodeSid;
sangho80f11cb2015-04-01 13:05:26 -0700175 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800176 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
177 throw new DeviceConfigNotFoundException(message);
178 }
179 }
180
181 @Override
182 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
183 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
184 if (srinfo != null) {
185 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
186 return srinfo.ipv6NodeSid;
187 } else {
188 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800189 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700190 }
191 }
192
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700193 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800194 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700195 *
196 * @param routerMac router mac address
Saurav Das7c305372015-10-28 12:39:42 -0700197 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700198 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800199 public int getIPv4SegmentId(MacAddress routerMac) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700200 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
201 deviceConfigMap.entrySet()) {
202 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800203 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700204 }
205 }
sangho80f11cb2015-04-01 13:05:26 -0700206
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700207 return -1;
208 }
209
210 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800211 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
212 *
213 * @param routerMac router mac address
214 * @return node segment id, or -1 if not found in config
215 */
216 public int getIPv6SegmentId(MacAddress routerMac) {
217 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
218 deviceConfigMap.entrySet()) {
219 if (entry.getValue().mac.equals(routerMac)) {
220 return entry.getValue().ipv6NodeSid;
221 }
222 }
223
224 return -1;
225 }
226
227 /**
228 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700229 *
230 * @param routerAddress router ip address
Saurav Das7c305372015-10-28 12:39:42 -0700231 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700232 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800233 public int getIPv4SegmentId(Ip4Address routerAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700234 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
235 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800236 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
237 return entry.getValue().ipv4NodeSid;
238 }
239 }
240
241 return -1;
242 }
243
244 /**
245 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
246 *
247 * @param routerAddress router ip address
248 * @return node segment id, or -1 if not found in config
249 */
250 public int getIPv6SegmentId(Ip6Address routerAddress) {
251 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
252 deviceConfigMap.entrySet()) {
253 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
254 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700255 }
256 }
257
258 return -1;
259 }
260
sangho80f11cb2015-04-01 13:05:26 -0700261 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800262 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700263 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
264 if (srinfo != null) {
265 log.trace("getDeviceMac for device{} is {}", deviceId, srinfo.mac);
266 return srinfo.mac;
sangho80f11cb2015-04-01 13:05:26 -0700267 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800268 String message = "getDeviceMac fails for device: " + deviceId + ".";
269 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700270 }
271 }
272
Charles Chan319d1a22015-11-03 10:42:14 -0800273 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800274 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700275 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
276 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800277 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
278 return srinfo.ipv4Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700279 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800280 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
281 throw new DeviceConfigNotFoundException(message);
282 }
283 }
284
285 @Override
286 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
287 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
288 if (srinfo != null) {
289 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
290 return srinfo.ipv6Loopback;
291 } else {
292 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800293 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700294 }
sangho80f11cb2015-04-01 13:05:26 -0700295 }
296
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700297 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800298 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700299 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
300 if (srinfo != null) {
301 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
302 return srinfo.isEdge;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700303 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800304 String message = "isEdgeDevice fails for device: " + deviceId + ".";
305 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700306 }
307 }
308
sangho80f11cb2015-04-01 13:05:26 -0700309 @Override
310 public List<Integer> getAllDeviceSegmentIds() {
311 return allSegmentIds;
312 }
313
Charles Chan77277672015-10-20 16:24:19 -0700314 @Override
Pier Ventreb6a7f342016-11-26 21:05:22 -0800315 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das52d4ed72016-03-28 19:00:18 -0700316 throws DeviceConfigNotFoundException {
317 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
318 if (srinfo == null) {
319 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
320 throw new DeviceConfigNotFoundException(message);
321 }
Charles Chan77277672015-10-20 16:24:19 -0700322 // Construct subnet-port mapping from port-subnet mapping
Pier Ventreb6a7f342016-11-26 21:05:22 -0800323 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
324 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan82ab1932016-01-30 23:22:37 -0800325
326 portSubnetMap.entries().forEach(entry -> {
327 PortNumber port = entry.getKey();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800328 IpPrefix subnet = entry.getValue();
Charles Chan82ab1932016-01-30 23:22:37 -0800329
Pier Ventreb6a7f342016-11-26 21:05:22 -0800330 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
331 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chanbbd004c2016-02-16 23:14:49 -0800332 return;
333 }
334
Charles Chan77277672015-10-20 16:24:19 -0700335 if (subnetPortMap.containsKey(subnet)) {
336 subnetPortMap.get(subnet).add(port);
337 } else {
338 ArrayList<PortNumber> ports = new ArrayList<>();
339 ports.add(port);
340 subnetPortMap.put(subnet, ports);
341 }
342 });
Charles Chan77277672015-10-20 16:24:19 -0700343 return subnetPortMap;
344 }
345
sangho80f11cb2015-04-01 13:05:26 -0700346 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700347 * Returns the device identifier or data plane identifier (dpid)
348 * of a segment router given its segment id.
sangho80f11cb2015-04-01 13:05:26 -0700349 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700350 * @param sid segment id
351 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700352 */
353 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700354 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
355 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800356 if (entry.getValue().ipv4NodeSid == sid ||
357 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700358 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700359 }
360 }
361
362 return null;
363 }
364
365 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700366 * Returns the device identifier or data plane identifier (dpid)
367 * of a segment router given its router ip address.
sangho80f11cb2015-04-01 13:05:26 -0700368 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700369 * @param ipAddress router ip address
370 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700371 */
372 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700373 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
374 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800375 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
376 return entry.getValue().deviceId;
377 }
378 }
379
380 return null;
381 }
382
383 /**
384 * Returns the device identifier or data plane identifier (dpid)
385 * of a segment router given its router ipv6 address.
386 *
387 * @param ipAddress router ipv6 address
388 * @return deviceId device identifier
389 */
390 public DeviceId getDeviceId(Ip6Address ipAddress) {
391 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
392 deviceConfigMap.entrySet()) {
393 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700394 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700395 }
396 }
397
398 return null;
399 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700400
401 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700402 * Returns the configured port ip addresses for a segment router.
403 * These addresses serve as gateway IP addresses for the subnets configured
404 * on those ports.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700405 *
406 * @param deviceId device identifier
Saurav Dasc28b3432015-10-30 17:45:38 -0700407 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700408 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800409 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700410 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
411 if (srinfo != null) {
412 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
413 srinfo.gatewayIps.values());
Saurav Dasc28b3432015-10-30 17:45:38 -0700414 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700415 }
Saurav Das7c305372015-10-28 12:39:42 -0700416 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700417 }
418
419 /**
420 * Returns the configured subnet prefixes for a segment router.
421 *
422 * @param deviceId device identifier
Saurav Das7c305372015-10-28 12:39:42 -0700423 * @return list of ip prefixes or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700424 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800425 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700426 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
427 if (srinfo != null) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800428 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chandebfea32016-10-24 14:52:01 -0700429 return builder.addAll(srinfo.subnets.values()).build();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700430 }
Saurav Das7c305372015-10-28 12:39:42 -0700431 return null;
432 }
433
Charles Chan46fdfaf2016-11-09 20:51:44 -0800434
Saurav Das7c305372015-10-28 12:39:42 -0700435 /**
Charles Chan46fdfaf2016-11-09 20:51:44 -0800436 * Returns the subnet configuration of given device and port.
Saurav Das7c305372015-10-28 12:39:42 -0700437 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800438 * @param deviceId Device ID
439 * @param port Port number
Pier Ventreb6a7f342016-11-26 21:05:22 -0800440 * @return The subnets configured on given port or empty set if
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700441 * the port is unconfigured or suppressed.
Saurav Das7c305372015-10-28 12:39:42 -0700442 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800443 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800444 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
445
446 if (isSuppressedPort(connectPoint)) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800447 return Collections.emptySet();
Saurav Das7c305372015-10-28 12:39:42 -0700448 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800449
Pier Ventreb6a7f342016-11-26 21:05:22 -0800450 Set<IpPrefix> subnets =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800451 srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
452 .flatMap(intf -> intf.ipAddressesList().stream())
453 .map(InterfaceIpAddress::subnetAddress)
Charles Chan46fdfaf2016-11-09 20:51:44 -0800454 .collect(Collectors.toSet());
455
Jon Hall31d84782017-01-18 20:15:44 -0800456 if (subnets.isEmpty()) {
Saurav Dasf9332192017-02-18 14:05:44 -0800457 log.debug(NO_SUBNET, connectPoint);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800458 return Collections.emptySet();
Charles Chan46fdfaf2016-11-09 20:51:44 -0800459 }
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700460
461 return subnets;
Pier Ventreb6a7f342016-11-26 21:05:22 -0800462 }
463
464 /**
465 * Returns the IPv4 subnet configured of given device and port.
466 *
467 * @param deviceId Device ID
468 * @param port Port number
469 * @return The IPv4 subnet configured on given port or null if
470 * the port is unconfigured, misconfigured or suppressed.
471 */
472 public Ip4Prefix getPortIPv4Subnet(DeviceId deviceId, PortNumber port) {
473 return getPortSubnets(deviceId, port).stream()
474 .filter(IpPrefix::isIp4)
475 .map(IpPrefix::getIp4Prefix)
476 .findFirst().orElse(null);
477 }
478
479 /**
480 * Returns the IPv6 subnet configured of given device and port.
481 *
482 * @param deviceId Device ID
483 * @param port Port number
484 * @return The IPV6 subnet configured on given port or null if
485 * the port is unconfigured, misconfigured or suppressed.
486 */
487 public Ip6Prefix getPortIPv6Subnet(DeviceId deviceId, PortNumber port) {
488 return getPortSubnets(deviceId, port).stream()
489 .filter(IpPrefix::isIp6)
490 .map(IpPrefix::getIp6Prefix)
491 .findFirst().orElse(null);
492 }
493
494 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700495 * Returns the router ip address of segment router that has the
496 * specified ip address in its subnets.
497 *
498 * @param destIpAddress target ip address
499 * @return router ip address
500 */
501 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan70661362016-12-09 12:54:49 -0800502 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
503
504 if (matchIntf == null) {
505 log.debug("No router was found for {}", destIpAddress);
506 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700507 }
508
Charles Chan70661362016-12-09 12:54:49 -0800509 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
510 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
511 if (srInfo == null) {
512 log.debug("No device config was found for {}", routerDeviceId);
513 return null;
514 }
515
Pier Ventreadb4ae62016-11-23 09:57:42 -0800516 return srInfo.ipv4Loopback;
517 }
518
519 /**
520 * Returns the router ipv6 address of segment router that has the
521 * specified ip address in its subnets.
522 *
523 * @param destIpAddress target ip address
524 * @return router ip address
525 */
526 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
527 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
528
529 if (matchIntf == null) {
530 log.debug("No router was found for {}", destIpAddress);
531 return null;
532 }
533
534 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
535 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
536 if (srInfo == null) {
537 log.debug("No device config was found for {}", routerDeviceId);
538 return null;
539 }
540
541 return srInfo.ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700542 }
543
544 /**
545 * Returns the router mac address of segment router that has the
546 * specified ip address as one of its subnet gateway ip address.
547 *
548 * @param gatewayIpAddress router gateway ip address
Saurav Das7c305372015-10-28 12:39:42 -0700549 * @return router mac address or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700550 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800551 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700552 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
553 deviceConfigMap.entrySet()) {
554 if (entry.getValue().gatewayIps.
555 values().contains(gatewayIpAddress)) {
556 return entry.getValue().mac;
557 }
558 }
559
560 log.debug("Cannot find a router for {}", gatewayIpAddress);
561 return null;
562 }
sangho9b169e32015-04-14 16:27:13 -0700563
sangho9b169e32015-04-14 16:27:13 -0700564 /**
565 * Checks if the host is in the subnet defined in the router with the
566 * device ID given.
567 *
568 * @param deviceId device identification of the router
569 * @param hostIp host IP address to check
570 * @return true if the host is within the subnet of the router,
571 * false if no subnet is defined under the router or if the host is not
572 * within the subnet defined in the router
573 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800574 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
sangho9b169e32015-04-14 16:27:13 -0700575
Pier Ventreb6a7f342016-11-26 21:05:22 -0800576 Set<IpPrefix> subnets = getSubnets(deviceId);
sangho9b169e32015-04-14 16:27:13 -0700577 if (subnets == null) {
578 return false;
579 }
580
Pier Ventreb6a7f342016-11-26 21:05:22 -0800581 for (IpPrefix subnet: subnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800582 // Exclude /0 since it is a special case used for default route
583 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho9b169e32015-04-14 16:27:13 -0700584 return true;
585 }
586 }
587
588 return false;
589 }
sangho27462c62015-05-14 00:39:53 -0700590
591 /**
Charles Chandebfea32016-10-24 14:52:01 -0700592 * Checks if the IP is in the subnet defined on given connect point.
593 *
594 * @param connectPoint Connect point
595 * @param ip The IP address to check
596 * @return True if the IP belongs to the subnet.
597 * False if the IP does not belong to the subnet, or
598 * there is no subnet configuration on given connect point.
599 */
600 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800601 Ip4Prefix ipv4Subnet = getPortIPv4Subnet(connectPoint.deviceId(), connectPoint.port());
602 Ip6Prefix ipv6Subnet = getPortIPv6Subnet(connectPoint.deviceId(), connectPoint.port());
603 return (ipv4Subnet != null && ipv4Subnet.contains(ip)) ||
604 (ipv6Subnet != null && ipv6Subnet.contains(ip));
Charles Chandebfea32016-10-24 14:52:01 -0700605 }
606
607 /**
sangho27462c62015-05-14 00:39:53 -0700608 * Returns the ports corresponding to the adjacency Sid given.
609 *
610 * @param deviceId device identification of the router
611 * @param sid adjacency Sid
Charles Chan9bec8a32015-12-01 10:00:51 -0800612 * @return set of port numbers
sangho27462c62015-05-14 00:39:53 -0700613 */
Charles Chan9bec8a32015-12-01 10:00:51 -0800614 public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700615 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800616 return srinfo != null ?
617 ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
618 ImmutableSet.copyOf(new HashSet<>());
sangho27462c62015-05-14 00:39:53 -0700619 }
620
621 /**
622 * Check if the Sid given is whether adjacency Sid of the router device or not.
623 *
624 * @param deviceId device identification of the router
625 * @param sid Sid to check
626 * @return true if the Sid given is the adjacency Sid of the device,
627 * otherwise false
628 */
629 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700630 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800631 return srinfo != null && srinfo.adjacencySids.containsKey(sid);
sangho27462c62015-05-14 00:39:53 -0700632 }
Charles Chan43547ca2016-02-10 20:46:58 -0800633
Charles Chanc91c8782016-03-30 17:54:24 -0700634 /**
Charles Chanc22cef32016-04-29 14:38:22 -0700635 * Add subnet to specific connect point.
636 *
637 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800638 * @param ipPrefix subnet being added to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700639 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800640 public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700641 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800642 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700643 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
644 if (srinfo == null) {
645 log.warn("Device {} is not configured. Abort.", cp.deviceId());
646 return;
647 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800648 srinfo.subnets.put(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700649 }
650
651 /**
652 * Remove subnet from specific connect point.
653 *
654 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800655 * @param ipPrefix subnet being removed to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700656 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800657 public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700658 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800659 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700660 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
661 if (srinfo == null) {
662 log.warn("Device {} is not configured. Abort.", cp.deviceId());
663 return;
664 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800665 srinfo.subnets.remove(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700666 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800667
668 private boolean isSuppressedPort(ConnectPoint connectPoint) {
669 SegmentRoutingAppConfig appConfig = srManager.cfgService
Ray Milkeyb85de082017-04-05 09:42:04 -0700670 .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800671 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chandebfea32016-10-24 14:52:01 -0700672 log.info("Interface configuration on port {} is ignored", connectPoint);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800673 return true;
674 }
675 return false;
676 }
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800677}