blob: e70857f067158093a1c64f7c0683727c5fb0f419 [file] [log] [blame]
Jonathan Harteb8c9472015-08-05 07:43:13 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Jonathan Harteb8c9472015-08-05 07:43:13 -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 */
16
Ray Milkeyfacf2862017-08-03 11:58:29 -070017package org.onosproject.net.intf.impl;
Jonathan Harteb8c9472015-08-05 07:43:13 -070018
Deepa Vaddireddy2740a112017-10-26 06:23:26 +000019
Jonathan Harteb8c9472015-08-05 07:43:13 -070020import com.google.common.collect.ImmutableSet;
21import com.google.common.collect.Maps;
Jonathan Hart7dbe6292015-11-10 08:33:17 -080022import com.google.common.collect.Sets;
Jonathan Harteb8c9472015-08-05 07:43:13 -070023import org.onlab.packet.IpAddress;
24import org.onlab.packet.VlanId;
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -070025import org.onosproject.event.ListenerRegistry;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070026import org.onosproject.net.ConnectPoint;
27import org.onosproject.net.config.BasicNetworkConfigService;
Ray Milkey6c013742017-08-15 10:16:43 -070028import org.onosproject.net.config.ConfigException;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070029import org.onosproject.net.config.NetworkConfigEvent;
30import org.onosproject.net.config.NetworkConfigListener;
31import org.onosproject.net.config.NetworkConfigService;
Ray Milkey6c013742017-08-15 10:16:43 -070032import org.onosproject.net.config.basics.InterfaceConfig;
Ray Milkeyfacf2862017-08-03 11:58:29 -070033import org.onosproject.net.intf.Interface;
34import org.onosproject.net.intf.InterfaceAdminService;
35import org.onosproject.net.intf.InterfaceEvent;
36import org.onosproject.net.intf.InterfaceListener;
37import org.onosproject.net.intf.InterfaceService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070038import org.osgi.service.component.annotations.Activate;
39import org.osgi.service.component.annotations.Component;
40import org.osgi.service.component.annotations.Deactivate;
41import org.osgi.service.component.annotations.Reference;
42import org.osgi.service.component.annotations.ReferenceCardinality;
Jonathan Harteb8c9472015-08-05 07:43:13 -070043import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
Charles Chanb3b09cd2017-03-14 12:53:46 -070046import java.util.Collection;
Jonathan Hart4cb39882015-08-12 23:50:55 -040047import java.util.Collections;
Jonathan Harteb8c9472015-08-05 07:43:13 -070048import java.util.Map;
49import java.util.Optional;
50import java.util.Set;
Charles Chan971d7ba2018-05-01 11:50:20 -070051import java.util.stream.Collectors;
Charles Chanb3b09cd2017-03-14 12:53:46 -070052import java.util.stream.Stream;
Jonathan Harteb8c9472015-08-05 07:43:13 -070053
54import static java.util.stream.Collectors.collectingAndThen;
55import static java.util.stream.Collectors.toSet;
56
57/**
58 * Manages the inventory of interfaces in the system.
59 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070060@Component(immediate = true, service = { InterfaceService.class, InterfaceAdminService.class })
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -070061public class InterfaceManager extends ListenerRegistry<InterfaceEvent, InterfaceListener>
62 implements InterfaceService, InterfaceAdminService {
Jonathan Harteb8c9472015-08-05 07:43:13 -070063
64 private final Logger log = LoggerFactory.getLogger(getClass());
65
Jonathan Hart4cb39882015-08-12 23:50:55 -040066 private static final Class<ConnectPoint> SUBJECT_CLASS = ConnectPoint.class;
67 private static final Class<InterfaceConfig> CONFIG_CLASS = InterfaceConfig.class;
Jonathan Harteb8c9472015-08-05 07:43:13 -070068
Ray Milkeyd84f89b2018-08-17 14:54:17 -070069 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart4cb39882015-08-12 23:50:55 -040070 protected NetworkConfigService configService;
Jonathan Harteb8c9472015-08-05 07:43:13 -070071
Deepa Vaddireddy2740a112017-10-26 06:23:26 +000072 //Dependency to ensure subject factories are properly initialized
Ray Milkeyd84f89b2018-08-17 14:54:17 -070073 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Deepa Vaddireddy2740a112017-10-26 06:23:26 +000074 protected BasicNetworkConfigService basicNetworkConfigService;
75
Jonathan Harteb8c9472015-08-05 07:43:13 -070076 private final InternalConfigListener listener = new InternalConfigListener();
77
78 private final Map<ConnectPoint, Set<Interface>> interfaces = Maps.newConcurrentMap();
79
80 @Activate
81 public void activate() {
82 configService.addListener(listener);
83
Jonathan Hart4cb39882015-08-12 23:50:55 -040084 // TODO address concurrency issues here
85 for (ConnectPoint subject : configService.getSubjects(SUBJECT_CLASS, CONFIG_CLASS)) {
86 InterfaceConfig config = configService.getConfig(subject, CONFIG_CLASS);
Jonathan Harteb8c9472015-08-05 07:43:13 -070087
Jonathan Hart4cb39882015-08-12 23:50:55 -040088 if (config != null) {
89 updateInterfaces(config);
Jonathan Harteb8c9472015-08-05 07:43:13 -070090 }
91 }
92
93 log.info("Started");
94 }
95
96 @Deactivate
97 public void deactivate() {
98 configService.removeListener(listener);
99
100 log.info("Stopped");
101 }
102
103 @Override
104 public Set<Interface> getInterfaces() {
105 return interfaces.values()
106 .stream()
107 .flatMap(set -> set.stream())
108 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
109 }
110
111 @Override
Jonathan Hart43d232e2016-02-03 15:34:10 -0800112 public Interface getInterfaceByName(ConnectPoint connectPoint, String name) {
113 Optional<Interface> intf =
114 interfaces.getOrDefault(connectPoint, Collections.emptySet())
115 .stream()
116 .filter(i -> i.name().equals(name))
117 .findAny();
118
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800119 return intf.orElse(null);
Jonathan Hart43d232e2016-02-03 15:34:10 -0800120 }
121
122 @Override
Jonathan Harteb8c9472015-08-05 07:43:13 -0700123 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400124 Set<Interface> intfs = interfaces.get(port);
125 if (intfs == null) {
126 return Collections.emptySet();
127 }
128 return ImmutableSet.copyOf(intfs);
Jonathan Harteb8c9472015-08-05 07:43:13 -0700129 }
130
131 @Override
132 public Set<Interface> getInterfacesByIp(IpAddress ip) {
133 return interfaces.values()
134 .stream()
Charles Chanb3b09cd2017-03-14 12:53:46 -0700135 .flatMap(Collection::stream)
136 .filter(intf -> intf.ipAddressesList()
Jonathan Hart4cb39882015-08-12 23:50:55 -0400137 .stream()
138 .anyMatch(ia -> ia.ipAddress().equals(ip)))
Jonathan Harteb8c9472015-08-05 07:43:13 -0700139 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
140 }
141
142 @Override
143 public Interface getMatchingInterface(IpAddress ip) {
Charles Chanb3b09cd2017-03-14 12:53:46 -0700144 return getMatchingInterfacesStream(ip).findFirst().orElse(null);
145 }
Jonathan Harteb8c9472015-08-05 07:43:13 -0700146
Charles Chanb3b09cd2017-03-14 12:53:46 -0700147 @Override
148 public Set<Interface> getMatchingInterfaces(IpAddress ip) {
149 return getMatchingInterfacesStream(ip).collect(toSet());
150 }
151
152 private Stream<Interface> getMatchingInterfacesStream(IpAddress ip) {
153 return interfaces.values()
154 .stream()
155 .flatMap(Collection::stream)
156 .filter(intf -> intf.ipAddressesList()
157 .stream()
158 .anyMatch(intfIp -> intfIp.subnetAddress().contains(ip)));
Jonathan Harteb8c9472015-08-05 07:43:13 -0700159 }
160
161 @Override
162 public Set<Interface> getInterfacesByVlan(VlanId vlan) {
163 return interfaces.values()
164 .stream()
Charles Chanb3b09cd2017-03-14 12:53:46 -0700165 .flatMap(Collection::stream)
Jonathan Harteb8c9472015-08-05 07:43:13 -0700166 .filter(intf -> intf.vlan().equals(vlan))
167 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
168 }
169
Charles Chan971d7ba2018-05-01 11:50:20 -0700170 /**
171 * Returns untagged VLAN configured on given connect point.
172 * <p>
173 * Only returns the first match if there are multiple untagged VLAN configured
174 * on the connect point.
175 *
176 * @param connectPoint connect point
177 * @return untagged VLAN or null if not configured
178 */
Charles Chan0d4b8b32018-05-01 16:29:07 -0700179 @Override
Charles Chan971d7ba2018-05-01 11:50:20 -0700180 public VlanId getUntaggedVlanId(ConnectPoint connectPoint) {
181 return getInterfacesByPort(connectPoint).stream()
182 .filter(intf -> !intf.vlanUntagged().equals(VlanId.NONE))
183 .map(Interface::vlanUntagged)
184 .findFirst().orElse(null);
185 }
186
187 /**
188 * Returns tagged VLAN configured on given connect point.
189 * <p>
190 * Returns all matches if there are multiple tagged VLAN configured
191 * on the connect point.
192 *
193 * @param connectPoint connect point
194 * @return tagged VLAN or empty set if not configured
195 */
Charles Chan0d4b8b32018-05-01 16:29:07 -0700196 @Override
Charles Chan971d7ba2018-05-01 11:50:20 -0700197 public Set<VlanId> getTaggedVlanId(ConnectPoint connectPoint) {
198 Set<Interface> interfaces = getInterfacesByPort(connectPoint);
199 return interfaces.stream()
200 .map(Interface::vlanTagged)
201 .flatMap(Set::stream)
202 .collect(Collectors.toSet());
203 }
204
205 /**
206 * Returns native VLAN configured on given connect point.
207 * <p>
208 * Only returns the first match if there are multiple native VLAN configured
209 * on the connect point.
210 *
211 * @param connectPoint connect point
212 * @return native VLAN or null if not configured
213 */
Charles Chan0d4b8b32018-05-01 16:29:07 -0700214 @Override
Charles Chan971d7ba2018-05-01 11:50:20 -0700215 public VlanId getNativeVlanId(ConnectPoint connectPoint) {
216 Set<Interface> interfaces = getInterfacesByPort(connectPoint);
217 return interfaces.stream()
218 .filter(intf -> !intf.vlanNative().equals(VlanId.NONE))
219 .map(Interface::vlanNative)
220 .findFirst()
221 .orElse(null);
222 }
223
Saurav Das9a554292018-04-27 18:42:30 -0700224 @Override
225 public boolean isConfigured(ConnectPoint connectPoint) {
226 Set<Interface> intfs = interfaces.get(connectPoint);
227 if (intfs == null) {
228 return false;
229 }
230 for (Interface intf : intfs) {
231 if (!intf.ipAddressesList().isEmpty() || intf.vlan() != VlanId.NONE
232 || intf.vlanNative() != VlanId.NONE
233 || intf.vlanUntagged() != VlanId.NONE
234 || !intf.vlanTagged().isEmpty()) {
235 return true;
236 }
237 }
238 return false;
239 }
240
Saurav Das09c2c4d2018-08-13 15:34:26 -0700241 @Override
242 public boolean inUse(VlanId vlanId) {
243 for (Set<Interface> intfs : interfaces.values()) {
244 for (Interface intf : intfs) {
245 if (intf.vlan().equals(vlanId)
246 || intf.vlanNative().equals(vlanId)
247 || intf.vlanUntagged().equals(vlanId)
248 || intf.vlanTagged().contains(vlanId)) {
249 return true;
250 }
251 }
252 }
253 return false;
254 }
255
Jonathan Harteb8c9472015-08-05 07:43:13 -0700256 private void updateInterfaces(InterfaceConfig intfConfig) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400257 try {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700258 Set<Interface> old = interfaces.put(intfConfig.subject(),
259 Sets.newHashSet(intfConfig.getInterfaces()));
260
261 if (old == null) {
262 old = Collections.emptySet();
263 }
264
265 for (Interface intf : intfConfig.getInterfaces()) {
266 if (intf.name().equals(Interface.NO_INTERFACE_NAME)) {
267 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_ADDED, intf));
268 } else {
269 Optional<Interface> oldIntf = findInterface(intf, old);
270 if (oldIntf.isPresent()) {
271 old.remove(oldIntf.get());
272 if (!oldIntf.get().equals(intf)) {
gaurav2c626cc2016-04-26 04:18:33 +0530273 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_UPDATED, intf, oldIntf.get()));
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700274 }
275 } else {
276 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_ADDED, intf));
277 }
278 }
279 }
280
281 for (Interface intf : old) {
282 if (!intf.name().equals(Interface.NO_INTERFACE_NAME)) {
283 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_REMOVED, intf));
284 }
285 }
Jonathan Hart4cb39882015-08-12 23:50:55 -0400286 } catch (ConfigException e) {
287 log.error("Error in interface config", e);
288 }
Jonathan Harteb8c9472015-08-05 07:43:13 -0700289 }
290
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700291 private Optional<Interface> findInterface(Interface intf, Set<Interface> set) {
292 return set.stream().filter(i -> i.name().equals(intf.name())).findAny();
293 }
294
Jonathan Harteb8c9472015-08-05 07:43:13 -0700295 private void removeInterfaces(ConnectPoint port) {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700296 Set<Interface> old = interfaces.remove(port);
297
298 old.stream()
299 .filter(i -> !i.name().equals(Interface.NO_INTERFACE_NAME))
300 .forEach(i -> process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_REMOVED, i)));
Jonathan Harteb8c9472015-08-05 07:43:13 -0700301 }
302
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700303 @Override
304 public void add(Interface intf) {
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700305 InterfaceConfig config =
306 configService.addConfig(intf.connectPoint(), CONFIG_CLASS);
307
308 config.addInterface(intf);
309
310 configService.applyConfig(intf.connectPoint(), CONFIG_CLASS, config.node());
311 }
312
313 @Override
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800314 public boolean remove(ConnectPoint connectPoint, String name) {
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800315 InterfaceConfig config = configService.addConfig(connectPoint, CONFIG_CLASS);
316 config.removeInterface(name);
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700317
318 try {
319 if (config.getInterfaces().isEmpty()) {
320 configService.removeConfig(connectPoint, CONFIG_CLASS);
321 } else {
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800322 configService.applyConfig(connectPoint, CONFIG_CLASS, config.node());
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700323 }
324 } catch (ConfigException e) {
325 log.error("Error reading interfaces JSON", e);
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700326 return false;
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700327 }
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800328
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700329 return true;
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700330 }
331
Jonathan Harteb8c9472015-08-05 07:43:13 -0700332 /**
333 * Listener for network config events.
334 */
335 private class InternalConfigListener implements NetworkConfigListener {
336
337 @Override
338 public void event(NetworkConfigEvent event) {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700339 if (event.configClass() == CONFIG_CLASS) {
340 switch (event.type()) {
341 case CONFIG_ADDED:
342 case CONFIG_UPDATED:
Charles Chanee993b12017-08-14 13:32:49 -0700343 event.config().ifPresent(config -> updateInterfaces((InterfaceConfig) config));
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700344 break;
345 case CONFIG_REMOVED:
Jonathan Harteb8c9472015-08-05 07:43:13 -0700346 removeInterfaces((ConnectPoint) event.subject());
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700347 break;
348 case CONFIG_REGISTERED:
349 case CONFIG_UNREGISTERED:
350 default:
351 break;
Jonathan Harteb8c9472015-08-05 07:43:13 -0700352 }
Jonathan Harteb8c9472015-08-05 07:43:13 -0700353 }
354 }
355 }
356}