blob: e4b994936abf8612364f777dcdfe39595fb9899a [file] [log] [blame]
Thomas Vachuska8fd25052015-09-10 16:15:33 -07001/*
Brian O'Connor0947d7e2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuska8fd25052015-09-10 16:15:33 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Charles Chan319d1a22015-11-03 10:42:14 -080016package org.onosproject.segmentrouting.config;
sangho80f11cb2015-04-01 13:05:26 -070017
Charles Chan6191aca2017-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 Chan82ab1932016-01-30 23:22:37 -080021import com.google.common.collect.HashMultimap;
Charles Chanc6ad7752015-10-29 14:58:10 -070022import com.google.common.collect.ImmutableSet;
Charles Chandc7d6f92018-03-20 13:30:38 -070023import com.google.common.collect.Multimaps;
Charles Chan82ab1932016-01-30 23:22:37 -080024import com.google.common.collect.SetMultimap;
sangho80f11cb2015-04-01 13:05:26 -070025import org.onlab.packet.Ip4Address;
Pier Ventreadb4ae62016-11-23 09:57:42 -080026import org.onlab.packet.Ip6Address;
Charles Chandebfea32016-10-24 14:52:01 -070027import org.onlab.packet.IpAddress;
Charles Chan82ab1932016-01-30 23:22:37 -080028import org.onlab.packet.IpPrefix;
sangho80f11cb2015-04-01 13:05:26 -070029import org.onlab.packet.MacAddress;
Charles Chanb7f75ac2016-01-11 18:28:54 -080030import org.onlab.packet.VlanId;
Charles Chane7c61022015-10-07 14:21:45 -070031import org.onosproject.net.ConnectPoint;
sangho80f11cb2015-04-01 13:05:26 -070032import org.onosproject.net.DeviceId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070033import org.onosproject.net.PortNumber;
Jonathan Hart61e24e12017-11-30 18:23:42 -080034import org.onosproject.net.config.ConfigException;
35import org.onosproject.net.config.basics.InterfaceConfig;
36import org.onosproject.net.host.InterfaceIpAddress;
37import org.onosproject.net.intf.Interface;
Charles Chan46fdfaf2016-11-09 20:51:44 -080038import org.onosproject.segmentrouting.SegmentRoutingManager;
sangho80f11cb2015-04-01 13:05:26 -070039import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070042import java.util.ArrayList;
Jonathan Hart61e24e12017-11-30 18:23:42 -080043import java.util.Collection;
Pier Ventreb6a7f342016-11-26 21:05:22 -080044import java.util.Collections;
sangho80f11cb2015-04-01 13:05:26 -070045import java.util.HashMap;
Charles Chan9bec8a32015-12-01 10:00:51 -080046import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070047import java.util.List;
48import java.util.Map;
Charles Chan72f556a2015-10-05 17:50:33 -070049import java.util.Set;
Saurav Das7c305372015-10-28 12:39:42 -070050import java.util.concurrent.ConcurrentHashMap;
Charles Chan46fdfaf2016-11-09 20:51:44 -080051import java.util.stream.Collectors;
sangho80f11cb2015-04-01 13:05:26 -070052
Charles Chanc22cef32016-04-29 14:38:22 -070053import static com.google.common.base.Preconditions.checkNotNull;
54
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070055/**
56 * Segment Routing configuration component that reads the
57 * segment routing related configuration from Network Configuration Manager
58 * component and organizes in more accessible formats.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070059 */
sangho80f11cb2015-04-01 13:05:26 -070060public class DeviceConfiguration implements DeviceProperties {
61
Charles Chan46fdfaf2016-11-09 20:51:44 -080062 private static final String NO_SUBNET = "No subnet configured on {}";
63
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 {
Charles Chan3d35a542018-10-02 12:52:29 -070070 int ipv4NodeSid = -1;
71 int ipv6NodeSid = -1;
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;
Saurav Das261c3002017-06-13 15:35:54 -070080 DeviceId pairDeviceId;
81 PortNumber pairLocalPort;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070082 int pwRoutingLabel;
Charles Chan2b078ae2015-10-14 11:24:40 -070083
84 public SegmentRouterInfo() {
Charles Chandc7d6f92018-03-20 13:30:38 -070085 gatewayIps = Multimaps.synchronizedSetMultimap(HashMultimap.create());
86 subnets = Multimaps.synchronizedSetMultimap(HashMultimap.create());
Charles Chan2b078ae2015-10-14 11:24:40 -070087 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070088 }
sangho80f11cb2015-04-01 13:05:26 -070089
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070090 /**
Charles Chanb7f75ac2016-01-11 18:28:54 -080091 * Constructs device configuration for all Segment Router devices,
92 * organizing the data into various maps for easier access.
Brian O'Connor65eeb572015-10-09 17:03:44 -070093 *
Charles Chan46fdfaf2016-11-09 20:51:44 -080094 * @param srManager Segment Routing Manager
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070095 */
Charles Chan46fdfaf2016-11-09 20:51:44 -080096 public DeviceConfiguration(SegmentRoutingManager srManager) {
97 this.srManager = srManager;
Saurav Das261c3002017-06-13 15:35:54 -070098 updateConfig();
99 }
Charles Chan57bd98c2016-02-22 19:27:29 -0800100
Saurav Das261c3002017-06-13 15:35:54 -0700101 public void updateConfig() {
Charles Chane7c61022015-10-07 14:21:45 -0700102 // Read config from device subject, excluding gatewayIps and subnets.
103 Set<DeviceId> deviceSubjects =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800104 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700105 deviceSubjects.forEach(subject -> {
Charles Chan82ab1932016-01-30 23:22:37 -0800106 SegmentRoutingDeviceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800107 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700108 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chan72f556a2015-10-05 17:50:33 -0700109 info.deviceId = subject;
Pier Ventreadb4ae62016-11-23 09:57:42 -0800110 info.ipv4NodeSid = config.nodeSidIPv4();
111 info.ipv6NodeSid = config.nodeSidIPv6();
112 info.ipv4Loopback = config.routerIpv4();
113 info.ipv6Loopback = config.routerIpv6();
Charles Chan9bec8a32015-12-01 10:00:51 -0800114 info.mac = config.routerMac();
Charles Chan72f556a2015-10-05 17:50:33 -0700115 info.isEdge = config.isEdgeRouter();
Charles Chan9bec8a32015-12-01 10:00:51 -0800116 info.adjacencySids = config.adjacencySids();
Saurav Das261c3002017-06-13 15:35:54 -0700117 info.pairDeviceId = config.pairDeviceId();
118 info.pairLocalPort = config.pairLocalPort();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700119 info.pwRoutingLabel = info.ipv4NodeSid + 1000;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800120 deviceConfigMap.put(info.deviceId, info);
Charles Chan68363b12017-06-26 15:25:09 -0700121 log.debug("Read device config for device: {}", info.deviceId);
Pier Ventreadb4ae62016-11-23 09:57:42 -0800122 /*
123 * IPv6 sid is not inserted. this part of the code is not used for now.
124 */
125 allSegmentIds.add(info.ipv4NodeSid);
Charles Chan72f556a2015-10-05 17:50:33 -0700126 });
Charles Chane7c61022015-10-07 14:21:45 -0700127
Charles Chan46fdfaf2016-11-09 20:51:44 -0800128 // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
129 Set<ConnectPoint> portSubjects = srManager.cfgService
130 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
Jonathan Hart61e24e12017-11-30 18:23:42 -0800131 portSubjects.stream()
132 .filter(subject -> deviceConfigMap.containsKey(subject.deviceId()))
133 .filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chane7c61022015-10-07 14:21:45 -0700134 InterfaceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800135 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700136 Set<Interface> networkInterfaces;
137 try {
138 networkInterfaces = config.getInterfaces();
139 } catch (ConfigException e) {
140 log.error("Error loading port configuration");
141 return;
142 }
143 networkInterfaces.forEach(networkInterface -> {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800144 VlanId vlanId = networkInterface.vlan();
145 ConnectPoint connectPoint = networkInterface.connectPoint();
146 DeviceId dpid = connectPoint.deviceId();
147 PortNumber port = connectPoint.port();
Charles Chan6191aca2017-09-12 12:09:22 -0700148 MacAddress mac = networkInterface.mac();
Charles Chanb7f75ac2016-01-11 18:28:54 -0800149 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chane7c61022015-10-07 14:21:45 -0700150
Charles Chan2b078ae2015-10-14 11:24:40 -0700151 // skip if there is no corresponding device for this ConenctPoint
152 if (info != null) {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800153 // Extract subnet information
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800154 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chan2b078ae2015-10-14 11:24:40 -0700155 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800156 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan82ab1932016-01-30 23:22:37 -0800157 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800158 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
159 if (ipPrefix.isIp4()) {
160 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
161 info.gatewayIps.put(port, interfaceAddress.ipAddress());
162 }
163 info.subnets.put(port, interfaceAddress.subnetAddress());
164 } else {
165 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
166 info.gatewayIps.put(port, interfaceAddress.ipAddress());
167 }
168 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan82ab1932016-01-30 23:22:37 -0800169 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700170 });
Charles Chan6191aca2017-09-12 12:09:22 -0700171
172 // Override interface mac with router mac
173 if (!mac.equals(info.mac)) {
174 ArrayNode array = (ArrayNode) config.node();
175 for (JsonNode intfNode : array) {
176 ObjectNode objNode = (ObjectNode) intfNode;
177 objNode.put(InterfaceConfig.MAC, info.mac.toString());
178 }
179 srManager.cfgService.applyConfig(connectPoint, InterfaceConfig.class, array);
180 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700181 }
Charles Chane7c61022015-10-07 14:21:45 -0700182 });
Pier Luigi6a2643a2017-01-31 09:35:05 -0800183 // We register the connect point with the NRS.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800184 srManager.registerConnectPoint(subject);
Charles Chane7c61022015-10-07 14:21:45 -0700185 });
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700186 }
187
Jonathan Hart61e24e12017-11-30 18:23:42 -0800188 public Collection<DeviceId> getRouters() {
189 return deviceConfigMap.keySet();
190 }
Saurav Das261c3002017-06-13 15:35:54 -0700191
sangho80f11cb2015-04-01 13:05:26 -0700192 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800193 public boolean isConfigured(DeviceId deviceId) {
194 return deviceConfigMap.get(deviceId) != null;
195 }
196
197 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800198 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700199 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
200 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800201 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
202 return srinfo.ipv4NodeSid;
sangho80f11cb2015-04-01 13:05:26 -0700203 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800204 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
205 throw new DeviceConfigNotFoundException(message);
206 }
207 }
208
209 @Override
210 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
211 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
212 if (srinfo != null) {
213 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
214 return srinfo.ipv6NodeSid;
215 } else {
216 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800217 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700218 }
219 }
220
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700221 @Override
222 public int getPWRoutingLabel(DeviceId deviceId) throws DeviceConfigNotFoundException {
223 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
224 if (srinfo != null) {
225 log.trace("pwRoutingLabel for device{} is {}", deviceId, srinfo.pwRoutingLabel);
226 return srinfo.pwRoutingLabel;
227 } else {
228 String message = "getPWRoutingLabel fails for device: " + deviceId + ".";
229 throw new DeviceConfigNotFoundException(message);
230 }
231 }
232
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700233 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800234 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700235 *
236 * @param routerMac router mac address
Saurav Das7c305372015-10-28 12:39:42 -0700237 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700238 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800239 public int getIPv4SegmentId(MacAddress routerMac) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700240 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
241 deviceConfigMap.entrySet()) {
242 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800243 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700244 }
245 }
sangho80f11cb2015-04-01 13:05:26 -0700246
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700247 return -1;
248 }
249
250 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800251 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
252 *
253 * @param routerMac router mac address
254 * @return node segment id, or -1 if not found in config
255 */
256 public int getIPv6SegmentId(MacAddress routerMac) {
257 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
258 deviceConfigMap.entrySet()) {
259 if (entry.getValue().mac.equals(routerMac)) {
260 return entry.getValue().ipv6NodeSid;
261 }
262 }
263
264 return -1;
265 }
266
267 /**
268 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700269 *
270 * @param routerAddress router ip address
Saurav Das7c305372015-10-28 12:39:42 -0700271 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700272 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800273 public int getIPv4SegmentId(Ip4Address routerAddress) {
Charles Chan3d35a542018-10-02 12:52:29 -0700274 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: deviceConfigMap.entrySet()) {
275 Ip4Address ipv4Loopback = entry.getValue().ipv4Loopback;
276 if (ipv4Loopback == null) {
277 continue;
278 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800279 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
Charles Chan3d35a542018-10-02 12:52:29 -0700280 if (entry.getValue().ipv4NodeSid == -1) {
281 continue;
282 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800283 return entry.getValue().ipv4NodeSid;
284 }
285 }
286
287 return -1;
288 }
289
290 /**
291 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
292 *
293 * @param routerAddress router ip address
294 * @return node segment id, or -1 if not found in config
295 */
296 public int getIPv6SegmentId(Ip6Address routerAddress) {
Charles Chan3d35a542018-10-02 12:52:29 -0700297 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: deviceConfigMap.entrySet()) {
298 Ip6Address ipv6Loopback = entry.getValue().ipv6Loopback;
299 if (ipv6Loopback == null) {
300 continue;
301 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800302 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
Charles Chan3d35a542018-10-02 12:52:29 -0700303 if (entry.getValue().ipv6NodeSid == -1) {
304 continue;
305 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800306 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700307 }
308 }
309
310 return -1;
311 }
312
sangho80f11cb2015-04-01 13:05:26 -0700313 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800314 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700315 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
316 if (srinfo != null) {
Saurav Das7c305372015-10-28 12:39:42 -0700317 return srinfo.mac;
sangho80f11cb2015-04-01 13:05:26 -0700318 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800319 String message = "getDeviceMac fails for device: " + deviceId + ".";
320 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700321 }
322 }
323
Charles Chan319d1a22015-11-03 10:42:14 -0800324 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800325 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700326 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
327 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800328 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
329 return srinfo.ipv4Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700330 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800331 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
332 throw new DeviceConfigNotFoundException(message);
333 }
334 }
335
336 @Override
337 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
338 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
339 if (srinfo != null) {
340 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
341 return srinfo.ipv6Loopback;
342 } else {
343 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800344 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700345 }
sangho80f11cb2015-04-01 13:05:26 -0700346 }
347
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700348 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800349 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700350 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
351 if (srinfo != null) {
352 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
353 return srinfo.isEdge;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700354 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800355 String message = "isEdgeDevice fails for device: " + deviceId + ".";
356 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700357 }
358 }
359
sangho80f11cb2015-04-01 13:05:26 -0700360 @Override
361 public List<Integer> getAllDeviceSegmentIds() {
362 return allSegmentIds;
363 }
364
Charles Chan77277672015-10-20 16:24:19 -0700365 @Override
Pier Ventreb6a7f342016-11-26 21:05:22 -0800366 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das52d4ed72016-03-28 19:00:18 -0700367 throws DeviceConfigNotFoundException {
368 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
369 if (srinfo == null) {
370 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
371 throw new DeviceConfigNotFoundException(message);
372 }
Charles Chan77277672015-10-20 16:24:19 -0700373 // Construct subnet-port mapping from port-subnet mapping
Pier Ventreb6a7f342016-11-26 21:05:22 -0800374 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
375 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan82ab1932016-01-30 23:22:37 -0800376
377 portSubnetMap.entries().forEach(entry -> {
378 PortNumber port = entry.getKey();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800379 IpPrefix subnet = entry.getValue();
Charles Chan82ab1932016-01-30 23:22:37 -0800380
Pier Ventreb6a7f342016-11-26 21:05:22 -0800381 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
382 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chanbbd004c2016-02-16 23:14:49 -0800383 return;
384 }
385
Charles Chan77277672015-10-20 16:24:19 -0700386 if (subnetPortMap.containsKey(subnet)) {
387 subnetPortMap.get(subnet).add(port);
388 } else {
389 ArrayList<PortNumber> ports = new ArrayList<>();
390 ports.add(port);
391 subnetPortMap.put(subnet, ports);
392 }
393 });
Charles Chan77277672015-10-20 16:24:19 -0700394 return subnetPortMap;
395 }
396
sangho80f11cb2015-04-01 13:05:26 -0700397 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700398 * Returns the device identifier or data plane identifier (dpid)
399 * of a segment router given its segment id.
sangho80f11cb2015-04-01 13:05:26 -0700400 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700401 * @param sid segment id
402 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700403 */
404 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700405 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
406 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800407 if (entry.getValue().ipv4NodeSid == sid ||
408 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700409 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700410 }
411 }
412
413 return null;
414 }
415
416 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700417 * Returns the device identifier or data plane identifier (dpid)
418 * of a segment router given its router ip address.
sangho80f11cb2015-04-01 13:05:26 -0700419 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700420 * @param ipAddress router ip address
421 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700422 */
423 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700424 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
425 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800426 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
427 return entry.getValue().deviceId;
428 }
429 }
430
431 return null;
432 }
433
434 /**
435 * Returns the device identifier or data plane identifier (dpid)
436 * of a segment router given its router ipv6 address.
437 *
438 * @param ipAddress router ipv6 address
439 * @return deviceId device identifier
440 */
441 public DeviceId getDeviceId(Ip6Address ipAddress) {
442 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
443 deviceConfigMap.entrySet()) {
444 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700445 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700446 }
447 }
448
449 return null;
450 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700451
452 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700453 * Returns the configured port ip addresses for a segment router.
454 * These addresses serve as gateway IP addresses for the subnets configured
455 * on those ports.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700456 *
457 * @param deviceId device identifier
Saurav Dasc28b3432015-10-30 17:45:38 -0700458 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700459 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800460 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700461 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
462 if (srinfo != null) {
463 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
464 srinfo.gatewayIps.values());
Saurav Dasc28b3432015-10-30 17:45:38 -0700465 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700466 }
Saurav Das7c305372015-10-28 12:39:42 -0700467 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700468 }
469
470 /**
471 * Returns the configured subnet prefixes for a segment router.
472 *
473 * @param deviceId device identifier
Saurav Das7c305372015-10-28 12:39:42 -0700474 * @return list of ip prefixes or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700475 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800476 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700477 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan5eb66042018-06-18 14:42:17 -0700478 if (srinfo != null && srinfo.subnets != null) {
479 // Note: ImmutableSet.Builder.addAll calls the iterator of parameter internally,
480 // which is not protected by SynchronizedCollection mutex.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800481 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chan5eb66042018-06-18 14:42:17 -0700482 srinfo.subnets.forEach((k, v) -> builder.add(v));
483 return builder.build();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700484 }
Saurav Das7c305372015-10-28 12:39:42 -0700485 return null;
486 }
487
Charles Chan46fdfaf2016-11-09 20:51:44 -0800488
Saurav Das7c305372015-10-28 12:39:42 -0700489 /**
Charles Chan46fdfaf2016-11-09 20:51:44 -0800490 * Returns the subnet configuration of given device and port.
Saurav Das7c305372015-10-28 12:39:42 -0700491 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800492 * @param deviceId Device ID
493 * @param port Port number
Pier Ventreb6a7f342016-11-26 21:05:22 -0800494 * @return The subnets configured on given port or empty set if
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700495 * the port is unconfigured or suppressed.
Saurav Das7c305372015-10-28 12:39:42 -0700496 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800497 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800498 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
499
500 if (isSuppressedPort(connectPoint)) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800501 return Collections.emptySet();
Saurav Das7c305372015-10-28 12:39:42 -0700502 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800503
Pier Ventreb6a7f342016-11-26 21:05:22 -0800504 Set<IpPrefix> subnets =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800505 srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
506 .flatMap(intf -> intf.ipAddressesList().stream())
507 .map(InterfaceIpAddress::subnetAddress)
Charles Chan46fdfaf2016-11-09 20:51:44 -0800508 .collect(Collectors.toSet());
509
Jon Hall31d84782017-01-18 20:15:44 -0800510 if (subnets.isEmpty()) {
Saurav Dasf9332192017-02-18 14:05:44 -0800511 log.debug(NO_SUBNET, connectPoint);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800512 return Collections.emptySet();
Charles Chan46fdfaf2016-11-09 20:51:44 -0800513 }
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700514
515 return subnets;
Pier Ventreb6a7f342016-11-26 21:05:22 -0800516 }
517
518 /**
Charles Chan873661e2017-11-30 15:37:50 -0800519 * Returns all ports that has a subnet that contains any of the given IP addresses.
520 *
521 * @param ips a set of IP addresses
522 * @return a set of connect point that has a subnet that contains any of the given IP addresses
523 */
524 public Set<ConnectPoint> getPortByIps(Set<IpAddress> ips) {
525 return srManager.interfaceService.getInterfaces().stream()
526 .filter(intf -> intf.ipAddressesList().stream().anyMatch(intfAddress ->
527 ips.stream().anyMatch(ip -> intfAddress.subnetAddress().contains(ip))))
528 .map(Interface::connectPoint)
529 .collect(Collectors.toSet());
530 }
531
532 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700533 * Returns the router ip address of segment router that has the
534 * specified ip address in its subnets.
535 *
536 * @param destIpAddress target ip address
537 * @return router ip address
538 */
539 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan70661362016-12-09 12:54:49 -0800540 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
541
542 if (matchIntf == null) {
543 log.debug("No router was found for {}", destIpAddress);
544 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700545 }
546
Charles Chan70661362016-12-09 12:54:49 -0800547 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
548 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
549 if (srInfo == null) {
550 log.debug("No device config was found for {}", routerDeviceId);
551 return null;
552 }
553
Pier Ventreadb4ae62016-11-23 09:57:42 -0800554 return srInfo.ipv4Loopback;
555 }
556
557 /**
558 * Returns the router ipv6 address of segment router that has the
559 * specified ip address in its subnets.
560 *
561 * @param destIpAddress target ip address
562 * @return router ip address
563 */
564 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
565 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
566
567 if (matchIntf == null) {
568 log.debug("No router was found for {}", destIpAddress);
569 return null;
570 }
571
572 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
573 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
574 if (srInfo == null) {
575 log.debug("No device config was found for {}", routerDeviceId);
576 return null;
577 }
578
579 return srInfo.ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700580 }
581
582 /**
583 * Returns the router mac address of segment router that has the
584 * specified ip address as one of its subnet gateway ip address.
585 *
586 * @param gatewayIpAddress router gateway ip address
Saurav Das7c305372015-10-28 12:39:42 -0700587 * @return router mac address or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700588 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800589 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700590 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
591 deviceConfigMap.entrySet()) {
592 if (entry.getValue().gatewayIps.
593 values().contains(gatewayIpAddress)) {
594 return entry.getValue().mac;
595 }
596 }
597
598 log.debug("Cannot find a router for {}", gatewayIpAddress);
599 return null;
600 }
sangho9b169e32015-04-14 16:27:13 -0700601
sangho9b169e32015-04-14 16:27:13 -0700602 /**
Charles Chan35f21e42017-06-26 18:30:18 -0700603 * Checks if the host IP is in any of the subnet defined in the router with the
sangho9b169e32015-04-14 16:27:13 -0700604 * device ID given.
605 *
606 * @param deviceId device identification of the router
607 * @param hostIp host IP address to check
Charles Chan35f21e42017-06-26 18:30:18 -0700608 * @return true if the given IP is within any of the subnet defined in the router,
609 * false if no subnet is defined in the router or if the host is not
610 * within any subnet defined in the router
sangho9b169e32015-04-14 16:27:13 -0700611 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800612 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
sangho9b169e32015-04-14 16:27:13 -0700613
Pier Ventreb6a7f342016-11-26 21:05:22 -0800614 Set<IpPrefix> subnets = getSubnets(deviceId);
sangho9b169e32015-04-14 16:27:13 -0700615 if (subnets == null) {
616 return false;
617 }
618
Pier Ventreb6a7f342016-11-26 21:05:22 -0800619 for (IpPrefix subnet: subnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800620 // Exclude /0 since it is a special case used for default route
621 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho9b169e32015-04-14 16:27:13 -0700622 return true;
623 }
624 }
625
626 return false;
627 }
sangho27462c62015-05-14 00:39:53 -0700628
629 /**
Charles Chandebfea32016-10-24 14:52:01 -0700630 * Checks if the IP is in the subnet defined on given connect point.
631 *
632 * @param connectPoint Connect point
633 * @param ip The IP address to check
634 * @return True if the IP belongs to the subnet.
635 * False if the IP does not belong to the subnet, or
636 * there is no subnet configuration on given connect point.
637 */
638 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Charles Chan35f21e42017-06-26 18:30:18 -0700639 return getPortSubnets(connectPoint.deviceId(), connectPoint.port()).stream()
640 .anyMatch(ipPrefix -> ipPrefix.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
Ray Milkeyb85de082017-04-05 09:42:04 -0700706 .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800707 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 }
Saurav Das261c3002017-06-13 15:35:54 -0700713
714 public boolean isPairedEdge(DeviceId deviceId) throws DeviceConfigNotFoundException {
715 if (!isEdgeDevice(deviceId)) {
716 return false;
717 }
718 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
719 return (srinfo.pairDeviceId == null) ? false : true;
720 }
721
722 public DeviceId getPairDeviceId(DeviceId deviceId) throws DeviceConfigNotFoundException {
723 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
724 if (srinfo != null) {
725 return srinfo.pairDeviceId;
726 } else {
727 String message = "getPairDeviceId fails for device: " + deviceId + ".";
728 throw new DeviceConfigNotFoundException(message);
729 }
730 }
731
732 public PortNumber getPairLocalPort(DeviceId deviceId)
733 throws DeviceConfigNotFoundException {
734 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
735 if (srinfo != null) {
736 return srinfo.pairLocalPort;
737 } else {
738 String message = "getPairLocalPort fails for device: " + deviceId + ".";
739 throw new DeviceConfigNotFoundException(message);
740 }
741 }
742
Saurav Dasec683dc2018-04-27 18:42:30 -0700743 public boolean isPairLocalPort(DeviceId devId, PortNumber pnum) {
744 return pnum.equals(srManager.getPairLocalPort(devId).orElse(null));
745 }
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800746}