blob: 436e1d43bcf089275b2e757da9ab6f37276dc863 [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.onlab.packet.VlanId;
27import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
Yoonseon Han5cf483a2017-04-19 23:14:00 -070029import org.onosproject.core.DefaultApplicationId;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070030import org.onosproject.incubator.net.virtual.NetworkId;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090031import org.onosproject.incubator.net.virtual.VirtualNetworkService;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070032import org.onosproject.incubator.net.virtual.VirtualPort;
33import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider;
34import org.onosproject.incubator.net.virtual.provider.InternalRoutingAlgorithm;
35import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProvider;
36import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProviderService;
37import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
38import org.onosproject.net.ConnectPoint;
39import org.onosproject.net.DeviceId;
40import org.onosproject.net.Link;
41import org.onosproject.net.Path;
42import org.onosproject.net.PortNumber;
43import org.onosproject.net.device.DeviceService;
Yoonseon Han997c8422017-04-24 16:20:03 -070044import org.onosproject.net.flow.BatchOperationEntry;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090045import org.onosproject.net.flow.CompletedBatchOperation;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070046import org.onosproject.net.flow.DefaultFlowEntry;
47import org.onosproject.net.flow.DefaultFlowRule;
48import org.onosproject.net.flow.DefaultTrafficSelector;
49import org.onosproject.net.flow.DefaultTrafficTreatment;
50import org.onosproject.net.flow.FlowEntry;
51import org.onosproject.net.flow.FlowRule;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070052import org.onosproject.net.flow.FlowRuleEvent;
53import org.onosproject.net.flow.FlowRuleListener;
Yoonseon Han997c8422017-04-24 16:20:03 -070054import org.onosproject.net.flow.FlowRuleOperations;
55import org.onosproject.net.flow.FlowRuleOperationsContext;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070056import org.onosproject.net.flow.FlowRuleService;
57import org.onosproject.net.flow.TrafficSelector;
58import org.onosproject.net.flow.TrafficTreatment;
59import org.onosproject.net.flow.criteria.Criterion;
60import org.onosproject.net.flow.criteria.PortCriterion;
61import org.onosproject.net.flow.instructions.Instruction;
62import org.onosproject.net.flow.instructions.Instructions;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070063import org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry;
64import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070065import org.onosproject.net.provider.ProviderId;
66import org.onosproject.net.topology.TopologyService;
67import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070068import org.osgi.service.component.annotations.Activate;
69import org.osgi.service.component.annotations.Component;
70import org.osgi.service.component.annotations.Deactivate;
71import org.osgi.service.component.annotations.Modified;
72import org.osgi.service.component.annotations.Reference;
73import org.osgi.service.component.annotations.ReferenceCardinality;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070074import org.slf4j.Logger;
75
76import java.util.Dictionary;
77import java.util.HashSet;
78import java.util.Map;
79import java.util.Optional;
80import java.util.Set;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090081import java.util.stream.Collectors;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070082
83import static com.google.common.base.Preconditions.checkNotNull;
Yoonseon Hanc8089db2017-03-22 20:22:12 +090084import static com.google.common.collect.ImmutableSet.copyOf;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070085import static org.slf4j.LoggerFactory.getLogger;
86
87/**
88 * Provider that translate virtual flow rules into physical rules.
89 * Current implementation is based on FlowRules.
90 * This virtualize and de-virtualize virtual flow rules into physical flow rules.
91 * {@link org.onosproject.net.flow.FlowRule}
92 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070093@Component(service = VirtualFlowRuleProvider.class)
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070094public class DefaultVirtualFlowRuleProvider extends AbstractVirtualProvider
95 implements VirtualFlowRuleProvider {
96
Yoonseon Hanc8089db2017-03-22 20:22:12 +090097 private static final String APP_ID_STR = "org.onosproject.virtual.vnet-flow_";
Yoonseon Hanc70b4e02016-10-20 15:24:33 -070098
99 private final Logger log = getLogger(getClass());
100
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700101 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700102 protected TopologyService topologyService;
103
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700104 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900105 protected VirtualNetworkService vnService;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700106
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700107 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700108 protected CoreService coreService;
109
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700111 protected FlowRuleService flowRuleService;
112
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700113 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700114 protected DeviceService deviceService;
115
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700117 protected VirtualProviderRegistryService providerRegistryService;
118
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900119 private InternalRoutingAlgorithm internalRoutingAlgorithm;
120 private InternalVirtualFlowRuleManager frm;
121 private ApplicationId appId;
122 private FlowRuleListener flowRuleListener;
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700123
124 /**
yoonseond6ba9a62017-01-30 11:48:07 -0800125 * Creates a provider with the identifier.
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700126 */
127 public DefaultVirtualFlowRuleProvider() {
128 super(new ProviderId("vnet-flow", "org.onosproject.virtual.vnet-flow"));
129 }
130
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700131 @Activate
132 public void activate() {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900133 appId = coreService.registerApplication(APP_ID_STR);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700134
135 providerRegistryService.registerProvider(this);
136
137 flowRuleListener = new InternalFlowRuleListener();
138 flowRuleService.addListener(flowRuleListener);
139
140 internalRoutingAlgorithm = new DefaultInternalRoutingAlgorithm();
141 frm = new InternalVirtualFlowRuleManager();
142
143 log.info("Started");
144 }
145
146 @Deactivate
147 public void deactivate() {
148 flowRuleService.removeListener(flowRuleListener);
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700149 flowRuleService.removeFlowRulesById(appId);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700150 providerRegistryService.unregisterProvider(this);
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700151 log.info("Stopped");
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700152 }
153
154 @Modified
155 protected void modified(ComponentContext context) {
156 Dictionary<?, ?> properties = context.getProperties();
157 }
158
159 @Override
160 public void applyFlowRule(NetworkId networkId, FlowRule... flowRules) {
161 for (FlowRule flowRule : flowRules) {
162 devirtualize(networkId, flowRule).forEach(
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700163 r -> flowRuleService.applyFlowRules(r));
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700164 }
165 }
166
167 @Override
168 public void removeFlowRule(NetworkId networkId, FlowRule... flowRules) {
169 for (FlowRule flowRule : flowRules) {
170 devirtualize(networkId, flowRule).forEach(
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700171 r -> flowRuleService.removeFlowRules(r));
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700172 }
173 }
174
175 @Override
176 public void executeBatch(NetworkId networkId, FlowRuleBatchOperation batch) {
177 checkNotNull(batch);
178
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900179 for (FlowRuleBatchEntry fop : batch.getOperations()) {
Yoonseon Han997c8422017-04-24 16:20:03 -0700180 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
181
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700182 switch (fop.operator()) {
183 case ADD:
Yoonseon Han997c8422017-04-24 16:20:03 -0700184 devirtualize(networkId, fop.target()).forEach(builder::add);
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700185 break;
186 case REMOVE:
Yoonseon Han997c8422017-04-24 16:20:03 -0700187 devirtualize(networkId, fop.target()).forEach(builder::remove);
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700188 break;
189 case MODIFY:
Yoonseon Han997c8422017-04-24 16:20:03 -0700190 devirtualize(networkId, fop.target()).forEach(builder::modify);
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700191 break;
192 default:
193 break;
194 }
Yoonseon Han997c8422017-04-24 16:20:03 -0700195
196 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
197 @Override
198 public void onSuccess(FlowRuleOperations ops) {
199 CompletedBatchOperation status =
200 new CompletedBatchOperation(true,
201 Sets.newConcurrentHashSet(),
202 batch.deviceId());
203
204 VirtualFlowRuleProviderService providerService =
205 (VirtualFlowRuleProviderService) providerRegistryService
206 .getProviderService(networkId,
207 VirtualFlowRuleProvider.class);
208 providerService.batchOperationCompleted(batch.id(), status);
209 }
210
211 @Override
212 public void onError(FlowRuleOperations ops) {
213 Set<FlowRule> failures = ImmutableSet.copyOf(
214 Lists.transform(batch.getOperations(),
215 BatchOperationEntry::target));
216
217 CompletedBatchOperation status =
218 new CompletedBatchOperation(false,
219 failures,
220 batch.deviceId());
221
222 VirtualFlowRuleProviderService providerService =
223 (VirtualFlowRuleProviderService) providerRegistryService
224 .getProviderService(networkId,
225 VirtualFlowRuleProvider.class);
226 providerService.batchOperationCompleted(batch.id(), status);
227 }
228 }));
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900229 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700230 }
231
232 public void setEmbeddingAlgorithm(InternalRoutingAlgorithm
233 internalRoutingAlgorithm) {
234 this.internalRoutingAlgorithm = internalRoutingAlgorithm;
235 }
236
237 /**
238 * Translate the requested physical flow rules into virtual flow rules.
239 *
240 * @param flowRule A virtual flow rule to be translated
241 * @return A flow rule for a specific virtual network
242 */
kdarapu93722ef2017-02-16 19:24:29 +0530243 private FlowRule virtualizeFlowRule(FlowRule flowRule) {
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700244
245 FlowRule storedrule = frm.getVirtualRule(flowRule);
246
247 if (flowRule.reason() == FlowRule.FlowRemoveReason.NO_REASON) {
248 return storedrule;
249 } else {
250 return DefaultFlowRule.builder()
251 .withReason(flowRule.reason())
252 .withPriority(storedrule.priority())
253 .forDevice(storedrule.deviceId())
254 .forTable(storedrule.tableId())
255 .fromApp(new DefaultApplicationId(storedrule.appId(), null))
256 .withIdleTimeout(storedrule.timeout())
257 .withHardTimeout(storedrule.hardTimeout())
258 .withSelector(storedrule.selector())
259 .withTreatment(storedrule.treatment())
260 .build();
261 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700262 }
263
264 private FlowEntry virtualize(FlowEntry flowEntry) {
kdarapu93722ef2017-02-16 19:24:29 +0530265 FlowRule vRule = virtualizeFlowRule(flowEntry);
Yoonseon Han26d98c82017-07-19 15:46:57 +0900266
267 if (vRule == null) {
268 return null;
269 }
270
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700271 FlowEntry vEntry = new DefaultFlowEntry(vRule, flowEntry.state(),
272 flowEntry.life(),
273 flowEntry.packets(),
274 flowEntry.bytes());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700275 return vEntry;
276 }
277
278 /**
279 * Translate the requested virtual flow rules into physical flow rules.
280 * The translation could be one to many.
281 *
282 * @param flowRule A flow rule from underlying data plane to be translated
283 * @return A set of flow rules for physical network
284 */
285 private Set<FlowRule> devirtualize(NetworkId networkId, FlowRule flowRule) {
286
287 Set<FlowRule> outRules = new HashSet<>();
288
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900289 Set<ConnectPoint> ingressPoints = extractIngressPoints(networkId,
290 flowRule.deviceId(),
291 flowRule.selector());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700292
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900293 ConnectPoint egressPoint = extractEgressPoints(networkId,
294 flowRule.deviceId(),
295 flowRule.treatment());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700296
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900297 if (egressPoint == null) {
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700298 return outRules;
299 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700300
301 TrafficSelector.Builder commonSelectorBuilder
302 = DefaultTrafficSelector.builder();
303 flowRule.selector().criteria().stream()
304 .filter(c -> c.type() != Criterion.Type.IN_PORT)
305 .forEach(c -> commonSelectorBuilder.add(c));
306 TrafficSelector commonSelector = commonSelectorBuilder.build();
307
308 TrafficTreatment.Builder commonTreatmentBuilder
309 = DefaultTrafficTreatment.builder();
310 flowRule.treatment().allInstructions().stream()
311 .filter(i -> i.type() != Instruction.Type.OUTPUT)
312 .forEach(i -> commonTreatmentBuilder.add(i));
313 TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
314
315 for (ConnectPoint ingressPoint : ingressPoints) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900316 if (egressPoint.port() == PortNumber.FLOOD) {
317 Set<ConnectPoint> outPoints = vnService
318 .getVirtualPorts(networkId, flowRule.deviceId())
319 .stream()
320 .map(VirtualPort::realizedBy)
321 .filter(p -> !p.equals(ingressPoint))
322 .collect(Collectors.toSet());
323
324 for (ConnectPoint outPoint : outPoints) {
325 outRules.addAll(generateRules(networkId, ingressPoint, outPoint,
326 commonSelector, commonTreatment, flowRule));
327 }
328 } else {
329 outRules.addAll(generateRules(networkId, ingressPoint, egressPoint,
330 commonSelector, commonTreatment, flowRule));
331 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700332 }
333
334 return outRules;
335 }
336
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900337 /**
338 * Extract ingress connect points of the physical network
339 * from the requested traffic selector.
340 *
341 * @param networkId the virtual network identifier
342 * @param deviceId the virtual device identifier
343 * @param selector the traffic selector to extract ingress point
344 * @return the set of ingress connect points of the physical network
345 */
346 private Set<ConnectPoint> extractIngressPoints(NetworkId networkId,
347 DeviceId deviceId,
348 TrafficSelector selector) {
349
350 Set<ConnectPoint> ingressPoints = new HashSet<>();
351
352 Set<VirtualPort> vPorts = vnService
353 .getVirtualPorts(networkId, deviceId);
354
355 PortCriterion portCriterion = ((PortCriterion) selector
356 .getCriterion(Criterion.Type.IN_PORT));
357
358 if (portCriterion != null) {
359 PortNumber vInPortNum = portCriterion.port();
360
361 Optional<ConnectPoint> optionalCp = vPorts.stream()
362 .filter(v -> v.number().equals(vInPortNum))
363 .map(VirtualPort::realizedBy).findFirst();
364 if (!optionalCp.isPresent()) {
365 log.warn("Port {} is not realized yet, in Network {}, Device {}",
366 vInPortNum, networkId, deviceId);
367 return ingressPoints;
368 }
369
370 ingressPoints.add(optionalCp.get());
371 } else {
372 for (VirtualPort vPort : vPorts) {
373 if (vPort.realizedBy() != null) {
374 ingressPoints.add(vPort.realizedBy());
375 } else {
376 log.warn("Port {} is not realized yet, in Network {}, " +
377 "Device {}",
378 vPort, networkId, deviceId);
379 }
380 }
381 }
382
383 return ingressPoints;
384 }
385
386 /**
387 * Extract egress connect point of the physical network
388 * from the requested traffic treatment.
389 *
390 * @param networkId the virtual network identifier
391 * @param deviceId the virtual device identifier
392 * @param treatment the traffic treatment to extract ingress point
393 * @return the egress connect point of the physical network
394 */
395 private ConnectPoint extractEgressPoints(NetworkId networkId,
396 DeviceId deviceId,
397 TrafficTreatment treatment) {
398
399 Set<VirtualPort> vPorts = vnService
400 .getVirtualPorts(networkId, deviceId);
401
402 PortNumber vOutPortNum = treatment.allInstructions().stream()
403 .filter(i -> i.type() == Instruction.Type.OUTPUT)
404 .map(i -> ((Instructions.OutputInstruction) i).port())
405 .findFirst().get();
406
407 Optional<ConnectPoint> optionalCpOut = vPorts.stream()
408 .filter(v -> v.number().equals(vOutPortNum))
409 .map(VirtualPort::realizedBy)
410 .findFirst();
411
412 if (!optionalCpOut.isPresent()) {
413 if (vOutPortNum.isLogical()) {
414 return new ConnectPoint(DeviceId.deviceId("vNet"), vOutPortNum);
415 }
416
417 log.warn("Port {} is not realized yet, in Network {}, Device {}",
418 vOutPortNum, networkId, deviceId);
419 return null;
420 }
421
422 return optionalCpOut.get();
423 }
424
425
426 /**
427 * Generates the corresponding flow rules for the physical network.
428 *
429 * @param networkId The virtual network identifier
430 * @param ingressPoint The ingress point of the physical network
431 * @param egressPoint The egress point of the physical network
432 * @param commonSelector A common traffic selector between the virtual
433 * and physical flow rules
434 * @param commonTreatment A common traffic treatment between the virtual
435 * and physical flow rules
436 * @param flowRule The virtual flow rule to be translated
437 * @return A set of flow rules for the physical network
438 */
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700439 private Set<FlowRule> generateRules(NetworkId networkId,
440 ConnectPoint ingressPoint,
441 ConnectPoint egressPoint,
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900442 TrafficSelector commonSelector,
443 TrafficTreatment commonTreatment,
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700444 FlowRule flowRule) {
445
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900446 if (ingressPoint.deviceId().equals(egressPoint.deviceId()) ||
447 egressPoint.port().isLogical()) {
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700448 return generateRuleForSingle(networkId, ingressPoint, egressPoint,
449 commonSelector, commonTreatment, flowRule);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700450 } else {
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700451 return generateRuleForMulti(networkId, ingressPoint, egressPoint,
452 commonSelector, commonTreatment, flowRule);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700453 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700454 }
455
Harold Huang7362e672017-04-19 10:00:11 +0800456 /**
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700457 * Generate physical rules when a virtual flow rule can be handled inside
458 * a single physical switch.
Harold Huang7362e672017-04-19 10:00:11 +0800459 *
460 * @param networkId The virtual network identifier
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700461 * @param ingressPoint The ingress point of the physical network
462 * @param egressPoint The egress point of the physical network
Harold Huang7362e672017-04-19 10:00:11 +0800463 * @param commonSelector A common traffic selector between the virtual
464 * and physical flow rules
465 * @param commonTreatment A common traffic treatment between the virtual
466 * and physical flow rules
467 * @param flowRule The virtual flow rule to be translated
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700468 * @return A set of flow rules for the physical network
Harold Huang7362e672017-04-19 10:00:11 +0800469 */
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700470 private Set<FlowRule> generateRuleForSingle(NetworkId networkId,
471 ConnectPoint ingressPoint,
472 ConnectPoint egressPoint,
473 TrafficSelector commonSelector,
474 TrafficTreatment commonTreatment,
475 FlowRule flowRule) {
Harold Huang7362e672017-04-19 10:00:11 +0800476
Harold Huang7362e672017-04-19 10:00:11 +0800477 Set<FlowRule> outRules = new HashSet<>();
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700478
479 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector
480 .builder(commonSelector)
481 .matchInPort(ingressPoint.port());
482
483 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
484 .builder(commonTreatment)
485 .setOutput(egressPoint.port());
486
487 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
488 .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
489 .forDevice(ingressPoint.deviceId())
490 .withSelector(selectorBuilder.build())
491 .withTreatment(treatmentBuilder.build())
492 .withIdleTimeout(flowRule.timeout())
493 .withPriority(flowRule.priority());
494
495 FlowRule rule = ruleBuilder.build();
496 frm.addIngressRule(flowRule, rule, networkId);
497 outRules.add(rule);
498
499 return outRules;
500 }
501
502 /**
503 * Generate physical rules when a virtual flow rule can be handled with
504 * multiple physical switches.
505 *
506 * @param networkId The virtual network identifier
507 * @param ingressPoint The ingress point of the physical network
508 * @param egressPoint The egress point of the physical network
509 * @param commonSelector A common traffic selector between the virtual
510 * and physical flow rules
511 * @param commonTreatment A common traffic treatment between the virtual
512 * and physical flow rules
513 * @param flowRule The virtual flow rule to be translated
514 * @return A set of flow rules for the physical network
515 */
516 private Set<FlowRule> generateRuleForMulti(NetworkId networkId,
517 ConnectPoint ingressPoint,
518 ConnectPoint egressPoint,
519 TrafficSelector commonSelector,
520 TrafficTreatment commonTreatment,
521 FlowRule flowRule) {
522 Set<FlowRule> outRules = new HashSet<>();
Harold Huang7362e672017-04-19 10:00:11 +0800523
524 Path internalPath = internalRoutingAlgorithm
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700525 .findPath(ingressPoint, egressPoint);
526 checkNotNull(internalPath, "No path between " +
527 ingressPoint.toString() + " " + egressPoint.toString());
528
529 ConnectPoint outCp = internalPath.links().get(0).src();
530
531 //ingress point of tunnel
532 TrafficSelector.Builder selectorBuilder =
533 DefaultTrafficSelector.builder(commonSelector);
534 selectorBuilder.matchInPort(ingressPoint.port());
535
536 TrafficTreatment.Builder treatmentBuilder =
537 DefaultTrafficTreatment.builder(commonTreatment);
538 //TODO: add the logic to check host location
539 treatmentBuilder.pushVlan()
540 .setVlanId(VlanId.vlanId(networkId.id().shortValue()));
541 treatmentBuilder.setOutput(outCp.port());
542
543 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
544 .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
545 .forDevice(ingressPoint.deviceId())
546 .withSelector(selectorBuilder.build())
547 .withIdleTimeout(flowRule.timeout())
548 .withTreatment(treatmentBuilder.build())
549 .withPriority(flowRule.priority());
550
551 FlowRule rule = ruleBuilder.build();
552 frm.addIngressRule(flowRule, rule, networkId);
553 outRules.add(rule);
554
555 //routing inside tunnel
556 ConnectPoint inCp = internalPath.links().get(0).dst();
557
558 if (internalPath.links().size() > 1) {
559 for (Link l : internalPath.links()
560 .subList(1, internalPath.links().size())) {
561
562 outCp = l.src();
563
564 selectorBuilder = DefaultTrafficSelector
Harold Huang7362e672017-04-19 10:00:11 +0800565 .builder(commonSelector)
566 .matchVlanId(VlanId.vlanId(networkId.id().shortValue()))
567 .matchInPort(inCp.port());
568
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700569 treatmentBuilder = DefaultTrafficTreatment
Harold Huang7362e672017-04-19 10:00:11 +0800570 .builder(commonTreatment)
571 .setOutput(outCp.port());
572
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700573 ruleBuilder = DefaultFlowRule.builder()
Harold Huang7362e672017-04-19 10:00:11 +0800574 .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
575 .forDevice(inCp.deviceId())
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700576 .withSelector(selectorBuilder.build())
577 .withTreatment(treatmentBuilder.build())
578 .withIdleTimeout(flowRule.timeout())
Harold Huang7362e672017-04-19 10:00:11 +0800579 .withPriority(flowRule.priority());
580
Harold Huang7362e672017-04-19 10:00:11 +0800581 outRules.add(ruleBuilder.build());
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700582 inCp = l.dst();
Harold Huang7362e672017-04-19 10:00:11 +0800583 }
584 }
Yoonseon Han8c3680e2017-05-22 15:22:58 -0700585
586 //egress point of tunnel
587 selectorBuilder = DefaultTrafficSelector.builder(commonSelector)
588 .matchVlanId(VlanId.vlanId(networkId.id().shortValue()))
589 .matchInPort(inCp.port());
590
591 treatmentBuilder = DefaultTrafficTreatment.builder(commonTreatment)
592 .popVlan()
593 .setOutput(egressPoint.port());
594
595 ruleBuilder = DefaultFlowRule.builder()
596 .fromApp(appId)
597 .forDevice(egressPoint.deviceId())
598 .withSelector(selectorBuilder.build())
599 .withTreatment(treatmentBuilder.build())
600 .withIdleTimeout(flowRule.timeout())
601 .withPriority(flowRule.priority());
602
603 outRules.add(ruleBuilder.build());
604
Harold Huang7362e672017-04-19 10:00:11 +0800605 return outRules;
606 }
607
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700608 private class InternalFlowRuleListener implements FlowRuleListener {
609 @Override
610 public void event(FlowRuleEvent event) {
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700611 if ((event.type() == FlowRuleEvent.Type.RULE_ADDED) ||
612 (event.type() == FlowRuleEvent.Type.RULE_UPDATED)) {
613 if (frm.isVirtualIngressRule(event.subject())) {
614 NetworkId networkId = frm.getVirtualNetworkId(event.subject());
615 FlowEntry vEntry = getVirtualFlowEntry(event.subject());
Yoonseon Han26d98c82017-07-19 15:46:57 +0900616
617 if (vEntry == null) {
618 return;
619 }
620
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900621 frm.addOrUpdateFlowEntry(networkId, vEntry.deviceId(), vEntry);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700622
623 VirtualFlowRuleProviderService providerService =
624 (VirtualFlowRuleProviderService) providerRegistryService
625 .getProviderService(networkId,
626 VirtualFlowRuleProvider.class);
627
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900628 ImmutableList.Builder<FlowEntry> builder = ImmutableList.builder();
629 builder.addAll(frm.getFlowEntries(networkId, vEntry.deviceId()));
630
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700631 providerService.pushFlowMetrics(vEntry.deviceId(), builder.build());
632 }
633 } else if (event.type() == FlowRuleEvent.Type.RULE_REMOVED) {
634 if (frm.isVirtualIngressRule(event.subject())) {
635 //FIXME confirm all physical rules are removed
636 NetworkId networkId = frm.getVirtualNetworkId(event.subject());
637 FlowEntry vEntry = getVirtualFlowEntry(event.subject());
638
Yoonseon Han26d98c82017-07-19 15:46:57 +0900639 if (vEntry == null) {
640 return;
641 }
642
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700643 frm.removeFlowEntry(networkId, vEntry.deviceId(), vEntry);
644 frm.removeFlowRule(networkId, vEntry.deviceId(), vEntry);
645
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700646 VirtualFlowRuleProviderService providerService =
647 (VirtualFlowRuleProviderService) providerRegistryService
648 .getProviderService(networkId,
649 VirtualFlowRuleProvider.class);
650 providerService.flowRemoved(vEntry);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700651 }
652 }
653 }
654
655 private FlowEntry getVirtualFlowEntry(FlowRule rule) {
656 FlowEntry entry = null;
657 for (FlowEntry fe :
658 flowRuleService.getFlowEntries(rule.deviceId())) {
659 if (rule.exactMatch(fe)) {
660 entry = fe;
661 }
662 }
663
Yoonseon Han5cf483a2017-04-19 23:14:00 -0700664 if (entry != null) {
665 return virtualize(entry);
666 } else {
667 return virtualize(new DefaultFlowEntry(rule,
668 FlowEntry.FlowEntryState.PENDING_REMOVE));
669 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700670 }
671 }
672
673 private class InternalVirtualFlowRuleManager {
674 /** <Virtual Network ID, Virtual Device ID, Virtual Flow Rules>.*/
675 final Table<NetworkId, DeviceId, Set<FlowRule>> flowRuleTable
676 = HashBasedTable.create();
677
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700678 /** <Virtual Network ID, Virtual Device ID, Virtual Flow Entries>.*/
679 final Table<NetworkId, DeviceId, Set<FlowEntry>> flowEntryTable
680 = HashBasedTable.create();
681
682 /** <Physical Flow Rule, Virtual Network ID>.*/
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900683 final Map<FlowRule, NetworkId> ingressRuleMap = Maps.newHashMap();
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700684
685 /** <Physical Flow Rule, Virtual Virtual Flow Rule>.*/
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900686 final Map<FlowRule, FlowRule> virtualizationMap = Maps.newHashMap();
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700687
688 private Iterable<FlowRule> getFlowRules(NetworkId networkId,
689 DeviceId deviceId) {
690 return flowRuleTable.get(networkId, deviceId);
691 }
692
693 private Iterable<FlowEntry> getFlowEntries(NetworkId networkId,
694 DeviceId deviceId) {
695 return flowEntryTable.get(networkId, deviceId);
696 }
697
698 private void addFlowRule(NetworkId networkId, DeviceId deviceId,
699 FlowRule flowRule) {
700 Set<FlowRule> set = flowRuleTable.get(networkId, deviceId);
701 if (set == null) {
702 set = Sets.newHashSet();
703 flowRuleTable.put(networkId, deviceId, set);
704 }
705 set.add(flowRule);
706 }
707
708 private void removeFlowRule(NetworkId networkId, DeviceId deviceId,
709 FlowRule flowRule) {
710 Set<FlowRule> set = flowRuleTable.get(networkId, deviceId);
711 if (set == null) {
712 return;
713 }
714 set.remove(flowRule);
715 }
716
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900717 private void addOrUpdateFlowEntry(NetworkId networkId, DeviceId deviceId,
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700718 FlowEntry flowEntry) {
719 Set<FlowEntry> set = flowEntryTable.get(networkId, deviceId);
720 if (set == null) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900721 set = Sets.newConcurrentHashSet();
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700722 flowEntryTable.put(networkId, deviceId, set);
723 }
724
725 //Replace old entry with new one
726 set.stream().filter(fe -> fe.exactMatch(flowEntry))
727 .forEach(set::remove);
728 set.add(flowEntry);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700729 }
730
731 private void removeFlowEntry(NetworkId networkId, DeviceId deviceId,
732 FlowEntry flowEntry) {
733 Set<FlowEntry> set = flowEntryTable.get(networkId, deviceId);
734 if (set == null) {
735 return;
736 }
737 set.remove(flowEntry);
738 }
739
740 private void addIngressRule(FlowRule virtualRule, FlowRule physicalRule,
741 NetworkId networkId) {
742 ingressRuleMap.put(physicalRule, networkId);
743 virtualizationMap.put(physicalRule, virtualRule);
744 }
745
746 private FlowRule getVirtualRule(FlowRule physicalRule) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900747 return virtualizationMap.get(physicalRule);
748 }
749
750 private void removeIngressRule(FlowRule physicalRule) {
751 ingressRuleMap.remove(physicalRule);
752 virtualizationMap.remove(physicalRule);
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700753 }
754
755 private Set<FlowRule> getAllPhysicalRule() {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900756 return copyOf(virtualizationMap.keySet());
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700757 }
758
759 private NetworkId getVirtualNetworkId(FlowRule physicalRule) {
760 return ingressRuleMap.get(physicalRule);
761 }
762
763 /**
764 * Test the rule is the ingress rule for virtual rules.
765 *
766 * @param flowRule A flow rule from underlying data plane to be translated
767 * @return True when the rule is for ingress point for a virtual switch
768 */
769 private boolean isVirtualIngressRule(FlowRule flowRule) {
770 return ingressRuleMap.containsKey(flowRule);
771 }
Yoonseon Hanc70b4e02016-10-20 15:24:33 -0700772 }
773
774 private class DefaultInternalRoutingAlgorithm
775 implements InternalRoutingAlgorithm {
776
777 @Override
778 public Path findPath(ConnectPoint src, ConnectPoint dst) {
779 Set<Path> paths =
780 topologyService.getPaths(topologyService.currentTopology(),
781 src.deviceId(),
782 dst.deviceId());
783
784 if (paths.isEmpty()) {
785 return null;
786 }
787
788 //TODO the logic find the best path
789 return (Path) paths.toArray()[0];
790 }
791 }
792}