blob: 87d3f560ee721e7ca85bf788286ab4c5d7005f3e [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
17package org.onosproject.routing.impl;
18
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Sets;
21import org.onosproject.incubator.net.intf.Interface;
22import org.onosproject.incubator.net.intf.InterfaceEvent;
23import org.onosproject.incubator.net.intf.InterfaceListener;
24import org.onosproject.incubator.net.intf.InterfaceService;
25import org.onosproject.net.DeviceId;
26import org.slf4j.Logger;
27import org.slf4j.LoggerFactory;
28
29import java.util.Collections;
30import java.util.HashSet;
31import java.util.Set;
32import java.util.function.Consumer;
33import java.util.stream.Stream;
34
35import static com.google.common.base.Preconditions.checkNotNull;
36
37/**
38 * Manages which interfaces are part of the router when the configuration is
39 * updated, and handles the provisioning/unprovisioning of interfaces when they
40 * are added/removed.
41 */
42public class RouterInterfaceManager {
43
44 private final Logger log = LoggerFactory.getLogger(getClass());
45
46 private final Consumer<Interface> provisioner;
47 private final Consumer<Interface> unprovisioner;
48
49 private Set<String> configuredInterfaces = Collections.emptySet();
50 private Set<Interface> provisioned = new HashSet<>();
51
52 private InterfaceService interfaceService;
53 private InterfaceListener listener = new InternalInterfaceListener();
54
55 private final DeviceId routerDeviceId;
56
57 /**
58 * Creates a new router interface manager.
59 *
60 * @param deviceId router device ID
61 * @param configuredInterfaces names of interfaces configured for this router
62 * @param interfaceService interface service
63 * @param provisioner consumer that will provision new interfaces
64 * @param unprovisioner consumer that will unprovision old interfaces
65 */
66 public RouterInterfaceManager(DeviceId deviceId,
67 Set<String> configuredInterfaces,
68 InterfaceService interfaceService,
69 Consumer<Interface> provisioner,
70 Consumer<Interface> unprovisioner) {
71 this.routerDeviceId = checkNotNull(deviceId);
72 this.provisioner = checkNotNull(provisioner);
73 this.unprovisioner = checkNotNull(unprovisioner);
74 this.interfaceService = checkNotNull(interfaceService);
75 this.configuredInterfaces = checkNotNull(configuredInterfaces);
76
77 provision();
78
79 interfaceService.addListener(listener);
80 }
81
82 /**
83 * Cleans up the router and unprovisions all interfaces.
84 */
85 public void cleanup() {
86 interfaceService.removeListener(listener);
87
88 unprovision();
89 }
90
91 /**
92 * Retrieves the set of configured interface names.
93 *
94 * @return interface names
95 */
96 public Set<String> configuredInterfaces() {
97 return configuredInterfaces;
98 }
99
100 /**
101 * Changes the set of interfaces configured on the router.
102 *
103 * @param newConfiguredInterfaces new set of router interfaces
104 */
105 public void changeConfiguredInterfaces(Set<String> newConfiguredInterfaces) {
106 Set<String> oldConfiguredInterfaces = configuredInterfaces;
107 configuredInterfaces = ImmutableSet.copyOf(newConfiguredInterfaces);
108
109 if (newConfiguredInterfaces.isEmpty() && !oldConfiguredInterfaces.isEmpty()) {
110 // Reverted to using all interfaces. Provision interfaces that
111 // weren't previously in the configured list
112 getInterfacesForDevice(routerDeviceId)
113 .filter(intf -> !oldConfiguredInterfaces.contains(intf.name()))
114 .forEach(this::provision);
115 } else if (!newConfiguredInterfaces.isEmpty() && oldConfiguredInterfaces.isEmpty()) {
116 // Began using an interface list. Unprovision interfaces that
117 // are not in the new interface list.
118 getInterfacesForDevice(routerDeviceId)
119 .filter(intf -> !newConfiguredInterfaces.contains(intf.name()))
120 .forEach(this::unprovision);
121 } else {
122 // The existing interface list was changed.
123 Set<String> toUnprovision = Sets.difference(oldConfiguredInterfaces, newConfiguredInterfaces);
124 Set<String> toProvision = Sets.difference(newConfiguredInterfaces, oldConfiguredInterfaces);
125
126 toUnprovision.forEach(name ->
127 getInterfacesForDevice(routerDeviceId)
128 .filter(intf -> intf.name().equals(name))
129 .findFirst()
130 .ifPresent(this::unprovision)
131 );
132
133 toProvision.forEach(name ->
134 getInterfacesForDevice(routerDeviceId)
135 .filter(intf -> intf.name().equals(name))
136 .findFirst()
137 .ifPresent(this::provision)
138 );
139 }
140
141 configuredInterfaces = newConfiguredInterfaces;
142 }
143
144 private void provision() {
145 getInterfacesForDevice(routerDeviceId)
146 .filter(this::shouldUse)
147 .forEach(this::provision);
148 }
149
150 private void unprovision() {
151 getInterfacesForDevice(routerDeviceId)
152 .filter(this::shouldUse)
153 .forEach(this::unprovision);
154 }
155
156 private void provision(Interface intf) {
157 if (!provisioned.contains(intf) && shouldUse(intf)) {
158 log.info("Provisioning interface {}", intf);
159 provisioner.accept(intf);
160 provisioned.add(intf);
161 }
162 }
163
164 private void unprovision(Interface intf) {
165 if (provisioned.contains(intf)) {
166 log.info("Unprovisioning interface {}", intf);
167 unprovisioner.accept(intf);
168 provisioned.remove(intf);
169 }
170 }
171
172 private boolean shouldUse(Interface intf) {
173 return configuredInterfaces.isEmpty() || configuredInterfaces.contains(intf.name());
174 }
175
176 private Stream<Interface> getInterfacesForDevice(DeviceId deviceId) {
177 return interfaceService.getInterfaces().stream()
178 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId));
179 }
180
181 private class InternalInterfaceListener implements InterfaceListener {
182 @Override
183 public void event(InterfaceEvent event) {
184 Interface intf = event.subject();
185 switch (event.type()) {
186 case INTERFACE_ADDED:
187 provision(intf);
188 break;
189 case INTERFACE_UPDATED:
190 // TODO
191 break;
192 case INTERFACE_REMOVED:
193 unprovision(intf);
194 break;
195 default:
196 break;
197 }
198 }
199 }
200}