blob: 6ceeb4bab2e244296eb0b0b7cd4ce058ca8800ab [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
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;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070022import org.onlab.packet.Ip4Prefix;
Pier Ventree0ae7a32016-11-23 09:57:42 -080023import org.onlab.packet.Ip6Address;
Pier Ventre10bd8d12016-11-26 21:05:22 -080024import org.onlab.packet.Ip6Prefix;
Charles Chan03a73e02016-10-24 14:52:01 -070025import org.onlab.packet.IpAddress;
Charles Chan5270ed02016-01-30 23:22:37 -080026import org.onlab.packet.IpPrefix;
sanghob35a6192015-04-01 13:05:26 -070027import org.onlab.packet.MacAddress;
Charles Chane849c192016-01-11 18:28:54 -080028import org.onlab.packet.VlanId;
Charles Chan4636be02015-10-07 14:21:45 -070029import org.onosproject.incubator.net.config.basics.ConfigException;
30import org.onosproject.incubator.net.config.basics.InterfaceConfig;
31import org.onosproject.incubator.net.intf.Interface;
32import org.onosproject.net.ConnectPoint;
Charles Chan4636be02015-10-07 14:21:45 -070033import org.onosproject.net.host.InterfaceIpAddress;
sanghob35a6192015-04-01 13:05:26 -070034import org.onosproject.net.DeviceId;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070035import org.onosproject.net.PortNumber;
Charles Chan2c15aca2016-11-09 20:51:44 -080036import org.onosproject.segmentrouting.SegmentRoutingManager;
sanghob35a6192015-04-01 13:05:26 -070037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070040import java.util.ArrayList;
Pier Ventre10bd8d12016-11-26 21:05:22 -080041import java.util.Collections;
sanghob35a6192015-04-01 13:05:26 -070042import java.util.HashMap;
Charles Chan531a78b2015-12-01 10:00:51 -080043import java.util.HashSet;
sanghob35a6192015-04-01 13:05:26 -070044import java.util.List;
45import java.util.Map;
Charles Chand6832882015-10-05 17:50:33 -070046import java.util.Set;
Saurav Das0e99e2b2015-10-28 12:39:42 -070047import java.util.concurrent.ConcurrentHashMap;
Charles Chan2c15aca2016-11-09 20:51:44 -080048import java.util.stream.Collectors;
sanghob35a6192015-04-01 13:05:26 -070049
Charles Chan93e71ba2016-04-29 14:38:22 -070050import static com.google.common.base.Preconditions.checkNotNull;
51
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070052/**
53 * Segment Routing configuration component that reads the
54 * segment routing related configuration from Network Configuration Manager
55 * component and organizes in more accessible formats.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070056 */
sanghob35a6192015-04-01 13:05:26 -070057public class DeviceConfiguration implements DeviceProperties {
58
Charles Chan2c15aca2016-11-09 20:51:44 -080059 private static final String ERROR_CONFIG = "Configuration error.";
60 private static final String TOO_MANY_SUBNET = ERROR_CONFIG + " Too many subnets configured on {}";
61 private static final String NO_SUBNET = "No subnet configured on {}";
Pier Ventre10bd8d12016-11-26 21:05:22 -080062 private static final String MISCONFIGURED = "Subnets are not configured correctly for {}";
Charles Chan2c15aca2016-11-09 20:51:44 -080063
Charles Chanf2565a92016-02-10 20:46:58 -080064 private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -070065 private final List<Integer> allSegmentIds = new ArrayList<>();
Charles Chane849c192016-01-11 18:28:54 -080066 private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
Charles Chan2c15aca2016-11-09 20:51:44 -080067 private SegmentRoutingManager srManager;
sanghob35a6192015-04-01 13:05:26 -070068
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070069 private class SegmentRouterInfo {
Pier Ventree0ae7a32016-11-23 09:57:42 -080070 int ipv4NodeSid;
71 int ipv6NodeSid;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070072 DeviceId deviceId;
Pier Ventree0ae7a32016-11-23 09:57:42 -080073 Ip4Address ipv4Loopback;
74 Ip6Address ipv6Loopback;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070075 MacAddress mac;
76 boolean isEdge;
Pier Ventre10bd8d12016-11-26 21:05:22 -080077 SetMultimap<PortNumber, IpAddress> gatewayIps;
78 SetMultimap<PortNumber, IpPrefix> subnets;
Charles Chan531a78b2015-12-01 10:00:51 -080079 Map<Integer, Set<Integer>> adjacencySids;
Charles Chanb8e10c82015-10-14 11:24:40 -070080
81 public SegmentRouterInfo() {
Pier Ventre10bd8d12016-11-26 21:05:22 -080082 gatewayIps = HashMultimap.create();
Charles Chan5270ed02016-01-30 23:22:37 -080083 subnets = HashMultimap.create();
Charles Chanb8e10c82015-10-14 11:24:40 -070084 }
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070085 }
sanghob35a6192015-04-01 13:05:26 -070086
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070087 /**
Charles Chane849c192016-01-11 18:28:54 -080088 * Constructs device configuration for all Segment Router devices,
89 * organizing the data into various maps for easier access.
Brian O'Connor52515622015-10-09 17:03:44 -070090 *
Charles Chan2c15aca2016-11-09 20:51:44 -080091 * @param srManager Segment Routing Manager
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070092 */
Charles Chan2c15aca2016-11-09 20:51:44 -080093 public DeviceConfiguration(SegmentRoutingManager srManager) {
94 this.srManager = srManager;
Charles Chand9681e72016-02-22 19:27:29 -080095
Charles Chan4636be02015-10-07 14:21:45 -070096 // Read config from device subject, excluding gatewayIps and subnets.
97 Set<DeviceId> deviceSubjects =
Charles Chan2c15aca2016-11-09 20:51:44 -080098 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chan4636be02015-10-07 14:21:45 -070099 deviceSubjects.forEach(subject -> {
Charles Chan5270ed02016-01-30 23:22:37 -0800100 SegmentRoutingDeviceConfig config =
Charles Chan2c15aca2016-11-09 20:51:44 -0800101 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700102 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chand6832882015-10-05 17:50:33 -0700103 info.deviceId = subject;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800104 info.ipv4NodeSid = config.nodeSidIPv4();
105 info.ipv6NodeSid = config.nodeSidIPv6();
106 info.ipv4Loopback = config.routerIpv4();
107 info.ipv6Loopback = config.routerIpv6();
Charles Chan531a78b2015-12-01 10:00:51 -0800108 info.mac = config.routerMac();
Charles Chand6832882015-10-05 17:50:33 -0700109 info.isEdge = config.isEdgeRouter();
Charles Chan531a78b2015-12-01 10:00:51 -0800110 info.adjacencySids = config.adjacencySids();
Charles Chane849c192016-01-11 18:28:54 -0800111 deviceConfigMap.put(info.deviceId, info);
Saurav Das59232cf2016-04-27 18:35:50 -0700112 log.info("Read device config for device: {}", info.deviceId);
Pier Ventree0ae7a32016-11-23 09:57:42 -0800113 /*
114 * IPv6 sid is not inserted. this part of the code is not used for now.
115 */
116 allSegmentIds.add(info.ipv4NodeSid);
Charles Chand6832882015-10-05 17:50:33 -0700117 });
Charles Chan4636be02015-10-07 14:21:45 -0700118
Charles Chan2c15aca2016-11-09 20:51:44 -0800119 // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
120 Set<ConnectPoint> portSubjects = srManager.cfgService
121 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
122 portSubjects.stream().filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chan4636be02015-10-07 14:21:45 -0700123 InterfaceConfig config =
Charles Chan2c15aca2016-11-09 20:51:44 -0800124 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chan4636be02015-10-07 14:21:45 -0700125 Set<Interface> networkInterfaces;
126 try {
127 networkInterfaces = config.getInterfaces();
128 } catch (ConfigException e) {
129 log.error("Error loading port configuration");
130 return;
131 }
132 networkInterfaces.forEach(networkInterface -> {
Charles Chane849c192016-01-11 18:28:54 -0800133 VlanId vlanId = networkInterface.vlan();
134 ConnectPoint connectPoint = networkInterface.connectPoint();
135 DeviceId dpid = connectPoint.deviceId();
136 PortNumber port = connectPoint.port();
137 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chan4636be02015-10-07 14:21:45 -0700138
Charles Chanb8e10c82015-10-14 11:24:40 -0700139 // skip if there is no corresponding device for this ConenctPoint
140 if (info != null) {
Charles Chane849c192016-01-11 18:28:54 -0800141 // Extract subnet information
Jonathan Hart00cddda2016-02-16 10:30:37 -0800142 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chanb8e10c82015-10-14 11:24:40 -0700143 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800144 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan5270ed02016-01-30 23:22:37 -0800145 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventre10bd8d12016-11-26 21:05:22 -0800146 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
147 if (ipPrefix.isIp4()) {
148 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
149 info.gatewayIps.put(port, interfaceAddress.ipAddress());
150 }
151 info.subnets.put(port, interfaceAddress.subnetAddress());
152 } else {
153 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
154 info.gatewayIps.put(port, interfaceAddress.ipAddress());
155 }
156 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan5270ed02016-01-30 23:22:37 -0800157 }
Charles Chanb8e10c82015-10-14 11:24:40 -0700158 });
159 }
Charles Chan4636be02015-10-07 14:21:45 -0700160 });
Pier Luigi0e358632017-01-31 09:35:05 -0800161 // We register the connect point with the NRS.
Pier Ventre10bd8d12016-11-26 21:05:22 -0800162 srManager.registerConnectPoint(subject);
Charles Chan4636be02015-10-07 14:21:45 -0700163 });
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700164 }
165
sanghob35a6192015-04-01 13:05:26 -0700166 @Override
Charles Chan0b4e6182015-11-03 10:42:14 -0800167 public boolean isConfigured(DeviceId deviceId) {
168 return deviceConfigMap.get(deviceId) != null;
169 }
170
171 @Override
Pier Ventree0ae7a32016-11-23 09:57:42 -0800172 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700173 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
174 if (srinfo != null) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800175 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
176 return srinfo.ipv4NodeSid;
sanghob35a6192015-04-01 13:05:26 -0700177 } else {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800178 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
179 throw new DeviceConfigNotFoundException(message);
180 }
181 }
182
183 @Override
184 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
185 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
186 if (srinfo != null) {
187 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
188 return srinfo.ipv6NodeSid;
189 } else {
190 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan0b4e6182015-11-03 10:42:14 -0800191 throw new DeviceConfigNotFoundException(message);
sanghob35a6192015-04-01 13:05:26 -0700192 }
193 }
194
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700195 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800196 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700197 *
198 * @param routerMac router mac address
Saurav Das0e99e2b2015-10-28 12:39:42 -0700199 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700200 */
Pier Ventree0ae7a32016-11-23 09:57:42 -0800201 public int getIPv4SegmentId(MacAddress routerMac) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700202 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
203 deviceConfigMap.entrySet()) {
204 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800205 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700206 }
207 }
sanghob35a6192015-04-01 13:05:26 -0700208
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700209 return -1;
210 }
211
212 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800213 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
214 *
215 * @param routerMac router mac address
216 * @return node segment id, or -1 if not found in config
217 */
218 public int getIPv6SegmentId(MacAddress routerMac) {
219 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
220 deviceConfigMap.entrySet()) {
221 if (entry.getValue().mac.equals(routerMac)) {
222 return entry.getValue().ipv6NodeSid;
223 }
224 }
225
226 return -1;
227 }
228
229 /**
230 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700231 *
232 * @param routerAddress router ip address
Saurav Das0e99e2b2015-10-28 12:39:42 -0700233 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700234 */
Pier Ventree0ae7a32016-11-23 09:57:42 -0800235 public int getIPv4SegmentId(Ip4Address routerAddress) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700236 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
237 deviceConfigMap.entrySet()) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800238 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
239 return entry.getValue().ipv4NodeSid;
240 }
241 }
242
243 return -1;
244 }
245
246 /**
247 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
248 *
249 * @param routerAddress router ip address
250 * @return node segment id, or -1 if not found in config
251 */
252 public int getIPv6SegmentId(Ip6Address routerAddress) {
253 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
254 deviceConfigMap.entrySet()) {
255 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
256 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700257 }
258 }
259
260 return -1;
261 }
262
sanghob35a6192015-04-01 13:05:26 -0700263 @Override
Charles Chan0b4e6182015-11-03 10:42:14 -0800264 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700265 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
266 if (srinfo != null) {
267 log.trace("getDeviceMac for device{} is {}", deviceId, srinfo.mac);
268 return srinfo.mac;
sanghob35a6192015-04-01 13:05:26 -0700269 } else {
Charles Chan0b4e6182015-11-03 10:42:14 -0800270 String message = "getDeviceMac fails for device: " + deviceId + ".";
271 throw new DeviceConfigNotFoundException(message);
sanghob35a6192015-04-01 13:05:26 -0700272 }
273 }
274
Charles Chan0b4e6182015-11-03 10:42:14 -0800275 @Override
Pier Ventree0ae7a32016-11-23 09:57:42 -0800276 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700277 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
278 if (srinfo != null) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800279 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
280 return srinfo.ipv4Loopback;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700281 } else {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800282 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
283 throw new DeviceConfigNotFoundException(message);
284 }
285 }
286
287 @Override
288 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
289 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
290 if (srinfo != null) {
291 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
292 return srinfo.ipv6Loopback;
293 } else {
294 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan0b4e6182015-11-03 10:42:14 -0800295 throw new DeviceConfigNotFoundException(message);
sanghob35a6192015-04-01 13:05:26 -0700296 }
sanghob35a6192015-04-01 13:05:26 -0700297 }
298
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700299 @Override
Charles Chan0b4e6182015-11-03 10:42:14 -0800300 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700301 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
302 if (srinfo != null) {
303 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
304 return srinfo.isEdge;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700305 } else {
Charles Chan0b4e6182015-11-03 10:42:14 -0800306 String message = "isEdgeDevice fails for device: " + deviceId + ".";
307 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700308 }
309 }
310
sanghob35a6192015-04-01 13:05:26 -0700311 @Override
312 public List<Integer> getAllDeviceSegmentIds() {
313 return allSegmentIds;
314 }
315
Charles Chanc42e84e2015-10-20 16:24:19 -0700316 @Override
Pier Ventre10bd8d12016-11-26 21:05:22 -0800317 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das7a1ffca2016-03-28 19:00:18 -0700318 throws DeviceConfigNotFoundException {
319 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
320 if (srinfo == null) {
321 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
322 throw new DeviceConfigNotFoundException(message);
323 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700324 // Construct subnet-port mapping from port-subnet mapping
Pier Ventre10bd8d12016-11-26 21:05:22 -0800325 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
326 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan5270ed02016-01-30 23:22:37 -0800327
328 portSubnetMap.entries().forEach(entry -> {
329 PortNumber port = entry.getKey();
Pier Ventre10bd8d12016-11-26 21:05:22 -0800330 IpPrefix subnet = entry.getValue();
Charles Chan5270ed02016-01-30 23:22:37 -0800331
Pier Ventre10bd8d12016-11-26 21:05:22 -0800332 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
333 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chand0fd5dc2016-02-16 23:14:49 -0800334 return;
335 }
336
Charles Chanc42e84e2015-10-20 16:24:19 -0700337 if (subnetPortMap.containsKey(subnet)) {
338 subnetPortMap.get(subnet).add(port);
339 } else {
340 ArrayList<PortNumber> ports = new ArrayList<>();
341 ports.add(port);
342 subnetPortMap.put(subnet, ports);
343 }
344 });
Charles Chanc42e84e2015-10-20 16:24:19 -0700345 return subnetPortMap;
346 }
347
sanghob35a6192015-04-01 13:05:26 -0700348 /**
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700349 * Returns the device identifier or data plane identifier (dpid)
350 * of a segment router given its segment id.
sanghob35a6192015-04-01 13:05:26 -0700351 *
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700352 * @param sid segment id
353 * @return deviceId device identifier
sanghob35a6192015-04-01 13:05:26 -0700354 */
355 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700356 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
357 deviceConfigMap.entrySet()) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800358 if (entry.getValue().ipv4NodeSid == sid ||
359 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700360 return entry.getValue().deviceId;
sanghob35a6192015-04-01 13:05:26 -0700361 }
362 }
363
364 return null;
365 }
366
367 /**
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700368 * Returns the device identifier or data plane identifier (dpid)
369 * of a segment router given its router ip address.
sanghob35a6192015-04-01 13:05:26 -0700370 *
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700371 * @param ipAddress router ip address
372 * @return deviceId device identifier
sanghob35a6192015-04-01 13:05:26 -0700373 */
374 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700375 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
376 deviceConfigMap.entrySet()) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800377 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
378 return entry.getValue().deviceId;
379 }
380 }
381
382 return null;
383 }
384
385 /**
386 * Returns the device identifier or data plane identifier (dpid)
387 * of a segment router given its router ipv6 address.
388 *
389 * @param ipAddress router ipv6 address
390 * @return deviceId device identifier
391 */
392 public DeviceId getDeviceId(Ip6Address ipAddress) {
393 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
394 deviceConfigMap.entrySet()) {
395 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700396 return entry.getValue().deviceId;
sanghob35a6192015-04-01 13:05:26 -0700397 }
398 }
399
400 return null;
401 }
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700402
403 /**
Saurav Das822c4e22015-10-23 10:51:11 -0700404 * Returns the configured port ip addresses for a segment router.
405 * These addresses serve as gateway IP addresses for the subnets configured
406 * on those ports.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700407 *
408 * @param deviceId device identifier
Saurav Das837e0bb2015-10-30 17:45:38 -0700409 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700410 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800411 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700412 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
413 if (srinfo != null) {
414 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
415 srinfo.gatewayIps.values());
Saurav Das837e0bb2015-10-30 17:45:38 -0700416 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700417 }
Saurav Das0e99e2b2015-10-28 12:39:42 -0700418 return null;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700419 }
420
421 /**
422 * Returns the configured subnet prefixes for a segment router.
423 *
424 * @param deviceId device identifier
Saurav Das0e99e2b2015-10-28 12:39:42 -0700425 * @return list of ip prefixes or null if not found
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700426 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800427 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700428 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
429 if (srinfo != null) {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800430 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chan03a73e02016-10-24 14:52:01 -0700431 return builder.addAll(srinfo.subnets.values()).build();
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700432 }
Saurav Das0e99e2b2015-10-28 12:39:42 -0700433 return null;
434 }
435
Charles Chan2c15aca2016-11-09 20:51:44 -0800436
Saurav Das0e99e2b2015-10-28 12:39:42 -0700437 /**
Charles Chan2c15aca2016-11-09 20:51:44 -0800438 * Returns the subnet configuration of given device and port.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700439 *
Charles Chan2c15aca2016-11-09 20:51:44 -0800440 * @param deviceId Device ID
441 * @param port Port number
Pier Ventre10bd8d12016-11-26 21:05:22 -0800442 * @return The subnets configured on given port or empty set if
Charles Chan2c15aca2016-11-09 20:51:44 -0800443 * the port is unconfigured, misconfigured or suppressed.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700444 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800445 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan2c15aca2016-11-09 20:51:44 -0800446 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
447
448 if (isSuppressedPort(connectPoint)) {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800449 return Collections.emptySet();
Saurav Das0e99e2b2015-10-28 12:39:42 -0700450 }
Charles Chan2c15aca2016-11-09 20:51:44 -0800451
Pier Ventre10bd8d12016-11-26 21:05:22 -0800452 Set<IpPrefix> subnets =
Charles Chan2c15aca2016-11-09 20:51:44 -0800453 srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
454 .flatMap(intf -> intf.ipAddressesList().stream())
455 .map(InterfaceIpAddress::subnetAddress)
Charles Chan2c15aca2016-11-09 20:51:44 -0800456 .collect(Collectors.toSet());
457
Jon Hallcbd1b392017-01-18 20:15:44 -0800458 if (subnets.isEmpty()) {
Charles Chan2c15aca2016-11-09 20:51:44 -0800459 log.info(NO_SUBNET, connectPoint);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800460 return Collections.emptySet();
461 } else if (subnets.size() > 2) {
Charles Chan2c15aca2016-11-09 20:51:44 -0800462 log.warn(TOO_MANY_SUBNET, connectPoint);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800463 return Collections.emptySet();
464 } else if (verifySubnets(subnets)) {
465 return subnets;
Charles Chan2c15aca2016-11-09 20:51:44 -0800466 }
Pier Ventre10bd8d12016-11-26 21:05:22 -0800467 log.warn(MISCONFIGURED, connectPoint);
468 return Collections.emptySet();
469 }
470
471 /**
472 * Returns the IPv4 subnet configured of given device and port.
473 *
474 * @param deviceId Device ID
475 * @param port Port number
476 * @return The IPv4 subnet configured on given port or null if
477 * the port is unconfigured, misconfigured or suppressed.
478 */
479 public Ip4Prefix getPortIPv4Subnet(DeviceId deviceId, PortNumber port) {
480 return getPortSubnets(deviceId, port).stream()
481 .filter(IpPrefix::isIp4)
482 .map(IpPrefix::getIp4Prefix)
483 .findFirst().orElse(null);
484 }
485
486 /**
487 * Returns the IPv6 subnet configured of given device and port.
488 *
489 * @param deviceId Device ID
490 * @param port Port number
491 * @return The IPV6 subnet configured on given port or null if
492 * the port is unconfigured, misconfigured or suppressed.
493 */
494 public Ip6Prefix getPortIPv6Subnet(DeviceId deviceId, PortNumber port) {
495 return getPortSubnets(deviceId, port).stream()
496 .filter(IpPrefix::isIp6)
497 .map(IpPrefix::getIp6Prefix)
498 .findFirst().orElse(null);
499 }
500
501 /**
502 * Utility to verify the configuration of a given port.
503 *
504 * @param subnets the subnets set to verify
505 * @return true if the configured subnets are ok. False otherwise.
506 */
507 private boolean verifySubnets(Set<IpPrefix> subnets) {
508 Set<Ip4Prefix> ip4Prefices = subnets.stream()
509 .filter(IpPrefix::isIp4)
510 .map(IpPrefix::getIp4Prefix)
511 .collect(Collectors.toSet());
512 if (ip4Prefices.size() > 1) {
513 return false;
514 }
515 Set<Ip6Prefix> ip6Prefices = subnets.stream()
516 .filter(IpPrefix::isIp6)
517 .map(IpPrefix::getIp6Prefix)
518 .collect(Collectors.toSet());
519 if (ip6Prefices.size() > 1) {
520 return false;
521 }
522 return !(ip4Prefices.isEmpty() && ip6Prefices.isEmpty());
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700523 }
524
525 /**
526 * Returns the router ip address of segment router that has the
527 * specified ip address in its subnets.
528 *
529 * @param destIpAddress target ip address
530 * @return router ip address
531 */
532 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan68aaad52016-12-09 12:54:49 -0800533 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
534
535 if (matchIntf == null) {
536 log.debug("No router was found for {}", destIpAddress);
537 return null;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700538 }
539
Charles Chan68aaad52016-12-09 12:54:49 -0800540 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
541 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
542 if (srInfo == null) {
543 log.debug("No device config was found for {}", routerDeviceId);
544 return null;
545 }
546
Pier Ventree0ae7a32016-11-23 09:57:42 -0800547 return srInfo.ipv4Loopback;
548 }
549
550 /**
551 * Returns the router ipv6 address of segment router that has the
552 * specified ip address in its subnets.
553 *
554 * @param destIpAddress target ip address
555 * @return router ip address
556 */
557 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
558 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
559
560 if (matchIntf == null) {
561 log.debug("No router was found for {}", destIpAddress);
562 return null;
563 }
564
565 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
566 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
567 if (srInfo == null) {
568 log.debug("No device config was found for {}", routerDeviceId);
569 return null;
570 }
571
572 return srInfo.ipv6Loopback;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700573 }
574
575 /**
576 * Returns the router mac address of segment router that has the
577 * specified ip address as one of its subnet gateway ip address.
578 *
579 * @param gatewayIpAddress router gateway ip address
Saurav Das0e99e2b2015-10-28 12:39:42 -0700580 * @return router mac address or null if not found
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700581 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800582 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700583 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
584 deviceConfigMap.entrySet()) {
585 if (entry.getValue().gatewayIps.
586 values().contains(gatewayIpAddress)) {
587 return entry.getValue().mac;
588 }
589 }
590
591 log.debug("Cannot find a router for {}", gatewayIpAddress);
592 return null;
593 }
sangho666cd6d2015-04-14 16:27:13 -0700594
sangho666cd6d2015-04-14 16:27:13 -0700595 /**
596 * Checks if the host is in the subnet defined in the router with the
597 * device ID given.
598 *
599 * @param deviceId device identification of the router
600 * @param hostIp host IP address to check
601 * @return true if the host is within the subnet of the router,
602 * false if no subnet is defined under the router or if the host is not
603 * within the subnet defined in the router
604 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800605 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
sangho666cd6d2015-04-14 16:27:13 -0700606
Pier Ventre10bd8d12016-11-26 21:05:22 -0800607 Set<IpPrefix> subnets = getSubnets(deviceId);
sangho666cd6d2015-04-14 16:27:13 -0700608 if (subnets == null) {
609 return false;
610 }
611
Pier Ventre10bd8d12016-11-26 21:05:22 -0800612 for (IpPrefix subnet: subnets) {
Charles Chan5270ed02016-01-30 23:22:37 -0800613 // Exclude /0 since it is a special case used for default route
614 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho666cd6d2015-04-14 16:27:13 -0700615 return true;
616 }
617 }
618
619 return false;
620 }
sangho1e575652015-05-14 00:39:53 -0700621
622 /**
Charles Chan03a73e02016-10-24 14:52:01 -0700623 * Checks if the IP is in the subnet defined on given connect point.
624 *
625 * @param connectPoint Connect point
626 * @param ip The IP address to check
627 * @return True if the IP belongs to the subnet.
628 * False if the IP does not belong to the subnet, or
629 * there is no subnet configuration on given connect point.
630 */
631 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800632 Ip4Prefix ipv4Subnet = getPortIPv4Subnet(connectPoint.deviceId(), connectPoint.port());
633 Ip6Prefix ipv6Subnet = getPortIPv6Subnet(connectPoint.deviceId(), connectPoint.port());
634 return (ipv4Subnet != null && ipv4Subnet.contains(ip)) ||
635 (ipv6Subnet != null && ipv6Subnet.contains(ip));
Charles Chan03a73e02016-10-24 14:52:01 -0700636 }
637
638 /**
sangho1e575652015-05-14 00:39:53 -0700639 * Returns the ports corresponding to the adjacency Sid given.
640 *
641 * @param deviceId device identification of the router
642 * @param sid adjacency Sid
Charles Chan531a78b2015-12-01 10:00:51 -0800643 * @return set of port numbers
sangho1e575652015-05-14 00:39:53 -0700644 */
Charles Chan531a78b2015-12-01 10:00:51 -0800645 public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700646 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan531a78b2015-12-01 10:00:51 -0800647 return srinfo != null ?
648 ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
649 ImmutableSet.copyOf(new HashSet<>());
sangho1e575652015-05-14 00:39:53 -0700650 }
651
652 /**
653 * Check if the Sid given is whether adjacency Sid of the router device or not.
654 *
655 * @param deviceId device identification of the router
656 * @param sid Sid to check
657 * @return true if the Sid given is the adjacency Sid of the device,
658 * otherwise false
659 */
660 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700661 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan531a78b2015-12-01 10:00:51 -0800662 return srinfo != null && srinfo.adjacencySids.containsKey(sid);
sangho1e575652015-05-14 00:39:53 -0700663 }
Charles Chanf2565a92016-02-10 20:46:58 -0800664
Charles Chand55e84d2016-03-30 17:54:24 -0700665 /**
Charles Chan93e71ba2016-04-29 14:38:22 -0700666 * Add subnet to specific connect point.
667 *
668 * @param cp connect point
Pier Ventre10bd8d12016-11-26 21:05:22 -0800669 * @param ipPrefix subnet being added to the device
Charles Chan93e71ba2016-04-29 14:38:22 -0700670 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800671 public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chan93e71ba2016-04-29 14:38:22 -0700672 checkNotNull(cp);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800673 checkNotNull(ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700674 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
675 if (srinfo == null) {
676 log.warn("Device {} is not configured. Abort.", cp.deviceId());
677 return;
678 }
Pier Ventre10bd8d12016-11-26 21:05:22 -0800679 srinfo.subnets.put(cp.port(), ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700680 }
681
682 /**
683 * Remove subnet from specific connect point.
684 *
685 * @param cp connect point
Pier Ventre10bd8d12016-11-26 21:05:22 -0800686 * @param ipPrefix subnet being removed to the device
Charles Chan93e71ba2016-04-29 14:38:22 -0700687 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800688 public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chan93e71ba2016-04-29 14:38:22 -0700689 checkNotNull(cp);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800690 checkNotNull(ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700691 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
692 if (srinfo == null) {
693 log.warn("Device {} is not configured. Abort.", cp.deviceId());
694 return;
695 }
Pier Ventre10bd8d12016-11-26 21:05:22 -0800696 srinfo.subnets.remove(cp.port(), ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700697 }
Charles Chan2c15aca2016-11-09 20:51:44 -0800698
699 private boolean isSuppressedPort(ConnectPoint connectPoint) {
700 SegmentRoutingAppConfig appConfig = srManager.cfgService
701 .getConfig(srManager.appId, SegmentRoutingAppConfig.class);
702 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chan03a73e02016-10-24 14:52:01 -0700703 log.info("Interface configuration on port {} is ignored", connectPoint);
Charles Chan2c15aca2016-11-09 20:51:44 -0800704 return true;
705 }
706 return false;
707 }
Jonathan Hart00cddda2016-02-16 10:30:37 -0800708}