blob: 6f77a985891886d1992a398ae2a379e6c8136e97 [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.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
26import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.apache.felix.scr.annotations.Service;
29import org.onlab.packet.IpAddress;
30import org.onlab.packet.VlanId;
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -070031import org.onosproject.event.ListenerRegistry;
Ray Milkey6c013742017-08-15 10:16:43 -070032import org.onosproject.net.config.ConfigException;
33import org.onosproject.net.config.basics.InterfaceConfig;
Ray Milkeyfacf2862017-08-03 11:58:29 -070034import org.onosproject.net.intf.Interface;
35import org.onosproject.net.intf.InterfaceAdminService;
36import org.onosproject.net.intf.InterfaceEvent;
37import org.onosproject.net.intf.InterfaceListener;
38import org.onosproject.net.intf.InterfaceService;
Jonathan Harteb8c9472015-08-05 07:43:13 -070039import org.onosproject.net.ConnectPoint;
Deepa Vaddireddy2740a112017-10-26 06:23:26 +000040import org.onosproject.net.config.BasicNetworkConfigService;
Jonathan Hart4cb39882015-08-12 23:50:55 -040041import org.onosproject.net.config.NetworkConfigEvent;
42import org.onosproject.net.config.NetworkConfigListener;
43import org.onosproject.net.config.NetworkConfigService;
Jonathan Harteb8c9472015-08-05 07:43:13 -070044import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
Charles Chanb3b09cd2017-03-14 12:53:46 -070047import java.util.Collection;
Jonathan Hart4cb39882015-08-12 23:50:55 -040048import java.util.Collections;
Jonathan Harteb8c9472015-08-05 07:43:13 -070049import java.util.Map;
50import java.util.Optional;
51import java.util.Set;
Charles Chan971d7ba2018-05-01 11:50:20 -070052import java.util.stream.Collectors;
Charles Chanb3b09cd2017-03-14 12:53:46 -070053import java.util.stream.Stream;
Jonathan Harteb8c9472015-08-05 07:43:13 -070054
55import static java.util.stream.Collectors.collectingAndThen;
56import static java.util.stream.Collectors.toSet;
57
58/**
59 * Manages the inventory of interfaces in the system.
60 */
61@Service
62@Component(immediate = true)
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -070063public class InterfaceManager extends ListenerRegistry<InterfaceEvent, InterfaceListener>
64 implements InterfaceService, InterfaceAdminService {
Jonathan Harteb8c9472015-08-05 07:43:13 -070065
66 private final Logger log = LoggerFactory.getLogger(getClass());
67
Jonathan Hart4cb39882015-08-12 23:50:55 -040068 private static final Class<ConnectPoint> SUBJECT_CLASS = ConnectPoint.class;
69 private static final Class<InterfaceConfig> CONFIG_CLASS = InterfaceConfig.class;
Jonathan Harteb8c9472015-08-05 07:43:13 -070070
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hart4cb39882015-08-12 23:50:55 -040072 protected NetworkConfigService configService;
Jonathan Harteb8c9472015-08-05 07:43:13 -070073
Deepa Vaddireddy2740a112017-10-26 06:23:26 +000074 //Dependency to ensure subject factories are properly initialized
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected BasicNetworkConfigService basicNetworkConfigService;
77
Jonathan Harteb8c9472015-08-05 07:43:13 -070078 private final InternalConfigListener listener = new InternalConfigListener();
79
80 private final Map<ConnectPoint, Set<Interface>> interfaces = Maps.newConcurrentMap();
81
82 @Activate
83 public void activate() {
84 configService.addListener(listener);
85
Jonathan Hart4cb39882015-08-12 23:50:55 -040086 // TODO address concurrency issues here
87 for (ConnectPoint subject : configService.getSubjects(SUBJECT_CLASS, CONFIG_CLASS)) {
88 InterfaceConfig config = configService.getConfig(subject, CONFIG_CLASS);
Jonathan Harteb8c9472015-08-05 07:43:13 -070089
Jonathan Hart4cb39882015-08-12 23:50:55 -040090 if (config != null) {
91 updateInterfaces(config);
Jonathan Harteb8c9472015-08-05 07:43:13 -070092 }
93 }
94
95 log.info("Started");
96 }
97
98 @Deactivate
99 public void deactivate() {
100 configService.removeListener(listener);
101
102 log.info("Stopped");
103 }
104
105 @Override
106 public Set<Interface> getInterfaces() {
107 return interfaces.values()
108 .stream()
109 .flatMap(set -> set.stream())
110 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
111 }
112
113 @Override
Jonathan Hart43d232e2016-02-03 15:34:10 -0800114 public Interface getInterfaceByName(ConnectPoint connectPoint, String name) {
115 Optional<Interface> intf =
116 interfaces.getOrDefault(connectPoint, Collections.emptySet())
117 .stream()
118 .filter(i -> i.name().equals(name))
119 .findAny();
120
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800121 return intf.orElse(null);
Jonathan Hart43d232e2016-02-03 15:34:10 -0800122 }
123
124 @Override
Jonathan Harteb8c9472015-08-05 07:43:13 -0700125 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400126 Set<Interface> intfs = interfaces.get(port);
127 if (intfs == null) {
128 return Collections.emptySet();
129 }
130 return ImmutableSet.copyOf(intfs);
Jonathan Harteb8c9472015-08-05 07:43:13 -0700131 }
132
133 @Override
134 public Set<Interface> getInterfacesByIp(IpAddress ip) {
135 return interfaces.values()
136 .stream()
Charles Chanb3b09cd2017-03-14 12:53:46 -0700137 .flatMap(Collection::stream)
138 .filter(intf -> intf.ipAddressesList()
Jonathan Hart4cb39882015-08-12 23:50:55 -0400139 .stream()
140 .anyMatch(ia -> ia.ipAddress().equals(ip)))
Jonathan Harteb8c9472015-08-05 07:43:13 -0700141 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
142 }
143
144 @Override
145 public Interface getMatchingInterface(IpAddress ip) {
Charles Chanb3b09cd2017-03-14 12:53:46 -0700146 return getMatchingInterfacesStream(ip).findFirst().orElse(null);
147 }
Jonathan Harteb8c9472015-08-05 07:43:13 -0700148
Charles Chanb3b09cd2017-03-14 12:53:46 -0700149 @Override
150 public Set<Interface> getMatchingInterfaces(IpAddress ip) {
151 return getMatchingInterfacesStream(ip).collect(toSet());
152 }
153
154 private Stream<Interface> getMatchingInterfacesStream(IpAddress ip) {
155 return interfaces.values()
156 .stream()
157 .flatMap(Collection::stream)
158 .filter(intf -> intf.ipAddressesList()
159 .stream()
160 .anyMatch(intfIp -> intfIp.subnetAddress().contains(ip)));
Jonathan Harteb8c9472015-08-05 07:43:13 -0700161 }
162
163 @Override
164 public Set<Interface> getInterfacesByVlan(VlanId vlan) {
165 return interfaces.values()
166 .stream()
Charles Chanb3b09cd2017-03-14 12:53:46 -0700167 .flatMap(Collection::stream)
Jonathan Harteb8c9472015-08-05 07:43:13 -0700168 .filter(intf -> intf.vlan().equals(vlan))
169 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
170 }
171
Charles Chan971d7ba2018-05-01 11:50:20 -0700172 /**
173 * Returns untagged VLAN configured on given connect point.
174 * <p>
175 * Only returns the first match if there are multiple untagged VLAN configured
176 * on the connect point.
177 *
178 * @param connectPoint connect point
179 * @return untagged VLAN or null if not configured
180 */
Charles Chan0d4b8b32018-05-01 16:29:07 -0700181 @Override
Charles Chan971d7ba2018-05-01 11:50:20 -0700182 public VlanId getUntaggedVlanId(ConnectPoint connectPoint) {
183 return getInterfacesByPort(connectPoint).stream()
184 .filter(intf -> !intf.vlanUntagged().equals(VlanId.NONE))
185 .map(Interface::vlanUntagged)
186 .findFirst().orElse(null);
187 }
188
189 /**
190 * Returns tagged VLAN configured on given connect point.
191 * <p>
192 * Returns all matches if there are multiple tagged VLAN configured
193 * on the connect point.
194 *
195 * @param connectPoint connect point
196 * @return tagged VLAN or empty set if not configured
197 */
Charles Chan0d4b8b32018-05-01 16:29:07 -0700198 @Override
Charles Chan971d7ba2018-05-01 11:50:20 -0700199 public Set<VlanId> getTaggedVlanId(ConnectPoint connectPoint) {
200 Set<Interface> interfaces = getInterfacesByPort(connectPoint);
201 return interfaces.stream()
202 .map(Interface::vlanTagged)
203 .flatMap(Set::stream)
204 .collect(Collectors.toSet());
205 }
206
207 /**
208 * Returns native VLAN configured on given connect point.
209 * <p>
210 * Only returns the first match if there are multiple native VLAN configured
211 * on the connect point.
212 *
213 * @param connectPoint connect point
214 * @return native VLAN or null if not configured
215 */
Charles Chan0d4b8b32018-05-01 16:29:07 -0700216 @Override
Charles Chan971d7ba2018-05-01 11:50:20 -0700217 public VlanId getNativeVlanId(ConnectPoint connectPoint) {
218 Set<Interface> interfaces = getInterfacesByPort(connectPoint);
219 return interfaces.stream()
220 .filter(intf -> !intf.vlanNative().equals(VlanId.NONE))
221 .map(Interface::vlanNative)
222 .findFirst()
223 .orElse(null);
224 }
225
Saurav Das9a554292018-04-27 18:42:30 -0700226 @Override
227 public boolean isConfigured(ConnectPoint connectPoint) {
228 Set<Interface> intfs = interfaces.get(connectPoint);
229 if (intfs == null) {
230 return false;
231 }
232 for (Interface intf : intfs) {
233 if (!intf.ipAddressesList().isEmpty() || intf.vlan() != VlanId.NONE
234 || intf.vlanNative() != VlanId.NONE
235 || intf.vlanUntagged() != VlanId.NONE
236 || !intf.vlanTagged().isEmpty()) {
237 return true;
238 }
239 }
240 return false;
241 }
242
Saurav Das09c2c4d2018-08-13 15:34:26 -0700243 @Override
244 public boolean inUse(VlanId vlanId) {
245 for (Set<Interface> intfs : interfaces.values()) {
246 for (Interface intf : intfs) {
247 if (intf.vlan().equals(vlanId)
248 || intf.vlanNative().equals(vlanId)
249 || intf.vlanUntagged().equals(vlanId)
250 || intf.vlanTagged().contains(vlanId)) {
251 return true;
252 }
253 }
254 }
255 return false;
256 }
257
Jonathan Harteb8c9472015-08-05 07:43:13 -0700258 private void updateInterfaces(InterfaceConfig intfConfig) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400259 try {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700260 Set<Interface> old = interfaces.put(intfConfig.subject(),
261 Sets.newHashSet(intfConfig.getInterfaces()));
262
263 if (old == null) {
264 old = Collections.emptySet();
265 }
266
267 for (Interface intf : intfConfig.getInterfaces()) {
268 if (intf.name().equals(Interface.NO_INTERFACE_NAME)) {
269 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_ADDED, intf));
270 } else {
271 Optional<Interface> oldIntf = findInterface(intf, old);
272 if (oldIntf.isPresent()) {
273 old.remove(oldIntf.get());
274 if (!oldIntf.get().equals(intf)) {
gaurav2c626cc2016-04-26 04:18:33 +0530275 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_UPDATED, intf, oldIntf.get()));
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700276 }
277 } else {
278 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_ADDED, intf));
279 }
280 }
281 }
282
283 for (Interface intf : old) {
284 if (!intf.name().equals(Interface.NO_INTERFACE_NAME)) {
285 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_REMOVED, intf));
286 }
287 }
Jonathan Hart4cb39882015-08-12 23:50:55 -0400288 } catch (ConfigException e) {
289 log.error("Error in interface config", e);
290 }
Jonathan Harteb8c9472015-08-05 07:43:13 -0700291 }
292
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700293 private Optional<Interface> findInterface(Interface intf, Set<Interface> set) {
294 return set.stream().filter(i -> i.name().equals(intf.name())).findAny();
295 }
296
Jonathan Harteb8c9472015-08-05 07:43:13 -0700297 private void removeInterfaces(ConnectPoint port) {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700298 Set<Interface> old = interfaces.remove(port);
299
300 old.stream()
301 .filter(i -> !i.name().equals(Interface.NO_INTERFACE_NAME))
302 .forEach(i -> process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_REMOVED, i)));
Jonathan Harteb8c9472015-08-05 07:43:13 -0700303 }
304
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700305 @Override
306 public void add(Interface intf) {
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700307 InterfaceConfig config =
308 configService.addConfig(intf.connectPoint(), CONFIG_CLASS);
309
310 config.addInterface(intf);
311
312 configService.applyConfig(intf.connectPoint(), CONFIG_CLASS, config.node());
313 }
314
315 @Override
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800316 public boolean remove(ConnectPoint connectPoint, String name) {
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800317 InterfaceConfig config = configService.addConfig(connectPoint, CONFIG_CLASS);
318 config.removeInterface(name);
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700319
320 try {
321 if (config.getInterfaces().isEmpty()) {
322 configService.removeConfig(connectPoint, CONFIG_CLASS);
323 } else {
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800324 configService.applyConfig(connectPoint, CONFIG_CLASS, config.node());
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700325 }
326 } catch (ConfigException e) {
327 log.error("Error reading interfaces JSON", e);
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700328 return false;
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700329 }
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800330
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700331 return true;
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700332 }
333
Jonathan Harteb8c9472015-08-05 07:43:13 -0700334 /**
335 * Listener for network config events.
336 */
337 private class InternalConfigListener implements NetworkConfigListener {
338
339 @Override
340 public void event(NetworkConfigEvent event) {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700341 if (event.configClass() == CONFIG_CLASS) {
342 switch (event.type()) {
343 case CONFIG_ADDED:
344 case CONFIG_UPDATED:
Charles Chanee993b12017-08-14 13:32:49 -0700345 event.config().ifPresent(config -> updateInterfaces((InterfaceConfig) config));
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700346 break;
347 case CONFIG_REMOVED:
Jonathan Harteb8c9472015-08-05 07:43:13 -0700348 removeInterfaces((ConnectPoint) event.subject());
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700349 break;
350 case CONFIG_REGISTERED:
351 case CONFIG_UNREGISTERED:
352 default:
353 break;
Jonathan Harteb8c9472015-08-05 07:43:13 -0700354 }
Jonathan Harteb8c9472015-08-05 07:43:13 -0700355 }
356 }
357 }
358}