blob: 46a360b42c4082f4bb0003ed1f081a5a7ff44617 [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;
Sho SHIMIZU45906042016-01-13 23:05:54 -080075import java.util.Objects;
alshabib2a441c62015-04-13 18:39:38 -070076import java.util.Set;
77import java.util.concurrent.Executors;
78import java.util.concurrent.ScheduledExecutorService;
79import java.util.concurrent.TimeUnit;
80import java.util.stream.Collectors;
alshabibaebe7752015-04-07 17:45:42 -070081
alshabib2a441c62015-04-13 18:39:38 -070082import static org.onlab.util.Tools.groupedThreads;
alshabibaebe7752015-04-07 17:45:42 -070083import static org.slf4j.LoggerFactory.getLogger;
84
85/**
alshabib2a441c62015-04-13 18:39:38 -070086 * OpenvSwitch emulation of the Corsa pipeline handler.
alshabibaebe7752015-04-07 17:45:42 -070087 */
Thomas Vachuskafacc3f52015-04-10 08:58:36 -070088public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabibaebe7752015-04-07 17:45:42 -070089
Saurav Das3ea46622015-04-22 14:01:34 -070090 protected static final int MAC_TABLE = 0;
alshabibd17abc22015-04-21 18:26:35 -070091 protected static final int VLAN_MPLS_TABLE = 1;
92 protected static final int VLAN_TABLE = 2;
93 //protected static final int MPLS_TABLE = 3;
94 protected static final int ETHER_TABLE = 4;
95 protected static final int COS_MAP_TABLE = 5;
96 protected static final int FIB_TABLE = 6;
97 protected static final int LOCAL_TABLE = 9;
98
99
Saurav Dasd8b97002015-05-14 23:42:49 -0700100 protected static final int CONTROLLER_PRIORITY = 255;
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500101 protected static final int DROP_PRIORITY = 0;
102 protected static final int HIGHEST_PRIORITY = 0xffff;
alshabibaebe7752015-04-07 17:45:42 -0700103
104 private final Logger log = getLogger(getClass());
105
106 private ServiceDirectory serviceDirectory;
Saurav Dasd8b97002015-05-14 23:42:49 -0700107 protected FlowRuleService flowRuleService;
alshabibaebe7752015-04-07 17:45:42 -0700108 private CoreService coreService;
alshabib2a441c62015-04-13 18:39:38 -0700109 private GroupService groupService;
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500110 protected MeterService meterService;
alshabib2a441c62015-04-13 18:39:38 -0700111 private FlowObjectiveStore flowObjectiveStore;
Saurav Dasd8b97002015-05-14 23:42:49 -0700112 protected DeviceId deviceId;
113 protected ApplicationId appId;
alshabibaebe7752015-04-07 17:45:42 -0700114
alshabib2a441c62015-04-13 18:39:38 -0700115 private KryoNamespace appKryo = new KryoNamespace.Builder()
116 .register(GroupKey.class)
117 .register(DefaultGroupKey.class)
118 .register(CorsaGroup.class)
119 .register(byte[].class)
120 .build();
121
122 private Cache<GroupKey, NextObjective> pendingGroups;
123
124 private ScheduledExecutorService groupChecker =
125 Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
126 "ovs-corsa-%d"));
127
alshabibaebe7752015-04-07 17:45:42 -0700128 @Override
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700129 public void init(DeviceId deviceId, PipelinerContext context) {
130 this.serviceDirectory = context.directory();
alshabibaebe7752015-04-07 17:45:42 -0700131 this.deviceId = deviceId;
132
alshabib2a441c62015-04-13 18:39:38 -0700133 pendingGroups = CacheBuilder.newBuilder()
134 .expireAfterWrite(20, TimeUnit.SECONDS)
135 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
136 if (notification.getCause() == RemovalCause.EXPIRED) {
137 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
138 }
139 }).build();
140
141 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
alshabibaebe7752015-04-07 17:45:42 -0700142
143 coreService = serviceDirectory.get(CoreService.class);
144 flowRuleService = serviceDirectory.get(FlowRuleService.class);
alshabib2a441c62015-04-13 18:39:38 -0700145 groupService = serviceDirectory.get(GroupService.class);
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500146 meterService = serviceDirectory.get(MeterService.class);
alshabib2a441c62015-04-13 18:39:38 -0700147 flowObjectiveStore = context.store();
148
149 groupService.addListener(new InnerGroupListener());
alshabibaebe7752015-04-07 17:45:42 -0700150
151 appId = coreService.registerApplication(
152 "org.onosproject.driver.OVSCorsaPipeline");
153
Saurav Das100e3b82015-04-30 11:12:10 -0700154 initializePipeline();
alshabibaebe7752015-04-07 17:45:42 -0700155 }
156
157 @Override
alshabib2a441c62015-04-13 18:39:38 -0700158 public void filter(FilteringObjective filteringObjective) {
159 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
160 processFilter(filteringObjective,
161 filteringObjective.op() == Objective.Operation.ADD,
162 filteringObjective.appId());
163 } else {
164 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
165 }
166 }
alshabib910aff12015-04-09 16:55:57 -0700167
alshabib2a441c62015-04-13 18:39:38 -0700168 @Override
169 public void forward(ForwardingObjective fwd) {
170 Collection<FlowRule> rules;
171 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
172
173 rules = processForward(fwd);
174 switch (fwd.op()) {
175 case ADD:
176 rules.stream()
Sho SHIMIZU45906042016-01-13 23:05:54 -0800177 .filter(Objects::nonNull)
alshabib2a441c62015-04-13 18:39:38 -0700178 .forEach(flowBuilder::add);
179 break;
180 case REMOVE:
181 rules.stream()
Sho SHIMIZU45906042016-01-13 23:05:54 -0800182 .filter(Objects::nonNull)
alshabib2a441c62015-04-13 18:39:38 -0700183 .forEach(flowBuilder::remove);
184 break;
185 default:
186 fail(fwd, ObjectiveError.UNKNOWN);
187 log.warn("Unknown forwarding type {}", fwd.op());
188 }
189
190
191 flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
192 @Override
193 public void onSuccess(FlowRuleOperations ops) {
194 pass(fwd);
195 }
196
197 @Override
198 public void onError(FlowRuleOperations ops) {
199 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
200 }
201 }));
alshabib910aff12015-04-09 16:55:57 -0700202
203 }
204
alshabib2a441c62015-04-13 18:39:38 -0700205 @Override
206 public void next(NextObjective nextObjective) {
207 switch (nextObjective.type()) {
208 case SIMPLE:
209 Collection<TrafficTreatment> treatments = nextObjective.next();
210 if (treatments.size() == 1) {
211 TrafficTreatment treatment = treatments.iterator().next();
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500212 treatment = processNextTreatment(treatment);
alshabib2a441c62015-04-13 18:39:38 -0700213 GroupBucket bucket =
214 DefaultGroupBucket.createIndirectGroupBucket(treatment);
215 final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
216 GroupDescription groupDescription
217 = new DefaultGroupDescription(deviceId,
218 GroupDescription.Type.INDIRECT,
219 new GroupBuckets(Collections
220 .singletonList(bucket)),
221 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700222 null, // let group service determine group id
alshabib2a441c62015-04-13 18:39:38 -0700223 nextObjective.appId());
224 groupService.addGroup(groupDescription);
225 pendingGroups.put(key, nextObjective);
226 }
227 break;
228 case HASHED:
229 case BROADCAST:
230 case FAILOVER:
231 fail(nextObjective, ObjectiveError.UNSUPPORTED);
232 log.warn("Unsupported next objective type {}", nextObjective.type());
233 break;
234 default:
235 fail(nextObjective, ObjectiveError.UNKNOWN);
236 log.warn("Unknown next objective type {}", nextObjective.type());
237 }
238
239 }
240
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500241 /* Hook for altering the NextObjective treatment */
242 protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) {
243 return treatment; /* Keep treatment as is for OVSCorsaPipeline */
244 }
245
alshabib2a441c62015-04-13 18:39:38 -0700246 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
247 switch (fwd.flag()) {
248 case SPECIFIC:
249 return processSpecific(fwd);
250 case VERSATILE:
251 return processVersatile(fwd);
252 default:
253 fail(fwd, ObjectiveError.UNKNOWN);
254 log.warn("Unknown forwarding flag {}", fwd.flag());
255 }
256 return Collections.emptySet();
257 }
258
259 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
Saurav Das3d038262015-04-23 12:36:58 -0700260 log.debug("Processing versatile forwarding objective");
261 TrafficSelector selector = fwd.selector();
262
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700263 EthTypeCriterion ethType =
264 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Saurav Das3d038262015-04-23 12:36:58 -0700265 if (ethType == null) {
266 log.error("Versatile forwarding objective must include ethType");
267 fail(fwd, ObjectiveError.UNKNOWN);
268 return Collections.emptySet();
269 }
alshabibcaf1ca22015-06-25 15:18:16 -0700270 if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) {
Saurav Das3d038262015-04-23 12:36:58 -0700271 log.warn("Driver automatically handles ARP packets by punting to controller "
272 + " from ETHER table");
273 pass(fwd);
274 return Collections.emptySet();
alshabibcaf1ca22015-06-25 15:18:16 -0700275 } else if (ethType.ethType().toShort() == Ethernet.TYPE_LLDP ||
276 ethType.ethType().toShort() == Ethernet.TYPE_BSN) {
Saurav Das3d038262015-04-23 12:36:58 -0700277 log.warn("Driver currently does not currently handle LLDP packets");
278 fail(fwd, ObjectiveError.UNSUPPORTED);
279 return Collections.emptySet();
alshabibcaf1ca22015-06-25 15:18:16 -0700280 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700281 IPCriterion ipSrc = (IPCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700282 .getCriterion(Criterion.Type.IPV4_SRC);
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700283 IPCriterion ipDst = (IPCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700284 .getCriterion(Criterion.Type.IPV4_DST);
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700285 IPProtocolCriterion ipProto = (IPProtocolCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700286 .getCriterion(Criterion.Type.IP_PROTO);
287 if (ipSrc != null) {
Saurav Dasbd7f7422015-04-23 16:31:47 -0700288 log.warn("Driver does not currently handle matching Src IP");
Saurav Das3d038262015-04-23 12:36:58 -0700289 fail(fwd, ObjectiveError.UNSUPPORTED);
290 return Collections.emptySet();
291 }
292 if (ipDst != null) {
293 log.error("Driver handles Dst IP matching as specific forwarding "
294 + "objective, not versatile");
295 fail(fwd, ObjectiveError.UNSUPPORTED);
296 return Collections.emptySet();
297 }
298 if (ipProto != null && ipProto.protocol() == IPv4.PROTOCOL_TCP) {
299 log.warn("Driver automatically punts all packets reaching the "
300 + "LOCAL table to the controller");
301 pass(fwd);
302 return Collections.emptySet();
303 }
304 }
305
306 log.warn("Driver does not support given versatile forwarding objective");
alshabib2a441c62015-04-13 18:39:38 -0700307 fail(fwd, ObjectiveError.UNSUPPORTED);
308 return Collections.emptySet();
309 }
310
311 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
Saurav Das3d038262015-04-23 12:36:58 -0700312 log.debug("Processing specific forwarding objective");
alshabib2a441c62015-04-13 18:39:38 -0700313 TrafficSelector selector = fwd.selector();
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500314
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700315 EthTypeCriterion ethType =
316 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500317 if (ethType != null) {
318 short et = ethType.ethType().toShort();
319 if (et == Ethernet.TYPE_IPV4) {
320 return processSpecificRoute(fwd);
321 } else if (et == Ethernet.TYPE_VLAN) {
322 /* The ForwardingObjective must specify VLAN ethtype in order to use the Transit Circuit */
323 return processSpecificSwitch(fwd);
324 }
alshabib2a441c62015-04-13 18:39:38 -0700325 }
326
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500327 fail(fwd, ObjectiveError.UNSUPPORTED);
328 return Collections.emptySet();
329 }
330
331 private Collection<FlowRule> processSpecificRoute(ForwardingObjective fwd) {
alshabib2a441c62015-04-13 18:39:38 -0700332 TrafficSelector filteredSelector =
333 DefaultTrafficSelector.builder()
334 .matchEthType(Ethernet.TYPE_IPV4)
335 .matchIPDst(
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500336 ((IPCriterion) fwd.selector().getCriterion(Criterion.Type.IPV4_DST)).ip())
alshabib2a441c62015-04-13 18:39:38 -0700337 .build();
338
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500339 TrafficTreatment.Builder tb = processSpecificRoutingTreatment();
alshabib2a441c62015-04-13 18:39:38 -0700340
sanghodde53d12015-04-30 10:34:41 -0700341 if (fwd.nextId() != null) {
342 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
343 GroupKey key = appKryo.deserialize(next.data());
344 Group group = groupService.getGroup(deviceId, key);
345 if (group == null) {
346 log.warn("The group left!");
347 fail(fwd, ObjectiveError.GROUPMISSING);
348 return Collections.emptySet();
349 }
350 tb.group(group.id());
alshabib2a441c62015-04-13 18:39:38 -0700351 }
352
alshabibd17abc22015-04-21 18:26:35 -0700353 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
354 .fromApp(fwd.appId())
355 .withPriority(fwd.priority())
356 .forDevice(deviceId)
357 .withSelector(filteredSelector)
sanghodde53d12015-04-30 10:34:41 -0700358 .withTreatment(tb.build());
alshabibd17abc22015-04-21 18:26:35 -0700359
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500360 ruleBuilder = processSpecificRoutingRule(ruleBuilder);
361
alshabibd17abc22015-04-21 18:26:35 -0700362 if (fwd.permanent()) {
363 ruleBuilder.makePermanent();
364 } else {
365 ruleBuilder.makeTemporary(fwd.timeout());
366 }
367
alshabibd17abc22015-04-21 18:26:35 -0700368 return Collections.singletonList(ruleBuilder.build());
alshabib2a441c62015-04-13 18:39:38 -0700369 }
370
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500371 /* Hook for modifying Route traffic treatment */
372 protected TrafficTreatment.Builder processSpecificRoutingTreatment() {
373 return DefaultTrafficTreatment.builder();
374 }
375
376 /* Hook for modifying Route flow rule */
377 protected FlowRule.Builder processSpecificRoutingRule(FlowRule.Builder rb) {
378 return rb.forTable(FIB_TABLE);
379 }
380
381 protected Collection<FlowRule> processSpecificSwitch(ForwardingObjective fwd) {
382 /* Not supported by until CorsaPipelineV3 */
383 log.warn("Vlan switching not supported in ovs-corsa driver");
384 fail(fwd, ObjectiveError.UNSUPPORTED);
385 return Collections.emptySet();
386 }
387
388 protected void processFilter(FilteringObjective filt, boolean install,
alshabib910aff12015-04-09 16:55:57 -0700389 ApplicationId applicationId) {
Saurav Dascfd63d22015-04-13 16:08:24 -0700390 // This driver only processes filtering criteria defined with switch
391 // ports as the key
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700392 PortCriterion p;
Saurav Dascfd63d22015-04-13 16:08:24 -0700393 if (!filt.key().equals(Criteria.dummy()) &&
394 filt.key().type() == Criterion.Type.IN_PORT) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700395 p = (PortCriterion) filt.key();
Saurav Dascfd63d22015-04-13 16:08:24 -0700396 } else {
397 log.warn("No key defined in filtering objective from app: {}. Not"
398 + "processing filtering objective", applicationId);
alshabib2a441c62015-04-13 18:39:38 -0700399 fail(filt, ObjectiveError.UNKNOWN);
400 return;
alshabib910aff12015-04-09 16:55:57 -0700401 }
Saurav Dascfd63d22015-04-13 16:08:24 -0700402 // convert filtering conditions for switch-intfs into flowrules
403 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
404 for (Criterion c : filt.conditions()) {
405 if (c.type() == Criterion.Type.ETH_DST) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700406 EthCriterion e = (EthCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700407 log.debug("adding rule for MAC: {}", e.mac());
408 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
409 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
410 selector.matchEthDst(e.mac());
alshabibd17abc22015-04-21 18:26:35 -0700411 treatment.transition(VLAN_MPLS_TABLE);
412 FlowRule rule = DefaultFlowRule.builder()
413 .forDevice(deviceId)
414 .withSelector(selector.build())
415 .withTreatment(treatment.build())
416 .withPriority(CONTROLLER_PRIORITY)
417 .fromApp(applicationId)
418 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700419 .forTable(MAC_TABLE).build();
Saurav Dascfd63d22015-04-13 16:08:24 -0700420 ops = install ? ops.add(rule) : ops.remove(rule);
421 } else if (c.type() == Criterion.Type.VLAN_VID) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700422 VlanIdCriterion v = (VlanIdCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700423 log.debug("adding rule for VLAN: {}", v.vlanId());
424 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
425 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
426 selector.matchVlanId(v.vlanId());
427 selector.matchInPort(p.port());
alshabibd17abc22015-04-21 18:26:35 -0700428 treatment.transition(ETHER_TABLE);
Saurav Dascfd63d22015-04-13 16:08:24 -0700429 treatment.deferred().popVlan();
alshabibd17abc22015-04-21 18:26:35 -0700430 FlowRule rule = DefaultFlowRule.builder()
431 .forDevice(deviceId)
432 .withSelector(selector.build())
433 .withTreatment(treatment.build())
434 .withPriority(CONTROLLER_PRIORITY)
435 .fromApp(applicationId)
436 .makePermanent()
437 .forTable(VLAN_TABLE).build();
Saurav Dascfd63d22015-04-13 16:08:24 -0700438 ops = install ? ops.add(rule) : ops.remove(rule);
439 } else if (c.type() == Criterion.Type.IPV4_DST) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700440 IPCriterion ip = (IPCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700441 log.debug("adding rule for IP: {}", ip.ip());
442 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
443 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
444 selector.matchEthType(Ethernet.TYPE_IPV4);
445 selector.matchIPDst(ip.ip());
alshabibd17abc22015-04-21 18:26:35 -0700446 treatment.transition(LOCAL_TABLE);
447 FlowRule rule = DefaultFlowRule.builder()
448 .forDevice(deviceId)
449 .withSelector(selector.build())
450 .withTreatment(treatment.build())
451 .withPriority(HIGHEST_PRIORITY)
452 .fromApp(applicationId)
453 .makePermanent()
454 .forTable(FIB_TABLE).build();
455
Saurav Dascfd63d22015-04-13 16:08:24 -0700456 ops = install ? ops.add(rule) : ops.remove(rule);
457 } else {
458 log.warn("Driver does not currently process filtering condition"
459 + " of type: {}", c.type());
alshabib2a441c62015-04-13 18:39:38 -0700460 fail(filt, ObjectiveError.UNSUPPORTED);
Saurav Dascfd63d22015-04-13 16:08:24 -0700461 }
462 }
463 // apply filtering flow rules
464 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
465 @Override
466 public void onSuccess(FlowRuleOperations ops) {
alshabib2a441c62015-04-13 18:39:38 -0700467 pass(filt);
Saurav Das3ea46622015-04-22 14:01:34 -0700468 log.info("Applied filtering rules");
Saurav Dascfd63d22015-04-13 16:08:24 -0700469 }
470
471 @Override
472 public void onError(FlowRuleOperations ops) {
alshabib2a441c62015-04-13 18:39:38 -0700473 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Saurav Das3ea46622015-04-22 14:01:34 -0700474 log.info("Failed to apply filtering rules");
Saurav Dascfd63d22015-04-13 16:08:24 -0700475 }
476 }));
alshabibaebe7752015-04-07 17:45:42 -0700477 }
478
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500479 protected void pass(Objective obj) {
alshabib2a441c62015-04-13 18:39:38 -0700480 if (obj.context().isPresent()) {
481 obj.context().get().onSuccess(obj);
482 }
alshabibaebe7752015-04-07 17:45:42 -0700483 }
484
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500485 protected void fail(Objective obj, ObjectiveError error) {
alshabib2a441c62015-04-13 18:39:38 -0700486 if (obj.context().isPresent()) {
487 obj.context().get().onError(obj, error);
488 }
alshabibaebe7752015-04-07 17:45:42 -0700489 }
490
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500491 protected void initializePipeline() {
Saurav Das3ea46622015-04-22 14:01:34 -0700492 processMacTable(true);
493 processVlanMplsTable(true);
494 processVlanTable(true);
495 processEtherTable(true);
496 processCosTable(true);
497 processFibTable(true);
498 processLocalTable(true);
alshabibaebe7752015-04-07 17:45:42 -0700499 }
500
Saurav Das3ea46622015-04-22 14:01:34 -0700501 private void processMacTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700502 TrafficSelector.Builder selector;
503 TrafficTreatment.Builder treatment;
504
505 // Bcast rule
506 selector = DefaultTrafficSelector.builder();
507 treatment = DefaultTrafficTreatment.builder();
508
509 selector.matchEthDst(MacAddress.BROADCAST);
alshabibd17abc22015-04-21 18:26:35 -0700510 treatment.transition(VLAN_MPLS_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700511
alshabibd17abc22015-04-21 18:26:35 -0700512 FlowRule rule = DefaultFlowRule.builder()
513 .forDevice(deviceId)
514 .withSelector(selector.build())
515 .withTreatment(treatment.build())
516 .withPriority(CONTROLLER_PRIORITY)
517 .fromApp(appId)
518 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700519 .forTable(MAC_TABLE).build();
alshabibd17abc22015-04-21 18:26:35 -0700520
alshabibaebe7752015-04-07 17:45:42 -0700521
522 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
523
524 ops = install ? ops.add(rule) : ops.remove(rule);
525
526
alshabibaebe7752015-04-07 17:45:42 -0700527 //Drop rule
528 selector = DefaultTrafficSelector.builder();
529 treatment = DefaultTrafficTreatment.builder();
530
531 treatment.drop();
532
alshabibd17abc22015-04-21 18:26:35 -0700533 rule = DefaultFlowRule.builder()
534 .forDevice(deviceId)
535 .withSelector(selector.build())
536 .withTreatment(treatment.build())
537 .withPriority(DROP_PRIORITY)
538 .fromApp(appId)
539 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700540 .forTable(MAC_TABLE).build();
alshabibd17abc22015-04-21 18:26:35 -0700541
alshabibaebe7752015-04-07 17:45:42 -0700542
543 ops = install ? ops.add(rule) : ops.remove(rule);
544
545 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
546 @Override
547 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700548 log.info("Provisioned mac table");
alshabibaebe7752015-04-07 17:45:42 -0700549 }
550
551 @Override
552 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700553 log.info("Failed to provision mac table");
alshabibaebe7752015-04-07 17:45:42 -0700554 }
555 }));
556
557 }
558
Saurav Dasd8b97002015-05-14 23:42:49 -0700559 protected void processVlanMplsTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700560 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
561 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
562 .builder();
563 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
564 FlowRule rule;
565
566 selector.matchVlanId(VlanId.ANY);
alshabibd17abc22015-04-21 18:26:35 -0700567 treatment.transition(VLAN_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700568
alshabibd17abc22015-04-21 18:26:35 -0700569 rule = DefaultFlowRule.builder()
570 .forDevice(deviceId)
571 .withSelector(selector.build())
572 .withTreatment(treatment.build())
573 .withPriority(CONTROLLER_PRIORITY)
574 .fromApp(appId)
575 .makePermanent()
576 .forTable(VLAN_MPLS_TABLE).build();
577
alshabibaebe7752015-04-07 17:45:42 -0700578
579 ops = install ? ops.add(rule) : ops.remove(rule);
580
581 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
582 @Override
583 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700584 log.info("Provisioned vlan/mpls table");
alshabibaebe7752015-04-07 17:45:42 -0700585 }
586
587 @Override
588 public void onError(FlowRuleOperations ops) {
589 log.info(
Saurav Das3ea46622015-04-22 14:01:34 -0700590 "Failed to provision vlan/mpls table");
alshabibaebe7752015-04-07 17:45:42 -0700591 }
592 }));
593
594 }
595
Saurav Das3ea46622015-04-22 14:01:34 -0700596 private void processVlanTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700597 TrafficSelector.Builder selector;
598 TrafficTreatment.Builder treatment;
599 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
600 FlowRule rule;
601
602
alshabibaebe7752015-04-07 17:45:42 -0700603 //Drop rule
604 selector = DefaultTrafficSelector.builder();
605 treatment = DefaultTrafficTreatment.builder();
606
607 treatment.drop();
608
alshabibd17abc22015-04-21 18:26:35 -0700609 rule = DefaultFlowRule.builder()
610 .forDevice(deviceId)
611 .withSelector(selector.build())
612 .withTreatment(treatment.build())
613 .withPriority(DROP_PRIORITY)
614 .fromApp(appId)
615 .makePermanent()
616 .forTable(VLAN_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700617
618 ops = install ? ops.add(rule) : ops.remove(rule);
619
620 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
621 @Override
622 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700623 log.info("Provisioned vlan table");
alshabibaebe7752015-04-07 17:45:42 -0700624 }
625
626 @Override
627 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700628 log.info("Failed to provision vlan table");
alshabibaebe7752015-04-07 17:45:42 -0700629 }
630 }));
631 }
632
Saurav Das3ea46622015-04-22 14:01:34 -0700633 private void processEtherTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700634 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
635 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
636 .builder();
637 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
638 FlowRule rule;
639
640 selector.matchEthType(Ethernet.TYPE_ARP);
641 treatment.punt();
642
alshabibd17abc22015-04-21 18:26:35 -0700643 rule = DefaultFlowRule.builder()
644 .forDevice(deviceId)
645 .withSelector(selector.build())
646 .withTreatment(treatment.build())
647 .withPriority(CONTROLLER_PRIORITY)
648 .fromApp(appId)
649 .makePermanent()
650 .forTable(ETHER_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700651
652 ops = install ? ops.add(rule) : ops.remove(rule);
653
654 selector = DefaultTrafficSelector.builder();
655 treatment = DefaultTrafficTreatment.builder();
656
657 selector.matchEthType(Ethernet.TYPE_IPV4);
alshabibd17abc22015-04-21 18:26:35 -0700658 treatment.transition(COS_MAP_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700659
alshabibd17abc22015-04-21 18:26:35 -0700660 rule = DefaultFlowRule.builder()
661 .forDevice(deviceId)
662 .withPriority(CONTROLLER_PRIORITY)
663 .withSelector(selector.build())
664 .withTreatment(treatment.build())
665 .fromApp(appId)
666 .makePermanent()
667 .forTable(ETHER_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700668
669 ops = install ? ops.add(rule) : ops.remove(rule);
670
671 //Drop rule
672 selector = DefaultTrafficSelector.builder();
673 treatment = DefaultTrafficTreatment.builder();
674
675 treatment.drop();
676
alshabibd17abc22015-04-21 18:26:35 -0700677 rule = DefaultFlowRule.builder()
678 .forDevice(deviceId)
679 .withSelector(selector.build())
680 .withTreatment(treatment.build())
681 .withPriority(DROP_PRIORITY)
682 .fromApp(appId)
683 .makePermanent()
684 .forTable(ETHER_TABLE).build();
685
alshabibaebe7752015-04-07 17:45:42 -0700686
687 ops = install ? ops.add(rule) : ops.remove(rule);
688
689 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
690 @Override
691 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700692 log.info("Provisioned ether table");
alshabibaebe7752015-04-07 17:45:42 -0700693 }
694
695 @Override
696 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700697 log.info("Failed to provision ether table");
alshabibaebe7752015-04-07 17:45:42 -0700698 }
699 }));
700
701 }
702
Saurav Das3ea46622015-04-22 14:01:34 -0700703 private void processCosTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700704 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
705 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
706 .builder();
707 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
708 FlowRule rule;
709
alshabibd17abc22015-04-21 18:26:35 -0700710 treatment.transition(FIB_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700711
alshabibd17abc22015-04-21 18:26:35 -0700712 rule = DefaultFlowRule.builder()
713 .forDevice(deviceId)
714 .withSelector(selector.build())
715 .withTreatment(treatment.build())
716 .withPriority(DROP_PRIORITY)
717 .fromApp(appId)
718 .makePermanent()
719 .forTable(COS_MAP_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700720
721 ops = install ? ops.add(rule) : ops.remove(rule);
722
723 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
724 @Override
725 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700726 log.info("Provisioned cos table");
alshabibaebe7752015-04-07 17:45:42 -0700727 }
728
729 @Override
730 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700731 log.info("Failed to provision cos table");
alshabibaebe7752015-04-07 17:45:42 -0700732 }
733 }));
734
735 }
736
Saurav Das3ea46622015-04-22 14:01:34 -0700737 private void processFibTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700738 TrafficSelector.Builder selector;
739 TrafficTreatment.Builder treatment;
740 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
741 FlowRule rule;
742
743 //Drop rule
744 selector = DefaultTrafficSelector.builder();
745 treatment = DefaultTrafficTreatment.builder();
746
747 treatment.drop();
748
alshabibd17abc22015-04-21 18:26:35 -0700749 rule = DefaultFlowRule.builder()
750 .forDevice(deviceId)
751 .withSelector(selector.build())
752 .withTreatment(treatment.build())
753 .withPriority(DROP_PRIORITY)
754 .fromApp(appId)
755 .makePermanent()
756 .forTable(FIB_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700757
758 ops = install ? ops.add(rule) : ops.remove(rule);
759
760 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
761 @Override
762 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700763 log.info("Provisioned FIB table");
alshabibaebe7752015-04-07 17:45:42 -0700764 }
765
766 @Override
767 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700768 log.info("Failed to provision FIB table");
alshabibaebe7752015-04-07 17:45:42 -0700769 }
770 }));
771 }
772
Saurav Das3ea46622015-04-22 14:01:34 -0700773 private void processLocalTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700774 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
775 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
776 .builder();
777 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
778 FlowRule rule;
779
780 treatment.punt();
781
alshabibd17abc22015-04-21 18:26:35 -0700782 rule = DefaultFlowRule.builder()
783 .forDevice(deviceId)
784 .withSelector(selector.build())
785 .withTreatment(treatment.build())
786 .withPriority(CONTROLLER_PRIORITY)
787 .fromApp(appId)
788 .makePermanent()
789 .forTable(LOCAL_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700790
791 ops = install ? ops.add(rule) : ops.remove(rule);
792
793 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
794 @Override
795 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700796 log.info("Provisioned Local table");
alshabibaebe7752015-04-07 17:45:42 -0700797 }
798
799 @Override
800 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700801 log.info("Failed to provision Local table");
alshabibaebe7752015-04-07 17:45:42 -0700802 }
803 }));
804 }
805
alshabib2a441c62015-04-13 18:39:38 -0700806 private class InnerGroupListener implements GroupListener {
807 @Override
808 public void event(GroupEvent event) {
809 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
810 GroupKey key = event.subject().appCookie();
811
812 NextObjective obj = pendingGroups.getIfPresent(key);
813 if (obj != null) {
814 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
815 pass(obj);
816 pendingGroups.invalidate(key);
817 }
818 }
819 }
820 }
821
822
823 private class GroupChecker implements Runnable {
824
825 @Override
826 public void run() {
827 Set<GroupKey> keys = pendingGroups.asMap().keySet().stream()
828 .filter(key -> groupService.getGroup(deviceId, key) != null)
829 .collect(Collectors.toSet());
830
831 keys.stream().forEach(key -> {
832 NextObjective obj = pendingGroups.getIfPresent(key);
833 if (obj == null) {
834 return;
835 }
836 pass(obj);
837 pendingGroups.invalidate(key);
Saurav Dasbd7f7422015-04-23 16:31:47 -0700838 log.info("Heard back from group service for group {}. "
839 + "Applying pending forwarding objectives", obj.id());
alshabib2a441c62015-04-13 18:39:38 -0700840 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
841 });
842 }
843 }
844
845 private class CorsaGroup implements NextGroup {
846
847 private final GroupKey key;
848
849 public CorsaGroup(GroupKey key) {
850 this.key = key;
851 }
852
Saurav Dase3274c82015-05-24 17:21:56 -0700853 @SuppressWarnings("unused")
alshabib2a441c62015-04-13 18:39:38 -0700854 public GroupKey key() {
855 return key;
856 }
857
858 @Override
859 public byte[] data() {
860 return appKryo.serialize(key);
861 }
862
863 }
alshabibaebe7752015-04-07 17:45:42 -0700864}