blob: 94f95f43f9dc293e46bfed5eb5f4c88ee16f5b1c [file] [log] [blame]
Thomas Vachuska8fd25052015-09-10 16:15:33 -07001/*
Brian O'Connor43b53542016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska8fd25052015-09-10 16:15:33 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Charles Chan319d1a22015-11-03 10:42:14 -080016package org.onosproject.segmentrouting.config;
sangho80f11cb2015-04-01 13:05:26 -070017
Charles Chan82ab1932016-01-30 23:22:37 -080018import com.google.common.collect.HashMultimap;
Charles Chanc6ad7752015-10-29 14:58:10 -070019import com.google.common.collect.ImmutableSet;
Charles Chan82ab1932016-01-30 23:22:37 -080020import com.google.common.collect.SetMultimap;
sangho80f11cb2015-04-01 13:05:26 -070021import org.onlab.packet.Ip4Address;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070022import org.onlab.packet.Ip4Prefix;
Pier Ventreadb4ae62016-11-23 09:57:42 -080023import org.onlab.packet.Ip6Address;
Pier Ventreb6a7f342016-11-26 21:05:22 -080024import org.onlab.packet.Ip6Prefix;
Charles Chandebfea32016-10-24 14:52:01 -070025import org.onlab.packet.IpAddress;
Charles Chan82ab1932016-01-30 23:22:37 -080026import org.onlab.packet.IpPrefix;
sangho80f11cb2015-04-01 13:05:26 -070027import org.onlab.packet.MacAddress;
Charles Chanb7f75ac2016-01-11 18:28:54 -080028import org.onlab.packet.VlanId;
Charles Chane7c61022015-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 Chane7c61022015-10-07 14:21:45 -070033import org.onosproject.net.host.InterfaceIpAddress;
sangho80f11cb2015-04-01 13:05:26 -070034import org.onosproject.net.DeviceId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070035import org.onosproject.net.PortNumber;
Charles Chan46fdfaf2016-11-09 20:51:44 -080036import org.onosproject.segmentrouting.SegmentRoutingManager;
sangho80f11cb2015-04-01 13:05:26 -070037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070040import java.util.ArrayList;
Pier Ventreb6a7f342016-11-26 21:05:22 -080041import java.util.Collections;
sangho80f11cb2015-04-01 13:05:26 -070042import java.util.HashMap;
Charles Chan9bec8a32015-12-01 10:00:51 -080043import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070044import java.util.List;
45import java.util.Map;
Charles Chan72f556a2015-10-05 17:50:33 -070046import java.util.Set;
Saurav Das7c305372015-10-28 12:39:42 -070047import java.util.concurrent.ConcurrentHashMap;
Charles Chan46fdfaf2016-11-09 20:51:44 -080048import java.util.stream.Collectors;
sangho80f11cb2015-04-01 13:05:26 -070049
Charles Chanc22cef32016-04-29 14:38:22 -070050import static com.google.common.base.Preconditions.checkNotNull;
51
Srikanth Vavilapalli37a461b2015-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 Vavilapalli37a461b2015-04-07 15:12:32 -070056 */
sangho80f11cb2015-04-01 13:05:26 -070057public class DeviceConfiguration implements DeviceProperties {
58
Charles Chan46fdfaf2016-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 Ventreb6a7f342016-11-26 21:05:22 -080062 private static final String MISCONFIGURED = "Subnets are not configured correctly for {}";
Charles Chan46fdfaf2016-11-09 20:51:44 -080063
Charles Chan43547ca2016-02-10 20:46:58 -080064 private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -070065 private final List<Integer> allSegmentIds = new ArrayList<>();
Charles Chanb7f75ac2016-01-11 18:28:54 -080066 private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
Charles Chan46fdfaf2016-11-09 20:51:44 -080067 private SegmentRoutingManager srManager;
sangho80f11cb2015-04-01 13:05:26 -070068
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070069 private class SegmentRouterInfo {
Pier Ventreadb4ae62016-11-23 09:57:42 -080070 int ipv4NodeSid;
71 int ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070072 DeviceId deviceId;
Pier Ventreadb4ae62016-11-23 09:57:42 -080073 Ip4Address ipv4Loopback;
74 Ip6Address ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070075 MacAddress mac;
76 boolean isEdge;
Pier Ventreb6a7f342016-11-26 21:05:22 -080077 SetMultimap<PortNumber, IpAddress> gatewayIps;
78 SetMultimap<PortNumber, IpPrefix> subnets;
Charles Chan9bec8a32015-12-01 10:00:51 -080079 Map<Integer, Set<Integer>> adjacencySids;
Charles Chan2b078ae2015-10-14 11:24:40 -070080
81 public SegmentRouterInfo() {
Pier Ventreb6a7f342016-11-26 21:05:22 -080082 gatewayIps = HashMultimap.create();
Charles Chan82ab1932016-01-30 23:22:37 -080083 subnets = HashMultimap.create();
Charles Chan2b078ae2015-10-14 11:24:40 -070084 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070085 }
sangho80f11cb2015-04-01 13:05:26 -070086
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070087 /**
Charles Chanb7f75ac2016-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'Connor65eeb572015-10-09 17:03:44 -070090 *
Charles Chan46fdfaf2016-11-09 20:51:44 -080091 * @param srManager Segment Routing Manager
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070092 */
Charles Chan46fdfaf2016-11-09 20:51:44 -080093 public DeviceConfiguration(SegmentRoutingManager srManager) {
94 this.srManager = srManager;
Charles Chan57bd98c2016-02-22 19:27:29 -080095
Charles Chane7c61022015-10-07 14:21:45 -070096 // Read config from device subject, excluding gatewayIps and subnets.
97 Set<DeviceId> deviceSubjects =
Charles Chan46fdfaf2016-11-09 20:51:44 -080098 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -070099 deviceSubjects.forEach(subject -> {
Charles Chan82ab1932016-01-30 23:22:37 -0800100 SegmentRoutingDeviceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800101 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700102 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chan72f556a2015-10-05 17:50:33 -0700103 info.deviceId = subject;
Pier Ventreadb4ae62016-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 Chan9bec8a32015-12-01 10:00:51 -0800108 info.mac = config.routerMac();
Charles Chan72f556a2015-10-05 17:50:33 -0700109 info.isEdge = config.isEdgeRouter();
Charles Chan9bec8a32015-12-01 10:00:51 -0800110 info.adjacencySids = config.adjacencySids();
Charles Chanb7f75ac2016-01-11 18:28:54 -0800111 deviceConfigMap.put(info.deviceId, info);
Saurav Das07c74602016-04-27 18:35:50 -0700112 log.info("Read device config for device: {}", info.deviceId);
Pier Ventreadb4ae62016-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 Chan72f556a2015-10-05 17:50:33 -0700117 });
Charles Chane7c61022015-10-07 14:21:45 -0700118
Charles Chan46fdfaf2016-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);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800122
Charles Chan46fdfaf2016-11-09 20:51:44 -0800123 portSubjects.stream().filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chane7c61022015-10-07 14:21:45 -0700124 InterfaceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800125 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700126 Set<Interface> networkInterfaces;
127 try {
128 networkInterfaces = config.getInterfaces();
129 } catch (ConfigException e) {
130 log.error("Error loading port configuration");
131 return;
132 }
133 networkInterfaces.forEach(networkInterface -> {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800134 VlanId vlanId = networkInterface.vlan();
135 ConnectPoint connectPoint = networkInterface.connectPoint();
136 DeviceId dpid = connectPoint.deviceId();
137 PortNumber port = connectPoint.port();
138 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chane7c61022015-10-07 14:21:45 -0700139
Charles Chan2b078ae2015-10-14 11:24:40 -0700140 // skip if there is no corresponding device for this ConenctPoint
141 if (info != null) {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800142 // Extract subnet information
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800143 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chan2b078ae2015-10-14 11:24:40 -0700144 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800145 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan82ab1932016-01-30 23:22:37 -0800146 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800147 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
148 if (ipPrefix.isIp4()) {
149 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
150 info.gatewayIps.put(port, interfaceAddress.ipAddress());
151 }
152 info.subnets.put(port, interfaceAddress.subnetAddress());
153 } else {
154 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
155 info.gatewayIps.put(port, interfaceAddress.ipAddress());
156 }
157 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan82ab1932016-01-30 23:22:37 -0800158 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700159 });
160 }
Charles Chane7c61022015-10-07 14:21:45 -0700161 });
Pier Ventreb6a7f342016-11-26 21:05:22 -0800162 /*
163 * We register the connect point with the NRS.
164 */
165 srManager.registerConnectPoint(subject);
Charles Chane7c61022015-10-07 14:21:45 -0700166 });
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700167 }
168
sangho80f11cb2015-04-01 13:05:26 -0700169 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800170 public boolean isConfigured(DeviceId deviceId) {
171 return deviceConfigMap.get(deviceId) != null;
172 }
173
174 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800175 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700176 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
177 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800178 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
179 return srinfo.ipv4NodeSid;
sangho80f11cb2015-04-01 13:05:26 -0700180 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800181 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
182 throw new DeviceConfigNotFoundException(message);
183 }
184 }
185
186 @Override
187 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
188 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
189 if (srinfo != null) {
190 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
191 return srinfo.ipv6NodeSid;
192 } else {
193 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800194 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700195 }
196 }
197
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700198 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800199 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700200 *
201 * @param routerMac router mac address
Saurav Das7c305372015-10-28 12:39:42 -0700202 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700203 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800204 public int getIPv4SegmentId(MacAddress routerMac) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700205 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
206 deviceConfigMap.entrySet()) {
207 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800208 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700209 }
210 }
sangho80f11cb2015-04-01 13:05:26 -0700211
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700212 return -1;
213 }
214
215 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800216 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
217 *
218 * @param routerMac router mac address
219 * @return node segment id, or -1 if not found in config
220 */
221 public int getIPv6SegmentId(MacAddress routerMac) {
222 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
223 deviceConfigMap.entrySet()) {
224 if (entry.getValue().mac.equals(routerMac)) {
225 return entry.getValue().ipv6NodeSid;
226 }
227 }
228
229 return -1;
230 }
231
232 /**
233 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700234 *
235 * @param routerAddress router ip address
Saurav Das7c305372015-10-28 12:39:42 -0700236 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700237 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800238 public int getIPv4SegmentId(Ip4Address routerAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700239 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
240 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800241 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
242 return entry.getValue().ipv4NodeSid;
243 }
244 }
245
246 return -1;
247 }
248
249 /**
250 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
251 *
252 * @param routerAddress router ip address
253 * @return node segment id, or -1 if not found in config
254 */
255 public int getIPv6SegmentId(Ip6Address routerAddress) {
256 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
257 deviceConfigMap.entrySet()) {
258 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
259 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700260 }
261 }
262
263 return -1;
264 }
265
sangho80f11cb2015-04-01 13:05:26 -0700266 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800267 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700268 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
269 if (srinfo != null) {
270 log.trace("getDeviceMac for device{} is {}", deviceId, srinfo.mac);
271 return srinfo.mac;
sangho80f11cb2015-04-01 13:05:26 -0700272 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800273 String message = "getDeviceMac fails for device: " + deviceId + ".";
274 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700275 }
276 }
277
Charles Chan319d1a22015-11-03 10:42:14 -0800278 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800279 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700280 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
281 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800282 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
283 return srinfo.ipv4Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700284 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800285 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
286 throw new DeviceConfigNotFoundException(message);
287 }
288 }
289
290 @Override
291 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
292 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
293 if (srinfo != null) {
294 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
295 return srinfo.ipv6Loopback;
296 } else {
297 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800298 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700299 }
sangho80f11cb2015-04-01 13:05:26 -0700300 }
301
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700302 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800303 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700304 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
305 if (srinfo != null) {
306 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
307 return srinfo.isEdge;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700308 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800309 String message = "isEdgeDevice fails for device: " + deviceId + ".";
310 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700311 }
312 }
313
sangho80f11cb2015-04-01 13:05:26 -0700314 @Override
315 public List<Integer> getAllDeviceSegmentIds() {
316 return allSegmentIds;
317 }
318
Charles Chan77277672015-10-20 16:24:19 -0700319 @Override
Pier Ventreb6a7f342016-11-26 21:05:22 -0800320 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das52d4ed72016-03-28 19:00:18 -0700321 throws DeviceConfigNotFoundException {
322 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
323 if (srinfo == null) {
324 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
325 throw new DeviceConfigNotFoundException(message);
326 }
Charles Chan77277672015-10-20 16:24:19 -0700327 // Construct subnet-port mapping from port-subnet mapping
Pier Ventreb6a7f342016-11-26 21:05:22 -0800328 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
329 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan82ab1932016-01-30 23:22:37 -0800330
331 portSubnetMap.entries().forEach(entry -> {
332 PortNumber port = entry.getKey();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800333 IpPrefix subnet = entry.getValue();
Charles Chan82ab1932016-01-30 23:22:37 -0800334
Pier Ventreb6a7f342016-11-26 21:05:22 -0800335 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
336 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chanbbd004c2016-02-16 23:14:49 -0800337 return;
338 }
339
Charles Chan77277672015-10-20 16:24:19 -0700340 if (subnetPortMap.containsKey(subnet)) {
341 subnetPortMap.get(subnet).add(port);
342 } else {
343 ArrayList<PortNumber> ports = new ArrayList<>();
344 ports.add(port);
345 subnetPortMap.put(subnet, ports);
346 }
347 });
Charles Chan77277672015-10-20 16:24:19 -0700348 return subnetPortMap;
349 }
350
sangho80f11cb2015-04-01 13:05:26 -0700351 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700352 * Returns the device identifier or data plane identifier (dpid)
353 * of a segment router given its segment id.
sangho80f11cb2015-04-01 13:05:26 -0700354 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700355 * @param sid segment id
356 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700357 */
358 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700359 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
360 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800361 if (entry.getValue().ipv4NodeSid == sid ||
362 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700363 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700364 }
365 }
366
367 return null;
368 }
369
370 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700371 * Returns the device identifier or data plane identifier (dpid)
372 * of a segment router given its router ip address.
sangho80f11cb2015-04-01 13:05:26 -0700373 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700374 * @param ipAddress router ip address
375 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700376 */
377 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700378 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
379 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800380 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
381 return entry.getValue().deviceId;
382 }
383 }
384
385 return null;
386 }
387
388 /**
389 * Returns the device identifier or data plane identifier (dpid)
390 * of a segment router given its router ipv6 address.
391 *
392 * @param ipAddress router ipv6 address
393 * @return deviceId device identifier
394 */
395 public DeviceId getDeviceId(Ip6Address ipAddress) {
396 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
397 deviceConfigMap.entrySet()) {
398 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700399 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700400 }
401 }
402
403 return null;
404 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700405
406 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700407 * Returns the configured port ip addresses for a segment router.
408 * These addresses serve as gateway IP addresses for the subnets configured
409 * on those ports.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700410 *
411 * @param deviceId device identifier
Saurav Dasc28b3432015-10-30 17:45:38 -0700412 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700413 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800414 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700415 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
416 if (srinfo != null) {
417 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
418 srinfo.gatewayIps.values());
Saurav Dasc28b3432015-10-30 17:45:38 -0700419 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700420 }
Saurav Das7c305372015-10-28 12:39:42 -0700421 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700422 }
423
424 /**
425 * Returns the configured subnet prefixes for a segment router.
426 *
427 * @param deviceId device identifier
Saurav Das7c305372015-10-28 12:39:42 -0700428 * @return list of ip prefixes or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700429 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800430 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700431 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
432 if (srinfo != null) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800433 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chandebfea32016-10-24 14:52:01 -0700434 return builder.addAll(srinfo.subnets.values()).build();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700435 }
Saurav Das7c305372015-10-28 12:39:42 -0700436 return null;
437 }
438
Charles Chan46fdfaf2016-11-09 20:51:44 -0800439
Saurav Das7c305372015-10-28 12:39:42 -0700440 /**
Charles Chan46fdfaf2016-11-09 20:51:44 -0800441 * Returns the subnet configuration of given device and port.
Saurav Das7c305372015-10-28 12:39:42 -0700442 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800443 * @param deviceId Device ID
444 * @param port Port number
Pier Ventreb6a7f342016-11-26 21:05:22 -0800445 * @return The subnets configured on given port or empty set if
Charles Chan46fdfaf2016-11-09 20:51:44 -0800446 * the port is unconfigured, misconfigured or suppressed.
Saurav Das7c305372015-10-28 12:39:42 -0700447 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800448 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800449 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
450
451 if (isSuppressedPort(connectPoint)) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800452 return Collections.emptySet();
Saurav Das7c305372015-10-28 12:39:42 -0700453 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800454
Pier Ventreb6a7f342016-11-26 21:05:22 -0800455 Set<IpPrefix> subnets =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800456 srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
457 .flatMap(intf -> intf.ipAddressesList().stream())
458 .map(InterfaceIpAddress::subnetAddress)
459 .map(IpPrefix::getIp4Prefix)
460 .collect(Collectors.toSet());
461
Jon Hall31d84782017-01-18 20:15:44 -0800462 if (subnets.isEmpty()) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800463 log.info(NO_SUBNET, connectPoint);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800464 return Collections.emptySet();
465 } else if (subnets.size() > 2) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800466 log.warn(TOO_MANY_SUBNET, connectPoint);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800467 return Collections.emptySet();
468 } else if (verifySubnets(subnets)) {
469 return subnets;
Charles Chan46fdfaf2016-11-09 20:51:44 -0800470 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800471 log.warn(MISCONFIGURED, connectPoint);
472 return Collections.emptySet();
473 }
474
475 /**
476 * Returns the IPv4 subnet configured of given device and port.
477 *
478 * @param deviceId Device ID
479 * @param port Port number
480 * @return The IPv4 subnet configured on given port or null if
481 * the port is unconfigured, misconfigured or suppressed.
482 */
483 public Ip4Prefix getPortIPv4Subnet(DeviceId deviceId, PortNumber port) {
484 return getPortSubnets(deviceId, port).stream()
485 .filter(IpPrefix::isIp4)
486 .map(IpPrefix::getIp4Prefix)
487 .findFirst().orElse(null);
488 }
489
490 /**
491 * Returns the IPv6 subnet configured of given device and port.
492 *
493 * @param deviceId Device ID
494 * @param port Port number
495 * @return The IPV6 subnet configured on given port or null if
496 * the port is unconfigured, misconfigured or suppressed.
497 */
498 public Ip6Prefix getPortIPv6Subnet(DeviceId deviceId, PortNumber port) {
499 return getPortSubnets(deviceId, port).stream()
500 .filter(IpPrefix::isIp6)
501 .map(IpPrefix::getIp6Prefix)
502 .findFirst().orElse(null);
503 }
504
505 /**
506 * Utility to verify the configuration of a given port.
507 *
508 * @param subnets the subnets set to verify
509 * @return true if the configured subnets are ok. False otherwise.
510 */
511 private boolean verifySubnets(Set<IpPrefix> subnets) {
512 Set<Ip4Prefix> ip4Prefices = subnets.stream()
513 .filter(IpPrefix::isIp4)
514 .map(IpPrefix::getIp4Prefix)
515 .collect(Collectors.toSet());
516 if (ip4Prefices.size() > 1) {
517 return false;
518 }
519 Set<Ip6Prefix> ip6Prefices = subnets.stream()
520 .filter(IpPrefix::isIp6)
521 .map(IpPrefix::getIp6Prefix)
522 .collect(Collectors.toSet());
523 if (ip6Prefices.size() > 1) {
524 return false;
525 }
526 return !(ip4Prefices.isEmpty() && ip6Prefices.isEmpty());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700527 }
528
529 /**
530 * Returns the router ip address of segment router that has the
531 * specified ip address in its subnets.
532 *
533 * @param destIpAddress target ip address
534 * @return router ip address
535 */
536 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan70661362016-12-09 12:54:49 -0800537 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
538
539 if (matchIntf == null) {
540 log.debug("No router was found for {}", destIpAddress);
541 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700542 }
543
Charles Chan70661362016-12-09 12:54:49 -0800544 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
545 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
546 if (srInfo == null) {
547 log.debug("No device config was found for {}", routerDeviceId);
548 return null;
549 }
550
Pier Ventreadb4ae62016-11-23 09:57:42 -0800551 return srInfo.ipv4Loopback;
552 }
553
554 /**
555 * Returns the router ipv6 address of segment router that has the
556 * specified ip address in its subnets.
557 *
558 * @param destIpAddress target ip address
559 * @return router ip address
560 */
561 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
562 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
563
564 if (matchIntf == null) {
565 log.debug("No router was found for {}", destIpAddress);
566 return null;
567 }
568
569 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
570 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
571 if (srInfo == null) {
572 log.debug("No device config was found for {}", routerDeviceId);
573 return null;
574 }
575
576 return srInfo.ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700577 }
578
579 /**
580 * Returns the router mac address of segment router that has the
581 * specified ip address as one of its subnet gateway ip address.
582 *
583 * @param gatewayIpAddress router gateway ip address
Saurav Das7c305372015-10-28 12:39:42 -0700584 * @return router mac address or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700585 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800586 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700587 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
588 deviceConfigMap.entrySet()) {
589 if (entry.getValue().gatewayIps.
590 values().contains(gatewayIpAddress)) {
591 return entry.getValue().mac;
592 }
593 }
594
595 log.debug("Cannot find a router for {}", gatewayIpAddress);
596 return null;
597 }
sangho9b169e32015-04-14 16:27:13 -0700598
599
600 /**
601 * Checks if the host is in the subnet defined in the router with the
602 * device ID given.
603 *
604 * @param deviceId device identification of the router
605 * @param hostIp host IP address to check
606 * @return true if the host is within the subnet of the router,
607 * false if no subnet is defined under the router or if the host is not
608 * within the subnet defined in the router
609 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800610 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
sangho9b169e32015-04-14 16:27:13 -0700611
Pier Ventreb6a7f342016-11-26 21:05:22 -0800612 Set<IpPrefix> subnets = getSubnets(deviceId);
sangho9b169e32015-04-14 16:27:13 -0700613 if (subnets == null) {
614 return false;
615 }
616
Pier Ventreb6a7f342016-11-26 21:05:22 -0800617 for (IpPrefix subnet: subnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800618 // Exclude /0 since it is a special case used for default route
619 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho9b169e32015-04-14 16:27:13 -0700620 return true;
621 }
622 }
623
624 return false;
625 }
sangho27462c62015-05-14 00:39:53 -0700626
627 /**
Charles Chandebfea32016-10-24 14:52:01 -0700628 * Checks if the IP is in the subnet defined on given connect point.
629 *
630 * @param connectPoint Connect point
631 * @param ip The IP address to check
632 * @return True if the IP belongs to the subnet.
633 * False if the IP does not belong to the subnet, or
634 * there is no subnet configuration on given connect point.
635 */
636 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800637 Ip4Prefix ipv4Subnet = getPortIPv4Subnet(connectPoint.deviceId(), connectPoint.port());
638 Ip6Prefix ipv6Subnet = getPortIPv6Subnet(connectPoint.deviceId(), connectPoint.port());
639 return (ipv4Subnet != null && ipv4Subnet.contains(ip)) ||
640 (ipv6Subnet != null && ipv6Subnet.contains(ip));
Charles Chandebfea32016-10-24 14:52:01 -0700641 }
642
643 /**
sangho27462c62015-05-14 00:39:53 -0700644 * Returns the ports corresponding to the adjacency Sid given.
645 *
646 * @param deviceId device identification of the router
647 * @param sid adjacency Sid
Charles Chan9bec8a32015-12-01 10:00:51 -0800648 * @return set of port numbers
sangho27462c62015-05-14 00:39:53 -0700649 */
Charles Chan9bec8a32015-12-01 10:00:51 -0800650 public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700651 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800652 return srinfo != null ?
653 ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
654 ImmutableSet.copyOf(new HashSet<>());
sangho27462c62015-05-14 00:39:53 -0700655 }
656
657 /**
658 * Check if the Sid given is whether adjacency Sid of the router device or not.
659 *
660 * @param deviceId device identification of the router
661 * @param sid Sid to check
662 * @return true if the Sid given is the adjacency Sid of the device,
663 * otherwise false
664 */
665 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700666 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800667 return srinfo != null && srinfo.adjacencySids.containsKey(sid);
sangho27462c62015-05-14 00:39:53 -0700668 }
Charles Chan43547ca2016-02-10 20:46:58 -0800669
Charles Chanc91c8782016-03-30 17:54:24 -0700670 /**
Charles Chanc22cef32016-04-29 14:38:22 -0700671 * Add subnet to specific connect point.
672 *
673 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800674 * @param ipPrefix subnet being added to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700675 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800676 public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700677 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800678 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700679 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
680 if (srinfo == null) {
681 log.warn("Device {} is not configured. Abort.", cp.deviceId());
682 return;
683 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800684 srinfo.subnets.put(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700685 }
686
687 /**
688 * Remove subnet from specific connect point.
689 *
690 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800691 * @param ipPrefix subnet being removed to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700692 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800693 public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700694 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800695 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700696 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
697 if (srinfo == null) {
698 log.warn("Device {} is not configured. Abort.", cp.deviceId());
699 return;
700 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800701 srinfo.subnets.remove(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700702 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800703
704 private boolean isSuppressedPort(ConnectPoint connectPoint) {
705 SegmentRoutingAppConfig appConfig = srManager.cfgService
706 .getConfig(srManager.appId, SegmentRoutingAppConfig.class);
707 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chandebfea32016-10-24 14:52:01 -0700708 log.info("Interface configuration on port {} is ignored", connectPoint);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800709 return true;
710 }
711 return false;
712 }
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800713}