blob: 04d63a22d2962b57c106554ef8b9ff7c0ff3dcb6 [file] [log] [blame]
Thomas Vachuska8fd25052015-09-10 16:15:33 -07001/*
Brian O'Connor0947d7e2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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 */
pierventre2b102f92020-09-08 16:45:36 +020016package org.onosproject.segmentrouting;
sangho80f11cb2015-04-01 13:05:26 -070017
Charles Chan6191aca2017-09-12 12:09:22 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
Charles Chan82ab1932016-01-30 23:22:37 -080021import com.google.common.collect.HashMultimap;
Charles Chanc6ad7752015-10-29 14:58:10 -070022import com.google.common.collect.ImmutableSet;
Charles Chan19b70032019-04-17 14:20:26 -070023import com.google.common.collect.Lists;
Charles Chandc7d6f92018-03-20 13:30:38 -070024import com.google.common.collect.Multimaps;
Charles Chan82ab1932016-01-30 23:22:37 -080025import com.google.common.collect.SetMultimap;
Charles Chan19b70032019-04-17 14:20:26 -070026import com.google.common.collect.Sets;
sangho80f11cb2015-04-01 13:05:26 -070027import org.onlab.packet.Ip4Address;
Pier Ventreadb4ae62016-11-23 09:57:42 -080028import org.onlab.packet.Ip6Address;
Charles Chandebfea32016-10-24 14:52:01 -070029import org.onlab.packet.IpAddress;
Charles Chan82ab1932016-01-30 23:22:37 -080030import org.onlab.packet.IpPrefix;
sangho80f11cb2015-04-01 13:05:26 -070031import org.onlab.packet.MacAddress;
Charles Chanb7f75ac2016-01-11 18:28:54 -080032import org.onlab.packet.VlanId;
Charles Chane7c61022015-10-07 14:21:45 -070033import org.onosproject.net.ConnectPoint;
sangho80f11cb2015-04-01 13:05:26 -070034import org.onosproject.net.DeviceId;
Charles Chan5eec3b12019-04-18 14:30:41 -070035import org.onosproject.net.HostId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070036import org.onosproject.net.PortNumber;
Jonathan Hart61e24e12017-11-30 18:23:42 -080037import org.onosproject.net.config.ConfigException;
Andrea Campanella09943842020-03-27 12:53:46 +010038import org.onosproject.net.config.basics.BasicDeviceConfig;
Jonathan Hart61e24e12017-11-30 18:23:42 -080039import org.onosproject.net.config.basics.InterfaceConfig;
40import org.onosproject.net.host.InterfaceIpAddress;
41import org.onosproject.net.intf.Interface;
Charles Chan19b70032019-04-17 14:20:26 -070042import org.onosproject.routeservice.Route;
pierventre2b102f92020-09-08 16:45:36 +020043import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
44import org.onosproject.segmentrouting.config.DeviceProperties;
45import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
46import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
sangho80f11cb2015-04-01 13:05:26 -070047import org.slf4j.Logger;
48import org.slf4j.LoggerFactory;
49
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070050import java.util.ArrayList;
Jonathan Hart61e24e12017-11-30 18:23:42 -080051import java.util.Collection;
Pier Ventreb6a7f342016-11-26 21:05:22 -080052import java.util.Collections;
sangho80f11cb2015-04-01 13:05:26 -070053import java.util.HashMap;
Charles Chan9bec8a32015-12-01 10:00:51 -080054import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070055import java.util.List;
56import java.util.Map;
Charles Chancf789822019-03-22 10:04:27 -070057import java.util.Objects;
Charles Chan72f556a2015-10-05 17:50:33 -070058import java.util.Set;
Saurav Das7c305372015-10-28 12:39:42 -070059import java.util.concurrent.ConcurrentHashMap;
Charles Chan46fdfaf2016-11-09 20:51:44 -080060import java.util.stream.Collectors;
Charles Chan5eec3b12019-04-18 14:30:41 -070061import java.util.stream.Stream;
sangho80f11cb2015-04-01 13:05:26 -070062
Charles Chanc22cef32016-04-29 14:38:22 -070063import static com.google.common.base.Preconditions.checkNotNull;
64
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070065/**
66 * Segment Routing configuration component that reads the
67 * segment routing related configuration from Network Configuration Manager
68 * component and organizes in more accessible formats.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070069 */
sangho80f11cb2015-04-01 13:05:26 -070070public class DeviceConfiguration implements DeviceProperties {
71
Charles Chan46fdfaf2016-11-09 20:51:44 -080072 private static final String NO_SUBNET = "No subnet configured on {}";
73
Charles Chan43547ca2016-02-10 20:46:58 -080074 private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -070075 private final List<Integer> allSegmentIds = new ArrayList<>();
Charles Chanb7f75ac2016-01-11 18:28:54 -080076 private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
Charles Chan46fdfaf2016-11-09 20:51:44 -080077 private SegmentRoutingManager srManager;
sangho80f11cb2015-04-01 13:05:26 -070078
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070079 private class SegmentRouterInfo {
Charles Chan3d35a542018-10-02 12:52:29 -070080 int ipv4NodeSid = -1;
81 int ipv6NodeSid = -1;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070082 DeviceId deviceId;
Pier Ventreadb4ae62016-11-23 09:57:42 -080083 Ip4Address ipv4Loopback;
84 Ip6Address ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070085 MacAddress mac;
86 boolean isEdge;
Pier Ventreb6a7f342016-11-26 21:05:22 -080087 SetMultimap<PortNumber, IpAddress> gatewayIps;
88 SetMultimap<PortNumber, IpPrefix> subnets;
Charles Chan9bec8a32015-12-01 10:00:51 -080089 Map<Integer, Set<Integer>> adjacencySids;
Saurav Das261c3002017-06-13 15:35:54 -070090 DeviceId pairDeviceId;
91 PortNumber pairLocalPort;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070092 int pwRoutingLabel;
Charles Chan2b078ae2015-10-14 11:24:40 -070093
94 public SegmentRouterInfo() {
Charles Chandc7d6f92018-03-20 13:30:38 -070095 gatewayIps = Multimaps.synchronizedSetMultimap(HashMultimap.create());
96 subnets = Multimaps.synchronizedSetMultimap(HashMultimap.create());
Charles Chan2b078ae2015-10-14 11:24:40 -070097 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070098 }
sangho80f11cb2015-04-01 13:05:26 -070099
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700100 /**
Charles Chanb7f75ac2016-01-11 18:28:54 -0800101 * Constructs device configuration for all Segment Router devices,
102 * organizing the data into various maps for easier access.
Brian O'Connor65eeb572015-10-09 17:03:44 -0700103 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800104 * @param srManager Segment Routing Manager
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700105 */
Charles Chan46fdfaf2016-11-09 20:51:44 -0800106 public DeviceConfiguration(SegmentRoutingManager srManager) {
107 this.srManager = srManager;
Saurav Das261c3002017-06-13 15:35:54 -0700108 updateConfig();
109 }
Charles Chan57bd98c2016-02-22 19:27:29 -0800110
Saurav Das261c3002017-06-13 15:35:54 -0700111 public void updateConfig() {
Charles Chane7c61022015-10-07 14:21:45 -0700112 // Read config from device subject, excluding gatewayIps and subnets.
113 Set<DeviceId> deviceSubjects =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800114 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700115 deviceSubjects.forEach(subject -> {
Andrea Campanella09943842020-03-27 12:53:46 +0100116 BasicDeviceConfig basicDeviceConfig = srManager.cfgService.addConfig(subject, BasicDeviceConfig.class);
pierc81188f2020-04-15 22:48:36 +0200117 if (!basicDeviceConfig.purgeOnDisconnection()) {
118 // Setting purge on disconnection flag for the device SR has control over.
119 // addConfig returns a config if it exists or creates a new one.
120 log.info("PurgeOnDisconnection set to true for device {}", subject);
121 basicDeviceConfig.purgeOnDisconnection(true);
122 srManager.cfgService.applyConfig(subject, BasicDeviceConfig.class, basicDeviceConfig.node());
123 }
Charles Chan82ab1932016-01-30 23:22:37 -0800124 SegmentRoutingDeviceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800125 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700126 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chan72f556a2015-10-05 17:50:33 -0700127 info.deviceId = subject;
Pier Ventreadb4ae62016-11-23 09:57:42 -0800128 info.ipv4NodeSid = config.nodeSidIPv4();
129 info.ipv6NodeSid = config.nodeSidIPv6();
130 info.ipv4Loopback = config.routerIpv4();
131 info.ipv6Loopback = config.routerIpv6();
Charles Chan9bec8a32015-12-01 10:00:51 -0800132 info.mac = config.routerMac();
Charles Chan72f556a2015-10-05 17:50:33 -0700133 info.isEdge = config.isEdgeRouter();
Charles Chan9bec8a32015-12-01 10:00:51 -0800134 info.adjacencySids = config.adjacencySids();
Saurav Das261c3002017-06-13 15:35:54 -0700135 info.pairDeviceId = config.pairDeviceId();
136 info.pairLocalPort = config.pairLocalPort();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700137 info.pwRoutingLabel = info.ipv4NodeSid + 1000;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800138 deviceConfigMap.put(info.deviceId, info);
Charles Chan68363b12017-06-26 15:25:09 -0700139 log.debug("Read device config for device: {}", info.deviceId);
Pier Ventreadb4ae62016-11-23 09:57:42 -0800140 /*
141 * IPv6 sid is not inserted. this part of the code is not used for now.
142 */
143 allSegmentIds.add(info.ipv4NodeSid);
Charles Chan72f556a2015-10-05 17:50:33 -0700144 });
Charles Chane7c61022015-10-07 14:21:45 -0700145
Charles Chan46fdfaf2016-11-09 20:51:44 -0800146 // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
147 Set<ConnectPoint> portSubjects = srManager.cfgService
148 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
Jonathan Hart61e24e12017-11-30 18:23:42 -0800149 portSubjects.stream()
150 .filter(subject -> deviceConfigMap.containsKey(subject.deviceId()))
151 .filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chane7c61022015-10-07 14:21:45 -0700152 InterfaceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800153 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700154 Set<Interface> networkInterfaces;
155 try {
156 networkInterfaces = config.getInterfaces();
157 } catch (ConfigException e) {
158 log.error("Error loading port configuration");
159 return;
160 }
161 networkInterfaces.forEach(networkInterface -> {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800162 VlanId vlanId = networkInterface.vlan();
163 ConnectPoint connectPoint = networkInterface.connectPoint();
164 DeviceId dpid = connectPoint.deviceId();
165 PortNumber port = connectPoint.port();
Charles Chan6191aca2017-09-12 12:09:22 -0700166 MacAddress mac = networkInterface.mac();
Charles Chanb7f75ac2016-01-11 18:28:54 -0800167 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chane7c61022015-10-07 14:21:45 -0700168
Charles Chan2b078ae2015-10-14 11:24:40 -0700169 // skip if there is no corresponding device for this ConenctPoint
170 if (info != null) {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800171 // Extract subnet information
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800172 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chan2b078ae2015-10-14 11:24:40 -0700173 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800174 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan82ab1932016-01-30 23:22:37 -0800175 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800176 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
177 if (ipPrefix.isIp4()) {
178 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
179 info.gatewayIps.put(port, interfaceAddress.ipAddress());
180 }
181 info.subnets.put(port, interfaceAddress.subnetAddress());
182 } else {
183 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
184 info.gatewayIps.put(port, interfaceAddress.ipAddress());
185 }
186 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan82ab1932016-01-30 23:22:37 -0800187 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700188 });
Charles Chan6191aca2017-09-12 12:09:22 -0700189
190 // Override interface mac with router mac
191 if (!mac.equals(info.mac)) {
192 ArrayNode array = (ArrayNode) config.node();
193 for (JsonNode intfNode : array) {
194 ObjectNode objNode = (ObjectNode) intfNode;
195 objNode.put(InterfaceConfig.MAC, info.mac.toString());
196 }
197 srManager.cfgService.applyConfig(connectPoint, InterfaceConfig.class, array);
198 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700199 }
Charles Chane7c61022015-10-07 14:21:45 -0700200 });
Pier Luigi6a2643a2017-01-31 09:35:05 -0800201 // We register the connect point with the NRS.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800202 srManager.registerConnectPoint(subject);
Charles Chane7c61022015-10-07 14:21:45 -0700203 });
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700204 }
205
Jonathan Hart61e24e12017-11-30 18:23:42 -0800206 public Collection<DeviceId> getRouters() {
207 return deviceConfigMap.keySet();
208 }
Saurav Das261c3002017-06-13 15:35:54 -0700209
sangho80f11cb2015-04-01 13:05:26 -0700210 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800211 public boolean isConfigured(DeviceId deviceId) {
212 return deviceConfigMap.get(deviceId) != null;
213 }
214
215 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800216 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700217 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
218 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800219 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
220 return srinfo.ipv4NodeSid;
sangho80f11cb2015-04-01 13:05:26 -0700221 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800222 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
223 throw new DeviceConfigNotFoundException(message);
224 }
225 }
226
227 @Override
228 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
229 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
230 if (srinfo != null) {
231 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
232 return srinfo.ipv6NodeSid;
233 } else {
234 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800235 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700236 }
237 }
238
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700239 @Override
240 public int getPWRoutingLabel(DeviceId deviceId) throws DeviceConfigNotFoundException {
241 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
242 if (srinfo != null) {
243 log.trace("pwRoutingLabel for device{} is {}", deviceId, srinfo.pwRoutingLabel);
244 return srinfo.pwRoutingLabel;
245 } else {
246 String message = "getPWRoutingLabel fails for device: " + deviceId + ".";
247 throw new DeviceConfigNotFoundException(message);
248 }
249 }
250
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700251 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800252 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700253 *
254 * @param routerMac router mac address
Saurav Das7c305372015-10-28 12:39:42 -0700255 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700256 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800257 public int getIPv4SegmentId(MacAddress routerMac) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700258 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
259 deviceConfigMap.entrySet()) {
260 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800261 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700262 }
263 }
sangho80f11cb2015-04-01 13:05:26 -0700264
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700265 return -1;
266 }
267
268 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800269 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
270 *
271 * @param routerMac router mac address
272 * @return node segment id, or -1 if not found in config
273 */
274 public int getIPv6SegmentId(MacAddress routerMac) {
275 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
276 deviceConfigMap.entrySet()) {
277 if (entry.getValue().mac.equals(routerMac)) {
278 return entry.getValue().ipv6NodeSid;
279 }
280 }
281
282 return -1;
283 }
284
285 /**
286 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700287 *
288 * @param routerAddress router ip address
Saurav Das7c305372015-10-28 12:39:42 -0700289 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700290 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800291 public int getIPv4SegmentId(Ip4Address routerAddress) {
Charles Chan3d35a542018-10-02 12:52:29 -0700292 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: deviceConfigMap.entrySet()) {
293 Ip4Address ipv4Loopback = entry.getValue().ipv4Loopback;
294 if (ipv4Loopback == null) {
295 continue;
296 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800297 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
Charles Chan3d35a542018-10-02 12:52:29 -0700298 if (entry.getValue().ipv4NodeSid == -1) {
299 continue;
300 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800301 return entry.getValue().ipv4NodeSid;
302 }
303 }
304
305 return -1;
306 }
307
308 /**
309 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
310 *
311 * @param routerAddress router ip address
312 * @return node segment id, or -1 if not found in config
313 */
314 public int getIPv6SegmentId(Ip6Address routerAddress) {
Charles Chan3d35a542018-10-02 12:52:29 -0700315 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: deviceConfigMap.entrySet()) {
316 Ip6Address ipv6Loopback = entry.getValue().ipv6Loopback;
317 if (ipv6Loopback == null) {
318 continue;
319 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800320 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
Charles Chan3d35a542018-10-02 12:52:29 -0700321 if (entry.getValue().ipv6NodeSid == -1) {
322 continue;
323 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800324 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700325 }
326 }
327
328 return -1;
329 }
330
sangho80f11cb2015-04-01 13:05:26 -0700331 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800332 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700333 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
334 if (srinfo != null) {
Saurav Das7c305372015-10-28 12:39:42 -0700335 return srinfo.mac;
sangho80f11cb2015-04-01 13:05:26 -0700336 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800337 String message = "getDeviceMac fails for device: " + deviceId + ".";
338 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700339 }
340 }
341
Charles Chan319d1a22015-11-03 10:42:14 -0800342 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800343 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700344 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
345 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800346 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
347 return srinfo.ipv4Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700348 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800349 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
350 throw new DeviceConfigNotFoundException(message);
351 }
352 }
353
354 @Override
355 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
356 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
357 if (srinfo != null) {
358 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
359 return srinfo.ipv6Loopback;
360 } else {
361 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800362 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700363 }
sangho80f11cb2015-04-01 13:05:26 -0700364 }
365
pier6a2052b2019-06-28 22:17:31 +0200366 /**
367 * Gets router ip address based on the destination ip address.
368 *
369 * @param destIpAddress the destination ip address
370 * @param routerDeviceId the device id
371 * @return the ip address of the routes
372 */
373 public IpAddress getRouterIpAddress(IpAddress destIpAddress, DeviceId routerDeviceId) {
374 IpAddress routerIpAddress;
375 try {
376 routerIpAddress = destIpAddress.isIp4() ? getRouterIpv4(routerDeviceId) :
377 getRouterIpv6(routerDeviceId);
378 } catch (DeviceConfigNotFoundException e) {
379 routerIpAddress = null;
380 }
381 return routerIpAddress;
382 }
383
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700384 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800385 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700386 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
387 if (srinfo != null) {
388 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
389 return srinfo.isEdge;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700390 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800391 String message = "isEdgeDevice fails for device: " + deviceId + ".";
392 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700393 }
394 }
395
sangho80f11cb2015-04-01 13:05:26 -0700396 @Override
pierventre30368ab2021-02-24 23:23:22 +0100397 public List<DeviceId> getEdgeDeviceIds() {
398 return deviceConfigMap.values().stream()
399 .filter(deviceInfo -> deviceInfo.isEdge)
400 .map(deviceInfo -> deviceInfo.deviceId)
401 .collect(Collectors.toList());
402 }
403
404 @Override
sangho80f11cb2015-04-01 13:05:26 -0700405 public List<Integer> getAllDeviceSegmentIds() {
406 return allSegmentIds;
407 }
408
Charles Chan77277672015-10-20 16:24:19 -0700409 @Override
Pier Ventreb6a7f342016-11-26 21:05:22 -0800410 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das52d4ed72016-03-28 19:00:18 -0700411 throws DeviceConfigNotFoundException {
412 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
413 if (srinfo == null) {
414 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
415 throw new DeviceConfigNotFoundException(message);
416 }
Charles Chan77277672015-10-20 16:24:19 -0700417 // Construct subnet-port mapping from port-subnet mapping
Pier Ventreb6a7f342016-11-26 21:05:22 -0800418 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
419 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan82ab1932016-01-30 23:22:37 -0800420
421 portSubnetMap.entries().forEach(entry -> {
422 PortNumber port = entry.getKey();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800423 IpPrefix subnet = entry.getValue();
Charles Chan82ab1932016-01-30 23:22:37 -0800424
Pier Ventreb6a7f342016-11-26 21:05:22 -0800425 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
426 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chanbbd004c2016-02-16 23:14:49 -0800427 return;
428 }
429
Charles Chan77277672015-10-20 16:24:19 -0700430 if (subnetPortMap.containsKey(subnet)) {
431 subnetPortMap.get(subnet).add(port);
432 } else {
433 ArrayList<PortNumber> ports = new ArrayList<>();
434 ports.add(port);
435 subnetPortMap.put(subnet, ports);
436 }
437 });
Charles Chan77277672015-10-20 16:24:19 -0700438 return subnetPortMap;
439 }
440
sangho80f11cb2015-04-01 13:05:26 -0700441 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700442 * Returns the device identifier or data plane identifier (dpid)
443 * of a segment router given its segment id.
sangho80f11cb2015-04-01 13:05:26 -0700444 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700445 * @param sid segment id
446 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700447 */
448 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700449 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
450 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800451 if (entry.getValue().ipv4NodeSid == sid ||
452 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700453 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700454 }
455 }
456
457 return null;
458 }
459
460 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700461 * Returns the device identifier or data plane identifier (dpid)
462 * of a segment router given its router ip address.
sangho80f11cb2015-04-01 13:05:26 -0700463 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700464 * @param ipAddress router ip address
465 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700466 */
467 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700468 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
469 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800470 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
471 return entry.getValue().deviceId;
472 }
473 }
474
475 return null;
476 }
477
478 /**
479 * Returns the device identifier or data plane identifier (dpid)
480 * of a segment router given its router ipv6 address.
481 *
482 * @param ipAddress router ipv6 address
483 * @return deviceId device identifier
484 */
485 public DeviceId getDeviceId(Ip6Address ipAddress) {
486 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
487 deviceConfigMap.entrySet()) {
488 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700489 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700490 }
491 }
492
493 return null;
494 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700495
496 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700497 * Returns the configured port ip addresses for a segment router.
498 * These addresses serve as gateway IP addresses for the subnets configured
499 * on those ports.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700500 *
501 * @param deviceId device identifier
Saurav Dasc28b3432015-10-30 17:45:38 -0700502 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700503 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800504 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700505 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
506 if (srinfo != null) {
507 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
508 srinfo.gatewayIps.values());
Saurav Dasc28b3432015-10-30 17:45:38 -0700509 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700510 }
Saurav Das7c305372015-10-28 12:39:42 -0700511 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700512 }
513
514 /**
Charles Chancf789822019-03-22 10:04:27 -0700515 * Returns configured subnets for a segment router.
516 *
517 * @param deviceId device identifier
518 * @return list of ip prefixes or null if not found
519 */
520 public Set<IpPrefix> getConfiguredSubnets(DeviceId deviceId) {
521 Set<IpPrefix> subnets = srManager.interfaceService.getInterfaces().stream()
522 .filter(intf -> Objects.equals(deviceId, intf.connectPoint().deviceId()))
523 .flatMap(intf -> intf.ipAddressesList().stream())
524 .map(InterfaceIpAddress::subnetAddress)
525 .collect(Collectors.toSet());
526
527 if (subnets.isEmpty()) {
528 log.debug(NO_SUBNET, deviceId);
529 return Collections.emptySet();
530 }
531 return subnets;
532 }
533
534 /**
535 * Returns all subnets for a segment router, including subnets learnt from route service.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700536 *
537 * @param deviceId device identifier
Charles Chan19b70032019-04-17 14:20:26 -0700538 * @return set of ip prefixes or null if not found
539 * @deprecated use getBatchedSubnets(DeviceId deviceId) instead
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700540 */
Charles Chan19b70032019-04-17 14:20:26 -0700541 @Deprecated
Pier Ventreb6a7f342016-11-26 21:05:22 -0800542 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700543 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan5eb66042018-06-18 14:42:17 -0700544 if (srinfo != null && srinfo.subnets != null) {
545 // Note: ImmutableSet.Builder.addAll calls the iterator of parameter internally,
546 // which is not protected by SynchronizedCollection mutex.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800547 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chan5eb66042018-06-18 14:42:17 -0700548 srinfo.subnets.forEach((k, v) -> builder.add(v));
549 return builder.build();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700550 }
Saurav Das7c305372015-10-28 12:39:42 -0700551 return null;
552 }
553
Charles Chan19b70032019-04-17 14:20:26 -0700554 /**
Charles Chan5eec3b12019-04-18 14:30:41 -0700555 * Returns batches of all subnets reachable via given next hop
556 * <p>
557 * First batch includes FPM and STATIC routes
558 * Second batch includes all other type of routes obtained from routeService, including DHCP routes.
559 *
560 * @param hostId next hop host id
561 * @return list of subnet batches, each batch includes a set of prefixes.
562 */
563 // TODO Querying routeService directly may be expensive. Some kind of reverse lookup cache should be developed.
564 public List<Set<IpPrefix>> getBatchedSubnets(HostId hostId) {
565 Set<IpPrefix> high = Sets.newHashSet();
566 Set<IpPrefix> low = Sets.newHashSet();
567
568 srManager.routeService.getRouteTables().stream()
569 .map(tableId -> srManager.routeService.getResolvedRoutes(tableId))
570 .flatMap(Collection::stream)
571 .forEach(resolvedRoute -> {
572 // Continue if next hop is not what we are looking for
573 if (!Objects.equals(hostId.mac(), resolvedRoute.nextHopMac()) ||
574 !Objects.equals(hostId.vlanId(), resolvedRoute.nextHopVlan())) {
575 return;
576 }
577 // Prioritize STATIC and FPM among others
578 if (resolvedRoute.route().source() == Route.Source.STATIC ||
579 resolvedRoute.route().source() == Route.Source.FPM) {
580 high.add(resolvedRoute.prefix());
581 } else {
582 low.add(resolvedRoute.prefix());
583 }
584 });
585 return Stream.of(high, low).filter(set -> !set.isEmpty()).collect(Collectors.toList());
586 }
587
588 /**
Charles Chan19b70032019-04-17 14:20:26 -0700589 * Returns batches of all subnets reachable on the given device.
590 * <p>
591 * First batch includes configured subnets, FPM and STATIC routes
592 * Second batch includes all other type of routes obtained from routeService, including DHCP routes.
593 *
594 * @param deviceId device identifier
595 * @return list of subnet batches, each batch includes a set of prefixes.
596 */
597 // TODO Querying routeService directly may be expensive. Some kind of reverse lookup cache should be developed.
598 public List<Set<IpPrefix>> getBatchedSubnets(DeviceId deviceId) {
599 Set<IpPrefix> high = Sets.newHashSet();
600 Set<IpPrefix> low = Sets.newHashSet();
601
602 high.addAll(getConfiguredSubnets(deviceId));
603 srManager.routeService.getRouteTables().stream()
604 .map(tableId -> srManager.routeService.getResolvedRoutes(tableId))
605 .flatMap(Collection::stream)
606 .forEach(resolvedRoute -> {
607 // Continue to next resolved route if none of the next hop attaches to given device
608 if (srManager.nextHopLocations(resolvedRoute).stream()
609 .noneMatch(cp -> Objects.equals(deviceId, cp.deviceId()))) {
610 return;
611 }
612 // Prioritize STATIC and FPM among others
613 if (resolvedRoute.route().source() == Route.Source.STATIC ||
614 resolvedRoute.route().source() == Route.Source.FPM) {
615 high.add(resolvedRoute.prefix());
616 } else {
617 low.add(resolvedRoute.prefix());
618 }
619 });
620 return Lists.newArrayList(high, low);
621 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800622
Saurav Das7c305372015-10-28 12:39:42 -0700623 /**
Charles Chan46fdfaf2016-11-09 20:51:44 -0800624 * Returns the subnet configuration of given device and port.
Saurav Das7c305372015-10-28 12:39:42 -0700625 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800626 * @param deviceId Device ID
627 * @param port Port number
Pier Ventreb6a7f342016-11-26 21:05:22 -0800628 * @return The subnets configured on given port or empty set if
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700629 * the port is unconfigured or suppressed.
Saurav Das7c305372015-10-28 12:39:42 -0700630 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800631 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800632 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
633
634 if (isSuppressedPort(connectPoint)) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800635 return Collections.emptySet();
Saurav Das7c305372015-10-28 12:39:42 -0700636 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800637
Charles Chancf789822019-03-22 10:04:27 -0700638 Set<IpPrefix> subnets = srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
639 .flatMap(intf -> intf.ipAddressesList().stream())
640 .map(InterfaceIpAddress::subnetAddress)
641 .collect(Collectors.toSet());
Charles Chan46fdfaf2016-11-09 20:51:44 -0800642
Jon Hall31d84782017-01-18 20:15:44 -0800643 if (subnets.isEmpty()) {
Saurav Dasf9332192017-02-18 14:05:44 -0800644 log.debug(NO_SUBNET, connectPoint);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800645 return Collections.emptySet();
Charles Chan46fdfaf2016-11-09 20:51:44 -0800646 }
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700647 return subnets;
Pier Ventreb6a7f342016-11-26 21:05:22 -0800648 }
649
650 /**
Charles Chan873661e2017-11-30 15:37:50 -0800651 * Returns all ports that has a subnet that contains any of the given IP addresses.
652 *
653 * @param ips a set of IP addresses
654 * @return a set of connect point that has a subnet that contains any of the given IP addresses
655 */
656 public Set<ConnectPoint> getPortByIps(Set<IpAddress> ips) {
657 return srManager.interfaceService.getInterfaces().stream()
658 .filter(intf -> intf.ipAddressesList().stream().anyMatch(intfAddress ->
659 ips.stream().anyMatch(ip -> intfAddress.subnetAddress().contains(ip))))
660 .map(Interface::connectPoint)
661 .collect(Collectors.toSet());
662 }
663
664 /**
pier6a2052b2019-06-28 22:17:31 +0200665 * Returns all the connect points of the segment routers that have the
666 * specified ip address in their subnets.
667 *
668 * @param destIpAddress target ip address
669 * @return connect points of the segment routers
670 */
671 public Set<ConnectPoint> getConnectPointsForASubnetHost(IpAddress destIpAddress) {
672 return srManager.interfaceService.getMatchingInterfaces(destIpAddress).stream()
673 .map(Interface::connectPoint)
674 .collect(Collectors.toSet());
675 }
676
677 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700678 * Returns the router ip address of segment router that has the
679 * specified ip address in its subnets.
680 *
681 * @param destIpAddress target ip address
682 * @return router ip address
683 */
684 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan70661362016-12-09 12:54:49 -0800685 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
686
687 if (matchIntf == null) {
688 log.debug("No router was found for {}", destIpAddress);
689 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700690 }
691
Charles Chan70661362016-12-09 12:54:49 -0800692 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
693 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
694 if (srInfo == null) {
695 log.debug("No device config was found for {}", routerDeviceId);
696 return null;
697 }
698
Pier Ventreadb4ae62016-11-23 09:57:42 -0800699 return srInfo.ipv4Loopback;
700 }
701
702 /**
703 * Returns the router ipv6 address of segment router that has the
704 * specified ip address in its subnets.
705 *
706 * @param destIpAddress target ip address
707 * @return router ip address
708 */
709 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
710 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
711
712 if (matchIntf == null) {
713 log.debug("No router was found for {}", destIpAddress);
714 return null;
715 }
716
717 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
718 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
719 if (srInfo == null) {
720 log.debug("No device config was found for {}", routerDeviceId);
721 return null;
722 }
723
724 return srInfo.ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700725 }
726
727 /**
728 * Returns the router mac address of segment router that has the
729 * specified ip address as one of its subnet gateway ip address.
730 *
731 * @param gatewayIpAddress router gateway ip address
Saurav Das7c305372015-10-28 12:39:42 -0700732 * @return router mac address or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700733 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800734 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700735 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
736 deviceConfigMap.entrySet()) {
737 if (entry.getValue().gatewayIps.
738 values().contains(gatewayIpAddress)) {
739 return entry.getValue().mac;
740 }
741 }
742
743 log.debug("Cannot find a router for {}", gatewayIpAddress);
744 return null;
745 }
sangho9b169e32015-04-14 16:27:13 -0700746
sangho9b169e32015-04-14 16:27:13 -0700747 /**
Charles Chan35f21e42017-06-26 18:30:18 -0700748 * Checks if the host IP is in any of the subnet defined in the router with the
sangho9b169e32015-04-14 16:27:13 -0700749 * device ID given.
750 *
751 * @param deviceId device identification of the router
752 * @param hostIp host IP address to check
Charles Chan35f21e42017-06-26 18:30:18 -0700753 * @return true if the given IP is within any of the subnet defined in the router,
754 * false if no subnet is defined in the router or if the host is not
755 * within any subnet defined in the router
sangho9b169e32015-04-14 16:27:13 -0700756 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800757 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
Charles Chancf789822019-03-22 10:04:27 -0700758 Set<IpPrefix> subnets = getConfiguredSubnets(deviceId);
sangho9b169e32015-04-14 16:27:13 -0700759 if (subnets == null) {
760 return false;
761 }
762
Pier Ventreb6a7f342016-11-26 21:05:22 -0800763 for (IpPrefix subnet: subnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800764 // Exclude /0 since it is a special case used for default route
765 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho9b169e32015-04-14 16:27:13 -0700766 return true;
767 }
768 }
sangho9b169e32015-04-14 16:27:13 -0700769 return false;
770 }
sangho27462c62015-05-14 00:39:53 -0700771
772 /**
Charles Chandebfea32016-10-24 14:52:01 -0700773 * Checks if the IP is in the subnet defined on given connect point.
774 *
775 * @param connectPoint Connect point
776 * @param ip The IP address to check
777 * @return True if the IP belongs to the subnet.
778 * False if the IP does not belong to the subnet, or
779 * there is no subnet configuration on given connect point.
780 */
781 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Charles Chan35f21e42017-06-26 18:30:18 -0700782 return getPortSubnets(connectPoint.deviceId(), connectPoint.port()).stream()
783 .anyMatch(ipPrefix -> ipPrefix.contains(ip));
Charles Chandebfea32016-10-24 14:52:01 -0700784 }
785
786 /**
sangho27462c62015-05-14 00:39:53 -0700787 * Returns the ports corresponding to the adjacency Sid given.
788 *
789 * @param deviceId device identification of the router
790 * @param sid adjacency Sid
Charles Chan9bec8a32015-12-01 10:00:51 -0800791 * @return set of port numbers
sangho27462c62015-05-14 00:39:53 -0700792 */
Charles Chan9bec8a32015-12-01 10:00:51 -0800793 public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700794 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800795 return srinfo != null ?
796 ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
797 ImmutableSet.copyOf(new HashSet<>());
sangho27462c62015-05-14 00:39:53 -0700798 }
799
800 /**
801 * Check if the Sid given is whether adjacency Sid of the router device or not.
802 *
803 * @param deviceId device identification of the router
804 * @param sid Sid to check
805 * @return true if the Sid given is the adjacency Sid of the device,
806 * otherwise false
807 */
808 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700809 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800810 return srinfo != null && srinfo.adjacencySids.containsKey(sid);
sangho27462c62015-05-14 00:39:53 -0700811 }
Charles Chan43547ca2016-02-10 20:46:58 -0800812
Charles Chanc91c8782016-03-30 17:54:24 -0700813 /**
Charles Chanc22cef32016-04-29 14:38:22 -0700814 * Add subnet to specific connect point.
815 *
816 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800817 * @param ipPrefix subnet being added to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700818 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800819 public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700820 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800821 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700822 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
823 if (srinfo == null) {
824 log.warn("Device {} is not configured. Abort.", cp.deviceId());
825 return;
826 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800827 srinfo.subnets.put(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700828 }
829
830 /**
831 * Remove subnet from specific connect point.
832 *
833 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800834 * @param ipPrefix subnet being removed to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700835 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800836 public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700837 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800838 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700839 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
840 if (srinfo == null) {
841 log.warn("Device {} is not configured. Abort.", cp.deviceId());
842 return;
843 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800844 srinfo.subnets.remove(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700845 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800846
847 private boolean isSuppressedPort(ConnectPoint connectPoint) {
848 SegmentRoutingAppConfig appConfig = srManager.cfgService
Ray Milkeyb85de082017-04-05 09:42:04 -0700849 .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800850 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chandebfea32016-10-24 14:52:01 -0700851 log.info("Interface configuration on port {} is ignored", connectPoint);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800852 return true;
853 }
854 return false;
855 }
Saurav Das261c3002017-06-13 15:35:54 -0700856
857 public boolean isPairedEdge(DeviceId deviceId) throws DeviceConfigNotFoundException {
858 if (!isEdgeDevice(deviceId)) {
859 return false;
860 }
861 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
862 return (srinfo.pairDeviceId == null) ? false : true;
863 }
864
865 public DeviceId getPairDeviceId(DeviceId deviceId) throws DeviceConfigNotFoundException {
866 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
867 if (srinfo != null) {
868 return srinfo.pairDeviceId;
869 } else {
870 String message = "getPairDeviceId fails for device: " + deviceId + ".";
871 throw new DeviceConfigNotFoundException(message);
872 }
873 }
874
875 public PortNumber getPairLocalPort(DeviceId deviceId)
876 throws DeviceConfigNotFoundException {
877 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
878 if (srinfo != null) {
879 return srinfo.pairLocalPort;
880 } else {
881 String message = "getPairLocalPort fails for device: " + deviceId + ".";
882 throw new DeviceConfigNotFoundException(message);
883 }
884 }
885
Saurav Dasec683dc2018-04-27 18:42:30 -0700886 public boolean isPairLocalPort(DeviceId devId, PortNumber pnum) {
887 return pnum.equals(srManager.getPairLocalPort(devId).orElse(null));
888 }
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800889}