Saurav Das
Committed by Ray Milkey

CORD-48 Added support for broadcast next objective in OFDPA driver.

Changed groupid to show in hex for cli command 'groups'

Change-Id: I86474912a9fd775c36d5bc49545eaa58ecc46b47
...@@ -577,6 +577,7 @@ public class DefaultGroupHandler { ...@@ -577,6 +577,7 @@ public class DefaultGroupHandler {
577 577
578 ports.forEach(port -> { 578 ports.forEach(port -> {
579 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); 579 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
580 + tBuilder.popVlan();
580 tBuilder.setOutput(port); 581 tBuilder.setOutput(port);
581 nextObjBuilder.addTreatment(tBuilder.build()); 582 nextObjBuilder.addTreatment(tBuilder.build());
582 }); 583 });
......
...@@ -121,11 +121,11 @@ public class GroupsListCommand extends AbstractShellCommand { ...@@ -121,11 +121,11 @@ public class GroupsListCommand extends AbstractShellCommand {
121 private void printGroups(DeviceId deviceId, List<Group> groups) { 121 private void printGroups(DeviceId deviceId, List<Group> groups) {
122 print("deviceId=%s", deviceId); 122 print("deviceId=%s", deviceId);
123 for (Group group : groups) { 123 for (Group group : groups) {
124 - print(FORMAT, group.id().id(), group.state(), group.type(), 124 + print(FORMAT, Integer.toHexString(group.id().id()), group.state(), group.type(),
125 group.bytes(), group.packets(), group.appId().name()); 125 group.bytes(), group.packets(), group.appId().name());
126 int i = 0; 126 int i = 0;
127 for (GroupBucket bucket:group.buckets().buckets()) { 127 for (GroupBucket bucket:group.buckets().buckets()) {
128 - print(BUCKET_FORMAT, group.id().id(), ++i, 128 + print(BUCKET_FORMAT, Integer.toHexString(group.id().id()), ++i,
129 bucket.bytes(), bucket.packets(), 129 bucket.bytes(), bucket.packets(),
130 bucket.treatment().allInstructions()); 130 bucket.treatment().allInstructions());
131 } 131 }
......
...@@ -630,7 +630,8 @@ public final class Instructions { ...@@ -630,7 +630,8 @@ public final class Instructions {
630 @Override 630 @Override
631 public String toString() { 631 public String toString() {
632 return toStringHelper(type().toString()) 632 return toStringHelper(type().toString())
633 - .add("group ID", groupId.id()).toString(); 633 + .addValue("group ID=0x" + Integer.toHexString(groupId.id()))
634 + .toString();
634 } 635 }
635 636
636 @Override 637 @Override
......
...@@ -18,7 +18,10 @@ package org.onosproject.driver.pipeline; ...@@ -18,7 +18,10 @@ package org.onosproject.driver.pipeline;
18 import static org.slf4j.LoggerFactory.getLogger; 18 import static org.slf4j.LoggerFactory.getLogger;
19 19
20 import java.util.ArrayList; 20 import java.util.ArrayList;
21 +import java.util.Collections;
21 import java.util.List; 22 import java.util.List;
23 +import java.util.Set;
24 +import java.util.concurrent.ConcurrentHashMap;
22 25
23 import org.onlab.packet.VlanId; 26 import org.onlab.packet.VlanId;
24 import org.onosproject.core.ApplicationId; 27 import org.onosproject.core.ApplicationId;
...@@ -54,11 +57,16 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -54,11 +57,16 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
54 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 57 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
55 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); 58 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
56 selector.matchVlanId(vidCriterion.vlanId()); 59 selector.matchVlanId(vidCriterion.vlanId());
60 + treatment.transition(TMAC_TABLE);
61 +
62 + VlanId storeVlan = null;
57 if (vidCriterion.vlanId() == VlanId.NONE) { 63 if (vidCriterion.vlanId() == VlanId.NONE) {
58 // untagged packets are assigned vlans 64 // untagged packets are assigned vlans
59 treatment.pushVlan().setVlanId(assignedVlan); 65 treatment.pushVlan().setVlanId(assignedVlan);
66 + storeVlan = assignedVlan;
67 + } else {
68 + storeVlan = vidCriterion.vlanId();
60 } 69 }
61 - treatment.transition(TMAC_TABLE);
62 70
63 // ofdpa cannot match on ALL portnumber, so we need to use separate 71 // ofdpa cannot match on ALL portnumber, so we need to use separate
64 // rules for each port. 72 // rules for each port.
...@@ -72,7 +80,20 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -72,7 +80,20 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
72 } else { 80 } else {
73 portnums.add(portCriterion.port()); 81 portnums.add(portCriterion.port());
74 } 82 }
83 +
75 for (PortNumber pnum : portnums) { 84 for (PortNumber pnum : portnums) {
85 + // update storage
86 + port2Vlan.put(pnum, storeVlan);
87 + Set<PortNumber> vlanPorts = vlan2Port.get(storeVlan);
88 + if (vlanPorts == null) {
89 + vlanPorts = Collections.newSetFromMap(
90 + new ConcurrentHashMap<PortNumber, Boolean>());
91 + vlanPorts.add(pnum);
92 + vlan2Port.put(storeVlan, vlanPorts);
93 + } else {
94 + vlanPorts.add(pnum);
95 + }
96 + // create rest of flowrule
76 selector.matchInPort(pnum); 97 selector.matchInPort(pnum);
77 FlowRule rule = DefaultFlowRule.builder() 98 FlowRule rule = DefaultFlowRule.builder()
78 .forDevice(deviceId) 99 .forDevice(deviceId)
......
...@@ -23,11 +23,13 @@ import java.util.ArrayList; ...@@ -23,11 +23,13 @@ import java.util.ArrayList;
23 import java.util.Collection; 23 import java.util.Collection;
24 import java.util.Collections; 24 import java.util.Collections;
25 import java.util.List; 25 import java.util.List;
26 +import java.util.Map;
26 import java.util.Set; 27 import java.util.Set;
27 import java.util.concurrent.ConcurrentHashMap; 28 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.Executors; 29 import java.util.concurrent.Executors;
29 import java.util.concurrent.ScheduledExecutorService; 30 import java.util.concurrent.ScheduledExecutorService;
30 import java.util.concurrent.TimeUnit; 31 import java.util.concurrent.TimeUnit;
32 +import java.util.concurrent.atomic.AtomicInteger;
31 import java.util.stream.Collectors; 33 import java.util.stream.Collectors;
32 34
33 import org.onlab.osgi.ServiceDirectory; 35 import org.onlab.osgi.ServiceDirectory;
...@@ -147,6 +149,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -147,6 +149,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
147 private static final int L3UNICASTMASK = 0x20000000; 149 private static final int L3UNICASTMASK = 0x20000000;
148 //private static final int MPLSINTERFACEMASK = 0x90000000; 150 //private static final int MPLSINTERFACEMASK = 0x90000000;
149 private static final int L3ECMPMASK = 0x70000000; 151 private static final int L3ECMPMASK = 0x70000000;
152 + private static final int L2FLOODMASK = 0x40000000;
150 153
151 private final Logger log = getLogger(getClass()); 154 private final Logger log = getLogger(getClass());
152 private ServiceDirectory serviceDirectory; 155 private ServiceDirectory serviceDirectory;
...@@ -176,6 +179,13 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -176,6 +179,13 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
176 private Set<IPCriterion> sentIpFilters = Collections.newSetFromMap( 179 private Set<IPCriterion> sentIpFilters = Collections.newSetFromMap(
177 new ConcurrentHashMap<IPCriterion, Boolean>()); 180 new ConcurrentHashMap<IPCriterion, Boolean>());
178 181
182 + // local stores for port-vlan mapping
183 + Map<PortNumber, VlanId> port2Vlan = new ConcurrentHashMap<PortNumber, VlanId>();
184 + Map<VlanId, Set<PortNumber>> vlan2Port = new ConcurrentHashMap<VlanId,
185 + Set<PortNumber>>();
186 +
187 +
188 +
179 @Override 189 @Override
180 public void init(DeviceId deviceId, PipelinerContext context) { 190 public void init(DeviceId deviceId, PipelinerContext context) {
181 this.serviceDirectory = context.directory(); 191 this.serviceDirectory = context.directory();
...@@ -275,26 +285,23 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -275,26 +285,23 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
275 285
276 @Override 286 @Override
277 public void next(NextObjective nextObjective) { 287 public void next(NextObjective nextObjective) {
278 - switch (nextObjective.type()) { 288 + log.debug("Processing NextObjective id{} op{}", nextObjective.id(),
279 - case SIMPLE: 289 + nextObjective.op());
280 - Collection<TrafficTreatment> treatments = nextObjective.next(); 290 + if (nextObjective.op() == Objective.Operation.REMOVE) {
281 - if (treatments.size() != 1) { 291 + if (nextObjective.next().isEmpty()) {
282 - log.error("Next Objectives of type Simple should only have a " 292 + removeGroup(nextObjective);
283 - + "single Traffic Treatment. Next Objective Id:{}", nextObjective.id()); 293 + } else {
284 - fail(nextObjective, ObjectiveError.BADPARAMS); 294 + removeBucketFromGroup(nextObjective);
285 - return;
286 } 295 }
287 - processSimpleNextObjective(nextObjective); 296 + } else if (nextObjective.op() == Objective.Operation.ADD) {
288 - break; 297 + NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
289 - case HASHED: 298 + if (nextGroup != null) {
290 - case BROADCAST: 299 + addBucketToGroup(nextObjective);
291 - case FAILOVER: 300 + } else {
292 - fail(nextObjective, ObjectiveError.UNSUPPORTED); 301 + addGroup(nextObjective);
293 - log.warn("Unsupported next objective type {}", nextObjective.type()); 302 + }
294 - break; 303 + } else {
295 - default: 304 + log.warn("Unsupported operation {}", nextObjective.op());
296 - fail(nextObjective, ObjectiveError.UNKNOWN);
297 - log.warn("Unknown next objective type {}", nextObjective.type());
298 } 305 }
299 } 306 }
300 307
...@@ -302,6 +309,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -302,6 +309,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
302 // Flow handling 309 // Flow handling
303 ////////////////////////////////////// 310 //////////////////////////////////////
304 311
312 +
305 /** 313 /**
306 * As per OFDPA 2.0 TTP, filtering of VLAN ids, MAC addresses (for routing) 314 * As per OFDPA 2.0 TTP, filtering of VLAN ids, MAC addresses (for routing)
307 * and IP addresses configured on switch ports happen in different tables. 315 * and IP addresses configured on switch ports happen in different tables.
...@@ -455,14 +463,19 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -455,14 +463,19 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
455 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 463 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
456 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); 464 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
457 selector.matchVlanId(vidCriterion.vlanId()); 465 selector.matchVlanId(vidCriterion.vlanId());
466 + treatment.transition(TMAC_TABLE);
467 +
468 + VlanId storeVlan = null;
458 if (vidCriterion.vlanId() == VlanId.NONE) { 469 if (vidCriterion.vlanId() == VlanId.NONE) {
459 // untagged packets are assigned vlans 470 // untagged packets are assigned vlans
460 treatment.pushVlan().setVlanId(assignedVlan); 471 treatment.pushVlan().setVlanId(assignedVlan);
461 // XXX ofdpa will require an additional vlan match on the assigned vlan 472 // XXX ofdpa will require an additional vlan match on the assigned vlan
462 // and it may not require the push. This is not in compliance with OF 473 // and it may not require the push. This is not in compliance with OF
463 // standard. Waiting on what the exact flows are going to look like. 474 // standard. Waiting on what the exact flows are going to look like.
475 + storeVlan = assignedVlan;
476 + } else {
477 + storeVlan = vidCriterion.vlanId();
464 } 478 }
465 - treatment.transition(TMAC_TABLE);
466 479
467 // ofdpa cannot match on ALL portnumber, so we need to use separate 480 // ofdpa cannot match on ALL portnumber, so we need to use separate
468 // rules for each port. 481 // rules for each port.
...@@ -476,7 +489,20 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -476,7 +489,20 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
476 } else { 489 } else {
477 portnums.add(portCriterion.port()); 490 portnums.add(portCriterion.port());
478 } 491 }
492 +
479 for (PortNumber pnum : portnums) { 493 for (PortNumber pnum : portnums) {
494 + // update storage
495 + port2Vlan.put(pnum, storeVlan);
496 + Set<PortNumber> vlanPorts = vlan2Port.get(storeVlan);
497 + if (vlanPorts == null) {
498 + vlanPorts = Collections.newSetFromMap(
499 + new ConcurrentHashMap<PortNumber, Boolean>());
500 + vlanPorts.add(pnum);
501 + vlan2Port.put(storeVlan, vlanPorts);
502 + } else {
503 + vlanPorts.add(pnum);
504 + }
505 + // create rest of flowrule
480 selector.matchInPort(pnum); 506 selector.matchInPort(pnum);
481 FlowRule rule = DefaultFlowRule.builder() 507 FlowRule rule = DefaultFlowRule.builder()
482 .forDevice(deviceId) 508 .forDevice(deviceId)
...@@ -708,10 +734,39 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -708,10 +734,39 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
708 // Group handling 734 // Group handling
709 ////////////////////////////////////// 735 //////////////////////////////////////
710 736
737 + private void addGroup(NextObjective nextObjective) {
738 + switch (nextObjective.type()) {
739 + case SIMPLE:
740 + Collection<TrafficTreatment> treatments = nextObjective.next();
741 + if (treatments.size() != 1) {
742 + log.error("Next Objectives of type Simple should only have a "
743 + + "single Traffic Treatment. Next Objective Id:{}",
744 + nextObjective.id());
745 + fail(nextObjective, ObjectiveError.BADPARAMS);
746 + return;
747 + }
748 + processSimpleNextObjective(nextObjective);
749 + break;
750 + case BROADCAST:
751 + processBroadcastNextObjective(nextObjective);
752 + break;
753 + case HASHED:
754 + processHashedNextObjective(nextObjective);
755 + break;
756 + case FAILOVER:
757 + fail(nextObjective, ObjectiveError.UNSUPPORTED);
758 + log.warn("Unsupported next objective type {}", nextObjective.type());
759 + break;
760 + default:
761 + fail(nextObjective, ObjectiveError.UNKNOWN);
762 + log.warn("Unknown next objective type {}", nextObjective.type());
763 + }
764 + }
765 +
711 /** 766 /**
712 * As per the OFDPA 2.0 TTP, packets are sent out of ports by using 767 * As per the OFDPA 2.0 TTP, packets are sent out of ports by using
713 * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface 768 * a chain of groups, namely an L3 Unicast Group that points to an L2 Interface
714 - * Group which in turns points to an output port. The Next Objective passed 769 + * Group which in-turn points to an output port. The Next Objective passed
715 * in by the application has to be broken up into a group chain 770 * in by the application has to be broken up into a group chain
716 * to satisfy this TTP. 771 * to satisfy this TTP.
717 * 772 *
...@@ -770,7 +825,9 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -770,7 +825,9 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
770 Integer l3groupId = L3UNICASTMASK | (int) portNum; 825 Integer l3groupId = L3UNICASTMASK | (int) portNum;
771 l3utt.group(new DefaultGroupId(l2groupId)); 826 l3utt.group(new DefaultGroupId(l2groupId));
772 GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId, 827 GroupChainElem gce = new GroupChainElem(l3groupkey, l3groupId,
773 - l3utt.build(), nextObj.appId()); 828 + GroupDescription.Type.INDIRECT,
829 + Collections.singletonList(l3utt.build()),
830 + nextObj.appId(), 1);
774 831
775 // create object for local and distributed storage 832 // create object for local and distributed storage
776 List<GroupKey> gkeys = new ArrayList<GroupKey>(); 833 List<GroupKey> gkeys = new ArrayList<GroupKey>();
...@@ -797,27 +854,201 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -797,27 +854,201 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
797 } 854 }
798 855
799 /** 856 /**
857 + * As per the OFDPA 2.0 TTP, packets are sent out of ports by using
858 + * a chain of groups. The Next Objective passed in by the application
859 + * has to be broken up into a group chain comprising of an
860 + * L2 Flood group whose buckets point to L2 Interface groups.
861 + *
862 + * @param nextObj the nextObjective of type BROADCAST
863 + */
864 + private void processBroadcastNextObjective(NextObjective nextObj) {
865 + // break up broadcast next objective to multiple groups
866 + Collection<TrafficTreatment> buckets = nextObj.next();
867 +
868 + // each treatment is converted to an L2 interface group
869 + int indicator = 0;
870 + VlanId vlanid = null;
871 + List<GroupInfo> groupInfoCollection = new ArrayList<>();
872 + for (TrafficTreatment treatment : buckets) {
873 + TrafficTreatment.Builder newTreatment = DefaultTrafficTreatment.builder();
874 + PortNumber portNum = null;
875 + // ensure that the only allowed treatments are pop-vlan and output
876 + for (Instruction ins : treatment.allInstructions()) {
877 + if (ins.type() == Instruction.Type.L2MODIFICATION) {
878 + L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
879 + switch (l2ins.subtype()) {
880 + case VLAN_POP:
881 + newTreatment.add(l2ins);
882 + break;
883 + default:
884 + log.debug("action {} not permitted for broadcast nextObj",
885 + l2ins.subtype());
886 + break;
887 + }
888 + } else if (ins.type() == Instruction.Type.OUTPUT) {
889 + portNum = ((OutputInstruction) ins).port();
890 + newTreatment.add(ins);
891 + } else {
892 + log.debug("TrafficTreatment of type {} not permitted in "
893 + + " broadcast nextObjective", ins.type());
894 + }
895 + }
896 +
897 + // also ensure that all ports are in the same vlan
898 + VlanId thisvlanid = port2Vlan.get(portNum);
899 + if (vlanid == null) {
900 + vlanid = thisvlanid;
901 + } else {
902 + if (!vlanid.equals(thisvlanid)) {
903 + log.error("Driver requires all ports in a broadcast nextObj "
904 + + "to be in the same vlan. Different vlans found "
905 + + "{} and {}. Aborting group creation", vlanid, thisvlanid);
906 + return;
907 + }
908 + }
909 +
910 + // assemble info for all l2 interface groups
911 + indicator += GROUP1MASK;
912 + int l2gk = nextObj.id() | indicator;
913 + final GroupKey l2groupkey = new DefaultGroupKey(appKryo.serialize(l2gk));
914 + Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) |
915 + (int) portNum.toLong();
916 + GroupBucket newbucket =
917 + DefaultGroupBucket.createIndirectGroupBucket(newTreatment.build());
918 +
919 + // store the info needed to create this group
920 + groupInfoCollection.add(new GroupInfo(l2groupId, l2groupkey, newbucket));
921 + }
922 +
923 + // assemble info for l2 flood group
924 + int l2floodgk = nextObj.id() | GROUP0MASK;
925 + final GroupKey l2floodgroupkey = new DefaultGroupKey(appKryo.serialize(l2floodgk));
926 + Integer l2floodgroupId = L2FLOODMASK | (vlanid.toShort() << 16) | nextObj.id();
927 + // collection of treatment with groupids of l2 interface groups
928 + List<TrafficTreatment> floodtt = new ArrayList<>();
929 + for (GroupInfo gi : groupInfoCollection) {
930 + TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder();
931 + ttb.group(new DefaultGroupId(gi.groupId));
932 + floodtt.add(ttb.build());
933 + }
934 + GroupChainElem gce = new GroupChainElem(l2floodgroupkey, l2floodgroupId,
935 + GroupDescription.Type.ALL,
936 + floodtt,
937 + nextObj.appId(),
938 + groupInfoCollection.size());
939 +
940 + // create objects for local and distributed storage
941 + List<GroupKey> gkeys = new ArrayList<GroupKey>();
942 + gkeys.add(l2floodgroupkey); // group0 in chain
943 + OfdpaGroupChain ofdpaGrp = new OfdpaGroupChain(gkeys, nextObj);
944 +
945 + // store l2floodgroupkey with the ofdpaGroupChain for the nextObjective
946 + // that depends on it
947 + pendingNextObjectives.put(l2floodgroupkey, ofdpaGrp);
948 +
949 + for (GroupInfo gi : groupInfoCollection) {
950 + // store all l2groupkeys with the groupChainElem for the l2floodgroup
951 + // that depends on it
952 + pendingGroups.put(gi.groupKey, gce);
953 +
954 + // create and send groups for all l2 interface groups
955 + GroupDescription groupDescription =
956 + new DefaultGroupDescription(
957 + deviceId,
958 + GroupDescription.Type.INDIRECT,
959 + new GroupBuckets(Collections.singletonList(gi.groupBucket)),
960 + gi.groupKey,
961 + gi.groupId,
962 + nextObj.appId());
963 + groupService.addGroup(groupDescription);
964 + }
965 + }
966 +
967 + private class GroupInfo {
968 + private Integer groupId;
969 + private GroupKey groupKey;
970 + private GroupBucket groupBucket;
971 +
972 + GroupInfo(Integer groupId, GroupKey groupKey, GroupBucket groupBucket) {
973 + this.groupBucket = groupBucket;
974 + this.groupId = groupId;
975 + this.groupKey = groupKey;
976 + }
977 + }
978 +
979 + private void processHashedNextObjective(NextObjective nextObj) {
980 + // TODO Auto-generated method stub
981 + }
982 +
983 + private void addBucketToGroup(NextObjective nextObjective) {
984 + // TODO Auto-generated method stub
985 + }
986 +
987 + private void removeBucketFromGroup(NextObjective nextObjective) {
988 + // TODO Auto-generated method stub
989 + }
990 +
991 + private void removeGroup(NextObjective nextObjective) {
992 + // TODO Auto-generated method stub
993 + }
994 +
995 + /**
800 * Processes next element of a group chain. Assumption is that if this 996 * Processes next element of a group chain. Assumption is that if this
801 * group points to another group, the latter has already been created 997 * group points to another group, the latter has already been created
802 * and this driver has received notification for it. A second assumption is 998 * and this driver has received notification for it. A second assumption is
803 * that if there is another group waiting for this group then the appropriate 999 * that if there is another group waiting for this group then the appropriate
804 * stores already have the information to act upon the notification for the 1000 * stores already have the information to act upon the notification for the
805 * creating of this group. 1001 * creating of this group.
1002 + * <p>
1003 + * The processing of the GroupChainElement depends on the number of groups
1004 + * this element is waiting on. For all group types other than SIMPLE, a
1005 + * GroupChainElement could be waiting on multiple groups.
806 * 1006 *
807 * @param gce the group chain element to be processed next 1007 * @param gce the group chain element to be processed next
808 */ 1008 */
809 private void processGroupChain(GroupChainElem gce) { 1009 private void processGroupChain(GroupChainElem gce) {
810 - GroupBucket bucket = DefaultGroupBucket 1010 + int waitOnGroups = gce.decrementAndGetGroupsWaitedOn();
811 - .createIndirectGroupBucket(gce.getBucketActions()); 1011 + if (waitOnGroups != 0) {
812 - GroupDescription groupDesc = new DefaultGroupDescription(deviceId, 1012 + log.debug("GCE: {} waiting on {} groups. Not processing yet",
813 - GroupDescription.Type.INDIRECT, 1013 + gce, waitOnGroups);
814 - new GroupBuckets(Collections.singletonList(bucket)), 1014 + return;
815 - gce.getGkey(), 1015 + }
816 - gce.getGivenGroupId(), 1016 + List<GroupBucket> buckets = new ArrayList<>();
817 - gce.getAppId()); 1017 + switch (gce.groupType) {
818 - groupService.addGroup(groupDesc); 1018 + case INDIRECT:
819 - } 1019 + GroupBucket ibucket = DefaultGroupBucket
1020 + .createIndirectGroupBucket(gce.bucketActions.iterator().next());
1021 + buckets.add(ibucket);
1022 + break;
1023 + case ALL:
1024 + for (TrafficTreatment tt : gce.bucketActions) {
1025 + GroupBucket abucket = DefaultGroupBucket
1026 + .createAllGroupBucket(tt);
1027 + buckets.add(abucket);
1028 + }
1029 + break;
1030 + case SELECT:
1031 + for (TrafficTreatment tt : gce.bucketActions) {
1032 + GroupBucket sbucket = DefaultGroupBucket
1033 + .createSelectGroupBucket(tt);
1034 + buckets.add(sbucket);
1035 + }
1036 + break;
1037 + case FAILOVER:
1038 + default:
1039 + log.error("Unknown or unimplemented GroupChainElem {}", gce);
1040 + }
820 1041
1042 + if (buckets.size() > 0) {
1043 + GroupDescription groupDesc = new DefaultGroupDescription(
1044 + deviceId, gce.groupType,
1045 + new GroupBuckets(buckets),
1046 + gce.gkey,
1047 + gce.givenGroupId,
1048 + gce.appId);
1049 + groupService.addGroup(groupDesc);
1050 + }
1051 + }
821 1052
822 private class GroupChecker implements Runnable { 1053 private class GroupChecker implements Runnable {
823 @Override 1054 @Override
...@@ -837,7 +1068,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -837,7 +1068,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
837 log.info("Group service processed group key {}. Processing next " 1068 log.info("Group service processed group key {}. Processing next "
838 + "group in group chain with group key {}", 1069 + "group in group chain with group key {}",
839 appKryo.deserialize(key.key()), 1070 appKryo.deserialize(key.key()),
840 - appKryo.deserialize(gce.getGkey().key())); 1071 + appKryo.deserialize(gce.gkey.key()));
841 processGroupChain(gce); 1072 processGroupChain(gce);
842 } else { 1073 } else {
843 OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key); 1074 OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key);
...@@ -866,7 +1097,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -866,7 +1097,7 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
866 log.info("group ADDED with group key {} .. " 1097 log.info("group ADDED with group key {} .. "
867 + "Processing next group in group chain with group key {}", 1098 + "Processing next group in group chain with group key {}",
868 appKryo.deserialize(key.key()), 1099 appKryo.deserialize(key.key()),
869 - appKryo.deserialize(gce.getGkey().key())); 1100 + appKryo.deserialize(gce.gkey.key()));
870 processGroupChain(gce); 1101 processGroupChain(gce);
871 } else { 1102 } else {
872 OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key); 1103 OfdpaGroupChain obj = pendingNextObjectives.getIfPresent(key);
...@@ -890,6 +1121,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -890,6 +1121,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
890 * look like group0 --> group 1 --> outPort. Information about the groups 1121 * look like group0 --> group 1 --> outPort. Information about the groups
891 * themselves can be fetched from the Group Service using the group keys from 1122 * themselves can be fetched from the Group Service using the group keys from
892 * objects instantiating this class. 1123 * objects instantiating this class.
1124 + *
1125 + * XXX Revisit this - since the forwarding objective only ever needs the
1126 + * groupkey of the top-level group in the group chain, why store a series
1127 + * of groupkeys. Also the group-chain list only works for 1-to-1 chaining,
1128 + * not for 1-to-many chaining.
893 */ 1129 */
894 private class OfdpaGroupChain implements NextGroup { 1130 private class OfdpaGroupChain implements NextGroup {
895 private final NextObjective nextObj; 1131 private final NextObjective nextObj;
...@@ -925,33 +1161,40 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -925,33 +1161,40 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
925 * preceding groups in the group chain to be created. 1161 * preceding groups in the group chain to be created.
926 */ 1162 */
927 private class GroupChainElem { 1163 private class GroupChainElem {
928 - private TrafficTreatment bucketActions; 1164 + private Collection<TrafficTreatment> bucketActions;
929 private Integer givenGroupId; 1165 private Integer givenGroupId;
1166 + private GroupDescription.Type groupType;
930 private GroupKey gkey; 1167 private GroupKey gkey;
931 private ApplicationId appId; 1168 private ApplicationId appId;
1169 + private AtomicInteger waitOnGroups;
932 1170
933 - public GroupChainElem(GroupKey gkey, Integer givenGroupId, 1171 + GroupChainElem(GroupKey gkey, Integer givenGroupId,
934 - TrafficTreatment tr, ApplicationId appId) { 1172 + GroupDescription.Type groupType,
1173 + Collection<TrafficTreatment> tr, ApplicationId appId,
1174 + int waitOnGroups) {
935 this.bucketActions = tr; 1175 this.bucketActions = tr;
936 this.givenGroupId = givenGroupId; 1176 this.givenGroupId = givenGroupId;
1177 + this.groupType = groupType;
937 this.gkey = gkey; 1178 this.gkey = gkey;
938 this.appId = appId; 1179 this.appId = appId;
1180 + this.waitOnGroups = new AtomicInteger(waitOnGroups);
939 } 1181 }
940 1182
941 - public TrafficTreatment getBucketActions() { 1183 + /**
942 - return bucketActions; 1184 + * This methods atomically decrements the counter for the number of
943 - } 1185 + * groups this GroupChainElement is waiting on, for notifications from
944 - 1186 + * the Group Service. When this method returns a value of 0, this
945 - public Integer getGivenGroupId() { 1187 + * GroupChainElement is ready to be processed.
946 - return givenGroupId; 1188 + *
1189 + * @return integer indication of the number of notifications being waited on
1190 + */
1191 + int decrementAndGetGroupsWaitedOn() {
1192 + return waitOnGroups.decrementAndGet();
947 } 1193 }
948 1194
949 - public GroupKey getGkey() { 1195 + @Override
950 - return gkey; 1196 + public String toString() {
951 - } 1197 + return Integer.toHexString(givenGroupId);
952 -
953 - public ApplicationId getAppId() {
954 - return appId;
955 } 1198 }
956 1199
957 } 1200 }
......