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