Committed by
Gerrit Code Review
CORD-455 Implement multicast support in OFDPA driver
Also refactor Ofdpa2GroupHandler Change-Id: Id6a9224cab663f57edb8e85a0e7d81e7da3df132
Showing
4 changed files
with
283 additions
and
140 deletions
... | @@ -26,6 +26,7 @@ import java.util.Set; | ... | @@ -26,6 +26,7 @@ import java.util.Set; |
26 | import java.util.concurrent.ConcurrentHashMap; | 26 | import java.util.concurrent.ConcurrentHashMap; |
27 | 27 | ||
28 | import com.google.common.collect.ImmutableList; | 28 | import com.google.common.collect.ImmutableList; |
29 | +import com.google.common.collect.ImmutableSet; | ||
29 | import org.onlab.packet.Ethernet; | 30 | import org.onlab.packet.Ethernet; |
30 | import org.onlab.packet.MacAddress; | 31 | import org.onlab.packet.MacAddress; |
31 | import org.onlab.packet.IpPrefix; | 32 | import org.onlab.packet.IpPrefix; |
... | @@ -99,7 +100,8 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { | ... | @@ -99,7 +100,8 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { |
99 | // convert filtering conditions for switch-intfs into flowrules | 100 | // convert filtering conditions for switch-intfs into flowrules |
100 | FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); | 101 | FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); |
101 | for (Criterion criterion : filt.conditions()) { | 102 | for (Criterion criterion : filt.conditions()) { |
102 | - if (criterion.type() == Criterion.Type.ETH_DST) { | 103 | + if (criterion.type() == Criterion.Type.ETH_DST || |
104 | + criterion.type() == Criterion.Type.ETH_DST_MASKED) { | ||
103 | ethCriterion = (EthCriterion) criterion; | 105 | ethCriterion = (EthCriterion) criterion; |
104 | } else if (criterion.type() == Criterion.Type.VLAN_VID) { | 106 | } else if (criterion.type() == Criterion.Type.VLAN_VID) { |
105 | vidCriterion = (VlanIdCriterion) criterion; | 107 | vidCriterion = (VlanIdCriterion) criterion; |
... | @@ -294,6 +296,11 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { | ... | @@ -294,6 +296,11 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { |
294 | return processEthDstOnlyFilter(ethCriterion, applicationId); | 296 | return processEthDstOnlyFilter(ethCriterion, applicationId); |
295 | } | 297 | } |
296 | 298 | ||
299 | + // Multicast MAC | ||
300 | + if (ethCriterion.mask() != null) { | ||
301 | + return processMcastEthDstFilter(ethCriterion, applicationId); | ||
302 | + } | ||
303 | + | ||
297 | //handling untagged packets via assigned VLAN | 304 | //handling untagged packets via assigned VLAN |
298 | if (vidCriterion.vlanId() == VlanId.NONE) { | 305 | if (vidCriterion.vlanId() == VlanId.NONE) { |
299 | vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); | 306 | vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); |
... | @@ -416,9 +423,26 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { | ... | @@ -416,9 +423,26 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { |
416 | */ | 423 | */ |
417 | if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) { | 424 | if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) { |
418 | IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip(); | 425 | IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip(); |
426 | + if (ipv4Dst.isMulticast()) { | ||
427 | + if (ipv4Dst.prefixLength() != 32) { | ||
428 | + log.warn("Multicast specific forwarding objective can only be /32"); | ||
429 | + fail(fwd, ObjectiveError.BADPARAMS); | ||
430 | + return ImmutableSet.of(); | ||
431 | + } | ||
432 | + VlanId assignedVlan = readVlanFromSelector(fwd.meta()); | ||
433 | + if (assignedVlan == null) { | ||
434 | + log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort."); | ||
435 | + fail(fwd, ObjectiveError.BADPARAMS); | ||
436 | + return ImmutableSet.of(); | ||
437 | + } | ||
438 | + filteredSelector.matchVlanId(assignedVlan); | ||
439 | + filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst); | ||
440 | + forTableId = MULTICAST_ROUTING_TABLE; | ||
441 | + log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}" | ||
442 | + + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); | ||
443 | + } else { | ||
419 | if (ipv4Dst.prefixLength() > 0) { | 444 | if (ipv4Dst.prefixLength() > 0) { |
420 | - filteredSelector.matchEthType(Ethernet.TYPE_IPV4) | 445 | + filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst); |
421 | - .matchIPDst(ipv4Dst); | ||
422 | } else { | 446 | } else { |
423 | filteredSelector.matchEthType(Ethernet.TYPE_IPV4) | 447 | filteredSelector.matchEthType(Ethernet.TYPE_IPV4) |
424 | .matchIPDst(IpPrefix.valueOf("0.0.0.0/1")); | 448 | .matchIPDst(IpPrefix.valueOf("0.0.0.0/1")); |
... | @@ -427,8 +451,9 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { | ... | @@ -427,8 +451,9 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { |
427 | defaultRule = true; | 451 | defaultRule = true; |
428 | } | 452 | } |
429 | forTableId = UNICAST_ROUTING_TABLE; | 453 | forTableId = UNICAST_ROUTING_TABLE; |
430 | - log.debug("processing IPv4 specific forwarding objective {} -> next:{}" | 454 | + log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}" |
431 | + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); | 455 | + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); |
456 | + } | ||
432 | } else { | 457 | } else { |
433 | filteredSelector | 458 | filteredSelector |
434 | .matchEthType(Ethernet.MPLS_UNICAST) | 459 | .matchEthType(Ethernet.MPLS_UNICAST) | ... | ... |
... | @@ -83,6 +83,11 @@ public class CpqdOfdpa2VlanPipeline extends CpqdOfdpa2Pipeline { | ... | @@ -83,6 +83,11 @@ public class CpqdOfdpa2VlanPipeline extends CpqdOfdpa2Pipeline { |
83 | return processEthDstOnlyFilter(ethCriterion, applicationId); | 83 | return processEthDstOnlyFilter(ethCriterion, applicationId); |
84 | } | 84 | } |
85 | 85 | ||
86 | + // Multicast MAC | ||
87 | + if (ethCriterion.mask() != null) { | ||
88 | + return processMcastEthDstFilter(ethCriterion, applicationId); | ||
89 | + } | ||
90 | + | ||
86 | //handling untagged packets via assigned VLAN | 91 | //handling untagged packets via assigned VLAN |
87 | if (vidCriterion.vlanId() == VlanId.NONE) { | 92 | if (vidCriterion.vlanId() == VlanId.NONE) { |
88 | vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); | 93 | vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); | ... | ... |
... | @@ -4,7 +4,10 @@ import com.google.common.cache.Cache; | ... | @@ -4,7 +4,10 @@ import com.google.common.cache.Cache; |
4 | import com.google.common.cache.CacheBuilder; | 4 | import com.google.common.cache.CacheBuilder; |
5 | import com.google.common.cache.RemovalCause; | 5 | import com.google.common.cache.RemovalCause; |
6 | import com.google.common.cache.RemovalNotification; | 6 | import com.google.common.cache.RemovalNotification; |
7 | +import com.google.common.collect.ImmutableList; | ||
8 | +import com.google.common.collect.Lists; | ||
7 | import org.onlab.osgi.ServiceDirectory; | 9 | import org.onlab.osgi.ServiceDirectory; |
10 | +import org.onlab.packet.IpPrefix; | ||
8 | import org.onlab.packet.MacAddress; | 11 | import org.onlab.packet.MacAddress; |
9 | import org.onlab.packet.MplsLabel; | 12 | import org.onlab.packet.MplsLabel; |
10 | import org.onlab.packet.VlanId; | 13 | import org.onlab.packet.VlanId; |
... | @@ -74,7 +77,9 @@ public class Ofdpa2GroupHandler { | ... | @@ -74,7 +77,9 @@ public class Ofdpa2GroupHandler { |
74 | * L3 VPN Groups have <4bits-9><4bits-2><24bits-index> | 77 | * L3 VPN Groups have <4bits-9><4bits-2><24bits-index> |
75 | */ | 78 | */ |
76 | private static final int L2_INTERFACE_TYPE = 0x00000000; | 79 | private static final int L2_INTERFACE_TYPE = 0x00000000; |
80 | + private static final int L3_INTERFACE_TYPE = 0x50000000; | ||
77 | private static final int L3_UNICAST_TYPE = 0x20000000; | 81 | private static final int L3_UNICAST_TYPE = 0x20000000; |
82 | + private static final int L3_MULTICAST_TYPE = 0x60000000; | ||
78 | private static final int MPLS_INTERFACE_TYPE = 0x90000000; | 83 | private static final int MPLS_INTERFACE_TYPE = 0x90000000; |
79 | private static final int MPLS_L3VPN_SUBTYPE = 0x92000000; | 84 | private static final int MPLS_L3VPN_SUBTYPE = 0x92000000; |
80 | private static final int L3_ECMP_TYPE = 0x70000000; | 85 | private static final int L3_ECMP_TYPE = 0x70000000; |
... | @@ -82,6 +87,7 @@ public class Ofdpa2GroupHandler { | ... | @@ -82,6 +87,7 @@ public class Ofdpa2GroupHandler { |
82 | 87 | ||
83 | private static final int TYPE_MASK = 0x0fffffff; | 88 | private static final int TYPE_MASK = 0x0fffffff; |
84 | private static final int SUBTYPE_MASK = 0x00ffffff; | 89 | private static final int SUBTYPE_MASK = 0x00ffffff; |
90 | + private static final int TYPE_VLAN_MASK = 0x0000ffff; | ||
85 | 91 | ||
86 | private static final int PORT_LOWER_BITS_MASK = 0x3f; | 92 | private static final int PORT_LOWER_BITS_MASK = 0x3f; |
87 | private static final long PORT_HIGHER_BITS_MASK = ~PORT_LOWER_BITS_MASK; | 93 | private static final long PORT_HIGHER_BITS_MASK = ~PORT_LOWER_BITS_MASK; |
... | @@ -210,19 +216,19 @@ public class Ofdpa2GroupHandler { | ... | @@ -210,19 +216,19 @@ public class Ofdpa2GroupHandler { |
210 | } | 216 | } |
211 | // create object for local and distributed storage | 217 | // create object for local and distributed storage |
212 | Deque<GroupKey> gkeyChain = new ArrayDeque<>(); | 218 | Deque<GroupKey> gkeyChain = new ArrayDeque<>(); |
213 | - gkeyChain.addFirst(groupInfo.innerGrpDesc.appCookie()); | 219 | + gkeyChain.addFirst(groupInfo.innerMostGroupDesc.appCookie()); |
214 | - gkeyChain.addFirst(groupInfo.outerGrpDesc.appCookie()); | 220 | + gkeyChain.addFirst(groupInfo.nextGroupDesc.appCookie()); |
215 | OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup( | 221 | OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup( |
216 | Collections.singletonList(gkeyChain), | 222 | Collections.singletonList(gkeyChain), |
217 | nextObj); | 223 | nextObj); |
218 | 224 | ||
219 | // store l3groupkey with the ofdpaNextGroup for the nextObjective that depends on it | 225 | // store l3groupkey with the ofdpaNextGroup for the nextObjective that depends on it |
220 | - updatePendingNextObjective(groupInfo.outerGrpDesc.appCookie(), ofdpaGrp); | 226 | + updatePendingNextObjective(groupInfo.nextGroupDesc.appCookie(), ofdpaGrp); |
221 | 227 | ||
222 | // now we are ready to send the l2 groupDescription (inner), as all the stores | 228 | // now we are ready to send the l2 groupDescription (inner), as all the stores |
223 | // that will get async replies have been updated. By waiting to update | 229 | // that will get async replies have been updated. By waiting to update |
224 | // the stores, we prevent nasty race conditions. | 230 | // the stores, we prevent nasty race conditions. |
225 | - groupService.addGroup(groupInfo.innerGrpDesc); | 231 | + groupService.addGroup(groupInfo.innerMostGroupDesc); |
226 | } | 232 | } |
227 | 233 | ||
228 | /** | 234 | /** |
... | @@ -231,71 +237,30 @@ public class Ofdpa2GroupHandler { | ... | @@ -231,71 +237,30 @@ public class Ofdpa2GroupHandler { |
231 | * @param nextObj the next Objective | 237 | * @param nextObj the next Objective |
232 | */ | 238 | */ |
233 | private void createL2InterfaceGroup(NextObjective nextObj) { | 239 | private void createL2InterfaceGroup(NextObjective nextObj) { |
234 | - // only allowed actions are vlan pop and outport | 240 | + VlanId assignedVlan = Ofdpa2Pipeline.readVlanFromSelector(nextObj.meta()); |
235 | - TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); | 241 | + if (assignedVlan == null) { |
236 | - PortNumber portNum = null; | 242 | + log.warn("VLAN ID required by simple next obj is missing. Abort."); |
237 | - for (Instruction ins : nextObj.next().iterator().next().allInstructions()) { | 243 | + Ofdpa2Pipeline.fail(nextObj, ObjectiveError.BADPARAMS); |
238 | - if (ins.type() == Instruction.Type.L2MODIFICATION) { | ||
239 | - L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; | ||
240 | - switch (l2ins.subtype()) { | ||
241 | - case VLAN_POP: | ||
242 | - ttb.add(l2ins); | ||
243 | - break; | ||
244 | - default: | ||
245 | - break; | ||
246 | - } | ||
247 | - } else if (ins.type() == Instruction.Type.OUTPUT) { | ||
248 | - portNum = ((Instructions.OutputInstruction) ins).port(); | ||
249 | - ttb.add(ins); | ||
250 | - } else { | ||
251 | - log.warn("Driver does not handle this type of TrafficTreatment" | ||
252 | - + " instruction in simple nextObjectives: {}", ins.type()); | ||
253 | - } | ||
254 | - } | ||
255 | - | ||
256 | - VlanId vlanId = readVlanFromMeta(nextObj); | ||
257 | - if (vlanId == null) { | ||
258 | - log.error("Driver cannot process an L2/L3 group chain without " | ||
259 | - + "egress vlan information for dev: {} port:{}", | ||
260 | - deviceId, portNum); | ||
261 | return; | 244 | return; |
262 | } | 245 | } |
263 | 246 | ||
264 | - // assemble information for ofdpa l2interface group | 247 | + List<GroupInfo> groupInfos = prepareL2InterfaceGroup(nextObj, assignedVlan); |
265 | - int l2groupId = L2_INTERFACE_TYPE | (vlanId.toShort() << 16) | (int) portNum.toLong(); | ||
266 | - // a globally unique groupkey that is different for ports in the same devices | ||
267 | - // but different for the same portnumber on different devices. Also different | ||
268 | - // for the various group-types created out of the same next objective. | ||
269 | - int l2gk = l2InterfaceGroupKey(deviceId, vlanId, portNum.toLong()); | ||
270 | - final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk)); | ||
271 | 248 | ||
272 | - // create group description for the l2interfacegroup | 249 | + // There is only one L2 interface group in this case |
273 | - GroupBucket l2interfaceGroupBucket = | 250 | + GroupDescription l2InterfaceGroupDesc = groupInfos.get(0).innerMostGroupDesc; |
274 | - DefaultGroupBucket.createIndirectGroupBucket(ttb.build()); | ||
275 | - GroupDescription l2groupDescription = | ||
276 | - new DefaultGroupDescription( | ||
277 | - deviceId, | ||
278 | - GroupDescription.Type.INDIRECT, | ||
279 | - new GroupBuckets(Collections.singletonList( | ||
280 | - l2interfaceGroupBucket)), | ||
281 | - l2groupkey, | ||
282 | - l2groupId, | ||
283 | - nextObj.appId()); | ||
284 | - log.debug("Trying L2Interface: device:{} gid:{} gkey:{} nextId:{}", | ||
285 | - deviceId, Integer.toHexString(l2groupId), | ||
286 | - l2groupkey, nextObj.id()); | ||
287 | 251 | ||
288 | - // create object for local and distributed storage | 252 | + // Put all dependency information into allGroupKeys |
289 | - Deque<GroupKey> singleKey = new ArrayDeque<>(); | 253 | + List<Deque<GroupKey>> allGroupKeys = Lists.newArrayList(); |
290 | - singleKey.addFirst(l2groupkey); | 254 | + Deque<GroupKey> gkeyChain = new ArrayDeque<>(); |
291 | - OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup( | 255 | + gkeyChain.addFirst(l2InterfaceGroupDesc.appCookie()); |
292 | - Collections.singletonList(singleKey), | 256 | + allGroupKeys.add(gkeyChain); |
293 | - nextObj); | 257 | + |
258 | + // Point the next objective to this group | ||
259 | + OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj); | ||
260 | + updatePendingNextObjective(l2InterfaceGroupDesc.appCookie(), ofdpaGrp); | ||
294 | 261 | ||
295 | - // store l2groupkey for the nextObjective that depends on it | 262 | + // Start installing the inner-most group |
296 | - updatePendingNextObjective(l2groupkey, ofdpaGrp); | 263 | + groupService.addGroup(l2InterfaceGroupDesc); |
297 | - // send the group description to the group service | ||
298 | - groupService.addGroup(l2groupDescription); | ||
299 | } | 264 | } |
300 | 265 | ||
301 | /** | 266 | /** |
... | @@ -454,14 +419,14 @@ public class Ofdpa2GroupHandler { | ... | @@ -454,14 +419,14 @@ public class Ofdpa2GroupHandler { |
454 | updatePendingGroups(l2groupkey, gce); | 419 | updatePendingGroups(l2groupkey, gce); |
455 | 420 | ||
456 | // create group description for the inner l2interfacegroup | 421 | // create group description for the inner l2interfacegroup |
457 | - GroupBucket l2interfaceGroupBucket = | 422 | + GroupBucket l2InterfaceGroupBucket = |
458 | DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build()); | 423 | DefaultGroupBucket.createIndirectGroupBucket(innerTtb.build()); |
459 | GroupDescription l2groupDescription = | 424 | GroupDescription l2groupDescription = |
460 | new DefaultGroupDescription( | 425 | new DefaultGroupDescription( |
461 | deviceId, | 426 | deviceId, |
462 | GroupDescription.Type.INDIRECT, | 427 | GroupDescription.Type.INDIRECT, |
463 | new GroupBuckets(Collections.singletonList( | 428 | new GroupBuckets(Collections.singletonList( |
464 | - l2interfaceGroupBucket)), | 429 | + l2InterfaceGroupBucket)), |
465 | l2groupkey, | 430 | l2groupkey, |
466 | l2groupId, | 431 | l2groupId, |
467 | appId); | 432 | appId); |
... | @@ -481,21 +446,40 @@ public class Ofdpa2GroupHandler { | ... | @@ -481,21 +446,40 @@ public class Ofdpa2GroupHandler { |
481 | * @param nextObj the nextObjective of type BROADCAST | 446 | * @param nextObj the nextObjective of type BROADCAST |
482 | */ | 447 | */ |
483 | private void processBroadcastNextObjective(NextObjective nextObj) { | 448 | private void processBroadcastNextObjective(NextObjective nextObj) { |
484 | - // break up broadcast next objective to multiple groups | 449 | + VlanId assignedVlan = Ofdpa2Pipeline.readVlanFromSelector(nextObj.meta()); |
485 | - Collection<TrafficTreatment> buckets = nextObj.next(); | 450 | + if (assignedVlan == null) { |
451 | + log.warn("VLAN ID required by broadcast next obj is missing. Abort."); | ||
452 | + Ofdpa2Pipeline.fail(nextObj, ObjectiveError.BADPARAMS); | ||
453 | + return; | ||
454 | + } | ||
486 | 455 | ||
487 | - VlanId vlanId = readVlanFromMeta(nextObj); | 456 | + List<GroupInfo> groupInfos = prepareL2InterfaceGroup(nextObj, assignedVlan); |
488 | - if (vlanId == null) { | 457 | + |
489 | - log.warn("Required VLAN ID info in nextObj metadata but not found. Aborting"); | 458 | + IpPrefix ipDst = Ofdpa2Pipeline.readIpDstFromSelector(nextObj.meta()); |
459 | + if (ipDst != null) { | ||
460 | + if (ipDst.isMulticast()) { | ||
461 | + createL3MulticastGroup(nextObj, assignedVlan, groupInfos); | ||
462 | + } else { | ||
463 | + log.warn("Broadcast NextObj with non-multicast IP address {}", nextObj); | ||
464 | + Ofdpa2Pipeline.fail(nextObj, ObjectiveError.BADPARAMS); | ||
490 | return; | 465 | return; |
491 | } | 466 | } |
467 | + } else { | ||
468 | + createL2FloodGroup(nextObj, assignedVlan, groupInfos); | ||
469 | + } | ||
470 | + } | ||
471 | + | ||
472 | + private List<GroupInfo> prepareL2InterfaceGroup(NextObjective nextObj, VlanId assignedVlan) { | ||
473 | + ImmutableList.Builder<GroupInfo> groupInfoBuilder = ImmutableList.builder(); | ||
474 | + | ||
475 | + // break up broadcast next objective to multiple groups | ||
476 | + Collection<TrafficTreatment> buckets = nextObj.next(); | ||
492 | 477 | ||
493 | // each treatment is converted to an L2 interface group | 478 | // each treatment is converted to an L2 interface group |
494 | - List<GroupDescription> l2interfaceGroupDescs = new ArrayList<>(); | ||
495 | - List<Deque<GroupKey>> allGroupKeys = new ArrayList<>(); | ||
496 | for (TrafficTreatment treatment : buckets) { | 479 | for (TrafficTreatment treatment : buckets) { |
497 | TrafficTreatment.Builder newTreatment = DefaultTrafficTreatment.builder(); | 480 | TrafficTreatment.Builder newTreatment = DefaultTrafficTreatment.builder(); |
498 | PortNumber portNum = null; | 481 | PortNumber portNum = null; |
482 | + VlanId egressVlan = null; | ||
499 | // ensure that the only allowed treatments are pop-vlan and output | 483 | // ensure that the only allowed treatments are pop-vlan and output |
500 | for (Instruction ins : treatment.allInstructions()) { | 484 | for (Instruction ins : treatment.allInstructions()) { |
501 | if (ins.type() == Instruction.Type.L2MODIFICATION) { | 485 | if (ins.type() == Instruction.Type.L2MODIFICATION) { |
... | @@ -504,6 +488,9 @@ public class Ofdpa2GroupHandler { | ... | @@ -504,6 +488,9 @@ public class Ofdpa2GroupHandler { |
504 | case VLAN_POP: | 488 | case VLAN_POP: |
505 | newTreatment.add(l2ins); | 489 | newTreatment.add(l2ins); |
506 | break; | 490 | break; |
491 | + case VLAN_ID: | ||
492 | + egressVlan = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId(); | ||
493 | + break; | ||
507 | default: | 494 | default: |
508 | log.debug("action {} not permitted for broadcast nextObj", | 495 | log.debug("action {} not permitted for broadcast nextObj", |
509 | l2ins.subtype()); | 496 | l2ins.subtype()); |
... | @@ -519,46 +506,51 @@ public class Ofdpa2GroupHandler { | ... | @@ -519,46 +506,51 @@ public class Ofdpa2GroupHandler { |
519 | } | 506 | } |
520 | 507 | ||
521 | // assemble info for l2 interface group | 508 | // assemble info for l2 interface group |
522 | - int l2gk = l2InterfaceGroupKey(deviceId, vlanId, portNum.toLong()); | 509 | + VlanId l2InterfaceGroupVlan = |
523 | - final GroupKey l2groupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk)); | 510 | + (egressVlan != null && !assignedVlan.equals(egressVlan)) ? |
524 | - int l2groupId = L2_INTERFACE_TYPE | (vlanId.toShort() << 16) | | 511 | + egressVlan : assignedVlan; |
512 | + int l2gk = l2InterfaceGroupKey(deviceId, l2InterfaceGroupVlan, portNum.toLong()); | ||
513 | + final GroupKey l2InterfaceGroupKey = | ||
514 | + new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2gk)); | ||
515 | + int l2InterfaceGroupId = L2_INTERFACE_TYPE | (l2InterfaceGroupVlan.toShort() << 16) | | ||
525 | (int) portNum.toLong(); | 516 | (int) portNum.toLong(); |
526 | - GroupBucket l2interfaceGroupBucket = | 517 | + GroupBucket l2InterfaceGroupBucket = |
527 | DefaultGroupBucket.createIndirectGroupBucket(newTreatment.build()); | 518 | DefaultGroupBucket.createIndirectGroupBucket(newTreatment.build()); |
528 | - GroupDescription l2interfaceGroupDescription = | 519 | + GroupDescription l2InterfaceGroupDescription = |
529 | new DefaultGroupDescription( | 520 | new DefaultGroupDescription( |
530 | deviceId, | 521 | deviceId, |
531 | GroupDescription.Type.INDIRECT, | 522 | GroupDescription.Type.INDIRECT, |
532 | new GroupBuckets(Collections.singletonList( | 523 | new GroupBuckets(Collections.singletonList( |
533 | - l2interfaceGroupBucket)), | 524 | + l2InterfaceGroupBucket)), |
534 | - l2groupkey, | 525 | + l2InterfaceGroupKey, |
535 | - l2groupId, | 526 | + l2InterfaceGroupId, |
536 | nextObj.appId()); | 527 | nextObj.appId()); |
537 | log.debug("Trying L2-Interface: device:{} gid:{} gkey:{} nextid:{}", | 528 | log.debug("Trying L2-Interface: device:{} gid:{} gkey:{} nextid:{}", |
538 | - deviceId, Integer.toHexString(l2groupId), | 529 | + deviceId, Integer.toHexString(l2InterfaceGroupId), |
539 | - l2groupkey, nextObj.id()); | 530 | + l2InterfaceGroupKey, nextObj.id()); |
540 | 531 | ||
541 | - Deque<GroupKey> gkeyChain = new ArrayDeque<>(); | 532 | + groupInfoBuilder.add(new GroupInfo(l2InterfaceGroupDescription, |
542 | - gkeyChain.addFirst(l2groupkey); | 533 | + l2InterfaceGroupDescription)); |
543 | - | 534 | + } |
544 | - // store the info needed to create this group | 535 | + return groupInfoBuilder.build(); |
545 | - l2interfaceGroupDescs.add(l2interfaceGroupDescription); | ||
546 | - allGroupKeys.add(gkeyChain); | ||
547 | } | 536 | } |
548 | 537 | ||
538 | + private void createL2FloodGroup(NextObjective nextObj, VlanId vlanId, List<GroupInfo> groupInfos) { | ||
549 | // assemble info for l2 flood group | 539 | // assemble info for l2 flood group |
550 | // since there can be only one flood group for a vlan, its index is always the same - 0 | 540 | // since there can be only one flood group for a vlan, its index is always the same - 0 |
551 | Integer l2floodgroupId = L2_FLOOD_TYPE | (vlanId.toShort() << 16); | 541 | Integer l2floodgroupId = L2_FLOOD_TYPE | (vlanId.toShort() << 16); |
552 | int l2floodgk = getNextAvailableIndex(); | 542 | int l2floodgk = getNextAvailableIndex(); |
553 | final GroupKey l2floodgroupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2floodgk)); | 543 | final GroupKey l2floodgroupkey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l2floodgk)); |
544 | + | ||
554 | // collection of group buckets pointing to all the l2 interface groups | 545 | // collection of group buckets pointing to all the l2 interface groups |
555 | - List<GroupBucket> l2floodBuckets = new ArrayList<>(); | 546 | + List<GroupBucket> l2floodBuckets = Lists.newArrayList(); |
556 | - for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) { | 547 | + groupInfos.forEach(groupInfo -> { |
548 | + GroupDescription l2intGrpDesc = groupInfo.nextGroupDesc; | ||
557 | TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); | 549 | TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); |
558 | ttb.group(new DefaultGroupId(l2intGrpDesc.givenGroupId())); | 550 | ttb.group(new DefaultGroupId(l2intGrpDesc.givenGroupId())); |
559 | GroupBucket abucket = DefaultGroupBucket.createAllGroupBucket(ttb.build()); | 551 | GroupBucket abucket = DefaultGroupBucket.createAllGroupBucket(ttb.build()); |
560 | l2floodBuckets.add(abucket); | 552 | l2floodBuckets.add(abucket); |
561 | - } | 553 | + }); |
562 | // create the l2flood group-description to wait for all the | 554 | // create the l2flood group-description to wait for all the |
563 | // l2interface groups to be processed | 555 | // l2interface groups to be processed |
564 | GroupDescription l2floodGroupDescription = | 556 | GroupDescription l2floodGroupDescription = |
... | @@ -569,28 +561,91 @@ public class Ofdpa2GroupHandler { | ... | @@ -569,28 +561,91 @@ public class Ofdpa2GroupHandler { |
569 | l2floodgroupkey, | 561 | l2floodgroupkey, |
570 | l2floodgroupId, | 562 | l2floodgroupId, |
571 | nextObj.appId()); | 563 | nextObj.appId()); |
572 | - GroupChainElem gce = new GroupChainElem(l2floodGroupDescription, | ||
573 | - l2interfaceGroupDescs.size(), | ||
574 | - false); | ||
575 | log.debug("Trying L2-Flood: device:{} gid:{} gkey:{} nextid:{}", | 564 | log.debug("Trying L2-Flood: device:{} gid:{} gkey:{} nextid:{}", |
576 | deviceId, Integer.toHexString(l2floodgroupId), | 565 | deviceId, Integer.toHexString(l2floodgroupId), |
577 | l2floodgroupkey, nextObj.id()); | 566 | l2floodgroupkey, nextObj.id()); |
578 | 567 | ||
579 | - // create objects for local and distributed storage | 568 | + // Put all dependency information into allGroupKeys |
580 | - allGroupKeys.forEach(gkeyChain -> gkeyChain.addFirst(l2floodgroupkey)); | 569 | + List<Deque<GroupKey>> allGroupKeys = Lists.newArrayList(); |
581 | - OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj); | 570 | + groupInfos.forEach(groupInfo -> { |
571 | + Deque<GroupKey> gkeyChain = new ArrayDeque<>(); | ||
572 | + // In this case we should have L2 interface group only | ||
573 | + gkeyChain.addFirst(groupInfo.nextGroupDesc.appCookie()); | ||
574 | + gkeyChain.addFirst(l2floodgroupkey); | ||
575 | + allGroupKeys.add(gkeyChain); | ||
576 | + }); | ||
582 | 577 | ||
583 | - // store l2floodgroupkey with the ofdpaGroupChain for the nextObjective | 578 | + // Point the next objective to this group |
584 | - // that depends on it | 579 | + OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj); |
585 | updatePendingNextObjective(l2floodgroupkey, ofdpaGrp); | 580 | updatePendingNextObjective(l2floodgroupkey, ofdpaGrp); |
586 | 581 | ||
587 | - for (GroupDescription l2intGrpDesc : l2interfaceGroupDescs) { | 582 | + GroupChainElem gce = new GroupChainElem(l2floodGroupDescription, |
588 | - // store all l2groupkeys with the groupChainElem for the l2floodgroup | 583 | + groupInfos.size(), false); |
589 | - // that depends on it | 584 | + groupInfos.forEach(groupInfo -> { |
590 | - updatePendingGroups(l2intGrpDesc.appCookie(), gce); | 585 | + // Point this group to the next group |
591 | - // send groups for all l2 interface groups | 586 | + updatePendingGroups(groupInfo.nextGroupDesc.appCookie(), gce); |
592 | - groupService.addGroup(l2intGrpDesc); | 587 | + // Start installing the inner-most group |
588 | + groupService.addGroup(groupInfo.innerMostGroupDesc); | ||
589 | + }); | ||
593 | } | 590 | } |
591 | + | ||
592 | + private void createL3MulticastGroup(NextObjective nextObj, VlanId vlanId, List<GroupInfo> groupInfos) { | ||
593 | + List<GroupBucket> l3McastBuckets = new ArrayList<>(); | ||
594 | + groupInfos.forEach(groupInfo -> { | ||
595 | + // Points to L3 interface group if there is one. | ||
596 | + // Otherwise points to L2 interface group directly. | ||
597 | + GroupDescription nextGroupDesc = (groupInfo.nextGroupDesc != null) ? | ||
598 | + groupInfo.nextGroupDesc : groupInfo.innerMostGroupDesc; | ||
599 | + TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); | ||
600 | + ttb.group(new DefaultGroupId(nextGroupDesc.givenGroupId())); | ||
601 | + GroupBucket abucket = DefaultGroupBucket.createAllGroupBucket(ttb.build()); | ||
602 | + l3McastBuckets.add(abucket); | ||
603 | + }); | ||
604 | + | ||
605 | + int l3MulticastIndex = getNextAvailableIndex(); | ||
606 | + int l3MulticastGroupId = L3_MULTICAST_TYPE | vlanId.toShort() << 16 | (TYPE_VLAN_MASK & l3MulticastIndex); | ||
607 | + final GroupKey l3MulticastGroupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(l3MulticastIndex)); | ||
608 | + | ||
609 | + GroupDescription l3MulticastGroupDesc = new DefaultGroupDescription(deviceId, | ||
610 | + GroupDescription.Type.ALL, | ||
611 | + new GroupBuckets(l3McastBuckets), | ||
612 | + l3MulticastGroupKey, | ||
613 | + l3MulticastGroupId, | ||
614 | + nextObj.appId()); | ||
615 | + | ||
616 | + // Put all dependency information into allGroupKeys | ||
617 | + List<Deque<GroupKey>> allGroupKeys = Lists.newArrayList(); | ||
618 | + groupInfos.forEach(groupInfo -> { | ||
619 | + Deque<GroupKey> gkeyChain = new ArrayDeque<>(); | ||
620 | + gkeyChain.addFirst(groupInfo.innerMostGroupDesc.appCookie()); | ||
621 | + // Add L3 interface group to the chain if there is one. | ||
622 | + if (!groupInfo.nextGroupDesc.equals(groupInfo.innerMostGroupDesc)) { | ||
623 | + gkeyChain.addFirst(groupInfo.nextGroupDesc.appCookie()); | ||
624 | + } | ||
625 | + gkeyChain.addFirst(l3MulticastGroupKey); | ||
626 | + allGroupKeys.add(gkeyChain); | ||
627 | + }); | ||
628 | + | ||
629 | + // Point the next objective to this group | ||
630 | + OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj); | ||
631 | + updatePendingNextObjective(l3MulticastGroupKey, ofdpaGrp); | ||
632 | + | ||
633 | + GroupChainElem outerGce = new GroupChainElem(l3MulticastGroupDesc, | ||
634 | + groupInfos.size(), false); | ||
635 | + groupInfos.forEach(groupInfo -> { | ||
636 | + // Point this group (L3 multicast) to the next group | ||
637 | + updatePendingGroups(groupInfo.nextGroupDesc.appCookie(), outerGce); | ||
638 | + | ||
639 | + // Point next group to inner-most group, if any | ||
640 | + if (!groupInfo.nextGroupDesc.equals(groupInfo.innerMostGroupDesc)) { | ||
641 | + GroupChainElem innerGce = new GroupChainElem(groupInfo.nextGroupDesc, | ||
642 | + 1, false); | ||
643 | + updatePendingGroups(groupInfo.innerMostGroupDesc.appCookie(), innerGce); | ||
644 | + } | ||
645 | + | ||
646 | + // Start installing the inner-most group | ||
647 | + groupService.addGroup(groupInfo.innerMostGroupDesc); | ||
648 | + }); | ||
594 | } | 649 | } |
595 | 650 | ||
596 | /** | 651 | /** |
... | @@ -619,7 +674,7 @@ public class Ofdpa2GroupHandler { | ... | @@ -619,7 +674,7 @@ public class Ofdpa2GroupHandler { |
619 | for (GroupInfo gi : unsentGroups) { | 674 | for (GroupInfo gi : unsentGroups) { |
620 | // create ECMP bucket to point to the outer group | 675 | // create ECMP bucket to point to the outer group |
621 | TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); | 676 | TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); |
622 | - ttb.group(new DefaultGroupId(gi.outerGrpDesc.givenGroupId())); | 677 | + ttb.group(new DefaultGroupId(gi.nextGroupDesc.givenGroupId())); |
623 | GroupBucket sbucket = DefaultGroupBucket | 678 | GroupBucket sbucket = DefaultGroupBucket |
624 | .createSelectGroupBucket(ttb.build()); | 679 | .createSelectGroupBucket(ttb.build()); |
625 | l3ecmpGroupBuckets.add(sbucket); | 680 | l3ecmpGroupBuckets.add(sbucket); |
... | @@ -654,9 +709,9 @@ public class Ofdpa2GroupHandler { | ... | @@ -654,9 +709,9 @@ public class Ofdpa2GroupHandler { |
654 | // finally we are ready to send the innermost groups | 709 | // finally we are ready to send the innermost groups |
655 | for (GroupInfo gi : unsentGroups) { | 710 | for (GroupInfo gi : unsentGroups) { |
656 | log.debug("Sending innermost group {} in group chain on device {} ", | 711 | log.debug("Sending innermost group {} in group chain on device {} ", |
657 | - Integer.toHexString(gi.innerGrpDesc.givenGroupId()), deviceId); | 712 | + Integer.toHexString(gi.innerMostGroupDesc.givenGroupId()), deviceId); |
658 | - updatePendingGroups(gi.outerGrpDesc.appCookie(), l3ecmpGce); | 713 | + updatePendingGroups(gi.nextGroupDesc.appCookie(), l3ecmpGce); |
659 | - groupService.addGroup(gi.innerGrpDesc); | 714 | + groupService.addGroup(gi.innerMostGroupDesc); |
660 | } | 715 | } |
661 | 716 | ||
662 | } | 717 | } |
... | @@ -709,8 +764,8 @@ public class Ofdpa2GroupHandler { | ... | @@ -709,8 +764,8 @@ public class Ofdpa2GroupHandler { |
709 | nextObj.id(), deviceId); | 764 | nextObj.id(), deviceId); |
710 | return; | 765 | return; |
711 | } | 766 | } |
712 | - gkeyChain.addFirst(nolabelGroupInfo.innerGrpDesc.appCookie()); | 767 | + gkeyChain.addFirst(nolabelGroupInfo.innerMostGroupDesc.appCookie()); |
713 | - gkeyChain.addFirst(nolabelGroupInfo.outerGrpDesc.appCookie()); | 768 | + gkeyChain.addFirst(nolabelGroupInfo.nextGroupDesc.appCookie()); |
714 | 769 | ||
715 | // we can't send the inner group description yet, as we have to | 770 | // we can't send the inner group description yet, as we have to |
716 | // create the dependent ECMP group first. So we store.. | 771 | // create the dependent ECMP group first. So we store.. |
... | @@ -732,7 +787,7 @@ public class Ofdpa2GroupHandler { | ... | @@ -732,7 +787,7 @@ public class Ofdpa2GroupHandler { |
732 | .setMplsBos(true) | 787 | .setMplsBos(true) |
733 | .copyTtlOut() | 788 | .copyTtlOut() |
734 | .group(new DefaultGroupId( | 789 | .group(new DefaultGroupId( |
735 | - onelabelGroupInfo.outerGrpDesc.givenGroupId())); | 790 | + onelabelGroupInfo.nextGroupDesc.givenGroupId())); |
736 | GroupBucket l3vpnGrpBkt = | 791 | GroupBucket l3vpnGrpBkt = |
737 | DefaultGroupBucket.createIndirectGroupBucket(l3vpnTtb.build()); | 792 | DefaultGroupBucket.createIndirectGroupBucket(l3vpnTtb.build()); |
738 | int l3vpnIndex = getNextAvailableIndex(); | 793 | int l3vpnIndex = getNextAvailableIndex(); |
... | @@ -749,14 +804,14 @@ public class Ofdpa2GroupHandler { | ... | @@ -749,14 +804,14 @@ public class Ofdpa2GroupHandler { |
749 | l3vpngroupId, | 804 | l3vpngroupId, |
750 | nextObj.appId()); | 805 | nextObj.appId()); |
751 | GroupChainElem l3vpnGce = new GroupChainElem(l3vpnGroupDesc, 1, false); | 806 | GroupChainElem l3vpnGce = new GroupChainElem(l3vpnGroupDesc, 1, false); |
752 | - updatePendingGroups(onelabelGroupInfo.outerGrpDesc.appCookie(), l3vpnGce); | 807 | + updatePendingGroups(onelabelGroupInfo.nextGroupDesc.appCookie(), l3vpnGce); |
753 | 808 | ||
754 | - gkeyChain.addFirst(onelabelGroupInfo.innerGrpDesc.appCookie()); | 809 | + gkeyChain.addFirst(onelabelGroupInfo.innerMostGroupDesc.appCookie()); |
755 | - gkeyChain.addFirst(onelabelGroupInfo.outerGrpDesc.appCookie()); | 810 | + gkeyChain.addFirst(onelabelGroupInfo.nextGroupDesc.appCookie()); |
756 | gkeyChain.addFirst(l3vpngroupkey); | 811 | gkeyChain.addFirst(l3vpngroupkey); |
757 | 812 | ||
758 | //now we can replace the outerGrpDesc with the one we just created | 813 | //now we can replace the outerGrpDesc with the one we just created |
759 | - onelabelGroupInfo.outerGrpDesc = l3vpnGroupDesc; | 814 | + onelabelGroupInfo.nextGroupDesc = l3vpnGroupDesc; |
760 | 815 | ||
761 | // we can't send the innermost group yet, as we have to create | 816 | // we can't send the innermost group yet, as we have to create |
762 | // the dependent ECMP group first. So we store ... | 817 | // the dependent ECMP group first. So we store ... |
... | @@ -805,7 +860,7 @@ public class Ofdpa2GroupHandler { | ... | @@ -805,7 +860,7 @@ public class Ofdpa2GroupHandler { |
805 | // now we can create the outermost L3 ECMP group bucket to add | 860 | // now we can create the outermost L3 ECMP group bucket to add |
806 | GroupInfo gi = unsentGroups.get(0); // only one bucket, so only one group-chain | 861 | GroupInfo gi = unsentGroups.get(0); // only one bucket, so only one group-chain |
807 | TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); | 862 | TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder(); |
808 | - ttb.group(new DefaultGroupId(gi.outerGrpDesc.givenGroupId())); | 863 | + ttb.group(new DefaultGroupId(gi.nextGroupDesc.givenGroupId())); |
809 | GroupBucket sbucket = DefaultGroupBucket.createSelectGroupBucket(ttb.build()); | 864 | GroupBucket sbucket = DefaultGroupBucket.createSelectGroupBucket(ttb.build()); |
810 | 865 | ||
811 | // recreate the original L3 ECMP group id and description | 866 | // recreate the original L3 ECMP group id and description |
... | @@ -839,9 +894,9 @@ public class Ofdpa2GroupHandler { | ... | @@ -839,9 +894,9 @@ public class Ofdpa2GroupHandler { |
839 | l3ecmpGroupKey, nextObjective.id()); | 894 | l3ecmpGroupKey, nextObjective.id()); |
840 | // send the innermost group | 895 | // send the innermost group |
841 | log.debug("Sending innermost group {} in group chain on device {} ", | 896 | log.debug("Sending innermost group {} in group chain on device {} ", |
842 | - Integer.toHexString(gi.innerGrpDesc.givenGroupId()), deviceId); | 897 | + Integer.toHexString(gi.innerMostGroupDesc.givenGroupId()), deviceId); |
843 | - updatePendingGroups(gi.outerGrpDesc.appCookie(), l3ecmpGce); | 898 | + updatePendingGroups(gi.nextGroupDesc.appCookie(), l3ecmpGce); |
844 | - groupService.addGroup(gi.innerGrpDesc); | 899 | + groupService.addGroup(gi.innerMostGroupDesc); |
845 | 900 | ||
846 | } | 901 | } |
847 | 902 | ||
... | @@ -1072,13 +1127,6 @@ public class Ofdpa2GroupHandler { | ... | @@ -1072,13 +1127,6 @@ public class Ofdpa2GroupHandler { |
1072 | } | 1127 | } |
1073 | } | 1128 | } |
1074 | 1129 | ||
1075 | - private VlanId readVlanFromMeta(NextObjective nextObj) { | ||
1076 | - TrafficSelector metadata = nextObj.meta(); | ||
1077 | - Criterion criterion = metadata.getCriterion(Criterion.Type.VLAN_VID); | ||
1078 | - return (criterion == null) | ||
1079 | - ? null : ((VlanIdCriterion) criterion).vlanId(); | ||
1080 | - } | ||
1081 | - | ||
1082 | private int getNextAvailableIndex() { | 1130 | private int getNextAvailableIndex() { |
1083 | return (int) nextIndex.incrementAndGet(); | 1131 | return (int) nextIndex.incrementAndGet(); |
1084 | } | 1132 | } |
... | @@ -1106,12 +1154,22 @@ public class Ofdpa2GroupHandler { | ... | @@ -1106,12 +1154,22 @@ public class Ofdpa2GroupHandler { |
1106 | * Utility class for moving group information around. | 1154 | * Utility class for moving group information around. |
1107 | */ | 1155 | */ |
1108 | private class GroupInfo { | 1156 | private class GroupInfo { |
1109 | - private GroupDescription innerGrpDesc; | 1157 | + /** |
1110 | - private GroupDescription outerGrpDesc; | 1158 | + * Description of the inner-most group of the group chain. |
1159 | + * It is always an L2 interface group. | ||
1160 | + */ | ||
1161 | + private GroupDescription innerMostGroupDesc; | ||
1162 | + | ||
1163 | + /** | ||
1164 | + * Description of the next group in the group chain. | ||
1165 | + * It can be L2 interface, L3 interface, L3 unicast, L3 VPN group. | ||
1166 | + * It is possible that nextGroup is the same as the innerMostGroup. | ||
1167 | + */ | ||
1168 | + private GroupDescription nextGroupDesc; | ||
1111 | 1169 | ||
1112 | - GroupInfo(GroupDescription innerGrpDesc, GroupDescription outerGrpDesc) { | 1170 | + GroupInfo(GroupDescription innerMostGroupDesc, GroupDescription nextGroupDesc) { |
1113 | - this.innerGrpDesc = innerGrpDesc; | 1171 | + this.innerMostGroupDesc = innerMostGroupDesc; |
1114 | - this.outerGrpDesc = outerGrpDesc; | 1172 | + this.nextGroupDesc = nextGroupDesc; |
1115 | } | 1173 | } |
1116 | } | 1174 | } |
1117 | 1175 | ... | ... |
... | @@ -28,6 +28,7 @@ import java.util.Set; | ... | @@ -28,6 +28,7 @@ import java.util.Set; |
28 | import java.util.concurrent.ConcurrentHashMap; | 28 | import java.util.concurrent.ConcurrentHashMap; |
29 | 29 | ||
30 | import com.google.common.collect.ImmutableList; | 30 | import com.google.common.collect.ImmutableList; |
31 | +import com.google.common.collect.ImmutableSet; | ||
31 | import org.onlab.osgi.ServiceDirectory; | 32 | import org.onlab.osgi.ServiceDirectory; |
32 | import org.onlab.packet.Ethernet; | 33 | import org.onlab.packet.Ethernet; |
33 | import org.onlab.packet.IpPrefix; | 34 | import org.onlab.packet.IpPrefix; |
... | @@ -297,7 +298,8 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -297,7 +298,8 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
297 | // convert filtering conditions for switch-intfs into flowrules | 298 | // convert filtering conditions for switch-intfs into flowrules |
298 | FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); | 299 | FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); |
299 | for (Criterion criterion : filt.conditions()) { | 300 | for (Criterion criterion : filt.conditions()) { |
300 | - if (criterion.type() == Criterion.Type.ETH_DST) { | 301 | + if (criterion.type() == Criterion.Type.ETH_DST || |
302 | + criterion.type() == Criterion.Type.ETH_DST_MASKED) { | ||
301 | ethCriterion = (EthCriterion) criterion; | 303 | ethCriterion = (EthCriterion) criterion; |
302 | } else if (criterion.type() == Criterion.Type.VLAN_VID) { | 304 | } else if (criterion.type() == Criterion.Type.VLAN_VID) { |
303 | vidCriterion = (VlanIdCriterion) criterion; | 305 | vidCriterion = (VlanIdCriterion) criterion; |
... | @@ -559,6 +561,11 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -559,6 +561,11 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
559 | return processEthDstOnlyFilter(ethCriterion, applicationId); | 561 | return processEthDstOnlyFilter(ethCriterion, applicationId); |
560 | } | 562 | } |
561 | 563 | ||
564 | + // Multicast MAC | ||
565 | + if (ethCriterion.mask() != null) { | ||
566 | + return processMcastEthDstFilter(ethCriterion, applicationId); | ||
567 | + } | ||
568 | + | ||
562 | //handling untagged packets via assigned VLAN | 569 | //handling untagged packets via assigned VLAN |
563 | if (vidCriterion.vlanId() == VlanId.NONE) { | 570 | if (vidCriterion.vlanId() == VlanId.NONE) { |
564 | vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); | 571 | vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); |
... | @@ -635,6 +642,24 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -635,6 +642,24 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
635 | return ImmutableList.<FlowRule>builder().add(rule).build(); | 642 | return ImmutableList.<FlowRule>builder().add(rule).build(); |
636 | } | 643 | } |
637 | 644 | ||
645 | + protected List<FlowRule> processMcastEthDstFilter(EthCriterion ethCriterion, | ||
646 | + ApplicationId applicationId) { | ||
647 | + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | ||
648 | + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); | ||
649 | + selector.matchEthType(Ethernet.TYPE_IPV4); | ||
650 | + selector.matchEthDstMasked(ethCriterion.mac(), ethCriterion.mask()); | ||
651 | + treatment.transition(MULTICAST_ROUTING_TABLE); | ||
652 | + FlowRule rule = DefaultFlowRule.builder() | ||
653 | + .forDevice(deviceId) | ||
654 | + .withSelector(selector.build()) | ||
655 | + .withTreatment(treatment.build()) | ||
656 | + .withPriority(DEFAULT_PRIORITY) | ||
657 | + .fromApp(applicationId) | ||
658 | + .makePermanent() | ||
659 | + .forTable(TMAC_TABLE).build(); | ||
660 | + return ImmutableList.<FlowRule>builder().add(rule).build(); | ||
661 | + } | ||
662 | + | ||
638 | private Collection<FlowRule> processForward(ForwardingObjective fwd) { | 663 | private Collection<FlowRule> processForward(ForwardingObjective fwd) { |
639 | switch (fwd.flag()) { | 664 | switch (fwd.flag()) { |
640 | case SPECIFIC: | 665 | case SPECIFIC: |
... | @@ -802,9 +827,27 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -802,9 +827,27 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
802 | */ | 827 | */ |
803 | if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) { | 828 | if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) { |
804 | IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip(); | 829 | IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip(); |
830 | + if (ipv4Dst.isMulticast()) { | ||
831 | + if (ipv4Dst.prefixLength() != 32) { | ||
832 | + log.warn("Multicast specific forwarding objective can only be /32"); | ||
833 | + fail(fwd, ObjectiveError.BADPARAMS); | ||
834 | + return ImmutableSet.of(); | ||
835 | + } | ||
836 | + VlanId assignedVlan = readVlanFromSelector(fwd.meta()); | ||
837 | + if (assignedVlan == null) { | ||
838 | + log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort."); | ||
839 | + fail(fwd, ObjectiveError.BADPARAMS); | ||
840 | + return ImmutableSet.of(); | ||
841 | + } | ||
842 | + OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(assignedVlan); | ||
843 | + filteredSelector.extension(ofdpaMatchVlanVid, deviceId); | ||
844 | + filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst); | ||
845 | + forTableId = MULTICAST_ROUTING_TABLE; | ||
846 | + log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}" | ||
847 | + + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); | ||
848 | + } else { | ||
805 | if (ipv4Dst.prefixLength() > 0) { | 849 | if (ipv4Dst.prefixLength() > 0) { |
806 | - filteredSelector.matchEthType(Ethernet.TYPE_IPV4) | 850 | + filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst); |
807 | - .matchIPDst(ipv4Dst); | ||
808 | } else { | 851 | } else { |
809 | filteredSelector.matchEthType(Ethernet.TYPE_IPV4) | 852 | filteredSelector.matchEthType(Ethernet.TYPE_IPV4) |
810 | .matchIPDst(IpPrefix.valueOf("0.0.0.0/1")); | 853 | .matchIPDst(IpPrefix.valueOf("0.0.0.0/1")); |
... | @@ -813,8 +856,9 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -813,8 +856,9 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
813 | defaultRule = true; | 856 | defaultRule = true; |
814 | } | 857 | } |
815 | forTableId = UNICAST_ROUTING_TABLE; | 858 | forTableId = UNICAST_ROUTING_TABLE; |
816 | - log.debug("processing IPv4 specific forwarding objective {} -> next:{}" | 859 | + log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}" |
817 | + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); | 860 | + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); |
861 | + } | ||
818 | 862 | ||
819 | if (fwd.treatment() != null) { | 863 | if (fwd.treatment() != null) { |
820 | for (Instruction instr : fwd.treatment().allInstructions()) { | 864 | for (Instruction instr : fwd.treatment().allInstructions()) { |
... | @@ -1057,4 +1101,15 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1057,4 +1101,15 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
1057 | } | 1101 | } |
1058 | return mappings; | 1102 | return mappings; |
1059 | } | 1103 | } |
1104 | + | ||
1105 | + protected static VlanId readVlanFromSelector(TrafficSelector selector) { | ||
1106 | + Criterion criterion = selector.getCriterion(Criterion.Type.VLAN_VID); | ||
1107 | + return (criterion == null) | ||
1108 | + ? null : ((VlanIdCriterion) criterion).vlanId(); | ||
1109 | + } | ||
1110 | + | ||
1111 | + protected static IpPrefix readIpDstFromSelector(TrafficSelector selector) { | ||
1112 | + Criterion criterion = selector.getCriterion(Criterion.Type.IPV4_DST); | ||
1113 | + return (criterion == null) ? null : ((IPCriterion) criterion).ip(); | ||
1114 | + } | ||
1060 | } | 1115 | } | ... | ... |
-
Please register or login to post a comment