Saurav Das
Committed by Gerrit Code Review

First shot at Broadcom OFDPA 1.0 pipeline

Requires changes to the group description to accept groupId from callers.

Change-Id: Ic21dfe8ae7c246b7d3a6b00e8e5c986e1dc21fa0
...@@ -260,6 +260,8 @@ public class BgpRouter { ...@@ -260,6 +260,8 @@ public class BgpRouter {
260 .withFlag(ForwardingObjective.Flag.SPECIFIC); 260 .withFlag(ForwardingObjective.Flag.SPECIFIC);
261 261
262 if (nextId == null) { 262 if (nextId == null) {
263 + // Route withdraws are not specified with next hops. Generating
264 + // dummy treatment as there is no equivalent nextId info.
263 fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build()); 265 fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build());
264 } else { 266 } else {
265 fwdBuilder.nextStep(nextId); 267 fwdBuilder.nextStep(nextId);
......
...@@ -21,11 +21,11 @@ package org.onosproject.core; ...@@ -21,11 +21,11 @@ package org.onosproject.core;
21 public interface GroupId { 21 public interface GroupId {
22 22
23 /** 23 /**
24 - * Returns a group ID as short value. 24 + * Returns a group ID as an integer value.
25 * The method is not intended for use by application developers. 25 * The method is not intended for use by application developers.
26 * Return data type may change in the future release. 26 * Return data type may change in the future release.
27 * 27 *
28 - * @return a group ID as short value 28 + * @return a group ID as integer value
29 */ 29 */
30 int id(); 30 int id();
31 } 31 }
......
...@@ -36,7 +36,7 @@ public enum ObjectiveError { ...@@ -36,7 +36,7 @@ public enum ObjectiveError {
36 GROUPINSTALLATIONFAILED, 36 GROUPINSTALLATIONFAILED,
37 37
38 /** 38 /**
39 - * The group was reported as installed but is not missing. 39 + * The group was reported as installed but is missing.
40 */ 40 */
41 GROUPMISSING, 41 GROUPMISSING,
42 42
...@@ -46,6 +46,11 @@ public enum ObjectiveError { ...@@ -46,6 +46,11 @@ public enum ObjectiveError {
46 DEVICEMISSING, 46 DEVICEMISSING,
47 47
48 /** 48 /**
49 + * Incorrect Objective parameters passed in by the caller.
50 + */
51 + BADPARAMS,
52 +
53 + /**
49 * An unknown error occurred. 54 * An unknown error occurred.
50 */ 55 */
51 UNKNOWN 56 UNKNOWN
......
...@@ -32,11 +32,17 @@ public class DefaultGroupDescription implements GroupDescription { ...@@ -32,11 +32,17 @@ public class DefaultGroupDescription implements GroupDescription {
32 private final GroupKey appCookie; 32 private final GroupKey appCookie;
33 private final ApplicationId appId; 33 private final ApplicationId appId;
34 private final DeviceId deviceId; 34 private final DeviceId deviceId;
35 + private final Integer givenGroupId;
35 36
36 /** 37 /**
37 * Constructor to be used by north bound applications. 38 * Constructor to be used by north bound applications.
38 * NOTE: The caller of this subsystem MUST ensure the appCookie 39 * NOTE: The caller of this subsystem MUST ensure the appCookie
39 - * provided in this API is immutable 40 + * provided in this API is immutable.
41 + * NOTE: The caller may choose to pass in 'null' for the groupId. This is
42 + * the typical case, where the caller allows the group subsystem to choose
43 + * the groupId in a globally unique way. If the caller passes in the groupId,
44 + * the caller MUST ensure that the id is globally unique (not just unique
45 + * per device).
40 * 46 *
41 * @param deviceId device identifier 47 * @param deviceId device identifier
42 * @param type type of the group 48 * @param type type of the group
...@@ -49,11 +55,13 @@ public class DefaultGroupDescription implements GroupDescription { ...@@ -49,11 +55,13 @@ public class DefaultGroupDescription implements GroupDescription {
49 GroupDescription.Type type, 55 GroupDescription.Type type,
50 GroupBuckets buckets, 56 GroupBuckets buckets,
51 GroupKey appCookie, 57 GroupKey appCookie,
58 + Integer groupId,
52 ApplicationId appId) { 59 ApplicationId appId) {
53 this.type = checkNotNull(type); 60 this.type = checkNotNull(type);
54 this.deviceId = checkNotNull(deviceId); 61 this.deviceId = checkNotNull(deviceId);
55 this.buckets = checkNotNull(buckets); 62 this.buckets = checkNotNull(buckets);
56 this.appCookie = appCookie; 63 this.appCookie = appCookie;
64 + this.givenGroupId = groupId;
57 this.appId = appId; 65 this.appId = appId;
58 } 66 }
59 67
...@@ -70,6 +78,7 @@ public class DefaultGroupDescription implements GroupDescription { ...@@ -70,6 +78,7 @@ public class DefaultGroupDescription implements GroupDescription {
70 this.buckets = groupDesc.buckets(); 78 this.buckets = groupDesc.buckets();
71 this.appCookie = groupDesc.appCookie(); 79 this.appCookie = groupDesc.appCookie();
72 this.appId = groupDesc.appId(); 80 this.appId = groupDesc.appId();
81 + this.givenGroupId = groupDesc.givenGroupId();
73 } 82 }
74 83
75 /** 84 /**
...@@ -85,7 +94,7 @@ public class DefaultGroupDescription implements GroupDescription { ...@@ -85,7 +94,7 @@ public class DefaultGroupDescription implements GroupDescription {
85 public DefaultGroupDescription(DeviceId deviceId, 94 public DefaultGroupDescription(DeviceId deviceId,
86 GroupDescription.Type type, 95 GroupDescription.Type type,
87 GroupBuckets buckets) { 96 GroupBuckets buckets) {
88 - this(deviceId, type, buckets, null, null); 97 + this(deviceId, type, buckets, null, null, null);
89 } 98 }
90 99
91 /** 100 /**
...@@ -138,6 +147,17 @@ public class DefaultGroupDescription implements GroupDescription { ...@@ -138,6 +147,17 @@ public class DefaultGroupDescription implements GroupDescription {
138 return this.buckets; 147 return this.buckets;
139 } 148 }
140 149
150 + /**
151 + * Returns groupId passed in by application.
152 + *
153 + * @return Integer group Id passed in by caller. May be null if caller passed
154 + * in null during GroupDescription creation.
155 + */
156 + @Override
157 + public Integer givenGroupId() {
158 + return this.givenGroupId;
159 + }
160 +
141 @Override 161 @Override
142 /* 162 /*
143 * The deviceId, type and buckets are used for hash. 163 * The deviceId, type and buckets are used for hash.
...@@ -177,6 +197,7 @@ public class DefaultGroupDescription implements GroupDescription { ...@@ -177,6 +197,7 @@ public class DefaultGroupDescription implements GroupDescription {
177 .add("type", type) 197 .add("type", type)
178 .add("buckets", buckets) 198 .add("buckets", buckets)
179 .add("appId", appId) 199 .add("appId", appId)
200 + .add("givenGroupId", givenGroupId)
180 .toString(); 201 .toString();
181 } 202 }
182 } 203 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -75,6 +75,14 @@ public interface GroupDescription { ...@@ -75,6 +75,14 @@ public interface GroupDescription {
75 public GroupKey appCookie(); 75 public GroupKey appCookie();
76 76
77 /** 77 /**
78 + * Returns groupId passed in by caller.
79 + *
80 + * @return Integer group id passed in by caller. May be null if caller
81 + * passed in null to let groupService determin the group id.
82 + */
83 + public Integer givenGroupId();
84 +
85 + /**
78 * Returns group buckets of a group. 86 * Returns group buckets of a group.
79 * 87 *
80 * @return GroupBuckets immutable list of group bucket 88 * @return GroupBuckets immutable list of group bucket
......
...@@ -177,6 +177,7 @@ public class GroupManagerTest { ...@@ -177,6 +177,7 @@ public class GroupManagerTest {
177 Group.Type.SELECT, 177 Group.Type.SELECT,
178 groupBuckets, 178 groupBuckets,
179 key, 179 key,
180 + null,
180 appId); 181 appId);
181 groupService.addGroup(newGroupDesc); 182 groupService.addGroup(newGroupDesc);
182 internalProvider.validate(DID, null); 183 internalProvider.validate(DID, null);
...@@ -397,6 +398,7 @@ public class GroupManagerTest { ...@@ -397,6 +398,7 @@ public class GroupManagerTest {
397 Group.Type.SELECT, 398 Group.Type.SELECT,
398 groupBuckets, 399 groupBuckets,
399 key, 400 key,
401 + null,
400 appId); 402 appId);
401 groupService.addGroup(newGroupDesc); 403 groupService.addGroup(newGroupDesc);
402 404
......
...@@ -430,8 +430,13 @@ public class DistributedGroupStore ...@@ -430,8 +430,13 @@ public class DistributedGroupStore
430 return; 430 return;
431 } 431 }
432 432
433 - // Get a new group identifier 433 + GroupId id = null;
434 - GroupId id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId())); 434 + if (groupDesc.givenGroupId() == null) {
435 + // Get a new group identifier
436 + id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId()));
437 + } else {
438 + id = new DefaultGroupId(groupDesc.givenGroupId());
439 + }
435 // Create a group entry object 440 // Create a group entry object
436 StoredGroupEntry group = new DefaultGroup(id, groupDesc); 441 StoredGroupEntry group = new DefaultGroup(id, groupDesc);
437 // Insert the newly created group entry into key and id maps 442 // Insert the newly created group entry into key and id maps
...@@ -513,6 +518,7 @@ public class DistributedGroupStore ...@@ -513,6 +518,7 @@ public class DistributedGroupStore
513 oldGroup.type(), 518 oldGroup.type(),
514 updatedBuckets, 519 updatedBuckets,
515 newCookie, 520 newCookie,
521 + oldGroup.givenGroupId(),
516 oldGroup.appId()); 522 oldGroup.appId());
517 StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(), 523 StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(),
518 updatedGroupDesc); 524 updatedGroupDesc);
...@@ -718,6 +724,7 @@ public class DistributedGroupStore ...@@ -718,6 +724,7 @@ public class DistributedGroupStore
718 group.type(), 724 group.type(),
719 group.buckets(), 725 group.buckets(),
720 group.appCookie(), 726 group.appCookie(),
727 + group.givenGroupId(),
721 group.appId()); 728 group.appId());
722 storeGroupDescriptionInternal(tmp); 729 storeGroupDescriptionInternal(tmp);
723 getPendingGroupKeyTable(). 730 getPendingGroupKeyTable().
......
...@@ -275,8 +275,13 @@ public class SimpleGroupStore ...@@ -275,8 +275,13 @@ public class SimpleGroupStore
275 return; 275 return;
276 } 276 }
277 277
278 - // Get a new group identifier 278 + GroupId id = null;
279 - GroupId id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId())); 279 + if (groupDesc.givenGroupId() == null) {
280 + // Get a new group identifier
281 + id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId()));
282 + } else {
283 + id = new DefaultGroupId(groupDesc.givenGroupId());
284 + }
280 // Create a group entry object 285 // Create a group entry object
281 StoredGroupEntry group = new DefaultGroup(id, groupDesc); 286 StoredGroupEntry group = new DefaultGroup(id, groupDesc);
282 // Insert the newly created group entry into concurrent key and id maps 287 // Insert the newly created group entry into concurrent key and id maps
...@@ -324,6 +329,7 @@ public class SimpleGroupStore ...@@ -324,6 +329,7 @@ public class SimpleGroupStore
324 oldGroup.type(), 329 oldGroup.type(),
325 updatedBuckets, 330 updatedBuckets,
326 newCookie, 331 newCookie,
332 + oldGroup.givenGroupId(),
327 oldGroup.appId()); 333 oldGroup.appId());
328 StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(), 334 StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(),
329 updatedGroupDesc); 335 updatedGroupDesc);
...@@ -494,6 +500,7 @@ public class SimpleGroupStore ...@@ -494,6 +500,7 @@ public class SimpleGroupStore
494 group.type(), 500 group.type(),
495 group.buckets(), 501 group.buckets(),
496 group.appCookie(), 502 group.appCookie(),
503 + group.givenGroupId(),
497 group.appId()); 504 group.appId());
498 storeGroupDescriptionInternal(tmp); 505 storeGroupDescriptionInternal(tmp);
499 } 506 }
......
...@@ -224,6 +224,7 @@ public class SimpleGroupStoreTest { ...@@ -224,6 +224,7 @@ public class SimpleGroupStoreTest {
224 Group.Type.SELECT, 224 Group.Type.SELECT,
225 groupBuckets, 225 groupBuckets,
226 key, 226 key,
227 + null,
227 appId); 228 appId);
228 InternalGroupStoreDelegate checkStoreGroupDelegate = 229 InternalGroupStoreDelegate checkStoreGroupDelegate =
229 new InternalGroupStoreDelegate(key, 230 new InternalGroupStoreDelegate(key,
...@@ -424,6 +425,7 @@ public class SimpleGroupStoreTest { ...@@ -424,6 +425,7 @@ public class SimpleGroupStoreTest {
424 Group.Type.SELECT, 425 Group.Type.SELECT,
425 groupBuckets, 426 groupBuckets,
426 key, 427 key,
428 + null,
427 appId); 429 appId);
428 InternalGroupStoreDelegate checkStoreGroupDelegate = 430 InternalGroupStoreDelegate checkStoreGroupDelegate =
429 new InternalGroupStoreDelegate(key, 431 new InternalGroupStoreDelegate(key,
......
1 +/*
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 + */
16 +package org.onosproject.driver.pipeline;
17 +
18 +import static org.onlab.util.Tools.groupedThreads;
19 +import static org.slf4j.LoggerFactory.getLogger;
20 +
21 +import java.util.ArrayList;
22 +import java.util.Collection;
23 +import java.util.Collections;
24 +import java.util.List;
25 +import java.util.Set;
26 +import java.util.concurrent.ConcurrentHashMap;
27 +import java.util.concurrent.Executors;
28 +import java.util.concurrent.ScheduledExecutorService;
29 +import java.util.concurrent.TimeUnit;
30 +import java.util.stream.Collectors;
31 +
32 +import org.onlab.osgi.ServiceDirectory;
33 +import org.onlab.packet.Ethernet;
34 +import org.onlab.packet.VlanId;
35 +import org.onlab.util.KryoNamespace;
36 +import org.onosproject.core.ApplicationId;
37 +import org.onosproject.core.CoreService;
38 +import org.onosproject.core.DefaultGroupId;
39 +import org.onosproject.net.DeviceId;
40 +import org.onosproject.net.PortNumber;
41 +import org.onosproject.net.behaviour.NextGroup;
42 +import org.onosproject.net.behaviour.Pipeliner;
43 +import org.onosproject.net.behaviour.PipelinerContext;
44 +import org.onosproject.net.driver.AbstractHandlerBehaviour;
45 +import org.onosproject.net.flow.DefaultFlowRule;
46 +import org.onosproject.net.flow.DefaultTrafficSelector;
47 +import org.onosproject.net.flow.DefaultTrafficTreatment;
48 +import org.onosproject.net.flow.FlowRule;
49 +import org.onosproject.net.flow.FlowRuleOperations;
50 +import org.onosproject.net.flow.FlowRuleOperationsContext;
51 +import org.onosproject.net.flow.FlowRuleService;
52 +import org.onosproject.net.flow.TrafficSelector;
53 +import org.onosproject.net.flow.TrafficTreatment;
54 +import org.onosproject.net.flow.criteria.Criteria;
55 +import org.onosproject.net.flow.criteria.Criterion;
56 +import org.onosproject.net.flow.criteria.EthCriterion;
57 +import org.onosproject.net.flow.criteria.EthTypeCriterion;
58 +import org.onosproject.net.flow.criteria.IPCriterion;
59 +import org.onosproject.net.flow.criteria.PortCriterion;
60 +import org.onosproject.net.flow.criteria.VlanIdCriterion;
61 +import org.onosproject.net.flow.instructions.Instruction;
62 +import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
63 +import org.onosproject.net.flow.instructions.L2ModificationInstruction;
64 +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
65 +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
66 +import org.onosproject.net.flowobjective.FilteringObjective;
67 +import org.onosproject.net.flowobjective.FlowObjectiveStore;
68 +import org.onosproject.net.flowobjective.ForwardingObjective;
69 +import org.onosproject.net.flowobjective.NextObjective;
70 +import org.onosproject.net.flowobjective.Objective;
71 +import org.onosproject.net.flowobjective.ObjectiveError;
72 +import org.onosproject.net.group.DefaultGroupBucket;
73 +import org.onosproject.net.group.DefaultGroupDescription;
74 +import org.onosproject.net.group.DefaultGroupKey;
75 +import org.onosproject.net.group.Group;
76 +import org.onosproject.net.group.GroupBucket;
77 +import org.onosproject.net.group.GroupBuckets;
78 +import org.onosproject.net.group.GroupDescription;
79 +import org.onosproject.net.group.GroupEvent;
80 +import org.onosproject.net.group.GroupKey;
81 +import org.onosproject.net.group.GroupListener;
82 +import org.onosproject.net.group.GroupService;
83 +import org.slf4j.Logger;
84 +
85 +import com.google.common.cache.Cache;
86 +import com.google.common.cache.CacheBuilder;
87 +import com.google.common.cache.RemovalCause;
88 +import com.google.common.cache.RemovalNotification;
89 +
90 +/**
91 + * Driver for Broadcom's OF-DPA v1.0 TTP.
92 + *
93 + */
94 +public class OFDPA1Pipeline extends AbstractHandlerBehaviour implements Pipeliner {
95 +
96 + protected static final int PORT_TABLE = 0;
97 + protected static final int VLAN_TABLE = 10;
98 + protected static final int TMAC_TABLE = 20;
99 + protected static final int UNICAST_ROUTING_TABLE = 30;
100 + protected static final int MULTICAST_ROUTING_TABLE = 40;
101 + protected static final int BRIDGING_TABLE = 50;
102 + protected static final int ACL_TABLE = 60;
103 + protected static final int MAC_LEARNING_TABLE = 254;
104 +
105 + @SuppressWarnings("unused")
106 + private static final int HIGHEST_PRIORITY = 0xffff;
107 + private static final int DEFAULT_PRIORITY = 0x8000;
108 + private static final int LOWEST_PRIORITY = 0x0;
109 +
110 + /*
111 + * Group keys are normally generated by using the next Objective id. In the
112 + * case of a next objective resulting in a group chain, each group derives a
113 + * group key from the next objective id in the following way:
114 + * The upper 4 bits of the group-key are used to denote the position of the
115 + * group in the group chain. For example, in the chain
116 + * group0 --> group1 --> group2 --> port
117 + * group0's group key would have the upper 4 bits as 0, group1's upper four
118 + * bits would be 1, and so on
119 + */
120 + private static final int GROUP0MASK = 0x0;
121 + private static final int GROUP1MASK = 0x10000000;
122 +
123 + /*
124 + * OFDPA requires group-id's to have a certain form.
125 + * L2 Interface Groups have <4bits-0><12bits-vlanid><16bits-portid>
126 + * L3 Unicast Groups have <4bits-2><28bits-index>
127 + */
128 + private static final int L2INTERFACEMASK = 0x0;
129 + private static final int L3UNICASTMASK = 0x20000000;
130 +
131 + private final Logger log = getLogger(getClass());
132 + private ServiceDirectory serviceDirectory;
133 + private FlowRuleService flowRuleService;
134 + private CoreService coreService;
135 + private GroupService groupService;
136 + private FlowObjectiveStore flowObjectiveStore;
137 + private DeviceId deviceId;
138 + private ApplicationId appId;
139 +
140 + private KryoNamespace appKryo = new KryoNamespace.Builder()
141 + .register(GroupKey.class)
142 + .register(DefaultGroupKey.class)
143 + .register(OfdpaGroupChain.class)
144 + .register(byte[].class)
145 + .build();
146 +
147 + private Cache<GroupKey, OfdpaGroupChain> pendingNextObjectives;
148 + private ConcurrentHashMap<GroupKey, GroupChainElem> pendingGroups;
149 +
150 + private ScheduledExecutorService groupChecker =
151 + Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
152 + "ofdpa1-%d"));
153 +
154 + @Override
155 + public void init(DeviceId deviceId, PipelinerContext context) {
156 + this.serviceDirectory = context.directory();
157 + this.deviceId = deviceId;
158 +
159 + pendingNextObjectives = CacheBuilder.newBuilder()
160 + .expireAfterWrite(20, TimeUnit.SECONDS)
161 + .removalListener((RemovalNotification<GroupKey, OfdpaGroupChain> notification) -> {
162 + if (notification.getCause() == RemovalCause.EXPIRED) {
163 + fail(notification.getValue().nextObjective(),
164 + ObjectiveError.GROUPINSTALLATIONFAILED);
165 + }
166 + }).build();
167 +
168 + groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
169 + pendingGroups = new ConcurrentHashMap<GroupKey, GroupChainElem>();
170 +
171 + coreService = serviceDirectory.get(CoreService.class);
172 + flowRuleService = serviceDirectory.get(FlowRuleService.class);
173 + groupService = serviceDirectory.get(GroupService.class);
174 + flowObjectiveStore = context.store();
175 +
176 + groupService.addListener(new InnerGroupListener());
177 +
178 + appId = coreService.registerApplication(
179 + "org.onosproject.driver.OFDPA1Pipeline");
180 +
181 + initializePipeline();
182 +
183 + }
184 +
185 + @Override
186 + public void filter(FilteringObjective filteringObjective) {
187 + if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
188 + processFilter(filteringObjective,
189 + filteringObjective.op() == Objective.Operation.ADD,
190 + filteringObjective.appId());
191 + } else {
192 + fail(filteringObjective, ObjectiveError.UNSUPPORTED);
193 + }
194 + }
195 +
196 + @Override
197 + public void forward(ForwardingObjective fwd) {
198 + Collection<FlowRule> rules;
199 + FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
200 +
201 + rules = processForward(fwd);
202 + switch (fwd.op()) {
203 + case ADD:
204 + rules.stream()
205 + .filter(rule -> rule != null)
206 + .forEach(flowOpsBuilder::add);
207 + break;
208 + case REMOVE:
209 + rules.stream()
210 + .filter(rule -> rule != null)
211 + .forEach(flowOpsBuilder::remove);
212 + break;
213 + default:
214 + fail(fwd, ObjectiveError.UNKNOWN);
215 + log.warn("Unknown forwarding type {}", fwd.op());
216 + }
217 +
218 +
219 + flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
220 + @Override
221 + public void onSuccess(FlowRuleOperations ops) {
222 + pass(fwd);
223 + }
224 +
225 + @Override
226 + public void onError(FlowRuleOperations ops) {
227 + fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
228 + }
229 + }));
230 +
231 + }
232 +
233 + @Override
234 + public void next(NextObjective nextObjective) {
235 + switch (nextObjective.type()) {
236 + case SIMPLE:
237 + Collection<TrafficTreatment> treatments = nextObjective.next();
238 + if (treatments.size() != 1) {
239 + log.error("Next Objectives of type Simple should only have a "
240 + + "single Traffic Treatment. Next Objective Id:{}", nextObjective.id());
241 + fail(nextObjective, ObjectiveError.BADPARAMS);
242 + return;
243 + }
244 + processSimpleNextObjective(nextObjective);
245 + break;
246 + case HASHED:
247 + case BROADCAST:
248 + case FAILOVER:
249 + fail(nextObjective, ObjectiveError.UNSUPPORTED);
250 + log.warn("Unsupported next objective type {}", nextObjective.type());
251 + break;
252 + default:
253 + fail(nextObjective, ObjectiveError.UNKNOWN);
254 + log.warn("Unknown next objective type {}", nextObjective.type());
255 + }
256 + }
257 +
258 + /**
259 + * As per OFDPA 1.0 TTP, filtering of VLAN ids, MAC addresses (for routing)
260 + * and IP addresses configured on switch ports happen in different tables.
261 + * Note that IP filtering rules need to be added to the ACL table, as there
262 + * is no mechanism to send to controller via IP table.
263 + *
264 + * @param filt
265 + * @param install
266 + * @param applicationId
267 + */
268 + private void processFilter(FilteringObjective filt,
269 + boolean install, ApplicationId applicationId) {
270 + // This driver only processes filtering criteria defined with switch
271 + // ports as the key
272 + PortCriterion p = null; EthCriterion e = null; VlanIdCriterion v = null;
273 + Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
274 + if (!filt.key().equals(Criteria.dummy()) &&
275 + filt.key().type() == Criterion.Type.IN_PORT) {
276 + p = (PortCriterion) filt.key();
277 + } else {
278 + log.warn("No key defined in filtering objective from app: {}. Not"
279 + + "processing filtering objective", applicationId);
280 + fail(filt, ObjectiveError.UNKNOWN);
281 + return;
282 + }
283 + // convert filtering conditions for switch-intfs into flowrules
284 + FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
285 + for (Criterion c : filt.conditions()) {
286 + if (c.type() == Criterion.Type.ETH_DST) {
287 + e = (EthCriterion) c;
288 + } else if (c.type() == Criterion.Type.VLAN_VID) {
289 + v = (VlanIdCriterion) c;
290 + } else if (c.type() == Criterion.Type.IPV4_DST) {
291 + ips.add((IPCriterion) c);
292 + } else {
293 + log.error("Unsupported filter {}", c);
294 + fail(filt, ObjectiveError.UNSUPPORTED);
295 + return;
296 + }
297 + }
298 +
299 + log.debug("adding VLAN filtering rule in VLAN table: {}", e.mac());
300 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
301 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
302 + selector.matchInPort(p.port());
303 + selector.matchVlanId(v.vlanId());
304 + treatment.transition(TMAC_TABLE);
305 + FlowRule rule = DefaultFlowRule.builder()
306 + .forDevice(deviceId)
307 + .withSelector(selector.build())
308 + .withTreatment(treatment.build())
309 + .withPriority(DEFAULT_PRIORITY)
310 + .fromApp(appId)
311 + .makePermanent()
312 + .forTable(VLAN_TABLE).build();
313 + ops = ops.add(rule);
314 +
315 + log.debug("adding MAC filtering rules in TMAC table: {}", e.mac());
316 + selector = DefaultTrafficSelector.builder();
317 + treatment = DefaultTrafficTreatment.builder();
318 + selector.matchInPort(p.port());
319 + selector.matchVlanId(v.vlanId());
320 + selector.matchEthType(Ethernet.TYPE_IPV4);
321 + selector.matchEthDst(e.mac());
322 + treatment.transition(UNICAST_ROUTING_TABLE);
323 + rule = DefaultFlowRule.builder()
324 + .forDevice(deviceId)
325 + .withSelector(selector.build())
326 + .withTreatment(treatment.build())
327 + .withPriority(DEFAULT_PRIORITY)
328 + .fromApp(appId)
329 + .makePermanent()
330 + .forTable(TMAC_TABLE).build();
331 + ops = ops.add(rule);
332 +
333 + log.debug("adding IP filtering rules in ACL table");
334 + for (IPCriterion ipaddr : ips) {
335 + selector = DefaultTrafficSelector.builder();
336 + treatment = DefaultTrafficTreatment.builder();
337 + selector.matchEthType(Ethernet.TYPE_IPV4);
338 + selector.matchIPDst(ipaddr.ip());
339 + treatment.setOutput(PortNumber.CONTROLLER);
340 + rule = DefaultFlowRule.builder()
341 + .forDevice(deviceId)
342 + .withSelector(selector.build())
343 + .withTreatment(treatment.build())
344 + .withPriority(DEFAULT_PRIORITY)
345 + .fromApp(appId)
346 + .makePermanent()
347 + .forTable(ACL_TABLE).build();
348 + ops = ops.add(rule);
349 + }
350 +
351 + ops = install ? ops.add(rule) : ops.remove(rule);
352 + // apply filtering flow rules
353 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
354 + @Override
355 + public void onSuccess(FlowRuleOperations ops) {
356 + pass(filt);
357 + log.info("Applied filtering rules");
358 + }
359 +
360 + @Override
361 + public void onError(FlowRuleOperations ops) {
362 + fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
363 + log.info("Failed to apply filtering rules");
364 + }
365 + }));
366 +
367 + }
368 +
369 +
370 + /**
371 + * As per the OFDPA 1.0 TTP, packets are sent out of ports by using
372 + * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface
373 + * Group which in turns points to an output port. The Next Objective passed
374 + * in by the application has to be broken up into a group chain
375 + * to satisfy this TTP.
376 + *
377 + * @param nextObj the nextObjective of type SIMPLE
378 + */
379 + private void processSimpleNextObjective(NextObjective nextObj) {
380 + // break up next objective to GroupChain objects
381 + TrafficTreatment treatment = nextObj.next().iterator().next();
382 + // for the l2interface group, get vlan and port info
383 + // for the l3unicast group, get the src/dst mac and vlan info
384 + TrafficTreatment.Builder l3utt = DefaultTrafficTreatment.builder();
385 + TrafficTreatment.Builder l2itt = DefaultTrafficTreatment.builder();
386 + VlanId vlanid = null;
387 + long portNum = 0;
388 + for (Instruction ins : treatment.allInstructions()) {
389 + if (ins.type() == Instruction.Type.L2MODIFICATION) {
390 + L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
391 + switch (l2ins.subtype()) {
392 + case ETH_DST:
393 + l3utt.setEthDst(((ModEtherInstruction) l2ins).mac());
394 + break;
395 + case ETH_SRC:
396 + l3utt.setEthSrc(((ModEtherInstruction) l2ins).mac());
397 + break;
398 + case VLAN_ID:
399 + vlanid = ((ModVlanIdInstruction) l2ins).vlanId();
400 + l3utt.setVlanId(vlanid);
401 + break;
402 + case DEC_MPLS_TTL:
403 + case MPLS_LABEL:
404 + case MPLS_POP:
405 + case MPLS_PUSH:
406 + case VLAN_PCP:
407 + case VLAN_POP:
408 + case VLAN_PUSH:
409 + default:
410 + break;
411 + }
412 + } else if (ins.type() == Instruction.Type.OUTPUT) {
413 + portNum = ((OutputInstruction) ins).port().toLong();
414 + l2itt.add(ins);
415 + } else {
416 + log.warn("Driver does not handle this type of TrafficTreatment"
417 + + " instruction in nextObjectives: {}", ins.type());
418 + }
419 + }
420 +
421 + // assemble information for ofdpa l2interface group
422 + int l2gk = nextObj.id() | GROUP1MASK;
423 + final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk));
424 + Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum;
425 +
426 + // assemble information for ofdpa l3unicast group
427 + int l3gk = nextObj.id() | GROUP0MASK;
428 + final GroupKey l3groupkey = new DefaultGroupKey(appKryo.serialize(l3gk));
429 + Integer l3groupId = L3UNICASTMASK | (int) portNum;
430 + l3utt.group(new DefaultGroupId(l2groupId));
431 + GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId,
432 + l3utt.build(), nextObj.appId());
433 +
434 + // create object for local and distributed storage
435 + List<GroupKey> gkeys = new ArrayList<GroupKey>();
436 + gkeys.add(l3groupkey); // group0 in chain
437 + gkeys.add(l2groupkey); // group1 in chain
438 + OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj);
439 +
440 + // store l2groupkey with the groupChainElem for the l3group that depends on it
441 + pendingGroups.put(l2groupkey, gce);
442 +
443 + // store l3groupkey with the ofdpaGroupChain for the nextObjective that depends on it
444 + pendingNextObjectives.put(l3groupkey, ofdpaGrp);
445 +
446 + // create group description for the ofdpa l2interfacegroup and send to groupservice
447 + GroupBucket bucket =
448 + DefaultGroupBucket.createIndirectGroupBucket(l2itt.build());
449 + GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
450 + GroupDescription.Type.INDIRECT,
451 + new GroupBuckets(Collections.singletonList(bucket)),
452 + l2groupkey,
453 + l2groupId,
454 + nextObj.appId());
455 + groupService.addGroup(groupDescription);
456 + }
457 +
458 + /**
459 + * Processes next element of a group chain. Assumption is that if this
460 + * group points to another group, the latter has already been created
461 + * and this driver has received notification for it. A second assumption is
462 + * that if there is another group waiting for this group then the appropriate
463 + * stores already have the information to act upon the notification for the
464 + * creating of this group.
465 + *
466 + * @param gce the group chain element to be processed next
467 + */
468 + private void processGroupChain(GroupChainElem gce) {
469 + GroupBucket bucket = DefaultGroupBucket
470 + .createIndirectGroupBucket(gce.getBucketActions());
471 + GroupDescription groupDesc = new DefaultGroupDescription(deviceId,
472 + GroupDescription.Type.INDIRECT,
473 + new GroupBuckets(Collections.singletonList(bucket)),
474 + gce.getGkey(),
475 + gce.getGivenGroupId(),
476 + gce.getAppId());
477 + groupService.addGroup(groupDesc);
478 + }
479 +
480 + private Collection<FlowRule> processForward(ForwardingObjective fwd) {
481 + switch (fwd.flag()) {
482 + case SPECIFIC:
483 + return processSpecific(fwd);
484 + case VERSATILE:
485 + return processVersatile(fwd);
486 + default:
487 + fail(fwd, ObjectiveError.UNKNOWN);
488 + log.warn("Unknown forwarding flag {}", fwd.flag());
489 + }
490 + return Collections.emptySet();
491 + }
492 +
493 + /**
494 + * In the OF-DPA 1.0 pipeline, versatile forwarding objectives go to the
495 + * ACL table.
496 + * @param fwd the forwarding objective of type 'versatile'
497 + * @return a collection of flow rules to be sent to the switch. An empty
498 + * collection may be returned if there is a problem in processing
499 + * the flow rule
500 + */
501 + private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
502 + log.info("Processing versatile forwarding objective");
503 + TrafficSelector selector = fwd.selector();
504 +
505 + EthTypeCriterion ethType =
506 + (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
507 + if (ethType == null) {
508 + log.error("Versatile forwarding objective must include ethType");
509 + fail(fwd, ObjectiveError.UNKNOWN);
510 + return Collections.emptySet();
511 + }
512 + if (ethType.ethType() == Ethernet.TYPE_ARP) {
513 + log.warn("Installing ARP rule to table 60");
514 +
515 + // currently need to punt from ACL table should use:
516 + // OF apply-actions-instruction
517 + // To use OF write-actions-instruction
518 + /*TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
519 + fwd.treatment().allInstructions().stream()
520 + .forEach(ti -> tb.deferred().add(ti));*/
521 +
522 + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
523 + .fromApp(fwd.appId())
524 + .withPriority(fwd.priority())
525 + .forDevice(deviceId)
526 + .withSelector(fwd.selector())
527 + .withTreatment(fwd.treatment())
528 + .makePermanent()
529 + .forTable(ACL_TABLE);
530 +
531 + // XXX bug in OFDPA
532 + return Collections.singletonList(ruleBuilder.build());
533 + }
534 +
535 + // XXX not handling other versatile flows yet
536 + return Collections.emptySet();
537 + }
538 +
539 + /**
540 + * In the OF-DPA 1.0 pipeline, specific forwarding refers to the IP table
541 + * (unicast or multicast) or the L2 table (mac + vlan).
542 + *
543 + * @param fwd the forwarding objective of type 'specific'
544 + * @return a collection of flow rules. Typically there will be only one
545 + * for this type of forwarding objective. An empty set may be
546 + * returned if there is an issue in processing the objective.
547 + */
548 + private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
549 + log.debug("Processing specific forwarding objective");
550 + TrafficSelector selector = fwd.selector();
551 + EthTypeCriterion ethType =
552 + (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
553 + // XXX currently supporting only the L3 unicast table
554 + if (ethType == null || ethType.ethType() != Ethernet.TYPE_IPV4) {
555 + fail(fwd, ObjectiveError.UNSUPPORTED);
556 + return Collections.emptySet();
557 + }
558 +
559 + TrafficSelector filteredSelector =
560 + DefaultTrafficSelector.builder()
561 + .matchEthType(Ethernet.TYPE_IPV4)
562 + .matchIPDst(
563 + ((IPCriterion)
564 + selector.getCriterion(Criterion.Type.IPV4_DST)).ip())
565 + .build();
566 +
567 + TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
568 +
569 + if (fwd.nextId() != null) {
570 + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
571 + List<GroupKey> gkeys = appKryo.deserialize(next.data());
572 + Group group = groupService.getGroup(deviceId, gkeys.get(0));
573 + if (group == null) {
574 + log.warn("The group left!");
575 + fail(fwd, ObjectiveError.GROUPMISSING);
576 + return Collections.emptySet();
577 + }
578 + tb.group(group.id());
579 + }
580 +
581 + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
582 + .fromApp(fwd.appId())
583 + .withPriority(fwd.priority())
584 + .forDevice(deviceId)
585 + .withSelector(filteredSelector)
586 + .withTreatment(tb.build());
587 +
588 + if (fwd.permanent()) {
589 + ruleBuilder.makePermanent();
590 + } else {
591 + ruleBuilder.makeTemporary(fwd.timeout());
592 + }
593 +
594 + ruleBuilder.forTable(UNICAST_ROUTING_TABLE);
595 + return Collections.singletonList(ruleBuilder.build());
596 + }
597 +
598 + private void pass(Objective obj) {
599 + if (obj.context().isPresent()) {
600 + obj.context().get().onSuccess(obj);
601 + }
602 + }
603 +
604 +
605 + private void fail(Objective obj, ObjectiveError error) {
606 + if (obj.context().isPresent()) {
607 + obj.context().get().onError(obj, error);
608 + }
609 + }
610 +
611 +
612 + private void initializePipeline() {
613 + processPortTable();
614 + processVlanTable();
615 + processTmacTable();
616 + processIpTable();
617 + //processMcastTable();
618 + //processBridgingTable();
619 + //processAclTable();
620 + //processGroupTable();
621 + }
622 +
623 + private void processPortTable() {
624 + //XXX is table miss entry enough or do we need to do the maskable in-port 0?
625 + FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
626 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
627 + selector.matchInPort(PortNumber.portNumber(0)); // should be maskable?
628 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
629 + treatment.transition(VLAN_TABLE);
630 + FlowRule tmisse = DefaultFlowRule.builder()
631 + .forDevice(deviceId)
632 + .withSelector(selector.build())
633 + .withTreatment(treatment.build())
634 + .withPriority(LOWEST_PRIORITY)
635 + .fromApp(appId)
636 + .makePermanent()
637 + .forTable(PORT_TABLE).build();
638 + ops = ops.add(tmisse);
639 +
640 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
641 + @Override
642 + public void onSuccess(FlowRuleOperations ops) {
643 + log.info("Initialized port table");
644 + }
645 +
646 + @Override
647 + public void onError(FlowRuleOperations ops) {
648 + log.info("Failed to initialize port table");
649 + }
650 + }));
651 +
652 + }
653 +
654 + private void processVlanTable() {
655 + // make these up for now - should really be filtering rules
656 + /*FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
657 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
658 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
659 + selector.matchInPort(PortNumber.portNumber(10));
660 + selector.matchVlanId(VlanId.vlanId((short) 100));
661 + treatment.transition(TMAC_TABLE);
662 + FlowRule rule = DefaultFlowRule.builder()
663 + .forDevice(deviceId)
664 + .withSelector(selector.build())
665 + .withTreatment(treatment.build())
666 + .withPriority(DEFAULT_PRIORITY)
667 + .fromApp(appId)
668 + .makePermanent()
669 + .forTable(VLAN_TABLE).build();
670 + ops = ops.add(rule);
671 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
672 + @Override
673 + public void onSuccess(FlowRuleOperations ops) {
674 + log.info("Initialized vlan table");
675 + }
676 +
677 + @Override
678 + public void onError(FlowRuleOperations ops) {
679 + log.info("Failed to initialize vlan table");
680 + }
681 + }));*/
682 +
683 + // Table miss entry is not required as ofdpa default is to drop
684 + // In OF terms, the absence of a t.m.e. also implies drop
685 + }
686 +
687 +
688 + private void processTmacTable() {
689 + // this is made up as well -- should be a filtering rule
690 + /*selector.matchInPort(PortNumber.portNumber(10));
691 + selector.matchVlanId(VlanId.vlanId((short) 100));
692 + selector.matchEthType(Ethernet.TYPE_IPV4);
693 + selector.matchEthDst(MacAddress.valueOf("00:00:00:ba:ba:00"));
694 + treatment.transition(UNICAST_ROUTING_TABLE);
695 + FlowRule rule = DefaultFlowRule.builder()
696 + .forDevice(deviceId)
697 + .withSelector(selector.build())
698 + .withTreatment(treatment.build())
699 + .withPriority(DEFAULT_PRIORITY)
700 + .fromApp(appId)
701 + .makePermanent()
702 + .forTable(TMAC_TABLE).build();
703 + ops = ops.add(rule);*/
704 +
705 + //table miss entry
706 + FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
707 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
708 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
709 + selector = DefaultTrafficSelector.builder();
710 + treatment = DefaultTrafficTreatment.builder();
711 + treatment.transition(BRIDGING_TABLE);
712 + FlowRule rule = DefaultFlowRule.builder()
713 + .forDevice(deviceId)
714 + .withSelector(selector.build())
715 + .withTreatment(treatment.build())
716 + .withPriority(LOWEST_PRIORITY)
717 + .fromApp(appId)
718 + .makePermanent()
719 + .forTable(TMAC_TABLE).build();
720 + ops = ops.add(rule); // XXX bug in ofdpa
721 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
722 + @Override
723 + public void onSuccess(FlowRuleOperations ops) {
724 + log.info("Initialized tmac table");
725 + }
726 +
727 + @Override
728 + public void onError(FlowRuleOperations ops) {
729 + log.info("Failed to initialize tmac table");
730 + }
731 + }));
732 + }
733 +
734 + private void processIpTable() {
735 + //table miss entry
736 + FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
737 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
738 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
739 + selector = DefaultTrafficSelector.builder();
740 + treatment = DefaultTrafficTreatment.builder();
741 + treatment.transition(ACL_TABLE);
742 + FlowRule rule = DefaultFlowRule.builder()
743 + .forDevice(deviceId)
744 + .withSelector(selector.build())
745 + .withTreatment(treatment.build())
746 + .withPriority(LOWEST_PRIORITY)
747 + .fromApp(appId)
748 + .makePermanent()
749 + .forTable(UNICAST_ROUTING_TABLE).build();
750 + ops = ops.add(rule);
751 + flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
752 + @Override
753 + public void onSuccess(FlowRuleOperations ops) {
754 + log.info("Initialized IP table");
755 + }
756 +
757 + @Override
758 + public void onError(FlowRuleOperations ops) {
759 + log.info("Failed to initialize unicast IP table");
760 + }
761 + }));
762 + }
763 +
764 + @SuppressWarnings("unused")
765 + private void processGroupTable() {
766 + // Creating a dummy L2 group as per OFDPA requirements
767 + /* TrafficTreatment treatment = DefaultTrafficTreatment.builder()
768 + .setOutput(PortNumber.portNumber(10))
769 + .build();
770 + NextObjective nextObjective = DefaultNextObjective.builder()
771 + .addTreatment(treatment)
772 + .fromApp(appId)
773 + .withId(678) // dummy next objective id
774 + .withType(NextObjective.Type.SIMPLE)
775 + .add();
776 + Integer l2groupId = 0x0064000a;
777 + GroupBucket bucket =
778 + DefaultGroupBucket.createIndirectGroupBucket(treatment);
779 + final GroupKey key = new DefaultGroupKey(appKryo.serialize(678));
780 + GroupDescription groupDescriptionl2
781 + = new DefaultGroupDescription(deviceId,
782 + GroupDescription.Type.INDIRECT,
783 + new GroupBuckets(Collections
784 + .singletonList(bucket)),
785 + key,
786 + l2groupId,
787 + appId);
788 + groupService.addGroup(groupDescriptionl2);*/
789 + //pendingNextObjectives.put(key, nextObjective);
790 +
791 + }
792 +
793 + @SuppressWarnings("unused")
794 + private void tryGroupChain() {
795 + //Create a dummy L3 group as per OFDPA requirements
796 + /*TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
797 + .setEthDst(MacAddress.valueOf("00:00:00:aa:aa:aa"))
798 + .setEthSrc(MacAddress.valueOf("00:00:00:dd:dd:dd"))
799 + .setVlanId(VlanId.vlanId((short) 100))
800 + .group(new DefaultGroupId(0x0064000a))
801 + .build();
802 + NextObjective nextObjective2 = DefaultNextObjective.builder()
803 + .addTreatment(treatment2)
804 + .fromApp(appId)
805 + .withId(67800) // another dummy next objective id
806 + .withType(NextObjective.Type.SIMPLE)
807 + .add();
808 + Integer l3groupId = 0x2000000a;
809 + GroupBucket bucket2 = DefaultGroupBucket.createIndirectGroupBucket(treatment2);
810 + final GroupKey key2 = new DefaultGroupKey(appKryo.serialize(67800));
811 + GroupDescription groupDescriptionl3
812 + = new DefaultGroupDescription(deviceId,
813 + GroupDescription.Type.INDIRECT,
814 + new GroupBuckets(Collections
815 + .singletonList(bucket2)),
816 + key2,
817 + l3groupId,
818 + appId);
819 + groupService.addGroup(groupDescriptionl3);
820 + pendingNextObjectives.put(key2, nextObjective2);
821 + */
822 + }
823 +
824 + private class GroupChecker implements Runnable {
825 + @Override
826 + public void run() {
827 + Set<GroupKey> keys = pendingNextObjectives.asMap().keySet().stream()
828 + .filter(key -> groupService.getGroup(deviceId, key) != null)
829 + .collect(Collectors.toSet());
830 +
831 + keys.stream().forEach(key -> {
832 + //first check for group chain
833 + GroupChainElem gce = pendingGroups.remove(key);
834 + if (gce != null) {
835 + log.info("Heard back from group service. Processing next "
836 + + "group in group chain with group key {}", gce.getGkey());
837 + processGroupChain(gce);
838 + } else {
839 + OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key);
840 + if (obj == null) {
841 + return;
842 + }
843 + pass(obj.nextObjective());
844 + pendingNextObjectives.invalidate(key);
845 + log.info("Heard back from group service. Applying pending "
846 + + "objectives for nextId {}", obj.nextObjective().id());
847 + flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj);
848 + }
849 + });
850 + }
851 + }
852 +
853 +
854 + private class InnerGroupListener implements GroupListener {
855 + @Override
856 + public void event(GroupEvent event) {
857 + if (event.type() == GroupEvent.Type.GROUP_ADDED) {
858 + GroupKey key = event.subject().appCookie();
859 + // first check for group chain
860 + GroupChainElem gce = pendingGroups.remove(key);
861 + if (gce != null) {
862 + log.info("group ADDED .. Processing next group in group chain "
863 + + "with group key {}", gce.getGkey());
864 + processGroupChain(gce);
865 + } else {
866 + OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key);
867 + log.info("group ADDED .. Applying pending objectives if any");
868 + if (obj != null) {
869 + flowObjectiveStore.putNextGroup(obj.nextObjective().id(), obj);
870 + pass(obj.nextObjective());
871 + pendingNextObjectives.invalidate(key);
872 + }
873 + }
874 + }
875 + }
876 + }
877 +
878 + /**
879 + * Represents a group-chain that implements a Next-Objective from
880 + * the application. Includes information about the next objective Id, and the
881 + * group keys for the groups in the group chain. The chain is expected to
882 + * look like group0 --> group 1 --> outPort. Information about the groups
883 + * themselves can be fetched from the Group Service using the group keys from
884 + * objects instantiating this class.
885 + */
886 + private class OfdpaGroupChain implements NextGroup {
887 + private final NextObjective nextObj;
888 + private final List<GroupKey> gkeys;
889 +
890 + /** expected group chain: group0 --> group1 --> port. */
891 + public OfdpaGroupChain(List<GroupKey> gkeys, NextObjective nextObj) {
892 + this.gkeys = gkeys;
893 + this.nextObj = nextObj;
894 + }
895 +
896 + @SuppressWarnings("unused")
897 + public List<GroupKey> groupKeys() {
898 + return gkeys;
899 + }
900 +
901 + public NextObjective nextObjective() {
902 + return nextObj;
903 + }
904 +
905 + @Override
906 + public byte[] data() {
907 + return appKryo.serialize(gkeys);
908 + }
909 +
910 + }
911 +
912 + /**
913 + * Represents a group element that is part of a chain of groups.
914 + * Stores enough information to create a Group Description to add the group
915 + * to the switch by requesting the Group Service. Objects instantiating this
916 + * class are meant to be temporary and live as long as it is needed to wait for
917 + * preceding groups in the group chain to be created.
918 + */
919 + private class GroupChainElem {
920 + private TrafficTreatment bucketActions;
921 + private Integer givenGroupId;
922 + private GroupKey gkey;
923 + private ApplicationId appId;
924 +
925 + public GroupChainElem(GroupKey gkey, Integer givenGroupId,
926 + TrafficTreatment tr, ApplicationId appId) {
927 + this.bucketActions = tr;
928 + this.givenGroupId = givenGroupId;
929 + this.gkey = gkey;
930 + this.appId = appId;
931 + }
932 +
933 + public TrafficTreatment getBucketActions() {
934 + return bucketActions;
935 + }
936 +
937 + public Integer getGivenGroupId() {
938 + return givenGroupId;
939 + }
940 +
941 + public GroupKey getGkey() {
942 + return gkey;
943 + }
944 +
945 + public ApplicationId getAppId() {
946 + return appId;
947 + }
948 +
949 + }
950 +}
...@@ -85,8 +85,6 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -85,8 +85,6 @@ import static org.slf4j.LoggerFactory.getLogger;
85 */ 85 */
86 public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeliner { 86 public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeliner {
87 87
88 -
89 -
90 protected static final int MAC_TABLE = 0; 88 protected static final int MAC_TABLE = 0;
91 protected static final int VLAN_MPLS_TABLE = 1; 89 protected static final int VLAN_MPLS_TABLE = 1;
92 protected static final int VLAN_TABLE = 2; 90 protected static final int VLAN_TABLE = 2;
...@@ -149,7 +147,7 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli ...@@ -149,7 +147,7 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli
149 appId = coreService.registerApplication( 147 appId = coreService.registerApplication(
150 "org.onosproject.driver.OVSCorsaPipeline"); 148 "org.onosproject.driver.OVSCorsaPipeline");
151 149
152 - pushDefaultRules(); 150 + initializePipeline();
153 } 151 }
154 152
155 @Override 153 @Override
...@@ -216,6 +214,7 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli ...@@ -216,6 +214,7 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli
216 new GroupBuckets(Collections 214 new GroupBuckets(Collections
217 .singletonList(bucket)), 215 .singletonList(bucket)),
218 key, 216 key,
217 + null, // let group service determine group id
219 nextObjective.appId()); 218 nextObjective.appId());
220 groupService.addGroup(groupDescription); 219 groupService.addGroup(groupDescription);
221 pendingGroups.put(key, nextObjective); 220 pendingGroups.put(key, nextObjective);
...@@ -454,7 +453,7 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli ...@@ -454,7 +453,7 @@ public class OVSCorsaPipeline extends AbstractHandlerBehaviour implements Pipeli
454 } 453 }
455 } 454 }
456 455
457 - private void pushDefaultRules() { 456 + private void initializePipeline() {
458 processMacTable(true); 457 processMacTable(true);
459 processVlanMplsTable(true); 458 processVlanMplsTable(true);
460 processVlanTable(true); 459 processVlanTable(true);
......
...@@ -252,6 +252,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -252,6 +252,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
252 new GroupBuckets( 252 new GroupBuckets(
253 Collections.singletonList(bucket)), 253 Collections.singletonList(bucket)),
254 key, 254 key,
255 + null,
255 nextObjective.appId()); 256 nextObjective.appId());
256 groupService.addGroup(groupDescription); 257 groupService.addGroup(groupDescription);
257 pendingGroups.put(key, nextObjective); 258 pendingGroups.put(key, nextObjective);
...@@ -274,6 +275,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -274,6 +275,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
274 GroupDescription.Type.SELECT, 275 GroupDescription.Type.SELECT,
275 new GroupBuckets(buckets), 276 new GroupBuckets(buckets),
276 key, 277 key,
278 + null,
277 nextObjective.appId()); 279 nextObjective.appId());
278 groupService.addGroup(groupDescription); 280 groupService.addGroup(groupDescription);
279 pendingGroups.put(key, nextObjective); 281 pendingGroups.put(key, nextObjective);
......
...@@ -55,5 +55,9 @@ ...@@ -55,5 +55,9 @@
55 <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver" 55 <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
56 impl="org.onosproject.driver.handshaker.OFCorsaSwitchDriver"/> 56 impl="org.onosproject.driver.handshaker.OFCorsaSwitchDriver"/>
57 </driver> 57 </driver>
58 + <driver name="ofdpa" manufacturer="Broadcom Corp." hwVersion="OF-DPA 1.0" swVersion="OF-DPA 1.0">
59 + <behaviour api="org.onosproject.net.behaviour.Pipeliner"
60 + impl="org.onosproject.driver.pipeline.OFDPA1Pipeline"/>
61 + </driver>
58 </drivers> 62 </drivers>
59 63
......
...@@ -213,6 +213,7 @@ public class Controller { ...@@ -213,6 +213,7 @@ public class Controller {
213 ofSwitchDriver.init(new Dpid(dpid), desc, ofv); 213 ofSwitchDriver.init(new Dpid(dpid), desc, ofv);
214 ofSwitchDriver.setAgent(agent); 214 ofSwitchDriver.setAgent(agent);
215 ofSwitchDriver.setRoleHandler(new RoleManager(ofSwitchDriver)); 215 ofSwitchDriver.setRoleHandler(new RoleManager(ofSwitchDriver));
216 + log.info("OpenFlow handshaker found for device {}: {}", dpid, ofSwitchDriver);
216 return ofSwitchDriver; 217 return ofSwitchDriver;
217 } 218 }
218 log.error("No OpenFlow driver for {} : {}", dpid, desc); 219 log.error("No OpenFlow driver for {} : {}", dpid, desc);
......
...@@ -35,6 +35,7 @@ import org.projectfloodlight.openflow.protocol.OFGroupDelete; ...@@ -35,6 +35,7 @@ import org.projectfloodlight.openflow.protocol.OFGroupDelete;
35 import org.projectfloodlight.openflow.protocol.OFGroupMod; 35 import org.projectfloodlight.openflow.protocol.OFGroupMod;
36 import org.projectfloodlight.openflow.protocol.OFGroupType; 36 import org.projectfloodlight.openflow.protocol.OFGroupType;
37 import org.projectfloodlight.openflow.protocol.action.OFAction; 37 import org.projectfloodlight.openflow.protocol.action.OFAction;
38 +import org.projectfloodlight.openflow.protocol.action.OFActionGroup;
38 import org.projectfloodlight.openflow.protocol.action.OFActionOutput; 39 import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
39 import org.projectfloodlight.openflow.protocol.oxm.OFOxm; 40 import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
40 import org.projectfloodlight.openflow.types.CircuitSignalID; 41 import org.projectfloodlight.openflow.types.CircuitSignalID;
...@@ -210,6 +211,12 @@ public final class GroupModBuilder { ...@@ -210,6 +211,12 @@ public final class GroupModBuilder {
210 actions.add(action.build()); 211 actions.add(action.build());
211 break; 212 break;
212 case GROUP: 213 case GROUP:
214 + Instructions.GroupInstruction grp =
215 + (Instructions.GroupInstruction) i;
216 + OFActionGroup.Builder actgrp = factory.actions().buildGroup()
217 + .setGroup(OFGroup.of(grp.groupId().id()));
218 + actions.add(actgrp.build());
219 + break;
213 default: 220 default:
214 log.warn("Instruction type {} not yet implemented.", i.type()); 221 log.warn("Instruction type {} not yet implemented.", i.type());
215 } 222 }
......