blob: 9da21778e69429b13e5f9f3a115323e5df527605 [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
112 return intf.isPresent() ? intf.get() : null;
113 }
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
145 if (match.isPresent()) {
146 return match.get();
147 }
148
149 return null;
150 }
151
152 @Override
153 public Set<Interface> getInterfacesByVlan(VlanId vlan) {
154 return interfaces.values()
155 .stream()
156 .flatMap(set -> set.stream())
157 .filter(intf -> intf.vlan().equals(vlan))
158 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
159 }
160
161 private void updateInterfaces(InterfaceConfig intfConfig) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400162 try {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700163 Set<Interface> old = interfaces.put(intfConfig.subject(),
164 Sets.newHashSet(intfConfig.getInterfaces()));
165
166 if (old == null) {
167 old = Collections.emptySet();
168 }
169
170 for (Interface intf : intfConfig.getInterfaces()) {
171 if (intf.name().equals(Interface.NO_INTERFACE_NAME)) {
172 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_ADDED, intf));
173 } else {
174 Optional<Interface> oldIntf = findInterface(intf, old);
175 if (oldIntf.isPresent()) {
176 old.remove(oldIntf.get());
177 if (!oldIntf.get().equals(intf)) {
178 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_UPDATED, intf));
179 }
180 } else {
181 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_ADDED, intf));
182 }
183 }
184 }
185
186 for (Interface intf : old) {
187 if (!intf.name().equals(Interface.NO_INTERFACE_NAME)) {
188 process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_REMOVED, intf));
189 }
190 }
Jonathan Hart4cb39882015-08-12 23:50:55 -0400191 } catch (ConfigException e) {
192 log.error("Error in interface config", e);
193 }
Jonathan Harteb8c9472015-08-05 07:43:13 -0700194 }
195
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700196 private Optional<Interface> findInterface(Interface intf, Set<Interface> set) {
197 return set.stream().filter(i -> i.name().equals(intf.name())).findAny();
198 }
199
Jonathan Harteb8c9472015-08-05 07:43:13 -0700200 private void removeInterfaces(ConnectPoint port) {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700201 Set<Interface> old = interfaces.remove(port);
202
203 old.stream()
204 .filter(i -> !i.name().equals(Interface.NO_INTERFACE_NAME))
205 .forEach(i -> process(new InterfaceEvent(InterfaceEvent.Type.INTERFACE_REMOVED, i)));
Jonathan Harteb8c9472015-08-05 07:43:13 -0700206 }
207
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700208 @Override
209 public void add(Interface intf) {
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700210 InterfaceConfig config =
211 configService.addConfig(intf.connectPoint(), CONFIG_CLASS);
212
213 config.addInterface(intf);
214
215 configService.applyConfig(intf.connectPoint(), CONFIG_CLASS, config.node());
216 }
217
218 @Override
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800219 public boolean remove(ConnectPoint connectPoint, String name) {
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800220 InterfaceConfig config = configService.addConfig(connectPoint, CONFIG_CLASS);
221 config.removeInterface(name);
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700222
223 try {
224 if (config.getInterfaces().isEmpty()) {
225 configService.removeConfig(connectPoint, CONFIG_CLASS);
226 } else {
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800227 configService.applyConfig(connectPoint, CONFIG_CLASS, config.node());
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700228 }
229 } catch (ConfigException e) {
230 log.error("Error reading interfaces JSON", e);
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700231 return false;
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700232 }
Jonathan Hart7dbe6292015-11-10 08:33:17 -0800233
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700234 return true;
Jonathan Hart0bdf8372015-10-08 14:30:36 -0700235 }
236
Jonathan Harteb8c9472015-08-05 07:43:13 -0700237 /**
238 * Listener for network config events.
239 */
240 private class InternalConfigListener implements NetworkConfigListener {
241
242 @Override
243 public void event(NetworkConfigEvent event) {
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700244 if (event.configClass() == CONFIG_CLASS) {
245 switch (event.type()) {
246 case CONFIG_ADDED:
247 case CONFIG_UPDATED:
Jonathan Harteb8c9472015-08-05 07:43:13 -0700248 InterfaceConfig config =
249 configService.getConfig((ConnectPoint) event.subject(), InterfaceConfig.class);
250 updateInterfaces(config);
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700251 break;
252 case CONFIG_REMOVED:
Jonathan Harteb8c9472015-08-05 07:43:13 -0700253 removeInterfaces((ConnectPoint) event.subject());
Jonathan Hart4b5c6dc2015-10-13 14:27:48 -0700254 break;
255 case CONFIG_REGISTERED:
256 case CONFIG_UNREGISTERED:
257 default:
258 break;
Jonathan Harteb8c9472015-08-05 07:43:13 -0700259 }
Jonathan Harteb8c9472015-08-05 07:43:13 -0700260 }
261 }
262 }
263}