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