blob: 16f1b5007125f2e8a18c42bb42e8b4e1c3d0f1f3 [file] [log] [blame]
Yi Tseng28767f02016-09-13 04:27:20 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Yi Tseng28767f02016-09-13 04:27:20 -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 */
Yi Tseng28767f02016-09-13 04:27:20 -070016package org.onosproject.vpls;
17
Yi Tseng28767f02016-09-13 04:27:20 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
Yi Tsengf4e13e32017-03-30 15:38:39 -070023import org.onlab.packet.MacAddress;
24import org.onlab.packet.VlanId;
Yi Tseng28767f02016-09-13 04:27:20 -070025import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.incubator.net.intf.Interface;
28import org.onosproject.incubator.net.intf.InterfaceEvent;
29import org.onosproject.incubator.net.intf.InterfaceListener;
30import org.onosproject.incubator.net.intf.InterfaceService;
31import org.onosproject.incubator.net.neighbour.NeighbourMessageContext;
32import org.onosproject.incubator.net.neighbour.NeighbourMessageHandler;
33import org.onosproject.incubator.net.neighbour.NeighbourResolutionService;
Yi Tsengf4e13e32017-03-30 15:38:39 -070034import org.onosproject.net.ConnectPoint;
Yi Tseng28767f02016-09-13 04:27:20 -070035import org.onosproject.net.Host;
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -070036import org.onosproject.net.config.NetworkConfigEvent;
37import org.onosproject.net.config.NetworkConfigListener;
38import org.onosproject.net.config.NetworkConfigService;
Yi Tseng28767f02016-09-13 04:27:20 -070039import org.onosproject.net.host.HostService;
Yi Tsengf4e13e32017-03-30 15:38:39 -070040import org.onosproject.vpls.api.VplsData;
41import org.onosproject.vpls.api.VplsStore;
Yi Tseng28767f02016-09-13 04:27:20 -070042import org.slf4j.Logger;
43
Yi Tsengf4e13e32017-03-30 15:38:39 -070044import java.util.Collection;
45import java.util.Objects;
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -070046import java.util.Set;
Yi Tsengf4e13e32017-03-30 15:38:39 -070047import java.util.stream.Collectors;
Yi Tseng28767f02016-09-13 04:27:20 -070048
49import static org.slf4j.LoggerFactory.getLogger;
50
51/**
Luca Prete092e8952016-10-26 16:25:56 +020052 * Handles neighbour messages for on behalf of the VPLS application. Handlers
53 * will be changed automatically by interface or network configuration events.
Yi Tseng28767f02016-09-13 04:27:20 -070054 */
55@Component(immediate = true)
56public class VplsNeighbourHandler {
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -070057 private static final String UNKNOWN_CONTEXT = "Unknown context type: {}";
58
Luca Prete092e8952016-10-26 16:25:56 +020059 private static final String CAN_NOT_FIND_VPLS =
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -070060 "Cannot find VPLS for port {} with VLAN Id {}.";
Yi Tseng28767f02016-09-13 04:27:20 -070061
62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 protected CoreService coreService;
64
65 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 protected InterfaceService interfaceService;
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected NeighbourResolutionService neighbourService;
70
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -070071 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yi Tsengf4e13e32017-03-30 15:38:39 -070072 protected VplsStore vplsStore;
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -070073
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected NetworkConfigService configService;
76
Luca Prete092e8952016-10-26 16:25:56 +020077 private VplsInterfaceListener interfaceListener =
78 new VplsInterfaceListener();
Yi Tseng28767f02016-09-13 04:27:20 -070079
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -070080 protected VplsNeighbourMessageHandler neighbourHandler =
Yi Tseng28767f02016-09-13 04:27:20 -070081 new VplsNeighbourMessageHandler();
82
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -070083 protected VplsConfigListener configListener =
84 new VplsConfigListener();
Yi Tseng28767f02016-09-13 04:27:20 -070085
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -070086 private final Logger log = getLogger(getClass());
Yi Tseng28767f02016-09-13 04:27:20 -070087
88 private ApplicationId appId;
89
90
91 @Activate
92 protected void activate() {
Yi Tsengf4e13e32017-03-30 15:38:39 -070093 appId = coreService.registerApplication(VplsManager.VPLS_APP);
Yi Tseng28767f02016-09-13 04:27:20 -070094 interfaceService.addListener(interfaceListener);
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -070095 configService.addListener(configListener);
96 configNeighbourHandler();
Yi Tseng28767f02016-09-13 04:27:20 -070097 }
98
99 @Deactivate
100 protected void deactivate() {
101 interfaceService.removeListener(interfaceListener);
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700102 configService.removeListener(configListener);
103 neighbourService.unregisterNeighbourHandlers(appId);
Yi Tseng28767f02016-09-13 04:27:20 -0700104 }
105
Yi Tsengf4e13e32017-03-30 15:38:39 -0700106 /**
107 * Registers neighbour handler to all available interfaces.
108 */
109 protected void configNeighbourHandler() {
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700110 neighbourService.unregisterNeighbourHandlers(appId);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700111 interfaceService
112 .getInterfaces()
113 .forEach(intf -> neighbourService.registerNeighbourHandler(intf,
114 neighbourHandler,
115 appId));
Yi Tseng28767f02016-09-13 04:27:20 -0700116 }
117
118 /**
119 * Handler for neighbour messages.
120 */
121 private class VplsNeighbourMessageHandler implements NeighbourMessageHandler {
122
123 @Override
124 public void handleMessage(NeighbourMessageContext context,
125 HostService hostService) {
Yi Tseng28767f02016-09-13 04:27:20 -0700126 switch (context.type()) {
127 case REQUEST:
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700128 handleRequest(context);
Yi Tseng28767f02016-09-13 04:27:20 -0700129 break;
130 case REPLY:
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700131 handleReply(context, hostService);
Yi Tseng28767f02016-09-13 04:27:20 -0700132 break;
Yi Tseng28767f02016-09-13 04:27:20 -0700133 default:
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700134 log.warn(UNKNOWN_CONTEXT, context.type());
Yi Tseng28767f02016-09-13 04:27:20 -0700135 break;
136 }
137 }
138 }
139
140 /**
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700141 * Handles request messages.
142 *
143 * @param context the message context
144 */
145 protected void handleRequest(NeighbourMessageContext context) {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700146 // Find target VPLS first, then broadcast to all interface of this VPLS
147 VplsData vplsData = findVpls(context);
148 if (vplsData != null) {
149 vplsData.interfaces().stream()
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700150 .filter(intf -> !context.inPort().equals(intf.connectPoint()))
151 .forEach(context::forward);
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700152 } else {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700153 log.warn(CAN_NOT_FIND_VPLS, context.inPort(), context.vlan());
154 context.drop();
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700155 }
156 }
157
158 /**
159 * Handles reply messages between VLAN tagged interfaces.
160 *
161 * @param context the message context
162 * @param hostService the host service
163 */
164 protected void handleReply(NeighbourMessageContext context,
165 HostService hostService) {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700166 // Find target VPLS, then reply to the host
167 VplsData vplsData = findVpls(context);
168 if (vplsData != null) {
169 MacAddress dstMac = context.dstMac();
170 Set<Host> hosts = hostService.getHostsByMac(dstMac);
171 hosts = hosts.stream()
172 .filter(host -> vplsData.interfaces().contains(getHostInterface(host)))
173 .collect(Collectors.toSet());
174
175 // reply to all host in same VPLS
176 hosts.stream()
177 .map(this::getHostInterface)
178 .filter(Objects::nonNull)
179 .forEach(context::forward);
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700180 } else {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700181 // this might be happened when we remove an interface from VPLS
182 // just ignore this message
183 log.warn(CAN_NOT_FIND_VPLS, context.inPort(), context.vlan());
184 context.drop();
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700185 }
186 }
187
188 /**
Yi Tsengf4e13e32017-03-30 15:38:39 -0700189 * Finds the VPLS with given neighbour message context.
190 *
191 * @param context the neighbour message context
192 * @return the VPLS for specific neighbour message context
193 */
194 private VplsData findVpls(NeighbourMessageContext context) {
195 Collection<VplsData> vplses = vplsStore.getAllVpls();
196 for (VplsData vplsData : vplses) {
197 Set<Interface> interfaces = vplsData.interfaces();
198 ConnectPoint port = context.inPort();
199 VlanId vlanId = context.vlan();
200 boolean match = interfaces.stream()
201 .anyMatch(iface -> iface.connectPoint().equals(port) &&
202 iface.vlan().equals(vlanId));
203 if (match) {
204 return vplsData;
205 }
206 }
207 return null;
208 }
209
210 /**
211 * Finds the network interface related to the host.
212 *
213 * @param host the host
214 * @return the interface related to the host
215 */
216 private Interface getHostInterface(Host host) {
217 Set<Interface> interfaces = interfaceService.getInterfaces();
218 return interfaces.stream()
219 .filter(iface -> iface.connectPoint().equals(host.location()) &&
220 iface.vlan().equals(host.vlan()))
221 .findFirst()
222 .orElse(null);
223 }
224
225 /**
Yi Tseng28767f02016-09-13 04:27:20 -0700226 * Listener for interface configuration events.
227 */
228 private class VplsInterfaceListener implements InterfaceListener {
229
230 @Override
231 public void event(InterfaceEvent event) {
Yong-hwan Kimfbf653c2016-09-21 10:05:22 -0700232 configNeighbourHandler();
233 }
234 }
235
236 /**
237 * Listener for network configuration events.
238 */
239 private class VplsConfigListener implements NetworkConfigListener {
240
241 @Override
242 public void event(NetworkConfigEvent event) {
243 configNeighbourHandler();
Yi Tseng28767f02016-09-13 04:27:20 -0700244 }
245 }
Carolina Fernandezb1cef5c2016-11-22 19:18:40 +0100246}