blob: 97fee88e53d4af025f4980a733586390d5814e99 [file] [log] [blame]
Jonathan Hartf8cd0522016-10-25 07:09:55 -07001/*
2 * Copyright 2017-present Open Networking Laboratory
3 *
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
Jonathan Hartf4bd0482017-01-27 15:11:18 -080017package org.onosproject.routing;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070018
Jonathan Hartf8cd0522016-10-25 07:09:55 -070019import com.google.common.collect.Sets;
20import org.onosproject.incubator.net.intf.Interface;
21import org.onosproject.incubator.net.intf.InterfaceEvent;
22import org.onosproject.incubator.net.intf.InterfaceListener;
23import org.onosproject.incubator.net.intf.InterfaceService;
24import org.onosproject.net.DeviceId;
Jonathan Hart249b4cf2017-02-03 18:02:58 -080025import org.onosproject.net.device.DeviceService;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070026import org.slf4j.Logger;
27import org.slf4j.LoggerFactory;
28
Jonathan Hartf8cd0522016-10-25 07:09:55 -070029import java.util.HashSet;
30import java.util.Set;
31import java.util.function.Consumer;
32import java.util.stream.Stream;
33
34import static com.google.common.base.Preconditions.checkNotNull;
35
36/**
Jonathan Hart249b4cf2017-02-03 18:02:58 -080037 * Manages the configuration and provisioning of a single-device router.
38 * It maintains which interfaces are part of the router when the configuration
39 * changes, and handles the provisioning/unprovisioning of interfaces when they
Jonathan Hartf8cd0522016-10-25 07:09:55 -070040 * are added/removed.
41 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -080042public class Router {
Jonathan Hartf8cd0522016-10-25 07:09:55 -070043
44 private final Logger log = LoggerFactory.getLogger(getClass());
45
Jonathan Hart249b4cf2017-02-03 18:02:58 -080046 private final Consumer<InterfaceProvisionRequest> provisioner;
47 private final Consumer<InterfaceProvisionRequest> unprovisioner;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070048
Jonathan Hart249b4cf2017-02-03 18:02:58 -080049 private RouterInfo info;
50
Jonathan Hartf8cd0522016-10-25 07:09:55 -070051 private Set<Interface> provisioned = new HashSet<>();
52
53 private InterfaceService interfaceService;
54 private InterfaceListener listener = new InternalInterfaceListener();
55
Jonathan Hart249b4cf2017-02-03 18:02:58 -080056 private AsyncDeviceFetcher asyncDeviceFetcher;
57
58 private volatile boolean deviceAvailable = false;
Jonathan Hartf8cd0522016-10-25 07:09:55 -070059
60 /**
61 * Creates a new router interface manager.
62 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -080063 * @param info router configuration information
Jonathan Hartf8cd0522016-10-25 07:09:55 -070064 * @param interfaceService interface service
Jonathan Hart249b4cf2017-02-03 18:02:58 -080065 * @param deviceService device service
Jonathan Hartf8cd0522016-10-25 07:09:55 -070066 * @param provisioner consumer that will provision new interfaces
67 * @param unprovisioner consumer that will unprovision old interfaces
68 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -080069 public Router(RouterInfo info,
70 InterfaceService interfaceService,
71 DeviceService deviceService,
72 Consumer<InterfaceProvisionRequest> provisioner,
73 Consumer<InterfaceProvisionRequest> unprovisioner) {
74 this.info = checkNotNull(info);
Jonathan Hartf8cd0522016-10-25 07:09:55 -070075 this.provisioner = checkNotNull(provisioner);
76 this.unprovisioner = checkNotNull(unprovisioner);
77 this.interfaceService = checkNotNull(interfaceService);
Jonathan Hartf8cd0522016-10-25 07:09:55 -070078
Jonathan Hart249b4cf2017-02-03 18:02:58 -080079 this.asyncDeviceFetcher = AsyncDeviceFetcher.create(deviceService);
80 asyncDeviceFetcher.getDevice(info.deviceId())
81 .thenAccept(deviceId1 -> {
82 deviceAvailable = true;
83 provision();
84 }).whenComplete((v, t) -> {
85 if (t != null) {
86 log.error("Error provisioning: ", t);
87 }
88 });
Jonathan Hartf8cd0522016-10-25 07:09:55 -070089
90 interfaceService.addListener(listener);
91 }
92
93 /**
94 * Cleans up the router and unprovisions all interfaces.
95 */
96 public void cleanup() {
97 interfaceService.removeListener(listener);
98
99 unprovision();
100 }
101
102 /**
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800103 * Retrieves the router configuration information.
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700104 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800105 * @return router configuration information
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700106 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800107 public RouterInfo info() {
108 return info;
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700109 }
110
111 /**
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800112 * Changes the router configuration.
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700113 *
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800114 * @param newConfig new configuration
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700115 */
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800116 public void changeConfiguration(RouterInfo newConfig) {
117 Set<String> oldConfiguredInterfaces = info.interfaces();
118 info = newConfig;
119 Set<String> newConfiguredInterfaces = info.interfaces();
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700120
121 if (newConfiguredInterfaces.isEmpty() && !oldConfiguredInterfaces.isEmpty()) {
122 // Reverted to using all interfaces. Provision interfaces that
123 // weren't previously in the configured list
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800124 getInterfacesForDevice(info.deviceId())
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700125 .filter(intf -> !oldConfiguredInterfaces.contains(intf.name()))
126 .forEach(this::provision);
127 } else if (!newConfiguredInterfaces.isEmpty() && oldConfiguredInterfaces.isEmpty()) {
128 // Began using an interface list. Unprovision interfaces that
129 // are not in the new interface list.
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800130 getInterfacesForDevice(info.deviceId())
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700131 .filter(intf -> !newConfiguredInterfaces.contains(intf.name()))
132 .forEach(this::unprovision);
133 } else {
134 // The existing interface list was changed.
135 Set<String> toUnprovision = Sets.difference(oldConfiguredInterfaces, newConfiguredInterfaces);
136 Set<String> toProvision = Sets.difference(newConfiguredInterfaces, oldConfiguredInterfaces);
137
138 toUnprovision.forEach(name ->
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800139 getInterfacesForDevice(info.deviceId())
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700140 .filter(intf -> intf.name().equals(name))
141 .findFirst()
142 .ifPresent(this::unprovision)
143 );
144
145 toProvision.forEach(name ->
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800146 getInterfacesForDevice(info.deviceId())
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700147 .filter(intf -> intf.name().equals(name))
148 .findFirst()
149 .ifPresent(this::provision)
150 );
151 }
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700152 }
153
154 private void provision() {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800155 getInterfacesForDevice(info.deviceId())
156 .filter(this::shouldProvision)
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700157 .forEach(this::provision);
158 }
159
160 private void unprovision() {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800161 getInterfacesForDevice(info.deviceId())
162 .filter(this::shouldProvision)
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700163 .forEach(this::unprovision);
164 }
165
166 private void provision(Interface intf) {
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800167 if (!provisioned.contains(intf) && shouldProvision(intf)) {
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700168 log.info("Provisioning interface {}", intf);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800169 provisioner.accept(InterfaceProvisionRequest.of(info, intf));
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700170 provisioned.add(intf);
171 }
172 }
173
174 private void unprovision(Interface intf) {
175 if (provisioned.contains(intf)) {
176 log.info("Unprovisioning interface {}", intf);
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800177 unprovisioner.accept(InterfaceProvisionRequest.of(info, intf));
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700178 provisioned.remove(intf);
179 }
180 }
181
Jonathan Hart249b4cf2017-02-03 18:02:58 -0800182 private boolean shouldProvision(Interface intf) {
183 return deviceAvailable &&
184 (info.interfaces().isEmpty() || info.interfaces().contains(intf.name()));
Jonathan Hartf8cd0522016-10-25 07:09:55 -0700185 }
186
187 private Stream<Interface> getInterfacesForDevice(DeviceId deviceId) {
188 return interfaceService.getInterfaces().stream()
189 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId));
190 }
191
192 private class InternalInterfaceListener implements InterfaceListener {
193 @Override
194 public void event(InterfaceEvent event) {
195 Interface intf = event.subject();
196 switch (event.type()) {
197 case INTERFACE_ADDED:
198 provision(intf);
199 break;
200 case INTERFACE_UPDATED:
201 // TODO
202 break;
203 case INTERFACE_REMOVED:
204 unprovision(intf);
205 break;
206 default:
207 break;
208 }
209 }
210 }
211}