Charles Chan
Committed by Gerrit Code Review

CORD-455 Implement multicast support in OFDPA driver

Also refactor Ofdpa2GroupHandler

Change-Id: Id6a9224cab663f57edb8e85a0e7d81e7da3df132
...@@ -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 }
......