blob: a9bff1da32dbe29a70dfc77dd757db9d722a2d15 [file] [log] [blame]
Yoonseon Hanc70b4e02016-10-20 15:24:33 -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.HashBasedTable;
20import com.google.common.collect.ImmutableList;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070021import com.google.common.collect.Maps;
22import com.google.common.collect.Sets;
23import com.google.common.collect.Table;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070024import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
27import org.apache.felix.scr.annotations.Modified;
28import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
30import org.apache.felix.scr.annotations.Service;
31import org.onlab.packet.VlanId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
34import org.onosproject.incubator.net.virtual.NetworkId;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090035import org.onosproject.incubator.net.virtual.VirtualNetworkService;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070036import org.onosproject.incubator.net.virtual.VirtualPort;
37import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider;
38import org.onosproject.incubator.net.virtual.provider.InternalRoutingAlgorithm;
39import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProvider;
40import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProviderService;
41import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
42import org.onosproject.net.ConnectPoint;
43import org.onosproject.net.DeviceId;
44import org.onosproject.net.Link;
45import org.onosproject.net.Path;
46import org.onosproject.net.PortNumber;
47import org.onosproject.net.device.DeviceService;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090048import org.onosproject.net.flow.CompletedBatchOperation;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070049import org.onosproject.net.flow.DefaultFlowEntry;
50import org.onosproject.net.flow.DefaultFlowRule;
51import org.onosproject.net.flow.DefaultTrafficSelector;
52import org.onosproject.net.flow.DefaultTrafficTreatment;
53import org.onosproject.net.flow.FlowEntry;
54import org.onosproject.net.flow.FlowRule;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090055import org.onosproject.net.flow.FlowRuleBatchEntry;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070056import org.onosproject.net.flow.FlowRuleBatchOperation;
57import org.onosproject.net.flow.FlowRuleEvent;
58import org.onosproject.net.flow.FlowRuleListener;
59import org.onosproject.net.flow.FlowRuleService;
60import org.onosproject.net.flow.TrafficSelector;
61import org.onosproject.net.flow.TrafficTreatment;
62import org.onosproject.net.flow.criteria.Criterion;
63import org.onosproject.net.flow.criteria.PortCriterion;
64import org.onosproject.net.flow.instructions.Instruction;
65import org.onosproject.net.flow.instructions.Instructions;
66import org.onosproject.net.provider.ProviderId;
67import org.onosproject.net.topology.TopologyService;
68import org.osgi.service.component.ComponentContext;
69import org.slf4j.Logger;
70
71import java.util.Dictionary;
72import java.util.HashSet;
73import java.util.Map;
74import java.util.Optional;
75import java.util.Set;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090076import java.util.stream.Collectors;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070077
78import static com.google.common.base.Preconditions.checkNotNull;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090079import static com.google.common.collect.ImmutableSet.copyOf;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070080import static org.slf4j.LoggerFactory.getLogger;
81
82/**
83 * Provider that translate virtual flow rules into physical rules.
84 * Current implementation is based on FlowRules.
85 * This virtualize and de-virtualize virtual flow rules into physical flow rules.
86 * {@link org.onosproject.net.flow.FlowRule}
87 */
88@Component(immediate = true)
89@Service
90public class DefaultVirtualFlowRuleProvider extends AbstractVirtualProvider
91 implements VirtualFlowRuleProvider {
92
Yoonseon Hanc8089db2017-03-22 20:22:12 +090093 private static final String APP_ID_STR = "org.onosproject.virtual.vnet-flow_";
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070094
95 private final Logger log = getLogger(getClass());
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected TopologyService topologyService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900101 protected VirtualNetworkService vnService;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected CoreService coreService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected FlowRuleService flowRuleService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected DeviceService deviceService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected VirtualProviderRegistryService providerRegistryService;
114
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900115 private InternalRoutingAlgorithm internalRoutingAlgorithm;
116 private InternalVirtualFlowRuleManager frm;
117 private ApplicationId appId;
118 private FlowRuleListener flowRuleListener;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700119
120 /**
121 * Creates a provider with the supplied identifier.
122 */
123 public DefaultVirtualFlowRuleProvider() {
124 super(new ProviderId("vnet-flow", "org.onosproject.virtual.vnet-flow"));
125 }
126
127
128 @Activate
129 public void activate() {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900130 appId = coreService.registerApplication(APP_ID_STR);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700131
132 providerRegistryService.registerProvider(this);
133
134 flowRuleListener = new InternalFlowRuleListener();
135 flowRuleService.addListener(flowRuleListener);
136
137 internalRoutingAlgorithm = new DefaultInternalRoutingAlgorithm();
138 frm = new InternalVirtualFlowRuleManager();
139
140 log.info("Started");
141 }
142
143 @Deactivate
144 public void deactivate() {
145 flowRuleService.removeListener(flowRuleListener);
146 providerRegistryService.unregisterProvider(this);
147 }
148
149 @Modified
150 protected void modified(ComponentContext context) {
151 Dictionary<?, ?> properties = context.getProperties();
152 }
153
154 @Override
155 public void applyFlowRule(NetworkId networkId, FlowRule... flowRules) {
156 for (FlowRule flowRule : flowRules) {
157 devirtualize(networkId, flowRule).forEach(
158 r -> {
159 flowRuleService.applyFlowRules(r);
160 }
161 );
162 }
163 }
164
165 @Override
166 public void removeFlowRule(NetworkId networkId, FlowRule... flowRules) {
167 for (FlowRule flowRule : flowRules) {
168 devirtualize(networkId, flowRule).forEach(
169 r -> {
170 flowRuleService.removeFlowRules(r);
171 }
172 );
173 }
174 }
175
176 @Override
177 public void executeBatch(NetworkId networkId, FlowRuleBatchOperation batch) {
178 checkNotNull(batch);
179
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900180 for (FlowRuleBatchEntry fop : batch.getOperations()) {
181 devirtualize(networkId, fop.target())
182 .forEach(f -> flowRuleService.applyFlowRules(f));
183 }
184
185 //FIXME: check the success of the all batch operations
186 CompletedBatchOperation status =
187 new CompletedBatchOperation(true, Sets.newConcurrentHashSet(),
188 batch.deviceId());
189
190 VirtualFlowRuleProviderService providerService =
191 (VirtualFlowRuleProviderService) providerRegistryService
192 .getProviderService(networkId,
193 VirtualFlowRuleProvider.class);
194 providerService.batchOperationCompleted(batch.id(), status);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700195 }
196
197 public void setEmbeddingAlgorithm(InternalRoutingAlgorithm
198 internalRoutingAlgorithm) {
199 this.internalRoutingAlgorithm = internalRoutingAlgorithm;
200 }
201
202 /**
203 * Translate the requested physical flow rules into virtual flow rules.
204 *
205 * @param flowRule A virtual flow rule to be translated
206 * @return A flow rule for a specific virtual network
207 */
kdarapu93722ef2017-02-16 19:24:29 +0530208 private FlowRule virtualizeFlowRule(FlowRule flowRule) {
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700209 return frm.getVirtualRule(flowRule);
210 }
211
212 private FlowEntry virtualize(FlowEntry flowEntry) {
kdarapu93722ef2017-02-16 19:24:29 +0530213 FlowRule vRule = virtualizeFlowRule(flowEntry);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700214 FlowEntry vEntry = new DefaultFlowEntry(vRule, flowEntry.state(),
215 flowEntry.life(),
216 flowEntry.packets(),
217 flowEntry.bytes());
218
219 return vEntry;
220 }
221
222 /**
223 * Translate the requested virtual flow rules into physical flow rules.
224 * The translation could be one to many.
225 *
226 * @param flowRule A flow rule from underlying data plane to be translated
227 * @return A set of flow rules for physical network
228 */
229 private Set<FlowRule> devirtualize(NetworkId networkId, FlowRule flowRule) {
230
231 Set<FlowRule> outRules = new HashSet<>();
232
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900233 Set<ConnectPoint> ingressPoints = extractIngressPoints(networkId,
234 flowRule.deviceId(),
235 flowRule.selector());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700236
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900237 ConnectPoint egressPoint = extractEgressPoints(networkId,
238 flowRule.deviceId(),
239 flowRule.treatment());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700240
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900241 if (egressPoint == null) {
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700242 return outRules;
243 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700244
245 TrafficSelector.Builder commonSelectorBuilder
246 = DefaultTrafficSelector.builder();
247 flowRule.selector().criteria().stream()
248 .filter(c -> c.type() != Criterion.Type.IN_PORT)
249 .forEach(c -> commonSelectorBuilder.add(c));
250 TrafficSelector commonSelector = commonSelectorBuilder.build();
251
252 TrafficTreatment.Builder commonTreatmentBuilder
253 = DefaultTrafficTreatment.builder();
254 flowRule.treatment().allInstructions().stream()
255 .filter(i -> i.type() != Instruction.Type.OUTPUT)
256 .forEach(i -> commonTreatmentBuilder.add(i));
257 TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
258
259 for (ConnectPoint ingressPoint : ingressPoints) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900260 if (egressPoint.port() == PortNumber.FLOOD) {
261 Set<ConnectPoint> outPoints = vnService
262 .getVirtualPorts(networkId, flowRule.deviceId())
263 .stream()
264 .map(VirtualPort::realizedBy)
265 .filter(p -> !p.equals(ingressPoint))
266 .collect(Collectors.toSet());
267
268 for (ConnectPoint outPoint : outPoints) {
269 outRules.addAll(generateRules(networkId, ingressPoint, outPoint,
270 commonSelector, commonTreatment, flowRule));
271 }
272 } else {
273 outRules.addAll(generateRules(networkId, ingressPoint, egressPoint,
274 commonSelector, commonTreatment, flowRule));
275 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700276 }
277
278 return outRules;
279 }
280
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900281 /**
282 * Extract ingress connect points of the physical network
283 * from the requested traffic selector.
284 *
285 * @param networkId the virtual network identifier
286 * @param deviceId the virtual device identifier
287 * @param selector the traffic selector to extract ingress point
288 * @return the set of ingress connect points of the physical network
289 */
290 private Set<ConnectPoint> extractIngressPoints(NetworkId networkId,
291 DeviceId deviceId,
292 TrafficSelector selector) {
293
294 Set<ConnectPoint> ingressPoints = new HashSet<>();
295
296 Set<VirtualPort> vPorts = vnService
297 .getVirtualPorts(networkId, deviceId);
298
299 PortCriterion portCriterion = ((PortCriterion) selector
300 .getCriterion(Criterion.Type.IN_PORT));
301
302 if (portCriterion != null) {
303 PortNumber vInPortNum = portCriterion.port();
304
305 Optional<ConnectPoint> optionalCp = vPorts.stream()
306 .filter(v -> v.number().equals(vInPortNum))
307 .map(VirtualPort::realizedBy).findFirst();
308 if (!optionalCp.isPresent()) {
309 log.warn("Port {} is not realized yet, in Network {}, Device {}",
310 vInPortNum, networkId, deviceId);
311 return ingressPoints;
312 }
313
314 ingressPoints.add(optionalCp.get());
315 } else {
316 for (VirtualPort vPort : vPorts) {
317 if (vPort.realizedBy() != null) {
318 ingressPoints.add(vPort.realizedBy());
319 } else {
320 log.warn("Port {} is not realized yet, in Network {}, " +
321 "Device {}",
322 vPort, networkId, deviceId);
323 }
324 }
325 }
326
327 return ingressPoints;
328 }
329
330 /**
331 * Extract egress connect point of the physical network
332 * from the requested traffic treatment.
333 *
334 * @param networkId the virtual network identifier
335 * @param deviceId the virtual device identifier
336 * @param treatment the traffic treatment to extract ingress point
337 * @return the egress connect point of the physical network
338 */
339 private ConnectPoint extractEgressPoints(NetworkId networkId,
340 DeviceId deviceId,
341 TrafficTreatment treatment) {
342
343 Set<VirtualPort> vPorts = vnService
344 .getVirtualPorts(networkId, deviceId);
345
346 PortNumber vOutPortNum = treatment.allInstructions().stream()
347 .filter(i -> i.type() == Instruction.Type.OUTPUT)
348 .map(i -> ((Instructions.OutputInstruction) i).port())
349 .findFirst().get();
350
351 Optional<ConnectPoint> optionalCpOut = vPorts.stream()
352 .filter(v -> v.number().equals(vOutPortNum))
353 .map(VirtualPort::realizedBy)
354 .findFirst();
355
356 if (!optionalCpOut.isPresent()) {
357 if (vOutPortNum.isLogical()) {
358 return new ConnectPoint(DeviceId.deviceId("vNet"), vOutPortNum);
359 }
360
361 log.warn("Port {} is not realized yet, in Network {}, Device {}",
362 vOutPortNum, networkId, deviceId);
363 return null;
364 }
365
366 return optionalCpOut.get();
367 }
368
369
370 /**
371 * Generates the corresponding flow rules for the physical network.
372 *
373 * @param networkId The virtual network identifier
374 * @param ingressPoint The ingress point of the physical network
375 * @param egressPoint The egress point of the physical network
376 * @param commonSelector A common traffic selector between the virtual
377 * and physical flow rules
378 * @param commonTreatment A common traffic treatment between the virtual
379 * and physical flow rules
380 * @param flowRule The virtual flow rule to be translated
381 * @return A set of flow rules for the physical network
382 */
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700383 private Set<FlowRule> generateRules(NetworkId networkId,
384 ConnectPoint ingressPoint,
385 ConnectPoint egressPoint,
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900386 TrafficSelector commonSelector,
387 TrafficTreatment commonTreatment,
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700388 FlowRule flowRule) {
389
390 Set<FlowRule> outRules = new HashSet<>();
391
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900392 if (ingressPoint.deviceId().equals(egressPoint.deviceId()) ||
393 egressPoint.port().isLogical()) {
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700394 //Traffic is handled inside a single physical switch
395 //No tunnel is needed.
396
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900397 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector
398 .builder(commonSelector)
399 .matchInPort(ingressPoint.port());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700400
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900401 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
402 .builder(commonTreatment)
403 .setOutput(egressPoint.port());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700404
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900405 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
406 .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
407 .forDevice(ingressPoint.deviceId())
408 .withSelector(selectorBuilder.build())
409 .withTreatment(treatmentBuilder.build())
410 .withPriority(flowRule.priority());
411
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700412 if (flowRule.isPermanent()) {
413 ruleBuilder.makePermanent();
414 } else {
415 ruleBuilder.makeTemporary(flowRule.timeout());
416 }
417
418 FlowRule rule = ruleBuilder.build();
419 frm.addIngressRule(flowRule, rule, networkId);
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900420 outRules.add(rule);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700421 } else {
422 //Traffic is handled by multiple physical switches
423 //A tunnel is needed.
424
425 Path internalPath = internalRoutingAlgorithm
426 .findPath(ingressPoint, egressPoint);
427 checkNotNull(internalPath, "No path between " +
428 ingressPoint.toString() + " " + egressPoint.toString());
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900429
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700430 ConnectPoint outCp = internalPath.links().get(0).src();
431
432 //ingress point of tunnel
433 TrafficSelector.Builder selectorBuilder =
434 DefaultTrafficSelector.builder(commonSelector);
435 selectorBuilder.matchInPort(ingressPoint.port());
436
437 TrafficTreatment.Builder treatmentBuilder =
438 DefaultTrafficTreatment.builder(commonTreatment);
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900439 //TODO: add the logic to check host location
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700440 treatmentBuilder.pushVlan()
441 .setVlanId(VlanId.vlanId(networkId.id().shortValue()));
442 treatmentBuilder.setOutput(outCp.port());
443
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900444 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
445 .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
446 .forDevice(ingressPoint.deviceId())
447 .withSelector(selectorBuilder.build())
448 .withTreatment(treatmentBuilder.build())
449 .withPriority(flowRule.priority());
450
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700451 if (flowRule.isPermanent()) {
452 ruleBuilder.makePermanent();
453 } else {
454 ruleBuilder.makeTemporary(flowRule.timeout());
455 }
456
457 FlowRule rule = ruleBuilder.build();
458 frm.addIngressRule(flowRule, rule, networkId);
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900459 outRules.add(rule);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700460
461 //routing inside tunnel
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900462 ConnectPoint inCp = internalPath.links().get(0).dst();
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700463
464 if (internalPath.links().size() > 1) {
465 for (Link l : internalPath.links()
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900466 .subList(1, internalPath.links().size())) {
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700467
468 outCp = l.src();
469
470 selectorBuilder = DefaultTrafficSelector
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900471 .builder(commonSelector)
472 .matchVlanId(VlanId.vlanId(networkId.id().shortValue()))
473 .matchInPort(inCp.port());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700474
475 treatmentBuilder = DefaultTrafficTreatment
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900476 .builder(commonTreatment)
477 .setOutput(outCp.port());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700478
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900479 ruleBuilder = DefaultFlowRule.builder()
480 .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
481 .forDevice(inCp.deviceId())
482 .withSelector(selectorBuilder.build())
483 .withTreatment(treatmentBuilder.build())
484 .withPriority(flowRule.priority());
485
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700486 if (flowRule.isPermanent()) {
487 ruleBuilder.makePermanent();
488 } else {
489 ruleBuilder.makeTemporary(flowRule.timeout());
490 }
491
492 outRules.add(ruleBuilder.build());
493 inCp = l.dst();
494 }
495 }
496
497 //egress point of tunnel
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900498 selectorBuilder = DefaultTrafficSelector.builder(commonSelector)
499 .matchVlanId(VlanId.vlanId(networkId.id().shortValue()))
500 .matchInPort(inCp.port());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700501
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900502 treatmentBuilder = DefaultTrafficTreatment.builder(commonTreatment)
503 .popVlan()
504 .setOutput(egressPoint.port());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700505
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900506 ruleBuilder = DefaultFlowRule.builder()
507 .fromApp(appId)
508 .forDevice(egressPoint.deviceId())
509 .withSelector(selectorBuilder.build())
510 .withTreatment(treatmentBuilder.build())
511 .withPriority(flowRule.priority());
512
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700513 if (flowRule.isPermanent()) {
514 ruleBuilder.makePermanent();
515 } else {
516 ruleBuilder.makeTemporary(flowRule.timeout());
517 }
518
519 outRules.add(ruleBuilder.build());
520 }
521
522 return outRules;
523 }
524
525 private class InternalFlowRuleListener implements FlowRuleListener {
526 @Override
527 public void event(FlowRuleEvent event) {
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700528 if ((event.type() == FlowRuleEvent.Type.RULE_ADDED) ||
529 (event.type() == FlowRuleEvent.Type.RULE_UPDATED)) {
530 if (frm.isVirtualIngressRule(event.subject())) {
531 NetworkId networkId = frm.getVirtualNetworkId(event.subject());
532 FlowEntry vEntry = getVirtualFlowEntry(event.subject());
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900533 frm.addOrUpdateFlowEntry(networkId, vEntry.deviceId(), vEntry);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700534
535 VirtualFlowRuleProviderService providerService =
536 (VirtualFlowRuleProviderService) providerRegistryService
537 .getProviderService(networkId,
538 VirtualFlowRuleProvider.class);
539
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900540 ImmutableList.Builder<FlowEntry> builder = ImmutableList.builder();
541 builder.addAll(frm.getFlowEntries(networkId, vEntry.deviceId()));
542
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700543 providerService.pushFlowMetrics(vEntry.deviceId(), builder.build());
544 }
545 } else if (event.type() == FlowRuleEvent.Type.RULE_REMOVED) {
546 if (frm.isVirtualIngressRule(event.subject())) {
547 //FIXME confirm all physical rules are removed
548 NetworkId networkId = frm.getVirtualNetworkId(event.subject());
549 FlowEntry vEntry = getVirtualFlowEntry(event.subject());
550
551 VirtualFlowRuleProviderService providerService =
552 (VirtualFlowRuleProviderService) providerRegistryService
553 .getProviderService(networkId,
554 VirtualFlowRuleProvider.class);
555 providerService.flowRemoved(vEntry);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700556 }
557 }
558 }
559
560 private FlowEntry getVirtualFlowEntry(FlowRule rule) {
561 FlowEntry entry = null;
562 for (FlowEntry fe :
563 flowRuleService.getFlowEntries(rule.deviceId())) {
564 if (rule.exactMatch(fe)) {
565 entry = fe;
566 }
567 }
568
569 FlowRule vRule = virtualize(entry);
570 FlowEntry vEntry = new DefaultFlowEntry(vRule, entry.state(),
571 entry.life(), entry.packets(),
572 entry.bytes());
573
574 return vEntry;
575 }
576 }
577
578 private class InternalVirtualFlowRuleManager {
579 /** <Virtual Network ID, Virtual Device ID, Virtual Flow Rules>.*/
580 final Table<NetworkId, DeviceId, Set<FlowRule>> flowRuleTable
581 = HashBasedTable.create();
582
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700583 /** <Virtual Network ID, Virtual Device ID, Virtual Flow Entries>.*/
584 final Table<NetworkId, DeviceId, Set<FlowEntry>> flowEntryTable
585 = HashBasedTable.create();
586
587 /** <Physical Flow Rule, Virtual Network ID>.*/
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900588 final Map<FlowRule, NetworkId> ingressRuleMap = Maps.newHashMap();
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700589
590 /** <Physical Flow Rule, Virtual Virtual Flow Rule>.*/
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900591 final Map<FlowRule, FlowRule> virtualizationMap = Maps.newHashMap();
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700592
593 private Iterable<FlowRule> getFlowRules(NetworkId networkId,
594 DeviceId deviceId) {
595 return flowRuleTable.get(networkId, deviceId);
596 }
597
598 private Iterable<FlowEntry> getFlowEntries(NetworkId networkId,
599 DeviceId deviceId) {
600 return flowEntryTable.get(networkId, deviceId);
601 }
602
603 private void addFlowRule(NetworkId networkId, DeviceId deviceId,
604 FlowRule flowRule) {
605 Set<FlowRule> set = flowRuleTable.get(networkId, deviceId);
606 if (set == null) {
607 set = Sets.newHashSet();
608 flowRuleTable.put(networkId, deviceId, set);
609 }
610 set.add(flowRule);
611 }
612
613 private void removeFlowRule(NetworkId networkId, DeviceId deviceId,
614 FlowRule flowRule) {
615 Set<FlowRule> set = flowRuleTable.get(networkId, deviceId);
616 if (set == null) {
617 return;
618 }
619 set.remove(flowRule);
620 }
621
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900622 private void addOrUpdateFlowEntry(NetworkId networkId, DeviceId deviceId,
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700623 FlowEntry flowEntry) {
624 Set<FlowEntry> set = flowEntryTable.get(networkId, deviceId);
625 if (set == null) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900626 set = Sets.newConcurrentHashSet();
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700627 flowEntryTable.put(networkId, deviceId, set);
628 }
629
630 //Replace old entry with new one
631 set.stream().filter(fe -> fe.exactMatch(flowEntry))
632 .forEach(set::remove);
633 set.add(flowEntry);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700634 }
635
636 private void removeFlowEntry(NetworkId networkId, DeviceId deviceId,
637 FlowEntry flowEntry) {
638 Set<FlowEntry> set = flowEntryTable.get(networkId, deviceId);
639 if (set == null) {
640 return;
641 }
642 set.remove(flowEntry);
643 }
644
645 private void addIngressRule(FlowRule virtualRule, FlowRule physicalRule,
646 NetworkId networkId) {
647 ingressRuleMap.put(physicalRule, networkId);
648 virtualizationMap.put(physicalRule, virtualRule);
649 }
650
651 private FlowRule getVirtualRule(FlowRule physicalRule) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900652 return virtualizationMap.get(physicalRule);
653 }
654
655 private void removeIngressRule(FlowRule physicalRule) {
656 ingressRuleMap.remove(physicalRule);
657 virtualizationMap.remove(physicalRule);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700658 }
659
660 private Set<FlowRule> getAllPhysicalRule() {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900661 return copyOf(virtualizationMap.keySet());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700662 }
663
664 private NetworkId getVirtualNetworkId(FlowRule physicalRule) {
665 return ingressRuleMap.get(physicalRule);
666 }
667
668 /**
669 * Test the rule is the ingress rule for virtual rules.
670 *
671 * @param flowRule A flow rule from underlying data plane to be translated
672 * @return True when the rule is for ingress point for a virtual switch
673 */
674 private boolean isVirtualIngressRule(FlowRule flowRule) {
675 return ingressRuleMap.containsKey(flowRule);
676 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700677 }
678
679 private class DefaultInternalRoutingAlgorithm
680 implements InternalRoutingAlgorithm {
681
682 @Override
683 public Path findPath(ConnectPoint src, ConnectPoint dst) {
684 Set<Path> paths =
685 topologyService.getPaths(topologyService.currentTopology(),
686 src.deviceId(),
687 dst.deviceId());
688
689 if (paths.isEmpty()) {
690 return null;
691 }
692
693 //TODO the logic find the best path
694 return (Path) paths.toArray()[0];
695 }
696 }
697}