Michele Santuari
Committed by Gerrit Code Review

SinglePoint to MultiPoint Intent initial implementation

Change-Id: I1010997ce4ea993ae34afb8dab4b6c0ae112448d
1 +package org.onlab.onos.cli.net;
2 +
3 +import static org.onlab.onos.net.DeviceId.deviceId;
4 +import static org.onlab.onos.net.PortNumber.portNumber;
5 +
6 +import java.util.HashSet;
7 +import java.util.List;
8 +import java.util.Set;
9 +
10 +import org.apache.karaf.shell.commands.Argument;
11 +import org.apache.karaf.shell.commands.Command;
12 +import org.onlab.onos.net.ConnectPoint;
13 +import org.onlab.onos.net.DeviceId;
14 +import org.onlab.onos.net.PortNumber;
15 +import org.onlab.onos.net.flow.DefaultTrafficTreatment;
16 +import org.onlab.onos.net.flow.TrafficSelector;
17 +import org.onlab.onos.net.flow.TrafficTreatment;
18 +import org.onlab.onos.net.intent.Constraint;
19 +import org.onlab.onos.net.intent.IntentService;
20 +import org.onlab.onos.net.intent.SinglePointToMultiPointIntent;
21 +
22 +
23 +@Command(scope = "onos", name = "add-single-to-multi-intent",
24 + description = "Installs connectivity intent between multiple egress devices and a single ingress device")
25 +public class AddSinglePointToMultiPointIntentCommand extends ConnectivityIntentCommand {
26 + @Argument(index = 0, name = "egressDevices ingressDevice",
27 + description = "egress Device/Port...egress Device/Port ingressDevice/port",
28 + required = true, multiValued = true)
29 + String[] deviceStrings = null;
30 +
31 + @Override
32 + protected void execute() {
33 + IntentService service = get(IntentService.class);
34 +
35 + if (deviceStrings.length < 2) {
36 + return;
37 + }
38 +
39 + String ingressDeviceString = deviceStrings[deviceStrings.length - 1];
40 + DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString));
41 + PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString));
42 + ConnectPoint ingressPoint = new ConnectPoint(ingressDeviceId,
43 + ingressPortNumber);
44 +
45 + Set<ConnectPoint> egressPoints = new HashSet<>();
46 + for (int index = 0; index < deviceStrings.length - 1; index++) {
47 + String egressDeviceString = deviceStrings[index];
48 + DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString));
49 + PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
50 + ConnectPoint egress = new ConnectPoint(egressDeviceId,
51 + egressPortNumber);
52 + egressPoints.add(egress);
53 + }
54 +
55 + TrafficSelector selector = buildTrafficSelector();
56 + TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
57 + List<Constraint> constraints = buildConstraints();
58 +
59 + SinglePointToMultiPointIntent intent = new SinglePointToMultiPointIntent(
60 + appId(),
61 + selector,
62 + treatment,
63 + ingressPoint,
64 + egressPoints,
65 + constraints);
66 + service.submit(intent);
67 + }
68 +
69 + /**
70 + * Extracts the port number portion of the ConnectPoint.
71 + *
72 + * @param deviceString string representing the device/port
73 + * @return port number as a string, empty string if the port is not found
74 + */
75 + private String getPortNumber(String deviceString) {
76 + int slash = deviceString.indexOf('/');
77 + if (slash <= 0) {
78 + return "";
79 + }
80 + return deviceString.substring(slash + 1, deviceString.length());
81 + }
82 +
83 + /**
84 + * Extracts the device ID portion of the ConnectPoint.
85 + *
86 + * @param deviceString string representing the device/port
87 + * @return device ID string
88 + */
89 + private String getDeviceId(String deviceString) {
90 + int slash = deviceString.indexOf('/');
91 + if (slash <= 0) {
92 + return "";
93 + }
94 + return deviceString.substring(0, slash);
95 + }
96 +
97 +}
...@@ -340,7 +340,7 @@ public class IntentsListCommand extends AbstractShellCommand { ...@@ -340,7 +340,7 @@ public class IntentsListCommand extends AbstractShellCommand {
340 } else if (intent instanceof LinkCollectionIntent) { 340 } else if (intent instanceof LinkCollectionIntent) {
341 LinkCollectionIntent li = (LinkCollectionIntent) intent; 341 LinkCollectionIntent li = (LinkCollectionIntent) intent;
342 print(" links=%s", li.links()); 342 print(" links=%s", li.links());
343 - print(" egress=%s", li.egressPoint()); 343 + print(" egress=%s", li.egressPoints());
344 } 344 }
345 345
346 List<Intent> installable = service.getInstallableIntents(intent.id()); 346 List<Intent> installable = service.getInstallableIntents(intent.id());
......
...@@ -161,6 +161,15 @@ ...@@ -161,6 +161,15 @@
161 </optional-completers> 161 </optional-completers>
162 </command> 162 </command>
163 <command> 163 <command>
164 + <action class="org.onlab.onos.cli.net.AddSinglePointToMultiPointIntentCommand"/>
165 + <completers>
166 + <ref component-id="connectPointCompleter"/>
167 + </completers>
168 + <optional-completers>
169 + <entry key="-t" value-ref="ethTypeCompleter"/>
170 + </optional-completers>
171 + </command>
172 + <command>
164 <action class="org.onlab.onos.cli.net.IntentPushTestCommand"/> 173 <action class="org.onlab.onos.cli.net.IntentPushTestCommand"/>
165 <completers> 174 <completers>
166 <ref component-id="connectPointCompleter"/> 175 <ref component-id="connectPointCompleter"/>
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
16 package org.onlab.onos.net.intent; 16 package org.onlab.onos.net.intent;
17 17
18 import com.google.common.base.MoreObjects; 18 import com.google.common.base.MoreObjects;
19 +import com.google.common.collect.ImmutableSet;
20 +
19 import org.onlab.onos.core.ApplicationId; 21 import org.onlab.onos.core.ApplicationId;
20 import org.onlab.onos.net.ConnectPoint; 22 import org.onlab.onos.net.ConnectPoint;
21 import org.onlab.onos.net.Link; 23 import org.onlab.onos.net.Link;
...@@ -34,11 +36,11 @@ public final class LinkCollectionIntent extends ConnectivityIntent { ...@@ -34,11 +36,11 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
34 36
35 private final Set<Link> links; 37 private final Set<Link> links;
36 38
37 - private final ConnectPoint egressPoint; 39 + private final Set<ConnectPoint> egressPoints;
38 40
39 /** 41 /**
40 - * Creates a new actionable intent capable of funneling the selected 42 + * Creates a new actionable intent capable of funneling the selected traffic
41 - * traffic along the specified convergent tree and out the given egress point. 43 + * along the specified convergent tree and out the given egress point.
42 * 44 *
43 * @param appId application identifier 45 * @param appId application identifier
44 * @param selector traffic match 46 * @param selector traffic match
...@@ -77,7 +79,31 @@ public final class LinkCollectionIntent extends ConnectivityIntent { ...@@ -77,7 +79,31 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
77 super(id(LinkCollectionIntent.class, selector, treatment, links, egressPoint, constraints), 79 super(id(LinkCollectionIntent.class, selector, treatment, links, egressPoint, constraints),
78 appId, resources(links), selector, treatment, constraints); 80 appId, resources(links), selector, treatment, constraints);
79 this.links = links; 81 this.links = links;
80 - this.egressPoint = egressPoint; 82 + this.egressPoints = ImmutableSet.of(egressPoint);
83 + }
84 +
85 + /**
86 + * Creates a new actionable intent capable of funneling the selected traffic
87 + * along the specified convergent tree and out the given egress point.
88 + *
89 + * @param appId application identifier
90 + * @param selector traffic match
91 + * @param treatment action
92 + * @param links traversed links
93 + * @param egressPoints Set of egress point
94 + * @throws NullPointerException {@code path} is null
95 + */
96 + public LinkCollectionIntent(ApplicationId appId,
97 + TrafficSelector selector,
98 + TrafficTreatment treatment,
99 + Set<Link> links,
100 + Set<ConnectPoint> egressPoints,
101 + List<Constraint> constraints) {
102 + super(id(LinkCollectionIntent.class, selector, treatment, links,
103 + egressPoints), appId, resources(links), selector, treatment);
104 +
105 + this.links = links;
106 + this.egressPoints = ImmutableSet.copyOf(egressPoints);
81 } 107 }
82 108
83 /** 109 /**
...@@ -86,7 +112,7 @@ public final class LinkCollectionIntent extends ConnectivityIntent { ...@@ -86,7 +112,7 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
86 protected LinkCollectionIntent() { 112 protected LinkCollectionIntent() {
87 super(); 113 super();
88 this.links = null; 114 this.links = null;
89 - this.egressPoint = null; 115 + this.egressPoints = null;
90 } 116 }
91 117
92 /** 118 /**
...@@ -104,8 +130,8 @@ public final class LinkCollectionIntent extends ConnectivityIntent { ...@@ -104,8 +130,8 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
104 * 130 *
105 * @return the egress point 131 * @return the egress point
106 */ 132 */
107 - public ConnectPoint egressPoint() { 133 + public Set<ConnectPoint> egressPoints() {
108 - return egressPoint; 134 + return egressPoints;
109 } 135 }
110 136
111 @Override 137 @Override
...@@ -121,7 +147,7 @@ public final class LinkCollectionIntent extends ConnectivityIntent { ...@@ -121,7 +147,7 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
121 .add("selector", selector()) 147 .add("selector", selector())
122 .add("treatment", treatment()) 148 .add("treatment", treatment())
123 .add("links", links()) 149 .add("links", links())
124 - .add("egress", egressPoint()) 150 + .add("egress", egressPoints())
125 .toString(); 151 .toString();
126 } 152 }
127 } 153 }
......
...@@ -17,12 +17,15 @@ package org.onlab.onos.net.intent; ...@@ -17,12 +17,15 @@ package org.onlab.onos.net.intent;
17 17
18 import com.google.common.base.MoreObjects; 18 import com.google.common.base.MoreObjects;
19 import com.google.common.collect.Sets; 19 import com.google.common.collect.Sets;
20 +
20 import org.onlab.onos.core.ApplicationId; 21 import org.onlab.onos.core.ApplicationId;
21 import org.onlab.onos.net.ConnectPoint; 22 import org.onlab.onos.net.ConnectPoint;
22 import org.onlab.onos.net.flow.TrafficSelector; 23 import org.onlab.onos.net.flow.TrafficSelector;
23 import org.onlab.onos.net.flow.TrafficTreatment; 24 import org.onlab.onos.net.flow.TrafficTreatment;
24 25
26 +import java.util.Collections;
25 import java.util.Set; 27 import java.util.Set;
28 +import java.util.List;
26 29
27 import static com.google.common.base.Preconditions.checkArgument; 30 import static com.google.common.base.Preconditions.checkArgument;
28 import static com.google.common.base.Preconditions.checkNotNull; 31 import static com.google.common.base.Preconditions.checkNotNull;
...@@ -49,19 +52,39 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent { ...@@ -49,19 +52,39 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent {
49 * not more than 1 52 * not more than 1
50 */ 53 */
51 public SinglePointToMultiPointIntent(ApplicationId appId, 54 public SinglePointToMultiPointIntent(ApplicationId appId,
52 - TrafficSelector selector, 55 + TrafficSelector selector, TrafficTreatment treatment,
53 - TrafficTreatment treatment, 56 + ConnectPoint ingressPoint, Set<ConnectPoint> egressPoints) {
54 - ConnectPoint ingressPoint, 57 + this(appId, selector, treatment, ingressPoint, egressPoints, Collections.emptyList());
55 - Set<ConnectPoint> egressPoints) { 58 + }
59 +
60 + /**
61 + * Creates a new single-to-multi point connectivity intent.
62 + *
63 + * @param appId application identifier
64 + * @param selector traffic selector
65 + * @param treatment treatment
66 + * @param ingressPoint port on which traffic will ingress
67 + * @param egressPoints set of ports on which traffic will egress
68 + * @param constraints constraints to apply to the intent
69 + * @throws NullPointerException if {@code ingressPoint} or
70 + * {@code egressPoints} is null
71 + * @throws IllegalArgumentException if the size of {@code egressPoints} is
72 + * not more than 1
73 + */
74 + public SinglePointToMultiPointIntent(ApplicationId appId,
75 + TrafficSelector selector, TrafficTreatment treatment,
76 + ConnectPoint ingressPoint, Set<ConnectPoint> egressPoints,
77 + List<Constraint> constraints) {
56 super(id(SinglePointToMultiPointIntent.class, selector, treatment, 78 super(id(SinglePointToMultiPointIntent.class, selector, treatment,
57 - ingressPoint, egressPoints), appId, null, selector, treatment); 79 + ingressPoint, egressPoints), appId, null, selector, treatment,
80 + constraints);
58 checkNotNull(egressPoints); 81 checkNotNull(egressPoints);
59 checkNotNull(ingressPoint); 82 checkNotNull(ingressPoint);
60 checkArgument(!egressPoints.isEmpty(), "Egress point set cannot be empty"); 83 checkArgument(!egressPoints.isEmpty(), "Egress point set cannot be empty");
61 checkArgument(!egressPoints.contains(ingressPoint), 84 checkArgument(!egressPoints.contains(ingressPoint),
62 "Set of egresses should not contain ingress (ingress: %s)", ingressPoint); 85 "Set of egresses should not contain ingress (ingress: %s)", ingressPoint);
63 86
64 - this.ingressPoint = ingressPoint; 87 + this.ingressPoint = checkNotNull(ingressPoint);
65 this.egressPoints = Sets.newHashSet(egressPoints); 88 this.egressPoints = Sets.newHashSet(egressPoints);
66 } 89 }
67 90
...@@ -75,7 +98,8 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent { ...@@ -75,7 +98,8 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent {
75 } 98 }
76 99
77 /** 100 /**
78 - * Returns the port on which the ingress traffic should be connected to the egress. 101 + * Returns the port on which the ingress traffic should be connected to the
102 + * egress.
79 * 103 *
80 * @return ingress port 104 * @return ingress port
81 */ 105 */
...@@ -101,6 +125,7 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent { ...@@ -101,6 +125,7 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent {
101 .add("treatment", treatment()) 125 .add("treatment", treatment())
102 .add("ingress", ingressPoint) 126 .add("ingress", ingressPoint)
103 .add("egress", egressPoints) 127 .add("egress", egressPoints)
128 + .add("constraints", constraints())
104 .toString(); 129 .toString();
105 } 130 }
106 131
......
...@@ -28,6 +28,7 @@ import org.onlab.onos.net.flow.TrafficSelector; ...@@ -28,6 +28,7 @@ import org.onlab.onos.net.flow.TrafficSelector;
28 import org.onlab.onos.net.intent.constraint.LambdaConstraint; 28 import org.onlab.onos.net.intent.constraint.LambdaConstraint;
29 import org.onlab.onos.net.resource.Lambda; 29 import org.onlab.onos.net.resource.Lambda;
30 30
31 +import com.google.common.collect.ImmutableSet;
31 import com.google.common.testing.EqualsTester; 32 import com.google.common.testing.EqualsTester;
32 33
33 import static org.hamcrest.MatcherAssert.assertThat; 34 import static org.hamcrest.MatcherAssert.assertThat;
...@@ -111,7 +112,7 @@ public class LinkCollectionIntentTest { ...@@ -111,7 +112,7 @@ public class LinkCollectionIntentTest {
111 assertThat(collectionIntent.isInstallable(), is(true)); 112 assertThat(collectionIntent.isInstallable(), is(true));
112 assertThat(collectionIntent.treatment(), is(treatment)); 113 assertThat(collectionIntent.treatment(), is(treatment));
113 assertThat(collectionIntent.selector(), is(selector)); 114 assertThat(collectionIntent.selector(), is(selector));
114 - assertThat(collectionIntent.egressPoint(), is(egress)); 115 + assertThat(collectionIntent.egressPoints(), is(ImmutableSet.of(egress)));
115 assertThat(collectionIntent.resources(), hasSize(1)); 116 assertThat(collectionIntent.resources(), hasSize(1));
116 final List<Constraint> createdConstraints = collectionIntent.constraints(); 117 final List<Constraint> createdConstraints = collectionIntent.constraints();
117 assertThat(createdConstraints, hasSize(0)); 118 assertThat(createdConstraints, hasSize(0));
...@@ -140,7 +141,7 @@ public class LinkCollectionIntentTest { ...@@ -140,7 +141,7 @@ public class LinkCollectionIntentTest {
140 assertThat(collectionIntent.isInstallable(), is(true)); 141 assertThat(collectionIntent.isInstallable(), is(true));
141 assertThat(collectionIntent.treatment(), is(treatment)); 142 assertThat(collectionIntent.treatment(), is(treatment));
142 assertThat(collectionIntent.selector(), is(selector)); 143 assertThat(collectionIntent.selector(), is(selector));
143 - assertThat(collectionIntent.egressPoint(), is(egress)); 144 + assertThat(collectionIntent.egressPoints(), is(ImmutableSet.of(egress)));
144 145
145 final List<Constraint> createdConstraints = collectionIntent.constraints(); 146 final List<Constraint> createdConstraints = collectionIntent.constraints();
146 assertThat(createdConstraints, hasSize(1)); 147 assertThat(createdConstraints, hasSize(1));
...@@ -161,7 +162,7 @@ public class LinkCollectionIntentTest { ...@@ -161,7 +162,7 @@ public class LinkCollectionIntentTest {
161 assertThat(collectionIntent.isInstallable(), is(true)); 162 assertThat(collectionIntent.isInstallable(), is(true));
162 assertThat(collectionIntent.treatment(), nullValue()); 163 assertThat(collectionIntent.treatment(), nullValue());
163 assertThat(collectionIntent.selector(), nullValue()); 164 assertThat(collectionIntent.selector(), nullValue());
164 - assertThat(collectionIntent.egressPoint(), nullValue()); 165 + assertThat(collectionIntent.egressPoints(), nullValue());
165 166
166 final List<Constraint> createdConstraints = collectionIntent.constraints(); 167 final List<Constraint> createdConstraints = collectionIntent.constraints();
167 assertThat(createdConstraints, hasSize(0)); 168 assertThat(createdConstraints, hasSize(0));
......
...@@ -15,9 +15,12 @@ ...@@ -15,9 +15,12 @@
15 */ 15 */
16 package org.onlab.onos.net.intent.impl; 16 package org.onlab.onos.net.intent.impl;
17 17
18 -import static org.slf4j.LoggerFactory.getLogger; 18 +import java.util.HashMap;
19 - 19 +import java.util.HashSet;
20 import java.util.List; 20 import java.util.List;
21 +import java.util.Map;
22 +import java.util.Map.Entry;
23 +import java.util.Set;
21 24
22 import org.apache.felix.scr.annotations.Activate; 25 import org.apache.felix.scr.annotations.Activate;
23 import org.apache.felix.scr.annotations.Component; 26 import org.apache.felix.scr.annotations.Component;
...@@ -26,6 +29,7 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -26,6 +29,7 @@ import org.apache.felix.scr.annotations.Reference;
26 import org.apache.felix.scr.annotations.ReferenceCardinality; 29 import org.apache.felix.scr.annotations.ReferenceCardinality;
27 import org.onlab.onos.core.ApplicationId; 30 import org.onlab.onos.core.ApplicationId;
28 import org.onlab.onos.core.CoreService; 31 import org.onlab.onos.core.CoreService;
32 +import org.onlab.onos.net.ConnectPoint;
29 import org.onlab.onos.net.DeviceId; 33 import org.onlab.onos.net.DeviceId;
30 import org.onlab.onos.net.Link; 34 import org.onlab.onos.net.Link;
31 import org.onlab.onos.net.PortNumber; 35 import org.onlab.onos.net.PortNumber;
...@@ -42,18 +46,16 @@ import org.onlab.onos.net.intent.IntentExtensionService; ...@@ -42,18 +46,16 @@ import org.onlab.onos.net.intent.IntentExtensionService;
42 import org.onlab.onos.net.intent.IntentInstaller; 46 import org.onlab.onos.net.intent.IntentInstaller;
43 import org.onlab.onos.net.intent.LinkCollectionIntent; 47 import org.onlab.onos.net.intent.LinkCollectionIntent;
44 import org.onlab.onos.net.intent.PathIntent; 48 import org.onlab.onos.net.intent.PathIntent;
45 -import org.slf4j.Logger;
46 49
47 import com.google.common.collect.Lists; 50 import com.google.common.collect.Lists;
48 51
49 /** 52 /**
50 - * Installer for {@link org.onlab.onos.net.intent.LinkCollectionIntent} 53 + * Installer for {@link org.onlab.onos.net.intent.LinkCollectionIntent} path
51 - * path segment intents. 54 + * segment intents.
52 */ 55 */
53 @Component(immediate = true) 56 @Component(immediate = true)
54 -public class LinkCollectionIntentInstaller implements IntentInstaller<LinkCollectionIntent> { 57 +public class LinkCollectionIntentInstaller
55 - 58 + implements IntentInstaller<LinkCollectionIntent> {
56 - private final Logger log = getLogger(getClass());
57 59
58 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 protected IntentExtensionService intentManager; 61 protected IntentExtensionService intentManager;
...@@ -76,37 +78,58 @@ public class LinkCollectionIntentInstaller implements IntentInstaller<LinkCollec ...@@ -76,37 +78,58 @@ public class LinkCollectionIntentInstaller implements IntentInstaller<LinkCollec
76 78
77 @Override 79 @Override
78 public List<FlowRuleBatchOperation> install(LinkCollectionIntent intent) { 80 public List<FlowRuleBatchOperation> install(LinkCollectionIntent intent) {
81 + Map<DeviceId, Set<PortNumber>> outputMap = new HashMap<DeviceId, Set<PortNumber>>();
79 List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); 82 List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
83 +
80 for (Link link : intent.links()) { 84 for (Link link : intent.links()) {
81 - rules.add(createBatchEntry(FlowRuleOperation.ADD, 85 + if (outputMap.get(link.src().deviceId()) == null) {
82 - intent, 86 + outputMap.put(link.src().deviceId(), new HashSet<PortNumber>());
83 - link.src().deviceId(), 87 + }
84 - link.src().port())); 88 + outputMap.get(link.src().deviceId()).add(link.src().port());
89 +
90 + }
91 +
92 + for (ConnectPoint egressPoint : intent.egressPoints()) {
93 + if (outputMap.get(egressPoint.deviceId()) == null) {
94 + outputMap
95 + .put(egressPoint.deviceId(), new HashSet<PortNumber>());
96 + }
97 + outputMap.get(egressPoint.deviceId()).add(egressPoint.port());
98 +
85 } 99 }
86 100
87 - rules.add(createBatchEntry(FlowRuleOperation.ADD, 101 + for (Entry<DeviceId, Set<PortNumber>> entry : outputMap.entrySet()) {
88 - intent, 102 + rules.add(createBatchEntry(FlowRuleOperation.ADD, intent,
89 - intent.egressPoint().deviceId(), 103 + entry.getKey(), entry.getValue()));
90 - intent.egressPoint().port())); 104 + }
91 105
92 return Lists.newArrayList(new FlowRuleBatchOperation(rules)); 106 return Lists.newArrayList(new FlowRuleBatchOperation(rules));
93 } 107 }
94 108
95 @Override 109 @Override
96 public List<FlowRuleBatchOperation> uninstall(LinkCollectionIntent intent) { 110 public List<FlowRuleBatchOperation> uninstall(LinkCollectionIntent intent) {
111 + Map<DeviceId, Set<PortNumber>> outputMap = new HashMap<DeviceId, Set<PortNumber>>();
97 List<FlowRuleBatchEntry> rules = Lists.newLinkedList(); 112 List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
98 113
99 for (Link link : intent.links()) { 114 for (Link link : intent.links()) {
100 - rules.add(createBatchEntry(FlowRuleOperation.REMOVE, 115 + if (outputMap.get(link.src().deviceId()) == null) {
101 - intent, 116 + outputMap.put(link.src().deviceId(), new HashSet<PortNumber>());
102 - link.src().deviceId(), 117 + }
103 - link.src().port())); 118 + outputMap.get(link.src().deviceId()).add(link.src().port());
119 + }
120 +
121 + for (ConnectPoint egressPoint : intent.egressPoints()) {
122 + if (outputMap.get(egressPoint.deviceId()) == null) {
123 + outputMap
124 + .put(egressPoint.deviceId(), new HashSet<PortNumber>());
125 + }
126 + outputMap.get(egressPoint.deviceId()).add(egressPoint.port());
104 } 127 }
105 128
106 - rules.add(createBatchEntry(FlowRuleOperation.REMOVE, 129 + for (Entry<DeviceId, Set<PortNumber>> entry : outputMap.entrySet()) {
107 - intent, 130 + rules.add(createBatchEntry(FlowRuleOperation.REMOVE, intent,
108 - intent.egressPoint().deviceId(), 131 + entry.getKey(), entry.getValue()));
109 - intent.egressPoint().port())); 132 + }
110 133
111 return Lists.newArrayList(new FlowRuleBatchOperation(rules)); 134 return Lists.newArrayList(new FlowRuleBatchOperation(rules));
112 } 135 }
...@@ -130,15 +153,18 @@ public class LinkCollectionIntentInstaller implements IntentInstaller<LinkCollec ...@@ -130,15 +153,18 @@ public class LinkCollectionIntentInstaller implements IntentInstaller<LinkCollec
130 private FlowRuleBatchEntry createBatchEntry(FlowRuleOperation operation, 153 private FlowRuleBatchEntry createBatchEntry(FlowRuleOperation operation,
131 LinkCollectionIntent intent, 154 LinkCollectionIntent intent,
132 DeviceId deviceId, 155 DeviceId deviceId,
133 - PortNumber outPort) { 156 + Set<PortNumber> outPorts) {
134 157
135 - TrafficTreatment.Builder treatmentBuilder = 158 + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
136 - DefaultTrafficTreatment.builder(intent.treatment()); 159 + .builder(intent.treatment());
137 160
138 - TrafficTreatment treatment = treatmentBuilder.setOutput(outPort).build(); 161 + for (PortNumber outPort : outPorts) {
162 + treatmentBuilder.setOutput(outPort);
163 + }
164 + TrafficTreatment treatment = treatmentBuilder.build();
139 165
140 - TrafficSelector selector = DefaultTrafficSelector.builder(intent.selector()) 166 + TrafficSelector selector = DefaultTrafficSelector
141 - .build(); 167 + .builder(intent.selector()).build();
142 168
143 FlowRule rule = new DefaultFlowRule(deviceId, 169 FlowRule rule = new DefaultFlowRule(deviceId,
144 selector, treatment, 123, 170 selector, treatment, 123,
......
1 +package org.onlab.onos.net.intent.impl;
2 +
3 +import java.util.Arrays;
4 +import java.util.HashSet;
5 +import java.util.List;
6 +import java.util.Set;
7 +
8 +import org.apache.felix.scr.annotations.Activate;
9 +import org.apache.felix.scr.annotations.Component;
10 +import org.apache.felix.scr.annotations.Deactivate;
11 +import org.onlab.onos.net.ConnectPoint;
12 +import org.onlab.onos.net.Link;
13 +import org.onlab.onos.net.Path;
14 +import org.onlab.onos.net.intent.Intent;
15 +import org.onlab.onos.net.intent.LinkCollectionIntent;
16 +import org.onlab.onos.net.intent.SinglePointToMultiPointIntent;
17 +import org.onlab.onos.net.provider.ProviderId;
18 +import org.onlab.onos.net.resource.LinkResourceAllocations;
19 +
20 +@Component(immediate = true)
21 +public class SinglePointToMultiPointIntentCompiler
22 + extends ConnectivityIntentCompiler<SinglePointToMultiPointIntent> {
23 +
24 + // TODO: use off-the-shell core provider ID
25 + private static final ProviderId PID =
26 + new ProviderId("core", "org.onlab.onos.core", true);
27 +
28 + @Activate
29 + public void activate() {
30 + intentManager.registerCompiler(SinglePointToMultiPointIntent.class,
31 + this);
32 + }
33 +
34 + @Deactivate
35 + public void deactivate() {
36 + intentManager.unregisterCompiler(SinglePointToMultiPointIntent.class);
37 + }
38 +
39 +
40 + @Override
41 + public List<Intent> compile(SinglePointToMultiPointIntent intent,
42 + List<Intent> installable,
43 + Set<LinkResourceAllocations> resources) {
44 + Set<Link> links = new HashSet<>();
45 + //FIXME: need to handle the case where ingress/egress points are on same switch
46 + for (ConnectPoint egressPoint : intent.egressPoints()) {
47 + Path path = getPath(intent, intent.ingressPoint().deviceId(), egressPoint.deviceId());
48 + links.addAll(path.links());
49 + }
50 +
51 + Intent result = new LinkCollectionIntent(intent.appId(),
52 + intent.selector(),
53 + intent.treatment(), links,
54 + intent.egressPoints(), null);
55 +
56 + return Arrays.asList(result);
57 + }
58 +}
...@@ -80,6 +80,7 @@ import org.onlab.onos.net.intent.OpticalPathIntent; ...@@ -80,6 +80,7 @@ import org.onlab.onos.net.intent.OpticalPathIntent;
80 import org.onlab.onos.net.intent.PathIntent; 80 import org.onlab.onos.net.intent.PathIntent;
81 import org.onlab.onos.net.intent.PointToPointIntent; 81 import org.onlab.onos.net.intent.PointToPointIntent;
82 import org.onlab.onos.net.intent.constraint.AnnotationConstraint; 82 import org.onlab.onos.net.intent.constraint.AnnotationConstraint;
83 +import org.onlab.onos.net.intent.SinglePointToMultiPointIntent;
83 import org.onlab.onos.net.intent.constraint.BandwidthConstraint; 84 import org.onlab.onos.net.intent.constraint.BandwidthConstraint;
84 import org.onlab.onos.net.intent.constraint.BooleanConstraint; 85 import org.onlab.onos.net.intent.constraint.BooleanConstraint;
85 import org.onlab.onos.net.intent.constraint.LambdaConstraint; 86 import org.onlab.onos.net.intent.constraint.LambdaConstraint;
...@@ -251,6 +252,7 @@ public final class KryoNamespaces { ...@@ -251,6 +252,7 @@ public final class KryoNamespaces {
251 HostToHostIntent.class, 252 HostToHostIntent.class,
252 PointToPointIntent.class, 253 PointToPointIntent.class,
253 MultiPointToSinglePointIntent.class, 254 MultiPointToSinglePointIntent.class,
255 + SinglePointToMultiPointIntent.class,
254 LinkCollectionIntent.class, 256 LinkCollectionIntent.class,
255 OpticalConnectivityIntent.class, 257 OpticalConnectivityIntent.class,
256 OpticalPathIntent.class, 258 OpticalPathIntent.class,
......