0439d038a49a6b28c5fdcba09325bb0ebfa5efe5
[onosfw.git] /
1 /*
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
17 package org.onosproject.incubator.net.intf.impl;
18
19 import com.google.common.collect.ImmutableSet;
20 import com.google.common.collect.Maps;
21 import org.apache.felix.scr.annotations.Activate;
22 import org.apache.felix.scr.annotations.Component;
23 import org.apache.felix.scr.annotations.Deactivate;
24 import org.apache.felix.scr.annotations.Reference;
25 import org.apache.felix.scr.annotations.ReferenceCardinality;
26 import org.apache.felix.scr.annotations.Service;
27 import org.onlab.packet.IpAddress;
28 import org.onlab.packet.VlanId;
29 import org.onosproject.incubator.net.config.basics.ConfigException;
30 import org.onosproject.incubator.net.config.basics.InterfaceConfig;
31 import org.onosproject.incubator.net.intf.Interface;
32 import org.onosproject.incubator.net.intf.InterfaceAdminService;
33 import org.onosproject.incubator.net.intf.InterfaceService;
34 import org.onosproject.net.ConnectPoint;
35 import org.onosproject.net.config.NetworkConfigEvent;
36 import org.onosproject.net.config.NetworkConfigListener;
37 import org.onosproject.net.config.NetworkConfigService;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 import java.util.Collections;
42 import java.util.Map;
43 import java.util.Optional;
44 import java.util.Set;
45
46 import static java.util.stream.Collectors.collectingAndThen;
47 import static java.util.stream.Collectors.toSet;
48
49 /**
50  * Manages the inventory of interfaces in the system.
51  */
52 @Service
53 @Component(immediate = true)
54 public class InterfaceManager implements InterfaceService,
55         InterfaceAdminService {
56
57     private final Logger log = LoggerFactory.getLogger(getClass());
58
59     private static final Class<ConnectPoint> SUBJECT_CLASS = ConnectPoint.class;
60     private static final Class<InterfaceConfig> CONFIG_CLASS = InterfaceConfig.class;
61
62     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63     protected NetworkConfigService configService;
64
65     private final InternalConfigListener listener = new InternalConfigListener();
66
67     private final Map<ConnectPoint, Set<Interface>> interfaces = Maps.newConcurrentMap();
68
69     @Activate
70     public void activate() {
71         configService.addListener(listener);
72
73         // TODO address concurrency issues here
74         for (ConnectPoint subject : configService.getSubjects(SUBJECT_CLASS, CONFIG_CLASS)) {
75             InterfaceConfig config = configService.getConfig(subject, CONFIG_CLASS);
76
77             if (config != null) {
78                 updateInterfaces(config);
79             }
80         }
81
82         log.info("Started");
83     }
84
85     @Deactivate
86     public void deactivate() {
87         configService.removeListener(listener);
88
89         log.info("Stopped");
90     }
91
92     @Override
93     public Set<Interface> getInterfaces() {
94         return interfaces.values()
95                 .stream()
96                 .flatMap(set -> set.stream())
97                 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
98     }
99
100     @Override
101     public Set<Interface> getInterfacesByPort(ConnectPoint port) {
102         Set<Interface> intfs = interfaces.get(port);
103         if (intfs == null) {
104             return Collections.emptySet();
105         }
106         return ImmutableSet.copyOf(intfs);
107     }
108
109     @Override
110     public Set<Interface> getInterfacesByIp(IpAddress ip) {
111         return interfaces.values()
112                 .stream()
113                 .flatMap(set -> set.stream())
114                 .filter(intf -> intf.ipAddresses()
115                         .stream()
116                         .anyMatch(ia -> ia.ipAddress().equals(ip)))
117                 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
118     }
119
120     @Override
121     public Interface getMatchingInterface(IpAddress ip) {
122         Optional<Interface> match = interfaces.values()
123                 .stream()
124                 .flatMap(set -> set.stream())
125                 .filter(intf -> intf.ipAddresses()
126                         .stream()
127                         .anyMatch(intfIp -> intfIp.subnetAddress().contains(ip)))
128                 .findFirst();
129
130         if (match.isPresent()) {
131             return match.get();
132         }
133
134         return null;
135     }
136
137     @Override
138     public Set<Interface> getInterfacesByVlan(VlanId vlan) {
139         return interfaces.values()
140                 .stream()
141                 .flatMap(set -> set.stream())
142                 .filter(intf -> intf.vlan().equals(vlan))
143                 .collect(collectingAndThen(toSet(), ImmutableSet::copyOf));
144     }
145
146     private void updateInterfaces(InterfaceConfig intfConfig) {
147         try {
148             interfaces.put(intfConfig.subject(), intfConfig.getInterfaces());
149         } catch (ConfigException e) {
150             log.error("Error in interface config", e);
151         }
152     }
153
154     private void removeInterfaces(ConnectPoint port) {
155         interfaces.remove(port);
156     }
157
158     @Override
159     public void add(Interface intf) {
160         if (interfaces.containsKey(intf.connectPoint())) {
161             boolean conflict = interfaces.get(intf.connectPoint()).stream()
162                     .filter(i -> i.connectPoint().equals(intf.connectPoint()))
163                     .filter(i -> i.mac().equals(intf.mac()))
164                     .filter(i -> i.vlan().equals(intf.vlan()))
165                     .findAny().isPresent();
166
167             if (conflict) {
168                 log.error("Can't add interface because it conflicts with existing config");
169                 return;
170             }
171         }
172
173         InterfaceConfig config =
174                 configService.addConfig(intf.connectPoint(), CONFIG_CLASS);
175
176         config.addInterface(intf);
177
178         configService.applyConfig(intf.connectPoint(), CONFIG_CLASS, config.node());
179     }
180
181     @Override
182     public void remove(ConnectPoint connectPoint, VlanId vlanId) {
183         Optional<Interface> intf = interfaces.get(connectPoint).stream()
184                 .filter(i -> i.vlan().equals(vlanId))
185                 .findAny();
186
187         if (!intf.isPresent()) {
188             log.error("Can't find interface {}/{} to remove", connectPoint, vlanId);
189             return;
190         }
191
192         InterfaceConfig config = configService.addConfig(intf.get().connectPoint(), CONFIG_CLASS);
193         config.removeInterface(intf.get());
194
195         try {
196             if (config.getInterfaces().isEmpty()) {
197                 configService.removeConfig(connectPoint, CONFIG_CLASS);
198             } else {
199                 configService.applyConfig(intf.get().connectPoint(), CONFIG_CLASS, config.node());
200             }
201         } catch (ConfigException e) {
202             log.error("Error reading interfaces JSON", e);
203         }
204     }
205
206     /**
207      * Listener for network config events.
208      */
209     private class InternalConfigListener implements NetworkConfigListener {
210
211         @Override
212         public void event(NetworkConfigEvent event) {
213             switch (event.type()) {
214             case CONFIG_ADDED:
215             case CONFIG_UPDATED:
216                 if (event.configClass() == InterfaceConfig.class) {
217                     InterfaceConfig config =
218                             configService.getConfig((ConnectPoint) event.subject(), InterfaceConfig.class);
219                     updateInterfaces(config);
220                 }
221                 break;
222             case CONFIG_REMOVED:
223                 if (event.configClass() == InterfaceConfig.class) {
224                     removeInterfaces((ConnectPoint) event.subject());
225                 }
226                 break;
227             case CONFIG_REGISTERED:
228             case CONFIG_UNREGISTERED:
229             default:
230                 break;
231             }
232         }
233     }
234 }