blob: a92dbe11ead9507d8e63bed5295058f606d5ea75 [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
320 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
321
322 GroupKey key = appKryo.deserialize(next.data());
323
324 Group group = groupService.getGroup(deviceId, key);
325
326 if (group == null) {
327 log.warn("The group left!");
328 fail(fwd, ObjectiveError.GROUPMISSING);
329 return Collections.emptySet();
330 }
331
332 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
333 .group(group.id())
334 .build();
335
alshabibd17abc22015-04-21 18:26:35 -0700336 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
337 .fromApp(fwd.appId())
338 .withPriority(fwd.priority())
339 .forDevice(deviceId)
340 .withSelector(filteredSelector)
341 .withTreatment(treatment);
342
343 if (fwd.permanent()) {
344 ruleBuilder.makePermanent();
345 } else {
346 ruleBuilder.makeTemporary(fwd.timeout());
347 }
348
349 ruleBuilder.forTable(FIB_TABLE);
350
351
352 return Collections.singletonList(ruleBuilder.build());
alshabib2a441c62015-04-13 18:39:38 -0700353
354 }
355
356 private void processFilter(FilteringObjective filt, boolean install,
alshabib910aff12015-04-09 16:55:57 -0700357 ApplicationId applicationId) {
Saurav Dascfd63d22015-04-13 16:08:24 -0700358 // This driver only processes filtering criteria defined with switch
359 // ports as the key
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700360 PortCriterion p;
Saurav Dascfd63d22015-04-13 16:08:24 -0700361 if (!filt.key().equals(Criteria.dummy()) &&
362 filt.key().type() == Criterion.Type.IN_PORT) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700363 p = (PortCriterion) filt.key();
Saurav Dascfd63d22015-04-13 16:08:24 -0700364 } else {
365 log.warn("No key defined in filtering objective from app: {}. Not"
366 + "processing filtering objective", applicationId);
alshabib2a441c62015-04-13 18:39:38 -0700367 fail(filt, ObjectiveError.UNKNOWN);
368 return;
alshabib910aff12015-04-09 16:55:57 -0700369 }
Saurav Dascfd63d22015-04-13 16:08:24 -0700370 // convert filtering conditions for switch-intfs into flowrules
371 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
372 for (Criterion c : filt.conditions()) {
373 if (c.type() == Criterion.Type.ETH_DST) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700374 EthCriterion e = (EthCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700375 log.debug("adding rule for MAC: {}", e.mac());
376 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
377 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
378 selector.matchEthDst(e.mac());
alshabibd17abc22015-04-21 18:26:35 -0700379 treatment.transition(VLAN_MPLS_TABLE);
380 FlowRule rule = DefaultFlowRule.builder()
381 .forDevice(deviceId)
382 .withSelector(selector.build())
383 .withTreatment(treatment.build())
384 .withPriority(CONTROLLER_PRIORITY)
385 .fromApp(applicationId)
386 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700387 .forTable(MAC_TABLE).build();
Saurav Dascfd63d22015-04-13 16:08:24 -0700388 ops = install ? ops.add(rule) : ops.remove(rule);
389 } else if (c.type() == Criterion.Type.VLAN_VID) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700390 VlanIdCriterion v = (VlanIdCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700391 log.debug("adding rule for VLAN: {}", v.vlanId());
392 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
393 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
394 selector.matchVlanId(v.vlanId());
395 selector.matchInPort(p.port());
alshabibd17abc22015-04-21 18:26:35 -0700396 treatment.transition(ETHER_TABLE);
Saurav Dascfd63d22015-04-13 16:08:24 -0700397 treatment.deferred().popVlan();
alshabibd17abc22015-04-21 18:26:35 -0700398 FlowRule rule = DefaultFlowRule.builder()
399 .forDevice(deviceId)
400 .withSelector(selector.build())
401 .withTreatment(treatment.build())
402 .withPriority(CONTROLLER_PRIORITY)
403 .fromApp(applicationId)
404 .makePermanent()
405 .forTable(VLAN_TABLE).build();
Saurav Dascfd63d22015-04-13 16:08:24 -0700406 ops = install ? ops.add(rule) : ops.remove(rule);
407 } else if (c.type() == Criterion.Type.IPV4_DST) {
Sho SHIMIZUfbc80e52015-04-28 10:41:58 -0700408 IPCriterion ip = (IPCriterion) c;
Saurav Dascfd63d22015-04-13 16:08:24 -0700409 log.debug("adding rule for IP: {}", ip.ip());
410 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
411 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
412 selector.matchEthType(Ethernet.TYPE_IPV4);
413 selector.matchIPDst(ip.ip());
alshabibd17abc22015-04-21 18:26:35 -0700414 treatment.transition(LOCAL_TABLE);
415 FlowRule rule = DefaultFlowRule.builder()
416 .forDevice(deviceId)
417 .withSelector(selector.build())
418 .withTreatment(treatment.build())
419 .withPriority(HIGHEST_PRIORITY)
420 .fromApp(applicationId)
421 .makePermanent()
422 .forTable(FIB_TABLE).build();
423
Saurav Dascfd63d22015-04-13 16:08:24 -0700424 ops = install ? ops.add(rule) : ops.remove(rule);
425 } else {
426 log.warn("Driver does not currently process filtering condition"
427 + " of type: {}", c.type());
alshabib2a441c62015-04-13 18:39:38 -0700428 fail(filt, ObjectiveError.UNSUPPORTED);
Saurav Dascfd63d22015-04-13 16:08:24 -0700429 }
430 }
431 // apply filtering flow rules
432 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
433 @Override
434 public void onSuccess(FlowRuleOperations ops) {
alshabib2a441c62015-04-13 18:39:38 -0700435 pass(filt);
Saurav Das3ea46622015-04-22 14:01:34 -0700436 log.info("Applied filtering rules");
Saurav Dascfd63d22015-04-13 16:08:24 -0700437 }
438
439 @Override
440 public void onError(FlowRuleOperations ops) {
alshabib2a441c62015-04-13 18:39:38 -0700441 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Saurav Das3ea46622015-04-22 14:01:34 -0700442 log.info("Failed to apply filtering rules");
Saurav Dascfd63d22015-04-13 16:08:24 -0700443 }
444 }));
alshabibaebe7752015-04-07 17:45:42 -0700445 }
446
alshabib2a441c62015-04-13 18:39:38 -0700447 private void pass(Objective obj) {
448 if (obj.context().isPresent()) {
449 obj.context().get().onSuccess(obj);
450 }
alshabibaebe7752015-04-07 17:45:42 -0700451 }
452
alshabib2a441c62015-04-13 18:39:38 -0700453 private void fail(Objective obj, ObjectiveError error) {
454 if (obj.context().isPresent()) {
455 obj.context().get().onError(obj, error);
456 }
alshabibaebe7752015-04-07 17:45:42 -0700457 }
458
alshabibaebe7752015-04-07 17:45:42 -0700459 private void pushDefaultRules() {
Saurav Das3ea46622015-04-22 14:01:34 -0700460 processMacTable(true);
461 processVlanMplsTable(true);
462 processVlanTable(true);
463 processEtherTable(true);
464 processCosTable(true);
465 processFibTable(true);
466 processLocalTable(true);
alshabibaebe7752015-04-07 17:45:42 -0700467 }
468
Saurav Das3ea46622015-04-22 14:01:34 -0700469 private void processMacTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700470 TrafficSelector.Builder selector;
471 TrafficTreatment.Builder treatment;
472
473 // Bcast rule
474 selector = DefaultTrafficSelector.builder();
475 treatment = DefaultTrafficTreatment.builder();
476
477 selector.matchEthDst(MacAddress.BROADCAST);
alshabibd17abc22015-04-21 18:26:35 -0700478 treatment.transition(VLAN_MPLS_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700479
alshabibd17abc22015-04-21 18:26:35 -0700480 FlowRule rule = DefaultFlowRule.builder()
481 .forDevice(deviceId)
482 .withSelector(selector.build())
483 .withTreatment(treatment.build())
484 .withPriority(CONTROLLER_PRIORITY)
485 .fromApp(appId)
486 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700487 .forTable(MAC_TABLE).build();
alshabibd17abc22015-04-21 18:26:35 -0700488
alshabibaebe7752015-04-07 17:45:42 -0700489
490 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
491
492 ops = install ? ops.add(rule) : ops.remove(rule);
493
494
alshabibaebe7752015-04-07 17:45:42 -0700495 //Drop rule
496 selector = DefaultTrafficSelector.builder();
497 treatment = DefaultTrafficTreatment.builder();
498
499 treatment.drop();
500
alshabibd17abc22015-04-21 18:26:35 -0700501 rule = DefaultFlowRule.builder()
502 .forDevice(deviceId)
503 .withSelector(selector.build())
504 .withTreatment(treatment.build())
505 .withPriority(DROP_PRIORITY)
506 .fromApp(appId)
507 .makePermanent()
Saurav Das3ea46622015-04-22 14:01:34 -0700508 .forTable(MAC_TABLE).build();
alshabibd17abc22015-04-21 18:26:35 -0700509
alshabibaebe7752015-04-07 17:45:42 -0700510
511 ops = install ? ops.add(rule) : ops.remove(rule);
512
513 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
514 @Override
515 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700516 log.info("Provisioned mac table");
alshabibaebe7752015-04-07 17:45:42 -0700517 }
518
519 @Override
520 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700521 log.info("Failed to provision mac table");
alshabibaebe7752015-04-07 17:45:42 -0700522 }
523 }));
524
525 }
526
Saurav Das3ea46622015-04-22 14:01:34 -0700527 private void processVlanMplsTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700528 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
529 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
530 .builder();
531 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
532 FlowRule rule;
533
534 selector.matchVlanId(VlanId.ANY);
alshabibd17abc22015-04-21 18:26:35 -0700535 treatment.transition(VLAN_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700536
alshabibd17abc22015-04-21 18:26:35 -0700537 rule = DefaultFlowRule.builder()
538 .forDevice(deviceId)
539 .withSelector(selector.build())
540 .withTreatment(treatment.build())
541 .withPriority(CONTROLLER_PRIORITY)
542 .fromApp(appId)
543 .makePermanent()
544 .forTable(VLAN_MPLS_TABLE).build();
545
alshabibaebe7752015-04-07 17:45:42 -0700546
547 ops = install ? ops.add(rule) : ops.remove(rule);
548
549 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
550 @Override
551 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700552 log.info("Provisioned vlan/mpls table");
alshabibaebe7752015-04-07 17:45:42 -0700553 }
554
555 @Override
556 public void onError(FlowRuleOperations ops) {
557 log.info(
Saurav Das3ea46622015-04-22 14:01:34 -0700558 "Failed to provision vlan/mpls table");
alshabibaebe7752015-04-07 17:45:42 -0700559 }
560 }));
561
562 }
563
Saurav Das3ea46622015-04-22 14:01:34 -0700564 private void processVlanTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700565 TrafficSelector.Builder selector;
566 TrafficTreatment.Builder treatment;
567 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
568 FlowRule rule;
569
570
alshabibaebe7752015-04-07 17:45:42 -0700571 //Drop rule
572 selector = DefaultTrafficSelector.builder();
573 treatment = DefaultTrafficTreatment.builder();
574
575 treatment.drop();
576
alshabibd17abc22015-04-21 18:26:35 -0700577 rule = DefaultFlowRule.builder()
578 .forDevice(deviceId)
579 .withSelector(selector.build())
580 .withTreatment(treatment.build())
581 .withPriority(DROP_PRIORITY)
582 .fromApp(appId)
583 .makePermanent()
584 .forTable(VLAN_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700585
586 ops = install ? ops.add(rule) : ops.remove(rule);
587
588 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
589 @Override
590 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700591 log.info("Provisioned vlan table");
alshabibaebe7752015-04-07 17:45:42 -0700592 }
593
594 @Override
595 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700596 log.info("Failed to provision vlan table");
alshabibaebe7752015-04-07 17:45:42 -0700597 }
598 }));
599 }
600
Saurav Das3ea46622015-04-22 14:01:34 -0700601 private void processEtherTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700602 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
603 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
604 .builder();
605 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
606 FlowRule rule;
607
608 selector.matchEthType(Ethernet.TYPE_ARP);
609 treatment.punt();
610
alshabibd17abc22015-04-21 18:26:35 -0700611 rule = DefaultFlowRule.builder()
612 .forDevice(deviceId)
613 .withSelector(selector.build())
614 .withTreatment(treatment.build())
615 .withPriority(CONTROLLER_PRIORITY)
616 .fromApp(appId)
617 .makePermanent()
618 .forTable(ETHER_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700619
620 ops = install ? ops.add(rule) : ops.remove(rule);
621
622 selector = DefaultTrafficSelector.builder();
623 treatment = DefaultTrafficTreatment.builder();
624
625 selector.matchEthType(Ethernet.TYPE_IPV4);
alshabibd17abc22015-04-21 18:26:35 -0700626 treatment.transition(COS_MAP_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700627
alshabibd17abc22015-04-21 18:26:35 -0700628 rule = DefaultFlowRule.builder()
629 .forDevice(deviceId)
630 .withPriority(CONTROLLER_PRIORITY)
631 .withSelector(selector.build())
632 .withTreatment(treatment.build())
633 .fromApp(appId)
634 .makePermanent()
635 .forTable(ETHER_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700636
637 ops = install ? ops.add(rule) : ops.remove(rule);
638
639 //Drop rule
640 selector = DefaultTrafficSelector.builder();
641 treatment = DefaultTrafficTreatment.builder();
642
643 treatment.drop();
644
alshabibd17abc22015-04-21 18:26:35 -0700645 rule = DefaultFlowRule.builder()
646 .forDevice(deviceId)
647 .withSelector(selector.build())
648 .withTreatment(treatment.build())
649 .withPriority(DROP_PRIORITY)
650 .fromApp(appId)
651 .makePermanent()
652 .forTable(ETHER_TABLE).build();
653
alshabibaebe7752015-04-07 17:45:42 -0700654
655 ops = install ? ops.add(rule) : ops.remove(rule);
656
657 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
658 @Override
659 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700660 log.info("Provisioned ether table");
alshabibaebe7752015-04-07 17:45:42 -0700661 }
662
663 @Override
664 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700665 log.info("Failed to provision ether table");
alshabibaebe7752015-04-07 17:45:42 -0700666 }
667 }));
668
669 }
670
Saurav Das3ea46622015-04-22 14:01:34 -0700671 private void processCosTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700672 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
673 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
674 .builder();
675 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
676 FlowRule rule;
677
alshabibd17abc22015-04-21 18:26:35 -0700678 treatment.transition(FIB_TABLE);
alshabibaebe7752015-04-07 17:45:42 -0700679
alshabibd17abc22015-04-21 18:26:35 -0700680 rule = DefaultFlowRule.builder()
681 .forDevice(deviceId)
682 .withSelector(selector.build())
683 .withTreatment(treatment.build())
684 .withPriority(DROP_PRIORITY)
685 .fromApp(appId)
686 .makePermanent()
687 .forTable(COS_MAP_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700688
689 ops = install ? ops.add(rule) : ops.remove(rule);
690
691 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
692 @Override
693 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700694 log.info("Provisioned cos table");
alshabibaebe7752015-04-07 17:45:42 -0700695 }
696
697 @Override
698 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700699 log.info("Failed to provision cos table");
alshabibaebe7752015-04-07 17:45:42 -0700700 }
701 }));
702
703 }
704
Saurav Das3ea46622015-04-22 14:01:34 -0700705 private void processFibTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700706 TrafficSelector.Builder selector;
707 TrafficTreatment.Builder treatment;
708 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
709 FlowRule rule;
710
711 //Drop rule
712 selector = DefaultTrafficSelector.builder();
713 treatment = DefaultTrafficTreatment.builder();
714
715 treatment.drop();
716
alshabibd17abc22015-04-21 18:26:35 -0700717 rule = DefaultFlowRule.builder()
718 .forDevice(deviceId)
719 .withSelector(selector.build())
720 .withTreatment(treatment.build())
721 .withPriority(DROP_PRIORITY)
722 .fromApp(appId)
723 .makePermanent()
724 .forTable(FIB_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700725
726 ops = install ? ops.add(rule) : ops.remove(rule);
727
728 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
729 @Override
730 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700731 log.info("Provisioned FIB table");
alshabibaebe7752015-04-07 17:45:42 -0700732 }
733
734 @Override
735 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700736 log.info("Failed to provision FIB table");
alshabibaebe7752015-04-07 17:45:42 -0700737 }
738 }));
739 }
740
Saurav Das3ea46622015-04-22 14:01:34 -0700741 private void processLocalTable(boolean install) {
alshabibaebe7752015-04-07 17:45:42 -0700742 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
743 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
744 .builder();
745 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
746 FlowRule rule;
747
748 treatment.punt();
749
alshabibd17abc22015-04-21 18:26:35 -0700750 rule = DefaultFlowRule.builder()
751 .forDevice(deviceId)
752 .withSelector(selector.build())
753 .withTreatment(treatment.build())
754 .withPriority(CONTROLLER_PRIORITY)
755 .fromApp(appId)
756 .makePermanent()
757 .forTable(LOCAL_TABLE).build();
alshabibaebe7752015-04-07 17:45:42 -0700758
759 ops = install ? ops.add(rule) : ops.remove(rule);
760
761 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
762 @Override
763 public void onSuccess(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700764 log.info("Provisioned Local table");
alshabibaebe7752015-04-07 17:45:42 -0700765 }
766
767 @Override
768 public void onError(FlowRuleOperations ops) {
Saurav Das3ea46622015-04-22 14:01:34 -0700769 log.info("Failed to provision Local table");
alshabibaebe7752015-04-07 17:45:42 -0700770 }
771 }));
772 }
773
alshabib2a441c62015-04-13 18:39:38 -0700774 private class InnerGroupListener implements GroupListener {
775 @Override
776 public void event(GroupEvent event) {
777 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
778 GroupKey key = event.subject().appCookie();
779
780 NextObjective obj = pendingGroups.getIfPresent(key);
781 if (obj != null) {
782 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
783 pass(obj);
784 pendingGroups.invalidate(key);
785 }
786 }
787 }
788 }
789
790
791 private class GroupChecker implements Runnable {
792
793 @Override
794 public void run() {
795 Set<GroupKey> keys = pendingGroups.asMap().keySet().stream()
796 .filter(key -> groupService.getGroup(deviceId, key) != null)
797 .collect(Collectors.toSet());
798
799 keys.stream().forEach(key -> {
800 NextObjective obj = pendingGroups.getIfPresent(key);
801 if (obj == null) {
802 return;
803 }
804 pass(obj);
805 pendingGroups.invalidate(key);
Saurav Dasbd7f7422015-04-23 16:31:47 -0700806 log.info("Heard back from group service for group {}. "
807 + "Applying pending forwarding objectives", obj.id());
alshabib2a441c62015-04-13 18:39:38 -0700808 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
809 });
810 }
811 }
812
813 private class CorsaGroup implements NextGroup {
814
815 private final GroupKey key;
816
817 public CorsaGroup(GroupKey key) {
818 this.key = key;
819 }
820
821 public GroupKey key() {
822 return key;
823 }
824
825 @Override
826 public byte[] data() {
827 return appKryo.serialize(key);
828 }
829
830 }
alshabibaebe7752015-04-07 17:45:42 -0700831}