blob: 8e497e857a3a60ca46a7f9cc3fe527635fb0b029 [file] [log] [blame]
Yoonseon Hanc70b4e02016-10-20 15:24:33 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Yoonseon Hanc70b4e02016-10-20 15:24:33 -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 */
16
17package org.onosproject.incubator.net.virtual.impl.provider;
18
19import com.google.common.collect.HashBasedTable;
20import com.google.common.collect.ImmutableList;
Yoonseon Han997c8422017-04-24 16:20:03 -070021import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Lists;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070023import com.google.common.collect.Maps;
24import com.google.common.collect.Sets;
25import com.google.common.collect.Table;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070026import org.apache.felix.scr.annotations.Activate;
27import org.apache.felix.scr.annotations.Component;
28import org.apache.felix.scr.annotations.Deactivate;
29import org.apache.felix.scr.annotations.Modified;
30import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
32import org.apache.felix.scr.annotations.Service;
33import org.onlab.packet.VlanId;
34import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
Yoonseon Han5cf483a2017-04-19 23:14:00 -070036import org.onosproject.core.DefaultApplicationId;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070037import org.onosproject.incubator.net.virtual.NetworkId;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090038import org.onosproject.incubator.net.virtual.VirtualNetworkService;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070039import org.onosproject.incubator.net.virtual.VirtualPort;
40import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider;
41import org.onosproject.incubator.net.virtual.provider.InternalRoutingAlgorithm;
42import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProvider;
43import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProviderService;
44import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
45import org.onosproject.net.ConnectPoint;
46import org.onosproject.net.DeviceId;
47import org.onosproject.net.Link;
48import org.onosproject.net.Path;
49import org.onosproject.net.PortNumber;
50import org.onosproject.net.device.DeviceService;
Yoonseon Han997c8422017-04-24 16:20:03 -070051import org.onosproject.net.flow.BatchOperationEntry;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090052import org.onosproject.net.flow.CompletedBatchOperation;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070053import org.onosproject.net.flow.DefaultFlowEntry;
54import org.onosproject.net.flow.DefaultFlowRule;
55import org.onosproject.net.flow.DefaultTrafficSelector;
56import org.onosproject.net.flow.DefaultTrafficTreatment;
57import org.onosproject.net.flow.FlowEntry;
58import org.onosproject.net.flow.FlowRule;
Ray Milkey7bf273c2017-09-27 16:15:15 -070059import org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry;
60import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070061import org.onosproject.net.flow.FlowRuleEvent;
62import org.onosproject.net.flow.FlowRuleListener;
Yoonseon Han997c8422017-04-24 16:20:03 -070063import org.onosproject.net.flow.FlowRuleOperations;
64import org.onosproject.net.flow.FlowRuleOperationsContext;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070065import org.onosproject.net.flow.FlowRuleService;
66import org.onosproject.net.flow.TrafficSelector;
67import org.onosproject.net.flow.TrafficTreatment;
68import org.onosproject.net.flow.criteria.Criterion;
69import org.onosproject.net.flow.criteria.PortCriterion;
70import org.onosproject.net.flow.instructions.Instruction;
71import org.onosproject.net.flow.instructions.Instructions;
72import org.onosproject.net.provider.ProviderId;
73import org.onosproject.net.topology.TopologyService;
74import org.osgi.service.component.ComponentContext;
75import org.slf4j.Logger;
76
77import java.util.Dictionary;
78import java.util.HashSet;
79import java.util.Map;
80import java.util.Optional;
81import java.util.Set;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090082import java.util.stream.Collectors;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070083
84import static com.google.common.base.Preconditions.checkNotNull;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090085import static com.google.common.collect.ImmutableSet.copyOf;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070086import static org.slf4j.LoggerFactory.getLogger;
87
88/**
89 * Provider that translate virtual flow rules into physical rules.
90 * Current implementation is based on FlowRules.
91 * This virtualize and de-virtualize virtual flow rules into physical flow rules.
92 * {@link org.onosproject.net.flow.FlowRule}
93 */
94@Component(immediate = true)
95@Service
96public class DefaultVirtualFlowRuleProvider extends AbstractVirtualProvider
97 implements VirtualFlowRuleProvider {
98
Yoonseon Hanc8089db2017-03-22 20:22:12 +090099 private static final String APP_ID_STR = "org.onosproject.virtual.vnet-flow_";
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700100
101 private final Logger log = getLogger(getClass());
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected TopologyService topologyService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900107 protected VirtualNetworkService vnService;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected CoreService coreService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected FlowRuleService flowRuleService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected DeviceService deviceService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected VirtualProviderRegistryService providerRegistryService;
120
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900121 private InternalRoutingAlgorithm internalRoutingAlgorithm;
122 private InternalVirtualFlowRuleManager frm;
123 private ApplicationId appId;
124 private FlowRuleListener flowRuleListener;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700125
126 /**
yoonseond6ba9a62017-01-30 11:48:07 -0800127 * Creates a provider with the identifier.
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700128 */
129 public DefaultVirtualFlowRuleProvider() {
130 super(new ProviderId("vnet-flow", "org.onosproject.virtual.vnet-flow"));
131 }
132
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700133 @Activate
134 public void activate() {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900135 appId = coreService.registerApplication(APP_ID_STR);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700136
137 providerRegistryService.registerProvider(this);
138
139 flowRuleListener = new InternalFlowRuleListener();
140 flowRuleService.addListener(flowRuleListener);
141
142 internalRoutingAlgorithm = new DefaultInternalRoutingAlgorithm();
143 frm = new InternalVirtualFlowRuleManager();
144
145 log.info("Started");
146 }
147
148 @Deactivate
149 public void deactivate() {
150 flowRuleService.removeListener(flowRuleListener);
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700151 flowRuleService.removeFlowRulesById(appId);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700152 providerRegistryService.unregisterProvider(this);
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700153 log.info("Stopped");
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700154 }
155
156 @Modified
157 protected void modified(ComponentContext context) {
158 Dictionary<?, ?> properties = context.getProperties();
159 }
160
161 @Override
162 public void applyFlowRule(NetworkId networkId, FlowRule... flowRules) {
163 for (FlowRule flowRule : flowRules) {
164 devirtualize(networkId, flowRule).forEach(
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700165 r -> flowRuleService.applyFlowRules(r));
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700166 }
167 }
168
169 @Override
170 public void removeFlowRule(NetworkId networkId, FlowRule... flowRules) {
171 for (FlowRule flowRule : flowRules) {
172 devirtualize(networkId, flowRule).forEach(
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700173 r -> flowRuleService.removeFlowRules(r));
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700174 }
175 }
176
177 @Override
178 public void executeBatch(NetworkId networkId, FlowRuleBatchOperation batch) {
179 checkNotNull(batch);
180
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900181 for (FlowRuleBatchEntry fop : batch.getOperations()) {
Yoonseon Han997c8422017-04-24 16:20:03 -0700182 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
183
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700184 switch (fop.operator()) {
185 case ADD:
Yoonseon Han997c8422017-04-24 16:20:03 -0700186 devirtualize(networkId, fop.target()).forEach(builder::add);
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700187 break;
188 case REMOVE:
Yoonseon Han997c8422017-04-24 16:20:03 -0700189 devirtualize(networkId, fop.target()).forEach(builder::remove);
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700190 break;
191 case MODIFY:
Yoonseon Han997c8422017-04-24 16:20:03 -0700192 devirtualize(networkId, fop.target()).forEach(builder::modify);
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700193 break;
194 default:
195 break;
196 }
Yoonseon Han997c8422017-04-24 16:20:03 -0700197
198 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
199 @Override
200 public void onSuccess(FlowRuleOperations ops) {
201 CompletedBatchOperation status =
202 new CompletedBatchOperation(true,
203 Sets.newConcurrentHashSet(),
204 batch.deviceId());
205
206 VirtualFlowRuleProviderService providerService =
207 (VirtualFlowRuleProviderService) providerRegistryService
208 .getProviderService(networkId,
209 VirtualFlowRuleProvider.class);
210 providerService.batchOperationCompleted(batch.id(), status);
211 }
212
213 @Override
214 public void onError(FlowRuleOperations ops) {
215 Set<FlowRule> failures = ImmutableSet.copyOf(
216 Lists.transform(batch.getOperations(),
217 BatchOperationEntry::target));
218
219 CompletedBatchOperation status =
220 new CompletedBatchOperation(false,
221 failures,
222 batch.deviceId());
223
224 VirtualFlowRuleProviderService providerService =
225 (VirtualFlowRuleProviderService) providerRegistryService
226 .getProviderService(networkId,
227 VirtualFlowRuleProvider.class);
228 providerService.batchOperationCompleted(batch.id(), status);
229 }
230 }));
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900231 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700232 }
233
234 public void setEmbeddingAlgorithm(InternalRoutingAlgorithm
235 internalRoutingAlgorithm) {
236 this.internalRoutingAlgorithm = internalRoutingAlgorithm;
237 }
238
239 /**
240 * Translate the requested physical flow rules into virtual flow rules.
241 *
242 * @param flowRule A virtual flow rule to be translated
243 * @return A flow rule for a specific virtual network
244 */
kdarapu93722ef2017-02-16 19:24:29 +0530245 private FlowRule virtualizeFlowRule(FlowRule flowRule) {
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700246
247 FlowRule storedrule = frm.getVirtualRule(flowRule);
248
249 if (flowRule.reason() == FlowRule.FlowRemoveReason.NO_REASON) {
250 return storedrule;
251 } else {
252 return DefaultFlowRule.builder()
253 .withReason(flowRule.reason())
254 .withPriority(storedrule.priority())
255 .forDevice(storedrule.deviceId())
256 .forTable(storedrule.tableId())
257 .fromApp(new DefaultApplicationId(storedrule.appId(), null))
258 .withIdleTimeout(storedrule.timeout())
259 .withHardTimeout(storedrule.hardTimeout())
260 .withSelector(storedrule.selector())
261 .withTreatment(storedrule.treatment())
262 .build();
263 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700264 }
265
266 private FlowEntry virtualize(FlowEntry flowEntry) {
kdarapu93722ef2017-02-16 19:24:29 +0530267 FlowRule vRule = virtualizeFlowRule(flowEntry);
Yoonseon Han26d98c82017-07-19 15:46:57 +0900268
269 if (vRule == null) {
270 return null;
271 }
272
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700273 FlowEntry vEntry = new DefaultFlowEntry(vRule, flowEntry.state(),
274 flowEntry.life(),
275 flowEntry.packets(),
276 flowEntry.bytes());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700277 return vEntry;
278 }
279
280 /**
281 * Translate the requested virtual flow rules into physical flow rules.
282 * The translation could be one to many.
283 *
284 * @param flowRule A flow rule from underlying data plane to be translated
285 * @return A set of flow rules for physical network
286 */
287 private Set<FlowRule> devirtualize(NetworkId networkId, FlowRule flowRule) {
288
289 Set<FlowRule> outRules = new HashSet<>();
290
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900291 Set<ConnectPoint> ingressPoints = extractIngressPoints(networkId,
292 flowRule.deviceId(),
293 flowRule.selector());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700294
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900295 ConnectPoint egressPoint = extractEgressPoints(networkId,
296 flowRule.deviceId(),
297 flowRule.treatment());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700298
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900299 if (egressPoint == null) {
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700300 return outRules;
301 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700302
303 TrafficSelector.Builder commonSelectorBuilder
304 = DefaultTrafficSelector.builder();
305 flowRule.selector().criteria().stream()
306 .filter(c -> c.type() != Criterion.Type.IN_PORT)
307 .forEach(c -> commonSelectorBuilder.add(c));
308 TrafficSelector commonSelector = commonSelectorBuilder.build();
309
310 TrafficTreatment.Builder commonTreatmentBuilder
311 = DefaultTrafficTreatment.builder();
312 flowRule.treatment().allInstructions().stream()
313 .filter(i -> i.type() != Instruction.Type.OUTPUT)
314 .forEach(i -> commonTreatmentBuilder.add(i));
315 TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
316
317 for (ConnectPoint ingressPoint : ingressPoints) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900318 if (egressPoint.port() == PortNumber.FLOOD) {
319 Set<ConnectPoint> outPoints = vnService
320 .getVirtualPorts(networkId, flowRule.deviceId())
321 .stream()
322 .map(VirtualPort::realizedBy)
323 .filter(p -> !p.equals(ingressPoint))
324 .collect(Collectors.toSet());
325
326 for (ConnectPoint outPoint : outPoints) {
327 outRules.addAll(generateRules(networkId, ingressPoint, outPoint,
328 commonSelector, commonTreatment, flowRule));
329 }
330 } else {
331 outRules.addAll(generateRules(networkId, ingressPoint, egressPoint,
332 commonSelector, commonTreatment, flowRule));
333 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700334 }
335
336 return outRules;
337 }
338
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900339 /**
340 * Extract ingress connect points of the physical network
341 * from the requested traffic selector.
342 *
343 * @param networkId the virtual network identifier
344 * @param deviceId the virtual device identifier
345 * @param selector the traffic selector to extract ingress point
346 * @return the set of ingress connect points of the physical network
347 */
348 private Set<ConnectPoint> extractIngressPoints(NetworkId networkId,
349 DeviceId deviceId,
350 TrafficSelector selector) {
351
352 Set<ConnectPoint> ingressPoints = new HashSet<>();
353
354 Set<VirtualPort> vPorts = vnService
355 .getVirtualPorts(networkId, deviceId);
356
357 PortCriterion portCriterion = ((PortCriterion) selector
358 .getCriterion(Criterion.Type.IN_PORT));
359
360 if (portCriterion != null) {
361 PortNumber vInPortNum = portCriterion.port();
362
363 Optional<ConnectPoint> optionalCp = vPorts.stream()
364 .filter(v -> v.number().equals(vInPortNum))
365 .map(VirtualPort::realizedBy).findFirst();
366 if (!optionalCp.isPresent()) {
367 log.warn("Port {} is not realized yet, in Network {}, Device {}",
368 vInPortNum, networkId, deviceId);
369 return ingressPoints;
370 }
371
372 ingressPoints.add(optionalCp.get());
373 } else {
374 for (VirtualPort vPort : vPorts) {
375 if (vPort.realizedBy() != null) {
376 ingressPoints.add(vPort.realizedBy());
377 } else {
378 log.warn("Port {} is not realized yet, in Network {}, " +
379 "Device {}",
380 vPort, networkId, deviceId);
381 }
382 }
383 }
384
385 return ingressPoints;
386 }
387
388 /**
389 * Extract egress connect point of the physical network
390 * from the requested traffic treatment.
391 *
392 * @param networkId the virtual network identifier
393 * @param deviceId the virtual device identifier
394 * @param treatment the traffic treatment to extract ingress point
395 * @return the egress connect point of the physical network
396 */
397 private ConnectPoint extractEgressPoints(NetworkId networkId,
398 DeviceId deviceId,
399 TrafficTreatment treatment) {
400
401 Set<VirtualPort> vPorts = vnService
402 .getVirtualPorts(networkId, deviceId);
403
404 PortNumber vOutPortNum = treatment.allInstructions().stream()
405 .filter(i -> i.type() == Instruction.Type.OUTPUT)
406 .map(i -> ((Instructions.OutputInstruction) i).port())
407 .findFirst().get();
408
409 Optional<ConnectPoint> optionalCpOut = vPorts.stream()
410 .filter(v -> v.number().equals(vOutPortNum))
411 .map(VirtualPort::realizedBy)
412 .findFirst();
413
414 if (!optionalCpOut.isPresent()) {
415 if (vOutPortNum.isLogical()) {
416 return new ConnectPoint(DeviceId.deviceId("vNet"), vOutPortNum);
417 }
418
419 log.warn("Port {} is not realized yet, in Network {}, Device {}",
420 vOutPortNum, networkId, deviceId);
421 return null;
422 }
423
424 return optionalCpOut.get();
425 }
426
427
428 /**
429 * Generates the corresponding flow rules for the physical network.
430 *
431 * @param networkId The virtual network identifier
432 * @param ingressPoint The ingress point of the physical network
433 * @param egressPoint The egress point of the physical network
434 * @param commonSelector A common traffic selector between the virtual
435 * and physical flow rules
436 * @param commonTreatment A common traffic treatment between the virtual
437 * and physical flow rules
438 * @param flowRule The virtual flow rule to be translated
439 * @return A set of flow rules for the physical network
440 */
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700441 private Set<FlowRule> generateRules(NetworkId networkId,
442 ConnectPoint ingressPoint,
443 ConnectPoint egressPoint,
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900444 TrafficSelector commonSelector,
445 TrafficTreatment commonTreatment,
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700446 FlowRule flowRule) {
447
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900448 if (ingressPoint.deviceId().equals(egressPoint.deviceId()) ||
449 egressPoint.port().isLogical()) {
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700450 return generateRuleForSingle(networkId, ingressPoint, egressPoint,
451 commonSelector, commonTreatment, flowRule);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700452 } else {
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700453 return generateRuleForMulti(networkId, ingressPoint, egressPoint,
454 commonSelector, commonTreatment, flowRule);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700455 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700456 }
457
Harold Huang7362e672017-04-19 10:00:11 +0800458 /**
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700459 * Generate physical rules when a virtual flow rule can be handled inside
460 * a single physical switch.
Harold Huang7362e672017-04-19 10:00:11 +0800461 *
462 * @param networkId The virtual network identifier
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700463 * @param ingressPoint The ingress point of the physical network
464 * @param egressPoint The egress point of the physical network
Harold Huang7362e672017-04-19 10:00:11 +0800465 * @param commonSelector A common traffic selector between the virtual
466 * and physical flow rules
467 * @param commonTreatment A common traffic treatment between the virtual
468 * and physical flow rules
469 * @param flowRule The virtual flow rule to be translated
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700470 * @return A set of flow rules for the physical network
Harold Huang7362e672017-04-19 10:00:11 +0800471 */
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700472 private Set<FlowRule> generateRuleForSingle(NetworkId networkId,
473 ConnectPoint ingressPoint,
474 ConnectPoint egressPoint,
475 TrafficSelector commonSelector,
476 TrafficTreatment commonTreatment,
477 FlowRule flowRule) {
Harold Huang7362e672017-04-19 10:00:11 +0800478
Harold Huang7362e672017-04-19 10:00:11 +0800479 Set<FlowRule> outRules = new HashSet<>();
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700480
481 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector
482 .builder(commonSelector)
483 .matchInPort(ingressPoint.port());
484
485 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
486 .builder(commonTreatment)
487 .setOutput(egressPoint.port());
488
489 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
490 .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
491 .forDevice(ingressPoint.deviceId())
492 .withSelector(selectorBuilder.build())
493 .withTreatment(treatmentBuilder.build())
494 .withIdleTimeout(flowRule.timeout())
495 .withPriority(flowRule.priority());
496
497 FlowRule rule = ruleBuilder.build();
498 frm.addIngressRule(flowRule, rule, networkId);
499 outRules.add(rule);
500
501 return outRules;
502 }
503
504 /**
505 * Generate physical rules when a virtual flow rule can be handled with
506 * multiple physical switches.
507 *
508 * @param networkId The virtual network identifier
509 * @param ingressPoint The ingress point of the physical network
510 * @param egressPoint The egress point of the physical network
511 * @param commonSelector A common traffic selector between the virtual
512 * and physical flow rules
513 * @param commonTreatment A common traffic treatment between the virtual
514 * and physical flow rules
515 * @param flowRule The virtual flow rule to be translated
516 * @return A set of flow rules for the physical network
517 */
518 private Set<FlowRule> generateRuleForMulti(NetworkId networkId,
519 ConnectPoint ingressPoint,
520 ConnectPoint egressPoint,
521 TrafficSelector commonSelector,
522 TrafficTreatment commonTreatment,
523 FlowRule flowRule) {
524 Set<FlowRule> outRules = new HashSet<>();
Harold Huang7362e672017-04-19 10:00:11 +0800525
526 Path internalPath = internalRoutingAlgorithm
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700527 .findPath(ingressPoint, egressPoint);
528 checkNotNull(internalPath, "No path between " +
529 ingressPoint.toString() + " " + egressPoint.toString());
530
531 ConnectPoint outCp = internalPath.links().get(0).src();
532
533 //ingress point of tunnel
534 TrafficSelector.Builder selectorBuilder =
535 DefaultTrafficSelector.builder(commonSelector);
536 selectorBuilder.matchInPort(ingressPoint.port());
537
538 TrafficTreatment.Builder treatmentBuilder =
539 DefaultTrafficTreatment.builder(commonTreatment);
540 //TODO: add the logic to check host location
541 treatmentBuilder.pushVlan()
542 .setVlanId(VlanId.vlanId(networkId.id().shortValue()));
543 treatmentBuilder.setOutput(outCp.port());
544
545 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
546 .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
547 .forDevice(ingressPoint.deviceId())
548 .withSelector(selectorBuilder.build())
549 .withIdleTimeout(flowRule.timeout())
550 .withTreatment(treatmentBuilder.build())
551 .withPriority(flowRule.priority());
552
553 FlowRule rule = ruleBuilder.build();
554 frm.addIngressRule(flowRule, rule, networkId);
555 outRules.add(rule);
556
557 //routing inside tunnel
558 ConnectPoint inCp = internalPath.links().get(0).dst();
559
560 if (internalPath.links().size() > 1) {
561 for (Link l : internalPath.links()
562 .subList(1, internalPath.links().size())) {
563
564 outCp = l.src();
565
566 selectorBuilder = DefaultTrafficSelector
Harold Huang7362e672017-04-19 10:00:11 +0800567 .builder(commonSelector)
568 .matchVlanId(VlanId.vlanId(networkId.id().shortValue()))
569 .matchInPort(inCp.port());
570
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700571 treatmentBuilder = DefaultTrafficTreatment
Harold Huang7362e672017-04-19 10:00:11 +0800572 .builder(commonTreatment)
573 .setOutput(outCp.port());
574
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700575 ruleBuilder = DefaultFlowRule.builder()
Harold Huang7362e672017-04-19 10:00:11 +0800576 .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
577 .forDevice(inCp.deviceId())
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700578 .withSelector(selectorBuilder.build())
579 .withTreatment(treatmentBuilder.build())
580 .withIdleTimeout(flowRule.timeout())
Harold Huang7362e672017-04-19 10:00:11 +0800581 .withPriority(flowRule.priority());
582
Harold Huang7362e672017-04-19 10:00:11 +0800583 outRules.add(ruleBuilder.build());
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700584 inCp = l.dst();
Harold Huang7362e672017-04-19 10:00:11 +0800585 }
586 }
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700587
588 //egress point of tunnel
589 selectorBuilder = DefaultTrafficSelector.builder(commonSelector)
590 .matchVlanId(VlanId.vlanId(networkId.id().shortValue()))
591 .matchInPort(inCp.port());
592
593 treatmentBuilder = DefaultTrafficTreatment.builder(commonTreatment)
594 .popVlan()
595 .setOutput(egressPoint.port());
596
597 ruleBuilder = DefaultFlowRule.builder()
598 .fromApp(appId)
599 .forDevice(egressPoint.deviceId())
600 .withSelector(selectorBuilder.build())
601 .withTreatment(treatmentBuilder.build())
602 .withIdleTimeout(flowRule.timeout())
603 .withPriority(flowRule.priority());
604
605 outRules.add(ruleBuilder.build());
606
Harold Huang7362e672017-04-19 10:00:11 +0800607 return outRules;
608 }
609
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700610 private class InternalFlowRuleListener implements FlowRuleListener {
611 @Override
612 public void event(FlowRuleEvent event) {
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700613 if ((event.type() == FlowRuleEvent.Type.RULE_ADDED) ||
614 (event.type() == FlowRuleEvent.Type.RULE_UPDATED)) {
615 if (frm.isVirtualIngressRule(event.subject())) {
616 NetworkId networkId = frm.getVirtualNetworkId(event.subject());
617 FlowEntry vEntry = getVirtualFlowEntry(event.subject());
Yoonseon Han26d98c82017-07-19 15:46:57 +0900618
619 if (vEntry == null) {
620 return;
621 }
622
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900623 frm.addOrUpdateFlowEntry(networkId, vEntry.deviceId(), vEntry);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700624
625 VirtualFlowRuleProviderService providerService =
626 (VirtualFlowRuleProviderService) providerRegistryService
627 .getProviderService(networkId,
628 VirtualFlowRuleProvider.class);
629
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900630 ImmutableList.Builder<FlowEntry> builder = ImmutableList.builder();
631 builder.addAll(frm.getFlowEntries(networkId, vEntry.deviceId()));
632
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700633 providerService.pushFlowMetrics(vEntry.deviceId(), builder.build());
634 }
635 } else if (event.type() == FlowRuleEvent.Type.RULE_REMOVED) {
636 if (frm.isVirtualIngressRule(event.subject())) {
637 //FIXME confirm all physical rules are removed
638 NetworkId networkId = frm.getVirtualNetworkId(event.subject());
639 FlowEntry vEntry = getVirtualFlowEntry(event.subject());
640
Yoonseon Han26d98c82017-07-19 15:46:57 +0900641 if (vEntry == null) {
642 return;
643 }
644
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700645 frm.removeFlowEntry(networkId, vEntry.deviceId(), vEntry);
646 frm.removeFlowRule(networkId, vEntry.deviceId(), vEntry);
647
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700648 VirtualFlowRuleProviderService providerService =
649 (VirtualFlowRuleProviderService) providerRegistryService
650 .getProviderService(networkId,
651 VirtualFlowRuleProvider.class);
652 providerService.flowRemoved(vEntry);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700653 }
654 }
655 }
656
657 private FlowEntry getVirtualFlowEntry(FlowRule rule) {
658 FlowEntry entry = null;
659 for (FlowEntry fe :
660 flowRuleService.getFlowEntries(rule.deviceId())) {
661 if (rule.exactMatch(fe)) {
662 entry = fe;
663 }
664 }
665
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700666 if (entry != null) {
667 return virtualize(entry);
668 } else {
669 return virtualize(new DefaultFlowEntry(rule,
670 FlowEntry.FlowEntryState.PENDING_REMOVE));
671 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700672 }
673 }
674
675 private class InternalVirtualFlowRuleManager {
676 /** <Virtual Network ID, Virtual Device ID, Virtual Flow Rules>.*/
677 final Table<NetworkId, DeviceId, Set<FlowRule>> flowRuleTable
678 = HashBasedTable.create();
679
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700680 /** <Virtual Network ID, Virtual Device ID, Virtual Flow Entries>.*/
681 final Table<NetworkId, DeviceId, Set<FlowEntry>> flowEntryTable
682 = HashBasedTable.create();
683
684 /** <Physical Flow Rule, Virtual Network ID>.*/
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900685 final Map<FlowRule, NetworkId> ingressRuleMap = Maps.newHashMap();
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700686
687 /** <Physical Flow Rule, Virtual Virtual Flow Rule>.*/
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900688 final Map<FlowRule, FlowRule> virtualizationMap = Maps.newHashMap();
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700689
690 private Iterable<FlowRule> getFlowRules(NetworkId networkId,
691 DeviceId deviceId) {
692 return flowRuleTable.get(networkId, deviceId);
693 }
694
695 private Iterable<FlowEntry> getFlowEntries(NetworkId networkId,
696 DeviceId deviceId) {
697 return flowEntryTable.get(networkId, deviceId);
698 }
699
700 private void addFlowRule(NetworkId networkId, DeviceId deviceId,
701 FlowRule flowRule) {
702 Set<FlowRule> set = flowRuleTable.get(networkId, deviceId);
703 if (set == null) {
704 set = Sets.newHashSet();
705 flowRuleTable.put(networkId, deviceId, set);
706 }
707 set.add(flowRule);
708 }
709
710 private void removeFlowRule(NetworkId networkId, DeviceId deviceId,
711 FlowRule flowRule) {
712 Set<FlowRule> set = flowRuleTable.get(networkId, deviceId);
713 if (set == null) {
714 return;
715 }
716 set.remove(flowRule);
717 }
718
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900719 private void addOrUpdateFlowEntry(NetworkId networkId, DeviceId deviceId,
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700720 FlowEntry flowEntry) {
721 Set<FlowEntry> set = flowEntryTable.get(networkId, deviceId);
722 if (set == null) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900723 set = Sets.newConcurrentHashSet();
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700724 flowEntryTable.put(networkId, deviceId, set);
725 }
726
727 //Replace old entry with new one
728 set.stream().filter(fe -> fe.exactMatch(flowEntry))
729 .forEach(set::remove);
730 set.add(flowEntry);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700731 }
732
733 private void removeFlowEntry(NetworkId networkId, DeviceId deviceId,
734 FlowEntry flowEntry) {
735 Set<FlowEntry> set = flowEntryTable.get(networkId, deviceId);
736 if (set == null) {
737 return;
738 }
739 set.remove(flowEntry);
740 }
741
742 private void addIngressRule(FlowRule virtualRule, FlowRule physicalRule,
743 NetworkId networkId) {
744 ingressRuleMap.put(physicalRule, networkId);
745 virtualizationMap.put(physicalRule, virtualRule);
746 }
747
748 private FlowRule getVirtualRule(FlowRule physicalRule) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900749 return virtualizationMap.get(physicalRule);
750 }
751
752 private void removeIngressRule(FlowRule physicalRule) {
753 ingressRuleMap.remove(physicalRule);
754 virtualizationMap.remove(physicalRule);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700755 }
756
757 private Set<FlowRule> getAllPhysicalRule() {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900758 return copyOf(virtualizationMap.keySet());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700759 }
760
761 private NetworkId getVirtualNetworkId(FlowRule physicalRule) {
762 return ingressRuleMap.get(physicalRule);
763 }
764
765 /**
766 * Test the rule is the ingress rule for virtual rules.
767 *
768 * @param flowRule A flow rule from underlying data plane to be translated
769 * @return True when the rule is for ingress point for a virtual switch
770 */
771 private boolean isVirtualIngressRule(FlowRule flowRule) {
772 return ingressRuleMap.containsKey(flowRule);
773 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700774 }
775
776 private class DefaultInternalRoutingAlgorithm
777 implements InternalRoutingAlgorithm {
778
779 @Override
780 public Path findPath(ConnectPoint src, ConnectPoint dst) {
781 Set<Path> paths =
782 topologyService.getPaths(topologyService.currentTopology(),
783 src.deviceId(),
784 dst.deviceId());
785
786 if (paths.isEmpty()) {
787 return null;
788 }
789
790 //TODO the logic find the best path
791 return (Path) paths.toArray()[0];
792 }
793 }
794}