blob: 321cf40cf267e0f606c915d2a6863c7c8c00d12a [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;
Ray Milkeyc2567832017-08-15 10:16:43 -070030import org.onosproject.net.config.ConfigException;
31import org.onosproject.net.config.basics.InterfaceConfig;
Ray Milkeyc2d43be2017-08-03 11:58:29 -070032import org.onosproject.net.intf.Interface;
Charles Chane7c61022015-10-07 14:21:45 -070033import org.onosproject.net.ConnectPoint;
Charles Chane7c61022015-10-07 14:21:45 -070034import org.onosproject.net.host.InterfaceIpAddress;
sangho80f11cb2015-04-01 13:05:26 -070035import org.onosproject.net.DeviceId;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070036import org.onosproject.net.PortNumber;
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;
Pier Ventreb6a7f342016-11-26 21:05:22 -080042import java.util.Collections;
sangho80f11cb2015-04-01 13:05:26 -070043import java.util.HashMap;
Charles Chan9bec8a32015-12-01 10:00:51 -080044import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070045import java.util.List;
46import java.util.Map;
Charles Chan72f556a2015-10-05 17:50:33 -070047import java.util.Set;
Saurav Das7c305372015-10-28 12:39:42 -070048import java.util.concurrent.ConcurrentHashMap;
Charles Chan46fdfaf2016-11-09 20:51:44 -080049import java.util.stream.Collectors;
sangho80f11cb2015-04-01 13:05:26 -070050
Charles Chanc22cef32016-04-29 14:38:22 -070051import static com.google.common.base.Preconditions.checkNotNull;
52
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070053/**
54 * Segment Routing configuration component that reads the
55 * segment routing related configuration from Network Configuration Manager
56 * component and organizes in more accessible formats.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070057 */
sangho80f11cb2015-04-01 13:05:26 -070058public class DeviceConfiguration implements DeviceProperties {
59
Charles Chan46fdfaf2016-11-09 20:51:44 -080060 private static final String NO_SUBNET = "No subnet configured on {}";
61
Charles Chan43547ca2016-02-10 20:46:58 -080062 private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class);
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -070063 private final List<Integer> allSegmentIds = new ArrayList<>();
Charles Chanb7f75ac2016-01-11 18:28:54 -080064 private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
Charles Chan46fdfaf2016-11-09 20:51:44 -080065 private SegmentRoutingManager srManager;
sangho80f11cb2015-04-01 13:05:26 -070066
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070067 private class SegmentRouterInfo {
Pier Ventreadb4ae62016-11-23 09:57:42 -080068 int ipv4NodeSid;
69 int ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070070 DeviceId deviceId;
Pier Ventreadb4ae62016-11-23 09:57:42 -080071 Ip4Address ipv4Loopback;
72 Ip6Address ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070073 MacAddress mac;
74 boolean isEdge;
Pier Ventreb6a7f342016-11-26 21:05:22 -080075 SetMultimap<PortNumber, IpAddress> gatewayIps;
76 SetMultimap<PortNumber, IpPrefix> subnets;
Charles Chan9bec8a32015-12-01 10:00:51 -080077 Map<Integer, Set<Integer>> adjacencySids;
Saurav Das261c3002017-06-13 15:35:54 -070078 DeviceId pairDeviceId;
79 PortNumber pairLocalPort;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070080 int pwRoutingLabel;
Charles Chan2b078ae2015-10-14 11:24:40 -070081
82 public SegmentRouterInfo() {
Pier Ventreb6a7f342016-11-26 21:05:22 -080083 gatewayIps = HashMultimap.create();
Charles Chan82ab1932016-01-30 23:22:37 -080084 subnets = HashMultimap.create();
Charles Chan2b078ae2015-10-14 11:24:40 -070085 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070086 }
sangho80f11cb2015-04-01 13:05:26 -070087
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070088 /**
Charles Chanb7f75ac2016-01-11 18:28:54 -080089 * Constructs device configuration for all Segment Router devices,
90 * organizing the data into various maps for easier access.
Brian O'Connor65eeb572015-10-09 17:03:44 -070091 *
Charles Chan46fdfaf2016-11-09 20:51:44 -080092 * @param srManager Segment Routing Manager
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070093 */
Charles Chan46fdfaf2016-11-09 20:51:44 -080094 public DeviceConfiguration(SegmentRoutingManager srManager) {
95 this.srManager = srManager;
Saurav Das261c3002017-06-13 15:35:54 -070096 updateConfig();
97 }
Charles Chan57bd98c2016-02-22 19:27:29 -080098
Saurav Das261c3002017-06-13 15:35:54 -070099 public void updateConfig() {
Charles Chane7c61022015-10-07 14:21:45 -0700100 // Read config from device subject, excluding gatewayIps and subnets.
101 Set<DeviceId> deviceSubjects =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800102 srManager.cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700103 deviceSubjects.forEach(subject -> {
Charles Chan82ab1932016-01-30 23:22:37 -0800104 SegmentRoutingDeviceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800105 srManager.cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700106 SegmentRouterInfo info = new SegmentRouterInfo();
Charles Chan72f556a2015-10-05 17:50:33 -0700107 info.deviceId = subject;
Pier Ventreadb4ae62016-11-23 09:57:42 -0800108 info.ipv4NodeSid = config.nodeSidIPv4();
109 info.ipv6NodeSid = config.nodeSidIPv6();
110 info.ipv4Loopback = config.routerIpv4();
111 info.ipv6Loopback = config.routerIpv6();
Charles Chan9bec8a32015-12-01 10:00:51 -0800112 info.mac = config.routerMac();
Charles Chan72f556a2015-10-05 17:50:33 -0700113 info.isEdge = config.isEdgeRouter();
Charles Chan9bec8a32015-12-01 10:00:51 -0800114 info.adjacencySids = config.adjacencySids();
Saurav Das261c3002017-06-13 15:35:54 -0700115 info.pairDeviceId = config.pairDeviceId();
116 info.pairLocalPort = config.pairLocalPort();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700117 info.pwRoutingLabel = info.ipv4NodeSid + 1000;
Charles Chanb7f75ac2016-01-11 18:28:54 -0800118 deviceConfigMap.put(info.deviceId, info);
Charles Chan68363b12017-06-26 15:25:09 -0700119 log.debug("Read device config for device: {}", info.deviceId);
Pier Ventreadb4ae62016-11-23 09:57:42 -0800120 /*
121 * IPv6 sid is not inserted. this part of the code is not used for now.
122 */
123 allSegmentIds.add(info.ipv4NodeSid);
Charles Chan72f556a2015-10-05 17:50:33 -0700124 });
Charles Chane7c61022015-10-07 14:21:45 -0700125
Charles Chan46fdfaf2016-11-09 20:51:44 -0800126 // Read gatewayIps and subnets from port subject. Ignore suppressed ports.
127 Set<ConnectPoint> portSubjects = srManager.cfgService
128 .getSubjects(ConnectPoint.class, InterfaceConfig.class);
129 portSubjects.stream().filter(subject -> !isSuppressedPort(subject)).forEach(subject -> {
Charles Chane7c61022015-10-07 14:21:45 -0700130 InterfaceConfig config =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800131 srManager.cfgService.getConfig(subject, InterfaceConfig.class);
Charles Chane7c61022015-10-07 14:21:45 -0700132 Set<Interface> networkInterfaces;
133 try {
134 networkInterfaces = config.getInterfaces();
135 } catch (ConfigException e) {
136 log.error("Error loading port configuration");
137 return;
138 }
139 networkInterfaces.forEach(networkInterface -> {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800140 VlanId vlanId = networkInterface.vlan();
141 ConnectPoint connectPoint = networkInterface.connectPoint();
142 DeviceId dpid = connectPoint.deviceId();
143 PortNumber port = connectPoint.port();
Charles Chan6191aca2017-09-12 12:09:22 -0700144 MacAddress mac = networkInterface.mac();
Charles Chanb7f75ac2016-01-11 18:28:54 -0800145 SegmentRouterInfo info = deviceConfigMap.get(dpid);
Charles Chane7c61022015-10-07 14:21:45 -0700146
Charles Chan2b078ae2015-10-14 11:24:40 -0700147 // skip if there is no corresponding device for this ConenctPoint
148 if (info != null) {
Charles Chanb7f75ac2016-01-11 18:28:54 -0800149 // Extract subnet information
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800150 List<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddressesList();
Charles Chan2b078ae2015-10-14 11:24:40 -0700151 interfaceAddresses.forEach(interfaceAddress -> {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800152 // Do not add /0, /32 and /128 to gateway IP list
Charles Chan82ab1932016-01-30 23:22:37 -0800153 int prefixLength = interfaceAddress.subnetAddress().prefixLength();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800154 IpPrefix ipPrefix = interfaceAddress.subnetAddress();
155 if (ipPrefix.isIp4()) {
156 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
157 info.gatewayIps.put(port, interfaceAddress.ipAddress());
158 }
159 info.subnets.put(port, interfaceAddress.subnetAddress());
160 } else {
161 if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET6_MASK_LENGTH) {
162 info.gatewayIps.put(port, interfaceAddress.ipAddress());
163 }
164 info.subnets.put(port, interfaceAddress.subnetAddress());
Charles Chan82ab1932016-01-30 23:22:37 -0800165 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700166 });
Charles Chan6191aca2017-09-12 12:09:22 -0700167
168 // Override interface mac with router mac
169 if (!mac.equals(info.mac)) {
170 ArrayNode array = (ArrayNode) config.node();
171 for (JsonNode intfNode : array) {
172 ObjectNode objNode = (ObjectNode) intfNode;
173 objNode.put(InterfaceConfig.MAC, info.mac.toString());
174 }
175 srManager.cfgService.applyConfig(connectPoint, InterfaceConfig.class, array);
176 }
Charles Chan2b078ae2015-10-14 11:24:40 -0700177 }
Charles Chane7c61022015-10-07 14:21:45 -0700178 });
Pier Luigi6a2643a2017-01-31 09:35:05 -0800179 // We register the connect point with the NRS.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800180 srManager.registerConnectPoint(subject);
Charles Chane7c61022015-10-07 14:21:45 -0700181 });
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700182 }
183
Saurav Das261c3002017-06-13 15:35:54 -0700184
sangho80f11cb2015-04-01 13:05:26 -0700185 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800186 public boolean isConfigured(DeviceId deviceId) {
187 return deviceConfigMap.get(deviceId) != null;
188 }
189
190 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800191 public int getIPv4SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700192 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700193 log.info("DEVICE MAP IS {}", deviceConfigMap);
Saurav Das7c305372015-10-28 12:39:42 -0700194 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800195 log.trace("getIPv4SegmentId for device{} is {}", deviceId, srinfo.ipv4NodeSid);
196 return srinfo.ipv4NodeSid;
sangho80f11cb2015-04-01 13:05:26 -0700197 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800198 String message = "getIPv4SegmentId fails for device: " + deviceId + ".";
199 throw new DeviceConfigNotFoundException(message);
200 }
201 }
202
203 @Override
204 public int getIPv6SegmentId(DeviceId deviceId) throws DeviceConfigNotFoundException {
205 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
206 if (srinfo != null) {
207 log.trace("getIPv6SegmentId for device{} is {}", deviceId, srinfo.ipv6NodeSid);
208 return srinfo.ipv6NodeSid;
209 } else {
210 String message = "getIPv6SegmentId fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800211 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700212 }
213 }
214
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700215 @Override
216 public int getPWRoutingLabel(DeviceId deviceId) throws DeviceConfigNotFoundException {
217 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
218 if (srinfo != null) {
219 log.trace("pwRoutingLabel for device{} is {}", deviceId, srinfo.pwRoutingLabel);
220 return srinfo.pwRoutingLabel;
221 } else {
222 String message = "getPWRoutingLabel fails for device: " + deviceId + ".";
223 throw new DeviceConfigNotFoundException(message);
224 }
225 }
226
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700227 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800228 * Returns the IPv4 Node segment id of a segment router given its Router mac address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700229 *
230 * @param routerMac router mac address
Saurav Das7c305372015-10-28 12:39:42 -0700231 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700232 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800233 public int getIPv4SegmentId(MacAddress routerMac) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700234 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
235 deviceConfigMap.entrySet()) {
236 if (entry.getValue().mac.equals(routerMac)) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800237 return entry.getValue().ipv4NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700238 }
239 }
sangho80f11cb2015-04-01 13:05:26 -0700240
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700241 return -1;
242 }
243
244 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800245 * Returns the IPv6 Node segment id of a segment router given its Router mac address.
246 *
247 * @param routerMac router mac address
248 * @return node segment id, or -1 if not found in config
249 */
250 public int getIPv6SegmentId(MacAddress routerMac) {
251 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
252 deviceConfigMap.entrySet()) {
253 if (entry.getValue().mac.equals(routerMac)) {
254 return entry.getValue().ipv6NodeSid;
255 }
256 }
257
258 return -1;
259 }
260
261 /**
262 * Returns the IPv4 Node segment id of a segment router given its Router ip address.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700263 *
264 * @param routerAddress router ip address
Saurav Das7c305372015-10-28 12:39:42 -0700265 * @return node segment id, or -1 if not found in config
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700266 */
Pier Ventreadb4ae62016-11-23 09:57:42 -0800267 public int getIPv4SegmentId(Ip4Address routerAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700268 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
269 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800270 if (entry.getValue().ipv4Loopback.equals(routerAddress)) {
271 return entry.getValue().ipv4NodeSid;
272 }
273 }
274
275 return -1;
276 }
277
278 /**
279 * Returns the IPv6 Node segment id of a segment router given its Router ip address.
280 *
281 * @param routerAddress router ip address
282 * @return node segment id, or -1 if not found in config
283 */
284 public int getIPv6SegmentId(Ip6Address routerAddress) {
285 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
286 deviceConfigMap.entrySet()) {
287 if (entry.getValue().ipv6Loopback.equals(routerAddress)) {
288 return entry.getValue().ipv6NodeSid;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700289 }
290 }
291
292 return -1;
293 }
294
sangho80f11cb2015-04-01 13:05:26 -0700295 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800296 public MacAddress getDeviceMac(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700297 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
298 if (srinfo != null) {
Saurav Das7c305372015-10-28 12:39:42 -0700299 return srinfo.mac;
sangho80f11cb2015-04-01 13:05:26 -0700300 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800301 String message = "getDeviceMac fails for device: " + deviceId + ".";
302 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700303 }
304 }
305
Charles Chan319d1a22015-11-03 10:42:14 -0800306 @Override
Pier Ventreadb4ae62016-11-23 09:57:42 -0800307 public Ip4Address getRouterIpv4(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700308 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
309 if (srinfo != null) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800310 log.trace("getRouterIpv4 for device{} is {}", deviceId, srinfo.ipv4Loopback);
311 return srinfo.ipv4Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700312 } else {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800313 String message = "getRouterIpv4 fails for device: " + deviceId + ".";
314 throw new DeviceConfigNotFoundException(message);
315 }
316 }
317
318 @Override
319 public Ip6Address getRouterIpv6(DeviceId deviceId) throws DeviceConfigNotFoundException {
320 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
321 if (srinfo != null) {
322 log.trace("getRouterIpv6 for device{} is {}", deviceId, srinfo.ipv6Loopback);
323 return srinfo.ipv6Loopback;
324 } else {
325 String message = "getRouterIpv6 fails for device: " + deviceId + ".";
Charles Chan319d1a22015-11-03 10:42:14 -0800326 throw new DeviceConfigNotFoundException(message);
sangho80f11cb2015-04-01 13:05:26 -0700327 }
sangho80f11cb2015-04-01 13:05:26 -0700328 }
329
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700330 @Override
Charles Chan319d1a22015-11-03 10:42:14 -0800331 public boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException {
Saurav Das7c305372015-10-28 12:39:42 -0700332 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
333 if (srinfo != null) {
334 log.trace("isEdgeDevice for device{} is {}", deviceId, srinfo.isEdge);
335 return srinfo.isEdge;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700336 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800337 String message = "isEdgeDevice fails for device: " + deviceId + ".";
338 throw new DeviceConfigNotFoundException(message);
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700339 }
340 }
341
sangho80f11cb2015-04-01 13:05:26 -0700342 @Override
343 public List<Integer> getAllDeviceSegmentIds() {
344 return allSegmentIds;
345 }
346
Charles Chan77277672015-10-20 16:24:19 -0700347 @Override
Pier Ventreb6a7f342016-11-26 21:05:22 -0800348 public Map<IpPrefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId)
Saurav Das52d4ed72016-03-28 19:00:18 -0700349 throws DeviceConfigNotFoundException {
350 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
351 if (srinfo == null) {
352 String message = "getSubnetPortsMap fails for device: " + deviceId + ".";
353 throw new DeviceConfigNotFoundException(message);
354 }
Charles Chan77277672015-10-20 16:24:19 -0700355 // Construct subnet-port mapping from port-subnet mapping
Pier Ventreb6a7f342016-11-26 21:05:22 -0800356 SetMultimap<PortNumber, IpPrefix> portSubnetMap = srinfo.subnets;
357 Map<IpPrefix, List<PortNumber>> subnetPortMap = new HashMap<>();
Charles Chan82ab1932016-01-30 23:22:37 -0800358
359 portSubnetMap.entries().forEach(entry -> {
360 PortNumber port = entry.getKey();
Pier Ventreb6a7f342016-11-26 21:05:22 -0800361 IpPrefix subnet = entry.getValue();
Charles Chan82ab1932016-01-30 23:22:37 -0800362
Pier Ventreb6a7f342016-11-26 21:05:22 -0800363 if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
364 subnet.prefixLength() == IpPrefix.MAX_INET6_MASK_LENGTH) {
Charles Chanbbd004c2016-02-16 23:14:49 -0800365 return;
366 }
367
Charles Chan77277672015-10-20 16:24:19 -0700368 if (subnetPortMap.containsKey(subnet)) {
369 subnetPortMap.get(subnet).add(port);
370 } else {
371 ArrayList<PortNumber> ports = new ArrayList<>();
372 ports.add(port);
373 subnetPortMap.put(subnet, ports);
374 }
375 });
Charles Chan77277672015-10-20 16:24:19 -0700376 return subnetPortMap;
377 }
378
sangho80f11cb2015-04-01 13:05:26 -0700379 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700380 * Returns the device identifier or data plane identifier (dpid)
381 * of a segment router given its segment id.
sangho80f11cb2015-04-01 13:05:26 -0700382 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700383 * @param sid segment id
384 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700385 */
386 public DeviceId getDeviceId(int sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700387 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
388 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800389 if (entry.getValue().ipv4NodeSid == sid ||
390 entry.getValue().ipv6NodeSid == sid) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700391 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700392 }
393 }
394
395 return null;
396 }
397
398 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700399 * Returns the device identifier or data plane identifier (dpid)
400 * of a segment router given its router ip address.
sangho80f11cb2015-04-01 13:05:26 -0700401 *
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700402 * @param ipAddress router ip address
403 * @return deviceId device identifier
sangho80f11cb2015-04-01 13:05:26 -0700404 */
405 public DeviceId getDeviceId(Ip4Address ipAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700406 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
407 deviceConfigMap.entrySet()) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800408 if (entry.getValue().ipv4Loopback.equals(ipAddress)) {
409 return entry.getValue().deviceId;
410 }
411 }
412
413 return null;
414 }
415
416 /**
417 * Returns the device identifier or data plane identifier (dpid)
418 * of a segment router given its router ipv6 address.
419 *
420 * @param ipAddress router ipv6 address
421 * @return deviceId device identifier
422 */
423 public DeviceId getDeviceId(Ip6Address ipAddress) {
424 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
425 deviceConfigMap.entrySet()) {
426 if (entry.getValue().ipv6Loopback.equals(ipAddress)) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700427 return entry.getValue().deviceId;
sangho80f11cb2015-04-01 13:05:26 -0700428 }
429 }
430
431 return null;
432 }
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700433
434 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700435 * Returns the configured port ip addresses for a segment router.
436 * These addresses serve as gateway IP addresses for the subnets configured
437 * on those ports.
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700438 *
439 * @param deviceId device identifier
Saurav Dasc28b3432015-10-30 17:45:38 -0700440 * @return immutable set of ip addresses configured on the ports or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700441 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800442 public Set<IpAddress> getPortIPs(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700443 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
444 if (srinfo != null) {
445 log.trace("getSubnetGatewayIps for device{} is {}", deviceId,
446 srinfo.gatewayIps.values());
Saurav Dasc28b3432015-10-30 17:45:38 -0700447 return ImmutableSet.copyOf(srinfo.gatewayIps.values());
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700448 }
Saurav Das7c305372015-10-28 12:39:42 -0700449 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700450 }
451
452 /**
453 * Returns the configured subnet prefixes for a segment router.
454 *
455 * @param deviceId device identifier
Saurav Das7c305372015-10-28 12:39:42 -0700456 * @return list of ip prefixes or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700457 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800458 public Set<IpPrefix> getSubnets(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700459 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
460 if (srinfo != null) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800461 ImmutableSet.Builder<IpPrefix> builder = ImmutableSet.builder();
Charles Chandebfea32016-10-24 14:52:01 -0700462 return builder.addAll(srinfo.subnets.values()).build();
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700463 }
Saurav Das7c305372015-10-28 12:39:42 -0700464 return null;
465 }
466
Charles Chan46fdfaf2016-11-09 20:51:44 -0800467
Saurav Das7c305372015-10-28 12:39:42 -0700468 /**
Charles Chan46fdfaf2016-11-09 20:51:44 -0800469 * Returns the subnet configuration of given device and port.
Saurav Das7c305372015-10-28 12:39:42 -0700470 *
Charles Chan46fdfaf2016-11-09 20:51:44 -0800471 * @param deviceId Device ID
472 * @param port Port number
Pier Ventreb6a7f342016-11-26 21:05:22 -0800473 * @return The subnets configured on given port or empty set if
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700474 * the port is unconfigured or suppressed.
Saurav Das7c305372015-10-28 12:39:42 -0700475 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800476 public Set<IpPrefix> getPortSubnets(DeviceId deviceId, PortNumber port) {
Charles Chan46fdfaf2016-11-09 20:51:44 -0800477 ConnectPoint connectPoint = new ConnectPoint(deviceId, port);
478
479 if (isSuppressedPort(connectPoint)) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800480 return Collections.emptySet();
Saurav Das7c305372015-10-28 12:39:42 -0700481 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800482
Pier Ventreb6a7f342016-11-26 21:05:22 -0800483 Set<IpPrefix> subnets =
Charles Chan46fdfaf2016-11-09 20:51:44 -0800484 srManager.interfaceService.getInterfacesByPort(connectPoint).stream()
485 .flatMap(intf -> intf.ipAddressesList().stream())
486 .map(InterfaceIpAddress::subnetAddress)
Charles Chan46fdfaf2016-11-09 20:51:44 -0800487 .collect(Collectors.toSet());
488
Jon Hall31d84782017-01-18 20:15:44 -0800489 if (subnets.isEmpty()) {
Saurav Dasf9332192017-02-18 14:05:44 -0800490 log.debug(NO_SUBNET, connectPoint);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800491 return Collections.emptySet();
Charles Chan46fdfaf2016-11-09 20:51:44 -0800492 }
Charles Chan2f4d2bc2017-04-24 16:21:01 -0700493
494 return subnets;
Pier Ventreb6a7f342016-11-26 21:05:22 -0800495 }
496
497 /**
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700498 * Returns the router ip address of segment router that has the
499 * specified ip address in its subnets.
500 *
501 * @param destIpAddress target ip address
502 * @return router ip address
503 */
504 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
Charles Chan70661362016-12-09 12:54:49 -0800505 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
506
507 if (matchIntf == null) {
508 log.debug("No router was found for {}", destIpAddress);
509 return null;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700510 }
511
Charles Chan70661362016-12-09 12:54:49 -0800512 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
513 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
514 if (srInfo == null) {
515 log.debug("No device config was found for {}", routerDeviceId);
516 return null;
517 }
518
Pier Ventreadb4ae62016-11-23 09:57:42 -0800519 return srInfo.ipv4Loopback;
520 }
521
522 /**
523 * Returns the router ipv6 address of segment router that has the
524 * specified ip address in its subnets.
525 *
526 * @param destIpAddress target ip address
527 * @return router ip address
528 */
529 public Ip6Address getRouterIpAddressForASubnetHost(Ip6Address destIpAddress) {
530 Interface matchIntf = srManager.interfaceService.getMatchingInterface(destIpAddress);
531
532 if (matchIntf == null) {
533 log.debug("No router was found for {}", destIpAddress);
534 return null;
535 }
536
537 DeviceId routerDeviceId = matchIntf.connectPoint().deviceId();
538 SegmentRouterInfo srInfo = deviceConfigMap.get(routerDeviceId);
539 if (srInfo == null) {
540 log.debug("No device config was found for {}", routerDeviceId);
541 return null;
542 }
543
544 return srInfo.ipv6Loopback;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700545 }
546
547 /**
548 * Returns the router mac address of segment router that has the
549 * specified ip address as one of its subnet gateway ip address.
550 *
551 * @param gatewayIpAddress router gateway ip address
Saurav Das7c305372015-10-28 12:39:42 -0700552 * @return router mac address or null if not found
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700553 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800554 public MacAddress getRouterMacForAGatewayIp(IpAddress gatewayIpAddress) {
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -0700555 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
556 deviceConfigMap.entrySet()) {
557 if (entry.getValue().gatewayIps.
558 values().contains(gatewayIpAddress)) {
559 return entry.getValue().mac;
560 }
561 }
562
563 log.debug("Cannot find a router for {}", gatewayIpAddress);
564 return null;
565 }
sangho9b169e32015-04-14 16:27:13 -0700566
sangho9b169e32015-04-14 16:27:13 -0700567 /**
Charles Chan35f21e42017-06-26 18:30:18 -0700568 * Checks if the host IP is in any of the subnet defined in the router with the
sangho9b169e32015-04-14 16:27:13 -0700569 * device ID given.
570 *
571 * @param deviceId device identification of the router
572 * @param hostIp host IP address to check
Charles Chan35f21e42017-06-26 18:30:18 -0700573 * @return true if the given IP is within any of the subnet defined in the router,
574 * false if no subnet is defined in the router or if the host is not
575 * within any subnet defined in the router
sangho9b169e32015-04-14 16:27:13 -0700576 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800577 public boolean inSameSubnet(DeviceId deviceId, IpAddress hostIp) {
sangho9b169e32015-04-14 16:27:13 -0700578
Pier Ventreb6a7f342016-11-26 21:05:22 -0800579 Set<IpPrefix> subnets = getSubnets(deviceId);
sangho9b169e32015-04-14 16:27:13 -0700580 if (subnets == null) {
581 return false;
582 }
583
Pier Ventreb6a7f342016-11-26 21:05:22 -0800584 for (IpPrefix subnet: subnets) {
Charles Chan82ab1932016-01-30 23:22:37 -0800585 // Exclude /0 since it is a special case used for default route
586 if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
sangho9b169e32015-04-14 16:27:13 -0700587 return true;
588 }
589 }
590
591 return false;
592 }
sangho27462c62015-05-14 00:39:53 -0700593
594 /**
Charles Chandebfea32016-10-24 14:52:01 -0700595 * Checks if the IP is in the subnet defined on given connect point.
596 *
597 * @param connectPoint Connect point
598 * @param ip The IP address to check
599 * @return True if the IP belongs to the subnet.
600 * False if the IP does not belong to the subnet, or
601 * there is no subnet configuration on given connect point.
602 */
603 public boolean inSameSubnet(ConnectPoint connectPoint, IpAddress ip) {
Charles Chan35f21e42017-06-26 18:30:18 -0700604 return getPortSubnets(connectPoint.deviceId(), connectPoint.port()).stream()
605 .anyMatch(ipPrefix -> ipPrefix.contains(ip));
Charles Chandebfea32016-10-24 14:52:01 -0700606 }
607
608 /**
sangho27462c62015-05-14 00:39:53 -0700609 * Returns the ports corresponding to the adjacency Sid given.
610 *
611 * @param deviceId device identification of the router
612 * @param sid adjacency Sid
Charles Chan9bec8a32015-12-01 10:00:51 -0800613 * @return set of port numbers
sangho27462c62015-05-14 00:39:53 -0700614 */
Charles Chan9bec8a32015-12-01 10:00:51 -0800615 public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700616 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800617 return srinfo != null ?
618 ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
619 ImmutableSet.copyOf(new HashSet<>());
sangho27462c62015-05-14 00:39:53 -0700620 }
621
622 /**
623 * Check if the Sid given is whether adjacency Sid of the router device or not.
624 *
625 * @param deviceId device identification of the router
626 * @param sid Sid to check
627 * @return true if the Sid given is the adjacency Sid of the device,
628 * otherwise false
629 */
630 public boolean isAdjacencySid(DeviceId deviceId, int sid) {
Saurav Das7c305372015-10-28 12:39:42 -0700631 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
Charles Chan9bec8a32015-12-01 10:00:51 -0800632 return srinfo != null && srinfo.adjacencySids.containsKey(sid);
sangho27462c62015-05-14 00:39:53 -0700633 }
Charles Chan43547ca2016-02-10 20:46:58 -0800634
Charles Chanc91c8782016-03-30 17:54:24 -0700635 /**
Charles Chanc22cef32016-04-29 14:38:22 -0700636 * Add subnet to specific connect point.
637 *
638 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800639 * @param ipPrefix subnet being added to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700640 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800641 public void addSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700642 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800643 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700644 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
645 if (srinfo == null) {
646 log.warn("Device {} is not configured. Abort.", cp.deviceId());
647 return;
648 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800649 srinfo.subnets.put(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700650 }
651
652 /**
653 * Remove subnet from specific connect point.
654 *
655 * @param cp connect point
Pier Ventreb6a7f342016-11-26 21:05:22 -0800656 * @param ipPrefix subnet being removed to the device
Charles Chanc22cef32016-04-29 14:38:22 -0700657 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800658 public void removeSubnet(ConnectPoint cp, IpPrefix ipPrefix) {
Charles Chanc22cef32016-04-29 14:38:22 -0700659 checkNotNull(cp);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800660 checkNotNull(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700661 SegmentRouterInfo srinfo = deviceConfigMap.get(cp.deviceId());
662 if (srinfo == null) {
663 log.warn("Device {} is not configured. Abort.", cp.deviceId());
664 return;
665 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800666 srinfo.subnets.remove(cp.port(), ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700667 }
Charles Chan46fdfaf2016-11-09 20:51:44 -0800668
669 private boolean isSuppressedPort(ConnectPoint connectPoint) {
670 SegmentRoutingAppConfig appConfig = srManager.cfgService
Ray Milkeyb85de082017-04-05 09:42:04 -0700671 .getConfig(srManager.appId(), SegmentRoutingAppConfig.class);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800672 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chandebfea32016-10-24 14:52:01 -0700673 log.info("Interface configuration on port {} is ignored", connectPoint);
Charles Chan46fdfaf2016-11-09 20:51:44 -0800674 return true;
675 }
676 return false;
677 }
Saurav Das261c3002017-06-13 15:35:54 -0700678
679 public boolean isPairedEdge(DeviceId deviceId) throws DeviceConfigNotFoundException {
680 if (!isEdgeDevice(deviceId)) {
681 return false;
682 }
683 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
684 return (srinfo.pairDeviceId == null) ? false : true;
685 }
686
687 public DeviceId getPairDeviceId(DeviceId deviceId) throws DeviceConfigNotFoundException {
688 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
689 if (srinfo != null) {
690 return srinfo.pairDeviceId;
691 } else {
692 String message = "getPairDeviceId fails for device: " + deviceId + ".";
693 throw new DeviceConfigNotFoundException(message);
694 }
695 }
696
697 public PortNumber getPairLocalPort(DeviceId deviceId)
698 throws DeviceConfigNotFoundException {
699 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
700 if (srinfo != null) {
701 return srinfo.pairLocalPort;
702 } else {
703 String message = "getPairLocalPort fails for device: " + deviceId + ".";
704 throw new DeviceConfigNotFoundException(message);
705 }
706 }
707
Jonathan Hart8fa9ec52016-02-16 10:30:37 -0800708}