Saurav Das
Committed by Gerrit Code Review

CORD-48 Implementation of hashing Next Objective in OF-DPA driver. Major changes…

… to ensure multi-ONOS-instance group-chain installation.
Also includes:
     Changes to Next Objective that adds metadata field for applications to optionally send auxillary info to drivers
     Changes to Next Objective that allows more explicit modification of the next objective
     Changes to Forwarding Objective and PendingNext to include hashCode() and equals() method
     MplsBosInstruction included in kryo serializer
     GroupKey's byte[] represented as a hex string
     Bug fix in mpls flow installation to report failure in install
     Bug fix in linkUp in SR app to disallow non-masters to modify groups
     Bug fix in ordering of actions in group

Change-Id: I3e7003f55724c2de79589e43e11d05ff4815a81d
Showing 18 changed files with 345 additions and 27 deletions
...@@ -448,7 +448,6 @@ public class DefaultRoutingHandler { ...@@ -448,7 +448,6 @@ public class DefaultRoutingHandler {
448 if (nextHops.isEmpty()) { 448 if (nextHops.isEmpty()) {
449 nextHops.add(destSw); 449 nextHops.add(destSw);
450 } 450 }
451 -
452 // If both target switch and dest switch are edge routers, then set IP 451 // If both target switch and dest switch are edge routers, then set IP
453 // rule for both subnet and router IP. 452 // rule for both subnet and router IP.
454 boolean targetIsEdge; 453 boolean targetIsEdge;
...@@ -485,8 +484,8 @@ public class DefaultRoutingHandler { ...@@ -485,8 +484,8 @@ public class DefaultRoutingHandler {
485 return false; 484 return false;
486 } 485 }
487 486
488 - // If the target switch is an edge router, then set IP rules for the router IP.
489 } else if (targetIsEdge) { 487 } else if (targetIsEdge) {
488 + // If the target switch is an edge router, then set IP rules for the router IP.
490 Ip4Address routerIp = destRouterIp; 489 Ip4Address routerIp = destRouterIp;
491 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); 490 IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH);
492 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}", 491 log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}",
...@@ -496,7 +495,6 @@ public class DefaultRoutingHandler { ...@@ -496,7 +495,6 @@ public class DefaultRoutingHandler {
496 return false; 495 return false;
497 } 496 }
498 } 497 }
499 -
500 // Populates MPLS rules to all routers 498 // Populates MPLS rules to all routers
501 log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules", 499 log.debug("* populateEcmpRoutingRulePartial in device{} towards {} for all MPLS rules",
502 targetSw, destSw); 500 targetSw, destSw);
...@@ -504,7 +502,6 @@ public class DefaultRoutingHandler { ...@@ -504,7 +502,6 @@ public class DefaultRoutingHandler {
504 if (!result) { 502 if (!result) {
505 return false; 503 return false;
506 } 504 }
507 -
508 return true; 505 return true;
509 } 506 }
510 507
......
...@@ -424,17 +424,22 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -424,17 +424,22 @@ public class SegmentRoutingManager implements SegmentRoutingService {
424 424
425 /** 425 /**
426 * Returns the next objective ID for the given NeighborSet. 426 * Returns the next objective ID for the given NeighborSet.
427 - * If the nextObjectiveID does not exist, a new one is created and returned. 427 + * If the nextObjective does not exist, a new one is created and
428 + * it's id is returned.
429 + * TODO move the side-effect creation of a Next Objective into a new method
428 * 430 *
429 * @param deviceId Device ID 431 * @param deviceId Device ID
430 * @param ns NegighborSet 432 * @param ns NegighborSet
431 - * @return next objective ID 433 + * @param meta metadata passed into the creation of a Next Objective
434 + * @return next objective ID or -1 if an error was encountered during the
435 + * creation of the nextObjective
432 */ 436 */
433 - public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) { 437 + public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns,
438 + TrafficSelector meta) {
434 if (groupHandlerMap.get(deviceId) != null) { 439 if (groupHandlerMap.get(deviceId) != null) {
435 log.trace("getNextObjectiveId query in device {}", deviceId); 440 log.trace("getNextObjectiveId query in device {}", deviceId);
436 return groupHandlerMap 441 return groupHandlerMap
437 - .get(deviceId).getNextObjectiveId(ns); 442 + .get(deviceId).getNextObjectiveId(ns, meta);
438 } else { 443 } else {
439 log.warn("getNextObjectiveId query in device {} not found", deviceId); 444 log.warn("getNextObjectiveId query in device {} not found", deviceId);
440 return -1; 445 return -1;
...@@ -586,7 +591,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -586,7 +591,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
586 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src() 591 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
587 .deviceId()); 592 .deviceId());
588 if (groupHandler != null) { 593 if (groupHandler != null) {
589 - groupHandler.linkUp(link); 594 + groupHandler.linkUp(link, mastershipService.isLocalMaster(
595 + link.src().deviceId()));
590 } else { 596 } else {
591 Device device = deviceService.getDevice(link.src().deviceId()); 597 Device device = deviceService.getDevice(link.src().deviceId());
592 if (device != null) { 598 if (device != null) {
...@@ -596,7 +602,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -596,7 +602,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
596 processDeviceAdded(device); 602 processDeviceAdded(device);
597 groupHandler = groupHandlerMap.get(link.src() 603 groupHandler = groupHandlerMap.get(link.src()
598 .deviceId()); 604 .deviceId());
599 - groupHandler.linkUp(link); 605 + groupHandler.linkUp(link, mastershipService.isLocalMaster(device.id()));
600 } 606 }
601 } 607 }
602 608
......
...@@ -194,7 +194,7 @@ public class TunnelHandler { ...@@ -194,7 +194,7 @@ public class TunnelHandler {
194 tunnel.allowToRemoveGroup(true); 194 tunnel.allowToRemoveGroup(true);
195 } 195 }
196 196
197 - return groupHandlerMap.get(deviceId).getNextObjectiveId(ns); 197 + return groupHandlerMap.get(deviceId).getNextObjectiveId(ns, null);
198 } 198 }
199 199
200 } 200 }
......
...@@ -93,7 +93,7 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler { ...@@ -93,7 +93,7 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
93 + "with label for sw {} is {}", 93 + "with label for sw {} is {}",
94 deviceId, nsSet); 94 deviceId, nsSet);
95 95
96 - createGroupsFromNeighborsets(nsSet); 96 + //createGroupsFromNeighborsets(nsSet);
97 } 97 }
98 98
99 @Override 99 @Override
...@@ -107,7 +107,7 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler { ...@@ -107,7 +107,7 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
107 Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent( 107 Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(
108 newNeighborLink.dst().deviceId(), 108 newNeighborLink.dst().deviceId(),
109 devicePortMap.keySet()); 109 devicePortMap.keySet());
110 - createGroupsFromNeighborsets(nsSet); 110 + //createGroupsFromNeighborsets(nsSet);
111 } 111 }
112 112
113 @Override 113 @Override
......
...@@ -81,7 +81,7 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler { ...@@ -81,7 +81,7 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
81 log.debug("createGroupsAtTransitRouter: The neighborset with label " 81 log.debug("createGroupsAtTransitRouter: The neighborset with label "
82 + "for sw {} is {}", deviceId, nsSet); 82 + "for sw {} is {}", deviceId, nsSet);
83 83
84 - createGroupsFromNeighborsets(nsSet); 84 + //createGroupsFromNeighborsets(nsSet);
85 } 85 }
86 86
87 @Override 87 @Override
...@@ -95,7 +95,7 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler { ...@@ -95,7 +95,7 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
95 Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent( 95 Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(
96 newNeighborLink.dst().deviceId(), 96 newNeighborLink.dst().deviceId(),
97 devicePortMap.keySet()); 97 devicePortMap.keySet());
98 - createGroupsFromNeighborsets(nsSet); 98 + //createGroupsFromNeighborsets(nsSet);
99 } 99 }
100 100
101 @Override 101 @Override
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.net.flowobjective; 16 package org.onosproject.net.flowobjective;
17 17
18 import com.google.common.annotations.Beta; 18 import com.google.common.annotations.Beta;
19 +
19 import org.onosproject.core.ApplicationId; 20 import org.onosproject.core.ApplicationId;
20 import org.onosproject.net.flow.TrafficSelector; 21 import org.onosproject.net.flow.TrafficSelector;
21 import org.onosproject.net.flow.TrafficTreatment; 22 import org.onosproject.net.flow.TrafficTreatment;
...@@ -119,6 +120,53 @@ public final class DefaultForwardingObjective implements ForwardingObjective { ...@@ -119,6 +120,53 @@ public final class DefaultForwardingObjective implements ForwardingObjective {
119 return context; 120 return context;
120 } 121 }
121 122
123 + /*
124 + * (non-Javadoc)
125 + *
126 + * @see java.lang.Object#hashCode()
127 + */
128 + @Override
129 + public int hashCode() {
130 + return Objects.hash(selector, flag, permanent,
131 + timeout, appId, priority, nextId,
132 + treatment, op);
133 + }
134 +
135 + /*
136 + * (non-Javadoc)
137 + *
138 + * @see java.lang.Object#equals(java.lang.Object)
139 + */
140 + @Override
141 + public boolean equals(final Object obj) {
142 + if (this == obj) {
143 + return true;
144 + }
145 + if (!(obj instanceof DefaultForwardingObjective)) {
146 + return false;
147 + }
148 + final DefaultForwardingObjective other = (DefaultForwardingObjective) obj;
149 + boolean nextEq = false, treatmentEq = false;
150 + if (this.selector.equals(other.selector) &&
151 + this.flag == other.flag &&
152 + this.permanent == other.permanent &&
153 + this.timeout == other.timeout &&
154 + this.appId.equals(other.appId) &&
155 + this.priority == other.priority &&
156 + this.op == other.op) {
157 + if (this.nextId != null && other.nextId != null) {
158 + nextEq = this.nextId == other.nextId;
159 + }
160 + if (this.treatment != null && other.treatment != null) {
161 + treatmentEq = this.treatment.equals(other.treatment);
162 + }
163 + if (nextEq && treatmentEq) {
164 + return true;
165 + }
166 + }
167 + return false;
168 + }
169 +
122 /** 170 /**
123 * Returns a new builder. 171 * Returns a new builder.
124 * 172 *
......
...@@ -18,6 +18,7 @@ package org.onosproject.net.flowobjective; ...@@ -18,6 +18,7 @@ package org.onosproject.net.flowobjective;
18 import com.google.common.annotations.Beta; 18 import com.google.common.annotations.Beta;
19 import com.google.common.collect.ImmutableList; 19 import com.google.common.collect.ImmutableList;
20 import org.onosproject.core.ApplicationId; 20 import org.onosproject.core.ApplicationId;
21 +import org.onosproject.net.flow.TrafficSelector;
21 import org.onosproject.net.flow.TrafficTreatment; 22 import org.onosproject.net.flow.TrafficTreatment;
22 23
23 import java.util.Collection; 24 import java.util.Collection;
...@@ -39,6 +40,7 @@ public final class DefaultNextObjective implements NextObjective { ...@@ -39,6 +40,7 @@ public final class DefaultNextObjective implements NextObjective {
39 private final Integer id; 40 private final Integer id;
40 private final Operation op; 41 private final Operation op;
41 private final Optional<ObjectiveContext> context; 42 private final Optional<ObjectiveContext> context;
43 + private final TrafficSelector meta;
42 44
43 private DefaultNextObjective(Builder builder) { 45 private DefaultNextObjective(Builder builder) {
44 this.treatments = builder.treatments; 46 this.treatments = builder.treatments;
...@@ -47,6 +49,7 @@ public final class DefaultNextObjective implements NextObjective { ...@@ -47,6 +49,7 @@ public final class DefaultNextObjective implements NextObjective {
47 this.id = builder.id; 49 this.id = builder.id;
48 this.op = builder.op; 50 this.op = builder.op;
49 this.context = Optional.ofNullable(builder.context); 51 this.context = Optional.ofNullable(builder.context);
52 + this.meta = builder.meta;
50 } 53 }
51 54
52 @Override 55 @Override
...@@ -94,6 +97,11 @@ public final class DefaultNextObjective implements NextObjective { ...@@ -94,6 +97,11 @@ public final class DefaultNextObjective implements NextObjective {
94 return context; 97 return context;
95 } 98 }
96 99
100 + @Override
101 + public TrafficSelector meta() {
102 + return meta;
103 + }
104 +
97 /** 105 /**
98 * Returns a new builder. 106 * Returns a new builder.
99 * 107 *
...@@ -111,6 +119,7 @@ public final class DefaultNextObjective implements NextObjective { ...@@ -111,6 +119,7 @@ public final class DefaultNextObjective implements NextObjective {
111 private List<TrafficTreatment> treatments; 119 private List<TrafficTreatment> treatments;
112 private Operation op; 120 private Operation op;
113 private ObjectiveContext context; 121 private ObjectiveContext context;
122 + private TrafficSelector meta;
114 123
115 private final ImmutableList.Builder<TrafficTreatment> listBuilder 124 private final ImmutableList.Builder<TrafficTreatment> listBuilder
116 = ImmutableList.builder(); 125 = ImmutableList.builder();
...@@ -172,6 +181,12 @@ public final class DefaultNextObjective implements NextObjective { ...@@ -172,6 +181,12 @@ public final class DefaultNextObjective implements NextObjective {
172 } 181 }
173 182
174 @Override 183 @Override
184 + public Builder setMeta(TrafficSelector meta) {
185 + this.meta = meta;
186 + return this;
187 + }
188 +
189 + @Override
175 public NextObjective add() { 190 public NextObjective add() {
176 treatments = listBuilder.build(); 191 treatments = listBuilder.build();
177 op = Operation.ADD; 192 op = Operation.ADD;
...@@ -218,5 +233,55 @@ public final class DefaultNextObjective implements NextObjective { ...@@ -218,5 +233,55 @@ public final class DefaultNextObjective implements NextObjective {
218 233
219 return new DefaultNextObjective(this); 234 return new DefaultNextObjective(this);
220 } 235 }
236 +
237 + @Override
238 + public NextObjective addToExisting() {
239 + treatments = listBuilder.build();
240 + op = Operation.ADD_TO_EXISTING;
241 + checkNotNull(appId, "Must supply an application id");
242 + checkNotNull(id, "id cannot be null");
243 + checkNotNull(type, "The type cannot be null");
244 + checkArgument(!treatments.isEmpty(), "Must have at least one treatment");
245 +
246 + return new DefaultNextObjective(this);
247 + }
248 +
249 + @Override
250 + public NextObjective removeFromExisting() {
251 + treatments = listBuilder.build();
252 + op = Operation.REMOVE_FROM_EXISTING;
253 + checkNotNull(appId, "Must supply an application id");
254 + checkNotNull(id, "id cannot be null");
255 + checkNotNull(type, "The type cannot be null");
256 +
257 + return new DefaultNextObjective(this);
221 } 258 }
259 +
260 + @Override
261 + public NextObjective addToExisting(ObjectiveContext context) {
262 + treatments = listBuilder.build();
263 + op = Operation.ADD_TO_EXISTING;
264 + this.context = context;
265 + checkNotNull(appId, "Must supply an application id");
266 + checkNotNull(id, "id cannot be null");
267 + checkNotNull(type, "The type cannot be null");
268 + checkArgument(!treatments.isEmpty(), "Must have at least one treatment");
269 +
270 + return new DefaultNextObjective(this);
271 + }
272 +
273 + @Override
274 + public NextObjective removeFromExisting(ObjectiveContext context) {
275 + treatments = listBuilder.build();
276 + op = Operation.REMOVE_FROM_EXISTING;
277 + this.context = context;
278 + checkNotNull(appId, "Must supply an application id");
279 + checkNotNull(id, "id cannot be null");
280 + checkNotNull(type, "The type cannot be null");
281 +
282 + return new DefaultNextObjective(this);
283 + }
284 +
285 + }
286 +
222 } 287 }
......
...@@ -17,6 +17,7 @@ package org.onosproject.net.flowobjective; ...@@ -17,6 +17,7 @@ package org.onosproject.net.flowobjective;
17 17
18 import com.google.common.annotations.Beta; 18 import com.google.common.annotations.Beta;
19 import org.onosproject.core.ApplicationId; 19 import org.onosproject.core.ApplicationId;
20 +import org.onosproject.net.flow.TrafficSelector;
20 import org.onosproject.net.flow.TrafficTreatment; 21 import org.onosproject.net.flow.TrafficTreatment;
21 22
22 import java.util.Collection; 23 import java.util.Collection;
...@@ -34,7 +35,7 @@ import java.util.Collection; ...@@ -34,7 +35,7 @@ import java.util.Collection;
34 * - Failover 35 * - Failover
35 * - Simple 36 * - Simple
36 * 37 *
37 - * These types will indicate to the driver what the intended behaviour is. 38 + * These types will indicate to the driver what the intended behavior is.
38 * For example, a broadcast next objective with a collection of output 39 * For example, a broadcast next objective with a collection of output
39 * treatments will indicate to a driver that all output actions are expected 40 * treatments will indicate to a driver that all output actions are expected
40 * to be executed simultaneously. The driver is then free to implement this 41 * to be executed simultaneously. The driver is then free to implement this
...@@ -84,6 +85,16 @@ public interface NextObjective extends Objective { ...@@ -84,6 +85,16 @@ public interface NextObjective extends Objective {
84 Type type(); 85 Type type();
85 86
86 /** 87 /**
88 + * Auxiliary optional information provided to the device-driver.Typically
89 + * conveys information about selectors (matches) that are intended to
90 + * use this Next Objective.
91 + *
92 + * @return a selector intended to pass meta information to the device driver.
93 + * Value may be null if no meta information is provided.
94 + */
95 + TrafficSelector meta();
96 +
97 + /**
87 * A next step builder. 98 * A next step builder.
88 */ 99 */
89 interface Builder extends Objective.Builder { 100 interface Builder extends Objective.Builder {
...@@ -131,6 +142,14 @@ public interface NextObjective extends Objective { ...@@ -131,6 +142,14 @@ public interface NextObjective extends Objective {
131 Builder withPriority(int priority); 142 Builder withPriority(int priority);
132 143
133 /** 144 /**
145 + * Set meta information related to this next objective.
146 + *
147 + * @param selector match conditions
148 + * @return an objective builder
149 + */
150 + Builder setMeta(TrafficSelector selector);
151 +
152 + /**
134 * Builds the next objective that will be added. 153 * Builds the next objective that will be added.
135 * 154 *
136 * @return a next objective 155 * @return a next objective
...@@ -162,6 +181,40 @@ public interface NextObjective extends Objective { ...@@ -162,6 +181,40 @@ public interface NextObjective extends Objective {
162 */ 181 */
163 NextObjective remove(ObjectiveContext context); 182 NextObjective remove(ObjectiveContext context);
164 183
184 + /**
185 + * Build the next objective that will be added, with {@link Operation}
186 + * ADD_TO_EXISTING.
187 + *
188 + * @return a next objective
189 + */
190 + NextObjective addToExisting();
191 +
192 + /**
193 + * Build the next objective that will be removed, with {@link Operation}
194 + * REMOVE_FROM_EXISTING.
195 + *
196 + * @return a next objective
197 + */
198 + NextObjective removeFromExisting();
199 +
200 + /**
201 + * Builds the next objective that will be added, with {@link Operation}
202 + * ADD_TO_EXISTING. The context will be used to notify the calling application.
203 + *
204 + * @param context an objective context
205 + * @return a next objective
206 + */
207 + NextObjective addToExisting(ObjectiveContext context);
208 +
209 + /**
210 + * Builds the next objective that will be removed, with {@link Operation}
211 + * REMOVE_FROM_EXISTING. The context will be used to notify the calling application.
212 + *
213 + * @param context an objective context
214 + * @return a next objective
215 + */
216 + NextObjective removeFromExisting(ObjectiveContext context);
217 +
165 } 218 }
166 219
167 } 220 }
......
...@@ -21,7 +21,7 @@ import org.onosproject.core.ApplicationId; ...@@ -21,7 +21,7 @@ import org.onosproject.core.ApplicationId;
21 import java.util.Optional; 21 import java.util.Optional;
22 22
23 /** 23 /**
24 - * Base representation of an flow description. 24 + * Base representation of a flow-objective description.
25 */ 25 */
26 @Beta 26 @Beta
27 public interface Objective { 27 public interface Objective {
...@@ -35,14 +35,30 @@ public interface Objective { ...@@ -35,14 +35,30 @@ public interface Objective {
35 */ 35 */
36 enum Operation { 36 enum Operation {
37 /** 37 /**
38 - * Adds the objective. 38 + * Adds the objective. Can be used for any flow objective. For forwarding
39 + * and filtering objectives, existing objectives with identical selector
40 + * and priority fields (but different treatments or next) will be replaced.
41 + * For next objectives, if modification is desired, ADD will not
42 + * do anything - use ADD_TO_EXISTING.
39 */ 43 */
40 ADD, 44 ADD,
41 45
42 /** 46 /**
43 - * Removes the objective. 47 + * Removes the objective. Can be used for any flow objective.
44 */ 48 */
45 - REMOVE 49 + REMOVE,
50 +
51 + /**
52 + * Add to an existing Next Objective. Should not be used for any other
53 + * objective.
54 + */
55 + ADD_TO_EXISTING,
56 +
57 + /**
58 + * Remove from an existing Next Objective. Should not be used for any
59 + * other objective.
60 + */
61 + REMOVE_FROM_EXISTING
46 } 62 }
47 63
48 /** 64 /**
...@@ -129,6 +145,7 @@ public interface Objective { ...@@ -129,6 +145,7 @@ public interface Objective {
129 * @return an objective builder 145 * @return an objective builder
130 */ 146 */
131 Builder withPriority(int priority); 147 Builder withPriority(int priority);
148 +
132 } 149 }
133 150
134 } 151 }
......
...@@ -25,6 +25,7 @@ import java.util.Arrays; ...@@ -25,6 +25,7 @@ import java.util.Arrays;
25 public class DefaultGroupKey implements GroupKey { 25 public class DefaultGroupKey implements GroupKey {
26 26
27 private final byte[] key; 27 private final byte[] key;
28 + protected static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
28 29
29 public DefaultGroupKey(byte[] key) { 30 public DefaultGroupKey(byte[] key) {
30 this.key = checkNotNull(key); 31 this.key = checkNotNull(key);
...@@ -52,4 +53,20 @@ public class DefaultGroupKey implements GroupKey { ...@@ -52,4 +53,20 @@ public class DefaultGroupKey implements GroupKey {
52 return Arrays.hashCode(this.key); 53 return Arrays.hashCode(this.key);
53 } 54 }
54 55
56 + /**
57 + * Returns a hex string representation of the byte array that is used
58 + * as a group key. This solution was adapted from
59 + * http://stackoverflow.com/questions/9655181/
60 + */
61 + @Override
62 + public String toString() {
63 + char[] hexChars = new char[key.length * 2];
64 + for (int j = 0; j < key.length; j++) {
65 + int v = key[j] & 0xFF;
66 + hexChars[j * 2] = HEX_ARRAY[v >>> 4];
67 + hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
68 + }
69 + return "GroupKey:0x" + new String(hexChars);
70 + }
71 +
55 } 72 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -54,6 +54,7 @@ import org.slf4j.Logger; ...@@ -54,6 +54,7 @@ import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory; 54 import org.slf4j.LoggerFactory;
55 55
56 import java.util.Map; 56 import java.util.Map;
57 +import java.util.Objects;
57 import java.util.Set; 58 import java.util.Set;
58 import java.util.concurrent.ExecutorService; 59 import java.util.concurrent.ExecutorService;
59 60
...@@ -226,10 +227,11 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -226,10 +227,11 @@ public class FlowObjectiveManager implements FlowObjectiveService {
226 if (fwd.nextId() != null && 227 if (fwd.nextId() != null &&
227 flowObjectiveStore.getNextGroup(fwd.nextId()) == null) { 228 flowObjectiveStore.getNextGroup(fwd.nextId()) == null) {
228 log.trace("Queuing forwarding objective for nextId {}", fwd.nextId()); 229 log.trace("Queuing forwarding objective for nextId {}", fwd.nextId());
229 - if (pendingForwards.putIfAbsent(fwd.nextId(), 230 + // TODO: change to computeIfAbsent
230 - Sets.newHashSet(new PendingNext(deviceId, fwd))) != null) { 231 + Set<PendingNext> pnext = pendingForwards.putIfAbsent(fwd.nextId(),
231 - Set<PendingNext> pending = pendingForwards.get(fwd.nextId()); 232 + Sets.newHashSet(new PendingNext(deviceId, fwd)));
232 - pending.add(new PendingNext(deviceId, fwd)); 233 + if (pnext != null) {
234 + pnext.add(new PendingNext(deviceId, fwd));
233 } 235 }
234 return true; 236 return true;
235 } 237 }
...@@ -412,5 +414,26 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -412,5 +414,26 @@ public class FlowObjectiveManager implements FlowObjectiveService {
412 public ForwardingObjective forwardingObjective() { 414 public ForwardingObjective forwardingObjective() {
413 return fwd; 415 return fwd;
414 } 416 }
417 +
418 + @Override
419 + public int hashCode() {
420 + return Objects.hash(deviceId, fwd);
421 + }
422 +
423 + @Override
424 + public boolean equals(final Object obj) {
425 + if (this == obj) {
426 + return true;
427 + }
428 + if (!(obj instanceof PendingNext)) {
429 + return false;
430 + }
431 + final PendingNext other = (PendingNext) obj;
432 + if (this.deviceId.equals(other.deviceId) &&
433 + this.fwd.equals(other.fwd)) {
434 + return true;
435 + }
436 + return false;
437 + }
415 } 438 }
416 } 439 }
......
...@@ -348,9 +348,11 @@ public class DistributedGroupStore ...@@ -348,9 +348,11 @@ public class DistributedGroupStore
348 public void storeGroupDescription(GroupDescription groupDesc) { 348 public void storeGroupDescription(GroupDescription groupDesc) {
349 log.debug("In storeGroupDescription"); 349 log.debug("In storeGroupDescription");
350 // Check if a group is existing with the same key 350 // Check if a group is existing with the same key
351 - if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) { 351 + Group existingGroup = getGroup(groupDesc.deviceId(), groupDesc.appCookie());
352 - log.warn("Group already exists with the same key {}", 352 + if (existingGroup != null) {
353 - groupDesc.appCookie()); 353 + log.warn("Group already exists with the same key {} in dev:{} with id:{}",
354 + groupDesc.appCookie(), groupDesc.deviceId(),
355 + Integer.toHexString(existingGroup.id().id()));
354 return; 356 return;
355 } 357 }
356 358
......
...@@ -368,6 +368,7 @@ public final class KryoNamespaces { ...@@ -368,6 +368,7 @@ public final class KryoNamespaces {
368 L2ModificationInstruction.ModVlanPcpInstruction.class, 368 L2ModificationInstruction.ModVlanPcpInstruction.class,
369 L2ModificationInstruction.PopVlanInstruction.class, 369 L2ModificationInstruction.PopVlanInstruction.class,
370 L2ModificationInstruction.ModMplsLabelInstruction.class, 370 L2ModificationInstruction.ModMplsLabelInstruction.class,
371 + L2ModificationInstruction.ModMplsBosInstruction.class,
371 L2ModificationInstruction.ModMplsTtlInstruction.class, 372 L2ModificationInstruction.ModMplsTtlInstruction.class,
372 L2ModificationInstruction.ModTunnelIdInstruction.class, 373 L2ModificationInstruction.ModTunnelIdInstruction.class,
373 L3ModificationInstruction.class, 374 L3ModificationInstruction.class,
......
...@@ -18,15 +18,19 @@ package org.onosproject.driver.pipeline; ...@@ -18,15 +18,19 @@ package org.onosproject.driver.pipeline;
18 import static org.slf4j.LoggerFactory.getLogger; 18 import static org.slf4j.LoggerFactory.getLogger;
19 19
20 import java.util.ArrayList; 20 import java.util.ArrayList;
21 +import java.util.Collection;
21 import java.util.Collections; 22 import java.util.Collections;
23 +import java.util.Deque;
22 import java.util.List; 24 import java.util.List;
23 import java.util.Set; 25 import java.util.Set;
24 import java.util.concurrent.ConcurrentHashMap; 26 import java.util.concurrent.ConcurrentHashMap;
25 27
28 +import org.onlab.packet.Ethernet;
26 import org.onlab.packet.VlanId; 29 import org.onlab.packet.VlanId;
27 import org.onosproject.core.ApplicationId; 30 import org.onosproject.core.ApplicationId;
28 import org.onosproject.net.Port; 31 import org.onosproject.net.Port;
29 import org.onosproject.net.PortNumber; 32 import org.onosproject.net.PortNumber;
33 +import org.onosproject.net.behaviour.NextGroup;
30 import org.onosproject.net.flow.DefaultFlowRule; 34 import org.onosproject.net.flow.DefaultFlowRule;
31 import org.onosproject.net.flow.DefaultTrafficSelector; 35 import org.onosproject.net.flow.DefaultTrafficSelector;
32 import org.onosproject.net.flow.DefaultTrafficTreatment; 36 import org.onosproject.net.flow.DefaultTrafficTreatment;
...@@ -35,8 +39,18 @@ import org.onosproject.net.flow.FlowRuleOperations; ...@@ -35,8 +39,18 @@ import org.onosproject.net.flow.FlowRuleOperations;
35 import org.onosproject.net.flow.FlowRuleOperationsContext; 39 import org.onosproject.net.flow.FlowRuleOperationsContext;
36 import org.onosproject.net.flow.TrafficSelector; 40 import org.onosproject.net.flow.TrafficSelector;
37 import org.onosproject.net.flow.TrafficTreatment; 41 import org.onosproject.net.flow.TrafficTreatment;
42 +import org.onosproject.net.flow.criteria.Criterion;
43 +import org.onosproject.net.flow.criteria.EthTypeCriterion;
44 +import org.onosproject.net.flow.criteria.IPCriterion;
45 +import org.onosproject.net.flow.criteria.MplsBosCriterion;
46 +import org.onosproject.net.flow.criteria.MplsCriterion;
38 import org.onosproject.net.flow.criteria.PortCriterion; 47 import org.onosproject.net.flow.criteria.PortCriterion;
39 import org.onosproject.net.flow.criteria.VlanIdCriterion; 48 import org.onosproject.net.flow.criteria.VlanIdCriterion;
49 +import org.onosproject.net.flow.instructions.Instruction;
50 +import org.onosproject.net.flowobjective.ForwardingObjective;
51 +import org.onosproject.net.flowobjective.ObjectiveError;
52 +import org.onosproject.net.group.Group;
53 +import org.onosproject.net.group.GroupKey;
40 import org.slf4j.Logger; 54 import org.slf4j.Logger;
41 55
42 56
...@@ -108,6 +122,81 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -108,6 +122,81 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
108 return rules; 122 return rules;
109 } 123 }
110 124
125 + @Override
126 + protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
127 + TrafficSelector selector = fwd.selector();
128 + EthTypeCriterion ethType =
129 + (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
130 + if ((ethType == null) ||
131 + (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
132 + (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
133 + log.warn("processSpecific: Unsupported "
134 + + "forwarding objective criteraia");
135 + fail(fwd, ObjectiveError.UNSUPPORTED);
136 + return Collections.emptySet();
137 + }
138 +
139 + int forTableId = -1;
140 + TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
141 + if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
142 + filteredSelector.matchEthType(Ethernet.TYPE_IPV4)
143 + .matchIPDst(((IPCriterion)
144 + selector.getCriterion(Criterion.Type.IPV4_DST)).ip());
145 + forTableId = UNICAST_ROUTING_TABLE;
146 + log.debug("processing IPv4 specific forwarding objective {} hash{} in dev:{}",
147 + fwd.id(), fwd.hashCode(), deviceId);
148 + } else {
149 + filteredSelector
150 + .matchEthType(Ethernet.MPLS_UNICAST)
151 + .matchMplsLabel(((MplsCriterion)
152 + selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
153 + MplsBosCriterion bos = (MplsBosCriterion) selector
154 + .getCriterion(Criterion.Type.MPLS_BOS);
155 + if (bos != null) {
156 + filteredSelector.matchMplsBos(bos.mplsBos());
157 + }
158 + forTableId = MPLS_TABLE_1;
159 + log.debug("processing MPLS specific forwarding objective {} hash:{} in dev {}",
160 + fwd.id(), fwd.hashCode(), deviceId);
161 + }
162 +
163 + TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
164 + if (fwd.treatment() != null) {
165 + for (Instruction i : fwd.treatment().allInstructions()) {
166 + tb.add(i);
167 + }
168 + }
169 +
170 + if (fwd.nextId() != null) {
171 + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
172 + List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
173 + // we only need the top level group's key to point the flow to it
174 + Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
175 + if (group == null) {
176 + log.warn("The group left!");
177 + fail(fwd, ObjectiveError.GROUPMISSING);
178 + return Collections.emptySet();
179 + }
180 + tb.deferred().group(group.id());
181 + }
182 + tb.transition(ACL_TABLE);
183 + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
184 + .fromApp(fwd.appId())
185 + .withPriority(fwd.priority())
186 + .forDevice(deviceId)
187 + .withSelector(filteredSelector.build())
188 + .withTreatment(tb.build())
189 + .forTable(forTableId);
190 +
191 + if (fwd.permanent()) {
192 + ruleBuilder.makePermanent();
193 + } else {
194 + ruleBuilder.makeTemporary(fwd.timeout());
195 + }
196 +
197 + return Collections.singletonList(ruleBuilder.build());
198 + }
199 +
111 200
112 @Override 201 @Override
113 protected void initializePipeline() { 202 protected void initializePipeline() {
......