blob: 1620c3375e3f72bd0fe5e405d515dadf9327b495 [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;
alshabibaebe7752015-04-07 17:45:42 -070070import org.slf4j.Logger;
71
72import java.util.Collection;
alshabib2a441c62015-04-13 18:39:38 -070073import java.util.Collections;
74import java.util.Set;
75import java.util.concurrent.Executors;
76import java.util.concurrent.ScheduledExecutorService;
77import java.util.concurrent.TimeUnit;
78import java.util.stream.Collectors;
alshabibaebe7752015-04-07 17:45:42 -070079
alshabib2a441c62015-04-13 18:39:38 -070080import static org.onlab.util.Tools.groupedThreads;
alshabibaebe7752015-04-07 17:45:42 -070081import static org.slf4j.LoggerFactory.getLogger;
82
83/**
alshabib2a441c62015-04-13 18:39:38 -070084 * OpenvSwitch emulation of the Corsa pipeline handler.
alshabibaebe7752015-04-07 17:45:42 -070085 */
Thomas Vachuskafacc3f52015-04-10 08:58:36 -070086public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabibaebe7752015-04-07 17:45:42 -070087
alshabibd17abc22015-04-21 18:26:35 -070088
89
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
alshabibaebe7752015-04-07 17:45:42 -0700100 private static final int CONTROLLER_PRIORITY = 255;
101 private static final int DROP_PRIORITY = 0;
102 private static final int HIGHEST_PRIORITY = 0xffff;
103
104 private final Logger log = getLogger(getClass());
105
106 private ServiceDirectory serviceDirectory;
107 private FlowRuleService flowRuleService;
108 private CoreService coreService;
alshabib2a441c62015-04-13 18:39:38 -0700109 private GroupService groupService;
110 private FlowObjectiveStore flowObjectiveStore;
alshabibaebe7752015-04-07 17:45:42 -0700111 private DeviceId deviceId;
112 private ApplicationId appId;
113
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);
145 flowObjectiveStore = context.store();
146
147 groupService.addListener(new InnerGroupListener());
alshabibaebe7752015-04-07 17:45:42 -0700148
149 appId = coreService.registerApplication(
150 "org.onosproject.driver.OVSCorsaPipeline");
151
152 pushDefaultRules();
alshabibaebe7752015-04-07 17:45:42 -0700153 }
154
155 @Override
alshabib2a441c62015-04-13 18:39:38 -0700156 public void filter(FilteringObjective filteringObjective) {
157 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
158 processFilter(filteringObjective,
159 filteringObjective.op() == Objective.Operation.ADD,
160 filteringObjective.appId());
161 } else {
162 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
163 }
164 }
alshabib910aff12015-04-09 16:55:57 -0700165
alshabib2a441c62015-04-13 18:39:38 -0700166 @Override
167 public void forward(ForwardingObjective fwd) {
168 Collection<FlowRule> rules;
169 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
170
171 rules = processForward(fwd);
172 switch (fwd.op()) {
173 case ADD:
174 rules.stream()
175 .filter(rule -> rule != null)
176 .forEach(flowBuilder::add);
177 break;
178 case REMOVE:
179 rules.stream()
180 .filter(rule -> rule != null)
181 .forEach(flowBuilder::remove);
182 break;
183 default:
184 fail(fwd, ObjectiveError.UNKNOWN);
185 log.warn("Unknown forwarding type {}", fwd.op());
186 }
187
188
189 flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
190 @Override
191 public void onSuccess(FlowRuleOperations ops) {
192 pass(fwd);
193 }
194
195 @Override
196 public void onError(FlowRuleOperations ops) {
197 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
198 }
199 }));
alshabib910aff12015-04-09 16:55:57 -0700200
201 }
202
alshabib2a441c62015-04-13 18:39:38 -0700203 @Override
204 public void next(NextObjective nextObjective) {
205 switch (nextObjective.type()) {
206 case SIMPLE:
207 Collection<TrafficTreatment> treatments = nextObjective.next();
208 if (treatments.size() == 1) {
209 TrafficTreatment treatment = treatments.iterator().next();
210 GroupBucket bucket =
211 DefaultGroupBucket.createIndirectGroupBucket(treatment);
212 final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
213 GroupDescription groupDescription
214 = new DefaultGroupDescription(deviceId,
215 GroupDescription.Type.INDIRECT,
216 new GroupBuckets(Collections
217 .singletonList(bucket)),
218 key,
219 nextObjective.appId());
220 groupService.addGroup(groupDescription);
221 pendingGroups.put(key, nextObjective);
222 }
223 break;
224 case HASHED:
225 case BROADCAST:
226 case FAILOVER:
227 fail(nextObjective, ObjectiveError.UNSUPPORTED);
228 log.warn("Unsupported next objective type {}", nextObjective.type());
229 break;
230 default:
231 fail(nextObjective, ObjectiveError.UNKNOWN);
232 log.warn("Unknown next objective type {}", nextObjective.type());
233 }
234
235 }
236
237 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
238 switch (fwd.flag()) {
239 case SPECIFIC:
240 return processSpecific(fwd);
241 case VERSATILE:
242 return processVersatile(fwd);
243 default:
244 fail(fwd, ObjectiveError.UNKNOWN);
245 log.warn("Unknown forwarding flag {}", fwd.flag());
246 }
247 return Collections.emptySet();
248 }
249
250 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
Saurav Das3d038262015-04-23 12:36:58 -0700251 log.debug("Processing versatile forwarding objective");
252 TrafficSelector selector = fwd.selector();
253
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700254 EthTypeCriterion ethType =
255 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Saurav Das3d038262015-04-23 12:36:58 -0700256 if (ethType == null) {
257 log.error("Versatile forwarding objective must include ethType");
258 fail(fwd, ObjectiveError.UNKNOWN);
259 return Collections.emptySet();
260 }
261 if (ethType.ethType() == Ethernet.TYPE_ARP) {
262 log.warn("Driver automatically handles ARP packets by punting to controller "
263 + " from ETHER table");
264 pass(fwd);
265 return Collections.emptySet();
266 } else if (ethType.ethType() == Ethernet.TYPE_LLDP ||
267 ethType.ethType() == Ethernet.TYPE_BSN) {
268 log.warn("Driver currently does not currently handle LLDP packets");
269 fail(fwd, ObjectiveError.UNSUPPORTED);
270 return Collections.emptySet();
271 } else if (ethType.ethType() == Ethernet.TYPE_IPV4) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700272 IPCriterion ipSrc = (IPCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700273 .getCriterion(Criterion.Type.IPV4_SRC);
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700274 IPCriterion ipDst = (IPCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700275 .getCriterion(Criterion.Type.IPV4_DST);
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700276 IPProtocolCriterion ipProto = (IPProtocolCriterion) selector
Saurav Das3d038262015-04-23 12:36:58 -0700277 .getCriterion(Criterion.Type.IP_PROTO);
278 if (ipSrc != null) {
Saurav Dasbd7f7422015-04-23 16:31:47 -0700279 log.warn("Driver does not currently handle matching Src IP");
Saurav Das3d038262015-04-23 12:36:58 -0700280 fail(fwd, ObjectiveError.UNSUPPORTED);
281 return Collections.emptySet();
282 }
283 if (ipDst != null) {
284 log.error("Driver handles Dst IP matching as specific forwarding "
285 + "objective, not versatile");
286 fail(fwd, ObjectiveError.UNSUPPORTED);
287 return Collections.emptySet();
288 }
289 if (ipProto != null && ipProto.protocol() == IPv4.PROTOCOL_TCP) {
290 log.warn("Driver automatically punts all packets reaching the "
291 + "LOCAL table to the controller");
292 pass(fwd);
293 return Collections.emptySet();
294 }
295 }
296
297 log.warn("Driver does not support given versatile forwarding objective");
alshabib2a441c62015-04-13 18:39:38 -0700298 fail(fwd, ObjectiveError.UNSUPPORTED);
299 return Collections.emptySet();
300 }
301
302 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
Saurav Das3d038262015-04-23 12:36:58 -0700303 log.debug("Processing specific forwarding objective");
alshabib2a441c62015-04-13 18:39:38 -0700304 TrafficSelector selector = fwd.selector();
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700305 EthTypeCriterion ethType =
306 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
alshabib2a441c62015-04-13 18:39:38 -0700307 if (ethType == null || ethType.ethType() != Ethernet.TYPE_IPV4) {
308 fail(fwd, ObjectiveError.UNSUPPORTED);
309 return Collections.emptySet();
310 }
311
312 TrafficSelector filteredSelector =
313 DefaultTrafficSelector.builder()
314 .matchEthType(Ethernet.TYPE_IPV4)
315 .matchIPDst(
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700316 ((IPCriterion)
alshabib2a441c62015-04-13 18:39:38 -0700317 selector.getCriterion(Criterion.Type.IPV4_DST)).ip())
318 .build();
319
sanghodde53d12015-04-30 10:34:41 -0700320 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
alshabib2a441c62015-04-13 18:39:38 -0700321
sanghodde53d12015-04-30 10:34:41 -0700322 if (fwd.nextId() != null) {
323 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
324 GroupKey key = appKryo.deserialize(next.data());
325 Group group = groupService.getGroup(deviceId, key);
326 if (group == null) {
327 log.warn("The group left!");
328 fail(fwd, ObjectiveError.GROUPMISSING);
329 return Collections.emptySet();
330 }
331 tb.group(group.id());
alshabib2a441c62015-04-13 18:39:38 -0700332 }
333
alshabibd17abc22015-04-21 18:26:35 -0700334 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
335 .fromApp(fwd.appId())
336 .withPriority(fwd.priority())
337 .forDevice(deviceId)
338 .withSelector(filteredSelector)
sanghodde53d12015-04-30 10:34:41 -0700339 .withTreatment(tb.build());
alshabibd17abc22015-04-21 18:26:35 -0700340
341 if (fwd.permanent()) {
342 ruleBuilder.makePermanent();
343 } else {
344 ruleBuilder.makeTemporary(fwd.timeout());
345 }
346
347 ruleBuilder.forTable(FIB_TABLE);
348
349
350 return Collections.singletonList(ruleBuilder.build());
alshabib2a441c62015-04-13 18:39:38 -0700351
352 }
353
354 private void processFilter(FilteringObjective filt, boolean install,
alshabib910aff12015-04-09 16:55:57 -0700355 ApplicationId applicationId) {
Saurav Dascfd63d22015-04-13 16:08:24 -0700356 // This driver only processes filtering criteria defined with switch
357 // ports as the key
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700358 PortCriterion p;
Saurav Dascfd63d22015-04-13 16:08:24 -0700359 if (!filt.key().equals(Criteria.dummy()) &&
360 filt.key().type() == Criterion.Type.IN_PORT) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700361 p = (PortCriterion) filt.key();
Saurav Dascfd63d22015-04-13 16:08:24 -0700362 } else {
363 log.warn("No key defined in filtering objective from app: {}. Not"
364 + "processing filtering objective", applicationId);
alshabib2a441c62015-04-13 18:39:38 -0700365 fail(filt, ObjectiveError.UNKNOWN);
366 return;
alshabib910aff12015-04-09 16:55:57 -0700367 }
Saurav Dascfd63d22015-04-13 16:08:24 -0700368 // convert filtering conditions for switch-intfs into flowrules
369 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
370 for (Criterion c : filt.conditions()) {
371 if (c.type() == Criterion.Type.ETH_DST) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700372 EthCriterion e = (EthCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700373 log.debug("adding rule for MAC: {}", e.mac());
374 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
375 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
376 selector.matchEthDst(e.mac());
alshabibd17abc22015-04-21 18:26:35 -0700377 treatment.transition(VLAN_MPLS_TABLE);
378 FlowRule rule = DefaultFlowRule.builder()
379 .forDevice(deviceId)
380 .withSelector(selector.build())
381 .withTreatment(treatment.build())
382 .withPriority(CONTROLLER_PRIORITY)
383 .fromApp(applicationId)
384 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700385 .forTable(MAC_TABLE).build();
Saurav Dascfd63d22015-04-13 16:08:24 -0700386 ops = install ? ops.add(rule) : ops.remove(rule);
387 } else if (c.type() == Criterion.Type.VLAN_VID) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700388 VlanIdCriterion v = (VlanIdCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700389 log.debug("adding rule for VLAN: {}", v.vlanId());
390 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
391 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
392 selector.matchVlanId(v.vlanId());
393 selector.matchInPort(p.port());
alshabibd17abc22015-04-21 18:26:35 -0700394 treatment.transition(ETHER_TABLE);
Saurav Dascfd63d22015-04-13 16:08:24 -0700395 treatment.deferred().popVlan();
alshabibd17abc22015-04-21 18:26:35 -0700396 FlowRule rule = DefaultFlowRule.builder()
397 .forDevice(deviceId)
398 .withSelector(selector.build())
399 .withTreatment(treatment.build())
400 .withPriority(CONTROLLER_PRIORITY)
401 .fromApp(applicationId)
402 .makePermanent()
403 .forTable(VLAN_TABLE).build();
Saurav Dascfd63d22015-04-13 16:08:24 -0700404 ops = install ? ops.add(rule) : ops.remove(rule);
405 } else if (c.type() == Criterion.Type.IPV4_DST) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700406 IPCriterion ip = (IPCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700407 log.debug("adding rule for IP: {}", ip.ip());
408 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
409 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
410 selector.matchEthType(Ethernet.TYPE_IPV4);
411 selector.matchIPDst(ip.ip());
alshabibd17abc22015-04-21 18:26:35 -0700412 treatment.transition(LOCAL_TABLE);
413 FlowRule rule = DefaultFlowRule.builder()
414 .forDevice(deviceId)
415 .withSelector(selector.build())
416 .withTreatment(treatment.build())
417 .withPriority(HIGHEST_PRIORITY)
418 .fromApp(applicationId)
419 .makePermanent()
420 .forTable(FIB_TABLE).build();
421
Saurav Dascfd63d22015-04-13 16:08:24 -0700422 ops = install ? ops.add(rule) : ops.remove(rule);
423 } else {
424 log.warn("Driver does not currently process filtering condition"
425 + " of type: {}", c.type());
alshabib2a441c62015-04-13 18:39:38 -0700426 fail(filt, ObjectiveError.UNSUPPORTED);
Saurav Dascfd63d22015-04-13 16:08:24 -0700427 }
428 }
429 // apply filtering flow rules
430 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
431 @Override
432 public void onSuccess(FlowRuleOperations ops) {
alshabib2a441c62015-04-13 18:39:38 -0700433 pass(filt);
Saurav Das3ea46622015-04-22 14:01:34 -0700434 log.info("Applied filtering rules");
Saurav Dascfd63d22015-04-13 16:08:24 -0700435 }
436
437 @Override
438 public void onError(FlowRuleOperations ops) {
alshabib2a441c62015-04-13 18:39:38 -0700439 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Saurav Das3ea46622015-04-22 14:01:34 -0700440 log.info("Failed to apply filtering rules");
Saurav Dascfd63d22015-04-13 16:08:24 -0700441 }
442 }));
alshabibaebe7752015-04-07 17:45:42 -0700443 }
444
alshabib2a441c62015-04-13 18:39:38 -0700445 private void pass(Objective obj) {
446 if (obj.context().isPresent()) {
447 obj.context().get().onSuccess(obj);
448 }
alshabibaebe7752015-04-07 17:45:42 -0700449 }
450
alshabib2a441c62015-04-13 18:39:38 -0700451 private void fail(Objective obj, ObjectiveError error) {
452 if (obj.context().isPresent()) {
453 obj.context().get().onError(obj, error);
454 }
alshabibaebe7752015-04-07 17:45:42 -0700455 }
456
alshabibaebe7752015-04-07 17:45:42 -0700457 private void pushDefaultRules() {
Saurav Das3ea46622015-04-22 14:01:34 -0700458 processMacTable(true);
459 processVlanMplsTable(true);
460 processVlanTable(true);
461 processEtherTable(true);
462 processCosTable(true);
463 processFibTable(true);
464 processLocalTable(true);
alshabibaebe7752015-04-07 17:45:42 -0700465 }
466
Saurav Das3ea46622015-04-22 14:01:34 -0700467 private void processMacTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700468 TrafficSelector.Builder selector;
469 TrafficTreatment.Builder treatment;
470
471 // Bcast rule
472 selector = DefaultTrafficSelector.builder();
473 treatment = DefaultTrafficTreatment.builder();
474
475 selector.matchEthDst(MacAddress.BROADCAST);
alshabibd17abc22015-04-21 18:26:35 -0700476 treatment.transition(VLAN_MPLS_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700477
alshabibd17abc22015-04-21 18:26:35 -0700478 FlowRule rule = DefaultFlowRule.builder()
479 .forDevice(deviceId)
480 .withSelector(selector.build())
481 .withTreatment(treatment.build())
482 .withPriority(CONTROLLER_PRIORITY)
483 .fromApp(appId)
484 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700485 .forTable(MAC_TABLE).build();
alshabibd17abc22015-04-21 18:26:35 -0700486
alshabibaebe7752015-04-07 17:45:42 -0700487
488 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
489
490 ops = install ? ops.add(rule) : ops.remove(rule);
491
492
alshabibaebe7752015-04-07 17:45:42 -0700493 //Drop rule
494 selector = DefaultTrafficSelector.builder();
495 treatment = DefaultTrafficTreatment.builder();
496
497 treatment.drop();
498
alshabibd17abc22015-04-21 18:26:35 -0700499 rule = DefaultFlowRule.builder()
500 .forDevice(deviceId)
501 .withSelector(selector.build())
502 .withTreatment(treatment.build())
503 .withPriority(DROP_PRIORITY)
504 .fromApp(appId)
505 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700506 .forTable(MAC_TABLE).build();
alshabibd17abc22015-04-21 18:26:35 -0700507
alshabibaebe7752015-04-07 17:45:42 -0700508
509 ops = install ? ops.add(rule) : ops.remove(rule);
510
511 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
512 @Override
513 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700514 log.info("Provisioned mac table");
alshabibaebe7752015-04-07 17:45:42 -0700515 }
516
517 @Override
518 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700519 log.info("Failed to provision mac table");
alshabibaebe7752015-04-07 17:45:42 -0700520 }
521 }));
522
523 }
524
Saurav Das3ea46622015-04-22 14:01:34 -0700525 private void processVlanMplsTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700526 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
527 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
528 .builder();
529 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
530 FlowRule rule;
531
532 selector.matchVlanId(VlanId.ANY);
alshabibd17abc22015-04-21 18:26:35 -0700533 treatment.transition(VLAN_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700534
alshabibd17abc22015-04-21 18:26:35 -0700535 rule = DefaultFlowRule.builder()
536 .forDevice(deviceId)
537 .withSelector(selector.build())
538 .withTreatment(treatment.build())
539 .withPriority(CONTROLLER_PRIORITY)
540 .fromApp(appId)
541 .makePermanent()
542 .forTable(VLAN_MPLS_TABLE).build();
543
alshabibaebe7752015-04-07 17:45:42 -0700544
545 ops = install ? ops.add(rule) : ops.remove(rule);
546
547 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
548 @Override
549 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700550 log.info("Provisioned vlan/mpls table");
alshabibaebe7752015-04-07 17:45:42 -0700551 }
552
553 @Override
554 public void onError(FlowRuleOperations ops) {
555 log.info(
Saurav Das3ea46622015-04-22 14:01:34 -0700556 "Failed to provision vlan/mpls table");
alshabibaebe7752015-04-07 17:45:42 -0700557 }
558 }));
559
560 }
561
Saurav Das3ea46622015-04-22 14:01:34 -0700562 private void processVlanTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700563 TrafficSelector.Builder selector;
564 TrafficTreatment.Builder treatment;
565 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
566 FlowRule rule;
567
568
alshabibaebe7752015-04-07 17:45:42 -0700569 //Drop rule
570 selector = DefaultTrafficSelector.builder();
571 treatment = DefaultTrafficTreatment.builder();
572
573 treatment.drop();
574
alshabibd17abc22015-04-21 18:26:35 -0700575 rule = DefaultFlowRule.builder()
576 .forDevice(deviceId)
577 .withSelector(selector.build())
578 .withTreatment(treatment.build())
579 .withPriority(DROP_PRIORITY)
580 .fromApp(appId)
581 .makePermanent()
582 .forTable(VLAN_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700583
584 ops = install ? ops.add(rule) : ops.remove(rule);
585
586 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
587 @Override
588 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700589 log.info("Provisioned vlan table");
alshabibaebe7752015-04-07 17:45:42 -0700590 }
591
592 @Override
593 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700594 log.info("Failed to provision vlan table");
alshabibaebe7752015-04-07 17:45:42 -0700595 }
596 }));
597 }
598
Saurav Das3ea46622015-04-22 14:01:34 -0700599 private void processEtherTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700600 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
601 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
602 .builder();
603 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
604 FlowRule rule;
605
606 selector.matchEthType(Ethernet.TYPE_ARP);
607 treatment.punt();
608
alshabibd17abc22015-04-21 18:26:35 -0700609 rule = DefaultFlowRule.builder()
610 .forDevice(deviceId)
611 .withSelector(selector.build())
612 .withTreatment(treatment.build())
613 .withPriority(CONTROLLER_PRIORITY)
614 .fromApp(appId)
615 .makePermanent()
616 .forTable(ETHER_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700617
618 ops = install ? ops.add(rule) : ops.remove(rule);
619
620 selector = DefaultTrafficSelector.builder();
621 treatment = DefaultTrafficTreatment.builder();
622
623 selector.matchEthType(Ethernet.TYPE_IPV4);
alshabibd17abc22015-04-21 18:26:35 -0700624 treatment.transition(COS_MAP_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700625
alshabibd17abc22015-04-21 18:26:35 -0700626 rule = DefaultFlowRule.builder()
627 .forDevice(deviceId)
628 .withPriority(CONTROLLER_PRIORITY)
629 .withSelector(selector.build())
630 .withTreatment(treatment.build())
631 .fromApp(appId)
632 .makePermanent()
633 .forTable(ETHER_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700634
635 ops = install ? ops.add(rule) : ops.remove(rule);
636
637 //Drop rule
638 selector = DefaultTrafficSelector.builder();
639 treatment = DefaultTrafficTreatment.builder();
640
641 treatment.drop();
642
alshabibd17abc22015-04-21 18:26:35 -0700643 rule = DefaultFlowRule.builder()
644 .forDevice(deviceId)
645 .withSelector(selector.build())
646 .withTreatment(treatment.build())
647 .withPriority(DROP_PRIORITY)
648 .fromApp(appId)
649 .makePermanent()
650 .forTable(ETHER_TABLE).build();
651
alshabibaebe7752015-04-07 17:45:42 -0700652
653 ops = install ? ops.add(rule) : ops.remove(rule);
654
655 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
656 @Override
657 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700658 log.info("Provisioned ether table");
alshabibaebe7752015-04-07 17:45:42 -0700659 }
660
661 @Override
662 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700663 log.info("Failed to provision ether table");
alshabibaebe7752015-04-07 17:45:42 -0700664 }
665 }));
666
667 }
668
Saurav Das3ea46622015-04-22 14:01:34 -0700669 private void processCosTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700670 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
671 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
672 .builder();
673 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
674 FlowRule rule;
675
alshabibd17abc22015-04-21 18:26:35 -0700676 treatment.transition(FIB_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700677
alshabibd17abc22015-04-21 18:26:35 -0700678 rule = DefaultFlowRule.builder()
679 .forDevice(deviceId)
680 .withSelector(selector.build())
681 .withTreatment(treatment.build())
682 .withPriority(DROP_PRIORITY)
683 .fromApp(appId)
684 .makePermanent()
685 .forTable(COS_MAP_TABLE).build();
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 cos 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 cos table");
alshabibaebe7752015-04-07 17:45:42 -0700698 }
699 }));
700
701 }
702
Saurav Das3ea46622015-04-22 14:01:34 -0700703 private void processFibTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700704 TrafficSelector.Builder selector;
705 TrafficTreatment.Builder treatment;
706 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
707 FlowRule rule;
708
709 //Drop rule
710 selector = DefaultTrafficSelector.builder();
711 treatment = DefaultTrafficTreatment.builder();
712
713 treatment.drop();
714
alshabibd17abc22015-04-21 18:26:35 -0700715 rule = DefaultFlowRule.builder()
716 .forDevice(deviceId)
717 .withSelector(selector.build())
718 .withTreatment(treatment.build())
719 .withPriority(DROP_PRIORITY)
720 .fromApp(appId)
721 .makePermanent()
722 .forTable(FIB_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700723
724 ops = install ? ops.add(rule) : ops.remove(rule);
725
726 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
727 @Override
728 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700729 log.info("Provisioned FIB table");
alshabibaebe7752015-04-07 17:45:42 -0700730 }
731
732 @Override
733 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700734 log.info("Failed to provision FIB table");
alshabibaebe7752015-04-07 17:45:42 -0700735 }
736 }));
737 }
738
Saurav Das3ea46622015-04-22 14:01:34 -0700739 private void processLocalTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700740 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
741 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
742 .builder();
743 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
744 FlowRule rule;
745
746 treatment.punt();
747
alshabibd17abc22015-04-21 18:26:35 -0700748 rule = DefaultFlowRule.builder()
749 .forDevice(deviceId)
750 .withSelector(selector.build())
751 .withTreatment(treatment.build())
752 .withPriority(CONTROLLER_PRIORITY)
753 .fromApp(appId)
754 .makePermanent()
755 .forTable(LOCAL_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 Local 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 Local table");
alshabibaebe7752015-04-07 17:45:42 -0700768 }
769 }));
770 }
771
alshabib2a441c62015-04-13 18:39:38 -0700772 private class InnerGroupListener implements GroupListener {
773 @Override
774 public void event(GroupEvent event) {
775 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
776 GroupKey key = event.subject().appCookie();
777
778 NextObjective obj = pendingGroups.getIfPresent(key);
779 if (obj != null) {
780 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
781 pass(obj);
782 pendingGroups.invalidate(key);
783 }
784 }
785 }
786 }
787
788
789 private class GroupChecker implements Runnable {
790
791 @Override
792 public void run() {
793 Set<GroupKey> keys = pendingGroups.asMap().keySet().stream()
794 .filter(key -> groupService.getGroup(deviceId, key) != null)
795 .collect(Collectors.toSet());
796
797 keys.stream().forEach(key -> {
798 NextObjective obj = pendingGroups.getIfPresent(key);
799 if (obj == null) {
800 return;
801 }
802 pass(obj);
803 pendingGroups.invalidate(key);
Saurav Dasbd7f7422015-04-23 16:31:47 -0700804 log.info("Heard back from group service for group {}. "
805 + "Applying pending forwarding objectives", obj.id());
alshabib2a441c62015-04-13 18:39:38 -0700806 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
807 });
808 }
809 }
810
811 private class CorsaGroup implements NextGroup {
812
813 private final GroupKey key;
814
815 public CorsaGroup(GroupKey key) {
816 this.key = key;
817 }
818
819 public GroupKey key() {
820 return key;
821 }
822
823 @Override
824 public byte[] data() {
825 return appKryo.serialize(key);
826 }
827
828 }
alshabibaebe7752015-04-07 17:45:42 -0700829}