blob: 3db48aba4e40f830be340da871e6da13313603af [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;
Charles Chan44e914e2021-04-01 16:18:30 -070019import com.fasterxml.jackson.databind.ObjectMapper;
Charles Chan6191aca2017-09-12 12:09:22 -070020import com.fasterxml.jackson.databind.node.ArrayNode;
21import com.fasterxml.jackson.databind.node.ObjectNode;
Charles Chan82ab1932016-01-30 23:22:37 -080022import com.google.common.collect.HashMultimap;
Charles Chanc6ad7752015-10-29 14:58:10 -070023import com.google.common.collect.ImmutableSet;
Charles Chan19b70032019-04-17 14:20:26 -070024import com.google.common.collect.Lists;
Charles Chandc7d6f92018-03-20 13:30:38 -070025import com.google.common.collect.Multimaps;
Charles Chan82ab1932016-01-30 23:22:37 -080026import com.google.common.collect.SetMultimap;
Charles Chan19b70032019-04-17 14:20:26 -070027import com.google.common.collect.Sets;
sangho80f11cb2015-04-01 13:05:26 -070028import org.onlab.packet.Ip4Address;
Pier Ventreadb4ae62016-11-23 09:57:42 -080029import org.onlab.packet.Ip6Address;
Charles Chandebfea32016-10-24 14:52:01 -070030import org.onlab.packet.IpAddress;
Charles Chan82ab1932016-01-30 23:22:37 -080031import org.onlab.packet.IpPrefix;
sangho80f11cb2015-04-01 13:05:26 -070032import org.onlab.packet.MacAddress;
Charles Chanb7f75ac2016-01-11 18:28:54 -080033import org.onlab.packet.VlanId;
Charles Chane7c61022015-10-07 14:21:45 -070034import org.onosproject.net.ConnectPoint;
sangho80f11cb2015-04-01 13:05:26 -070035import org.onosproject.net.DeviceId;
Charles Chan5eec3b12019-04-18 14:30:41 -070036import org.onosproject.net.HostId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070037import org.onosproject.net.PortNumber;
Jonathan Hart61e24e12017-11-30 18:23:42 -080038import org.onosproject.net.config.ConfigException;
Charles Chan44e914e2021-04-01 16:18:30 -070039import org.onosproject.net.config.basics.BasicHostConfig;
Jonathan Hart61e24e12017-11-30 18:23:42 -080040import org.onosproject.net.config.basics.InterfaceConfig;
41import org.onosproject.net.host.InterfaceIpAddress;
42import org.onosproject.net.intf.Interface;
Charles Chan19b70032019-04-17 14:20:26 -070043import org.onosproject.routeservice.Route;
pierventre2b102f92020-09-08 16:45:36 +020044import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
45import org.onosproject.segmentrouting.config.DeviceProperties;
46import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
47import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
sangho80f11cb2015-04-01 13:05:26 -070048import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
50
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070051import java.util.ArrayList;
Jonathan Hart61e24e12017-11-30 18:23:42 -080052import java.util.Collection;
Pier Ventreb6a7f342016-11-26 21:05:22 -080053import java.util.Collections;
sangho80f11cb2015-04-01 13:05:26 -070054import java.util.HashMap;
Charles Chan9bec8a32015-12-01 10:00:51 -080055import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070056import java.util.List;
57import java.util.Map;
Charles Chancf789822019-03-22 10:04:27 -070058import java.util.Objects;
Charles Chan72f556a2015-10-05 17:50:33 -070059import java.util.Set;
Saurav Das7c305372015-10-28 12:39:42 -070060import java.util.concurrent.ConcurrentHashMap;
Charles Chan46fdfaf2016-11-09 20:51:44 -080061import java.util.stream.Collectors;
Charles Chan5eec3b12019-04-18 14:30:41 -070062import java.util.stream.Stream;
sangho80f11cb2015-04-01 13:05:26 -070063
Charles Chanc22cef32016-04-29 14:38:22 -070064import static com.google.common.base.Preconditions.checkNotNull;
65
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070066/**
67 * Segment Routing configuration component that reads the
68 * segment routing related configuration from Network Configuration Manager
69 * component and organizes in more accessible formats.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070070 */
sangho80f11cb2015-04-01 13:05:26 -070071public class DeviceConfiguration implements DeviceProperties {
72
Charles Chan46fdfaf2016-11-09 20:51:44 -080073 private static final String NO_SUBNET = "No subnet configured on {}";
Charles Chan44e914e2021-04-01 16:18:30 -070074 // Key for BasicHostConfig
75 private static final String BASIC_KEY = "basic";
Charles Chan46fdfaf2016-11-09 20:51:44 -080076
Charles Chan43547ca2016-02-10 20:46:58 -080077 private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -070078 private final List<Integer> allSegmentIds = new ArrayList<>();
Charles Chanb7f75ac2016-01-11 18:28:54 -080079 private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
Charles Chan46fdfaf2016-11-09 20:51:44 -080080 private SegmentRoutingManager srManager;
sangho80f11cb2015-04-01 13:05:26 -070081
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070082 private class SegmentRouterInfo {
Charles Chan3d35a542018-10-02 12:52:29 -070083 int ipv4NodeSid = -1;
84 int ipv6NodeSid = -1;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070085 DeviceId deviceId;
Pier Ventreadb4ae62016-11-23 09:57:42 -080086 Ip4Address ipv4Loopback;
87 Ip6Address ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070088 MacAddress mac;
89 boolean isEdge;
Pier Ventreb6a7f342016-11-26 21:05:22 -080090 SetMultimap<PortNumber, IpAddress> gatewayIps;
91 SetMultimap<PortNumber, IpPrefix> subnets;
Charles Chan9bec8a32015-12-01 10:00:51 -080092 Map<Integer, Set<Integer>> adjacencySids;
Saurav Das261c3002017-06-13 15:35:54 -070093 DeviceId pairDeviceId;
94 PortNumber pairLocalPort;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070095 int pwRoutingLabel;
Charles Chan2b078ae2015-10-14 11:24:40 -070096
97 public SegmentRouterInfo() {
Charles Chandc7d6f92018-03-20 13:30:38 -070098 gatewayIps = Multimaps.synchronizedSetMultimap(HashMultimap.create());
99 subnets = Multimaps.synchronizedSetMultimap(HashMultimap.create());
Charles Chan2b078ae2015-10-14 11:24:40 -0700100 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700101 }
sangho80f11cb2015-04-01 13:05:26 -0700102
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700103 /**
Charles Chanb7f75ac2016-01-11 18:28:54 -0800104 * Constructs device configuration for all Segment Router devices,
105 * organizing the data into various maps for easier access.
Brian O'Connor65eeb572015-10-09 17:03:44 -0700106 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800107 * @param srManager Segment Routing Manager
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700108 */
Charles Chan46fdfaf2016-11-09 20:51:44 -0800109 public DeviceConfiguration(SegmentRoutingManager srManager) {
110 this.srManager = srManager;
Saurav Das261c3002017-06-13 15:35:54 -0700111 updateConfig();
112 }
Charles Chan57bd98c2016-02-22 19:27:29 -0800113
Saurav Das261c3002017-06-13 15:35:54 -0700114 public void updateConfig() {
Charles Chane7c61022015-10-07 14:21:45 -0700115 // Read config from device subject, excluding gatewayIps and subnets.
116 Set<DeviceId> deviceSubjects =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800117 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700118 deviceSubjects.forEach(subject -> {
Charles Chan82ab1932016-01-30 23:22:37 -0800119 SegmentRoutingDeviceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800120 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700121 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chan72f556a2015-10-05 17:50:33 -0700122 info.deviceId = subject;
Pier Ventreadb4ae62016-11-23 09:57:42 -0800123 info.ipv4NodeSid = config.nodeSidIPv4();
124 info.ipv6NodeSid = config.nodeSidIPv6();
125 info.ipv4Loopback = config.routerIpv4();
126 info.ipv6Loopback = config.routerIpv6();
Charles Chan9bec8a32015-12-01 10:00:51 -0800127 info.mac = config.routerMac();
Charles Chan72f556a2015-10-05 17:50:33 -0700128 info.isEdge = config.isEdgeRouter();
Charles Chan9bec8a32015-12-01 10:00:51 -0800129 info.adjacencySids = config.adjacencySids();
Saurav Das261c3002017-06-13 15:35:54 -0700130 info.pairDeviceId = config.pairDeviceId();
131 info.pairLocalPort = config.pairLocalPort();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700132 info.pwRoutingLabel = info.ipv4NodeSid + 1000;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800133 deviceConfigMap.put(info.deviceId, info);
Charles Chan68363b12017-06-26 15:25:09 -0700134 log.debug("Read device config for device: {}", info.deviceId);
Charles Chan44e914e2021-04-01 16:18:30 -0700135 // IPv6 sid is not inserted. this part of the code is not used for now.
Pier Ventreadb4ae62016-11-23 09:57:42 -0800136 allSegmentIds.add(info.ipv4NodeSid);
Charles Chan44e914e2021-04-01 16:18:30 -0700137
138 // Block host with routerMac and untagged VLAN
139 blockHost(info.mac, VlanId.NONE);
Charles Chan72f556a2015-10-05 17:50:33 -0700140 });
Charles Chane7c61022015-10-07 14:21:45 -0700141
Charles Chan46fdfaf2016-11-09 20:51:44 -0800142 // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
143 Set<ConnectPoint> portSubjects = srManager.cfgService
144 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
Jonathan Hart61e24e12017-11-30 18:23:42 -0800145 portSubjects.stream()
146 .filter(subject -> deviceConfigMap.containsKey(subject.deviceId()))
147 .filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chane7c61022015-10-07 14:21:45 -0700148 InterfaceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800149 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700150 Set<Interface> networkInterfaces;
151 try {
152 networkInterfaces = config.getInterfaces();
153 } catch (ConfigException e) {
154 log.error("Error loading port configuration");
155 return;
156 }
157 networkInterfaces.forEach(networkInterface -> {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800158 VlanId vlanId = networkInterface.vlan();
159 ConnectPoint connectPoint = networkInterface.connectPoint();
160 DeviceId dpid = connectPoint.deviceId();
161 PortNumber port = connectPoint.port();
Charles Chan6191aca2017-09-12 12:09:22 -0700162 MacAddress mac = networkInterface.mac();
Charles Chanb7f75ac2016-01-11 18:28:54 -0800163 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chane7c61022015-10-07 14:21:45 -0700164
Charles Chan44e914e2021-04-01 16:18:30 -0700165 // skip if there is no corresponding device for this ConnectPoint
Charles Chan2b078ae2015-10-14 11:24:40 -0700166 if (info != null) {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800167 // Extract subnet information
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800168 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chan2b078ae2015-10-14 11:24:40 -0700169 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800170 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan82ab1932016-01-30 23:22:37 -0800171 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800172 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
173 if (ipPrefix.isIp4()) {
174 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
175 info.gatewayIps.put(port, interfaceAddress.ipAddress());
176 }
177 info.subnets.put(port, interfaceAddress.subnetAddress());
178 } else {
179 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
180 info.gatewayIps.put(port, interfaceAddress.ipAddress());
181 }
182 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan82ab1932016-01-30 23:22:37 -0800183 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700184 });
Charles Chan6191aca2017-09-12 12:09:22 -0700185
186 // Override interface mac with router mac
187 if (!mac.equals(info.mac)) {
188 ArrayNode array = (ArrayNode) config.node();
189 for (JsonNode intfNode : array) {
190 ObjectNode objNode = (ObjectNode) intfNode;
191 objNode.put(InterfaceConfig.MAC, info.mac.toString());
192 }
193 srManager.cfgService.applyConfig(connectPoint, InterfaceConfig.class, array);
194 }
Charles Chan44e914e2021-04-01 16:18:30 -0700195
196 // Block host with routerMac and taggedVlan
197 networkInterface.vlanTagged().forEach(taggedVlan -> {
198 blockHost(info.mac, taggedVlan);
199 });
Charles Chan2b078ae2015-10-14 11:24:40 -0700200 }
Charles Chane7c61022015-10-07 14:21:45 -0700201 });
Pier Luigi6a2643a2017-01-31 09:35:05 -0800202 // We register the connect point with the NRS.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800203 srManager.registerConnectPoint(subject);
Charles Chane7c61022015-10-07 14:21:45 -0700204 });
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700205 }
206
Charles Chan44e914e2021-04-01 16:18:30 -0700207 private void blockHost(MacAddress macAddress, VlanId vlanId) {
208 HostId hostId = HostId.hostId(macAddress, vlanId);
209 BasicHostConfig hostConfig = srManager.cfgService.getConfig(hostId, BasicHostConfig.class);
210 if (hostConfig == null) {
211 ObjectMapper mapper = new ObjectMapper();
212 JsonNode jsonNode = mapper.createObjectNode();
213 hostConfig = new BasicHostConfig();
214 hostConfig.init(hostId, BASIC_KEY, jsonNode, mapper, config -> { });
215 }
216 hostConfig.isAllowed(false);
217 srManager.cfgService.applyConfig(hostId, BasicHostConfig.class, hostConfig.node());
218 log.info("Blocking {} from being learnt as host", hostId);
219 }
220
Jonathan Hart61e24e12017-11-30 18:23:42 -0800221 public Collection<DeviceId> getRouters() {
222 return deviceConfigMap.keySet();
223 }
Saurav Das261c3002017-06-13 15:35:54 -0700224
sangho80f11cb2015-04-01 13:05:26 -0700225 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800226 public boolean isConfigured(DeviceId deviceId) {
227 return deviceConfigMap.get(deviceId) != null;
228 }
229
230 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800231 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700232 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
233 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800234 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
235 return srinfo.ipv4NodeSid;
sangho80f11cb2015-04-01 13:05:26 -0700236 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800237 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
238 throw new DeviceConfigNotFoundException(message);
239 }
240 }
241
242 @Override
243 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
244 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
245 if (srinfo != null) {
246 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
247 return srinfo.ipv6NodeSid;
248 } else {
249 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800250 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700251 }
252 }
253
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700254 @Override
255 public int getPWRoutingLabel(DeviceId deviceId) throws DeviceConfigNotFoundException {
256 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
257 if (srinfo != null) {
258 log.trace("pwRoutingLabel for device{} is {}", deviceId, srinfo.pwRoutingLabel);
259 return srinfo.pwRoutingLabel;
260 } else {
261 String message = "getPWRoutingLabel fails for device: " + deviceId + ".";
262 throw new DeviceConfigNotFoundException(message);
263 }
264 }
265
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700266 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800267 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700268 *
269 * @param routerMac router mac address
Saurav Das7c305372015-10-28 12:39:42 -0700270 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700271 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800272 public int getIPv4SegmentId(MacAddress routerMac) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700273 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
274 deviceConfigMap.entrySet()) {
275 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800276 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700277 }
278 }
sangho80f11cb2015-04-01 13:05:26 -0700279
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700280 return -1;
281 }
282
283 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800284 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
285 *
286 * @param routerMac router mac address
287 * @return node segment id, or -1 if not found in config
288 */
289 public int getIPv6SegmentId(MacAddress routerMac) {
290 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
291 deviceConfigMap.entrySet()) {
292 if (entry.getValue().mac.equals(routerMac)) {
293 return entry.getValue().ipv6NodeSid;
294 }
295 }
296
297 return -1;
298 }
299
300 /**
301 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700302 *
303 * @param routerAddress router ip address
Saurav Das7c305372015-10-28 12:39:42 -0700304 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700305 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800306 public int getIPv4SegmentId(Ip4Address routerAddress) {
Charles Chan3d35a542018-10-02 12:52:29 -0700307 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: deviceConfigMap.entrySet()) {
308 Ip4Address ipv4Loopback = entry.getValue().ipv4Loopback;
309 if (ipv4Loopback == null) {
310 continue;
311 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800312 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
Charles Chan3d35a542018-10-02 12:52:29 -0700313 if (entry.getValue().ipv4NodeSid == -1) {
314 continue;
315 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800316 return entry.getValue().ipv4NodeSid;
317 }
318 }
319
320 return -1;
321 }
322
323 /**
324 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
325 *
326 * @param routerAddress router ip address
327 * @return node segment id, or -1 if not found in config
328 */
329 public int getIPv6SegmentId(Ip6Address routerAddress) {
Charles Chan3d35a542018-10-02 12:52:29 -0700330 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: deviceConfigMap.entrySet()) {
331 Ip6Address ipv6Loopback = entry.getValue().ipv6Loopback;
332 if (ipv6Loopback == null) {
333 continue;
334 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800335 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
Charles Chan3d35a542018-10-02 12:52:29 -0700336 if (entry.getValue().ipv6NodeSid == -1) {
337 continue;
338 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800339 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700340 }
341 }
342
343 return -1;
344 }
345
sangho80f11cb2015-04-01 13:05:26 -0700346 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800347 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700348 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
349 if (srinfo != null) {
Saurav Das7c305372015-10-28 12:39:42 -0700350 return srinfo.mac;
sangho80f11cb2015-04-01 13:05:26 -0700351 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800352 String message = "getDeviceMac fails for device: " + deviceId + ".";
353 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700354 }
355 }
356
Charles Chan319d1a22015-11-03 10:42:14 -0800357 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800358 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700359 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
360 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800361 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
362 return srinfo.ipv4Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700363 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800364 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
365 throw new DeviceConfigNotFoundException(message);
366 }
367 }
368
369 @Override
370 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
371 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
372 if (srinfo != null) {
373 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
374 return srinfo.ipv6Loopback;
375 } else {
376 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800377 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700378 }
sangho80f11cb2015-04-01 13:05:26 -0700379 }
380
pier6a2052b2019-06-28 22:17:31 +0200381 /**
382 * Gets router ip address based on the destination ip address.
383 *
384 * @param destIpAddress the destination ip address
385 * @param routerDeviceId the device id
386 * @return the ip address of the routes
387 */
388 public IpAddress getRouterIpAddress(IpAddress destIpAddress, DeviceId routerDeviceId) {
389 IpAddress routerIpAddress;
390 try {
391 routerIpAddress = destIpAddress.isIp4() ? getRouterIpv4(routerDeviceId) :
392 getRouterIpv6(routerDeviceId);
393 } catch (DeviceConfigNotFoundException e) {
394 routerIpAddress = null;
395 }
396 return routerIpAddress;
397 }
398
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700399 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800400 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700401 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
402 if (srinfo != null) {
403 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
404 return srinfo.isEdge;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700405 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800406 String message = "isEdgeDevice fails for device: " + deviceId + ".";
407 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700408 }
409 }
410
sangho80f11cb2015-04-01 13:05:26 -0700411 @Override
pierventre30368ab2021-02-24 23:23:22 +0100412 public List<DeviceId> getEdgeDeviceIds() {
413 return deviceConfigMap.values().stream()
414 .filter(deviceInfo -> deviceInfo.isEdge)
415 .map(deviceInfo -> deviceInfo.deviceId)
416 .collect(Collectors.toList());
417 }
418
419 @Override
Charles Chana2401452021-06-03 15:57:48 -0700420 public List<DeviceId> getInfraDeviceIds() {
421 return deviceConfigMap.values().stream()
422 .filter(deviceInfo -> !deviceInfo.isEdge)
423 .map(deviceInfo -> deviceInfo.deviceId)
424 .collect(Collectors.toList());
425 }
426
427 @Override
sangho80f11cb2015-04-01 13:05:26 -0700428 public List<Integer> getAllDeviceSegmentIds() {
429 return allSegmentIds;
430 }
431
Charles Chan77277672015-10-20 16:24:19 -0700432 @Override
Pier Ventreb6a7f342016-11-26 21:05:22 -0800433 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das52d4ed72016-03-28 19:00:18 -0700434 throws DeviceConfigNotFoundException {
435 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
436 if (srinfo == null) {
437 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
438 throw new DeviceConfigNotFoundException(message);
439 }
Charles Chan77277672015-10-20 16:24:19 -0700440 // Construct subnet-port mapping from port-subnet mapping
Pier Ventreb6a7f342016-11-26 21:05:22 -0800441 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
442 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan82ab1932016-01-30 23:22:37 -0800443
444 portSubnetMap.entries().forEach(entry -> {
445 PortNumber port = entry.getKey();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800446 IpPrefix subnet = entry.getValue();
Charles Chan82ab1932016-01-30 23:22:37 -0800447
Pier Ventreb6a7f342016-11-26 21:05:22 -0800448 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
449 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chanbbd004c2016-02-16 23:14:49 -0800450 return;
451 }
452
Charles Chan77277672015-10-20 16:24:19 -0700453 if (subnetPortMap.containsKey(subnet)) {
454 subnetPortMap.get(subnet).add(port);
455 } else {
456 ArrayList<PortNumber> ports = new ArrayList<>();
457 ports.add(port);
458 subnetPortMap.put(subnet, ports);
459 }
460 });
Charles Chan77277672015-10-20 16:24:19 -0700461 return subnetPortMap;
462 }
463
sangho80f11cb2015-04-01 13:05:26 -0700464 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700465 * Returns the device identifier or data plane identifier (dpid)
466 * of a segment router given its segment id.
sangho80f11cb2015-04-01 13:05:26 -0700467 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700468 * @param sid segment id
469 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700470 */
471 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700472 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
473 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800474 if (entry.getValue().ipv4NodeSid == sid ||
475 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700476 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700477 }
478 }
479
480 return null;
481 }
482
483 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700484 * Returns the device identifier or data plane identifier (dpid)
485 * of a segment router given its router ip address.
sangho80f11cb2015-04-01 13:05:26 -0700486 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700487 * @param ipAddress router ip address
488 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700489 */
490 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700491 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
492 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800493 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
494 return entry.getValue().deviceId;
495 }
496 }
497
498 return null;
499 }
500
501 /**
502 * Returns the device identifier or data plane identifier (dpid)
503 * of a segment router given its router ipv6 address.
504 *
505 * @param ipAddress router ipv6 address
506 * @return deviceId device identifier
507 */
508 public DeviceId getDeviceId(Ip6Address ipAddress) {
509 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
510 deviceConfigMap.entrySet()) {
511 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700512 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700513 }
514 }
515
516 return null;
517 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700518
519 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700520 * Returns the configured port ip addresses for a segment router.
521 * These addresses serve as gateway IP addresses for the subnets configured
522 * on those ports.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700523 *
524 * @param deviceId device identifier
Saurav Dasc28b3432015-10-30 17:45:38 -0700525 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700526 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800527 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700528 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
529 if (srinfo != null) {
530 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
531 srinfo.gatewayIps.values());
Saurav Dasc28b3432015-10-30 17:45:38 -0700532 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700533 }
Saurav Das7c305372015-10-28 12:39:42 -0700534 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700535 }
536
537 /**
Charles Chancf789822019-03-22 10:04:27 -0700538 * Returns configured subnets for a segment router.
539 *
540 * @param deviceId device identifier
541 * @return list of ip prefixes or null if not found
542 */
543 public Set<IpPrefix> getConfiguredSubnets(DeviceId deviceId) {
544 Set<IpPrefix> subnets = srManager.interfaceService.getInterfaces().stream()
545 .filter(intf -> Objects.equals(deviceId, intf.connectPoint().deviceId()))
546 .flatMap(intf -> intf.ipAddressesList().stream())
547 .map(InterfaceIpAddress::subnetAddress)
548 .collect(Collectors.toSet());
549
550 if (subnets.isEmpty()) {
551 log.debug(NO_SUBNET, deviceId);
552 return Collections.emptySet();
553 }
554 return subnets;
555 }
556
557 /**
558 * Returns all subnets for a segment router, including subnets learnt from route service.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700559 *
560 * @param deviceId device identifier
Charles Chan19b70032019-04-17 14:20:26 -0700561 * @return set of ip prefixes or null if not found
562 * @deprecated use getBatchedSubnets(DeviceId deviceId) instead
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700563 */
Charles Chan19b70032019-04-17 14:20:26 -0700564 @Deprecated
Pier Ventreb6a7f342016-11-26 21:05:22 -0800565 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700566 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan5eb66042018-06-18 14:42:17 -0700567 if (srinfo != null && srinfo.subnets != null) {
568 // Note: ImmutableSet.Builder.addAll calls the iterator of parameter internally,
569 // which is not protected by SynchronizedCollection mutex.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800570 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chan5eb66042018-06-18 14:42:17 -0700571 srinfo.subnets.forEach((k, v) -> builder.add(v));
572 return builder.build();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700573 }
Saurav Das7c305372015-10-28 12:39:42 -0700574 return null;
575 }
576
Charles Chan19b70032019-04-17 14:20:26 -0700577 /**
Charles Chan5eec3b12019-04-18 14:30:41 -0700578 * Returns batches of all subnets reachable via given next hop
579 * <p>
580 * First batch includes FPM and STATIC routes
581 * Second batch includes all other type of routes obtained from routeService, including DHCP routes.
582 *
583 * @param hostId next hop host id
584 * @return list of subnet batches, each batch includes a set of prefixes.
585 */
586 // TODO Querying routeService directly may be expensive. Some kind of reverse lookup cache should be developed.
587 public List<Set<IpPrefix>> getBatchedSubnets(HostId hostId) {
588 Set<IpPrefix> high = Sets.newHashSet();
589 Set<IpPrefix> low = Sets.newHashSet();
590
591 srManager.routeService.getRouteTables().stream()
592 .map(tableId -> srManager.routeService.getResolvedRoutes(tableId))
593 .flatMap(Collection::stream)
594 .forEach(resolvedRoute -> {
595 // Continue if next hop is not what we are looking for
596 if (!Objects.equals(hostId.mac(), resolvedRoute.nextHopMac()) ||
597 !Objects.equals(hostId.vlanId(), resolvedRoute.nextHopVlan())) {
598 return;
599 }
600 // Prioritize STATIC and FPM among others
601 if (resolvedRoute.route().source() == Route.Source.STATIC ||
602 resolvedRoute.route().source() == Route.Source.FPM) {
603 high.add(resolvedRoute.prefix());
604 } else {
605 low.add(resolvedRoute.prefix());
606 }
607 });
608 return Stream.of(high, low).filter(set -> !set.isEmpty()).collect(Collectors.toList());
609 }
610
611 /**
Charles Chan19b70032019-04-17 14:20:26 -0700612 * Returns batches of all subnets reachable on the given device.
613 * <p>
614 * First batch includes configured subnets, FPM and STATIC routes
615 * Second batch includes all other type of routes obtained from routeService, including DHCP routes.
616 *
617 * @param deviceId device identifier
618 * @return list of subnet batches, each batch includes a set of prefixes.
619 */
620 // TODO Querying routeService directly may be expensive. Some kind of reverse lookup cache should be developed.
621 public List<Set<IpPrefix>> getBatchedSubnets(DeviceId deviceId) {
622 Set<IpPrefix> high = Sets.newHashSet();
623 Set<IpPrefix> low = Sets.newHashSet();
624
625 high.addAll(getConfiguredSubnets(deviceId));
626 srManager.routeService.getRouteTables().stream()
627 .map(tableId -> srManager.routeService.getResolvedRoutes(tableId))
628 .flatMap(Collection::stream)
629 .forEach(resolvedRoute -> {
630 // Continue to next resolved route if none of the next hop attaches to given device
631 if (srManager.nextHopLocations(resolvedRoute).stream()
632 .noneMatch(cp -> Objects.equals(deviceId, cp.deviceId()))) {
633 return;
634 }
635 // Prioritize STATIC and FPM among others
636 if (resolvedRoute.route().source() == Route.Source.STATIC ||
637 resolvedRoute.route().source() == Route.Source.FPM) {
638 high.add(resolvedRoute.prefix());
639 } else {
640 low.add(resolvedRoute.prefix());
641 }
642 });
643 return Lists.newArrayList(high, low);
644 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800645
Saurav Das7c305372015-10-28 12:39:42 -0700646 /**
Charles Chan46fdfaf2016-11-09 20:51:44 -0800647 * Returns the subnet configuration of given device and port.
Saurav Das7c305372015-10-28 12:39:42 -0700648 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800649 * @param deviceId Device ID
650 * @param port Port number
Pier Ventreb6a7f342016-11-26 21:05:22 -0800651 * @return The subnets configured on given port or empty set if
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700652 * the port is unconfigured or suppressed.
Saurav Das7c305372015-10-28 12:39:42 -0700653 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800654 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800655 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
656
657 if (isSuppressedPort(connectPoint)) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800658 return Collections.emptySet();
Saurav Das7c305372015-10-28 12:39:42 -0700659 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800660
Charles Chancf789822019-03-22 10:04:27 -0700661 Set<IpPrefix> subnets = srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
662 .flatMap(intf -> intf.ipAddressesList().stream())
663 .map(InterfaceIpAddress::subnetAddress)
664 .collect(Collectors.toSet());
Charles Chan46fdfaf2016-11-09 20:51:44 -0800665
Jon Hall31d84782017-01-18 20:15:44 -0800666 if (subnets.isEmpty()) {
Saurav Dasf9332192017-02-18 14:05:44 -0800667 log.debug(NO_SUBNET, connectPoint);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800668 return Collections.emptySet();
Charles Chan46fdfaf2016-11-09 20:51:44 -0800669 }
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700670 return subnets;
Pier Ventreb6a7f342016-11-26 21:05:22 -0800671 }
672
673 /**
Charles Chan873661e2017-11-30 15:37:50 -0800674 * Returns all ports that has a subnet that contains any of the given IP addresses.
675 *
676 * @param ips a set of IP addresses
677 * @return a set of connect point that has a subnet that contains any of the given IP addresses
678 */
679 public Set<ConnectPoint> getPortByIps(Set<IpAddress> ips) {
680 return srManager.interfaceService.getInterfaces().stream()
681 .filter(intf -> intf.ipAddressesList().stream().anyMatch(intfAddress ->
682 ips.stream().anyMatch(ip -> intfAddress.subnetAddress().contains(ip))))
683 .map(Interface::connectPoint)
684 .collect(Collectors.toSet());
685 }
686
687 /**
pier6a2052b2019-06-28 22:17:31 +0200688 * Returns all the connect points of the segment routers that have the
689 * specified ip address in their subnets.
690 *
691 * @param destIpAddress target ip address
692 * @return connect points of the segment routers
693 */
694 public Set<ConnectPoint> getConnectPointsForASubnetHost(IpAddress destIpAddress) {
695 return srManager.interfaceService.getMatchingInterfaces(destIpAddress).stream()
696 .map(Interface::connectPoint)
697 .collect(Collectors.toSet());
698 }
699
700 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700701 * Returns the router ip address of segment router that has the
702 * specified ip address in its subnets.
703 *
704 * @param destIpAddress target ip address
705 * @return router ip address
706 */
707 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan70661362016-12-09 12:54:49 -0800708 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
709
710 if (matchIntf == null) {
711 log.debug("No router was found for {}", destIpAddress);
712 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700713 }
714
Charles Chan70661362016-12-09 12:54:49 -0800715 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
716 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
717 if (srInfo == null) {
718 log.debug("No device config was found for {}", routerDeviceId);
719 return null;
720 }
721
Pier Ventreadb4ae62016-11-23 09:57:42 -0800722 return srInfo.ipv4Loopback;
723 }
724
725 /**
726 * Returns the router ipv6 address of segment router that has the
727 * specified ip address in its subnets.
728 *
729 * @param destIpAddress target ip address
730 * @return router ip address
731 */
732 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
733 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
734
735 if (matchIntf == null) {
736 log.debug("No router was found for {}", destIpAddress);
737 return null;
738 }
739
740 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
741 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
742 if (srInfo == null) {
743 log.debug("No device config was found for {}", routerDeviceId);
744 return null;
745 }
746
747 return srInfo.ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700748 }
749
750 /**
751 * Returns the router mac address of segment router that has the
752 * specified ip address as one of its subnet gateway ip address.
753 *
754 * @param gatewayIpAddress router gateway ip address
Saurav Das7c305372015-10-28 12:39:42 -0700755 * @return router mac address or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700756 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800757 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700758 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
759 deviceConfigMap.entrySet()) {
760 if (entry.getValue().gatewayIps.
761 values().contains(gatewayIpAddress)) {
762 return entry.getValue().mac;
763 }
764 }
765
766 log.debug("Cannot find a router for {}", gatewayIpAddress);
767 return null;
768 }
sangho9b169e32015-04-14 16:27:13 -0700769
sangho9b169e32015-04-14 16:27:13 -0700770 /**
Charles Chan35f21e42017-06-26 18:30:18 -0700771 * Checks if the host IP is in any of the subnet defined in the router with the
sangho9b169e32015-04-14 16:27:13 -0700772 * device ID given.
773 *
774 * @param deviceId device identification of the router
775 * @param hostIp host IP address to check
Charles Chan35f21e42017-06-26 18:30:18 -0700776 * @return true if the given IP is within any of the subnet defined in the router,
777 * false if no subnet is defined in the router or if the host is not
778 * within any subnet defined in the router
sangho9b169e32015-04-14 16:27:13 -0700779 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800780 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
Charles Chancf789822019-03-22 10:04:27 -0700781 Set<IpPrefix> subnets = getConfiguredSubnets(deviceId);
sangho9b169e32015-04-14 16:27:13 -0700782 if (subnets == null) {
783 return false;
784 }
785
Pier Ventreb6a7f342016-11-26 21:05:22 -0800786 for (IpPrefix subnet: subnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800787 // Exclude /0 since it is a special case used for default route
788 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho9b169e32015-04-14 16:27:13 -0700789 return true;
790 }
791 }
sangho9b169e32015-04-14 16:27:13 -0700792 return false;
793 }
sangho27462c62015-05-14 00:39:53 -0700794
795 /**
Charles Chandebfea32016-10-24 14:52:01 -0700796 * Checks if the IP is in the subnet defined on given connect point.
797 *
798 * @param connectPoint Connect point
799 * @param ip The IP address to check
800 * @return True if the IP belongs to the subnet.
801 * False if the IP does not belong to the subnet, or
802 * there is no subnet configuration on given connect point.
803 */
804 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Charles Chan35f21e42017-06-26 18:30:18 -0700805 return getPortSubnets(connectPoint.deviceId(), connectPoint.port()).stream()
806 .anyMatch(ipPrefix -> ipPrefix.contains(ip));
Charles Chandebfea32016-10-24 14:52:01 -0700807 }
808
809 /**
sangho27462c62015-05-14 00:39:53 -0700810 * Returns the ports corresponding to the adjacency Sid given.
811 *
812 * @param deviceId device identification of the router
813 * @param sid adjacency Sid
Charles Chan9bec8a32015-12-01 10:00:51 -0800814 * @return set of port numbers
sangho27462c62015-05-14 00:39:53 -0700815 */
Charles Chan9bec8a32015-12-01 10:00:51 -0800816 public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700817 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800818 return srinfo != null ?
819 ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
820 ImmutableSet.copyOf(new HashSet<>());
sangho27462c62015-05-14 00:39:53 -0700821 }
822
823 /**
824 * Check if the Sid given is whether adjacency Sid of the router device or not.
825 *
826 * @param deviceId device identification of the router
827 * @param sid Sid to check
828 * @return true if the Sid given is the adjacency Sid of the device,
829 * otherwise false
830 */
831 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700832 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800833 return srinfo != null && srinfo.adjacencySids.containsKey(sid);
sangho27462c62015-05-14 00:39:53 -0700834 }
Charles Chan43547ca2016-02-10 20:46:58 -0800835
Charles Chanc91c8782016-03-30 17:54:24 -0700836 /**
Charles Chanc22cef32016-04-29 14:38:22 -0700837 * Add subnet to specific connect point.
838 *
839 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800840 * @param ipPrefix subnet being added to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700841 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800842 public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700843 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800844 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700845 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
846 if (srinfo == null) {
847 log.warn("Device {} is not configured. Abort.", cp.deviceId());
848 return;
849 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800850 srinfo.subnets.put(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700851 }
852
853 /**
854 * Remove subnet from specific connect point.
855 *
856 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800857 * @param ipPrefix subnet being removed to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700858 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800859 public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700860 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800861 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700862 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
863 if (srinfo == null) {
864 log.warn("Device {} is not configured. Abort.", cp.deviceId());
865 return;
866 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800867 srinfo.subnets.remove(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700868 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800869
870 private boolean isSuppressedPort(ConnectPoint connectPoint) {
871 SegmentRoutingAppConfig appConfig = srManager.cfgService
Ray Milkeyb85de082017-04-05 09:42:04 -0700872 .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800873 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chandebfea32016-10-24 14:52:01 -0700874 log.info("Interface configuration on port {} is ignored", connectPoint);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800875 return true;
876 }
877 return false;
878 }
Saurav Das261c3002017-06-13 15:35:54 -0700879
880 public boolean isPairedEdge(DeviceId deviceId) throws DeviceConfigNotFoundException {
881 if (!isEdgeDevice(deviceId)) {
882 return false;
883 }
884 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
885 return (srinfo.pairDeviceId == null) ? false : true;
886 }
887
888 public DeviceId getPairDeviceId(DeviceId deviceId) throws DeviceConfigNotFoundException {
889 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
890 if (srinfo != null) {
891 return srinfo.pairDeviceId;
892 } else {
893 String message = "getPairDeviceId fails for device: " + deviceId + ".";
894 throw new DeviceConfigNotFoundException(message);
895 }
896 }
897
898 public PortNumber getPairLocalPort(DeviceId deviceId)
899 throws DeviceConfigNotFoundException {
900 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
901 if (srinfo != null) {
902 return srinfo.pairLocalPort;
903 } else {
904 String message = "getPairLocalPort fails for device: " + deviceId + ".";
905 throw new DeviceConfigNotFoundException(message);
906 }
907 }
908
Saurav Dasec683dc2018-04-27 18:42:30 -0700909 public boolean isPairLocalPort(DeviceId devId, PortNumber pnum) {
910 return pnum.equals(srManager.getPairLocalPort(devId).orElse(null));
911 }
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800912}