blob: 7980d2501c1409075f5881e0e39641e86b97220c [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;
Andrea Campanella09943842020-03-27 12:53:46 +010039import org.onosproject.net.config.basics.BasicDeviceConfig;
Charles Chan44e914e2021-04-01 16:18:30 -070040import org.onosproject.net.config.basics.BasicHostConfig;
Jonathan Hart61e24e12017-11-30 18:23:42 -080041import org.onosproject.net.config.basics.InterfaceConfig;
42import org.onosproject.net.host.InterfaceIpAddress;
43import org.onosproject.net.intf.Interface;
Charles Chan19b70032019-04-17 14:20:26 -070044import org.onosproject.routeservice.Route;
pierventre2b102f92020-09-08 16:45:36 +020045import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
46import org.onosproject.segmentrouting.config.DeviceProperties;
47import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
48import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
sangho80f11cb2015-04-01 13:05:26 -070049import org.slf4j.Logger;
50import org.slf4j.LoggerFactory;
51
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070052import java.util.ArrayList;
Jonathan Hart61e24e12017-11-30 18:23:42 -080053import java.util.Collection;
Pier Ventreb6a7f342016-11-26 21:05:22 -080054import java.util.Collections;
sangho80f11cb2015-04-01 13:05:26 -070055import java.util.HashMap;
Charles Chan9bec8a32015-12-01 10:00:51 -080056import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070057import java.util.List;
58import java.util.Map;
Charles Chancf789822019-03-22 10:04:27 -070059import java.util.Objects;
Charles Chan72f556a2015-10-05 17:50:33 -070060import java.util.Set;
Saurav Das7c305372015-10-28 12:39:42 -070061import java.util.concurrent.ConcurrentHashMap;
Charles Chan46fdfaf2016-11-09 20:51:44 -080062import java.util.stream.Collectors;
Charles Chan5eec3b12019-04-18 14:30:41 -070063import java.util.stream.Stream;
sangho80f11cb2015-04-01 13:05:26 -070064
Charles Chanc22cef32016-04-29 14:38:22 -070065import static com.google.common.base.Preconditions.checkNotNull;
66
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070067/**
68 * Segment Routing configuration component that reads the
69 * segment routing related configuration from Network Configuration Manager
70 * component and organizes in more accessible formats.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070071 */
sangho80f11cb2015-04-01 13:05:26 -070072public class DeviceConfiguration implements DeviceProperties {
73
Charles Chan46fdfaf2016-11-09 20:51:44 -080074 private static final String NO_SUBNET = "No subnet configured on {}";
Charles Chan44e914e2021-04-01 16:18:30 -070075 // Key for BasicHostConfig
76 private static final String BASIC_KEY = "basic";
Charles Chan46fdfaf2016-11-09 20:51:44 -080077
Charles Chan43547ca2016-02-10 20:46:58 -080078 private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -070079 private final List<Integer> allSegmentIds = new ArrayList<>();
Charles Chanb7f75ac2016-01-11 18:28:54 -080080 private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
Charles Chan46fdfaf2016-11-09 20:51:44 -080081 private SegmentRoutingManager srManager;
sangho80f11cb2015-04-01 13:05:26 -070082
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070083 private class SegmentRouterInfo {
Charles Chan3d35a542018-10-02 12:52:29 -070084 int ipv4NodeSid = -1;
85 int ipv6NodeSid = -1;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070086 DeviceId deviceId;
Pier Ventreadb4ae62016-11-23 09:57:42 -080087 Ip4Address ipv4Loopback;
88 Ip6Address ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070089 MacAddress mac;
90 boolean isEdge;
Pier Ventreb6a7f342016-11-26 21:05:22 -080091 SetMultimap<PortNumber, IpAddress> gatewayIps;
92 SetMultimap<PortNumber, IpPrefix> subnets;
Charles Chan9bec8a32015-12-01 10:00:51 -080093 Map<Integer, Set<Integer>> adjacencySids;
Saurav Das261c3002017-06-13 15:35:54 -070094 DeviceId pairDeviceId;
95 PortNumber pairLocalPort;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070096 int pwRoutingLabel;
Charles Chan2b078ae2015-10-14 11:24:40 -070097
98 public SegmentRouterInfo() {
Charles Chandc7d6f92018-03-20 13:30:38 -070099 gatewayIps = Multimaps.synchronizedSetMultimap(HashMultimap.create());
100 subnets = Multimaps.synchronizedSetMultimap(HashMultimap.create());
Charles Chan2b078ae2015-10-14 11:24:40 -0700101 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700102 }
sangho80f11cb2015-04-01 13:05:26 -0700103
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700104 /**
Charles Chanb7f75ac2016-01-11 18:28:54 -0800105 * Constructs device configuration for all Segment Router devices,
106 * organizing the data into various maps for easier access.
Brian O'Connor65eeb572015-10-09 17:03:44 -0700107 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800108 * @param srManager Segment Routing Manager
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700109 */
Charles Chan46fdfaf2016-11-09 20:51:44 -0800110 public DeviceConfiguration(SegmentRoutingManager srManager) {
111 this.srManager = srManager;
Saurav Das261c3002017-06-13 15:35:54 -0700112 updateConfig();
113 }
Charles Chan57bd98c2016-02-22 19:27:29 -0800114
Saurav Das261c3002017-06-13 15:35:54 -0700115 public void updateConfig() {
Charles Chane7c61022015-10-07 14:21:45 -0700116 // Read config from device subject, excluding gatewayIps and subnets.
117 Set<DeviceId> deviceSubjects =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800118 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700119 deviceSubjects.forEach(subject -> {
Andrea Campanella09943842020-03-27 12:53:46 +0100120 BasicDeviceConfig basicDeviceConfig = srManager.cfgService.addConfig(subject, BasicDeviceConfig.class);
pierc81188f2020-04-15 22:48:36 +0200121 if (!basicDeviceConfig.purgeOnDisconnection()) {
122 // Setting purge on disconnection flag for the device SR has control over.
123 // addConfig returns a config if it exists or creates a new one.
124 log.info("PurgeOnDisconnection set to true for device {}", subject);
125 basicDeviceConfig.purgeOnDisconnection(true);
126 srManager.cfgService.applyConfig(subject, BasicDeviceConfig.class, basicDeviceConfig.node());
127 }
Charles Chan82ab1932016-01-30 23:22:37 -0800128 SegmentRoutingDeviceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800129 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700130 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chan72f556a2015-10-05 17:50:33 -0700131 info.deviceId = subject;
Pier Ventreadb4ae62016-11-23 09:57:42 -0800132 info.ipv4NodeSid = config.nodeSidIPv4();
133 info.ipv6NodeSid = config.nodeSidIPv6();
134 info.ipv4Loopback = config.routerIpv4();
135 info.ipv6Loopback = config.routerIpv6();
Charles Chan9bec8a32015-12-01 10:00:51 -0800136 info.mac = config.routerMac();
Charles Chan72f556a2015-10-05 17:50:33 -0700137 info.isEdge = config.isEdgeRouter();
Charles Chan9bec8a32015-12-01 10:00:51 -0800138 info.adjacencySids = config.adjacencySids();
Saurav Das261c3002017-06-13 15:35:54 -0700139 info.pairDeviceId = config.pairDeviceId();
140 info.pairLocalPort = config.pairLocalPort();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700141 info.pwRoutingLabel = info.ipv4NodeSid + 1000;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800142 deviceConfigMap.put(info.deviceId, info);
Charles Chan68363b12017-06-26 15:25:09 -0700143 log.debug("Read device config for device: {}", info.deviceId);
Charles Chan44e914e2021-04-01 16:18:30 -0700144 // IPv6 sid is not inserted. this part of the code is not used for now.
Pier Ventreadb4ae62016-11-23 09:57:42 -0800145 allSegmentIds.add(info.ipv4NodeSid);
Charles Chan44e914e2021-04-01 16:18:30 -0700146
147 // Block host with routerMac and untagged VLAN
148 blockHost(info.mac, VlanId.NONE);
Charles Chan72f556a2015-10-05 17:50:33 -0700149 });
Charles Chane7c61022015-10-07 14:21:45 -0700150
Charles Chan46fdfaf2016-11-09 20:51:44 -0800151 // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
152 Set<ConnectPoint> portSubjects = srManager.cfgService
153 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
Jonathan Hart61e24e12017-11-30 18:23:42 -0800154 portSubjects.stream()
155 .filter(subject -> deviceConfigMap.containsKey(subject.deviceId()))
156 .filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chane7c61022015-10-07 14:21:45 -0700157 InterfaceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800158 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700159 Set<Interface> networkInterfaces;
160 try {
161 networkInterfaces = config.getInterfaces();
162 } catch (ConfigException e) {
163 log.error("Error loading port configuration");
164 return;
165 }
166 networkInterfaces.forEach(networkInterface -> {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800167 VlanId vlanId = networkInterface.vlan();
168 ConnectPoint connectPoint = networkInterface.connectPoint();
169 DeviceId dpid = connectPoint.deviceId();
170 PortNumber port = connectPoint.port();
Charles Chan6191aca2017-09-12 12:09:22 -0700171 MacAddress mac = networkInterface.mac();
Charles Chanb7f75ac2016-01-11 18:28:54 -0800172 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chane7c61022015-10-07 14:21:45 -0700173
Charles Chan44e914e2021-04-01 16:18:30 -0700174 // skip if there is no corresponding device for this ConnectPoint
Charles Chan2b078ae2015-10-14 11:24:40 -0700175 if (info != null) {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800176 // Extract subnet information
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800177 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chan2b078ae2015-10-14 11:24:40 -0700178 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800179 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan82ab1932016-01-30 23:22:37 -0800180 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800181 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
182 if (ipPrefix.isIp4()) {
183 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
184 info.gatewayIps.put(port, interfaceAddress.ipAddress());
185 }
186 info.subnets.put(port, interfaceAddress.subnetAddress());
187 } else {
188 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
189 info.gatewayIps.put(port, interfaceAddress.ipAddress());
190 }
191 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan82ab1932016-01-30 23:22:37 -0800192 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700193 });
Charles Chan6191aca2017-09-12 12:09:22 -0700194
195 // Override interface mac with router mac
196 if (!mac.equals(info.mac)) {
197 ArrayNode array = (ArrayNode) config.node();
198 for (JsonNode intfNode : array) {
199 ObjectNode objNode = (ObjectNode) intfNode;
200 objNode.put(InterfaceConfig.MAC, info.mac.toString());
201 }
202 srManager.cfgService.applyConfig(connectPoint, InterfaceConfig.class, array);
203 }
Charles Chan44e914e2021-04-01 16:18:30 -0700204
205 // Block host with routerMac and taggedVlan
206 networkInterface.vlanTagged().forEach(taggedVlan -> {
207 blockHost(info.mac, taggedVlan);
208 });
Charles Chan2b078ae2015-10-14 11:24:40 -0700209 }
Charles Chane7c61022015-10-07 14:21:45 -0700210 });
Pier Luigi6a2643a2017-01-31 09:35:05 -0800211 // We register the connect point with the NRS.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800212 srManager.registerConnectPoint(subject);
Charles Chane7c61022015-10-07 14:21:45 -0700213 });
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700214 }
215
Charles Chan44e914e2021-04-01 16:18:30 -0700216 private void blockHost(MacAddress macAddress, VlanId vlanId) {
217 HostId hostId = HostId.hostId(macAddress, vlanId);
218 BasicHostConfig hostConfig = srManager.cfgService.getConfig(hostId, BasicHostConfig.class);
219 if (hostConfig == null) {
220 ObjectMapper mapper = new ObjectMapper();
221 JsonNode jsonNode = mapper.createObjectNode();
222 hostConfig = new BasicHostConfig();
223 hostConfig.init(hostId, BASIC_KEY, jsonNode, mapper, config -> { });
224 }
225 hostConfig.isAllowed(false);
226 srManager.cfgService.applyConfig(hostId, BasicHostConfig.class, hostConfig.node());
227 log.info("Blocking {} from being learnt as host", hostId);
228 }
229
Jonathan Hart61e24e12017-11-30 18:23:42 -0800230 public Collection<DeviceId> getRouters() {
231 return deviceConfigMap.keySet();
232 }
Saurav Das261c3002017-06-13 15:35:54 -0700233
sangho80f11cb2015-04-01 13:05:26 -0700234 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800235 public boolean isConfigured(DeviceId deviceId) {
236 return deviceConfigMap.get(deviceId) != null;
237 }
238
239 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800240 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700241 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
242 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800243 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
244 return srinfo.ipv4NodeSid;
sangho80f11cb2015-04-01 13:05:26 -0700245 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800246 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
247 throw new DeviceConfigNotFoundException(message);
248 }
249 }
250
251 @Override
252 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
253 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
254 if (srinfo != null) {
255 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
256 return srinfo.ipv6NodeSid;
257 } else {
258 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800259 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700260 }
261 }
262
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700263 @Override
264 public int getPWRoutingLabel(DeviceId deviceId) throws DeviceConfigNotFoundException {
265 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
266 if (srinfo != null) {
267 log.trace("pwRoutingLabel for device{} is {}", deviceId, srinfo.pwRoutingLabel);
268 return srinfo.pwRoutingLabel;
269 } else {
270 String message = "getPWRoutingLabel fails for device: " + deviceId + ".";
271 throw new DeviceConfigNotFoundException(message);
272 }
273 }
274
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700275 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800276 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700277 *
278 * @param routerMac router mac address
Saurav Das7c305372015-10-28 12:39:42 -0700279 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700280 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800281 public int getIPv4SegmentId(MacAddress routerMac) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700282 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
283 deviceConfigMap.entrySet()) {
284 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800285 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700286 }
287 }
sangho80f11cb2015-04-01 13:05:26 -0700288
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700289 return -1;
290 }
291
292 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800293 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
294 *
295 * @param routerMac router mac address
296 * @return node segment id, or -1 if not found in config
297 */
298 public int getIPv6SegmentId(MacAddress routerMac) {
299 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
300 deviceConfigMap.entrySet()) {
301 if (entry.getValue().mac.equals(routerMac)) {
302 return entry.getValue().ipv6NodeSid;
303 }
304 }
305
306 return -1;
307 }
308
309 /**
310 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700311 *
312 * @param routerAddress router ip address
Saurav Das7c305372015-10-28 12:39:42 -0700313 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700314 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800315 public int getIPv4SegmentId(Ip4Address routerAddress) {
Charles Chan3d35a542018-10-02 12:52:29 -0700316 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: deviceConfigMap.entrySet()) {
317 Ip4Address ipv4Loopback = entry.getValue().ipv4Loopback;
318 if (ipv4Loopback == null) {
319 continue;
320 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800321 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
Charles Chan3d35a542018-10-02 12:52:29 -0700322 if (entry.getValue().ipv4NodeSid == -1) {
323 continue;
324 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800325 return entry.getValue().ipv4NodeSid;
326 }
327 }
328
329 return -1;
330 }
331
332 /**
333 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
334 *
335 * @param routerAddress router ip address
336 * @return node segment id, or -1 if not found in config
337 */
338 public int getIPv6SegmentId(Ip6Address routerAddress) {
Charles Chan3d35a542018-10-02 12:52:29 -0700339 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: deviceConfigMap.entrySet()) {
340 Ip6Address ipv6Loopback = entry.getValue().ipv6Loopback;
341 if (ipv6Loopback == null) {
342 continue;
343 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800344 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
Charles Chan3d35a542018-10-02 12:52:29 -0700345 if (entry.getValue().ipv6NodeSid == -1) {
346 continue;
347 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800348 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700349 }
350 }
351
352 return -1;
353 }
354
sangho80f11cb2015-04-01 13:05:26 -0700355 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800356 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700357 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
358 if (srinfo != null) {
Saurav Das7c305372015-10-28 12:39:42 -0700359 return srinfo.mac;
sangho80f11cb2015-04-01 13:05:26 -0700360 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800361 String message = "getDeviceMac fails for device: " + deviceId + ".";
362 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700363 }
364 }
365
Charles Chan319d1a22015-11-03 10:42:14 -0800366 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800367 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700368 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
369 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800370 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
371 return srinfo.ipv4Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700372 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800373 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
374 throw new DeviceConfigNotFoundException(message);
375 }
376 }
377
378 @Override
379 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
380 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
381 if (srinfo != null) {
382 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
383 return srinfo.ipv6Loopback;
384 } else {
385 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800386 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700387 }
sangho80f11cb2015-04-01 13:05:26 -0700388 }
389
pier6a2052b2019-06-28 22:17:31 +0200390 /**
391 * Gets router ip address based on the destination ip address.
392 *
393 * @param destIpAddress the destination ip address
394 * @param routerDeviceId the device id
395 * @return the ip address of the routes
396 */
397 public IpAddress getRouterIpAddress(IpAddress destIpAddress, DeviceId routerDeviceId) {
398 IpAddress routerIpAddress;
399 try {
400 routerIpAddress = destIpAddress.isIp4() ? getRouterIpv4(routerDeviceId) :
401 getRouterIpv6(routerDeviceId);
402 } catch (DeviceConfigNotFoundException e) {
403 routerIpAddress = null;
404 }
405 return routerIpAddress;
406 }
407
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700408 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800409 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700410 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
411 if (srinfo != null) {
412 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
413 return srinfo.isEdge;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700414 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800415 String message = "isEdgeDevice fails for device: " + deviceId + ".";
416 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700417 }
418 }
419
sangho80f11cb2015-04-01 13:05:26 -0700420 @Override
pierventre30368ab2021-02-24 23:23:22 +0100421 public List<DeviceId> getEdgeDeviceIds() {
422 return deviceConfigMap.values().stream()
423 .filter(deviceInfo -> deviceInfo.isEdge)
424 .map(deviceInfo -> deviceInfo.deviceId)
425 .collect(Collectors.toList());
426 }
427
428 @Override
Charles Chana2401452021-06-03 15:57:48 -0700429 public List<DeviceId> getInfraDeviceIds() {
430 return deviceConfigMap.values().stream()
431 .filter(deviceInfo -> !deviceInfo.isEdge)
432 .map(deviceInfo -> deviceInfo.deviceId)
433 .collect(Collectors.toList());
434 }
435
436 @Override
sangho80f11cb2015-04-01 13:05:26 -0700437 public List<Integer> getAllDeviceSegmentIds() {
438 return allSegmentIds;
439 }
440
Charles Chan77277672015-10-20 16:24:19 -0700441 @Override
Pier Ventreb6a7f342016-11-26 21:05:22 -0800442 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das52d4ed72016-03-28 19:00:18 -0700443 throws DeviceConfigNotFoundException {
444 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
445 if (srinfo == null) {
446 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
447 throw new DeviceConfigNotFoundException(message);
448 }
Charles Chan77277672015-10-20 16:24:19 -0700449 // Construct subnet-port mapping from port-subnet mapping
Pier Ventreb6a7f342016-11-26 21:05:22 -0800450 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
451 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan82ab1932016-01-30 23:22:37 -0800452
453 portSubnetMap.entries().forEach(entry -> {
454 PortNumber port = entry.getKey();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800455 IpPrefix subnet = entry.getValue();
Charles Chan82ab1932016-01-30 23:22:37 -0800456
Pier Ventreb6a7f342016-11-26 21:05:22 -0800457 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
458 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chanbbd004c2016-02-16 23:14:49 -0800459 return;
460 }
461
Charles Chan77277672015-10-20 16:24:19 -0700462 if (subnetPortMap.containsKey(subnet)) {
463 subnetPortMap.get(subnet).add(port);
464 } else {
465 ArrayList<PortNumber> ports = new ArrayList<>();
466 ports.add(port);
467 subnetPortMap.put(subnet, ports);
468 }
469 });
Charles Chan77277672015-10-20 16:24:19 -0700470 return subnetPortMap;
471 }
472
sangho80f11cb2015-04-01 13:05:26 -0700473 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700474 * Returns the device identifier or data plane identifier (dpid)
475 * of a segment router given its segment id.
sangho80f11cb2015-04-01 13:05:26 -0700476 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700477 * @param sid segment id
478 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700479 */
480 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700481 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
482 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800483 if (entry.getValue().ipv4NodeSid == sid ||
484 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700485 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700486 }
487 }
488
489 return null;
490 }
491
492 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700493 * Returns the device identifier or data plane identifier (dpid)
494 * of a segment router given its router ip address.
sangho80f11cb2015-04-01 13:05:26 -0700495 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700496 * @param ipAddress router ip address
497 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700498 */
499 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700500 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
501 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800502 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
503 return entry.getValue().deviceId;
504 }
505 }
506
507 return null;
508 }
509
510 /**
511 * Returns the device identifier or data plane identifier (dpid)
512 * of a segment router given its router ipv6 address.
513 *
514 * @param ipAddress router ipv6 address
515 * @return deviceId device identifier
516 */
517 public DeviceId getDeviceId(Ip6Address ipAddress) {
518 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
519 deviceConfigMap.entrySet()) {
520 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700521 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700522 }
523 }
524
525 return null;
526 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700527
528 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700529 * Returns the configured port ip addresses for a segment router.
530 * These addresses serve as gateway IP addresses for the subnets configured
531 * on those ports.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700532 *
533 * @param deviceId device identifier
Saurav Dasc28b3432015-10-30 17:45:38 -0700534 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700535 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800536 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700537 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
538 if (srinfo != null) {
539 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
540 srinfo.gatewayIps.values());
Saurav Dasc28b3432015-10-30 17:45:38 -0700541 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700542 }
Saurav Das7c305372015-10-28 12:39:42 -0700543 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700544 }
545
546 /**
Charles Chancf789822019-03-22 10:04:27 -0700547 * Returns configured subnets for a segment router.
548 *
549 * @param deviceId device identifier
550 * @return list of ip prefixes or null if not found
551 */
552 public Set<IpPrefix> getConfiguredSubnets(DeviceId deviceId) {
553 Set<IpPrefix> subnets = srManager.interfaceService.getInterfaces().stream()
554 .filter(intf -> Objects.equals(deviceId, intf.connectPoint().deviceId()))
555 .flatMap(intf -> intf.ipAddressesList().stream())
556 .map(InterfaceIpAddress::subnetAddress)
557 .collect(Collectors.toSet());
558
559 if (subnets.isEmpty()) {
560 log.debug(NO_SUBNET, deviceId);
561 return Collections.emptySet();
562 }
563 return subnets;
564 }
565
566 /**
567 * Returns all subnets for a segment router, including subnets learnt from route service.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700568 *
569 * @param deviceId device identifier
Charles Chan19b70032019-04-17 14:20:26 -0700570 * @return set of ip prefixes or null if not found
571 * @deprecated use getBatchedSubnets(DeviceId deviceId) instead
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700572 */
Charles Chan19b70032019-04-17 14:20:26 -0700573 @Deprecated
Pier Ventreb6a7f342016-11-26 21:05:22 -0800574 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700575 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan5eb66042018-06-18 14:42:17 -0700576 if (srinfo != null && srinfo.subnets != null) {
577 // Note: ImmutableSet.Builder.addAll calls the iterator of parameter internally,
578 // which is not protected by SynchronizedCollection mutex.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800579 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chan5eb66042018-06-18 14:42:17 -0700580 srinfo.subnets.forEach((k, v) -> builder.add(v));
581 return builder.build();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700582 }
Saurav Das7c305372015-10-28 12:39:42 -0700583 return null;
584 }
585
Charles Chan19b70032019-04-17 14:20:26 -0700586 /**
Charles Chan5eec3b12019-04-18 14:30:41 -0700587 * Returns batches of all subnets reachable via given next hop
588 * <p>
589 * First batch includes FPM and STATIC routes
590 * Second batch includes all other type of routes obtained from routeService, including DHCP routes.
591 *
592 * @param hostId next hop host id
593 * @return list of subnet batches, each batch includes a set of prefixes.
594 */
595 // TODO Querying routeService directly may be expensive. Some kind of reverse lookup cache should be developed.
596 public List<Set<IpPrefix>> getBatchedSubnets(HostId hostId) {
597 Set<IpPrefix> high = Sets.newHashSet();
598 Set<IpPrefix> low = Sets.newHashSet();
599
600 srManager.routeService.getRouteTables().stream()
601 .map(tableId -> srManager.routeService.getResolvedRoutes(tableId))
602 .flatMap(Collection::stream)
603 .forEach(resolvedRoute -> {
604 // Continue if next hop is not what we are looking for
605 if (!Objects.equals(hostId.mac(), resolvedRoute.nextHopMac()) ||
606 !Objects.equals(hostId.vlanId(), resolvedRoute.nextHopVlan())) {
607 return;
608 }
609 // Prioritize STATIC and FPM among others
610 if (resolvedRoute.route().source() == Route.Source.STATIC ||
611 resolvedRoute.route().source() == Route.Source.FPM) {
612 high.add(resolvedRoute.prefix());
613 } else {
614 low.add(resolvedRoute.prefix());
615 }
616 });
617 return Stream.of(high, low).filter(set -> !set.isEmpty()).collect(Collectors.toList());
618 }
619
620 /**
Charles Chan19b70032019-04-17 14:20:26 -0700621 * Returns batches of all subnets reachable on the given device.
622 * <p>
623 * First batch includes configured subnets, FPM and STATIC routes
624 * Second batch includes all other type of routes obtained from routeService, including DHCP routes.
625 *
626 * @param deviceId device identifier
627 * @return list of subnet batches, each batch includes a set of prefixes.
628 */
629 // TODO Querying routeService directly may be expensive. Some kind of reverse lookup cache should be developed.
630 public List<Set<IpPrefix>> getBatchedSubnets(DeviceId deviceId) {
631 Set<IpPrefix> high = Sets.newHashSet();
632 Set<IpPrefix> low = Sets.newHashSet();
633
634 high.addAll(getConfiguredSubnets(deviceId));
635 srManager.routeService.getRouteTables().stream()
636 .map(tableId -> srManager.routeService.getResolvedRoutes(tableId))
637 .flatMap(Collection::stream)
638 .forEach(resolvedRoute -> {
639 // Continue to next resolved route if none of the next hop attaches to given device
640 if (srManager.nextHopLocations(resolvedRoute).stream()
641 .noneMatch(cp -> Objects.equals(deviceId, cp.deviceId()))) {
642 return;
643 }
644 // Prioritize STATIC and FPM among others
645 if (resolvedRoute.route().source() == Route.Source.STATIC ||
646 resolvedRoute.route().source() == Route.Source.FPM) {
647 high.add(resolvedRoute.prefix());
648 } else {
649 low.add(resolvedRoute.prefix());
650 }
651 });
652 return Lists.newArrayList(high, low);
653 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800654
Saurav Das7c305372015-10-28 12:39:42 -0700655 /**
Charles Chan46fdfaf2016-11-09 20:51:44 -0800656 * Returns the subnet configuration of given device and port.
Saurav Das7c305372015-10-28 12:39:42 -0700657 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800658 * @param deviceId Device ID
659 * @param port Port number
Pier Ventreb6a7f342016-11-26 21:05:22 -0800660 * @return The subnets configured on given port or empty set if
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700661 * the port is unconfigured or suppressed.
Saurav Das7c305372015-10-28 12:39:42 -0700662 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800663 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800664 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
665
666 if (isSuppressedPort(connectPoint)) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800667 return Collections.emptySet();
Saurav Das7c305372015-10-28 12:39:42 -0700668 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800669
Charles Chancf789822019-03-22 10:04:27 -0700670 Set<IpPrefix> subnets = srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
671 .flatMap(intf -> intf.ipAddressesList().stream())
672 .map(InterfaceIpAddress::subnetAddress)
673 .collect(Collectors.toSet());
Charles Chan46fdfaf2016-11-09 20:51:44 -0800674
Jon Hall31d84782017-01-18 20:15:44 -0800675 if (subnets.isEmpty()) {
Saurav Dasf9332192017-02-18 14:05:44 -0800676 log.debug(NO_SUBNET, connectPoint);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800677 return Collections.emptySet();
Charles Chan46fdfaf2016-11-09 20:51:44 -0800678 }
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700679 return subnets;
Pier Ventreb6a7f342016-11-26 21:05:22 -0800680 }
681
682 /**
Charles Chan873661e2017-11-30 15:37:50 -0800683 * Returns all ports that has a subnet that contains any of the given IP addresses.
684 *
685 * @param ips a set of IP addresses
686 * @return a set of connect point that has a subnet that contains any of the given IP addresses
687 */
688 public Set<ConnectPoint> getPortByIps(Set<IpAddress> ips) {
689 return srManager.interfaceService.getInterfaces().stream()
690 .filter(intf -> intf.ipAddressesList().stream().anyMatch(intfAddress ->
691 ips.stream().anyMatch(ip -> intfAddress.subnetAddress().contains(ip))))
692 .map(Interface::connectPoint)
693 .collect(Collectors.toSet());
694 }
695
696 /**
pier6a2052b2019-06-28 22:17:31 +0200697 * Returns all the connect points of the segment routers that have the
698 * specified ip address in their subnets.
699 *
700 * @param destIpAddress target ip address
701 * @return connect points of the segment routers
702 */
703 public Set<ConnectPoint> getConnectPointsForASubnetHost(IpAddress destIpAddress) {
704 return srManager.interfaceService.getMatchingInterfaces(destIpAddress).stream()
705 .map(Interface::connectPoint)
706 .collect(Collectors.toSet());
707 }
708
709 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700710 * Returns the router ip address of segment router that has the
711 * specified ip address in its subnets.
712 *
713 * @param destIpAddress target ip address
714 * @return router ip address
715 */
716 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan70661362016-12-09 12:54:49 -0800717 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
718
719 if (matchIntf == null) {
720 log.debug("No router was found for {}", destIpAddress);
721 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700722 }
723
Charles Chan70661362016-12-09 12:54:49 -0800724 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
725 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
726 if (srInfo == null) {
727 log.debug("No device config was found for {}", routerDeviceId);
728 return null;
729 }
730
Pier Ventreadb4ae62016-11-23 09:57:42 -0800731 return srInfo.ipv4Loopback;
732 }
733
734 /**
735 * Returns the router ipv6 address of segment router that has the
736 * specified ip address in its subnets.
737 *
738 * @param destIpAddress target ip address
739 * @return router ip address
740 */
741 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
742 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
743
744 if (matchIntf == null) {
745 log.debug("No router was found for {}", destIpAddress);
746 return null;
747 }
748
749 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
750 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
751 if (srInfo == null) {
752 log.debug("No device config was found for {}", routerDeviceId);
753 return null;
754 }
755
756 return srInfo.ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700757 }
758
759 /**
760 * Returns the router mac address of segment router that has the
761 * specified ip address as one of its subnet gateway ip address.
762 *
763 * @param gatewayIpAddress router gateway ip address
Saurav Das7c305372015-10-28 12:39:42 -0700764 * @return router mac address or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700765 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800766 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700767 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
768 deviceConfigMap.entrySet()) {
769 if (entry.getValue().gatewayIps.
770 values().contains(gatewayIpAddress)) {
771 return entry.getValue().mac;
772 }
773 }
774
775 log.debug("Cannot find a router for {}", gatewayIpAddress);
776 return null;
777 }
sangho9b169e32015-04-14 16:27:13 -0700778
sangho9b169e32015-04-14 16:27:13 -0700779 /**
Charles Chan35f21e42017-06-26 18:30:18 -0700780 * Checks if the host IP is in any of the subnet defined in the router with the
sangho9b169e32015-04-14 16:27:13 -0700781 * device ID given.
782 *
783 * @param deviceId device identification of the router
784 * @param hostIp host IP address to check
Charles Chan35f21e42017-06-26 18:30:18 -0700785 * @return true if the given IP is within any of the subnet defined in the router,
786 * false if no subnet is defined in the router or if the host is not
787 * within any subnet defined in the router
sangho9b169e32015-04-14 16:27:13 -0700788 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800789 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
Charles Chancf789822019-03-22 10:04:27 -0700790 Set<IpPrefix> subnets = getConfiguredSubnets(deviceId);
sangho9b169e32015-04-14 16:27:13 -0700791 if (subnets == null) {
792 return false;
793 }
794
Pier Ventreb6a7f342016-11-26 21:05:22 -0800795 for (IpPrefix subnet: subnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800796 // Exclude /0 since it is a special case used for default route
797 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho9b169e32015-04-14 16:27:13 -0700798 return true;
799 }
800 }
sangho9b169e32015-04-14 16:27:13 -0700801 return false;
802 }
sangho27462c62015-05-14 00:39:53 -0700803
804 /**
Charles Chandebfea32016-10-24 14:52:01 -0700805 * Checks if the IP is in the subnet defined on given connect point.
806 *
807 * @param connectPoint Connect point
808 * @param ip The IP address to check
809 * @return True if the IP belongs to the subnet.
810 * False if the IP does not belong to the subnet, or
811 * there is no subnet configuration on given connect point.
812 */
813 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Charles Chan35f21e42017-06-26 18:30:18 -0700814 return getPortSubnets(connectPoint.deviceId(), connectPoint.port()).stream()
815 .anyMatch(ipPrefix -> ipPrefix.contains(ip));
Charles Chandebfea32016-10-24 14:52:01 -0700816 }
817
818 /**
sangho27462c62015-05-14 00:39:53 -0700819 * Returns the ports corresponding to the adjacency Sid given.
820 *
821 * @param deviceId device identification of the router
822 * @param sid adjacency Sid
Charles Chan9bec8a32015-12-01 10:00:51 -0800823 * @return set of port numbers
sangho27462c62015-05-14 00:39:53 -0700824 */
Charles Chan9bec8a32015-12-01 10:00:51 -0800825 public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700826 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800827 return srinfo != null ?
828 ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
829 ImmutableSet.copyOf(new HashSet<>());
sangho27462c62015-05-14 00:39:53 -0700830 }
831
832 /**
833 * Check if the Sid given is whether adjacency Sid of the router device or not.
834 *
835 * @param deviceId device identification of the router
836 * @param sid Sid to check
837 * @return true if the Sid given is the adjacency Sid of the device,
838 * otherwise false
839 */
840 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700841 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800842 return srinfo != null && srinfo.adjacencySids.containsKey(sid);
sangho27462c62015-05-14 00:39:53 -0700843 }
Charles Chan43547ca2016-02-10 20:46:58 -0800844
Charles Chanc91c8782016-03-30 17:54:24 -0700845 /**
Charles Chanc22cef32016-04-29 14:38:22 -0700846 * Add subnet to specific connect point.
847 *
848 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800849 * @param ipPrefix subnet being added to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700850 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800851 public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700852 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800853 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700854 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
855 if (srinfo == null) {
856 log.warn("Device {} is not configured. Abort.", cp.deviceId());
857 return;
858 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800859 srinfo.subnets.put(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700860 }
861
862 /**
863 * Remove subnet from specific connect point.
864 *
865 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800866 * @param ipPrefix subnet being removed to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700867 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800868 public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700869 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800870 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700871 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
872 if (srinfo == null) {
873 log.warn("Device {} is not configured. Abort.", cp.deviceId());
874 return;
875 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800876 srinfo.subnets.remove(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700877 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800878
879 private boolean isSuppressedPort(ConnectPoint connectPoint) {
880 SegmentRoutingAppConfig appConfig = srManager.cfgService
Ray Milkeyb85de082017-04-05 09:42:04 -0700881 .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800882 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chandebfea32016-10-24 14:52:01 -0700883 log.info("Interface configuration on port {} is ignored", connectPoint);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800884 return true;
885 }
886 return false;
887 }
Saurav Das261c3002017-06-13 15:35:54 -0700888
889 public boolean isPairedEdge(DeviceId deviceId) throws DeviceConfigNotFoundException {
890 if (!isEdgeDevice(deviceId)) {
891 return false;
892 }
893 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
894 return (srinfo.pairDeviceId == null) ? false : true;
895 }
896
897 public DeviceId getPairDeviceId(DeviceId deviceId) throws DeviceConfigNotFoundException {
898 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
899 if (srinfo != null) {
900 return srinfo.pairDeviceId;
901 } else {
902 String message = "getPairDeviceId fails for device: " + deviceId + ".";
903 throw new DeviceConfigNotFoundException(message);
904 }
905 }
906
907 public PortNumber getPairLocalPort(DeviceId deviceId)
908 throws DeviceConfigNotFoundException {
909 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
910 if (srinfo != null) {
911 return srinfo.pairLocalPort;
912 } else {
913 String message = "getPairLocalPort fails for device: " + deviceId + ".";
914 throw new DeviceConfigNotFoundException(message);
915 }
916 }
917
Saurav Dasec683dc2018-04-27 18:42:30 -0700918 public boolean isPairLocalPort(DeviceId devId, PortNumber pnum) {
919 return pnum.equals(srManager.getPairLocalPort(devId).orElse(null));
920 }
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800921}