Committed by
Gerrit Code Review
CORD-455 Implement multicast support in OFDPA driver
Also refactor Ofdpa2GroupHandler Change-Id: Id6a9224cab663f57edb8e85a0e7d81e7da3df132
Showing
4 changed files
with
301 additions
and
158 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,19 +423,37 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { | ... | @@ -416,19 +423,37 @@ 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(); |
| 419 | - if (ipv4Dst.prefixLength() > 0) { | 426 | + if (ipv4Dst.isMulticast()) { |
| 420 | - filteredSelector.matchEthType(Ethernet.TYPE_IPV4) | 427 | + if (ipv4Dst.prefixLength() != 32) { |
| 421 | - .matchIPDst(ipv4Dst); | 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); | ||
| 422 | } else { | 443 | } else { |
| 423 | - filteredSelector.matchEthType(Ethernet.TYPE_IPV4) | 444 | + if (ipv4Dst.prefixLength() > 0) { |
| 424 | - .matchIPDst(IpPrefix.valueOf("0.0.0.0/1")); | 445 | + filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst); |
| 425 | - complementarySelector.matchEthType(Ethernet.TYPE_IPV4) | 446 | + } else { |
| 426 | - .matchIPDst(IpPrefix.valueOf("128.0.0.0/1")); | 447 | + filteredSelector.matchEthType(Ethernet.TYPE_IPV4) |
| 427 | - defaultRule = true; | 448 | + .matchIPDst(IpPrefix.valueOf("0.0.0.0/1")); |
| 449 | + complementarySelector.matchEthType(Ethernet.TYPE_IPV4) | ||
| 450 | + .matchIPDst(IpPrefix.valueOf("128.0.0.0/1")); | ||
| 451 | + defaultRule = true; | ||
| 452 | + } | ||
| 453 | + forTableId = UNICAST_ROUTING_TABLE; | ||
| 454 | + log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}" | ||
| 455 | + + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); | ||
| 428 | } | 456 | } |
| 429 | - forTableId = UNICAST_ROUTING_TABLE; | ||
| 430 | - log.debug("processing IPv4 specific forwarding objective {} -> next:{}" | ||
| 431 | - + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); | ||
| 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) { |
| 486 | - | 451 | + log.warn("VLAN ID required by broadcast next obj is missing. Abort."); |
| 487 | - VlanId vlanId = readVlanFromMeta(nextObj); | 452 | + Ofdpa2Pipeline.fail(nextObj, ObjectiveError.BADPARAMS); |
| 488 | - if (vlanId == null) { | ||
| 489 | - log.warn("Required VLAN ID info in nextObj metadata but not found. Aborting"); | ||
| 490 | return; | 453 | return; |
| 491 | } | 454 | } |
| 492 | 455 | ||
| 456 | + List<GroupInfo> groupInfos = prepareL2InterfaceGroup(nextObj, assignedVlan); | ||
| 457 | + | ||
| 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); | ||
| 465 | + return; | ||
| 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(); | ||
| 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 | - | ||
| 541 | - Deque<GroupKey> gkeyChain = new ArrayDeque<>(); | ||
| 542 | - gkeyChain.addFirst(l2groupkey); | ||
| 543 | 531 | ||
| 544 | - // store the info needed to create this group | 532 | + groupInfoBuilder.add(new GroupInfo(l2InterfaceGroupDescription, |
| 545 | - l2interfaceGroupDescs.add(l2interfaceGroupDescription); | 533 | + l2InterfaceGroupDescription)); |
| 546 | - allGroupKeys.add(gkeyChain); | ||
| 547 | } | 534 | } |
| 535 | + return groupInfoBuilder.build(); | ||
| 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 |
| 593 | - } | 588 | + groupService.addGroup(groupInfo.innerMostGroupDesc); |
| 589 | + }); | ||
| 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,19 +827,38 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -802,19 +827,38 @@ 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(); |
| 805 | - if (ipv4Dst.prefixLength() > 0) { | 830 | + if (ipv4Dst.isMulticast()) { |
| 806 | - filteredSelector.matchEthType(Ethernet.TYPE_IPV4) | 831 | + if (ipv4Dst.prefixLength() != 32) { |
| 807 | - .matchIPDst(ipv4Dst); | 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); | ||
| 808 | } else { | 848 | } else { |
| 809 | - filteredSelector.matchEthType(Ethernet.TYPE_IPV4) | 849 | + if (ipv4Dst.prefixLength() > 0) { |
| 810 | - .matchIPDst(IpPrefix.valueOf("0.0.0.0/1")); | 850 | + filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst); |
| 811 | - complementarySelector.matchEthType(Ethernet.TYPE_IPV4) | 851 | + } else { |
| 812 | - .matchIPDst(IpPrefix.valueOf("128.0.0.0/1")); | 852 | + filteredSelector.matchEthType(Ethernet.TYPE_IPV4) |
| 813 | - defaultRule = true; | 853 | + .matchIPDst(IpPrefix.valueOf("0.0.0.0/1")); |
| 854 | + complementarySelector.matchEthType(Ethernet.TYPE_IPV4) | ||
| 855 | + .matchIPDst(IpPrefix.valueOf("128.0.0.0/1")); | ||
| 856 | + defaultRule = true; | ||
| 857 | + } | ||
| 858 | + forTableId = UNICAST_ROUTING_TABLE; | ||
| 859 | + log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}" | ||
| 860 | + + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); | ||
| 814 | } | 861 | } |
| 815 | - forTableId = UNICAST_ROUTING_TABLE; | ||
| 816 | - log.debug("processing IPv4 specific forwarding objective {} -> next:{}" | ||
| 817 | - + " in dev:{}", fwd.id(), fwd.nextId(), deviceId); | ||
| 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