blob: 070a7ecd20a9206dc482a94895e1fa363bcf4b05 [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 Chan82ab1932016-01-30 23:22:37 -080023import com.google.common.collect.SetMultimap;
sangho80f11cb2015-04-01 13:05:26 -070024import org.onlab.packet.Ip4Address;
Pier Ventreadb4ae62016-11-23 09:57:42 -080025import org.onlab.packet.Ip6Address;
Charles Chandebfea32016-10-24 14:52:01 -070026import org.onlab.packet.IpAddress;
Charles Chan82ab1932016-01-30 23:22:37 -080027import org.onlab.packet.IpPrefix;
sangho80f11cb2015-04-01 13:05:26 -070028import org.onlab.packet.MacAddress;
Charles Chanb7f75ac2016-01-11 18:28:54 -080029import org.onlab.packet.VlanId;
Charles Chane7c61022015-10-07 14:21:45 -070030import org.onosproject.net.ConnectPoint;
sangho80f11cb2015-04-01 13:05:26 -070031import org.onosproject.net.DeviceId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070032import org.onosproject.net.PortNumber;
Jonathan Hart61e24e12017-11-30 18:23:42 -080033import org.onosproject.net.config.ConfigException;
34import org.onosproject.net.config.basics.InterfaceConfig;
35import org.onosproject.net.host.InterfaceIpAddress;
36import org.onosproject.net.intf.Interface;
Charles Chan46fdfaf2016-11-09 20:51:44 -080037import org.onosproject.segmentrouting.SegmentRoutingManager;
sangho80f11cb2015-04-01 13:05:26 -070038import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070041import java.util.ArrayList;
Jonathan Hart61e24e12017-11-30 18:23:42 -080042import java.util.Collection;
Pier Ventreb6a7f342016-11-26 21:05:22 -080043import java.util.Collections;
sangho80f11cb2015-04-01 13:05:26 -070044import java.util.HashMap;
Charles Chan9bec8a32015-12-01 10:00:51 -080045import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070046import java.util.List;
47import java.util.Map;
Charles Chan72f556a2015-10-05 17:50:33 -070048import java.util.Set;
Saurav Das7c305372015-10-28 12:39:42 -070049import java.util.concurrent.ConcurrentHashMap;
Charles Chan46fdfaf2016-11-09 20:51:44 -080050import java.util.stream.Collectors;
sangho80f11cb2015-04-01 13:05:26 -070051
Charles Chanc22cef32016-04-29 14:38:22 -070052import static com.google.common.base.Preconditions.checkNotNull;
53
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070054/**
55 * Segment Routing configuration component that reads the
56 * segment routing related configuration from Network Configuration Manager
57 * component and organizes in more accessible formats.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070058 */
sangho80f11cb2015-04-01 13:05:26 -070059public class DeviceConfiguration implements DeviceProperties {
60
Charles Chan46fdfaf2016-11-09 20:51:44 -080061 private static final String NO_SUBNET = "No subnet configured on {}";
62
Charles Chan43547ca2016-02-10 20:46:58 -080063 private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -070064 private final List<Integer> allSegmentIds = new ArrayList<>();
Charles Chanb7f75ac2016-01-11 18:28:54 -080065 private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
Charles Chan46fdfaf2016-11-09 20:51:44 -080066 private SegmentRoutingManager srManager;
sangho80f11cb2015-04-01 13:05:26 -070067
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070068 private class SegmentRouterInfo {
Pier Ventreadb4ae62016-11-23 09:57:42 -080069 int ipv4NodeSid;
70 int ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070071 DeviceId deviceId;
Pier Ventreadb4ae62016-11-23 09:57:42 -080072 Ip4Address ipv4Loopback;
73 Ip6Address ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070074 MacAddress mac;
75 boolean isEdge;
Pier Ventreb6a7f342016-11-26 21:05:22 -080076 SetMultimap<PortNumber, IpAddress> gatewayIps;
77 SetMultimap<PortNumber, IpPrefix> subnets;
Charles Chan9bec8a32015-12-01 10:00:51 -080078 Map<Integer, Set<Integer>> adjacencySids;
Saurav Das261c3002017-06-13 15:35:54 -070079 DeviceId pairDeviceId;
80 PortNumber pairLocalPort;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070081 int pwRoutingLabel;
Charles Chan2b078ae2015-10-14 11:24:40 -070082
83 public SegmentRouterInfo() {
Pier Ventreb6a7f342016-11-26 21:05:22 -080084 gatewayIps = HashMultimap.create();
Charles Chan82ab1932016-01-30 23:22:37 -080085 subnets = HashMultimap.create();
Charles Chan2b078ae2015-10-14 11:24:40 -070086 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070087 }
sangho80f11cb2015-04-01 13:05:26 -070088
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070089 /**
Charles Chanb7f75ac2016-01-11 18:28:54 -080090 * Constructs device configuration for all Segment Router devices,
91 * organizing the data into various maps for easier access.
Brian O'Connor65eeb572015-10-09 17:03:44 -070092 *
Charles Chan46fdfaf2016-11-09 20:51:44 -080093 * @param srManager Segment Routing Manager
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070094 */
Charles Chan46fdfaf2016-11-09 20:51:44 -080095 public DeviceConfiguration(SegmentRoutingManager srManager) {
96 this.srManager = srManager;
Saurav Das261c3002017-06-13 15:35:54 -070097 updateConfig();
98 }
Charles Chan57bd98c2016-02-22 19:27:29 -080099
Saurav Das261c3002017-06-13 15:35:54 -0700100 public void updateConfig() {
Charles Chane7c61022015-10-07 14:21:45 -0700101 // Read config from device subject, excluding gatewayIps and subnets.
102 Set<DeviceId> deviceSubjects =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800103 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700104 deviceSubjects.forEach(subject -> {
Charles Chan82ab1932016-01-30 23:22:37 -0800105 SegmentRoutingDeviceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800106 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700107 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chan72f556a2015-10-05 17:50:33 -0700108 info.deviceId = subject;
Pier Ventreadb4ae62016-11-23 09:57:42 -0800109 info.ipv4NodeSid = config.nodeSidIPv4();
110 info.ipv6NodeSid = config.nodeSidIPv6();
111 info.ipv4Loopback = config.routerIpv4();
112 info.ipv6Loopback = config.routerIpv6();
Charles Chan9bec8a32015-12-01 10:00:51 -0800113 info.mac = config.routerMac();
Charles Chan72f556a2015-10-05 17:50:33 -0700114 info.isEdge = config.isEdgeRouter();
Charles Chan9bec8a32015-12-01 10:00:51 -0800115 info.adjacencySids = config.adjacencySids();
Saurav Das261c3002017-06-13 15:35:54 -0700116 info.pairDeviceId = config.pairDeviceId();
117 info.pairLocalPort = config.pairLocalPort();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700118 info.pwRoutingLabel = info.ipv4NodeSid + 1000;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800119 deviceConfigMap.put(info.deviceId, info);
Charles Chan68363b12017-06-26 15:25:09 -0700120 log.debug("Read device config for device: {}", info.deviceId);
Pier Ventreadb4ae62016-11-23 09:57:42 -0800121 /*
122 * IPv6 sid is not inserted. this part of the code is not used for now.
123 */
124 allSegmentIds.add(info.ipv4NodeSid);
Charles Chan72f556a2015-10-05 17:50:33 -0700125 });
Charles Chane7c61022015-10-07 14:21:45 -0700126
Charles Chan46fdfaf2016-11-09 20:51:44 -0800127 // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
128 Set<ConnectPoint> portSubjects = srManager.cfgService
129 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
Jonathan Hart61e24e12017-11-30 18:23:42 -0800130 portSubjects.stream()
131 .filter(subject -> deviceConfigMap.containsKey(subject.deviceId()))
132 .filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chane7c61022015-10-07 14:21:45 -0700133 InterfaceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800134 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700135 Set<Interface> networkInterfaces;
136 try {
137 networkInterfaces = config.getInterfaces();
138 } catch (ConfigException e) {
139 log.error("Error loading port configuration");
140 return;
141 }
142 networkInterfaces.forEach(networkInterface -> {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800143 VlanId vlanId = networkInterface.vlan();
144 ConnectPoint connectPoint = networkInterface.connectPoint();
145 DeviceId dpid = connectPoint.deviceId();
146 PortNumber port = connectPoint.port();
Charles Chan6191aca2017-09-12 12:09:22 -0700147 MacAddress mac = networkInterface.mac();
Charles Chanb7f75ac2016-01-11 18:28:54 -0800148 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chane7c61022015-10-07 14:21:45 -0700149
Charles Chan2b078ae2015-10-14 11:24:40 -0700150 // skip if there is no corresponding device for this ConenctPoint
151 if (info != null) {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800152 // Extract subnet information
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800153 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chan2b078ae2015-10-14 11:24:40 -0700154 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800155 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan82ab1932016-01-30 23:22:37 -0800156 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800157 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
158 if (ipPrefix.isIp4()) {
159 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
160 info.gatewayIps.put(port, interfaceAddress.ipAddress());
161 }
162 info.subnets.put(port, interfaceAddress.subnetAddress());
163 } else {
164 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
165 info.gatewayIps.put(port, interfaceAddress.ipAddress());
166 }
167 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan82ab1932016-01-30 23:22:37 -0800168 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700169 });
Charles Chan6191aca2017-09-12 12:09:22 -0700170
171 // Override interface mac with router mac
172 if (!mac.equals(info.mac)) {
173 ArrayNode array = (ArrayNode) config.node();
174 for (JsonNode intfNode : array) {
175 ObjectNode objNode = (ObjectNode) intfNode;
176 objNode.put(InterfaceConfig.MAC, info.mac.toString());
177 }
178 srManager.cfgService.applyConfig(connectPoint, InterfaceConfig.class, array);
179 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700180 }
Charles Chane7c61022015-10-07 14:21:45 -0700181 });
Pier Luigi6a2643a2017-01-31 09:35:05 -0800182 // We register the connect point with the NRS.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800183 srManager.registerConnectPoint(subject);
Charles Chane7c61022015-10-07 14:21:45 -0700184 });
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700185 }
186
Jonathan Hart61e24e12017-11-30 18:23:42 -0800187 public Collection<DeviceId> getRouters() {
188 return deviceConfigMap.keySet();
189 }
Saurav Das261c3002017-06-13 15:35:54 -0700190
sangho80f11cb2015-04-01 13:05:26 -0700191 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800192 public boolean isConfigured(DeviceId deviceId) {
193 return deviceConfigMap.get(deviceId) != null;
194 }
195
196 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800197 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700198 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
199 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800200 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
201 return srinfo.ipv4NodeSid;
sangho80f11cb2015-04-01 13:05:26 -0700202 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800203 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
204 throw new DeviceConfigNotFoundException(message);
205 }
206 }
207
208 @Override
209 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
210 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
211 if (srinfo != null) {
212 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
213 return srinfo.ipv6NodeSid;
214 } else {
215 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800216 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700217 }
218 }
219
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700220 @Override
221 public int getPWRoutingLabel(DeviceId deviceId) throws DeviceConfigNotFoundException {
222 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
223 if (srinfo != null) {
224 log.trace("pwRoutingLabel for device{} is {}", deviceId, srinfo.pwRoutingLabel);
225 return srinfo.pwRoutingLabel;
226 } else {
227 String message = "getPWRoutingLabel fails for device: " + deviceId + ".";
228 throw new DeviceConfigNotFoundException(message);
229 }
230 }
231
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700232 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800233 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700234 *
235 * @param routerMac router mac 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(MacAddress routerMac) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700239 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
240 deviceConfigMap.entrySet()) {
241 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800242 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700243 }
244 }
sangho80f11cb2015-04-01 13:05:26 -0700245
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700246 return -1;
247 }
248
249 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800250 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
251 *
252 * @param routerMac router mac address
253 * @return node segment id, or -1 if not found in config
254 */
255 public int getIPv6SegmentId(MacAddress routerMac) {
256 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
257 deviceConfigMap.entrySet()) {
258 if (entry.getValue().mac.equals(routerMac)) {
259 return entry.getValue().ipv6NodeSid;
260 }
261 }
262
263 return -1;
264 }
265
266 /**
267 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700268 *
269 * @param routerAddress router ip address
Saurav Das7c305372015-10-28 12:39:42 -0700270 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700271 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800272 public int getIPv4SegmentId(Ip4Address routerAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700273 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
274 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800275 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
276 return entry.getValue().ipv4NodeSid;
277 }
278 }
279
280 return -1;
281 }
282
283 /**
284 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
285 *
286 * @param routerAddress router ip address
287 * @return node segment id, or -1 if not found in config
288 */
289 public int getIPv6SegmentId(Ip6Address routerAddress) {
290 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
291 deviceConfigMap.entrySet()) {
292 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
293 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700294 }
295 }
296
297 return -1;
298 }
299
sangho80f11cb2015-04-01 13:05:26 -0700300 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800301 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700302 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
303 if (srinfo != null) {
Saurav Das7c305372015-10-28 12:39:42 -0700304 return srinfo.mac;
sangho80f11cb2015-04-01 13:05:26 -0700305 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800306 String message = "getDeviceMac fails for device: " + deviceId + ".";
307 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700308 }
309 }
310
Charles Chan319d1a22015-11-03 10:42:14 -0800311 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800312 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700313 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
314 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800315 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
316 return srinfo.ipv4Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700317 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800318 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
319 throw new DeviceConfigNotFoundException(message);
320 }
321 }
322
323 @Override
324 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
325 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
326 if (srinfo != null) {
327 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
328 return srinfo.ipv6Loopback;
329 } else {
330 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800331 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700332 }
sangho80f11cb2015-04-01 13:05:26 -0700333 }
334
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700335 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800336 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700337 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
338 if (srinfo != null) {
339 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
340 return srinfo.isEdge;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700341 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800342 String message = "isEdgeDevice fails for device: " + deviceId + ".";
343 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700344 }
345 }
346
sangho80f11cb2015-04-01 13:05:26 -0700347 @Override
348 public List<Integer> getAllDeviceSegmentIds() {
349 return allSegmentIds;
350 }
351
Charles Chan77277672015-10-20 16:24:19 -0700352 @Override
Pier Ventreb6a7f342016-11-26 21:05:22 -0800353 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das52d4ed72016-03-28 19:00:18 -0700354 throws DeviceConfigNotFoundException {
355 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
356 if (srinfo == null) {
357 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
358 throw new DeviceConfigNotFoundException(message);
359 }
Charles Chan77277672015-10-20 16:24:19 -0700360 // Construct subnet-port mapping from port-subnet mapping
Pier Ventreb6a7f342016-11-26 21:05:22 -0800361 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
362 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan82ab1932016-01-30 23:22:37 -0800363
364 portSubnetMap.entries().forEach(entry -> {
365 PortNumber port = entry.getKey();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800366 IpPrefix subnet = entry.getValue();
Charles Chan82ab1932016-01-30 23:22:37 -0800367
Pier Ventreb6a7f342016-11-26 21:05:22 -0800368 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
369 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chanbbd004c2016-02-16 23:14:49 -0800370 return;
371 }
372
Charles Chan77277672015-10-20 16:24:19 -0700373 if (subnetPortMap.containsKey(subnet)) {
374 subnetPortMap.get(subnet).add(port);
375 } else {
376 ArrayList<PortNumber> ports = new ArrayList<>();
377 ports.add(port);
378 subnetPortMap.put(subnet, ports);
379 }
380 });
Charles Chan77277672015-10-20 16:24:19 -0700381 return subnetPortMap;
382 }
383
sangho80f11cb2015-04-01 13:05:26 -0700384 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700385 * Returns the device identifier or data plane identifier (dpid)
386 * of a segment router given its segment id.
sangho80f11cb2015-04-01 13:05:26 -0700387 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700388 * @param sid segment id
389 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700390 */
391 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700392 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
393 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800394 if (entry.getValue().ipv4NodeSid == sid ||
395 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700396 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700397 }
398 }
399
400 return null;
401 }
402
403 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700404 * Returns the device identifier or data plane identifier (dpid)
405 * of a segment router given its router ip address.
sangho80f11cb2015-04-01 13:05:26 -0700406 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700407 * @param ipAddress router ip address
408 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700409 */
410 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700411 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
412 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800413 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
414 return entry.getValue().deviceId;
415 }
416 }
417
418 return null;
419 }
420
421 /**
422 * Returns the device identifier or data plane identifier (dpid)
423 * of a segment router given its router ipv6 address.
424 *
425 * @param ipAddress router ipv6 address
426 * @return deviceId device identifier
427 */
428 public DeviceId getDeviceId(Ip6Address ipAddress) {
429 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
430 deviceConfigMap.entrySet()) {
431 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700432 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700433 }
434 }
435
436 return null;
437 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700438
439 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700440 * Returns the configured port ip addresses for a segment router.
441 * These addresses serve as gateway IP addresses for the subnets configured
442 * on those ports.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700443 *
444 * @param deviceId device identifier
Saurav Dasc28b3432015-10-30 17:45:38 -0700445 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700446 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800447 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700448 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
449 if (srinfo != null) {
450 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
451 srinfo.gatewayIps.values());
Saurav Dasc28b3432015-10-30 17:45:38 -0700452 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700453 }
Saurav Das7c305372015-10-28 12:39:42 -0700454 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700455 }
456
457 /**
458 * Returns the configured subnet prefixes for a segment router.
459 *
460 * @param deviceId device identifier
Saurav Das7c305372015-10-28 12:39:42 -0700461 * @return list of ip prefixes or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700462 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800463 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700464 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
465 if (srinfo != null) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800466 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chandebfea32016-10-24 14:52:01 -0700467 return builder.addAll(srinfo.subnets.values()).build();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700468 }
Saurav Das7c305372015-10-28 12:39:42 -0700469 return null;
470 }
471
Charles Chan46fdfaf2016-11-09 20:51:44 -0800472
Saurav Das7c305372015-10-28 12:39:42 -0700473 /**
Charles Chan46fdfaf2016-11-09 20:51:44 -0800474 * Returns the subnet configuration of given device and port.
Saurav Das7c305372015-10-28 12:39:42 -0700475 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800476 * @param deviceId Device ID
477 * @param port Port number
Pier Ventreb6a7f342016-11-26 21:05:22 -0800478 * @return The subnets configured on given port or empty set if
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700479 * the port is unconfigured or suppressed.
Saurav Das7c305372015-10-28 12:39:42 -0700480 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800481 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800482 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
483
484 if (isSuppressedPort(connectPoint)) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800485 return Collections.emptySet();
Saurav Das7c305372015-10-28 12:39:42 -0700486 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800487
Pier Ventreb6a7f342016-11-26 21:05:22 -0800488 Set<IpPrefix> subnets =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800489 srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
490 .flatMap(intf -> intf.ipAddressesList().stream())
491 .map(InterfaceIpAddress::subnetAddress)
Charles Chan46fdfaf2016-11-09 20:51:44 -0800492 .collect(Collectors.toSet());
493
Jon Hall31d84782017-01-18 20:15:44 -0800494 if (subnets.isEmpty()) {
Saurav Dasf9332192017-02-18 14:05:44 -0800495 log.debug(NO_SUBNET, connectPoint);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800496 return Collections.emptySet();
Charles Chan46fdfaf2016-11-09 20:51:44 -0800497 }
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700498
499 return subnets;
Pier Ventreb6a7f342016-11-26 21:05:22 -0800500 }
501
502 /**
Charles Chan873661e2017-11-30 15:37:50 -0800503 * Returns all ports that has a subnet that contains any of the given IP addresses.
504 *
505 * @param ips a set of IP addresses
506 * @return a set of connect point that has a subnet that contains any of the given IP addresses
507 */
508 public Set<ConnectPoint> getPortByIps(Set<IpAddress> ips) {
509 return srManager.interfaceService.getInterfaces().stream()
510 .filter(intf -> intf.ipAddressesList().stream().anyMatch(intfAddress ->
511 ips.stream().anyMatch(ip -> intfAddress.subnetAddress().contains(ip))))
512 .map(Interface::connectPoint)
513 .collect(Collectors.toSet());
514 }
515
516 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700517 * Returns the router ip address of segment router that has the
518 * specified ip address in its subnets.
519 *
520 * @param destIpAddress target ip address
521 * @return router ip address
522 */
523 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan70661362016-12-09 12:54:49 -0800524 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
525
526 if (matchIntf == null) {
527 log.debug("No router was found for {}", destIpAddress);
528 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700529 }
530
Charles Chan70661362016-12-09 12:54:49 -0800531 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
532 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
533 if (srInfo == null) {
534 log.debug("No device config was found for {}", routerDeviceId);
535 return null;
536 }
537
Pier Ventreadb4ae62016-11-23 09:57:42 -0800538 return srInfo.ipv4Loopback;
539 }
540
541 /**
542 * Returns the router ipv6 address of segment router that has the
543 * specified ip address in its subnets.
544 *
545 * @param destIpAddress target ip address
546 * @return router ip address
547 */
548 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
549 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
550
551 if (matchIntf == null) {
552 log.debug("No router was found for {}", destIpAddress);
553 return null;
554 }
555
556 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
557 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
558 if (srInfo == null) {
559 log.debug("No device config was found for {}", routerDeviceId);
560 return null;
561 }
562
563 return srInfo.ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700564 }
565
566 /**
567 * Returns the router mac address of segment router that has the
568 * specified ip address as one of its subnet gateway ip address.
569 *
570 * @param gatewayIpAddress router gateway ip address
Saurav Das7c305372015-10-28 12:39:42 -0700571 * @return router mac address or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700572 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800573 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700574 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
575 deviceConfigMap.entrySet()) {
576 if (entry.getValue().gatewayIps.
577 values().contains(gatewayIpAddress)) {
578 return entry.getValue().mac;
579 }
580 }
581
582 log.debug("Cannot find a router for {}", gatewayIpAddress);
583 return null;
584 }
sangho9b169e32015-04-14 16:27:13 -0700585
sangho9b169e32015-04-14 16:27:13 -0700586 /**
Charles Chan35f21e42017-06-26 18:30:18 -0700587 * Checks if the host IP is in any of the subnet defined in the router with the
sangho9b169e32015-04-14 16:27:13 -0700588 * device ID given.
589 *
590 * @param deviceId device identification of the router
591 * @param hostIp host IP address to check
Charles Chan35f21e42017-06-26 18:30:18 -0700592 * @return true if the given IP is within any of the subnet defined in the router,
593 * false if no subnet is defined in the router or if the host is not
594 * within any subnet defined in the router
sangho9b169e32015-04-14 16:27:13 -0700595 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800596 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
sangho9b169e32015-04-14 16:27:13 -0700597
Pier Ventreb6a7f342016-11-26 21:05:22 -0800598 Set<IpPrefix> subnets = getSubnets(deviceId);
sangho9b169e32015-04-14 16:27:13 -0700599 if (subnets == null) {
600 return false;
601 }
602
Pier Ventreb6a7f342016-11-26 21:05:22 -0800603 for (IpPrefix subnet: subnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800604 // Exclude /0 since it is a special case used for default route
605 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho9b169e32015-04-14 16:27:13 -0700606 return true;
607 }
608 }
609
610 return false;
611 }
sangho27462c62015-05-14 00:39:53 -0700612
613 /**
Charles Chandebfea32016-10-24 14:52:01 -0700614 * Checks if the IP is in the subnet defined on given connect point.
615 *
616 * @param connectPoint Connect point
617 * @param ip The IP address to check
618 * @return True if the IP belongs to the subnet.
619 * False if the IP does not belong to the subnet, or
620 * there is no subnet configuration on given connect point.
621 */
622 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Charles Chan35f21e42017-06-26 18:30:18 -0700623 return getPortSubnets(connectPoint.deviceId(), connectPoint.port()).stream()
624 .anyMatch(ipPrefix -> ipPrefix.contains(ip));
Charles Chandebfea32016-10-24 14:52:01 -0700625 }
626
627 /**
sangho27462c62015-05-14 00:39:53 -0700628 * Returns the ports corresponding to the adjacency Sid given.
629 *
630 * @param deviceId device identification of the router
631 * @param sid adjacency Sid
Charles Chan9bec8a32015-12-01 10:00:51 -0800632 * @return set of port numbers
sangho27462c62015-05-14 00:39:53 -0700633 */
Charles Chan9bec8a32015-12-01 10:00:51 -0800634 public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700635 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800636 return srinfo != null ?
637 ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
638 ImmutableSet.copyOf(new HashSet<>());
sangho27462c62015-05-14 00:39:53 -0700639 }
640
641 /**
642 * Check if the Sid given is whether adjacency Sid of the router device or not.
643 *
644 * @param deviceId device identification of the router
645 * @param sid Sid to check
646 * @return true if the Sid given is the adjacency Sid of the device,
647 * otherwise false
648 */
649 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700650 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800651 return srinfo != null && srinfo.adjacencySids.containsKey(sid);
sangho27462c62015-05-14 00:39:53 -0700652 }
Charles Chan43547ca2016-02-10 20:46:58 -0800653
Charles Chanc91c8782016-03-30 17:54:24 -0700654 /**
Charles Chanc22cef32016-04-29 14:38:22 -0700655 * Add subnet to specific connect point.
656 *
657 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800658 * @param ipPrefix subnet being added to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700659 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800660 public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700661 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800662 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700663 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
664 if (srinfo == null) {
665 log.warn("Device {} is not configured. Abort.", cp.deviceId());
666 return;
667 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800668 srinfo.subnets.put(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700669 }
670
671 /**
672 * Remove subnet from specific connect point.
673 *
674 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800675 * @param ipPrefix subnet being removed to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700676 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800677 public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700678 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800679 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700680 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
681 if (srinfo == null) {
682 log.warn("Device {} is not configured. Abort.", cp.deviceId());
683 return;
684 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800685 srinfo.subnets.remove(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700686 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800687
688 private boolean isSuppressedPort(ConnectPoint connectPoint) {
689 SegmentRoutingAppConfig appConfig = srManager.cfgService
Ray Milkeyb85de082017-04-05 09:42:04 -0700690 .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800691 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chandebfea32016-10-24 14:52:01 -0700692 log.info("Interface configuration on port {} is ignored", connectPoint);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800693 return true;
694 }
695 return false;
696 }
Saurav Das261c3002017-06-13 15:35:54 -0700697
698 public boolean isPairedEdge(DeviceId deviceId) throws DeviceConfigNotFoundException {
699 if (!isEdgeDevice(deviceId)) {
700 return false;
701 }
702 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
703 return (srinfo.pairDeviceId == null) ? false : true;
704 }
705
706 public DeviceId getPairDeviceId(DeviceId deviceId) throws DeviceConfigNotFoundException {
707 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
708 if (srinfo != null) {
709 return srinfo.pairDeviceId;
710 } else {
711 String message = "getPairDeviceId fails for device: " + deviceId + ".";
712 throw new DeviceConfigNotFoundException(message);
713 }
714 }
715
716 public PortNumber getPairLocalPort(DeviceId deviceId)
717 throws DeviceConfigNotFoundException {
718 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
719 if (srinfo != null) {
720 return srinfo.pairLocalPort;
721 } else {
722 String message = "getPairLocalPort fails for device: " + deviceId + ".";
723 throw new DeviceConfigNotFoundException(message);
724 }
725 }
726
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800727}