blob: 71a199e88d9e5be540695e2ab07b936e1eb26272 [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuska58de4162015-09-10 16:15:33 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Charles Chan0b4e6182015-11-03 10:42:14 -080016package org.onosproject.segmentrouting.config;
sanghob35a6192015-04-01 13:05:26 -070017
Charles Chan5270ed02016-01-30 23:22:37 -080018import com.google.common.collect.HashMultimap;
Charles Chan9f676b62015-10-29 14:58:10 -070019import com.google.common.collect.ImmutableSet;
Charles Chan5270ed02016-01-30 23:22:37 -080020import com.google.common.collect.SetMultimap;
sanghob35a6192015-04-01 13:05:26 -070021import org.onlab.packet.Ip4Address;
Pier Ventree0ae7a32016-11-23 09:57:42 -080022import org.onlab.packet.Ip6Address;
Charles Chan03a73e02016-10-24 14:52:01 -070023import org.onlab.packet.IpAddress;
Charles Chan5270ed02016-01-30 23:22:37 -080024import org.onlab.packet.IpPrefix;
sanghob35a6192015-04-01 13:05:26 -070025import org.onlab.packet.MacAddress;
Charles Chane849c192016-01-11 18:28:54 -080026import org.onlab.packet.VlanId;
Charles Chan4636be02015-10-07 14:21:45 -070027import org.onosproject.incubator.net.config.basics.ConfigException;
28import org.onosproject.incubator.net.config.basics.InterfaceConfig;
29import org.onosproject.incubator.net.intf.Interface;
30import org.onosproject.net.ConnectPoint;
Charles Chan4636be02015-10-07 14:21:45 -070031import org.onosproject.net.host.InterfaceIpAddress;
sanghob35a6192015-04-01 13:05:26 -070032import org.onosproject.net.DeviceId;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070033import org.onosproject.net.PortNumber;
Charles Chan2c15aca2016-11-09 20:51:44 -080034import org.onosproject.segmentrouting.SegmentRoutingManager;
sanghob35a6192015-04-01 13:05:26 -070035import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070038import java.util.ArrayList;
Pier Ventre10bd8d12016-11-26 21:05:22 -080039import java.util.Collections;
sanghob35a6192015-04-01 13:05:26 -070040import java.util.HashMap;
Charles Chan531a78b2015-12-01 10:00:51 -080041import java.util.HashSet;
sanghob35a6192015-04-01 13:05:26 -070042import java.util.List;
43import java.util.Map;
Charles Chand6832882015-10-05 17:50:33 -070044import java.util.Set;
Saurav Das0e99e2b2015-10-28 12:39:42 -070045import java.util.concurrent.ConcurrentHashMap;
Charles Chan2c15aca2016-11-09 20:51:44 -080046import java.util.stream.Collectors;
sanghob35a6192015-04-01 13:05:26 -070047
Charles Chan93e71ba2016-04-29 14:38:22 -070048import static com.google.common.base.Preconditions.checkNotNull;
49
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070050/**
51 * Segment Routing configuration component that reads the
52 * segment routing related configuration from Network Configuration Manager
53 * component and organizes in more accessible formats.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070054 */
sanghob35a6192015-04-01 13:05:26 -070055public class DeviceConfiguration implements DeviceProperties {
56
Charles Chan2c15aca2016-11-09 20:51:44 -080057 private static final String NO_SUBNET = "No subnet configured on {}";
58
Charles Chanf2565a92016-02-10 20:46:58 -080059 private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -070060 private final List<Integer> allSegmentIds = new ArrayList<>();
Charles Chane849c192016-01-11 18:28:54 -080061 private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
Charles Chan2c15aca2016-11-09 20:51:44 -080062 private SegmentRoutingManager srManager;
sanghob35a6192015-04-01 13:05:26 -070063
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070064 private class SegmentRouterInfo {
Pier Ventree0ae7a32016-11-23 09:57:42 -080065 int ipv4NodeSid;
66 int ipv6NodeSid;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070067 DeviceId deviceId;
Pier Ventree0ae7a32016-11-23 09:57:42 -080068 Ip4Address ipv4Loopback;
69 Ip6Address ipv6Loopback;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070070 MacAddress mac;
71 boolean isEdge;
Pier Ventre10bd8d12016-11-26 21:05:22 -080072 SetMultimap<PortNumber, IpAddress> gatewayIps;
73 SetMultimap<PortNumber, IpPrefix> subnets;
Charles Chan531a78b2015-12-01 10:00:51 -080074 Map<Integer, Set<Integer>> adjacencySids;
Charles Chanb8e10c82015-10-14 11:24:40 -070075
76 public SegmentRouterInfo() {
Pier Ventre10bd8d12016-11-26 21:05:22 -080077 gatewayIps = HashMultimap.create();
Charles Chan5270ed02016-01-30 23:22:37 -080078 subnets = HashMultimap.create();
Charles Chanb8e10c82015-10-14 11:24:40 -070079 }
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070080 }
sanghob35a6192015-04-01 13:05:26 -070081
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070082 /**
Charles Chane849c192016-01-11 18:28:54 -080083 * Constructs device configuration for all Segment Router devices,
84 * organizing the data into various maps for easier access.
Brian O'Connor52515622015-10-09 17:03:44 -070085 *
Charles Chan2c15aca2016-11-09 20:51:44 -080086 * @param srManager Segment Routing Manager
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070087 */
Charles Chan2c15aca2016-11-09 20:51:44 -080088 public DeviceConfiguration(SegmentRoutingManager srManager) {
89 this.srManager = srManager;
Charles Chand9681e72016-02-22 19:27:29 -080090
Charles Chan4636be02015-10-07 14:21:45 -070091 // Read config from device subject, excluding gatewayIps and subnets.
92 Set<DeviceId> deviceSubjects =
Charles Chan2c15aca2016-11-09 20:51:44 -080093 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chan4636be02015-10-07 14:21:45 -070094 deviceSubjects.forEach(subject -> {
Charles Chan5270ed02016-01-30 23:22:37 -080095 SegmentRoutingDeviceConfig config =
Charles Chan2c15aca2016-11-09 20:51:44 -080096 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070097 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chand6832882015-10-05 17:50:33 -070098 info.deviceId = subject;
Pier Ventree0ae7a32016-11-23 09:57:42 -080099 info.ipv4NodeSid = config.nodeSidIPv4();
100 info.ipv6NodeSid = config.nodeSidIPv6();
101 info.ipv4Loopback = config.routerIpv4();
102 info.ipv6Loopback = config.routerIpv6();
Charles Chan531a78b2015-12-01 10:00:51 -0800103 info.mac = config.routerMac();
Charles Chand6832882015-10-05 17:50:33 -0700104 info.isEdge = config.isEdgeRouter();
Charles Chan531a78b2015-12-01 10:00:51 -0800105 info.adjacencySids = config.adjacencySids();
Charles Chane849c192016-01-11 18:28:54 -0800106 deviceConfigMap.put(info.deviceId, info);
Charles Chan278ce832017-06-26 15:25:09 -0700107 log.debug("Read device config for device: {}", info.deviceId);
Pier Ventree0ae7a32016-11-23 09:57:42 -0800108 /*
109 * IPv6 sid is not inserted. this part of the code is not used for now.
110 */
111 allSegmentIds.add(info.ipv4NodeSid);
Charles Chand6832882015-10-05 17:50:33 -0700112 });
Charles Chan4636be02015-10-07 14:21:45 -0700113
Charles Chan2c15aca2016-11-09 20:51:44 -0800114 // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
115 Set<ConnectPoint> portSubjects = srManager.cfgService
116 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
117 portSubjects.stream().filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chan4636be02015-10-07 14:21:45 -0700118 InterfaceConfig config =
Charles Chan2c15aca2016-11-09 20:51:44 -0800119 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chan4636be02015-10-07 14:21:45 -0700120 Set<Interface> networkInterfaces;
121 try {
122 networkInterfaces = config.getInterfaces();
123 } catch (ConfigException e) {
124 log.error("Error loading port configuration");
125 return;
126 }
127 networkInterfaces.forEach(networkInterface -> {
Charles Chane849c192016-01-11 18:28:54 -0800128 VlanId vlanId = networkInterface.vlan();
129 ConnectPoint connectPoint = networkInterface.connectPoint();
130 DeviceId dpid = connectPoint.deviceId();
131 PortNumber port = connectPoint.port();
132 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chan4636be02015-10-07 14:21:45 -0700133
Charles Chanb8e10c82015-10-14 11:24:40 -0700134 // skip if there is no corresponding device for this ConenctPoint
135 if (info != null) {
Charles Chane849c192016-01-11 18:28:54 -0800136 // Extract subnet information
Jonathan Hart00cddda2016-02-16 10:30:37 -0800137 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chanb8e10c82015-10-14 11:24:40 -0700138 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800139 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan5270ed02016-01-30 23:22:37 -0800140 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventre10bd8d12016-11-26 21:05:22 -0800141 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
142 if (ipPrefix.isIp4()) {
143 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
144 info.gatewayIps.put(port, interfaceAddress.ipAddress());
145 }
146 info.subnets.put(port, interfaceAddress.subnetAddress());
147 } else {
148 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
149 info.gatewayIps.put(port, interfaceAddress.ipAddress());
150 }
151 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan5270ed02016-01-30 23:22:37 -0800152 }
Charles Chanb8e10c82015-10-14 11:24:40 -0700153 });
154 }
Charles Chan4636be02015-10-07 14:21:45 -0700155 });
Pier Luigi0e358632017-01-31 09:35:05 -0800156 // We register the connect point with the NRS.
Pier Ventre10bd8d12016-11-26 21:05:22 -0800157 srManager.registerConnectPoint(subject);
Charles Chan4636be02015-10-07 14:21:45 -0700158 });
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700159 }
160
sanghob35a6192015-04-01 13:05:26 -0700161 @Override
Charles Chan0b4e6182015-11-03 10:42:14 -0800162 public boolean isConfigured(DeviceId deviceId) {
163 return deviceConfigMap.get(deviceId) != null;
164 }
165
166 @Override
Pier Ventree0ae7a32016-11-23 09:57:42 -0800167 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700168 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
169 if (srinfo != null) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800170 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
171 return srinfo.ipv4NodeSid;
sanghob35a6192015-04-01 13:05:26 -0700172 } else {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800173 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
174 throw new DeviceConfigNotFoundException(message);
175 }
176 }
177
178 @Override
179 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
180 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
181 if (srinfo != null) {
182 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
183 return srinfo.ipv6NodeSid;
184 } else {
185 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan0b4e6182015-11-03 10:42:14 -0800186 throw new DeviceConfigNotFoundException(message);
sanghob35a6192015-04-01 13:05:26 -0700187 }
188 }
189
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700190 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800191 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700192 *
193 * @param routerMac router mac address
Saurav Das0e99e2b2015-10-28 12:39:42 -0700194 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700195 */
Pier Ventree0ae7a32016-11-23 09:57:42 -0800196 public int getIPv4SegmentId(MacAddress routerMac) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700197 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
198 deviceConfigMap.entrySet()) {
199 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800200 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700201 }
202 }
sanghob35a6192015-04-01 13:05:26 -0700203
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700204 return -1;
205 }
206
207 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800208 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
209 *
210 * @param routerMac router mac address
211 * @return node segment id, or -1 if not found in config
212 */
213 public int getIPv6SegmentId(MacAddress routerMac) {
214 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
215 deviceConfigMap.entrySet()) {
216 if (entry.getValue().mac.equals(routerMac)) {
217 return entry.getValue().ipv6NodeSid;
218 }
219 }
220
221 return -1;
222 }
223
224 /**
225 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700226 *
227 * @param routerAddress router ip address
Saurav Das0e99e2b2015-10-28 12:39:42 -0700228 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700229 */
Pier Ventree0ae7a32016-11-23 09:57:42 -0800230 public int getIPv4SegmentId(Ip4Address routerAddress) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700231 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
232 deviceConfigMap.entrySet()) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800233 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
234 return entry.getValue().ipv4NodeSid;
235 }
236 }
237
238 return -1;
239 }
240
241 /**
242 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
243 *
244 * @param routerAddress router ip address
245 * @return node segment id, or -1 if not found in config
246 */
247 public int getIPv6SegmentId(Ip6Address routerAddress) {
248 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
249 deviceConfigMap.entrySet()) {
250 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
251 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700252 }
253 }
254
255 return -1;
256 }
257
sanghob35a6192015-04-01 13:05:26 -0700258 @Override
Charles Chan0b4e6182015-11-03 10:42:14 -0800259 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700260 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
261 if (srinfo != null) {
262 log.trace("getDeviceMac for device{} is {}", deviceId, srinfo.mac);
263 return srinfo.mac;
sanghob35a6192015-04-01 13:05:26 -0700264 } else {
Charles Chan0b4e6182015-11-03 10:42:14 -0800265 String message = "getDeviceMac fails for device: " + deviceId + ".";
266 throw new DeviceConfigNotFoundException(message);
sanghob35a6192015-04-01 13:05:26 -0700267 }
268 }
269
Charles Chan0b4e6182015-11-03 10:42:14 -0800270 @Override
Pier Ventree0ae7a32016-11-23 09:57:42 -0800271 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700272 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
273 if (srinfo != null) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800274 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
275 return srinfo.ipv4Loopback;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700276 } else {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800277 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
278 throw new DeviceConfigNotFoundException(message);
279 }
280 }
281
282 @Override
283 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
284 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
285 if (srinfo != null) {
286 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
287 return srinfo.ipv6Loopback;
288 } else {
289 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan0b4e6182015-11-03 10:42:14 -0800290 throw new DeviceConfigNotFoundException(message);
sanghob35a6192015-04-01 13:05:26 -0700291 }
sanghob35a6192015-04-01 13:05:26 -0700292 }
293
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700294 @Override
Charles Chan0b4e6182015-11-03 10:42:14 -0800295 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700296 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
297 if (srinfo != null) {
298 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
299 return srinfo.isEdge;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700300 } else {
Charles Chan0b4e6182015-11-03 10:42:14 -0800301 String message = "isEdgeDevice fails for device: " + deviceId + ".";
302 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700303 }
304 }
305
sanghob35a6192015-04-01 13:05:26 -0700306 @Override
307 public List<Integer> getAllDeviceSegmentIds() {
308 return allSegmentIds;
309 }
310
Charles Chanc42e84e2015-10-20 16:24:19 -0700311 @Override
Pier Ventre10bd8d12016-11-26 21:05:22 -0800312 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das7a1ffca2016-03-28 19:00:18 -0700313 throws DeviceConfigNotFoundException {
314 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
315 if (srinfo == null) {
316 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
317 throw new DeviceConfigNotFoundException(message);
318 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700319 // Construct subnet-port mapping from port-subnet mapping
Pier Ventre10bd8d12016-11-26 21:05:22 -0800320 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
321 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan5270ed02016-01-30 23:22:37 -0800322
323 portSubnetMap.entries().forEach(entry -> {
324 PortNumber port = entry.getKey();
Pier Ventre10bd8d12016-11-26 21:05:22 -0800325 IpPrefix subnet = entry.getValue();
Charles Chan5270ed02016-01-30 23:22:37 -0800326
Pier Ventre10bd8d12016-11-26 21:05:22 -0800327 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
328 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chand0fd5dc2016-02-16 23:14:49 -0800329 return;
330 }
331
Charles Chanc42e84e2015-10-20 16:24:19 -0700332 if (subnetPortMap.containsKey(subnet)) {
333 subnetPortMap.get(subnet).add(port);
334 } else {
335 ArrayList<PortNumber> ports = new ArrayList<>();
336 ports.add(port);
337 subnetPortMap.put(subnet, ports);
338 }
339 });
Charles Chanc42e84e2015-10-20 16:24:19 -0700340 return subnetPortMap;
341 }
342
sanghob35a6192015-04-01 13:05:26 -0700343 /**
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700344 * Returns the device identifier or data plane identifier (dpid)
345 * of a segment router given its segment id.
sanghob35a6192015-04-01 13:05:26 -0700346 *
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700347 * @param sid segment id
348 * @return deviceId device identifier
sanghob35a6192015-04-01 13:05:26 -0700349 */
350 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700351 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
352 deviceConfigMap.entrySet()) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800353 if (entry.getValue().ipv4NodeSid == sid ||
354 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700355 return entry.getValue().deviceId;
sanghob35a6192015-04-01 13:05:26 -0700356 }
357 }
358
359 return null;
360 }
361
362 /**
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700363 * Returns the device identifier or data plane identifier (dpid)
364 * of a segment router given its router ip address.
sanghob35a6192015-04-01 13:05:26 -0700365 *
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700366 * @param ipAddress router ip address
367 * @return deviceId device identifier
sanghob35a6192015-04-01 13:05:26 -0700368 */
369 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700370 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
371 deviceConfigMap.entrySet()) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800372 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
373 return entry.getValue().deviceId;
374 }
375 }
376
377 return null;
378 }
379
380 /**
381 * Returns the device identifier or data plane identifier (dpid)
382 * of a segment router given its router ipv6 address.
383 *
384 * @param ipAddress router ipv6 address
385 * @return deviceId device identifier
386 */
387 public DeviceId getDeviceId(Ip6Address ipAddress) {
388 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
389 deviceConfigMap.entrySet()) {
390 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700391 return entry.getValue().deviceId;
sanghob35a6192015-04-01 13:05:26 -0700392 }
393 }
394
395 return null;
396 }
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700397
398 /**
Saurav Das822c4e22015-10-23 10:51:11 -0700399 * Returns the configured port ip addresses for a segment router.
400 * These addresses serve as gateway IP addresses for the subnets configured
401 * on those ports.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700402 *
403 * @param deviceId device identifier
Saurav Das837e0bb2015-10-30 17:45:38 -0700404 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700405 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800406 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700407 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
408 if (srinfo != null) {
409 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
410 srinfo.gatewayIps.values());
Saurav Das837e0bb2015-10-30 17:45:38 -0700411 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700412 }
Saurav Das0e99e2b2015-10-28 12:39:42 -0700413 return null;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700414 }
415
416 /**
417 * Returns the configured subnet prefixes for a segment router.
418 *
419 * @param deviceId device identifier
Saurav Das0e99e2b2015-10-28 12:39:42 -0700420 * @return list of ip prefixes or null if not found
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700421 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800422 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700423 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
424 if (srinfo != null) {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800425 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chan03a73e02016-10-24 14:52:01 -0700426 return builder.addAll(srinfo.subnets.values()).build();
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700427 }
Saurav Das0e99e2b2015-10-28 12:39:42 -0700428 return null;
429 }
430
Charles Chan2c15aca2016-11-09 20:51:44 -0800431
Saurav Das0e99e2b2015-10-28 12:39:42 -0700432 /**
Charles Chan2c15aca2016-11-09 20:51:44 -0800433 * Returns the subnet configuration of given device and port.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700434 *
Charles Chan2c15aca2016-11-09 20:51:44 -0800435 * @param deviceId Device ID
436 * @param port Port number
Pier Ventre10bd8d12016-11-26 21:05:22 -0800437 * @return The subnets configured on given port or empty set if
Charles Chanc53d6172017-04-24 16:21:01 -0700438 * the port is unconfigured or suppressed.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700439 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800440 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan2c15aca2016-11-09 20:51:44 -0800441 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
442
443 if (isSuppressedPort(connectPoint)) {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800444 return Collections.emptySet();
Saurav Das0e99e2b2015-10-28 12:39:42 -0700445 }
Charles Chan2c15aca2016-11-09 20:51:44 -0800446
Pier Ventre10bd8d12016-11-26 21:05:22 -0800447 Set<IpPrefix> subnets =
Charles Chan2c15aca2016-11-09 20:51:44 -0800448 srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
449 .flatMap(intf -> intf.ipAddressesList().stream())
450 .map(InterfaceIpAddress::subnetAddress)
Charles Chan2c15aca2016-11-09 20:51:44 -0800451 .collect(Collectors.toSet());
452
Jon Hallcbd1b392017-01-18 20:15:44 -0800453 if (subnets.isEmpty()) {
Saurav Das018605f2017-02-18 14:05:44 -0800454 log.debug(NO_SUBNET, connectPoint);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800455 return Collections.emptySet();
Charles Chan2c15aca2016-11-09 20:51:44 -0800456 }
Charles Chanc53d6172017-04-24 16:21:01 -0700457
458 return subnets;
Pier Ventre10bd8d12016-11-26 21:05:22 -0800459 }
460
461 /**
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700462 * Returns the router ip address of segment router that has the
463 * specified ip address in its subnets.
464 *
465 * @param destIpAddress target ip address
466 * @return router ip address
467 */
468 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan68aaad52016-12-09 12:54:49 -0800469 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
470
471 if (matchIntf == null) {
472 log.debug("No router was found for {}", destIpAddress);
473 return null;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700474 }
475
Charles Chan68aaad52016-12-09 12:54:49 -0800476 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
477 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
478 if (srInfo == null) {
479 log.debug("No device config was found for {}", routerDeviceId);
480 return null;
481 }
482
Pier Ventree0ae7a32016-11-23 09:57:42 -0800483 return srInfo.ipv4Loopback;
484 }
485
486 /**
487 * Returns the router ipv6 address of segment router that has the
488 * specified ip address in its subnets.
489 *
490 * @param destIpAddress target ip address
491 * @return router ip address
492 */
493 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
494 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
495
496 if (matchIntf == null) {
497 log.debug("No router was found for {}", destIpAddress);
498 return null;
499 }
500
501 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
502 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
503 if (srInfo == null) {
504 log.debug("No device config was found for {}", routerDeviceId);
505 return null;
506 }
507
508 return srInfo.ipv6Loopback;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700509 }
510
511 /**
512 * Returns the router mac address of segment router that has the
513 * specified ip address as one of its subnet gateway ip address.
514 *
515 * @param gatewayIpAddress router gateway ip address
Saurav Das0e99e2b2015-10-28 12:39:42 -0700516 * @return router mac address or null if not found
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700517 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800518 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700519 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
520 deviceConfigMap.entrySet()) {
521 if (entry.getValue().gatewayIps.
522 values().contains(gatewayIpAddress)) {
523 return entry.getValue().mac;
524 }
525 }
526
527 log.debug("Cannot find a router for {}", gatewayIpAddress);
528 return null;
529 }
sangho666cd6d2015-04-14 16:27:13 -0700530
sangho666cd6d2015-04-14 16:27:13 -0700531 /**
Charles Chana9519af2017-06-26 18:30:18 -0700532 * Checks if the host IP is in any of the subnet defined in the router with the
sangho666cd6d2015-04-14 16:27:13 -0700533 * device ID given.
534 *
535 * @param deviceId device identification of the router
536 * @param hostIp host IP address to check
Charles Chana9519af2017-06-26 18:30:18 -0700537 * @return true if the given IP is within any of the subnet defined in the router,
538 * false if no subnet is defined in the router or if the host is not
539 * within any subnet defined in the router
sangho666cd6d2015-04-14 16:27:13 -0700540 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800541 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
sangho666cd6d2015-04-14 16:27:13 -0700542
Pier Ventre10bd8d12016-11-26 21:05:22 -0800543 Set<IpPrefix> subnets = getSubnets(deviceId);
sangho666cd6d2015-04-14 16:27:13 -0700544 if (subnets == null) {
545 return false;
546 }
547
Pier Ventre10bd8d12016-11-26 21:05:22 -0800548 for (IpPrefix subnet: subnets) {
Charles Chan5270ed02016-01-30 23:22:37 -0800549 // Exclude /0 since it is a special case used for default route
550 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho666cd6d2015-04-14 16:27:13 -0700551 return true;
552 }
553 }
554
555 return false;
556 }
sangho1e575652015-05-14 00:39:53 -0700557
558 /**
Charles Chan03a73e02016-10-24 14:52:01 -0700559 * Checks if the IP is in the subnet defined on given connect point.
560 *
561 * @param connectPoint Connect point
562 * @param ip The IP address to check
563 * @return True if the IP belongs to the subnet.
564 * False if the IP does not belong to the subnet, or
565 * there is no subnet configuration on given connect point.
566 */
567 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Charles Chana9519af2017-06-26 18:30:18 -0700568 return getPortSubnets(connectPoint.deviceId(), connectPoint.port()).stream()
569 .anyMatch(ipPrefix -> ipPrefix.contains(ip));
Charles Chan03a73e02016-10-24 14:52:01 -0700570 }
571
572 /**
sangho1e575652015-05-14 00:39:53 -0700573 * Returns the ports corresponding to the adjacency Sid given.
574 *
575 * @param deviceId device identification of the router
576 * @param sid adjacency Sid
Charles Chan531a78b2015-12-01 10:00:51 -0800577 * @return set of port numbers
sangho1e575652015-05-14 00:39:53 -0700578 */
Charles Chan531a78b2015-12-01 10:00:51 -0800579 public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700580 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan531a78b2015-12-01 10:00:51 -0800581 return srinfo != null ?
582 ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
583 ImmutableSet.copyOf(new HashSet<>());
sangho1e575652015-05-14 00:39:53 -0700584 }
585
586 /**
587 * Check if the Sid given is whether adjacency Sid of the router device or not.
588 *
589 * @param deviceId device identification of the router
590 * @param sid Sid to check
591 * @return true if the Sid given is the adjacency Sid of the device,
592 * otherwise false
593 */
594 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700595 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan531a78b2015-12-01 10:00:51 -0800596 return srinfo != null && srinfo.adjacencySids.containsKey(sid);
sangho1e575652015-05-14 00:39:53 -0700597 }
Charles Chanf2565a92016-02-10 20:46:58 -0800598
Charles Chand55e84d2016-03-30 17:54:24 -0700599 /**
Charles Chan93e71ba2016-04-29 14:38:22 -0700600 * Add subnet to specific connect point.
601 *
602 * @param cp connect point
Pier Ventre10bd8d12016-11-26 21:05:22 -0800603 * @param ipPrefix subnet being added to the device
Charles Chan93e71ba2016-04-29 14:38:22 -0700604 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800605 public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chan93e71ba2016-04-29 14:38:22 -0700606 checkNotNull(cp);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800607 checkNotNull(ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700608 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
609 if (srinfo == null) {
610 log.warn("Device {} is not configured. Abort.", cp.deviceId());
611 return;
612 }
Pier Ventre10bd8d12016-11-26 21:05:22 -0800613 srinfo.subnets.put(cp.port(), ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700614 }
615
616 /**
617 * Remove subnet from specific connect point.
618 *
619 * @param cp connect point
Pier Ventre10bd8d12016-11-26 21:05:22 -0800620 * @param ipPrefix subnet being removed to the device
Charles Chan93e71ba2016-04-29 14:38:22 -0700621 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800622 public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chan93e71ba2016-04-29 14:38:22 -0700623 checkNotNull(cp);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800624 checkNotNull(ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700625 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
626 if (srinfo == null) {
627 log.warn("Device {} is not configured. Abort.", cp.deviceId());
628 return;
629 }
Pier Ventre10bd8d12016-11-26 21:05:22 -0800630 srinfo.subnets.remove(cp.port(), ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700631 }
Charles Chan2c15aca2016-11-09 20:51:44 -0800632
633 private boolean isSuppressedPort(ConnectPoint connectPoint) {
634 SegmentRoutingAppConfig appConfig = srManager.cfgService
Ray Milkeye4afdb52017-04-05 09:42:04 -0700635 .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
Charles Chan2c15aca2016-11-09 20:51:44 -0800636 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chan03a73e02016-10-24 14:52:01 -0700637 log.info("Interface configuration on port {} is ignored", connectPoint);
Charles Chan2c15aca2016-11-09 20:51:44 -0800638 return true;
639 }
640 return false;
641 }
Jonathan Hart00cddda2016-02-16 10:30:37 -0800642}