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
Showing
5 changed files
with
319 additions
and
53 deletions
... | @@ -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 | } | ... | ... |
-
Please register or login to post a comment