blob: 1bdcacd2fac2fc45678b8e1e922fa631895a317d [file] [log] [blame]
Lee Yongjae7c27bb42017-11-17 12:00:45 +09001/*
Jian Li8df54a92018-08-23 17:01:31 +09002 * Copyright 2018-present Open Networking Foundation
Lee Yongjae7c27bb42017-11-17 12:00:45 +09003 *
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 */
16
Jian Li8df54a92018-08-23 17:01:31 +090017package org.onosproject.simplefabric.impl;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090018
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Maps;
21import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
22import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
23import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
24import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
27import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
29import org.apache.felix.scr.annotations.Service;
30import org.onlab.packet.ARP;
31import org.onlab.packet.Ethernet;
Jian Li8df54a92018-08-23 17:01:31 +090032import org.onlab.packet.IPv6;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090033import org.onlab.packet.Ip4Address;
34import org.onlab.packet.Ip6Address;
35import org.onlab.packet.IpAddress;
36import org.onlab.packet.IpPrefix;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090037import org.onlab.packet.MacAddress;
38import org.onlab.packet.VlanId;
39import org.onlab.packet.ndp.NeighborSolicitation;
Jian Li8df54a92018-08-23 17:01:31 +090040import org.onosproject.component.ComponentService;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090041import org.onosproject.core.ApplicationId;
42import org.onosproject.core.CoreService;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090043import org.onosproject.event.ListenerRegistry;
Jian Li8df54a92018-08-23 17:01:31 +090044import org.onosproject.net.ConnectPoint;
45import org.onosproject.net.Host;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090046import org.onosproject.net.config.ConfigFactory;
47import org.onosproject.net.config.NetworkConfigEvent;
48import org.onosproject.net.config.NetworkConfigListener;
49import org.onosproject.net.config.NetworkConfigRegistry;
50import org.onosproject.net.config.NetworkConfigService;
51import org.onosproject.net.config.basics.SubjectFactories;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090052import org.onosproject.net.device.DeviceEvent;
53import org.onosproject.net.device.DeviceListener;
54import org.onosproject.net.device.DeviceService;
55import org.onosproject.net.flow.DefaultTrafficTreatment;
56import org.onosproject.net.flow.TrafficTreatment;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090057import org.onosproject.net.host.HostEvent;
Jian Li8df54a92018-08-23 17:01:31 +090058import org.onosproject.net.host.HostListener;
59import org.onosproject.net.host.HostService;
60import org.onosproject.net.intf.Interface;
61import org.onosproject.net.intf.InterfaceEvent;
62import org.onosproject.net.intf.InterfaceListener;
63import org.onosproject.net.intf.InterfaceService;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090064import org.onosproject.net.packet.DefaultOutboundPacket;
65import org.onosproject.net.packet.OutboundPacket;
Jian Li8df54a92018-08-23 17:01:31 +090066import org.onosproject.net.packet.PacketService;
Jian Lie2d87512018-08-23 17:33:05 +090067import org.onosproject.simplefabric.api.FabricNetwork;
68import org.onosproject.simplefabric.api.FabricRoute;
69import org.onosproject.simplefabric.api.FabricSubnet;
Jian Lic7efc1d2018-08-23 16:37:34 +090070import org.onosproject.simplefabric.api.SimpleFabricEvent;
71import org.onosproject.simplefabric.api.SimpleFabricListener;
72import org.onosproject.simplefabric.api.SimpleFabricService;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090073import org.slf4j.Logger;
74import org.slf4j.LoggerFactory;
75
76import java.io.OutputStream;
77import java.io.PrintStream;
78import java.nio.ByteBuffer;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090079import java.util.Collection;
Jian Li8df54a92018-08-23 17:01:31 +090080import java.util.HashSet;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090081import java.util.Map;
Jian Li8df54a92018-08-23 17:01:31 +090082import java.util.Set;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090083
Jian Li8df54a92018-08-23 17:01:31 +090084import static org.onosproject.simplefabric.api.Constants.ALLOW_ETH_ADDRESS_SELECTOR;
85import static org.onosproject.simplefabric.api.Constants.ALLOW_IPV6;
86import static org.onosproject.simplefabric.api.Constants.APP_ID;
87import static org.onosproject.simplefabric.api.Constants.IDLE_INTERVAL_MSEC;
88import static org.onosproject.simplefabric.api.Constants.REACTIVE_ALLOW_LINK_CP;
89import static org.onosproject.simplefabric.api.Constants.REACTIVE_HASHED_PATH_SELECTION;
90import static org.onosproject.simplefabric.api.Constants.REACTIVE_MATCH_IP_PROTO;
91import static org.onosproject.simplefabric.api.Constants.REACTIVE_SINGLE_TO_SINGLE;
Jian Lie2d87512018-08-23 17:33:05 +090092import static org.onosproject.simplefabric.util.RouteTools.createBinaryString;
Lee Yongjae7c27bb42017-11-17 12:00:45 +090093
94
95/**
96 * Reactive routing configuration manager.
97 */
98@Component(immediate = true)
99@Service
100public class SimpleFabricManager extends ListenerRegistry<SimpleFabricEvent, SimpleFabricListener>
101 implements SimpleFabricService {
102
103 private final Logger log = LoggerFactory.getLogger(getClass());
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected CoreService coreService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900109 protected NetworkConfigService configService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected NetworkConfigRegistry registry;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected DeviceService deviceService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected InterfaceService interfaceService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected HostService hostService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected PacketService packetService;
125
Jian Lie2d87512018-08-23 17:33:05 +0900126 // components to be activated within SimpleFabric
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected ComponentService componentService;
129
130 // SimpleFabric variables
131 private ApplicationId appId = null;
132
Jian Lie2d87512018-08-23 17:33:05 +0900133 // fabric networks
134 private Set<FabricNetwork> fabricNetworks = new HashSet<>();
135 private Set<Interface> networkInterfaces = new HashSet<>();
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900136
137 // Subnet table
Jian Lie2d87512018-08-23 17:33:05 +0900138 private Set<FabricSubnet> fabricSubnets = new HashSet<>();
139 private InvertedRadixTree<FabricSubnet> ip4SubnetTable =
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900140 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
Jian Lie2d87512018-08-23 17:33:05 +0900141 private InvertedRadixTree<FabricSubnet> ip6SubnetTable =
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900142 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
143
Jian Lie2d87512018-08-23 17:33:05 +0900144 // Fabric Route table
145 private Set<FabricRoute> fabricRoutes = new HashSet<>();
146 private InvertedRadixTree<FabricRoute> ip4BorderRouteTable =
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900147 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
Jian Lie2d87512018-08-23 17:33:05 +0900148 private InvertedRadixTree<FabricRoute> ip6BorderRouteTable =
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900149 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
150
Jian Lie2d87512018-08-23 17:33:05 +0900151 // Virtual gateway
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900152 private Map<IpAddress, MacAddress> virtualGatewayIpMacMap = Maps.newConcurrentMap();
153
154 // Refresh monitor thread
155 private Object refreshMonitor = new Object();
156 private boolean doRefresh = false;
157 private boolean doFlush = false;
158 private InternalRefreshThread refreshThread;
159
160 // Listener for Service Events
161 private final InternalNetworkConfigListener configListener = new InternalNetworkConfigListener();
162 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
163 private final InternalHostListener hostListener = new InternalHostListener();
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900164
165 private ConfigFactory<ApplicationId, SimpleFabricConfig> simpleFabricConfigFactory =
166 new ConfigFactory<ApplicationId, SimpleFabricConfig>(
167 SubjectFactories.APP_SUBJECT_FACTORY,
168 SimpleFabricConfig.class, SimpleFabricConfig.KEY) {
169 @Override
170 public SimpleFabricConfig createConfig() {
171 return new SimpleFabricConfig();
172 }
173 };
174
175 @Activate
176 public void activate() {
177 log.info("simple fabric starting");
178
179 if (appId == null) {
180 appId = coreService.registerApplication(APP_ID);
181 }
182
183 // initial refresh
184 refresh();
185
186 configService.addListener(configListener);
187 registry.registerConfigFactory(simpleFabricConfigFactory);
188 deviceService.addListener(deviceListener);
189 hostService.addListener(hostListener);
190
191 componentService.activate(appId, SimpleFabricNeighbour.class.getName());
Jian Lie2d87512018-08-23 17:33:05 +0900192 componentService.activate(appId, SimpleFabricRouting.class.getName());
Jian Li8df54a92018-08-23 17:01:31 +0900193 if (ALLOW_ETH_ADDRESS_SELECTOR) {
Jian Lie2d87512018-08-23 17:33:05 +0900194 componentService.activate(appId, SimpleFabricForwarding.class.getName());
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900195 }
196
197 refreshThread = new InternalRefreshThread();
198 refreshThread.start();
199
200 log.info("simple fabric started");
201 }
202
203 @Deactivate
204 public void deactivate() {
205 log.info("simple fabric stopping");
206
207 componentService.deactivate(appId, SimpleFabricNeighbour.class.getName());
Jian Lie2d87512018-08-23 17:33:05 +0900208 componentService.deactivate(appId, SimpleFabricRouting.class.getName());
Jian Li8df54a92018-08-23 17:01:31 +0900209 if (ALLOW_ETH_ADDRESS_SELECTOR) {
Jian Lie2d87512018-08-23 17:33:05 +0900210 componentService.deactivate(appId, SimpleFabricForwarding.class.getName());
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900211 }
212
213 deviceService.removeListener(deviceListener);
214 hostService.removeListener(hostListener);
215 registry.unregisterConfigFactory(simpleFabricConfigFactory);
216 configService.removeListener(configListener);
217
218 refreshThread.stop();
219 refreshThread = null;
220
221 log.info("simple fabric stopped");
222 }
223
224 // Set up from configuration
Jian Lie2d87512018-08-23 17:33:05 +0900225 // returns found isDirty and refresh listeners are called (true) or not (false)
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900226 private boolean refresh() {
227 log.debug("simple fabric refresh");
228 boolean dirty = false;
229
230 SimpleFabricConfig config = configService.getConfig(coreService.registerApplication(APP_ID),
231 SimpleFabricConfig.class);
232 if (config == null) {
Yuta HIGUCHIc2bf02a2018-03-29 08:40:35 -0700233 log.debug("No simple fabric config available!");
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900234 return false;
235 }
236
Jian Lie2d87512018-08-23 17:33:05 +0900237 // fabricNetworks
238 Set<FabricNetwork> newFabricNetworks = new HashSet<>();
239 Set<Interface> newInterfaces = new HashSet<>();
240 for (FabricNetwork newFabricNetworkConfig : config.fabricNetworks()) {
241 FabricNetwork newFabricNetwork = DefaultFabricNetwork.of(newFabricNetworkConfig);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900242
243 // fill up interfaces and Hosts with active port only
Jian Lie2d87512018-08-23 17:33:05 +0900244 for (String ifaceName : newFabricNetworkConfig.interfaceNames()) {
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900245 Interface iface = getInterfaceByName(ifaceName);
246 if (iface != null && deviceService.isAvailable(iface.connectPoint().deviceId())) {
Jian Lie2d87512018-08-23 17:33:05 +0900247 newFabricNetwork.addInterface(iface);
248 newInterfaces.add(iface);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900249 }
250 }
251 for (Host host : hostService.getHosts()) {
252 // consider host with ip only
253 if (!host.ipAddresses().isEmpty()) {
Lee Yongjae6dc7e4f2017-12-06 16:17:51 +0900254 Interface iface = findAvailableDeviceHostInterface(host);
Jian Lie2d87512018-08-23 17:33:05 +0900255 if (iface != null && newFabricNetwork.contains(iface)) {
256 newFabricNetwork.addHost(host);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900257 }
258 }
259 }
Jian Lie2d87512018-08-23 17:33:05 +0900260 newFabricNetwork.setDirty(true);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900261
Jian Lie2d87512018-08-23 17:33:05 +0900262 // update newFabricNetwork's isDirty flags if same entry already exists
263 for (FabricNetwork prevFabricNetwork : fabricNetworks) {
264 if (prevFabricNetwork.equals(newFabricNetwork)) {
265 newFabricNetwork.setDirty(prevFabricNetwork.isDirty());
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900266 break;
267 }
268 }
Jian Lie2d87512018-08-23 17:33:05 +0900269 newFabricNetworks.add(newFabricNetwork);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900270 }
Jian Lie2d87512018-08-23 17:33:05 +0900271 if (!fabricNetworks.equals(newFabricNetworks)) {
272 fabricNetworks = newFabricNetworks;
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900273 dirty = true;
274 }
Jian Lie2d87512018-08-23 17:33:05 +0900275 if (!networkInterfaces.equals(newInterfaces)) {
276 networkInterfaces = newInterfaces;
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900277 dirty = true;
278 }
279
Jian Lie2d87512018-08-23 17:33:05 +0900280 // default Fabric Subnets
281 Set<FabricSubnet> newFabricSubnets = config.fabricSubnets();
282 InvertedRadixTree<FabricSubnet> newIp4SubnetTable =
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900283 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
Jian Lie2d87512018-08-23 17:33:05 +0900284 InvertedRadixTree<FabricSubnet> newIp6SubnetTable =
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900285 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
286 Map<IpAddress, MacAddress> newVirtualGatewayIpMacMap = Maps.newConcurrentMap();
Jian Lie2d87512018-08-23 17:33:05 +0900287 for (FabricSubnet subnet : newFabricSubnets) {
288 if (subnet.prefix().isIp4()) {
289 newIp4SubnetTable.put(createBinaryString(subnet.prefix()), subnet);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900290 } else {
Jian Lie2d87512018-08-23 17:33:05 +0900291 newIp6SubnetTable.put(createBinaryString(subnet.prefix()), subnet);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900292 }
293 newVirtualGatewayIpMacMap.put(subnet.gatewayIp(), subnet.gatewayMac());
294 }
Jian Lie2d87512018-08-23 17:33:05 +0900295 if (!fabricSubnets.equals(newFabricSubnets)) {
296 fabricSubnets = newFabricSubnets;
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900297 ip4SubnetTable = newIp4SubnetTable;
298 ip6SubnetTable = newIp6SubnetTable;
299 dirty = true;
300 }
301 if (!virtualGatewayIpMacMap.equals(newVirtualGatewayIpMacMap)) {
302 virtualGatewayIpMacMap = newVirtualGatewayIpMacMap;
303 dirty = true;
304 }
305
Jian Lie2d87512018-08-23 17:33:05 +0900306 // fabricRoutes config handling
307 Set<FabricRoute> newFabricRoutes = config.fabricRoutes();
308 if (!fabricRoutes.equals(newFabricRoutes)) {
309 InvertedRadixTree<FabricRoute> newIp4BorderRouteTable =
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900310 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
Jian Lie2d87512018-08-23 17:33:05 +0900311 InvertedRadixTree<FabricRoute> newIp6BorderRouteTable =
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900312 new ConcurrentInvertedRadixTree<>(new DefaultByteArrayNodeFactory());
Jian Lie2d87512018-08-23 17:33:05 +0900313 for (FabricRoute route : newFabricRoutes) {
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900314 if (route.prefix().isIp4()) {
315 newIp4BorderRouteTable.put(createBinaryString(route.prefix()), route);
316 } else {
317 newIp6BorderRouteTable.put(createBinaryString(route.prefix()), route);
318 }
319 }
Jian Lie2d87512018-08-23 17:33:05 +0900320 fabricRoutes = newFabricRoutes;
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900321 ip4BorderRouteTable = newIp4BorderRouteTable;
322 ip6BorderRouteTable = newIp6BorderRouteTable;
323 dirty = true;
324 }
325
326 // notify to SimpleFabric listeners
327 if (dirty) {
328 log.info("simple fabric refresh; notify events");
329 process(new SimpleFabricEvent(SimpleFabricEvent.Type.SIMPLE_FABRIC_UPDATED, "updated"));
330 }
331 return dirty;
332 }
333
334 private Interface getInterfaceByName(String interfaceName) {
335 Interface intf = interfaceService.getInterfaces().stream()
336 .filter(iface -> iface.name().equals(interfaceName))
337 .findFirst()
338 .orElse(null);
339 if (intf == null) {
340 log.warn("simple fabric unknown interface name: {}", interfaceName);
341 }
342 return intf;
343 }
344
345 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900346 public ApplicationId appId() {
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900347 if (appId == null) {
348 appId = coreService.registerApplication(APP_ID);
349 }
350 return appId;
351 }
352
353 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900354 public Collection<FabricNetwork> fabricNetworks() {
355 return ImmutableSet.copyOf(fabricNetworks);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900356 }
357
358 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900359 public Set<FabricSubnet> defaultFabricSubnets() {
360 return ImmutableSet.copyOf(fabricSubnets);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900361 }
362
363 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900364 public Set<FabricRoute> fabricRoutes() {
365 return ImmutableSet.copyOf(fabricRoutes);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900366 }
367
368 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900369 public boolean isVirtualGatewayMac(MacAddress mac) {
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900370 return virtualGatewayIpMacMap.containsValue(mac);
371 }
372
373 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900374 public boolean isFabricNetworkInterface(Interface intf) {
375 return networkInterfaces.contains(intf);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900376 }
377
378 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900379 public MacAddress vMacForIp(IpAddress ip) {
Lee Yongjae6dc7e4f2017-12-06 16:17:51 +0900380 return virtualGatewayIpMacMap.get(ip);
381 }
382
383 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900384 public FabricNetwork fabricNetwork(ConnectPoint port, VlanId vlanId) {
385 for (FabricNetwork fabricNetwork : fabricNetworks) {
386 if (fabricNetwork.contains(port, vlanId)) {
387 return fabricNetwork;
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900388 }
389 }
390 return null;
391 }
392
393 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900394 public FabricNetwork fabricNetwork(String name) {
395 for (FabricNetwork fabricNetwork : fabricNetworks) {
396 if (fabricNetwork.name().equals(name)) {
397 return fabricNetwork;
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900398 }
399 }
400 return null;
401 }
402
403 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900404 public FabricSubnet fabricSubnet(IpAddress ip) {
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900405 if (ip.isIp4()) {
Lee Yongjae6dc7e4f2017-12-06 16:17:51 +0900406 return ip4SubnetTable.getValueForLongestKeyPrefixing(
407 createBinaryString(IpPrefix.valueOf(ip, Ip4Address.BIT_LENGTH)));
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900408 } else {
Lee Yongjae6dc7e4f2017-12-06 16:17:51 +0900409 return ip6SubnetTable.getValueForLongestKeyPrefixing(
410 createBinaryString(IpPrefix.valueOf(ip, Ip6Address.BIT_LENGTH)));
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900411 }
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900412 }
413
414 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900415 public FabricRoute fabricRoute(IpAddress ip) {
416 // ASSUME: ipAddress is out of fabricSubnet
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900417 if (ip.isIp4()) {
Lee Yongjae6dc7e4f2017-12-06 16:17:51 +0900418 return ip4BorderRouteTable.getValueForLongestKeyPrefixing(
419 createBinaryString(IpPrefix.valueOf(ip, Ip4Address.BIT_LENGTH)));
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900420 } else {
Lee Yongjae6dc7e4f2017-12-06 16:17:51 +0900421 return ip6BorderRouteTable.getValueForLongestKeyPrefixing(
422 createBinaryString(IpPrefix.valueOf(ip, Ip6Address.BIT_LENGTH)));
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900423 }
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900424 }
425
426
427 @Override
Jian Lie2d87512018-08-23 17:33:05 +0900428 public Interface hostInterface(Host host) {
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900429 return interfaceService.getInterfaces().stream()
430 .filter(iface -> iface.connectPoint().equals(host.location()) &&
431 iface.vlan().equals(host.vlan()))
432 .findFirst()
433 .orElse(null);
434 }
435
Lee Yongjae6dc7e4f2017-12-06 16:17:51 +0900436 private Interface findAvailableDeviceHostInterface(Host host) {
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900437 return interfaceService.getInterfaces().stream()
438 .filter(iface -> iface.connectPoint().equals(host.location()) &&
439 iface.vlan().equals(host.vlan()))
440 .filter(iface -> deviceService.isAvailable(iface.connectPoint().deviceId()))
441 .findFirst()
442 .orElse(null);
443 }
444
445 @Override
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900446 public boolean requestMac(IpAddress ip) {
Jian Lie2d87512018-08-23 17:33:05 +0900447 FabricSubnet fabricSubnet = fabricSubnet(ip);
448 if (fabricSubnet == null) {
449 log.warn("simple fabric request mac failed for unknown fabricSubnet: {}", ip);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900450 return false;
451 }
Jian Lida0b4852018-08-29 20:40:44 +0900452 FabricNetwork fabricNetwork = fabricNetwork(fabricSubnet.networkName());
Jian Lie2d87512018-08-23 17:33:05 +0900453 if (fabricNetwork == null) {
454 log.warn("simple fabric request mac failed for unknown fabricNetwork name {}: {}",
Jian Lida0b4852018-08-29 20:40:44 +0900455 fabricSubnet.networkName(), ip);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900456 return false;
457 }
Jian Lie2d87512018-08-23 17:33:05 +0900458 log.debug("simple fabric send request mac fabricNetwork {}: {}", fabricNetwork.name(), ip);
459 for (Interface iface : fabricNetwork.interfaces()) {
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900460 Ethernet neighbourReq;
461 if (ip.isIp4()) {
Jian Lie2d87512018-08-23 17:33:05 +0900462 neighbourReq = ARP.buildArpRequest(fabricSubnet.gatewayMac().toBytes(),
463 fabricSubnet.gatewayIp().toOctets(),
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900464 ip.toOctets(),
465 iface.vlan().toShort());
466 } else {
467 byte[] soliciteIp = IPv6.getSolicitNodeAddress(ip.toOctets());
468 neighbourReq = NeighborSolicitation.buildNdpSolicit(
469 ip.toOctets(),
Jian Lie2d87512018-08-23 17:33:05 +0900470 fabricSubnet.gatewayIp().toOctets(),
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900471 soliciteIp,
Jian Lie2d87512018-08-23 17:33:05 +0900472 fabricSubnet.gatewayMac().toBytes(),
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900473 IPv6.getMCastMacAddress(soliciteIp),
474 iface.vlan());
475 }
476 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
477 .setOutput(iface.connectPoint().port()).build();
478 OutboundPacket packet = new DefaultOutboundPacket(iface.connectPoint().deviceId(),
479 treatment, ByteBuffer.wrap(neighbourReq.serialize()));
480 packetService.emit(packet);
481 }
482 return true;
483 }
484
485 @Override
486 public void dumpToStream(String subject, OutputStream out) {
487 SimpleFabricEvent event = new SimpleFabricEvent(SimpleFabricEvent.Type.SIMPLE_FABRIC_DUMP, subject, out);
488 dump(event.subject(), event.out()); // dump in itself
489 process(event); // dump in sub modules
490 }
491
492 // Dump handler
493 protected void dump(String subject, PrintStream out) {
Ray Milkey2ff67162018-01-22 10:14:19 -0800494 if ("show".equals(subject)) {
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900495 out.println("Static Configuration Flag:");
Jian Li8df54a92018-08-23 17:01:31 +0900496 out.println(" ALLOW_IPV6=" + ALLOW_IPV6);
497 out.println(" ALLOW_ETH_ADDRESS_SELECTOR=" + ALLOW_ETH_ADDRESS_SELECTOR);
498 out.println(" REACTIVE_SINGLE_TO_SINGLE=" + REACTIVE_SINGLE_TO_SINGLE);
499 out.println(" REACTIVE_ALLOW_LINK_CP=" + REACTIVE_ALLOW_LINK_CP);
500 out.println(" REACTIVE_HASHED_PATH_SELECTION=" + REACTIVE_HASHED_PATH_SELECTION);
501 out.println(" REACTIVE_MATCH_IP_PROTO=" + REACTIVE_MATCH_IP_PROTO);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900502 out.println("");
503 out.println("SimpleFabricAppId:");
Jian Lie2d87512018-08-23 17:33:05 +0900504 out.println(" " + appId());
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900505 out.println("");
Jian Lie2d87512018-08-23 17:33:05 +0900506 out.println("fabricNetworks:");
507 for (FabricNetwork fabricNetwork : fabricNetworks()) {
508 out.println(" " + fabricNetwork);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900509 }
510 out.println("");
Jian Lie2d87512018-08-23 17:33:05 +0900511 out.println("fabricSubnets:");
512 for (FabricSubnet fabricIpSubnet : defaultFabricSubnets()) {
513 out.println(" " + fabricIpSubnet);
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900514 }
515 out.println("");
Jian Lie2d87512018-08-23 17:33:05 +0900516 out.println("fabricRoutes:");
517 for (FabricRoute route : fabricRoutes()) {
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900518 out.println(" " + route);
519 }
520 }
521 }
522
523 // Refresh action thread and notifier
524
525 private class InternalRefreshThread extends Thread {
Yuta HIGUCHIc2bf02a2018-03-29 08:40:35 -0700526 @Override
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900527 public void run() {
528 while (true) {
529 boolean doRefreshMarked = false;
530 boolean doFlushMarked = false;
531 synchronized (refreshMonitor) {
532 if (!doRefresh && !doFlush) {
533 try {
534 refreshMonitor.wait(IDLE_INTERVAL_MSEC);
535 } catch (InterruptedException e) {
Ray Milkey5c7d4882018-02-05 14:50:39 -0800536 log.warn("run thread interrupted", e);
537 Thread.currentThread().interrupt();
Lee Yongjae7c27bb42017-11-17 12:00:45 +0900538 }
539 }
540 doRefreshMarked = doRefresh;
541 doRefresh = false;
542 doFlushMarked = doFlush;
543 doFlush = false;
544 }
545 if (doRefreshMarked) {
546 try {
547 refresh();
548 } catch (Exception e) {
549 log.warn("simple fabric refresh failed: exception={}", e);
550 }
551 }
552 if (doFlushMarked) {
553 try {
554 log.info("simple fabric flush execute");
555 process(new SimpleFabricEvent(SimpleFabricEvent.Type.SIMPLE_FABRIC_FLUSH, "flush"));
556 } catch (Exception e) {
557 log.warn("simple fabric flush failed: exception={}", e);
558 }
559 }
560 if (!doRefreshMarked && !doFlushMarked) {
561 try {
562 if (!refresh()) {
563 process(new SimpleFabricEvent(SimpleFabricEvent.Type.SIMPLE_FABRIC_IDLE, "idle"));
564 }
565 } catch (Exception e) {
566 log.warn("simple fabric idle failed: exception={}", e);
567 }
568 }
569 }
570 }
571 }
572
573 @Override
574 public void triggerRefresh() {
575 synchronized (refreshMonitor) {
576 doRefresh = true;
577 refreshMonitor.notifyAll();
578 }
579 }
580
581 @Override
582 public void triggerFlush() {
583 synchronized (refreshMonitor) {
584 doFlush = true;
585 refreshMonitor.notifyAll();
586 }
587 }
588
589 // Service Listeners
590
591 private class InternalNetworkConfigListener implements NetworkConfigListener {
592 @Override
593 public void event(NetworkConfigEvent event) {
594 switch (event.type()) {
595 case CONFIG_REGISTERED:
596 case CONFIG_UNREGISTERED:
597 case CONFIG_ADDED:
598 case CONFIG_UPDATED:
599 case CONFIG_REMOVED:
600 if (event.configClass().equals(SimpleFabricConfig.class)) {
601 triggerRefresh();
602 }
603 break;
604 default:
605 break;
606 }
607 }
608 }
609
610 private class InternalDeviceListener implements DeviceListener {
611 @Override
612 public void event(DeviceEvent event) {
613 switch (event.type()) {
614 case DEVICE_ADDED:
615 case DEVICE_AVAILABILITY_CHANGED:
616 case DEVICE_REMOVED:
617 case DEVICE_SUSPENDED:
618 case DEVICE_UPDATED:
619 case PORT_ADDED:
620 case PORT_REMOVED:
621 case PORT_UPDATED:
622 // case PORT_STATS_UPDATED: IGNORED
623 triggerRefresh();
624 break;
625 default:
626 break;
627 }
628 }
629 }
630
631 private class InternalHostListener implements HostListener {
632 @Override
633 public void event(HostEvent event) {
634 Host host = event.subject();
635 Host prevHost = event.prevSubject();
636 switch (event.type()) {
637 case HOST_MOVED:
638 case HOST_REMOVED:
639 case HOST_ADDED:
640 case HOST_UPDATED:
641 triggerRefresh();
642 break;
643 default:
644 break;
645 }
646 }
647 }
648
649 private class InternalInterfaceListener implements InterfaceListener {
650 @Override
651 public void event(InterfaceEvent event) {
652 Interface iface = event.subject();
653 Interface prevIface = event.prevSubject();
654 switch (event.type()) {
655 case INTERFACE_ADDED:
656 case INTERFACE_REMOVED:
657 case INTERFACE_UPDATED:
658 triggerRefresh();
659 break;
660 default:
661 break;
662 }
663 }
664 }
665
666}
667