blob: 5a8c68c4f9914d130b4ac29bd7be5e6a4f57d627 [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;
75import java.util.Set;
76import java.util.concurrent.Executors;
77import java.util.concurrent.ScheduledExecutorService;
78import java.util.concurrent.TimeUnit;
79import java.util.stream.Collectors;
alshabibaebe7752015-04-07 17:45:42 -070080
alshabib2a441c62015-04-13 18:39:38 -070081import static org.onlab.util.Tools.groupedThreads;
alshabibaebe7752015-04-07 17:45:42 -070082import static org.slf4j.LoggerFactory.getLogger;
83
84/**
alshabib2a441c62015-04-13 18:39:38 -070085 * OpenvSwitch emulation of the Corsa pipeline handler.
alshabibaebe7752015-04-07 17:45:42 -070086 */
Thomas Vachuskafacc3f52015-04-10 08:58:36 -070087public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabibaebe7752015-04-07 17:45:42 -070088
Saurav Das3ea46622015-04-22 14:01:34 -070089 protected static final int MAC_TABLE = 0;
alshabibd17abc22015-04-21 18:26:35 -070090 protected static final int VLAN_MPLS_TABLE = 1;
91 protected static final int VLAN_TABLE = 2;
92 //protected static final int MPLS_TABLE = 3;
93 protected static final int ETHER_TABLE = 4;
94 protected static final int COS_MAP_TABLE = 5;
95 protected static final int FIB_TABLE = 6;
96 protected static final int LOCAL_TABLE = 9;
97
98
Saurav Dasd8b97002015-05-14 23:42:49 -070099 protected static final int CONTROLLER_PRIORITY = 255;
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500100 protected static final int DROP_PRIORITY = 0;
101 protected static final int HIGHEST_PRIORITY = 0xffff;
alshabibaebe7752015-04-07 17:45:42 -0700102
103 private final Logger log = getLogger(getClass());
104
105 private ServiceDirectory serviceDirectory;
Saurav Dasd8b97002015-05-14 23:42:49 -0700106 protected FlowRuleService flowRuleService;
alshabibaebe7752015-04-07 17:45:42 -0700107 private CoreService coreService;
alshabib2a441c62015-04-13 18:39:38 -0700108 private GroupService groupService;
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500109 protected MeterService meterService;
alshabib2a441c62015-04-13 18:39:38 -0700110 private FlowObjectiveStore flowObjectiveStore;
Saurav Dasd8b97002015-05-14 23:42:49 -0700111 protected DeviceId deviceId;
112 protected ApplicationId appId;
alshabibaebe7752015-04-07 17:45:42 -0700113
alshabib2a441c62015-04-13 18:39:38 -0700114 private KryoNamespace appKryo = new KryoNamespace.Builder()
115 .register(GroupKey.class)
116 .register(DefaultGroupKey.class)
117 .register(CorsaGroup.class)
118 .register(byte[].class)
119 .build();
120
121 private Cache<GroupKey, NextObjective> pendingGroups;
122
123 private ScheduledExecutorService groupChecker =
124 Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
125 "ovs-corsa-%d"));
126
alshabibaebe7752015-04-07 17:45:42 -0700127 @Override
Thomas Vachuskaca88bb72015-04-08 19:38:02 -0700128 public void init(DeviceId deviceId, PipelinerContext context) {
129 this.serviceDirectory = context.directory();
alshabibaebe7752015-04-07 17:45:42 -0700130 this.deviceId = deviceId;
131
alshabib2a441c62015-04-13 18:39:38 -0700132 pendingGroups = CacheBuilder.newBuilder()
133 .expireAfterWrite(20, TimeUnit.SECONDS)
134 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
135 if (notification.getCause() == RemovalCause.EXPIRED) {
136 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
137 }
138 }).build();
139
140 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
alshabibaebe7752015-04-07 17:45:42 -0700141
142 coreService = serviceDirectory.get(CoreService.class);
143 flowRuleService = serviceDirectory.get(FlowRuleService.class);
alshabib2a441c62015-04-13 18:39:38 -0700144 groupService = serviceDirectory.get(GroupService.class);
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500145 meterService = serviceDirectory.get(MeterService.class);
alshabib2a441c62015-04-13 18:39:38 -0700146 flowObjectiveStore = context.store();
147
148 groupService.addListener(new InnerGroupListener());
alshabibaebe7752015-04-07 17:45:42 -0700149
150 appId = coreService.registerApplication(
151 "org.onosproject.driver.OVSCorsaPipeline");
152
Saurav Das100e3b82015-04-30 11:12:10 -0700153 initializePipeline();
alshabibaebe7752015-04-07 17:45:42 -0700154 }
155
156 @Override
alshabib2a441c62015-04-13 18:39:38 -0700157 public void filter(FilteringObjective filteringObjective) {
158 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
159 processFilter(filteringObjective,
160 filteringObjective.op() == Objective.Operation.ADD,
161 filteringObjective.appId());
162 } else {
163 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
164 }
165 }
alshabib910aff12015-04-09 16:55:57 -0700166
alshabib2a441c62015-04-13 18:39:38 -0700167 @Override
168 public void forward(ForwardingObjective fwd) {
169 Collection<FlowRule> rules;
170 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
171
172 rules = processForward(fwd);
173 switch (fwd.op()) {
174 case ADD:
175 rules.stream()
176 .filter(rule -> rule != null)
177 .forEach(flowBuilder::add);
178 break;
179 case REMOVE:
180 rules.stream()
181 .filter(rule -> rule != null)
182 .forEach(flowBuilder::remove);
183 break;
184 default:
185 fail(fwd, ObjectiveError.UNKNOWN);
186 log.warn("Unknown forwarding type {}", fwd.op());
187 }
188
189
190 flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
191 @Override
192 public void onSuccess(FlowRuleOperations ops) {
193 pass(fwd);
194 }
195
196 @Override
197 public void onError(FlowRuleOperations ops) {
198 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
199 }
200 }));
alshabib910aff12015-04-09 16:55:57 -0700201
202 }
203
alshabib2a441c62015-04-13 18:39:38 -0700204 @Override
205 public void next(NextObjective nextObjective) {
206 switch (nextObjective.type()) {
207 case SIMPLE:
208 Collection<TrafficTreatment> treatments = nextObjective.next();
209 if (treatments.size() == 1) {
210 TrafficTreatment treatment = treatments.iterator().next();
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500211 treatment = processNextTreatment(treatment);
alshabib2a441c62015-04-13 18:39:38 -0700212 GroupBucket bucket =
213 DefaultGroupBucket.createIndirectGroupBucket(treatment);
214 final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
215 GroupDescription groupDescription
216 = new DefaultGroupDescription(deviceId,
217 GroupDescription.Type.INDIRECT,
218 new GroupBuckets(Collections
219 .singletonList(bucket)),
220 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700221 null, // let group service determine group id
alshabib2a441c62015-04-13 18:39:38 -0700222 nextObjective.appId());
223 groupService.addGroup(groupDescription);
224 pendingGroups.put(key, nextObjective);
225 }
226 break;
227 case HASHED:
228 case BROADCAST:
229 case FAILOVER:
230 fail(nextObjective, ObjectiveError.UNSUPPORTED);
231 log.warn("Unsupported next objective type {}", nextObjective.type());
232 break;
233 default:
234 fail(nextObjective, ObjectiveError.UNKNOWN);
235 log.warn("Unknown next objective type {}", nextObjective.type());
236 }
237
238 }
239
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500240 /* Hook for altering the NextObjective treatment */
241 protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) {
242 return treatment; /* Keep treatment as is for OVSCorsaPipeline */
243 }
244
alshabib2a441c62015-04-13 18:39:38 -0700245 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
246 switch (fwd.flag()) {
247 case SPECIFIC:
248 return processSpecific(fwd);
249 case VERSATILE:
250 return processVersatile(fwd);
251 default:
252 fail(fwd, ObjectiveError.UNKNOWN);
253 log.warn("Unknown forwarding flag {}", fwd.flag());
254 }
255 return Collections.emptySet();
256 }
257
258 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
Saurav Das3d038262015-04-23 12:36:58 -0700259 log.debug("Processing versatile forwarding objective");
260 TrafficSelector selector = fwd.selector();
261
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700262 EthTypeCriterion ethType =
263 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Saurav Das3d038262015-04-23 12:36:58 -0700264 if (ethType == null) {
265 log.error("Versatile forwarding objective must include ethType");
266 fail(fwd, ObjectiveError.UNKNOWN);
267 return Collections.emptySet();
268 }
alshabibcaf1ca22015-06-25 15:18:16 -0700269 if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) {
Saurav Das3d038262015-04-23 12:36:58 -0700270 log.warn("Driver automatically handles ARP packets by punting to controller "
271 + " from ETHER table");
272 pass(fwd);
273 return Collections.emptySet();
alshabibcaf1ca22015-06-25 15:18:16 -0700274 } else if (ethType.ethType().toShort() == Ethernet.TYPE_LLDP ||
275 ethType.ethType().toShort() == Ethernet.TYPE_BSN) {
Saurav Das3d038262015-04-23 12:36:58 -0700276 log.warn("Driver currently does not currently handle LLDP packets");
277 fail(fwd, ObjectiveError.UNSUPPORTED);
278 return Collections.emptySet();
alshabibcaf1ca22015-06-25 15:18:16 -0700279 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700280 IPCriterion ipSrc = (IPCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700281 .getCriterion(Criterion.Type.IPV4_SRC);
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700282 IPCriterion ipDst = (IPCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700283 .getCriterion(Criterion.Type.IPV4_DST);
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700284 IPProtocolCriterion ipProto = (IPProtocolCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700285 .getCriterion(Criterion.Type.IP_PROTO);
286 if (ipSrc != null) {
Saurav Dasbd7f7422015-04-23 16:31:47 -0700287 log.warn("Driver does not currently handle matching Src IP");
Saurav Das3d038262015-04-23 12:36:58 -0700288 fail(fwd, ObjectiveError.UNSUPPORTED);
289 return Collections.emptySet();
290 }
291 if (ipDst != null) {
292 log.error("Driver handles Dst IP matching as specific forwarding "
293 + "objective, not versatile");
294 fail(fwd, ObjectiveError.UNSUPPORTED);
295 return Collections.emptySet();
296 }
297 if (ipProto != null && ipProto.protocol() == IPv4.PROTOCOL_TCP) {
298 log.warn("Driver automatically punts all packets reaching the "
299 + "LOCAL table to the controller");
300 pass(fwd);
301 return Collections.emptySet();
302 }
303 }
304
305 log.warn("Driver does not support given versatile forwarding objective");
alshabib2a441c62015-04-13 18:39:38 -0700306 fail(fwd, ObjectiveError.UNSUPPORTED);
307 return Collections.emptySet();
308 }
309
310 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
Saurav Das3d038262015-04-23 12:36:58 -0700311 log.debug("Processing specific forwarding objective");
alshabib2a441c62015-04-13 18:39:38 -0700312 TrafficSelector selector = fwd.selector();
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500313
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700314 EthTypeCriterion ethType =
315 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500316 if (ethType != null) {
317 short et = ethType.ethType().toShort();
318 if (et == Ethernet.TYPE_IPV4) {
319 return processSpecificRoute(fwd);
320 } else if (et == Ethernet.TYPE_VLAN) {
321 /* The ForwardingObjective must specify VLAN ethtype in order to use the Transit Circuit */
322 return processSpecificSwitch(fwd);
323 }
alshabib2a441c62015-04-13 18:39:38 -0700324 }
325
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500326 fail(fwd, ObjectiveError.UNSUPPORTED);
327 return Collections.emptySet();
328 }
329
330 private Collection<FlowRule> processSpecificRoute(ForwardingObjective fwd) {
alshabib2a441c62015-04-13 18:39:38 -0700331 TrafficSelector filteredSelector =
332 DefaultTrafficSelector.builder()
333 .matchEthType(Ethernet.TYPE_IPV4)
334 .matchIPDst(
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500335 ((IPCriterion) fwd.selector().getCriterion(Criterion.Type.IPV4_DST)).ip())
alshabib2a441c62015-04-13 18:39:38 -0700336 .build();
337
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500338 TrafficTreatment.Builder tb = processSpecificRoutingTreatment();
alshabib2a441c62015-04-13 18:39:38 -0700339
sanghodde53d12015-04-30 10:34:41 -0700340 if (fwd.nextId() != null) {
341 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
342 GroupKey key = appKryo.deserialize(next.data());
343 Group group = groupService.getGroup(deviceId, key);
344 if (group == null) {
345 log.warn("The group left!");
346 fail(fwd, ObjectiveError.GROUPMISSING);
347 return Collections.emptySet();
348 }
349 tb.group(group.id());
alshabib2a441c62015-04-13 18:39:38 -0700350 }
351
alshabibd17abc22015-04-21 18:26:35 -0700352 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
353 .fromApp(fwd.appId())
354 .withPriority(fwd.priority())
355 .forDevice(deviceId)
356 .withSelector(filteredSelector)
sanghodde53d12015-04-30 10:34:41 -0700357 .withTreatment(tb.build());
alshabibd17abc22015-04-21 18:26:35 -0700358
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500359 ruleBuilder = processSpecificRoutingRule(ruleBuilder);
360
alshabibd17abc22015-04-21 18:26:35 -0700361 if (fwd.permanent()) {
362 ruleBuilder.makePermanent();
363 } else {
364 ruleBuilder.makeTemporary(fwd.timeout());
365 }
366
alshabibd17abc22015-04-21 18:26:35 -0700367 return Collections.singletonList(ruleBuilder.build());
alshabib2a441c62015-04-13 18:39:38 -0700368 }
369
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500370 /* Hook for modifying Route traffic treatment */
371 protected TrafficTreatment.Builder processSpecificRoutingTreatment() {
372 return DefaultTrafficTreatment.builder();
373 }
374
375 /* Hook for modifying Route flow rule */
376 protected FlowRule.Builder processSpecificRoutingRule(FlowRule.Builder rb) {
377 return rb.forTable(FIB_TABLE);
378 }
379
380 protected Collection<FlowRule> processSpecificSwitch(ForwardingObjective fwd) {
381 /* Not supported by until CorsaPipelineV3 */
382 log.warn("Vlan switching not supported in ovs-corsa driver");
383 fail(fwd, ObjectiveError.UNSUPPORTED);
384 return Collections.emptySet();
385 }
386
387 protected void processFilter(FilteringObjective filt, boolean install,
alshabib910aff12015-04-09 16:55:57 -0700388 ApplicationId applicationId) {
Saurav Dascfd63d22015-04-13 16:08:24 -0700389 // This driver only processes filtering criteria defined with switch
390 // ports as the key
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700391 PortCriterion p;
Saurav Dascfd63d22015-04-13 16:08:24 -0700392 if (!filt.key().equals(Criteria.dummy()) &&
393 filt.key().type() == Criterion.Type.IN_PORT) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700394 p = (PortCriterion) filt.key();
Saurav Dascfd63d22015-04-13 16:08:24 -0700395 } else {
396 log.warn("No key defined in filtering objective from app: {}. Not"
397 + "processing filtering objective", applicationId);
alshabib2a441c62015-04-13 18:39:38 -0700398 fail(filt, ObjectiveError.UNKNOWN);
399 return;
alshabib910aff12015-04-09 16:55:57 -0700400 }
Saurav Dascfd63d22015-04-13 16:08:24 -0700401 // convert filtering conditions for switch-intfs into flowrules
402 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
403 for (Criterion c : filt.conditions()) {
404 if (c.type() == Criterion.Type.ETH_DST) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700405 EthCriterion e = (EthCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700406 log.debug("adding rule for MAC: {}", e.mac());
407 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
408 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
409 selector.matchEthDst(e.mac());
alshabibd17abc22015-04-21 18:26:35 -0700410 treatment.transition(VLAN_MPLS_TABLE);
411 FlowRule rule = DefaultFlowRule.builder()
412 .forDevice(deviceId)
413 .withSelector(selector.build())
414 .withTreatment(treatment.build())
415 .withPriority(CONTROLLER_PRIORITY)
416 .fromApp(applicationId)
417 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700418 .forTable(MAC_TABLE).build();
Saurav Dascfd63d22015-04-13 16:08:24 -0700419 ops = install ? ops.add(rule) : ops.remove(rule);
420 } else if (c.type() == Criterion.Type.VLAN_VID) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700421 VlanIdCriterion v = (VlanIdCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700422 log.debug("adding rule for VLAN: {}", v.vlanId());
423 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
424 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
425 selector.matchVlanId(v.vlanId());
426 selector.matchInPort(p.port());
alshabibd17abc22015-04-21 18:26:35 -0700427 treatment.transition(ETHER_TABLE);
Saurav Dascfd63d22015-04-13 16:08:24 -0700428 treatment.deferred().popVlan();
alshabibd17abc22015-04-21 18:26:35 -0700429 FlowRule rule = DefaultFlowRule.builder()
430 .forDevice(deviceId)
431 .withSelector(selector.build())
432 .withTreatment(treatment.build())
433 .withPriority(CONTROLLER_PRIORITY)
434 .fromApp(applicationId)
435 .makePermanent()
436 .forTable(VLAN_TABLE).build();
Saurav Dascfd63d22015-04-13 16:08:24 -0700437 ops = install ? ops.add(rule) : ops.remove(rule);
438 } else if (c.type() == Criterion.Type.IPV4_DST) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700439 IPCriterion ip = (IPCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700440 log.debug("adding rule for IP: {}", ip.ip());
441 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
442 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
443 selector.matchEthType(Ethernet.TYPE_IPV4);
444 selector.matchIPDst(ip.ip());
alshabibd17abc22015-04-21 18:26:35 -0700445 treatment.transition(LOCAL_TABLE);
446 FlowRule rule = DefaultFlowRule.builder()
447 .forDevice(deviceId)
448 .withSelector(selector.build())
449 .withTreatment(treatment.build())
450 .withPriority(HIGHEST_PRIORITY)
451 .fromApp(applicationId)
452 .makePermanent()
453 .forTable(FIB_TABLE).build();
454
Saurav Dascfd63d22015-04-13 16:08:24 -0700455 ops = install ? ops.add(rule) : ops.remove(rule);
456 } else {
457 log.warn("Driver does not currently process filtering condition"
458 + " of type: {}", c.type());
alshabib2a441c62015-04-13 18:39:38 -0700459 fail(filt, ObjectiveError.UNSUPPORTED);
Saurav Dascfd63d22015-04-13 16:08:24 -0700460 }
461 }
462 // apply filtering flow rules
463 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
464 @Override
465 public void onSuccess(FlowRuleOperations ops) {
alshabib2a441c62015-04-13 18:39:38 -0700466 pass(filt);
Saurav Das3ea46622015-04-22 14:01:34 -0700467 log.info("Applied filtering rules");
Saurav Dascfd63d22015-04-13 16:08:24 -0700468 }
469
470 @Override
471 public void onError(FlowRuleOperations ops) {
alshabib2a441c62015-04-13 18:39:38 -0700472 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Saurav Das3ea46622015-04-22 14:01:34 -0700473 log.info("Failed to apply filtering rules");
Saurav Dascfd63d22015-04-13 16:08:24 -0700474 }
475 }));
alshabibaebe7752015-04-07 17:45:42 -0700476 }
477
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500478 protected void pass(Objective obj) {
alshabib2a441c62015-04-13 18:39:38 -0700479 if (obj.context().isPresent()) {
480 obj.context().get().onSuccess(obj);
481 }
alshabibaebe7752015-04-07 17:45:42 -0700482 }
483
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500484 protected void fail(Objective obj, ObjectiveError error) {
alshabib2a441c62015-04-13 18:39:38 -0700485 if (obj.context().isPresent()) {
486 obj.context().get().onError(obj, error);
487 }
alshabibaebe7752015-04-07 17:45:42 -0700488 }
489
Jonathan Gravel8c9f7bc2015-12-03 15:46:20 -0500490 protected void initializePipeline() {
Saurav Das3ea46622015-04-22 14:01:34 -0700491 processMacTable(true);
492 processVlanMplsTable(true);
493 processVlanTable(true);
494 processEtherTable(true);
495 processCosTable(true);
496 processFibTable(true);
497 processLocalTable(true);
alshabibaebe7752015-04-07 17:45:42 -0700498 }
499
Saurav Das3ea46622015-04-22 14:01:34 -0700500 private void processMacTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700501 TrafficSelector.Builder selector;
502 TrafficTreatment.Builder treatment;
503
504 // Bcast rule
505 selector = DefaultTrafficSelector.builder();
506 treatment = DefaultTrafficTreatment.builder();
507
508 selector.matchEthDst(MacAddress.BROADCAST);
alshabibd17abc22015-04-21 18:26:35 -0700509 treatment.transition(VLAN_MPLS_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700510
alshabibd17abc22015-04-21 18:26:35 -0700511 FlowRule rule = DefaultFlowRule.builder()
512 .forDevice(deviceId)
513 .withSelector(selector.build())
514 .withTreatment(treatment.build())
515 .withPriority(CONTROLLER_PRIORITY)
516 .fromApp(appId)
517 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700518 .forTable(MAC_TABLE).build();
alshabibd17abc22015-04-21 18:26:35 -0700519
alshabibaebe7752015-04-07 17:45:42 -0700520
521 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
522
523 ops = install ? ops.add(rule) : ops.remove(rule);
524
525
alshabibaebe7752015-04-07 17:45:42 -0700526 //Drop rule
527 selector = DefaultTrafficSelector.builder();
528 treatment = DefaultTrafficTreatment.builder();
529
530 treatment.drop();
531
alshabibd17abc22015-04-21 18:26:35 -0700532 rule = DefaultFlowRule.builder()
533 .forDevice(deviceId)
534 .withSelector(selector.build())
535 .withTreatment(treatment.build())
536 .withPriority(DROP_PRIORITY)
537 .fromApp(appId)
538 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700539 .forTable(MAC_TABLE).build();
alshabibd17abc22015-04-21 18:26:35 -0700540
alshabibaebe7752015-04-07 17:45:42 -0700541
542 ops = install ? ops.add(rule) : ops.remove(rule);
543
544 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
545 @Override
546 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700547 log.info("Provisioned mac table");
alshabibaebe7752015-04-07 17:45:42 -0700548 }
549
550 @Override
551 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700552 log.info("Failed to provision mac table");
alshabibaebe7752015-04-07 17:45:42 -0700553 }
554 }));
555
556 }
557
Saurav Dasd8b97002015-05-14 23:42:49 -0700558 protected void processVlanMplsTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700559 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
560 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
561 .builder();
562 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
563 FlowRule rule;
564
565 selector.matchVlanId(VlanId.ANY);
alshabibd17abc22015-04-21 18:26:35 -0700566 treatment.transition(VLAN_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700567
alshabibd17abc22015-04-21 18:26:35 -0700568 rule = DefaultFlowRule.builder()
569 .forDevice(deviceId)
570 .withSelector(selector.build())
571 .withTreatment(treatment.build())
572 .withPriority(CONTROLLER_PRIORITY)
573 .fromApp(appId)
574 .makePermanent()
575 .forTable(VLAN_MPLS_TABLE).build();
576
alshabibaebe7752015-04-07 17:45:42 -0700577
578 ops = install ? ops.add(rule) : ops.remove(rule);
579
580 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
581 @Override
582 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700583 log.info("Provisioned vlan/mpls table");
alshabibaebe7752015-04-07 17:45:42 -0700584 }
585
586 @Override
587 public void onError(FlowRuleOperations ops) {
588 log.info(
Saurav Das3ea46622015-04-22 14:01:34 -0700589 "Failed to provision vlan/mpls table");
alshabibaebe7752015-04-07 17:45:42 -0700590 }
591 }));
592
593 }
594
Saurav Das3ea46622015-04-22 14:01:34 -0700595 private void processVlanTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700596 TrafficSelector.Builder selector;
597 TrafficTreatment.Builder treatment;
598 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
599 FlowRule rule;
600
601
alshabibaebe7752015-04-07 17:45:42 -0700602 //Drop rule
603 selector = DefaultTrafficSelector.builder();
604 treatment = DefaultTrafficTreatment.builder();
605
606 treatment.drop();
607
alshabibd17abc22015-04-21 18:26:35 -0700608 rule = DefaultFlowRule.builder()
609 .forDevice(deviceId)
610 .withSelector(selector.build())
611 .withTreatment(treatment.build())
612 .withPriority(DROP_PRIORITY)
613 .fromApp(appId)
614 .makePermanent()
615 .forTable(VLAN_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700616
617 ops = install ? ops.add(rule) : ops.remove(rule);
618
619 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
620 @Override
621 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700622 log.info("Provisioned vlan table");
alshabibaebe7752015-04-07 17:45:42 -0700623 }
624
625 @Override
626 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700627 log.info("Failed to provision vlan table");
alshabibaebe7752015-04-07 17:45:42 -0700628 }
629 }));
630 }
631
Saurav Das3ea46622015-04-22 14:01:34 -0700632 private void processEtherTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700633 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
634 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
635 .builder();
636 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
637 FlowRule rule;
638
639 selector.matchEthType(Ethernet.TYPE_ARP);
640 treatment.punt();
641
alshabibd17abc22015-04-21 18:26:35 -0700642 rule = DefaultFlowRule.builder()
643 .forDevice(deviceId)
644 .withSelector(selector.build())
645 .withTreatment(treatment.build())
646 .withPriority(CONTROLLER_PRIORITY)
647 .fromApp(appId)
648 .makePermanent()
649 .forTable(ETHER_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700650
651 ops = install ? ops.add(rule) : ops.remove(rule);
652
653 selector = DefaultTrafficSelector.builder();
654 treatment = DefaultTrafficTreatment.builder();
655
656 selector.matchEthType(Ethernet.TYPE_IPV4);
alshabibd17abc22015-04-21 18:26:35 -0700657 treatment.transition(COS_MAP_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700658
alshabibd17abc22015-04-21 18:26:35 -0700659 rule = DefaultFlowRule.builder()
660 .forDevice(deviceId)
661 .withPriority(CONTROLLER_PRIORITY)
662 .withSelector(selector.build())
663 .withTreatment(treatment.build())
664 .fromApp(appId)
665 .makePermanent()
666 .forTable(ETHER_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700667
668 ops = install ? ops.add(rule) : ops.remove(rule);
669
670 //Drop rule
671 selector = DefaultTrafficSelector.builder();
672 treatment = DefaultTrafficTreatment.builder();
673
674 treatment.drop();
675
alshabibd17abc22015-04-21 18:26:35 -0700676 rule = DefaultFlowRule.builder()
677 .forDevice(deviceId)
678 .withSelector(selector.build())
679 .withTreatment(treatment.build())
680 .withPriority(DROP_PRIORITY)
681 .fromApp(appId)
682 .makePermanent()
683 .forTable(ETHER_TABLE).build();
684
alshabibaebe7752015-04-07 17:45:42 -0700685
686 ops = install ? ops.add(rule) : ops.remove(rule);
687
688 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
689 @Override
690 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700691 log.info("Provisioned ether table");
alshabibaebe7752015-04-07 17:45:42 -0700692 }
693
694 @Override
695 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700696 log.info("Failed to provision ether table");
alshabibaebe7752015-04-07 17:45:42 -0700697 }
698 }));
699
700 }
701
Saurav Das3ea46622015-04-22 14:01:34 -0700702 private void processCosTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700703 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
704 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
705 .builder();
706 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
707 FlowRule rule;
708
alshabibd17abc22015-04-21 18:26:35 -0700709 treatment.transition(FIB_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700710
alshabibd17abc22015-04-21 18:26:35 -0700711 rule = DefaultFlowRule.builder()
712 .forDevice(deviceId)
713 .withSelector(selector.build())
714 .withTreatment(treatment.build())
715 .withPriority(DROP_PRIORITY)
716 .fromApp(appId)
717 .makePermanent()
718 .forTable(COS_MAP_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700719
720 ops = install ? ops.add(rule) : ops.remove(rule);
721
722 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
723 @Override
724 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700725 log.info("Provisioned cos table");
alshabibaebe7752015-04-07 17:45:42 -0700726 }
727
728 @Override
729 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700730 log.info("Failed to provision cos table");
alshabibaebe7752015-04-07 17:45:42 -0700731 }
732 }));
733
734 }
735
Saurav Das3ea46622015-04-22 14:01:34 -0700736 private void processFibTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700737 TrafficSelector.Builder selector;
738 TrafficTreatment.Builder treatment;
739 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
740 FlowRule rule;
741
742 //Drop rule
743 selector = DefaultTrafficSelector.builder();
744 treatment = DefaultTrafficTreatment.builder();
745
746 treatment.drop();
747
alshabibd17abc22015-04-21 18:26:35 -0700748 rule = DefaultFlowRule.builder()
749 .forDevice(deviceId)
750 .withSelector(selector.build())
751 .withTreatment(treatment.build())
752 .withPriority(DROP_PRIORITY)
753 .fromApp(appId)
754 .makePermanent()
755 .forTable(FIB_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700756
757 ops = install ? ops.add(rule) : ops.remove(rule);
758
759 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
760 @Override
761 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700762 log.info("Provisioned FIB table");
alshabibaebe7752015-04-07 17:45:42 -0700763 }
764
765 @Override
766 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700767 log.info("Failed to provision FIB table");
alshabibaebe7752015-04-07 17:45:42 -0700768 }
769 }));
770 }
771
Saurav Das3ea46622015-04-22 14:01:34 -0700772 private void processLocalTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700773 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
774 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
775 .builder();
776 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
777 FlowRule rule;
778
779 treatment.punt();
780
alshabibd17abc22015-04-21 18:26:35 -0700781 rule = DefaultFlowRule.builder()
782 .forDevice(deviceId)
783 .withSelector(selector.build())
784 .withTreatment(treatment.build())
785 .withPriority(CONTROLLER_PRIORITY)
786 .fromApp(appId)
787 .makePermanent()
788 .forTable(LOCAL_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700789
790 ops = install ? ops.add(rule) : ops.remove(rule);
791
792 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
793 @Override
794 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700795 log.info("Provisioned Local table");
alshabibaebe7752015-04-07 17:45:42 -0700796 }
797
798 @Override
799 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700800 log.info("Failed to provision Local table");
alshabibaebe7752015-04-07 17:45:42 -0700801 }
802 }));
803 }
804
alshabib2a441c62015-04-13 18:39:38 -0700805 private class InnerGroupListener implements GroupListener {
806 @Override
807 public void event(GroupEvent event) {
808 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
809 GroupKey key = event.subject().appCookie();
810
811 NextObjective obj = pendingGroups.getIfPresent(key);
812 if (obj != null) {
813 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
814 pass(obj);
815 pendingGroups.invalidate(key);
816 }
817 }
818 }
819 }
820
821
822 private class GroupChecker implements Runnable {
823
824 @Override
825 public void run() {
826 Set<GroupKey> keys = pendingGroups.asMap().keySet().stream()
827 .filter(key -> groupService.getGroup(deviceId, key) != null)
828 .collect(Collectors.toSet());
829
830 keys.stream().forEach(key -> {
831 NextObjective obj = pendingGroups.getIfPresent(key);
832 if (obj == null) {
833 return;
834 }
835 pass(obj);
836 pendingGroups.invalidate(key);
Saurav Dasbd7f7422015-04-23 16:31:47 -0700837 log.info("Heard back from group service for group {}. "
838 + "Applying pending forwarding objectives", obj.id());
alshabib2a441c62015-04-13 18:39:38 -0700839 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
840 });
841 }
842 }
843
844 private class CorsaGroup implements NextGroup {
845
846 private final GroupKey key;
847
848 public CorsaGroup(GroupKey key) {
849 this.key = key;
850 }
851
Saurav Dase3274c82015-05-24 17:21:56 -0700852 @SuppressWarnings("unused")
alshabib2a441c62015-04-13 18:39:38 -0700853 public GroupKey key() {
854 return key;
855 }
856
857 @Override
858 public byte[] data() {
859 return appKryo.serialize(key);
860 }
861
862 }
alshabibaebe7752015-04-07 17:45:42 -0700863}