blob: 4d2eaf705168760ba4f552c58ae51b7933175e22 [file] [log] [blame]
Thomas Vachuskac4ee7372016-02-02 16:10:09 -08001/*
2 * Copyright 2014-2016 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.net.flow.impl;
18
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.LinkedListMultimap;
21import com.google.common.collect.Multimap;
22import com.google.common.collect.Sets;
23import org.onosproject.core.ApplicationId;
24import org.onosproject.mastership.MastershipService;
25import org.onosproject.net.DeviceId;
26import org.onosproject.net.device.DeviceService;
27import org.onosproject.net.flow.CompletedBatchOperation;
28import org.onosproject.net.flow.FlowRule;
29import org.onosproject.net.flow.FlowRuleBatchEntry;
30import org.onosproject.net.flow.FlowRuleBatchOperation;
31import org.onosproject.net.flow.FlowRuleProgrammable;
32import org.onosproject.net.flow.FlowRuleProvider;
33import org.onosproject.net.flow.FlowRuleProviderService;
34import org.onosproject.net.provider.AbstractProvider;
35import org.onosproject.net.provider.ProviderId;
36import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39import java.util.Collection;
40import java.util.Set;
41import java.util.concurrent.Executors;
42import java.util.concurrent.ScheduledExecutorService;
43import java.util.concurrent.ScheduledFuture;
44import java.util.concurrent.TimeUnit;
45
46import static com.google.common.collect.ImmutableSet.copyOf;
47import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.*;
48
49/**
50 * Driver-based flow rule provider.
51 */
52class FlowRuleDriverProvider extends AbstractProvider implements FlowRuleProvider {
53
54 private final Logger log = LoggerFactory.getLogger(getClass());
55
56 // Perhaps to be extracted for better reuse as we deal with other.
57 public static final String SCHEME = "default";
58 public static final String PROVIDER_NAME = "org.onosproject.provider";
59
60 FlowRuleProviderService providerService;
61 private DeviceService deviceService;
62 private MastershipService mastershipService;
63
64 private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
65 private ScheduledFuture<?> poller = null;
66
67 /**
68 * Creates a new fallback flow rule provider.
69 */
70 FlowRuleDriverProvider() {
71 super(new ProviderId(SCHEME, PROVIDER_NAME));
72 }
73
74 /**
75 * Initializes the provider with necessary supporting services.
76 *
77 * @param providerService flow rule provider service
78 * @param deviceService device service
79 * @param mastershipService mastership service
80 * @param pollFrequency flow entry poll frequency
81 */
82 void init(FlowRuleProviderService providerService,
83 DeviceService deviceService, MastershipService mastershipService,
84 int pollFrequency) {
85 this.providerService = providerService;
86 this.deviceService = deviceService;
87 this.mastershipService = mastershipService;
88
89 if (poller != null && !poller.isCancelled()) {
90 poller.cancel(false);
91 }
92
93 poller = executor.scheduleAtFixedRate(this::pollFlowEntries, pollFrequency,
94 pollFrequency, TimeUnit.SECONDS);
95 }
96
97 @Override
98 public void applyFlowRule(FlowRule... flowRules) {
99 rulesByDevice(flowRules).asMap().forEach(this::applyFlowRules);
100 }
101
102 @Override
103 public void removeFlowRule(FlowRule... flowRules) {
104 rulesByDevice(flowRules).asMap().forEach(this::removeFlowRules);
105 }
106
107 @Override
108 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
109 removeFlowRule(flowRules);
110 }
111
112 @Override
113 public void executeBatch(FlowRuleBatchOperation batch) {
114 ImmutableList.Builder<FlowRule> toAdd = ImmutableList.builder();
115 ImmutableList.Builder<FlowRule> toRemove = ImmutableList.builder();
116 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
117 if (fbe.operator() == ADD || fbe.operator() == MODIFY) {
118 toAdd.add(fbe.target());
119 } else if (fbe.operator() == REMOVE) {
120 toRemove.add(fbe.target());
121 }
122 }
123
124 ImmutableList<FlowRule> rulesToAdd = toAdd.build();
125 ImmutableList<FlowRule> rulesToRemove = toRemove.build();
126
127 Collection<FlowRule> added = applyFlowRules(batch.deviceId(), rulesToAdd);
128 Collection<FlowRule> removed = removeFlowRules(batch.deviceId(), rulesToRemove);
129
130 Set<FlowRule> failedRules = Sets.union(Sets.difference(copyOf(rulesToAdd), copyOf(added)),
131 Sets.difference(copyOf(rulesToRemove), copyOf(removed)));
132 CompletedBatchOperation status =
133 new CompletedBatchOperation(failedRules.isEmpty(), failedRules, batch.deviceId());
134 providerService.batchOperationCompleted(batch.id(), status);
135 }
136
137 private Multimap<DeviceId, FlowRule> rulesByDevice(FlowRule[] flowRules) {
138 // Sort the flow rules by device id
139 Multimap<DeviceId, FlowRule> rulesByDevice = LinkedListMultimap.create();
140 for (FlowRule rule : flowRules) {
141 rulesByDevice.put(rule.deviceId(), rule);
142 }
143 return rulesByDevice;
144 }
145
146 private Collection<FlowRule> applyFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
147 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
148 return programmer != null ? programmer.applyFlowRules(flowRules) : ImmutableList.of();
149 }
150
151 private Collection<FlowRule> removeFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
152 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
153 return programmer != null ? programmer.removeFlowRules(flowRules) : ImmutableList.of();
154 }
155
156 private FlowRuleProgrammable getFlowRuleProgrammable(DeviceId deviceId) {
157 FlowRuleProgrammable programmable = deviceService.getDevice(deviceId).as(FlowRuleProgrammable.class);
158 if (programmable == null) {
159 log.warn("Device {} is not flow rule programmable");
160 }
161 return programmable;
162 }
163
164
165 private void pollFlowEntries() {
166 deviceService.getAvailableDevices().forEach(device -> {
167 if (mastershipService.isLocalMaster(device.id()) && device.is(FlowRuleProgrammable.class)) {
168 providerService.pushFlowMetrics(device.id(),
169 device.as(FlowRuleProgrammable.class).getFlowEntries());
170 }
171 });
172 }
173
174}