blob: ad810638a3675b7663240ee8b25d371c386c1c56 [file] [log] [blame]
yoonseon5a51ef72016-10-26 14:50:09 -07001/*
2 * Copyright 2016-present 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.virtual.impl.provider;
18
Yoonseon Hanc8089db2017-03-22 20:22:12 +090019import com.google.common.collect.Sets;
yoonseon5a51ef72016-10-26 14:50:09 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Modified;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.onlab.packet.Ethernet;
27import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
29import org.onosproject.incubator.net.virtual.NetworkId;
30import org.onosproject.incubator.net.virtual.TenantId;
31import org.onosproject.incubator.net.virtual.VirtualDevice;
32import org.onosproject.incubator.net.virtual.VirtualNetwork;
33import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
Harold Huangbee92f62017-06-07 22:39:37 +080034import org.onosproject.incubator.net.virtual.VirtualPacketContext;
yoonseon5a51ef72016-10-26 14:50:09 -070035import org.onosproject.incubator.net.virtual.VirtualPort;
36import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider;
37import org.onosproject.incubator.net.virtual.provider.VirtualPacketProvider;
38import org.onosproject.incubator.net.virtual.provider.VirtualPacketProviderService;
yoonseon736a73b2017-01-26 14:27:48 -080039import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
yoonseon5a51ef72016-10-26 14:50:09 -070040import org.onosproject.net.ConnectPoint;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090041import org.onosproject.net.DeviceId;
yoonseon5a51ef72016-10-26 14:50:09 -070042import org.onosproject.net.PortNumber;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.TrafficTreatment;
45import org.onosproject.net.flow.instructions.Instruction;
46import org.onosproject.net.flow.instructions.Instructions;
47import org.onosproject.net.packet.DefaultInboundPacket;
48import org.onosproject.net.packet.DefaultOutboundPacket;
49import org.onosproject.net.packet.InboundPacket;
50import org.onosproject.net.packet.OutboundPacket;
51import org.onosproject.net.packet.PacketContext;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090052import org.onosproject.net.packet.PacketPriority;
yoonseon5a51ef72016-10-26 14:50:09 -070053import org.onosproject.net.packet.PacketProcessor;
54import org.onosproject.net.packet.PacketService;
55import org.onosproject.net.provider.ProviderId;
56import org.osgi.service.component.ComponentContext;
57import org.slf4j.Logger;
58
59import java.nio.ByteBuffer;
60import java.util.Dictionary;
61import java.util.HashSet;
yoonseon5a51ef72016-10-26 14:50:09 -070062import java.util.Optional;
63import java.util.Set;
64import java.util.stream.Collectors;
65
66import static org.slf4j.LoggerFactory.getLogger;
67
68@Component(immediate = true)
69public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
70 implements VirtualPacketProvider {
71
72 private static final int PACKET_PROCESSOR_PRIORITY = 1;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090073 private static final PacketPriority VIRTUAL_PACKET_PRIORITY = PacketPriority.REACTIVE;
yoonseon5a51ef72016-10-26 14:50:09 -070074
75 private final Logger log = getLogger(getClass());
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
yoonseon5a51ef72016-10-26 14:50:09 -070078 protected PacketService packetService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected CoreService coreService;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yoonseon Hanc8089db2017-03-22 20:22:12 +090084 protected VirtualNetworkAdminService vnaService;
yoonseon5a51ef72016-10-26 14:50:09 -070085
yoonseon736a73b2017-01-26 14:27:48 -080086 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected VirtualProviderRegistryService providerRegistryService;
yoonseon5a51ef72016-10-26 14:50:09 -070088
Harold Huangbee92f62017-06-07 22:39:37 +080089 private ApplicationId appId;
90 private InternalPacketProcessor processor;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090091
92 private Set<NetworkId> requestsSet = Sets.newHashSet();
yoonseon5a51ef72016-10-26 14:50:09 -070093
94 /**
95 * Creates a provider with the supplied identifier.
yoonseon5a51ef72016-10-26 14:50:09 -070096 */
97 public DefaultVirtualPacketProvider() {
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070098 super(new ProviderId("virtual-packet", "org.onosproject.virtual.virtual-packet"));
yoonseon5a51ef72016-10-26 14:50:09 -070099 }
100
101 @Activate
102 public void activate() {
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700103 appId = coreService.registerApplication("org.onosproject.virtual.virtual-packet");
yoonseon736a73b2017-01-26 14:27:48 -0800104 providerRegistryService.registerProvider(this);
yoonseon5a51ef72016-10-26 14:50:09 -0700105
yoonseon5a51ef72016-10-26 14:50:09 -0700106 log.info("Started");
107 }
108
109 @Deactivate
110 public void deactivate() {
Jonathan Hart66028672017-02-02 16:25:49 -0800111 if (processor != null) {
112 packetService.removeProcessor(processor);
113 }
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700114 providerRegistryService.unregisterProvider(this);
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900115 log.info("Stopped");
yoonseon5a51ef72016-10-26 14:50:09 -0700116 }
117
118 @Modified
119 protected void modified(ComponentContext context) {
120 Dictionary<?, ?> properties = context.getProperties();
121 }
122
123
124 @Override
125 public void emit(NetworkId networkId, OutboundPacket packet) {
Harold Huangbee92f62017-06-07 22:39:37 +0800126 devirtualize(networkId, packet)
127 .forEach(outboundPacket -> packetService.emit(outboundPacket));
yoonseon5a51ef72016-10-26 14:50:09 -0700128 }
129
yoonseonfb4a1db2017-01-31 11:38:30 -0800130 @Override
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900131 public void startPacketHandling(NetworkId networkId) {
132 requestsSet.add(networkId);
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900133 if (processor == null) {
134 processor = new InternalPacketProcessor();
135 packetService.addProcessor(processor, PACKET_PROCESSOR_PRIORITY);
136 }
137 }
138
139 @Override
140 public void stopPacketHandling(NetworkId networkId) {
141 requestsSet.remove(networkId);
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900142 if (requestsSet.isEmpty()) {
143 packetService.removeProcessor(processor);
144 processor = null;
145 }
yoonseonfb4a1db2017-01-31 11:38:30 -0800146 }
147
yoonseon5a51ef72016-10-26 14:50:09 -0700148 /**
Harold Huangbee92f62017-06-07 22:39:37 +0800149 * Send the outbound packet of a virtual context.
150 * This method is designed to support Context's send() method that invoked
151 * by applications.
152 * See {@link org.onosproject.net.packet.PacketContext}
153 *
154 * @param virtualPacketContext virtual packet context
155 */
156 protected void send(VirtualPacketContext virtualPacketContext) {
157 devirtualizeContext(virtualPacketContext)
158 .forEach(outboundPacket -> packetService.emit(outboundPacket));
159 }
160
161 /**
yoonseon5a51ef72016-10-26 14:50:09 -0700162 * Translate the requested physical PacketContext into a virtual PacketContext.
Harold Huangbee92f62017-06-07 22:39:37 +0800163 * See {@link org.onosproject.net.packet.PacketContext}
yoonseon5a51ef72016-10-26 14:50:09 -0700164 *
165 * @param context A physical PacketContext be translated
166 * @return A translated virtual PacketContext
167 */
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900168 private VirtualPacketContext virtualize(PacketContext context) {
yoonseon5a51ef72016-10-26 14:50:09 -0700169
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900170 VirtualPort vPort = getMappedVirtualPort(context.inPacket().receivedFrom());
yoonseon5a51ef72016-10-26 14:50:09 -0700171
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900172 if (vPort != null) {
yoonseon5a51ef72016-10-26 14:50:09 -0700173 ConnectPoint cp = new ConnectPoint(vPort.element().id(),
174 vPort.number());
175
176 Ethernet eth = context.inPacket().parsed();
177 eth.setVlanID(Ethernet.VLAN_UNTAGGED);
178
179 InboundPacket inPacket =
180 new DefaultInboundPacket(cp, eth,
181 ByteBuffer.wrap(eth.serialize()));
182
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900183 DefaultOutboundPacket outPkt =
184 new DefaultOutboundPacket(cp.deviceId(),
185 DefaultTrafficTreatment.builder().build(),
186 ByteBuffer.wrap(eth.serialize()));
187
yoonseon5a51ef72016-10-26 14:50:09 -0700188 VirtualPacketContext vContext =
Harold Huangbee92f62017-06-07 22:39:37 +0800189 new DefaultVirtualPacketContext(context.time(), inPacket, outPkt,
190 context.isHandled(), vPort.networkId(),
yoonseon5a51ef72016-10-26 14:50:09 -0700191 this);
192
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900193 return vContext;
194 } else {
195 return null;
yoonseon5a51ef72016-10-26 14:50:09 -0700196 }
197
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900198 }
199
200 /**
201 * Find the corresponding virtual port with the physical port.
202 *
203 * @param cp the connect point for the physical network
204 * @return a virtual port
205 */
206 private VirtualPort getMappedVirtualPort(ConnectPoint cp) {
207 Set<TenantId> tIds = vnaService.getTenantIds();
208
209 Set<VirtualNetwork> vNetworks = new HashSet<>();
210 tIds.forEach(tid -> vNetworks.addAll(vnaService.getVirtualNetworks(tid)));
211
212 for (VirtualNetwork vNet : vNetworks) {
213 Set<VirtualDevice> vDevices = vnaService.getVirtualDevices(vNet.id());
214
215 Set<VirtualPort> vPorts = new HashSet<>();
216 vDevices.forEach(dev -> vPorts
217 .addAll(vnaService.getVirtualPorts(dev.networkId(), dev.id())));
218
219 VirtualPort vPort = vPorts.stream()
220 .filter(vp -> vp.realizedBy().equals(cp))
221 .findFirst().orElse(null);
222
223 if (vPort != null) {
224 return vPort;
225 }
226 }
227
228 return null;
yoonseon5a51ef72016-10-26 14:50:09 -0700229 }
230
231 /**
Harold Huangbee92f62017-06-07 22:39:37 +0800232 * Translate the requested virtual outbound packet into
233 * a set of physical OutboundPacket.
234 * See {@link org.onosproject.net.packet.OutboundPacket}
yoonseon5a51ef72016-10-26 14:50:09 -0700235 *
Harold Huangbee92f62017-06-07 22:39:37 +0800236 * @param packet an OutboundPacket to be translated
237 * @return a set of de-virtualized (physical) OutboundPacket
yoonseon5a51ef72016-10-26 14:50:09 -0700238 */
Harold Huangbee92f62017-06-07 22:39:37 +0800239 private Set<OutboundPacket> devirtualize(NetworkId networkId, OutboundPacket packet) {
240 Set<OutboundPacket> outboundPackets = new HashSet<>();
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900241 Set<VirtualPort> vPorts = vnaService
yoonseon5a51ef72016-10-26 14:50:09 -0700242 .getVirtualPorts(networkId, packet.sendThrough());
243
yoonseon5a51ef72016-10-26 14:50:09 -0700244 TrafficTreatment.Builder commonTreatmentBuilder
245 = DefaultTrafficTreatment.builder();
246 packet.treatment().allInstructions().stream()
247 .filter(i -> i.type() != Instruction.Type.OUTPUT)
248 .forEach(i -> commonTreatmentBuilder.add(i));
249 TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
250
Harold Huangbee92f62017-06-07 22:39:37 +0800251 PortNumber vOutPortNum = packet.treatment().allInstructions().stream()
252 .filter(i -> i.type() == Instruction.Type.OUTPUT)
253 .map(i -> ((Instructions.OutputInstruction) i).port())
254 .findFirst().get();
yoonseon5a51ef72016-10-26 14:50:09 -0700255
Harold Huangbee92f62017-06-07 22:39:37 +0800256 if (!vOutPortNum.isLogical()) {
257 Optional<ConnectPoint> optionalCpOut = vPorts.stream()
258 .filter(v -> v.number().equals(vOutPortNum))
259 .map(v -> v.realizedBy())
260 .findFirst();
261 if (!optionalCpOut.isPresent()) {
262 log.warn("Port {} is not realized yet, in Network {}, Device {}",
263 vOutPortNum, networkId, packet.sendThrough());
264 return outboundPackets;
265 }
266 ConnectPoint egressPoint = optionalCpOut.get();
267
268 TrafficTreatment treatment = DefaultTrafficTreatment
269 .builder(commonTreatment)
270 .setOutput(egressPoint.port()).build();
271
272 OutboundPacket outboundPacket = new DefaultOutboundPacket(
273 egressPoint.deviceId(), treatment, packet.data());
274 outboundPackets.add(outboundPacket);
275 } else {
276 if (vOutPortNum == PortNumber.FLOOD) {
277 for (VirtualPort outPort : vPorts) {
278 ConnectPoint cpOut = outPort.realizedBy();
279 if (cpOut != null) {
280 TrafficTreatment treatment = DefaultTrafficTreatment
281 .builder(commonTreatment)
282 .setOutput(cpOut.port()).build();
283 OutboundPacket outboundPacket = new DefaultOutboundPacket(
284 cpOut.deviceId(), treatment, packet.data());
285 outboundPackets.add(outboundPacket);
286 } else {
287 log.warn("Port {} is not realized yet, in Network {}, Device {}",
288 outPort.number(), networkId, packet.sendThrough());
289 }
290 }
291 }
292 }
293
294 return outboundPackets;
yoonseon5a51ef72016-10-26 14:50:09 -0700295 }
296
297 /**
Harold Huangbee92f62017-06-07 22:39:37 +0800298 * Translate the requested virtual packet context into
299 * a set of physical outbound packets.
yoonseon5a51ef72016-10-26 14:50:09 -0700300 *
Harold Huangbee92f62017-06-07 22:39:37 +0800301 * @param context A handled virtual packet context
yoonseon5a51ef72016-10-26 14:50:09 -0700302 */
Harold Huangbee92f62017-06-07 22:39:37 +0800303 private Set<OutboundPacket> devirtualizeContext(VirtualPacketContext context) {
yoonseon5a51ef72016-10-26 14:50:09 -0700304
Harold Huangbee92f62017-06-07 22:39:37 +0800305 Set<OutboundPacket> outboundPackets = new HashSet<>();
306
307 NetworkId networkId = context.networkId();
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900308 TrafficTreatment vTreatment = context.treatmentBuilder().build();
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900309 DeviceId sendThrough = context.outPacket().sendThrough();
yoonseon5a51ef72016-10-26 14:50:09 -0700310
Harold Huangbee92f62017-06-07 22:39:37 +0800311 Set<VirtualPort> vPorts = vnaService
312 .getVirtualPorts(networkId, sendThrough);
313
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900314 PortNumber vOutPortNum = vTreatment.allInstructions().stream()
315 .filter(i -> i.type() == Instruction.Type.OUTPUT)
316 .map(i -> ((Instructions.OutputInstruction) i).port())
317 .findFirst().get();
318
319 TrafficTreatment.Builder commonTreatmentBuilder
320 = DefaultTrafficTreatment.builder();
321 vTreatment.allInstructions().stream()
322 .filter(i -> i.type() != Instruction.Type.OUTPUT)
323 .forEach(i -> commonTreatmentBuilder.add(i));
324 TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
325
326 if (!vOutPortNum.isLogical()) {
Harold Huangbee92f62017-06-07 22:39:37 +0800327 Optional<ConnectPoint> optionalCpOut = vPorts.stream()
328 .filter(v -> v.number().equals(vOutPortNum))
329 .map(v -> v.realizedBy())
330 .findFirst();
331 if (!optionalCpOut.isPresent()) {
332 log.warn("Port {} is not realized yet, in Network {}, Device {}",
333 vOutPortNum, networkId, sendThrough);
334 return outboundPackets;
335 }
336 ConnectPoint egressPoint = optionalCpOut.get();
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900337
Harold Huangbee92f62017-06-07 22:39:37 +0800338 TrafficTreatment treatment = DefaultTrafficTreatment
339 .builder(commonTreatment)
340 .setOutput(egressPoint.port()).build();
341
342 OutboundPacket outboundPacket = new DefaultOutboundPacket(
343 egressPoint.deviceId(), treatment, context.outPacket().data());
344 outboundPackets.add(outboundPacket);
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900345 } else {
346 if (vOutPortNum == PortNumber.FLOOD) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900347 Set<VirtualPort> outPorts = vPorts.stream()
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700348 .filter(vp -> !vp.number().isLogical())
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900349 .filter(vp -> vp.number() !=
350 context.inPacket().receivedFrom().port())
351 .collect(Collectors.toSet());
352
353 for (VirtualPort outPort : outPorts) {
Harold Huangbee92f62017-06-07 22:39:37 +0800354 ConnectPoint cpOut = outPort.realizedBy();
355 if (cpOut != null) {
356 TrafficTreatment treatment = DefaultTrafficTreatment
357 .builder(commonTreatment)
358 .setOutput(cpOut.port()).build();
359 OutboundPacket outboundPacket = new DefaultOutboundPacket(
360 cpOut.deviceId(), treatment, context.outPacket().data());
361 outboundPackets.add(outboundPacket);
362 } else {
363 log.warn("Port {} is not realized yet, in Network {}, Device {}",
364 outPort.number(), networkId, sendThrough);
365 }
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900366 }
367 }
yoonseon5a51ef72016-10-26 14:50:09 -0700368 }
Harold Huangbee92f62017-06-07 22:39:37 +0800369 return outboundPackets;
yoonseon5a51ef72016-10-26 14:50:09 -0700370 }
371
372 private final class InternalPacketProcessor implements PacketProcessor {
373
374 @Override
375 public void process(PacketContext context) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900376 VirtualPacketContext vContexts = virtualize(context);
yoonseon736a73b2017-01-26 14:27:48 -0800377
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900378 if (vContexts == null) {
379 return;
380 }
381
382 VirtualPacketProviderService service =
383 (VirtualPacketProviderService) providerRegistryService
Harold Huangbee92f62017-06-07 22:39:37 +0800384 .getProviderService(vContexts.networkId(),
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900385 VirtualPacketProvider.class);
386 if (service != null) {
387 service.processPacket(vContexts);
388 }
yoonseon5a51ef72016-10-26 14:50:09 -0700389 }
390 }
391}