blob: 18169bba332a8600a6ebb7bc8e6901c5ad0a8b29 [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 Chan82fac582017-09-12 12:09:22 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
Charles Chan5270ed02016-01-30 23:22:37 -080021import com.google.common.collect.HashMultimap;
Charles Chan9f676b62015-10-29 14:58:10 -070022import com.google.common.collect.ImmutableSet;
Charles Chan5270ed02016-01-30 23:22:37 -080023import com.google.common.collect.SetMultimap;
sanghob35a6192015-04-01 13:05:26 -070024import org.onlab.packet.Ip4Address;
Pier Ventree0ae7a32016-11-23 09:57:42 -080025import org.onlab.packet.Ip6Address;
Charles Chan03a73e02016-10-24 14:52:01 -070026import org.onlab.packet.IpAddress;
Charles Chan5270ed02016-01-30 23:22:37 -080027import org.onlab.packet.IpPrefix;
sanghob35a6192015-04-01 13:05:26 -070028import org.onlab.packet.MacAddress;
Charles Chane849c192016-01-11 18:28:54 -080029import org.onlab.packet.VlanId;
Ray Milkey6c013742017-08-15 10:16:43 -070030import org.onosproject.net.config.ConfigException;
31import org.onosproject.net.config.basics.InterfaceConfig;
Ray Milkeyfacf2862017-08-03 11:58:29 -070032import org.onosproject.net.intf.Interface;
Charles Chan4636be02015-10-07 14:21:45 -070033import org.onosproject.net.ConnectPoint;
Charles Chan4636be02015-10-07 14:21:45 -070034import org.onosproject.net.host.InterfaceIpAddress;
sanghob35a6192015-04-01 13:05:26 -070035import org.onosproject.net.DeviceId;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070036import org.onosproject.net.PortNumber;
Charles Chan2c15aca2016-11-09 20:51:44 -080037import org.onosproject.segmentrouting.SegmentRoutingManager;
sanghob35a6192015-04-01 13:05:26 -070038import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070041import java.util.ArrayList;
Pier Ventre10bd8d12016-11-26 21:05:22 -080042import java.util.Collections;
sanghob35a6192015-04-01 13:05:26 -070043import java.util.HashMap;
Charles Chan531a78b2015-12-01 10:00:51 -080044import java.util.HashSet;
sanghob35a6192015-04-01 13:05:26 -070045import java.util.List;
46import java.util.Map;
Charles Chand6832882015-10-05 17:50:33 -070047import java.util.Set;
Saurav Das0e99e2b2015-10-28 12:39:42 -070048import java.util.concurrent.ConcurrentHashMap;
Charles Chan2c15aca2016-11-09 20:51:44 -080049import java.util.stream.Collectors;
sanghob35a6192015-04-01 13:05:26 -070050
Charles Chan93e71ba2016-04-29 14:38:22 -070051import static com.google.common.base.Preconditions.checkNotNull;
52
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070053/**
54 * Segment Routing configuration component that reads the
55 * segment routing related configuration from Network Configuration Manager
56 * component and organizes in more accessible formats.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070057 */
sanghob35a6192015-04-01 13:05:26 -070058public class DeviceConfiguration implements DeviceProperties {
59
Charles Chan2c15aca2016-11-09 20:51:44 -080060 private static final String NO_SUBNET = "No subnet configured on {}";
61
Charles Chanf2565a92016-02-10 20:46:58 -080062 private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
Sho SHIMIZU6cfc02d2015-09-11 11:19:11 -070063 private final List<Integer> allSegmentIds = new ArrayList<>();
Charles Chane849c192016-01-11 18:28:54 -080064 private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
Charles Chan2c15aca2016-11-09 20:51:44 -080065 private SegmentRoutingManager srManager;
sanghob35a6192015-04-01 13:05:26 -070066
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070067 private class SegmentRouterInfo {
Pier Ventree0ae7a32016-11-23 09:57:42 -080068 int ipv4NodeSid;
69 int ipv6NodeSid;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070070 DeviceId deviceId;
Pier Ventree0ae7a32016-11-23 09:57:42 -080071 Ip4Address ipv4Loopback;
72 Ip6Address ipv6Loopback;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070073 MacAddress mac;
74 boolean isEdge;
Pier Ventre10bd8d12016-11-26 21:05:22 -080075 SetMultimap<PortNumber, IpAddress> gatewayIps;
76 SetMultimap<PortNumber, IpPrefix> subnets;
Charles Chan531a78b2015-12-01 10:00:51 -080077 Map<Integer, Set<Integer>> adjacencySids;
Saurav Das7bcbe702017-06-13 15:35:54 -070078 DeviceId pairDeviceId;
79 PortNumber pairLocalPort;
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;
Saurav Das7bcbe702017-06-13 15:35:54 -070095 updateConfig();
96 }
Charles Chand9681e72016-02-22 19:27:29 -080097
Saurav Das7bcbe702017-06-13 15:35:54 -070098 public void updateConfig() {
Charles Chan4636be02015-10-07 14:21:45 -070099 // Read config from device subject, excluding gatewayIps and subnets.
100 Set<DeviceId> deviceSubjects =
Charles Chan2c15aca2016-11-09 20:51:44 -0800101 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chan4636be02015-10-07 14:21:45 -0700102 deviceSubjects.forEach(subject -> {
Charles Chan5270ed02016-01-30 23:22:37 -0800103 SegmentRoutingDeviceConfig config =
Charles Chan2c15aca2016-11-09 20:51:44 -0800104 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700105 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chand6832882015-10-05 17:50:33 -0700106 info.deviceId = subject;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800107 info.ipv4NodeSid = config.nodeSidIPv4();
108 info.ipv6NodeSid = config.nodeSidIPv6();
109 info.ipv4Loopback = config.routerIpv4();
110 info.ipv6Loopback = config.routerIpv6();
Charles Chan531a78b2015-12-01 10:00:51 -0800111 info.mac = config.routerMac();
Charles Chand6832882015-10-05 17:50:33 -0700112 info.isEdge = config.isEdgeRouter();
Charles Chan531a78b2015-12-01 10:00:51 -0800113 info.adjacencySids = config.adjacencySids();
Saurav Das7bcbe702017-06-13 15:35:54 -0700114 info.pairDeviceId = config.pairDeviceId();
115 info.pairLocalPort = config.pairLocalPort();
Charles Chane849c192016-01-11 18:28:54 -0800116 deviceConfigMap.put(info.deviceId, info);
Charles Chan278ce832017-06-26 15:25:09 -0700117 log.debug("Read device config for device: {}", info.deviceId);
Pier Ventree0ae7a32016-11-23 09:57:42 -0800118 /*
119 * IPv6 sid is not inserted. this part of the code is not used for now.
120 */
121 allSegmentIds.add(info.ipv4NodeSid);
Charles Chand6832882015-10-05 17:50:33 -0700122 });
Charles Chan4636be02015-10-07 14:21:45 -0700123
Charles Chan2c15aca2016-11-09 20:51:44 -0800124 // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
125 Set<ConnectPoint> portSubjects = srManager.cfgService
126 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
127 portSubjects.stream().filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chan4636be02015-10-07 14:21:45 -0700128 InterfaceConfig config =
Charles Chan2c15aca2016-11-09 20:51:44 -0800129 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chan4636be02015-10-07 14:21:45 -0700130 Set<Interface> networkInterfaces;
131 try {
132 networkInterfaces = config.getInterfaces();
133 } catch (ConfigException e) {
134 log.error("Error loading port configuration");
135 return;
136 }
137 networkInterfaces.forEach(networkInterface -> {
Charles Chane849c192016-01-11 18:28:54 -0800138 VlanId vlanId = networkInterface.vlan();
139 ConnectPoint connectPoint = networkInterface.connectPoint();
140 DeviceId dpid = connectPoint.deviceId();
141 PortNumber port = connectPoint.port();
Charles Chan82fac582017-09-12 12:09:22 -0700142 MacAddress mac = networkInterface.mac();
Charles Chane849c192016-01-11 18:28:54 -0800143 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chan4636be02015-10-07 14:21:45 -0700144
Charles Chanb8e10c82015-10-14 11:24:40 -0700145 // skip if there is no corresponding device for this ConenctPoint
146 if (info != null) {
Charles Chane849c192016-01-11 18:28:54 -0800147 // Extract subnet information
Jonathan Hart00cddda2016-02-16 10:30:37 -0800148 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chanb8e10c82015-10-14 11:24:40 -0700149 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800150 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan5270ed02016-01-30 23:22:37 -0800151 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventre10bd8d12016-11-26 21:05:22 -0800152 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
153 if (ipPrefix.isIp4()) {
154 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
155 info.gatewayIps.put(port, interfaceAddress.ipAddress());
156 }
157 info.subnets.put(port, interfaceAddress.subnetAddress());
158 } else {
159 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
160 info.gatewayIps.put(port, interfaceAddress.ipAddress());
161 }
162 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan5270ed02016-01-30 23:22:37 -0800163 }
Charles Chanb8e10c82015-10-14 11:24:40 -0700164 });
Charles Chan82fac582017-09-12 12:09:22 -0700165
166 // Override interface mac with router mac
167 if (!mac.equals(info.mac)) {
168 ArrayNode array = (ArrayNode) config.node();
169 for (JsonNode intfNode : array) {
170 ObjectNode objNode = (ObjectNode) intfNode;
171 objNode.put(InterfaceConfig.MAC, info.mac.toString());
172 }
173 srManager.cfgService.applyConfig(connectPoint, InterfaceConfig.class, array);
174 }
Charles Chanb8e10c82015-10-14 11:24:40 -0700175 }
Charles Chan4636be02015-10-07 14:21:45 -0700176 });
Pier Luigi0e358632017-01-31 09:35:05 -0800177 // We register the connect point with the NRS.
Pier Ventre10bd8d12016-11-26 21:05:22 -0800178 srManager.registerConnectPoint(subject);
Charles Chan4636be02015-10-07 14:21:45 -0700179 });
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700180 }
181
Saurav Das7bcbe702017-06-13 15:35:54 -0700182
sanghob35a6192015-04-01 13:05:26 -0700183 @Override
Charles Chan0b4e6182015-11-03 10:42:14 -0800184 public boolean isConfigured(DeviceId deviceId) {
185 return deviceConfigMap.get(deviceId) != null;
186 }
187
188 @Override
Pier Ventree0ae7a32016-11-23 09:57:42 -0800189 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700190 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
191 if (srinfo != null) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800192 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
193 return srinfo.ipv4NodeSid;
sanghob35a6192015-04-01 13:05:26 -0700194 } else {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800195 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
196 throw new DeviceConfigNotFoundException(message);
197 }
198 }
199
200 @Override
201 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
202 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
203 if (srinfo != null) {
204 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
205 return srinfo.ipv6NodeSid;
206 } else {
207 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan0b4e6182015-11-03 10:42:14 -0800208 throw new DeviceConfigNotFoundException(message);
sanghob35a6192015-04-01 13:05:26 -0700209 }
210 }
211
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700212 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800213 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700214 *
215 * @param routerMac router mac address
Saurav Das0e99e2b2015-10-28 12:39:42 -0700216 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700217 */
Pier Ventree0ae7a32016-11-23 09:57:42 -0800218 public int getIPv4SegmentId(MacAddress routerMac) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700219 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
220 deviceConfigMap.entrySet()) {
221 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800222 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700223 }
224 }
sanghob35a6192015-04-01 13:05:26 -0700225
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700226 return -1;
227 }
228
229 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800230 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
231 *
232 * @param routerMac router mac address
233 * @return node segment id, or -1 if not found in config
234 */
235 public int getIPv6SegmentId(MacAddress routerMac) {
236 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
237 deviceConfigMap.entrySet()) {
238 if (entry.getValue().mac.equals(routerMac)) {
239 return entry.getValue().ipv6NodeSid;
240 }
241 }
242
243 return -1;
244 }
245
246 /**
247 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700248 *
249 * @param routerAddress router ip address
Saurav Das0e99e2b2015-10-28 12:39:42 -0700250 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700251 */
Pier Ventree0ae7a32016-11-23 09:57:42 -0800252 public int getIPv4SegmentId(Ip4Address routerAddress) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700253 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
254 deviceConfigMap.entrySet()) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800255 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
256 return entry.getValue().ipv4NodeSid;
257 }
258 }
259
260 return -1;
261 }
262
263 /**
264 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
265 *
266 * @param routerAddress router ip address
267 * @return node segment id, or -1 if not found in config
268 */
269 public int getIPv6SegmentId(Ip6Address routerAddress) {
270 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
271 deviceConfigMap.entrySet()) {
272 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
273 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700274 }
275 }
276
277 return -1;
278 }
279
sanghob35a6192015-04-01 13:05:26 -0700280 @Override
Charles Chan0b4e6182015-11-03 10:42:14 -0800281 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700282 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
283 if (srinfo != null) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700284 return srinfo.mac;
sanghob35a6192015-04-01 13:05:26 -0700285 } else {
Charles Chan0b4e6182015-11-03 10:42:14 -0800286 String message = "getDeviceMac fails for device: " + deviceId + ".";
287 throw new DeviceConfigNotFoundException(message);
sanghob35a6192015-04-01 13:05:26 -0700288 }
289 }
290
Charles Chan0b4e6182015-11-03 10:42:14 -0800291 @Override
Pier Ventree0ae7a32016-11-23 09:57:42 -0800292 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700293 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
294 if (srinfo != null) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800295 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
296 return srinfo.ipv4Loopback;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700297 } else {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800298 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
299 throw new DeviceConfigNotFoundException(message);
300 }
301 }
302
303 @Override
304 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
305 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
306 if (srinfo != null) {
307 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
308 return srinfo.ipv6Loopback;
309 } else {
310 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan0b4e6182015-11-03 10:42:14 -0800311 throw new DeviceConfigNotFoundException(message);
sanghob35a6192015-04-01 13:05:26 -0700312 }
sanghob35a6192015-04-01 13:05:26 -0700313 }
314
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700315 @Override
Charles Chan0b4e6182015-11-03 10:42:14 -0800316 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700317 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
318 if (srinfo != null) {
319 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
320 return srinfo.isEdge;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700321 } else {
Charles Chan0b4e6182015-11-03 10:42:14 -0800322 String message = "isEdgeDevice fails for device: " + deviceId + ".";
323 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700324 }
325 }
326
sanghob35a6192015-04-01 13:05:26 -0700327 @Override
328 public List<Integer> getAllDeviceSegmentIds() {
329 return allSegmentIds;
330 }
331
Charles Chanc42e84e2015-10-20 16:24:19 -0700332 @Override
Pier Ventre10bd8d12016-11-26 21:05:22 -0800333 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das7a1ffca2016-03-28 19:00:18 -0700334 throws DeviceConfigNotFoundException {
335 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
336 if (srinfo == null) {
337 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
338 throw new DeviceConfigNotFoundException(message);
339 }
Charles Chanc42e84e2015-10-20 16:24:19 -0700340 // Construct subnet-port mapping from port-subnet mapping
Pier Ventre10bd8d12016-11-26 21:05:22 -0800341 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
342 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan5270ed02016-01-30 23:22:37 -0800343
344 portSubnetMap.entries().forEach(entry -> {
345 PortNumber port = entry.getKey();
Pier Ventre10bd8d12016-11-26 21:05:22 -0800346 IpPrefix subnet = entry.getValue();
Charles Chan5270ed02016-01-30 23:22:37 -0800347
Pier Ventre10bd8d12016-11-26 21:05:22 -0800348 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
349 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chand0fd5dc2016-02-16 23:14:49 -0800350 return;
351 }
352
Charles Chanc42e84e2015-10-20 16:24:19 -0700353 if (subnetPortMap.containsKey(subnet)) {
354 subnetPortMap.get(subnet).add(port);
355 } else {
356 ArrayList<PortNumber> ports = new ArrayList<>();
357 ports.add(port);
358 subnetPortMap.put(subnet, ports);
359 }
360 });
Charles Chanc42e84e2015-10-20 16:24:19 -0700361 return subnetPortMap;
362 }
363
sanghob35a6192015-04-01 13:05:26 -0700364 /**
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700365 * Returns the device identifier or data plane identifier (dpid)
366 * of a segment router given its segment id.
sanghob35a6192015-04-01 13:05:26 -0700367 *
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700368 * @param sid segment id
369 * @return deviceId device identifier
sanghob35a6192015-04-01 13:05:26 -0700370 */
371 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700372 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
373 deviceConfigMap.entrySet()) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800374 if (entry.getValue().ipv4NodeSid == sid ||
375 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700376 return entry.getValue().deviceId;
sanghob35a6192015-04-01 13:05:26 -0700377 }
378 }
379
380 return null;
381 }
382
383 /**
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700384 * Returns the device identifier or data plane identifier (dpid)
385 * of a segment router given its router ip address.
sanghob35a6192015-04-01 13:05:26 -0700386 *
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700387 * @param ipAddress router ip address
388 * @return deviceId device identifier
sanghob35a6192015-04-01 13:05:26 -0700389 */
390 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700391 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
392 deviceConfigMap.entrySet()) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800393 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
394 return entry.getValue().deviceId;
395 }
396 }
397
398 return null;
399 }
400
401 /**
402 * Returns the device identifier or data plane identifier (dpid)
403 * of a segment router given its router ipv6 address.
404 *
405 * @param ipAddress router ipv6 address
406 * @return deviceId device identifier
407 */
408 public DeviceId getDeviceId(Ip6Address ipAddress) {
409 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
410 deviceConfigMap.entrySet()) {
411 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700412 return entry.getValue().deviceId;
sanghob35a6192015-04-01 13:05:26 -0700413 }
414 }
415
416 return null;
417 }
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700418
419 /**
Saurav Das822c4e22015-10-23 10:51:11 -0700420 * Returns the configured port ip addresses for a segment router.
421 * These addresses serve as gateway IP addresses for the subnets configured
422 * on those ports.
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700423 *
424 * @param deviceId device identifier
Saurav Das837e0bb2015-10-30 17:45:38 -0700425 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700426 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800427 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700428 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
429 if (srinfo != null) {
430 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
431 srinfo.gatewayIps.values());
Saurav Das837e0bb2015-10-30 17:45:38 -0700432 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700433 }
Saurav Das0e99e2b2015-10-28 12:39:42 -0700434 return null;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700435 }
436
437 /**
438 * Returns the configured subnet prefixes for a segment router.
439 *
440 * @param deviceId device identifier
Saurav Das0e99e2b2015-10-28 12:39:42 -0700441 * @return list of ip prefixes or null if not found
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700442 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800443 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700444 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
445 if (srinfo != null) {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800446 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chan03a73e02016-10-24 14:52:01 -0700447 return builder.addAll(srinfo.subnets.values()).build();
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700448 }
Saurav Das0e99e2b2015-10-28 12:39:42 -0700449 return null;
450 }
451
Charles Chan2c15aca2016-11-09 20:51:44 -0800452
Saurav Das0e99e2b2015-10-28 12:39:42 -0700453 /**
Charles Chan2c15aca2016-11-09 20:51:44 -0800454 * Returns the subnet configuration of given device and port.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700455 *
Charles Chan2c15aca2016-11-09 20:51:44 -0800456 * @param deviceId Device ID
457 * @param port Port number
Pier Ventre10bd8d12016-11-26 21:05:22 -0800458 * @return The subnets configured on given port or empty set if
Charles Chanc53d6172017-04-24 16:21:01 -0700459 * the port is unconfigured or suppressed.
Saurav Das0e99e2b2015-10-28 12:39:42 -0700460 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800461 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan2c15aca2016-11-09 20:51:44 -0800462 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
463
464 if (isSuppressedPort(connectPoint)) {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800465 return Collections.emptySet();
Saurav Das0e99e2b2015-10-28 12:39:42 -0700466 }
Charles Chan2c15aca2016-11-09 20:51:44 -0800467
Pier Ventre10bd8d12016-11-26 21:05:22 -0800468 Set<IpPrefix> subnets =
Charles Chan2c15aca2016-11-09 20:51:44 -0800469 srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
470 .flatMap(intf -> intf.ipAddressesList().stream())
471 .map(InterfaceIpAddress::subnetAddress)
Charles Chan2c15aca2016-11-09 20:51:44 -0800472 .collect(Collectors.toSet());
473
Jon Hallcbd1b392017-01-18 20:15:44 -0800474 if (subnets.isEmpty()) {
Saurav Das018605f2017-02-18 14:05:44 -0800475 log.debug(NO_SUBNET, connectPoint);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800476 return Collections.emptySet();
Charles Chan2c15aca2016-11-09 20:51:44 -0800477 }
Charles Chanc53d6172017-04-24 16:21:01 -0700478
479 return subnets;
Pier Ventre10bd8d12016-11-26 21:05:22 -0800480 }
481
482 /**
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700483 * Returns the router ip address of segment router that has the
484 * specified ip address in its subnets.
485 *
486 * @param destIpAddress target ip address
487 * @return router ip address
488 */
489 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan68aaad52016-12-09 12:54:49 -0800490 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
491
492 if (matchIntf == null) {
493 log.debug("No router was found for {}", destIpAddress);
494 return null;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700495 }
496
Charles Chan68aaad52016-12-09 12:54:49 -0800497 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
498 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
499 if (srInfo == null) {
500 log.debug("No device config was found for {}", routerDeviceId);
501 return null;
502 }
503
Pier Ventree0ae7a32016-11-23 09:57:42 -0800504 return srInfo.ipv4Loopback;
505 }
506
507 /**
508 * Returns the router ipv6 address of segment router that has the
509 * specified ip address in its subnets.
510 *
511 * @param destIpAddress target ip address
512 * @return router ip address
513 */
514 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
515 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
516
517 if (matchIntf == null) {
518 log.debug("No router was found for {}", destIpAddress);
519 return null;
520 }
521
522 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
523 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
524 if (srInfo == null) {
525 log.debug("No device config was found for {}", routerDeviceId);
526 return null;
527 }
528
529 return srInfo.ipv6Loopback;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700530 }
531
532 /**
533 * Returns the router mac address of segment router that has the
534 * specified ip address as one of its subnet gateway ip address.
535 *
536 * @param gatewayIpAddress router gateway ip address
Saurav Das0e99e2b2015-10-28 12:39:42 -0700537 * @return router mac address or null if not found
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700538 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800539 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700540 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
541 deviceConfigMap.entrySet()) {
542 if (entry.getValue().gatewayIps.
543 values().contains(gatewayIpAddress)) {
544 return entry.getValue().mac;
545 }
546 }
547
548 log.debug("Cannot find a router for {}", gatewayIpAddress);
549 return null;
550 }
sangho666cd6d2015-04-14 16:27:13 -0700551
sangho666cd6d2015-04-14 16:27:13 -0700552 /**
Charles Chana9519af2017-06-26 18:30:18 -0700553 * Checks if the host IP is in any of the subnet defined in the router with the
sangho666cd6d2015-04-14 16:27:13 -0700554 * device ID given.
555 *
556 * @param deviceId device identification of the router
557 * @param hostIp host IP address to check
Charles Chana9519af2017-06-26 18:30:18 -0700558 * @return true if the given IP is within any of the subnet defined in the router,
559 * false if no subnet is defined in the router or if the host is not
560 * within any subnet defined in the router
sangho666cd6d2015-04-14 16:27:13 -0700561 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800562 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
sangho666cd6d2015-04-14 16:27:13 -0700563
Pier Ventre10bd8d12016-11-26 21:05:22 -0800564 Set<IpPrefix> subnets = getSubnets(deviceId);
sangho666cd6d2015-04-14 16:27:13 -0700565 if (subnets == null) {
566 return false;
567 }
568
Pier Ventre10bd8d12016-11-26 21:05:22 -0800569 for (IpPrefix subnet: subnets) {
Charles Chan5270ed02016-01-30 23:22:37 -0800570 // Exclude /0 since it is a special case used for default route
571 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho666cd6d2015-04-14 16:27:13 -0700572 return true;
573 }
574 }
575
576 return false;
577 }
sangho1e575652015-05-14 00:39:53 -0700578
579 /**
Charles Chan03a73e02016-10-24 14:52:01 -0700580 * Checks if the IP is in the subnet defined on given connect point.
581 *
582 * @param connectPoint Connect point
583 * @param ip The IP address to check
584 * @return True if the IP belongs to the subnet.
585 * False if the IP does not belong to the subnet, or
586 * there is no subnet configuration on given connect point.
587 */
588 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Charles Chana9519af2017-06-26 18:30:18 -0700589 return getPortSubnets(connectPoint.deviceId(), connectPoint.port()).stream()
590 .anyMatch(ipPrefix -> ipPrefix.contains(ip));
Charles Chan03a73e02016-10-24 14:52:01 -0700591 }
592
593 /**
sangho1e575652015-05-14 00:39:53 -0700594 * Returns the ports corresponding to the adjacency Sid given.
595 *
596 * @param deviceId device identification of the router
597 * @param sid adjacency Sid
Charles Chan531a78b2015-12-01 10:00:51 -0800598 * @return set of port numbers
sangho1e575652015-05-14 00:39:53 -0700599 */
Charles Chan531a78b2015-12-01 10:00:51 -0800600 public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700601 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan531a78b2015-12-01 10:00:51 -0800602 return srinfo != null ?
603 ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
604 ImmutableSet.copyOf(new HashSet<>());
sangho1e575652015-05-14 00:39:53 -0700605 }
606
607 /**
608 * Check if the Sid given is whether adjacency Sid of the router device or not.
609 *
610 * @param deviceId device identification of the router
611 * @param sid Sid to check
612 * @return true if the Sid given is the adjacency Sid of the device,
613 * otherwise false
614 */
615 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das0e99e2b2015-10-28 12:39:42 -0700616 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan531a78b2015-12-01 10:00:51 -0800617 return srinfo != null && srinfo.adjacencySids.containsKey(sid);
sangho1e575652015-05-14 00:39:53 -0700618 }
Charles Chanf2565a92016-02-10 20:46:58 -0800619
Charles Chand55e84d2016-03-30 17:54:24 -0700620 /**
Charles Chan93e71ba2016-04-29 14:38:22 -0700621 * Add subnet to specific connect point.
622 *
623 * @param cp connect point
Pier Ventre10bd8d12016-11-26 21:05:22 -0800624 * @param ipPrefix subnet being added to the device
Charles Chan93e71ba2016-04-29 14:38:22 -0700625 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800626 public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chan93e71ba2016-04-29 14:38:22 -0700627 checkNotNull(cp);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800628 checkNotNull(ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700629 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
630 if (srinfo == null) {
631 log.warn("Device {} is not configured. Abort.", cp.deviceId());
632 return;
633 }
Pier Ventre10bd8d12016-11-26 21:05:22 -0800634 srinfo.subnets.put(cp.port(), ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700635 }
636
637 /**
638 * Remove subnet from specific connect point.
639 *
640 * @param cp connect point
Pier Ventre10bd8d12016-11-26 21:05:22 -0800641 * @param ipPrefix subnet being removed to the device
Charles Chan93e71ba2016-04-29 14:38:22 -0700642 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800643 public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chan93e71ba2016-04-29 14:38:22 -0700644 checkNotNull(cp);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800645 checkNotNull(ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700646 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
647 if (srinfo == null) {
648 log.warn("Device {} is not configured. Abort.", cp.deviceId());
649 return;
650 }
Pier Ventre10bd8d12016-11-26 21:05:22 -0800651 srinfo.subnets.remove(cp.port(), ipPrefix);
Charles Chan93e71ba2016-04-29 14:38:22 -0700652 }
Charles Chan2c15aca2016-11-09 20:51:44 -0800653
654 private boolean isSuppressedPort(ConnectPoint connectPoint) {
655 SegmentRoutingAppConfig appConfig = srManager.cfgService
Ray Milkeye4afdb52017-04-05 09:42:04 -0700656 .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
Charles Chan2c15aca2016-11-09 20:51:44 -0800657 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chan03a73e02016-10-24 14:52:01 -0700658 log.info("Interface configuration on port {} is ignored", connectPoint);
Charles Chan2c15aca2016-11-09 20:51:44 -0800659 return true;
660 }
661 return false;
662 }
Saurav Das7bcbe702017-06-13 15:35:54 -0700663
664 public boolean isPairedEdge(DeviceId deviceId) throws DeviceConfigNotFoundException {
665 if (!isEdgeDevice(deviceId)) {
666 return false;
667 }
668 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
669 return (srinfo.pairDeviceId == null) ? false : true;
670 }
671
672 public DeviceId getPairDeviceId(DeviceId deviceId) throws DeviceConfigNotFoundException {
673 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
674 if (srinfo != null) {
675 return srinfo.pairDeviceId;
676 } else {
677 String message = "getPairDeviceId fails for device: " + deviceId + ".";
678 throw new DeviceConfigNotFoundException(message);
679 }
680 }
681
682 public PortNumber getPairLocalPort(DeviceId deviceId)
683 throws DeviceConfigNotFoundException {
684 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
685 if (srinfo != null) {
686 return srinfo.pairLocalPort;
687 } else {
688 String message = "getPairLocalPort fails for device: " + deviceId + ".";
689 throw new DeviceConfigNotFoundException(message);
690 }
691 }
692
Jonathan Hart00cddda2016-02-16 10:30:37 -0800693}