blob: d297080ebf054f18d0bc81922de99f90ea1a3d52 [file] [log] [blame]
Jonathan Harteb8c9472015-08-05 07:43:13 -07001/*
2 * Copyright 2015 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.incubator.net.intf.impl;
18
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Maps;
Jonathan Hart7dbe6292015-11-10 08:33:17 -080021import com.google.common.collect.Sets;
Jonathan Harteb8c9472015-08-05 07:43:13 -070022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.apache.felix.scr.annotations.Service;
28import org.onlab.packet.IpAddress;
29import org.onlab.packet.VlanId;
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -070030import org.onosproject.event.ListenerRegistry;
Jonathan Hart4cb39882015-08-12 23:50:55 -040031import org.onosproject.incubator.net.config.basics.ConfigException;
Jonathan Harteb8c9472015-08-05 07:43:13 -070032import org.onosproject.incubator.net.config.basics.InterfaceConfig;
33import org.onosproject.incubator.net.intf.Interface;
Jonathan Hart0bdf8372015-10-08 14:30:36 -070034import org.onosproject.incubator.net.intf.InterfaceAdminService;
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -070035import org.onosproject.incubator.net.intf.InterfaceEvent;
36import org.onosproject.incubator.net.intf.InterfaceListener;
Jonathan Harteb8c9472015-08-05 07:43:13 -070037import org.onosproject.incubator.net.intf.InterfaceService;
38import org.onosproject.net.ConnectPoint;
Jonathan Hart4cb39882015-08-12 23:50:55 -040039import org.onosproject.net.config.NetworkConfigEvent;
40import org.onosproject.net.config.NetworkConfigListener;
41import org.onosproject.net.config.NetworkConfigService;
Jonathan Harteb8c9472015-08-05 07:43:13 -070042import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
Jonathan Hart4cb39882015-08-12 23:50:55 -040045import java.util.Collections;
Jonathan Harteb8c9472015-08-05 07:43:13 -070046import java.util.Map;
47import java.util.Optional;
48import java.util.Set;
49
50import static java.util.stream.Collectors.collectingAndThen;
51import static java.util.stream.Collectors.toSet;
52
53/**
54 * Manages the inventory of interfaces in the system.
55 */
56@Service
57@Component(immediate = true)
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -070058public class InterfaceManager extends ListenerRegistry<InterfaceEvent, InterfaceListener>
59 implements InterfaceService, InterfaceAdminService {
Jonathan Harteb8c9472015-08-05 07:43:13 -070060
61 private final Logger log = LoggerFactory.getLogger(getClass());
62
Jonathan Hart4cb39882015-08-12 23:50:55 -040063 private static final Class<ConnectPoint> SUBJECT_CLASS = ConnectPoint.class;
64 private static final Class<InterfaceConfig> CONFIG_CLASS = InterfaceConfig.class;
Jonathan Harteb8c9472015-08-05 07:43:13 -070065
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hart4cb39882015-08-12 23:50:55 -040067 protected NetworkConfigService configService;
Jonathan Harteb8c9472015-08-05 07:43:13 -070068
69 private final InternalConfigListener listener = new InternalConfigListener();
70
71 private final Map<ConnectPoint, Set<Interface>> interfaces = Maps.newConcurrentMap();
72
73 @Activate
74 public void activate() {
75 configService.addListener(listener);
76
Jonathan Hart4cb39882015-08-12 23:50:55 -040077 // TODO address concurrency issues here
78 for (ConnectPoint subject : configService.getSubjects(SUBJECT_CLASS, CONFIG_CLASS)) {
79 InterfaceConfig config = configService.getConfig(subject, CONFIG_CLASS);
Jonathan Harteb8c9472015-08-05 07:43:13 -070080
Jonathan Hart4cb39882015-08-12 23:50:55 -040081 if (config != null) {
82 updateInterfaces(config);
Jonathan Harteb8c9472015-08-05 07:43:13 -070083 }
84 }
85
86 log.info("Started");
87 }
88
89 @Deactivate
90 public void deactivate() {
91 configService.removeListener(listener);
92
93 log.info("Stopped");
94 }
95
96 @Override
97 public Set<Interface> getInterfaces() {
98 return interfaces.values()
99 .stream()
100 .flatMap(set -> set.stream())
101 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
102 }
103
104 @Override
Jonathan Hart43d232e2016-02-03 15:34:10 -0800105 public Interface getInterfaceByName(ConnectPoint connectPoint, String name) {
106 Optional<Interface> intf =
107 interfaces.getOrDefault(connectPoint, Collections.emptySet())
108 .stream()
109 .filter(i -> i.name().equals(name))
110 .findAny();
111
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800112 return intf.orElse(null);
Jonathan Hart43d232e2016-02-03 15:34:10 -0800113 }
114
115 @Override
Jonathan Harteb8c9472015-08-05 07:43:13 -0700116 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400117 Set<Interface> intfs = interfaces.get(port);
118 if (intfs == null) {
119 return Collections.emptySet();
120 }
121 return ImmutableSet.copyOf(intfs);
Jonathan Harteb8c9472015-08-05 07:43:13 -0700122 }
123
124 @Override
125 public Set<Interface> getInterfacesByIp(IpAddress ip) {
126 return interfaces.values()
127 .stream()
128 .flatMap(set -> set.stream())
Jonathan Hart4cb39882015-08-12 23:50:55 -0400129 .filter(intf -> intf.ipAddresses()
130 .stream()
131 .anyMatch(ia -> ia.ipAddress().equals(ip)))
Jonathan Harteb8c9472015-08-05 07:43:13 -0700132 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
133 }
134
135 @Override
136 public Interface getMatchingInterface(IpAddress ip) {
137 Optional<Interface> match = interfaces.values()
138 .stream()
139 .flatMap(set -> set.stream())
140 .filter(intf -> intf.ipAddresses()
141 .stream()
142 .anyMatch(intfIp -> intfIp.subnetAddress().contains(ip)))
143 .findFirst();
144
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800145 return match.orElse(null);
Jonathan Harteb8c9472015-08-05 07:43:13 -0700146 }
147
148 @Override
149 public Set<Interface> getInterfacesByVlan(VlanId vlan) {
150 return interfaces.values()
151 .stream()
152 .flatMap(set -> set.stream())
153 .filter(intf -> intf.vlan().equals(vlan))
154 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
155 }
156
157 private void updateInterfaces(InterfaceConfig intfConfig) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400158 try {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700159 Set<Interface> old = interfaces.put(intfConfig.subject(),
160 Sets.newHashSet(intfConfig.getInterfaces()));
161
162 if (old == null) {
163 old = Collections.emptySet();
164 }
165
166 for (Interface intf : intfConfig.getInterfaces()) {
167 if (intf.name().equals(Interface.NO_INTERFACE_NAME)) {
168 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_ADDED, intf));
169 } else {
170 Optional<Interface> oldIntf = findInterface(intf, old);
171 if (oldIntf.isPresent()) {
172 old.remove(oldIntf.get());
173 if (!oldIntf.get().equals(intf)) {
174 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_UPDATED, intf));
175 }
176 } else {
177 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_ADDED, intf));
178 }
179 }
180 }
181
182 for (Interface intf : old) {
183 if (!intf.name().equals(Interface.NO_INTERFACE_NAME)) {
184 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_REMOVED, intf));
185 }
186 }
Jonathan Hart4cb39882015-08-12 23:50:55 -0400187 } catch (ConfigException e) {
188 log.error("Error in interface config", e);
189 }
Jonathan Harteb8c9472015-08-05 07:43:13 -0700190 }
191
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700192 private Optional<Interface> findInterface(Interface intf, Set<Interface> set) {
193 return set.stream().filter(i -> i.name().equals(intf.name())).findAny();
194 }
195
Jonathan Harteb8c9472015-08-05 07:43:13 -0700196 private void removeInterfaces(ConnectPoint port) {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700197 Set<Interface> old = interfaces.remove(port);
198
199 old.stream()
200 .filter(i -> !i.name().equals(Interface.NO_INTERFACE_NAME))
201 .forEach(i -> process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_REMOVED, i)));
Jonathan Harteb8c9472015-08-05 07:43:13 -0700202 }
203
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700204 @Override
205 public void add(Interface intf) {
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700206 InterfaceConfig config =
207 configService.addConfig(intf.connectPoint(), CONFIG_CLASS);
208
209 config.addInterface(intf);
210
211 configService.applyConfig(intf.connectPoint(), CONFIG_CLASS, config.node());
212 }
213
214 @Override
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800215 public boolean remove(ConnectPoint connectPoint, String name) {
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800216 InterfaceConfig config = configService.addConfig(connectPoint, CONFIG_CLASS);
217 config.removeInterface(name);
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700218
219 try {
220 if (config.getInterfaces().isEmpty()) {
221 configService.removeConfig(connectPoint, CONFIG_CLASS);
222 } else {
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800223 configService.applyConfig(connectPoint, CONFIG_CLASS, config.node());
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700224 }
225 } catch (ConfigException e) {
226 log.error("Error reading interfaces JSON", e);
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700227 return false;
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700228 }
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800229
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700230 return true;
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700231 }
232
Jonathan Harteb8c9472015-08-05 07:43:13 -0700233 /**
234 * Listener for network config events.
235 */
236 private class InternalConfigListener implements NetworkConfigListener {
237
238 @Override
239 public void event(NetworkConfigEvent event) {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700240 if (event.configClass() == CONFIG_CLASS) {
241 switch (event.type()) {
242 case CONFIG_ADDED:
243 case CONFIG_UPDATED:
Jonathan Harteb8c9472015-08-05 07:43:13 -0700244 InterfaceConfig config =
245 configService.getConfig((ConnectPoint) event.subject(), InterfaceConfig.class);
246 updateInterfaces(config);
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700247 break;
248 case CONFIG_REMOVED:
Jonathan Harteb8c9472015-08-05 07:43:13 -0700249 removeInterfaces((ConnectPoint) event.subject());
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700250 break;
251 case CONFIG_REGISTERED:
252 case CONFIG_UNREGISTERED:
253 default:
254 break;
Jonathan Harteb8c9472015-08-05 07:43:13 -0700255 }
Jonathan Harteb8c9472015-08-05 07:43:13 -0700256 }
257 }
258 }
259}