blob: b47012d90d2798ee59e42941e64f33c5bd1fd8cf [file] [log] [blame]
alshabibaebe7752015-04-07 17:45:42 -07001/*
2 * Copyright 2015 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 */
16package org.onosproject.driver.pipeline;
17
alshabib2a441c62015-04-13 18:39:38 -070018import com.google.common.cache.Cache;
19import com.google.common.cache.CacheBuilder;
20import com.google.common.cache.RemovalCause;
21import com.google.common.cache.RemovalNotification;
Saurav Das3d038262015-04-23 12:36:58 -070022
alshabibaebe7752015-04-07 17:45:42 -070023import org.onlab.osgi.ServiceDirectory;
24import org.onlab.packet.Ethernet;
Saurav Das3d038262015-04-23 12:36:58 -070025import org.onlab.packet.IPv4;
alshabibaebe7752015-04-07 17:45:42 -070026import org.onlab.packet.MacAddress;
27import org.onlab.packet.VlanId;
alshabib2a441c62015-04-13 18:39:38 -070028import org.onlab.util.KryoNamespace;
alshabibaebe7752015-04-07 17:45:42 -070029import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
31import org.onosproject.net.DeviceId;
alshabib2a441c62015-04-13 18:39:38 -070032import org.onosproject.net.behaviour.NextGroup;
alshabibaebe7752015-04-07 17:45:42 -070033import org.onosproject.net.behaviour.Pipeliner;
Thomas Vachuskaca88bb72015-04-08 19:38:02 -070034import org.onosproject.net.behaviour.PipelinerContext;
Thomas Vachuskafacc3f52015-04-10 08:58:36 -070035import org.onosproject.net.driver.AbstractHandlerBehaviour;
alshabibaebe7752015-04-07 17:45:42 -070036import org.onosproject.net.flow.DefaultFlowRule;
37import org.onosproject.net.flow.DefaultTrafficSelector;
38import org.onosproject.net.flow.DefaultTrafficTreatment;
39import org.onosproject.net.flow.FlowRule;
40import org.onosproject.net.flow.FlowRuleOperations;
41import org.onosproject.net.flow.FlowRuleOperationsContext;
42import org.onosproject.net.flow.FlowRuleService;
43import org.onosproject.net.flow.TrafficSelector;
44import org.onosproject.net.flow.TrafficTreatment;
alshabib910aff12015-04-09 16:55:57 -070045import org.onosproject.net.flow.criteria.Criteria;
46import org.onosproject.net.flow.criteria.Criterion;
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -070047import org.onosproject.net.flow.criteria.EthCriterion;
48import org.onosproject.net.flow.criteria.EthTypeCriterion;
49import org.onosproject.net.flow.criteria.IPCriterion;
50import org.onosproject.net.flow.criteria.IPProtocolCriterion;
51import org.onosproject.net.flow.criteria.PortCriterion;
52import org.onosproject.net.flow.criteria.VlanIdCriterion;
alshabibaebe7752015-04-07 17:45:42 -070053import org.onosproject.net.flowobjective.FilteringObjective;
alshabib2a441c62015-04-13 18:39:38 -070054import org.onosproject.net.flowobjective.FlowObjectiveStore;
alshabibaebe7752015-04-07 17:45:42 -070055import org.onosproject.net.flowobjective.ForwardingObjective;
56import org.onosproject.net.flowobjective.NextObjective;
alshabib910aff12015-04-09 16:55:57 -070057import org.onosproject.net.flowobjective.Objective;
alshabib2a441c62015-04-13 18:39:38 -070058import org.onosproject.net.flowobjective.ObjectiveError;
59import org.onosproject.net.group.DefaultGroupBucket;
60import org.onosproject.net.group.DefaultGroupDescription;
61import org.onosproject.net.group.DefaultGroupKey;
62import org.onosproject.net.group.Group;
63import org.onosproject.net.group.GroupBucket;
64import org.onosproject.net.group.GroupBuckets;
65import org.onosproject.net.group.GroupDescription;
66import org.onosproject.net.group.GroupEvent;
67import org.onosproject.net.group.GroupKey;
68import org.onosproject.net.group.GroupListener;
69import org.onosproject.net.group.GroupService;
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -050070import org.onosproject.net.meter.MeterService;
alshabibaebe7752015-04-07 17:45:42 -070071import org.slf4j.Logger;
72
73import java.util.Collection;
alshabib2a441c62015-04-13 18:39:38 -070074import java.util.Collections;
Saurav Das24431192016-03-07 19:13:00 -080075import java.util.List;
Sho SHIMIZU45906042016-01-13 23:05:54 -080076import java.util.Objects;
alshabib2a441c62015-04-13 18:39:38 -070077import java.util.Set;
78import java.util.concurrent.Executors;
79import java.util.concurrent.ScheduledExecutorService;
80import java.util.concurrent.TimeUnit;
81import java.util.stream.Collectors;
alshabibaebe7752015-04-07 17:45:42 -070082
alshabib2a441c62015-04-13 18:39:38 -070083import static org.onlab.util.Tools.groupedThreads;
alshabibaebe7752015-04-07 17:45:42 -070084import static org.slf4j.LoggerFactory.getLogger;
85
86/**
alshabib2a441c62015-04-13 18:39:38 -070087 * OpenvSwitch emulation of the Corsa pipeline handler.
alshabibaebe7752015-04-07 17:45:42 -070088 */
Thomas Vachuskafacc3f52015-04-10 08:58:36 -070089public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabibaebe7752015-04-07 17:45:42 -070090
Saurav Das3ea46622015-04-22 14:01:34 -070091 protected static final int MAC_TABLE = 0;
alshabibd17abc22015-04-21 18:26:35 -070092 protected static final int VLAN_MPLS_TABLE = 1;
93 protected static final int VLAN_TABLE = 2;
94 //protected static final int MPLS_TABLE = 3;
95 protected static final int ETHER_TABLE = 4;
96 protected static final int COS_MAP_TABLE = 5;
97 protected static final int FIB_TABLE = 6;
98 protected static final int LOCAL_TABLE = 9;
99
100
Saurav Dasd8b97002015-05-14 23:42:49 -0700101 protected static final int CONTROLLER_PRIORITY = 255;
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500102 protected static final int DROP_PRIORITY = 0;
103 protected static final int HIGHEST_PRIORITY = 0xffff;
alshabibaebe7752015-04-07 17:45:42 -0700104
105 private final Logger log = getLogger(getClass());
106
107 private ServiceDirectory serviceDirectory;
Saurav Dasd8b97002015-05-14 23:42:49 -0700108 protected FlowRuleService flowRuleService;
alshabibaebe7752015-04-07 17:45:42 -0700109 private CoreService coreService;
alshabib2a441c62015-04-13 18:39:38 -0700110 private GroupService groupService;
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500111 protected MeterService meterService;
alshabib2a441c62015-04-13 18:39:38 -0700112 private FlowObjectiveStore flowObjectiveStore;
Saurav Dasd8b97002015-05-14 23:42:49 -0700113 protected DeviceId deviceId;
114 protected ApplicationId appId;
alshabibaebe7752015-04-07 17:45:42 -0700115
alshabib2a441c62015-04-13 18:39:38 -0700116 private KryoNamespace appKryo = new KryoNamespace.Builder()
117 .register(GroupKey.class)
118 .register(DefaultGroupKey.class)
119 .register(CorsaGroup.class)
120 .register(byte[].class)
121 .build();
122
123 private Cache<GroupKey, NextObjective> pendingGroups;
124
125 private ScheduledExecutorService groupChecker =
126 Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
127 "ovs-corsa-%d"));
128
alshabibaebe7752015-04-07 17:45:42 -0700129 @Override
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700130 public void init(DeviceId deviceId, PipelinerContext context) {
131 this.serviceDirectory = context.directory();
alshabibaebe7752015-04-07 17:45:42 -0700132 this.deviceId = deviceId;
133
alshabib2a441c62015-04-13 18:39:38 -0700134 pendingGroups = CacheBuilder.newBuilder()
135 .expireAfterWrite(20, TimeUnit.SECONDS)
136 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
137 if (notification.getCause() == RemovalCause.EXPIRED) {
138 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
139 }
140 }).build();
141
142 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
alshabibaebe7752015-04-07 17:45:42 -0700143
144 coreService = serviceDirectory.get(CoreService.class);
145 flowRuleService = serviceDirectory.get(FlowRuleService.class);
alshabib2a441c62015-04-13 18:39:38 -0700146 groupService = serviceDirectory.get(GroupService.class);
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500147 meterService = serviceDirectory.get(MeterService.class);
alshabib2a441c62015-04-13 18:39:38 -0700148 flowObjectiveStore = context.store();
149
150 groupService.addListener(new InnerGroupListener());
alshabibaebe7752015-04-07 17:45:42 -0700151
152 appId = coreService.registerApplication(
153 "org.onosproject.driver.OVSCorsaPipeline");
154
Saurav Das100e3b82015-04-30 11:12:10 -0700155 initializePipeline();
alshabibaebe7752015-04-07 17:45:42 -0700156 }
157
158 @Override
alshabib2a441c62015-04-13 18:39:38 -0700159 public void filter(FilteringObjective filteringObjective) {
160 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
161 processFilter(filteringObjective,
162 filteringObjective.op() == Objective.Operation.ADD,
163 filteringObjective.appId());
164 } else {
165 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
166 }
167 }
alshabib910aff12015-04-09 16:55:57 -0700168
alshabib2a441c62015-04-13 18:39:38 -0700169 @Override
170 public void forward(ForwardingObjective fwd) {
171 Collection<FlowRule> rules;
172 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
173
174 rules = processForward(fwd);
175 switch (fwd.op()) {
176 case ADD:
177 rules.stream()
Sho SHIMIZU45906042016-01-13 23:05:54 -0800178 .filter(Objects::nonNull)
alshabib2a441c62015-04-13 18:39:38 -0700179 .forEach(flowBuilder::add);
180 break;
181 case REMOVE:
182 rules.stream()
Sho SHIMIZU45906042016-01-13 23:05:54 -0800183 .filter(Objects::nonNull)
alshabib2a441c62015-04-13 18:39:38 -0700184 .forEach(flowBuilder::remove);
185 break;
186 default:
187 fail(fwd, ObjectiveError.UNKNOWN);
188 log.warn("Unknown forwarding type {}", fwd.op());
189 }
190
191
192 flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
193 @Override
194 public void onSuccess(FlowRuleOperations ops) {
195 pass(fwd);
196 }
197
198 @Override
199 public void onError(FlowRuleOperations ops) {
200 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
201 }
202 }));
alshabib910aff12015-04-09 16:55:57 -0700203
204 }
205
alshabib2a441c62015-04-13 18:39:38 -0700206 @Override
207 public void next(NextObjective nextObjective) {
208 switch (nextObjective.type()) {
209 case SIMPLE:
210 Collection<TrafficTreatment> treatments = nextObjective.next();
211 if (treatments.size() == 1) {
212 TrafficTreatment treatment = treatments.iterator().next();
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500213 treatment = processNextTreatment(treatment);
alshabib2a441c62015-04-13 18:39:38 -0700214 GroupBucket bucket =
215 DefaultGroupBucket.createIndirectGroupBucket(treatment);
216 final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
217 GroupDescription groupDescription
218 = new DefaultGroupDescription(deviceId,
219 GroupDescription.Type.INDIRECT,
220 new GroupBuckets(Collections
221 .singletonList(bucket)),
222 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700223 null, // let group service determine group id
alshabib2a441c62015-04-13 18:39:38 -0700224 nextObjective.appId());
225 groupService.addGroup(groupDescription);
226 pendingGroups.put(key, nextObjective);
227 }
228 break;
229 case HASHED:
230 case BROADCAST:
231 case FAILOVER:
232 fail(nextObjective, ObjectiveError.UNSUPPORTED);
233 log.warn("Unsupported next objective type {}", nextObjective.type());
234 break;
235 default:
236 fail(nextObjective, ObjectiveError.UNKNOWN);
237 log.warn("Unknown next objective type {}", nextObjective.type());
238 }
239
240 }
241
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500242 /* Hook for altering the NextObjective treatment */
243 protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) {
244 return treatment; /* Keep treatment as is for OVSCorsaPipeline */
245 }
246
alshabib2a441c62015-04-13 18:39:38 -0700247 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
248 switch (fwd.flag()) {
249 case SPECIFIC:
250 return processSpecific(fwd);
251 case VERSATILE:
252 return processVersatile(fwd);
253 default:
254 fail(fwd, ObjectiveError.UNKNOWN);
255 log.warn("Unknown forwarding flag {}", fwd.flag());
256 }
257 return Collections.emptySet();
258 }
259
260 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
Saurav Das3d038262015-04-23 12:36:58 -0700261 log.debug("Processing versatile forwarding objective");
262 TrafficSelector selector = fwd.selector();
263
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700264 EthTypeCriterion ethType =
265 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Saurav Das3d038262015-04-23 12:36:58 -0700266 if (ethType == null) {
267 log.error("Versatile forwarding objective must include ethType");
268 fail(fwd, ObjectiveError.UNKNOWN);
269 return Collections.emptySet();
270 }
alshabibcaf1ca22015-06-25 15:18:16 -0700271 if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) {
Saurav Das3d038262015-04-23 12:36:58 -0700272 log.warn("Driver automatically handles ARP packets by punting to controller "
273 + " from ETHER table");
274 pass(fwd);
275 return Collections.emptySet();
alshabibcaf1ca22015-06-25 15:18:16 -0700276 } else if (ethType.ethType().toShort() == Ethernet.TYPE_LLDP ||
277 ethType.ethType().toShort() == Ethernet.TYPE_BSN) {
Saurav Das3d038262015-04-23 12:36:58 -0700278 log.warn("Driver currently does not currently handle LLDP packets");
279 fail(fwd, ObjectiveError.UNSUPPORTED);
280 return Collections.emptySet();
alshabibcaf1ca22015-06-25 15:18:16 -0700281 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700282 IPCriterion ipSrc = (IPCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700283 .getCriterion(Criterion.Type.IPV4_SRC);
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700284 IPCriterion ipDst = (IPCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700285 .getCriterion(Criterion.Type.IPV4_DST);
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700286 IPProtocolCriterion ipProto = (IPProtocolCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700287 .getCriterion(Criterion.Type.IP_PROTO);
288 if (ipSrc != null) {
Saurav Dasbd7f7422015-04-23 16:31:47 -0700289 log.warn("Driver does not currently handle matching Src IP");
Saurav Das3d038262015-04-23 12:36:58 -0700290 fail(fwd, ObjectiveError.UNSUPPORTED);
291 return Collections.emptySet();
292 }
293 if (ipDst != null) {
294 log.error("Driver handles Dst IP matching as specific forwarding "
295 + "objective, not versatile");
296 fail(fwd, ObjectiveError.UNSUPPORTED);
297 return Collections.emptySet();
298 }
299 if (ipProto != null && ipProto.protocol() == IPv4.PROTOCOL_TCP) {
300 log.warn("Driver automatically punts all packets reaching the "
301 + "LOCAL table to the controller");
302 pass(fwd);
303 return Collections.emptySet();
304 }
305 }
306
307 log.warn("Driver does not support given versatile forwarding objective");
alshabib2a441c62015-04-13 18:39:38 -0700308 fail(fwd, ObjectiveError.UNSUPPORTED);
309 return Collections.emptySet();
310 }
311
312 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
Saurav Das3d038262015-04-23 12:36:58 -0700313 log.debug("Processing specific forwarding objective");
alshabib2a441c62015-04-13 18:39:38 -0700314 TrafficSelector selector = fwd.selector();
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500315
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700316 EthTypeCriterion ethType =
317 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500318 if (ethType != null) {
319 short et = ethType.ethType().toShort();
320 if (et == Ethernet.TYPE_IPV4) {
321 return processSpecificRoute(fwd);
322 } else if (et == Ethernet.TYPE_VLAN) {
323 /* The ForwardingObjective must specify VLAN ethtype in order to use the Transit Circuit */
324 return processSpecificSwitch(fwd);
325 }
alshabib2a441c62015-04-13 18:39:38 -0700326 }
327
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500328 fail(fwd, ObjectiveError.UNSUPPORTED);
329 return Collections.emptySet();
330 }
331
332 private Collection<FlowRule> processSpecificRoute(ForwardingObjective fwd) {
alshabib2a441c62015-04-13 18:39:38 -0700333 TrafficSelector filteredSelector =
334 DefaultTrafficSelector.builder()
335 .matchEthType(Ethernet.TYPE_IPV4)
336 .matchIPDst(
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500337 ((IPCriterion) fwd.selector().getCriterion(Criterion.Type.IPV4_DST)).ip())
alshabib2a441c62015-04-13 18:39:38 -0700338 .build();
339
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500340 TrafficTreatment.Builder tb = processSpecificRoutingTreatment();
alshabib2a441c62015-04-13 18:39:38 -0700341
sanghodde53d12015-04-30 10:34:41 -0700342 if (fwd.nextId() != null) {
343 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
344 GroupKey key = appKryo.deserialize(next.data());
345 Group group = groupService.getGroup(deviceId, key);
346 if (group == null) {
347 log.warn("The group left!");
348 fail(fwd, ObjectiveError.GROUPMISSING);
349 return Collections.emptySet();
350 }
351 tb.group(group.id());
alshabib2a441c62015-04-13 18:39:38 -0700352 }
353
alshabibd17abc22015-04-21 18:26:35 -0700354 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
355 .fromApp(fwd.appId())
356 .withPriority(fwd.priority())
357 .forDevice(deviceId)
358 .withSelector(filteredSelector)
sanghodde53d12015-04-30 10:34:41 -0700359 .withTreatment(tb.build());
alshabibd17abc22015-04-21 18:26:35 -0700360
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500361 ruleBuilder = processSpecificRoutingRule(ruleBuilder);
362
alshabibd17abc22015-04-21 18:26:35 -0700363 if (fwd.permanent()) {
364 ruleBuilder.makePermanent();
365 } else {
366 ruleBuilder.makeTemporary(fwd.timeout());
367 }
368
alshabibd17abc22015-04-21 18:26:35 -0700369 return Collections.singletonList(ruleBuilder.build());
alshabib2a441c62015-04-13 18:39:38 -0700370 }
371
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500372 /* Hook for modifying Route traffic treatment */
373 protected TrafficTreatment.Builder processSpecificRoutingTreatment() {
374 return DefaultTrafficTreatment.builder();
375 }
376
377 /* Hook for modifying Route flow rule */
378 protected FlowRule.Builder processSpecificRoutingRule(FlowRule.Builder rb) {
379 return rb.forTable(FIB_TABLE);
380 }
381
382 protected Collection<FlowRule> processSpecificSwitch(ForwardingObjective fwd) {
383 /* Not supported by until CorsaPipelineV3 */
384 log.warn("Vlan switching not supported in ovs-corsa driver");
385 fail(fwd, ObjectiveError.UNSUPPORTED);
386 return Collections.emptySet();
387 }
388
389 protected void processFilter(FilteringObjective filt, boolean install,
alshabib910aff12015-04-09 16:55:57 -0700390 ApplicationId applicationId) {
Saurav Dascfd63d22015-04-13 16:08:24 -0700391 // This driver only processes filtering criteria defined with switch
392 // ports as the key
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700393 PortCriterion p;
Saurav Dascfd63d22015-04-13 16:08:24 -0700394 if (!filt.key().equals(Criteria.dummy()) &&
395 filt.key().type() == Criterion.Type.IN_PORT) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700396 p = (PortCriterion) filt.key();
Saurav Dascfd63d22015-04-13 16:08:24 -0700397 } else {
398 log.warn("No key defined in filtering objective from app: {}. Not"
399 + "processing filtering objective", applicationId);
alshabib2a441c62015-04-13 18:39:38 -0700400 fail(filt, ObjectiveError.UNKNOWN);
401 return;
alshabib910aff12015-04-09 16:55:57 -0700402 }
Saurav Dascfd63d22015-04-13 16:08:24 -0700403 // convert filtering conditions for switch-intfs into flowrules
404 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
405 for (Criterion c : filt.conditions()) {
406 if (c.type() == Criterion.Type.ETH_DST) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700407 EthCriterion e = (EthCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700408 log.debug("adding rule for MAC: {}", e.mac());
409 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
410 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
411 selector.matchEthDst(e.mac());
alshabibd17abc22015-04-21 18:26:35 -0700412 treatment.transition(VLAN_MPLS_TABLE);
413 FlowRule rule = DefaultFlowRule.builder()
414 .forDevice(deviceId)
415 .withSelector(selector.build())
416 .withTreatment(treatment.build())
417 .withPriority(CONTROLLER_PRIORITY)
418 .fromApp(applicationId)
419 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700420 .forTable(MAC_TABLE).build();
Saurav Dascfd63d22015-04-13 16:08:24 -0700421 ops = install ? ops.add(rule) : ops.remove(rule);
422 } else if (c.type() == Criterion.Type.VLAN_VID) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700423 VlanIdCriterion v = (VlanIdCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700424 log.debug("adding rule for VLAN: {}", v.vlanId());
425 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
426 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
427 selector.matchVlanId(v.vlanId());
428 selector.matchInPort(p.port());
alshabibd17abc22015-04-21 18:26:35 -0700429 treatment.transition(ETHER_TABLE);
Saurav Dascfd63d22015-04-13 16:08:24 -0700430 treatment.deferred().popVlan();
alshabibd17abc22015-04-21 18:26:35 -0700431 FlowRule rule = DefaultFlowRule.builder()
432 .forDevice(deviceId)
433 .withSelector(selector.build())
434 .withTreatment(treatment.build())
435 .withPriority(CONTROLLER_PRIORITY)
436 .fromApp(applicationId)
437 .makePermanent()
438 .forTable(VLAN_TABLE).build();
Saurav Dascfd63d22015-04-13 16:08:24 -0700439 ops = install ? ops.add(rule) : ops.remove(rule);
440 } else if (c.type() == Criterion.Type.IPV4_DST) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700441 IPCriterion ip = (IPCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700442 log.debug("adding rule for IP: {}", ip.ip());
443 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
444 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
445 selector.matchEthType(Ethernet.TYPE_IPV4);
446 selector.matchIPDst(ip.ip());
alshabibd17abc22015-04-21 18:26:35 -0700447 treatment.transition(LOCAL_TABLE);
448 FlowRule rule = DefaultFlowRule.builder()
449 .forDevice(deviceId)
450 .withSelector(selector.build())
451 .withTreatment(treatment.build())
452 .withPriority(HIGHEST_PRIORITY)
453 .fromApp(applicationId)
454 .makePermanent()
455 .forTable(FIB_TABLE).build();
456
Saurav Dascfd63d22015-04-13 16:08:24 -0700457 ops = install ? ops.add(rule) : ops.remove(rule);
458 } else {
459 log.warn("Driver does not currently process filtering condition"
460 + " of type: {}", c.type());
alshabib2a441c62015-04-13 18:39:38 -0700461 fail(filt, ObjectiveError.UNSUPPORTED);
Saurav Dascfd63d22015-04-13 16:08:24 -0700462 }
463 }
464 // apply filtering flow rules
465 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
466 @Override
467 public void onSuccess(FlowRuleOperations ops) {
alshabib2a441c62015-04-13 18:39:38 -0700468 pass(filt);
Saurav Das3ea46622015-04-22 14:01:34 -0700469 log.info("Applied filtering rules");
Saurav Dascfd63d22015-04-13 16:08:24 -0700470 }
471
472 @Override
473 public void onError(FlowRuleOperations ops) {
alshabib2a441c62015-04-13 18:39:38 -0700474 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Saurav Das3ea46622015-04-22 14:01:34 -0700475 log.info("Failed to apply filtering rules");
Saurav Dascfd63d22015-04-13 16:08:24 -0700476 }
477 }));
alshabibaebe7752015-04-07 17:45:42 -0700478 }
479
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500480 protected void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800481 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibaebe7752015-04-07 17:45:42 -0700482 }
483
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500484 protected void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800485 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibaebe7752015-04-07 17:45:42 -0700486 }
487
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500488 protected void initializePipeline() {
Saurav Das3ea46622015-04-22 14:01:34 -0700489 processMacTable(true);
490 processVlanMplsTable(true);
491 processVlanTable(true);
492 processEtherTable(true);
493 processCosTable(true);
494 processFibTable(true);
495 processLocalTable(true);
alshabibaebe7752015-04-07 17:45:42 -0700496 }
497
Saurav Das3ea46622015-04-22 14:01:34 -0700498 private void processMacTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700499 TrafficSelector.Builder selector;
500 TrafficTreatment.Builder treatment;
501
502 // Bcast rule
503 selector = DefaultTrafficSelector.builder();
504 treatment = DefaultTrafficTreatment.builder();
505
506 selector.matchEthDst(MacAddress.BROADCAST);
alshabibd17abc22015-04-21 18:26:35 -0700507 treatment.transition(VLAN_MPLS_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700508
alshabibd17abc22015-04-21 18:26:35 -0700509 FlowRule rule = DefaultFlowRule.builder()
510 .forDevice(deviceId)
511 .withSelector(selector.build())
512 .withTreatment(treatment.build())
513 .withPriority(CONTROLLER_PRIORITY)
514 .fromApp(appId)
515 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700516 .forTable(MAC_TABLE).build();
alshabibd17abc22015-04-21 18:26:35 -0700517
alshabibaebe7752015-04-07 17:45:42 -0700518
519 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
520
521 ops = install ? ops.add(rule) : ops.remove(rule);
522
523
alshabibaebe7752015-04-07 17:45:42 -0700524 //Drop rule
525 selector = DefaultTrafficSelector.builder();
526 treatment = DefaultTrafficTreatment.builder();
527
528 treatment.drop();
529
alshabibd17abc22015-04-21 18:26:35 -0700530 rule = DefaultFlowRule.builder()
531 .forDevice(deviceId)
532 .withSelector(selector.build())
533 .withTreatment(treatment.build())
534 .withPriority(DROP_PRIORITY)
535 .fromApp(appId)
536 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700537 .forTable(MAC_TABLE).build();
alshabibd17abc22015-04-21 18:26:35 -0700538
alshabibaebe7752015-04-07 17:45:42 -0700539
540 ops = install ? ops.add(rule) : ops.remove(rule);
541
542 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
543 @Override
544 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700545 log.info("Provisioned mac table");
alshabibaebe7752015-04-07 17:45:42 -0700546 }
547
548 @Override
549 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700550 log.info("Failed to provision mac table");
alshabibaebe7752015-04-07 17:45:42 -0700551 }
552 }));
553
554 }
555
Saurav Dasd8b97002015-05-14 23:42:49 -0700556 protected void processVlanMplsTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700557 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
558 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
559 .builder();
560 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
561 FlowRule rule;
562
563 selector.matchVlanId(VlanId.ANY);
alshabibd17abc22015-04-21 18:26:35 -0700564 treatment.transition(VLAN_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700565
alshabibd17abc22015-04-21 18:26:35 -0700566 rule = DefaultFlowRule.builder()
567 .forDevice(deviceId)
568 .withSelector(selector.build())
569 .withTreatment(treatment.build())
570 .withPriority(CONTROLLER_PRIORITY)
571 .fromApp(appId)
572 .makePermanent()
573 .forTable(VLAN_MPLS_TABLE).build();
574
alshabibaebe7752015-04-07 17:45:42 -0700575
576 ops = install ? ops.add(rule) : ops.remove(rule);
577
578 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
579 @Override
580 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700581 log.info("Provisioned vlan/mpls table");
alshabibaebe7752015-04-07 17:45:42 -0700582 }
583
584 @Override
585 public void onError(FlowRuleOperations ops) {
586 log.info(
Saurav Das3ea46622015-04-22 14:01:34 -0700587 "Failed to provision vlan/mpls table");
alshabibaebe7752015-04-07 17:45:42 -0700588 }
589 }));
590
591 }
592
Saurav Das3ea46622015-04-22 14:01:34 -0700593 private void processVlanTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700594 TrafficSelector.Builder selector;
595 TrafficTreatment.Builder treatment;
596 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
597 FlowRule rule;
598
599
alshabibaebe7752015-04-07 17:45:42 -0700600 //Drop rule
601 selector = DefaultTrafficSelector.builder();
602 treatment = DefaultTrafficTreatment.builder();
603
604 treatment.drop();
605
alshabibd17abc22015-04-21 18:26:35 -0700606 rule = DefaultFlowRule.builder()
607 .forDevice(deviceId)
608 .withSelector(selector.build())
609 .withTreatment(treatment.build())
610 .withPriority(DROP_PRIORITY)
611 .fromApp(appId)
612 .makePermanent()
613 .forTable(VLAN_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700614
615 ops = install ? ops.add(rule) : ops.remove(rule);
616
617 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
618 @Override
619 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700620 log.info("Provisioned vlan table");
alshabibaebe7752015-04-07 17:45:42 -0700621 }
622
623 @Override
624 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700625 log.info("Failed to provision vlan table");
alshabibaebe7752015-04-07 17:45:42 -0700626 }
627 }));
628 }
629
Saurav Das3ea46622015-04-22 14:01:34 -0700630 private void processEtherTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700631 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
632 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
633 .builder();
634 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
635 FlowRule rule;
636
637 selector.matchEthType(Ethernet.TYPE_ARP);
638 treatment.punt();
639
alshabibd17abc22015-04-21 18:26:35 -0700640 rule = DefaultFlowRule.builder()
641 .forDevice(deviceId)
642 .withSelector(selector.build())
643 .withTreatment(treatment.build())
644 .withPriority(CONTROLLER_PRIORITY)
645 .fromApp(appId)
646 .makePermanent()
647 .forTable(ETHER_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700648
649 ops = install ? ops.add(rule) : ops.remove(rule);
650
651 selector = DefaultTrafficSelector.builder();
652 treatment = DefaultTrafficTreatment.builder();
653
654 selector.matchEthType(Ethernet.TYPE_IPV4);
alshabibd17abc22015-04-21 18:26:35 -0700655 treatment.transition(COS_MAP_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700656
alshabibd17abc22015-04-21 18:26:35 -0700657 rule = DefaultFlowRule.builder()
658 .forDevice(deviceId)
659 .withPriority(CONTROLLER_PRIORITY)
660 .withSelector(selector.build())
661 .withTreatment(treatment.build())
662 .fromApp(appId)
663 .makePermanent()
664 .forTable(ETHER_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700665
666 ops = install ? ops.add(rule) : ops.remove(rule);
667
668 //Drop rule
669 selector = DefaultTrafficSelector.builder();
670 treatment = DefaultTrafficTreatment.builder();
671
672 treatment.drop();
673
alshabibd17abc22015-04-21 18:26:35 -0700674 rule = DefaultFlowRule.builder()
675 .forDevice(deviceId)
676 .withSelector(selector.build())
677 .withTreatment(treatment.build())
678 .withPriority(DROP_PRIORITY)
679 .fromApp(appId)
680 .makePermanent()
681 .forTable(ETHER_TABLE).build();
682
alshabibaebe7752015-04-07 17:45:42 -0700683
684 ops = install ? ops.add(rule) : ops.remove(rule);
685
686 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
687 @Override
688 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700689 log.info("Provisioned ether table");
alshabibaebe7752015-04-07 17:45:42 -0700690 }
691
692 @Override
693 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700694 log.info("Failed to provision ether table");
alshabibaebe7752015-04-07 17:45:42 -0700695 }
696 }));
697
698 }
699
Saurav Das3ea46622015-04-22 14:01:34 -0700700 private void processCosTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700701 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
702 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
703 .builder();
704 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
705 FlowRule rule;
706
alshabibd17abc22015-04-21 18:26:35 -0700707 treatment.transition(FIB_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700708
alshabibd17abc22015-04-21 18:26:35 -0700709 rule = DefaultFlowRule.builder()
710 .forDevice(deviceId)
711 .withSelector(selector.build())
712 .withTreatment(treatment.build())
713 .withPriority(DROP_PRIORITY)
714 .fromApp(appId)
715 .makePermanent()
716 .forTable(COS_MAP_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700717
718 ops = install ? ops.add(rule) : ops.remove(rule);
719
720 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
721 @Override
722 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700723 log.info("Provisioned cos table");
alshabibaebe7752015-04-07 17:45:42 -0700724 }
725
726 @Override
727 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700728 log.info("Failed to provision cos table");
alshabibaebe7752015-04-07 17:45:42 -0700729 }
730 }));
731
732 }
733
Saurav Das3ea46622015-04-22 14:01:34 -0700734 private void processFibTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700735 TrafficSelector.Builder selector;
736 TrafficTreatment.Builder treatment;
737 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
738 FlowRule rule;
739
740 //Drop rule
741 selector = DefaultTrafficSelector.builder();
742 treatment = DefaultTrafficTreatment.builder();
743
744 treatment.drop();
745
alshabibd17abc22015-04-21 18:26:35 -0700746 rule = DefaultFlowRule.builder()
747 .forDevice(deviceId)
748 .withSelector(selector.build())
749 .withTreatment(treatment.build())
750 .withPriority(DROP_PRIORITY)
751 .fromApp(appId)
752 .makePermanent()
753 .forTable(FIB_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700754
755 ops = install ? ops.add(rule) : ops.remove(rule);
756
757 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
758 @Override
759 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700760 log.info("Provisioned FIB table");
alshabibaebe7752015-04-07 17:45:42 -0700761 }
762
763 @Override
764 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700765 log.info("Failed to provision FIB table");
alshabibaebe7752015-04-07 17:45:42 -0700766 }
767 }));
768 }
769
Saurav Das3ea46622015-04-22 14:01:34 -0700770 private void processLocalTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700771 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
772 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
773 .builder();
774 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
775 FlowRule rule;
776
777 treatment.punt();
778
alshabibd17abc22015-04-21 18:26:35 -0700779 rule = DefaultFlowRule.builder()
780 .forDevice(deviceId)
781 .withSelector(selector.build())
782 .withTreatment(treatment.build())
783 .withPriority(CONTROLLER_PRIORITY)
784 .fromApp(appId)
785 .makePermanent()
786 .forTable(LOCAL_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700787
788 ops = install ? ops.add(rule) : ops.remove(rule);
789
790 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
791 @Override
792 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700793 log.info("Provisioned Local table");
alshabibaebe7752015-04-07 17:45:42 -0700794 }
795
796 @Override
797 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700798 log.info("Failed to provision Local table");
alshabibaebe7752015-04-07 17:45:42 -0700799 }
800 }));
801 }
802
alshabib2a441c62015-04-13 18:39:38 -0700803 private class InnerGroupListener implements GroupListener {
804 @Override
805 public void event(GroupEvent event) {
806 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
807 GroupKey key = event.subject().appCookie();
808
809 NextObjective obj = pendingGroups.getIfPresent(key);
810 if (obj != null) {
811 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
812 pass(obj);
813 pendingGroups.invalidate(key);
814 }
815 }
816 }
817 }
818
819
820 private class GroupChecker implements Runnable {
821
822 @Override
823 public void run() {
824 Set<GroupKey> keys = pendingGroups.asMap().keySet().stream()
825 .filter(key -> groupService.getGroup(deviceId, key) != null)
826 .collect(Collectors.toSet());
827
828 keys.stream().forEach(key -> {
829 NextObjective obj = pendingGroups.getIfPresent(key);
830 if (obj == null) {
831 return;
832 }
833 pass(obj);
834 pendingGroups.invalidate(key);
Saurav Dasbd7f7422015-04-23 16:31:47 -0700835 log.info("Heard back from group service for group {}. "
836 + "Applying pending forwarding objectives", obj.id());
alshabib2a441c62015-04-13 18:39:38 -0700837 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
838 });
839 }
840 }
841
842 private class CorsaGroup implements NextGroup {
843
844 private final GroupKey key;
845
846 public CorsaGroup(GroupKey key) {
847 this.key = key;
848 }
849
Saurav Dase3274c82015-05-24 17:21:56 -0700850 @SuppressWarnings("unused")
alshabib2a441c62015-04-13 18:39:38 -0700851 public GroupKey key() {
852 return key;
853 }
854
855 @Override
856 public byte[] data() {
857 return appKryo.serialize(key);
858 }
859
860 }
Saurav Das24431192016-03-07 19:13:00 -0800861
862 @Override
863 public List<String> getNextMappings(NextGroup nextGroup) {
864 // TODO Implementation deferred to vendor
865 return null;
866 }
alshabibaebe7752015-04-07 17:45:42 -0700867}