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
348 additions
and
30 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; |
... | @@ -467,7 +466,7 @@ public class DefaultRoutingHandler { | ... | @@ -467,7 +466,7 @@ public class DefaultRoutingHandler { |
467 | if (targetIsEdge && destIsEdge) { | 466 | if (targetIsEdge && destIsEdge) { |
468 | Set<Ip4Prefix> subnets = config.getSubnets(destSw); | 467 | Set<Ip4Prefix> subnets = config.getSubnets(destSw); |
469 | log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}", | 468 | log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for subnets {}", |
470 | - targetSw, destSw, subnets); | 469 | + targetSw, destSw, subnets); |
471 | result = rulePopulator.populateIpRuleForSubnet(targetSw, | 470 | result = rulePopulator.populateIpRuleForSubnet(targetSw, |
472 | subnets, | 471 | subnets, |
473 | destSw, | 472 | destSw, |
... | @@ -479,24 +478,23 @@ public class DefaultRoutingHandler { | ... | @@ -479,24 +478,23 @@ public class DefaultRoutingHandler { |
479 | Ip4Address routerIp = destRouterIp; | 478 | Ip4Address routerIp = destRouterIp; |
480 | IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); | 479 | IpPrefix routerIpPrefix = IpPrefix.valueOf(routerIp, IpPrefix.MAX_INET_MASK_LENGTH); |
481 | log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}", | 480 | log.debug("* populateEcmpRoutingRulePartial in device {} towards {} for router IP {}", |
482 | - targetSw, destSw, routerIpPrefix); | 481 | + targetSw, destSw, routerIpPrefix); |
483 | result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops); | 482 | result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops); |
484 | if (!result) { | 483 | if (!result) { |
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 {}", |
493 | - targetSw, destSw, routerIpPrefix); | 492 | + targetSw, destSw, routerIpPrefix); |
494 | result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops); | 493 | result = rulePopulator.populateIpRuleForRouter(targetSw, routerIpPrefix, destSw, nextHops); |
495 | if (!result) { | 494 | if (!result) { |
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 | ... | ... |
This diff is collapsed. Click to expand it.
... | @@ -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 | ... | ... |
This diff is collapsed. Click to expand it.
... | @@ -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); | ||
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 | + | ||
221 | } | 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() { | ... | ... |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment