blob: 36b4397c2d025775bc0629b30cb7bf51228e88ba [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
19import com.google.common.collect.Maps;
20import 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;
34import org.onosproject.incubator.net.virtual.VirtualPort;
35import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider;
36import org.onosproject.incubator.net.virtual.provider.VirtualPacketProvider;
37import org.onosproject.incubator.net.virtual.provider.VirtualPacketProviderService;
yoonseon736a73b2017-01-26 14:27:48 -080038import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
yoonseon5a51ef72016-10-26 14:50:09 -070039import org.onosproject.net.ConnectPoint;
40import org.onosproject.net.PortNumber;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.TrafficTreatment;
43import org.onosproject.net.flow.instructions.Instruction;
44import org.onosproject.net.flow.instructions.Instructions;
45import org.onosproject.net.packet.DefaultInboundPacket;
46import org.onosproject.net.packet.DefaultOutboundPacket;
47import org.onosproject.net.packet.InboundPacket;
48import org.onosproject.net.packet.OutboundPacket;
49import org.onosproject.net.packet.PacketContext;
50import org.onosproject.net.packet.PacketProcessor;
51import org.onosproject.net.packet.PacketService;
52import org.onosproject.net.provider.ProviderId;
53import org.osgi.service.component.ComponentContext;
54import org.slf4j.Logger;
55
56import java.nio.ByteBuffer;
57import java.util.Dictionary;
58import java.util.HashSet;
59import java.util.Map;
60import java.util.Optional;
61import java.util.Set;
62import java.util.stream.Collectors;
63
64import static org.slf4j.LoggerFactory.getLogger;
65
66@Component(immediate = true)
67public class DefaultVirtualPacketProvider extends AbstractVirtualProvider
68 implements VirtualPacketProvider {
69
70 private static final int PACKET_PROCESSOR_PRIORITY = 1;
71
72 private final Logger log = getLogger(getClass());
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
yoonseon5a51ef72016-10-26 14:50:09 -070075 protected PacketService packetService;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected CoreService coreService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
yoonseon5a51ef72016-10-26 14:50:09 -070081 protected VirtualNetworkAdminService virtualNetworkAdminService;
82
yoonseon736a73b2017-01-26 14:27:48 -080083 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected VirtualProviderRegistryService providerRegistryService;
yoonseon5a51ef72016-10-26 14:50:09 -070085
86 ApplicationId appId;
87 InternalPacketProcessor processor;
88
89 Map<VirtualPacketContext, PacketContext> contextMap;
90
91 /**
92 * Creates a provider with the supplied identifier.
93 *
94 */
95 public DefaultVirtualPacketProvider() {
96 super(new ProviderId("virtual-packet",
97 "org.onosproject.virtual.virtual-packet"));
98 }
99
100 @Activate
101 public void activate() {
102 appId = coreService.registerApplication(
yoonseon4994c3d2017-01-27 13:07:18 -0800103 "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 contextMap = Maps.newConcurrentMap();
107
108 log.info("Started");
109 }
110
111 @Deactivate
112 public void deactivate() {
Jonathan Hart66028672017-02-02 16:25:49 -0800113 if (processor != null) {
114 packetService.removeProcessor(processor);
115 }
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) {
126 packetService.emit(devirtualize(networkId, packet));
127 }
128
yoonseonfb4a1db2017-01-31 11:38:30 -0800129 @Override
130 public void startPacketHandling() {
131 processor = new InternalPacketProcessor();
132 packetService.addProcessor(processor, PACKET_PROCESSOR_PRIORITY);
133 }
134
yoonseon5a51ef72016-10-26 14:50:09 -0700135 /**
136 * Translate the requested physical PacketContext into a virtual PacketContext.
137 * See {@link org.onosproject.net.packet.OutboundPacket}
138 *
139 * @param context A physical PacketContext be translated
140 * @return A translated virtual PacketContext
141 */
142 private Set<VirtualPacketContext> virtualize(PacketContext context) {
143 Set<VirtualPacketContext> outContext = new HashSet<>();
144
145 Set<TenantId> tIds = virtualNetworkAdminService.getTenantIds();
146
147 Set<VirtualNetwork> vNetworks = new HashSet<>();
148 tIds.stream()
149 .map(tid -> virtualNetworkAdminService
150 .getVirtualNetworks(tid))
151 .forEach(vNetworks::addAll);
152
153 Set<VirtualDevice> vDevices = new HashSet<>();
154 vNetworks.stream()
155 .map(network -> virtualNetworkAdminService
156 .getVirtualDevices(network.id()))
157 .forEach(vDevices::addAll);
158
159 Set<VirtualPort> vPorts = new HashSet<>();
160 vDevices.stream()
161 .map(dev -> virtualNetworkAdminService
162 .getVirtualPorts(dev.networkId(), dev.id()))
163 .forEach(vPorts::addAll);
164
165 ConnectPoint inCp = context.inPacket().receivedFrom();
166
167 Set<VirtualPort> inVports = vPorts.stream()
168 .filter(vp -> vp.realizedBy().equals(inCp))
169 .collect(Collectors.toSet());
170
171 for (VirtualPort vPort : inVports) {
172 ConnectPoint cp = new ConnectPoint(vPort.element().id(),
173 vPort.number());
174
175 Ethernet eth = context.inPacket().parsed();
176 eth.setVlanID(Ethernet.VLAN_UNTAGGED);
177
178 InboundPacket inPacket =
179 new DefaultInboundPacket(cp, eth,
180 ByteBuffer.wrap(eth.serialize()));
181
182 VirtualPacketContext vContext =
183 new VirtualPacketContext(context.time(), inPacket, null,
184 false, vPort.networkId(),
185 this);
186
187 contextMap.put(vContext, context);
188 outContext.add(vContext);
189 }
190
191 return outContext;
192 }
193
194 /**
195 * Translate the requested a virtual outbound packet into
196 * a physical OutboundPacket.
197 * See {@link org.onosproject.net.packet.PacketContext}
198 *
199 * @param packet A OutboundPacket to be translated
200 * @return de-virtualized (physical) OutboundPacket
201 */
202 private OutboundPacket devirtualize(NetworkId networkId, OutboundPacket packet) {
203 Set<VirtualPort> vPorts = virtualNetworkAdminService
204 .getVirtualPorts(networkId, packet.sendThrough());
205
206 PortNumber vOutPortNum = packet.treatment().allInstructions().stream()
207 .filter(i -> i.type() == Instruction.Type.OUTPUT)
208 .map(i -> ((Instructions.OutputInstruction) i).port())
209 .findFirst().get();
210
211 Optional<ConnectPoint> optionalCpOut = vPorts.stream()
212 .filter(v -> v.number().equals(vOutPortNum))
213 .map(v -> v.realizedBy())
214 .findFirst();
215 if (!optionalCpOut.isPresent()) {
216 log.info("Port {} is not realized yet, in Network {}, Device {}",
217 vOutPortNum, networkId, packet.sendThrough());
218 return null;
219 }
220 ConnectPoint egressPoint = optionalCpOut.get();
221
222 TrafficTreatment.Builder commonTreatmentBuilder
223 = DefaultTrafficTreatment.builder();
224 packet.treatment().allInstructions().stream()
225 .filter(i -> i.type() != Instruction.Type.OUTPUT)
226 .forEach(i -> commonTreatmentBuilder.add(i));
227 TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
228
229 TrafficTreatment treatment = DefaultTrafficTreatment
230 .builder(commonTreatment)
231 .setOutput(egressPoint.port()).build();
232
233 OutboundPacket outboundPacket = new DefaultOutboundPacket(
234 egressPoint.deviceId(), treatment, packet.data());
235 return outboundPacket;
236 }
237
238 /**
239 * Translate the requested a virtual Packet Context into
240 * a physical Packet Context.
241 * This method is designed to support Context's send() method that invoked
242 * by applications.
243 * See {@link org.onosproject.net.packet.PacketContext}
244 *
245 * @param context A handled packet context
246 * @return de-virtualized (physical) PacketContext
247 */
248 public PacketContext devirtualizeContext(VirtualPacketContext context) {
249 NetworkId networkId = context.getNetworkId();
250
251 OutboundPacket op = devirtualize(networkId, context.outPacket());
252
253 PacketContext packetContext = contextMap.get(context);
254
255 TrafficTreatment.Builder treatmentBuilder
256 = packetContext.treatmentBuilder();
257 if (op.treatment() != null) {
258 op.treatment().allInstructions().forEach(treatmentBuilder::add);
259 }
260
261 return packetContext;
262 }
263
264 private final class InternalPacketProcessor implements PacketProcessor {
265
266 @Override
267 public void process(PacketContext context) {
268 Set<VirtualPacketContext> vContexts = virtualize(context);
yoonseon736a73b2017-01-26 14:27:48 -0800269
270 vContexts.forEach(vpc -> {
271 VirtualPacketProviderService service =
272 (VirtualPacketProviderService) providerRegistryService
273 .getProviderService(vpc.getNetworkId(),
274 VirtualPacketProvider.class);
275 service.processPacket(vpc);
276 });
yoonseon5a51ef72016-10-26 14:50:09 -0700277 }
278 }
279}