Adding Intent Impl and shell command to install simple intent
Showing
26 changed files
with
1258 additions
and
49 deletions
1 | +package org.onlab.onos.cli.net; | ||
2 | + | ||
3 | +import org.apache.karaf.shell.commands.Argument; | ||
4 | +import org.apache.karaf.shell.commands.Command; | ||
5 | +import org.onlab.onos.cli.AbstractShellCommand; | ||
6 | +import org.onlab.onos.net.HostId; | ||
7 | +import org.onlab.onos.net.flow.DefaultTrafficSelector; | ||
8 | +import org.onlab.onos.net.flow.DefaultTrafficTreatment; | ||
9 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
10 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
11 | +import org.onlab.onos.net.host.HostService; | ||
12 | +import org.onlab.onos.net.intent.HostToHostIntent; | ||
13 | +import org.onlab.onos.net.intent.IntentId; | ||
14 | +import org.onlab.onos.net.intent.IntentService; | ||
15 | + | ||
16 | +/** | ||
17 | + * Lists all shortest-paths paths between the specified source and | ||
18 | + * destination devices. | ||
19 | + */ | ||
20 | +@Command(scope = "onos", name = "add-intent", | ||
21 | + description = "Installs HostToHostIntent between the specified source and destination devices") | ||
22 | +public class IntentInstallCommand extends AbstractShellCommand { | ||
23 | + | ||
24 | + @Argument(index = 0, name = "src", description = "Source device ID", | ||
25 | + required = true, multiValued = false) | ||
26 | + String src = null; | ||
27 | + | ||
28 | + @Argument(index = 1, name = "dst", description = "Destination device ID", | ||
29 | + required = true, multiValued = false) | ||
30 | + String dst = null; | ||
31 | + | ||
32 | + private static long id = 1; | ||
33 | + | ||
34 | + @Override | ||
35 | + protected void execute() { | ||
36 | + IntentService service = get(IntentService.class); | ||
37 | + HostService hosts = get(HostService.class); | ||
38 | + | ||
39 | + HostId srcId = HostId.hostId(src); | ||
40 | + HostId dstId = HostId.hostId(dst); | ||
41 | + | ||
42 | + TrafficSelector.Builder builder = new DefaultTrafficSelector.Builder(); | ||
43 | + builder | ||
44 | + .matchEthSrc(hosts.getHost(srcId).mac()) | ||
45 | + .matchEthDst(hosts.getHost(dstId).mac()); | ||
46 | + | ||
47 | + TrafficTreatment.Builder treat = new DefaultTrafficTreatment.Builder(); | ||
48 | + | ||
49 | + HostToHostIntent intent = new HostToHostIntent( | ||
50 | + new IntentId(id++), | ||
51 | + srcId, | ||
52 | + dstId, | ||
53 | + builder.build(), | ||
54 | + treat.build()); | ||
55 | + | ||
56 | + log.info("Adding intent {}", intent); | ||
57 | + | ||
58 | + service.submit(intent); | ||
59 | + } | ||
60 | + | ||
61 | +} |
... | @@ -57,6 +57,13 @@ | ... | @@ -57,6 +57,13 @@ |
57 | </completers> | 57 | </completers> |
58 | </command> | 58 | </command> |
59 | <command> | 59 | <command> |
60 | + <action class="org.onlab.onos.cli.net.IntentInstallCommand"/> | ||
61 | + <completers> | ||
62 | + <ref component-id="hostIdCompleter"/> | ||
63 | + </completers> | ||
64 | + </command> | ||
65 | + | ||
66 | + <command> | ||
60 | <action class="org.onlab.onos.cli.net.ClustersListCommand"/> | 67 | <action class="org.onlab.onos.cli.net.ClustersListCommand"/> |
61 | </command> | 68 | </command> |
62 | <command> | 69 | <command> | ... | ... |
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | + | ||
5 | +import java.util.Objects; | ||
6 | + | ||
7 | +import org.onlab.onos.net.HostId; | ||
8 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
9 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
10 | + | ||
11 | +import com.google.common.base.MoreObjects; | ||
12 | + | ||
13 | +/** | ||
14 | + * Abstraction of point-to-point connectivity. | ||
15 | + */ | ||
16 | +public class HostToHostIntent extends ConnectivityIntent { | ||
17 | + | ||
18 | + private final HostId src; | ||
19 | + private final HostId dst; | ||
20 | + | ||
21 | + /** | ||
22 | + * Creates a new point-to-point intent with the supplied ingress/egress | ||
23 | + * ports. | ||
24 | + * | ||
25 | + * @param id intent identifier | ||
26 | + * @param match traffic match | ||
27 | + * @param action action | ||
28 | + * @param ingressPort ingress port | ||
29 | + * @param egressPort egress port | ||
30 | + * @throws NullPointerException if {@code ingressPort} or {@code egressPort} | ||
31 | + * is null. | ||
32 | + */ | ||
33 | + public HostToHostIntent(IntentId id, HostId src, HostId dst, | ||
34 | + TrafficSelector selector, TrafficTreatment treatment) { | ||
35 | + super(id, selector, treatment); | ||
36 | + this.src = checkNotNull(src); | ||
37 | + this.dst = checkNotNull(dst); | ||
38 | + } | ||
39 | + | ||
40 | + /** | ||
41 | + * Returns the port on which the ingress traffic should be connected to the | ||
42 | + * egress. | ||
43 | + * | ||
44 | + * @return ingress port | ||
45 | + */ | ||
46 | + public HostId getSrc() { | ||
47 | + return src; | ||
48 | + } | ||
49 | + | ||
50 | + /** | ||
51 | + * Returns the port on which the traffic should egress. | ||
52 | + * | ||
53 | + * @return egress port | ||
54 | + */ | ||
55 | + public HostId getDst() { | ||
56 | + return dst; | ||
57 | + } | ||
58 | + | ||
59 | + @Override | ||
60 | + public boolean equals(Object o) { | ||
61 | + if (this == o) { | ||
62 | + return true; | ||
63 | + } | ||
64 | + if (o == null || getClass() != o.getClass()) { | ||
65 | + return false; | ||
66 | + } | ||
67 | + if (!super.equals(o)) { | ||
68 | + return false; | ||
69 | + } | ||
70 | + | ||
71 | + HostToHostIntent that = (HostToHostIntent) o; | ||
72 | + return Objects.equals(this.src, that.src) | ||
73 | + && Objects.equals(this.dst, that.dst); | ||
74 | + } | ||
75 | + | ||
76 | + @Override | ||
77 | + public int hashCode() { | ||
78 | + return Objects.hash(super.hashCode(), src, dst); | ||
79 | + } | ||
80 | + | ||
81 | + @Override | ||
82 | + public String toString() { | ||
83 | + return MoreObjects.toStringHelper(getClass()) | ||
84 | + .add("id", getId()) | ||
85 | + .add("selector", getTrafficSelector()) | ||
86 | + .add("treatmetn", getTrafficTreatment()) | ||
87 | + .add("src", src) | ||
88 | + .add("dst", dst) | ||
89 | + .toString(); | ||
90 | + } | ||
91 | + | ||
92 | +} |
... | @@ -4,14 +4,17 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -4,14 +4,17 @@ import static com.google.common.base.Preconditions.checkNotNull; |
4 | 4 | ||
5 | import java.util.Objects; | 5 | import java.util.Objects; |
6 | 6 | ||
7 | +import org.onlab.onos.event.AbstractEvent; | ||
8 | + | ||
7 | import com.google.common.base.MoreObjects; | 9 | import com.google.common.base.MoreObjects; |
8 | 10 | ||
9 | /** | 11 | /** |
10 | * A class to represent an intent related event. | 12 | * A class to represent an intent related event. |
11 | */ | 13 | */ |
12 | -public class IntentEvent { | 14 | +public class IntentEvent extends AbstractEvent<IntentState, Intent> { |
13 | 15 | ||
14 | - // TODO: determine a suitable parent class; if one does not exist, consider introducing one | 16 | + // TODO: determine a suitable parent class; if one does not exist, consider |
17 | + // introducing one | ||
15 | 18 | ||
16 | private final long time; | 19 | private final long time; |
17 | private final Intent intent; | 20 | private final Intent intent; |
... | @@ -28,6 +31,7 @@ public class IntentEvent { | ... | @@ -28,6 +31,7 @@ public class IntentEvent { |
28 | * @throws NullPointerException if the intent or state is null | 31 | * @throws NullPointerException if the intent or state is null |
29 | */ | 32 | */ |
30 | public IntentEvent(Intent intent, IntentState state, IntentState previous, long time) { | 33 | public IntentEvent(Intent intent, IntentState state, IntentState previous, long time) { |
34 | + super(state, intent); | ||
31 | this.intent = checkNotNull(intent); | 35 | this.intent = checkNotNull(intent); |
32 | this.state = checkNotNull(state); | 36 | this.state = checkNotNull(state); |
33 | this.previous = previous; | 37 | this.previous = previous; |
... | @@ -35,16 +39,6 @@ public class IntentEvent { | ... | @@ -35,16 +39,6 @@ public class IntentEvent { |
35 | } | 39 | } |
36 | 40 | ||
37 | /** | 41 | /** |
38 | - * Constructor for serializer. | ||
39 | - */ | ||
40 | - protected IntentEvent() { | ||
41 | - this.intent = null; | ||
42 | - this.state = null; | ||
43 | - this.previous = null; | ||
44 | - this.time = 0; | ||
45 | - } | ||
46 | - | ||
47 | - /** | ||
48 | * Returns the state of the intent which caused the event. | 42 | * Returns the state of the intent which caused the event. |
49 | * | 43 | * |
50 | * @return the state of the intent | 44 | * @return the state of the intent | ... | ... |
1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | +import org.onlab.onos.event.EventListener; | ||
4 | + | ||
3 | /** | 5 | /** |
4 | * Listener for {@link IntentEvent intent events}. | 6 | * Listener for {@link IntentEvent intent events}. |
5 | */ | 7 | */ |
6 | -public interface IntentEventListener { | 8 | +public interface IntentListener extends EventListener<IntentEvent> { |
7 | - /** | ||
8 | - * Processes the specified intent event. | ||
9 | - * | ||
10 | - * @param event the event to process | ||
11 | - */ | ||
12 | - void event(IntentEvent event); | ||
13 | } | 9 | } | ... | ... |
1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | -import java.util.Set; | ||
4 | 3 | ||
5 | /** | 4 | /** |
6 | * Service for application submitting or withdrawing their intents. | 5 | * Service for application submitting or withdrawing their intents. |
... | @@ -9,8 +8,8 @@ public interface IntentService { | ... | @@ -9,8 +8,8 @@ public interface IntentService { |
9 | /** | 8 | /** |
10 | * Submits an intent into the system. | 9 | * Submits an intent into the system. |
11 | * | 10 | * |
12 | - * This is an asynchronous request meaning that any compiling | 11 | + * This is an asynchronous request meaning that any compiling or |
13 | - * or installation activities may be done at later time. | 12 | + * installation activities may be done at later time. |
14 | * | 13 | * |
15 | * @param intent intent to be submitted | 14 | * @param intent intent to be submitted |
16 | */ | 15 | */ |
... | @@ -19,8 +18,8 @@ public interface IntentService { | ... | @@ -19,8 +18,8 @@ public interface IntentService { |
19 | /** | 18 | /** |
20 | * Withdraws an intent from the system. | 19 | * Withdraws an intent from the system. |
21 | * | 20 | * |
22 | - * This is an asynchronous request meaning that the environment | 21 | + * This is an asynchronous request meaning that the environment may be |
23 | - * may be affected at later time. | 22 | + * affected at later time. |
24 | * | 23 | * |
25 | * @param intent intent to be withdrawn | 24 | * @param intent intent to be withdrawn |
26 | */ | 25 | */ |
... | @@ -30,19 +29,26 @@ public interface IntentService { | ... | @@ -30,19 +29,26 @@ public interface IntentService { |
30 | * Submits a batch of submit & withdraw operations. Such a batch is | 29 | * Submits a batch of submit & withdraw operations. Such a batch is |
31 | * assumed to be processed together. | 30 | * assumed to be processed together. |
32 | * | 31 | * |
33 | - * This is an asynchronous request meaning that the environment | 32 | + * This is an asynchronous request meaning that the environment may be |
34 | - * may be affected at later time. | 33 | + * affected at later time. |
35 | * | 34 | * |
36 | * @param operations batch of intent operations | 35 | * @param operations batch of intent operations |
37 | */ | 36 | */ |
38 | void execute(IntentOperations operations); | 37 | void execute(IntentOperations operations); |
39 | 38 | ||
40 | /** | 39 | /** |
41 | - * Returns immutable set of intents currently in the system. | 40 | + * Returns an iterable of intents currently in the system. |
42 | * | 41 | * |
43 | * @return set of intents | 42 | * @return set of intents |
44 | */ | 43 | */ |
45 | - Set<Intent> getIntents(); | 44 | + Iterable<Intent> getIntents(); |
45 | + | ||
46 | + /** | ||
47 | + * Returns the number of intents currently in the system. | ||
48 | + * | ||
49 | + * @return number of intents | ||
50 | + */ | ||
51 | + long getIntentCount(); | ||
46 | 52 | ||
47 | /** | 53 | /** |
48 | * Retrieves the intent specified by its identifier. | 54 | * Retrieves the intent specified by its identifier. |
... | @@ -56,7 +62,8 @@ public interface IntentService { | ... | @@ -56,7 +62,8 @@ public interface IntentService { |
56 | * Retrieves the state of an intent by its identifier. | 62 | * Retrieves the state of an intent by its identifier. |
57 | * | 63 | * |
58 | * @param id intent identifier | 64 | * @param id intent identifier |
59 | - * @return the intent state or null if one with the given identifier is not found | 65 | + * @return the intent state or null if one with the given identifier is not |
66 | + * found | ||
60 | */ | 67 | */ |
61 | IntentState getIntentState(IntentId id); | 68 | IntentState getIntentState(IntentId id); |
62 | 69 | ||
... | @@ -65,12 +72,12 @@ public interface IntentService { | ... | @@ -65,12 +72,12 @@ public interface IntentService { |
65 | * | 72 | * |
66 | * @param listener listener to be added | 73 | * @param listener listener to be added |
67 | */ | 74 | */ |
68 | - void addListener(IntentEventListener listener); | 75 | + void addListener(IntentListener listener); |
69 | 76 | ||
70 | /** | 77 | /** |
71 | * Removes the specified listener for intent events. | 78 | * Removes the specified listener for intent events. |
72 | * | 79 | * |
73 | * @param listener listener to be removed | 80 | * @param listener listener to be removed |
74 | */ | 81 | */ |
75 | - void removeListener(IntentEventListener listener); | 82 | + void removeListener(IntentListener listener); |
76 | } | 83 | } | ... | ... |
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import java.util.List; | ||
4 | + | ||
5 | +import org.onlab.onos.store.Store; | ||
6 | + | ||
7 | +/** | ||
8 | + * Manages inventory of end-station intents; not intended for direct use. | ||
9 | + */ | ||
10 | +public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { | ||
11 | + | ||
12 | + /** | ||
13 | + * Creates a new intent. | ||
14 | + * | ||
15 | + * @param intent intent | ||
16 | + * @return appropriate event or null if no change resulted | ||
17 | + */ | ||
18 | + IntentEvent createIntent(Intent intent); | ||
19 | + | ||
20 | + /** | ||
21 | + * Removes the specified intent from the inventory. | ||
22 | + * | ||
23 | + * @param intentId intent identification | ||
24 | + * @return remove event or null if intent was not found | ||
25 | + */ | ||
26 | + IntentEvent removeIntent(IntentId intent); | ||
27 | + | ||
28 | + /** | ||
29 | + * Returns the number of intents in the store. | ||
30 | + * | ||
31 | + */ | ||
32 | + long getIntentCount(); | ||
33 | + | ||
34 | + /** | ||
35 | + * Returns a collection of all intents in the store. | ||
36 | + * | ||
37 | + * @return iterable collection of all intents | ||
38 | + */ | ||
39 | + Iterable<Intent> getIntents(); | ||
40 | + | ||
41 | + /** | ||
42 | + * Returns the intent with the specified identifer. | ||
43 | + * | ||
44 | + * @param intentId intent identification | ||
45 | + * @return intent or null if not found | ||
46 | + */ | ||
47 | + Intent getIntent(IntentId intentId); | ||
48 | + | ||
49 | + IntentState getIntentState(IntentId id); | ||
50 | + | ||
51 | + /** | ||
52 | + * Sets the state of the specified intent to the new state. | ||
53 | + * | ||
54 | + * @param intent intent whose state is to be changed | ||
55 | + * @param newState new state | ||
56 | + */ | ||
57 | + IntentEvent setState(Intent intent, IntentState newState); | ||
58 | + | ||
59 | + IntentEvent addInstallableIntents(IntentId intentId, List<InstallableIntent> result); | ||
60 | + | ||
61 | + List<InstallableIntent> getInstallableIntents(IntentId intentId); | ||
62 | + | ||
63 | + void removeInstalledIntents(IntentId intentId); | ||
64 | +} |
... | @@ -12,7 +12,7 @@ import com.google.common.base.MoreObjects; | ... | @@ -12,7 +12,7 @@ import com.google.common.base.MoreObjects; |
12 | /** | 12 | /** |
13 | * Abstraction of explicitly path specified connectivity intent. | 13 | * Abstraction of explicitly path specified connectivity intent. |
14 | */ | 14 | */ |
15 | -public class PathIntent extends PointToPointIntent { | 15 | +public class PathIntent extends PointToPointIntent implements InstallableIntent { |
16 | 16 | ||
17 | private final Path path; | 17 | private final Path path; |
18 | 18 | ... | ... |
... | @@ -11,19 +11,19 @@ import java.util.concurrent.ExecutorService; | ... | @@ -11,19 +11,19 @@ import java.util.concurrent.ExecutorService; |
11 | import java.util.concurrent.Executors; | 11 | import java.util.concurrent.Executors; |
12 | 12 | ||
13 | /** | 13 | /** |
14 | - * Fake implementation of the intent service to assist in developing tests | 14 | + * Fake implementation of the intent service to assist in developing tests of |
15 | - * of the interface contract. | 15 | + * the interface contract. |
16 | */ | 16 | */ |
17 | public class FakeIntentManager implements TestableIntentService { | 17 | public class FakeIntentManager implements TestableIntentService { |
18 | 18 | ||
19 | private final Map<IntentId, Intent> intents = new HashMap<>(); | 19 | private final Map<IntentId, Intent> intents = new HashMap<>(); |
20 | private final Map<IntentId, IntentState> intentStates = new HashMap<>(); | 20 | private final Map<IntentId, IntentState> intentStates = new HashMap<>(); |
21 | private final Map<IntentId, List<InstallableIntent>> installables = new HashMap<>(); | 21 | private final Map<IntentId, List<InstallableIntent>> installables = new HashMap<>(); |
22 | - private final Set<IntentEventListener> listeners = new HashSet<>(); | 22 | + private final Set<IntentListener> listeners = new HashSet<>(); |
23 | 23 | ||
24 | private final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers = new HashMap<>(); | 24 | private final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers = new HashMap<>(); |
25 | - private final Map<Class<? extends InstallableIntent>, | 25 | + private final Map<Class<? extends InstallableIntent>, IntentInstaller<? extends InstallableIntent>> installers |
26 | - IntentInstaller<? extends InstallableIntent>> installers = new HashMap<>(); | 26 | + = new HashMap<>(); |
27 | 27 | ||
28 | private final ExecutorService executor = Executors.newSingleThreadExecutor(); | 28 | private final ExecutorService executor = Executors.newSingleThreadExecutor(); |
29 | private final List<IntentException> exceptions = new ArrayList<>(); | 29 | private final List<IntentException> exceptions = new ArrayList<>(); |
... | @@ -76,7 +76,8 @@ public class FakeIntentManager implements TestableIntentService { | ... | @@ -76,7 +76,8 @@ public class FakeIntentManager implements TestableIntentService { |
76 | 76 | ||
77 | private <T extends InstallableIntent> IntentInstaller<T> getInstaller(T intent) { | 77 | private <T extends InstallableIntent> IntentInstaller<T> getInstaller(T intent) { |
78 | @SuppressWarnings("unchecked") | 78 | @SuppressWarnings("unchecked") |
79 | - IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass()); | 79 | + IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent |
80 | + .getClass()); | ||
80 | if (installer == null) { | 81 | if (installer == null) { |
81 | throw new IntentException("no installer for class " + intent.getClass()); | 82 | throw new IntentException("no installer for class " + intent.getClass()); |
82 | } | 83 | } |
... | @@ -125,7 +126,6 @@ public class FakeIntentManager implements TestableIntentService { | ... | @@ -125,7 +126,6 @@ public class FakeIntentManager implements TestableIntentService { |
125 | } | 126 | } |
126 | } | 127 | } |
127 | 128 | ||
128 | - | ||
129 | // Sets the internal state for the given intent and dispatches an event | 129 | // Sets the internal state for the given intent and dispatches an event |
130 | private void setState(Intent intent, IntentState state) { | 130 | private void setState(Intent intent, IntentState state) { |
131 | IntentState previous = intentStates.get(intent.getId()); | 131 | IntentState previous = intentStates.get(intent.getId()); |
... | @@ -175,6 +175,11 @@ public class FakeIntentManager implements TestableIntentService { | ... | @@ -175,6 +175,11 @@ public class FakeIntentManager implements TestableIntentService { |
175 | } | 175 | } |
176 | 176 | ||
177 | @Override | 177 | @Override |
178 | + public long getIntentCount() { | ||
179 | + return intents.size(); | ||
180 | + } | ||
181 | + | ||
182 | + @Override | ||
178 | public Intent getIntent(IntentId id) { | 183 | public Intent getIntent(IntentId id) { |
179 | return intents.get(id); | 184 | return intents.get(id); |
180 | } | 185 | } |
... | @@ -185,23 +190,24 @@ public class FakeIntentManager implements TestableIntentService { | ... | @@ -185,23 +190,24 @@ public class FakeIntentManager implements TestableIntentService { |
185 | } | 190 | } |
186 | 191 | ||
187 | @Override | 192 | @Override |
188 | - public void addListener(IntentEventListener listener) { | 193 | + public void addListener(IntentListener listener) { |
189 | listeners.add(listener); | 194 | listeners.add(listener); |
190 | } | 195 | } |
191 | 196 | ||
192 | @Override | 197 | @Override |
193 | - public void removeListener(IntentEventListener listener) { | 198 | + public void removeListener(IntentListener listener) { |
194 | listeners.remove(listener); | 199 | listeners.remove(listener); |
195 | } | 200 | } |
196 | 201 | ||
197 | private void dispatch(IntentEvent event) { | 202 | private void dispatch(IntentEvent event) { |
198 | - for (IntentEventListener listener : listeners) { | 203 | + for (IntentListener listener : listeners) { |
199 | listener.event(event); | 204 | listener.event(event); |
200 | } | 205 | } |
201 | } | 206 | } |
202 | 207 | ||
203 | @Override | 208 | @Override |
204 | - public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) { | 209 | + public <T extends Intent> void registerCompiler(Class<T> cls, |
210 | + IntentCompiler<T> compiler) { | ||
205 | compilers.put(cls, compiler); | 211 | compilers.put(cls, compiler); |
206 | } | 212 | } |
207 | 213 | ||
... | @@ -216,7 +222,8 @@ public class FakeIntentManager implements TestableIntentService { | ... | @@ -216,7 +222,8 @@ public class FakeIntentManager implements TestableIntentService { |
216 | } | 222 | } |
217 | 223 | ||
218 | @Override | 224 | @Override |
219 | - public <T extends InstallableIntent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) { | 225 | + public <T extends InstallableIntent> void registerInstaller(Class<T> cls, |
226 | + IntentInstaller<T> installer) { | ||
220 | installers.put(cls, installer); | 227 | installers.put(cls, installer); |
221 | } | 228 | } |
222 | 229 | ||
... | @@ -252,7 +259,8 @@ public class FakeIntentManager implements TestableIntentService { | ... | @@ -252,7 +259,8 @@ public class FakeIntentManager implements TestableIntentService { |
252 | if (!installers.containsKey(intent.getClass())) { | 259 | if (!installers.containsKey(intent.getClass())) { |
253 | Class<?> cls = intent.getClass(); | 260 | Class<?> cls = intent.getClass(); |
254 | while (cls != Object.class) { | 261 | while (cls != Object.class) { |
255 | - // As long as we're within the InstallableIntent class descendants | 262 | + // As long as we're within the InstallableIntent class |
263 | + // descendants | ||
256 | if (InstallableIntent.class.isAssignableFrom(cls)) { | 264 | if (InstallableIntent.class.isAssignableFrom(cls)) { |
257 | IntentInstaller<?> installer = installers.get(cls); | 265 | IntentInstaller<?> installer = installers.get(cls); |
258 | if (installer != null) { | 266 | if (installer != null) { | ... | ... |
... | @@ -51,7 +51,7 @@ public class IntentServiceTest { | ... | @@ -51,7 +51,7 @@ public class IntentServiceTest { |
51 | @Test | 51 | @Test |
52 | public void basics() { | 52 | public void basics() { |
53 | // Make sure there are no intents | 53 | // Make sure there are no intents |
54 | - assertEquals("incorrect intent count", 0, service.getIntents().size()); | 54 | + assertEquals("incorrect intent count", 0, service.getIntentCount()); |
55 | 55 | ||
56 | // Register a compiler and an installer both setup for success. | 56 | // Register a compiler and an installer both setup for success. |
57 | service.registerCompiler(TestIntent.class, new TestCompiler(new TestInstallableIntent(INSTALLABLE_IID))); | 57 | service.registerCompiler(TestIntent.class, new TestCompiler(new TestInstallableIntent(INSTALLABLE_IID))); |
... | @@ -73,8 +73,7 @@ public class IntentServiceTest { | ... | @@ -73,8 +73,7 @@ public class IntentServiceTest { |
73 | validateEvents(intent, SUBMITTED, COMPILED, INSTALLED); | 73 | validateEvents(intent, SUBMITTED, COMPILED, INSTALLED); |
74 | 74 | ||
75 | // Make sure there is just one intent (and is ours) | 75 | // Make sure there is just one intent (and is ours) |
76 | - assertEquals("incorrect intent count", 1, service.getIntents().size()); | 76 | + assertEquals("incorrect intent count", 1, service.getIntentCount()); |
77 | - assertEquals("incorrect intent", intent, service.getIntent(intent.getId())); | ||
78 | 77 | ||
79 | // Reset the listener events | 78 | // Reset the listener events |
80 | listener.events.clear(); | 79 | listener.events.clear(); |
... | @@ -250,7 +249,7 @@ public class IntentServiceTest { | ... | @@ -250,7 +249,7 @@ public class IntentServiceTest { |
250 | 249 | ||
251 | 250 | ||
252 | // Fixture to track emitted intent events | 251 | // Fixture to track emitted intent events |
253 | - protected class TestListener implements IntentEventListener { | 252 | + protected class TestListener implements IntentListener { |
254 | final List<IntentEvent> events = new ArrayList<>(); | 253 | final List<IntentEvent> events = new ArrayList<>(); |
255 | 254 | ||
256 | @Override | 255 | @Override | ... | ... |
core/net/src/main/java/org/onlab/onos/net/intent/impl/AbstractBlockAllocatorBasedIdGenerator.java
0 → 100644
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import org.onlab.onos.net.intent.IdGenerator; | ||
4 | + | ||
5 | +/** | ||
6 | + * Base class of {@link IdGenerator} implementations which use {@link IdBlockAllocator} as | ||
7 | + * backend. | ||
8 | + * | ||
9 | + * @param <T> the type of ID | ||
10 | + */ | ||
11 | +public abstract class AbstractBlockAllocatorBasedIdGenerator<T> implements IdGenerator<T> { | ||
12 | + protected final IdBlockAllocator allocator; | ||
13 | + protected IdBlock idBlock; | ||
14 | + | ||
15 | + /** | ||
16 | + * Constructs an ID generator which use {@link IdBlockAllocator} as backend. | ||
17 | + * | ||
18 | + * @param allocator | ||
19 | + */ | ||
20 | + protected AbstractBlockAllocatorBasedIdGenerator(IdBlockAllocator allocator) { | ||
21 | + this.allocator = allocator; | ||
22 | + this.idBlock = allocator.allocateUniqueIdBlock(); | ||
23 | + } | ||
24 | + | ||
25 | + @Override | ||
26 | + public synchronized T getNewId() { | ||
27 | + try { | ||
28 | + return convertFrom(idBlock.getNextId()); | ||
29 | + } catch (UnavailableIdException e) { | ||
30 | + idBlock = allocator.allocateUniqueIdBlock(); | ||
31 | + return convertFrom(idBlock.getNextId()); | ||
32 | + } | ||
33 | + } | ||
34 | + | ||
35 | + /** | ||
36 | + * Returns an ID instance of {@code T} type from the long value. | ||
37 | + * | ||
38 | + * @param value original long value | ||
39 | + * @return ID instance | ||
40 | + */ | ||
41 | + protected abstract T convertFrom(long value); | ||
42 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +public class DummyIdBlockAllocator implements IdBlockAllocator { | ||
4 | + private long blockTop; | ||
5 | + private static final long BLOCK_SIZE = 0x1000000L; | ||
6 | + | ||
7 | + /** | ||
8 | + * Returns a block of IDs which are unique and unused. | ||
9 | + * Range of IDs is fixed size and is assigned incrementally as this method | ||
10 | + * called. | ||
11 | + * | ||
12 | + * @return an IdBlock containing a set of unique IDs | ||
13 | + */ | ||
14 | + @Override | ||
15 | + public IdBlock allocateUniqueIdBlock() { | ||
16 | + synchronized (this) { | ||
17 | + long blockHead = blockTop; | ||
18 | + long blockTail = blockTop + BLOCK_SIZE; | ||
19 | + | ||
20 | + IdBlock block = new IdBlock(blockHead, BLOCK_SIZE); | ||
21 | + blockTop = blockTail; | ||
22 | + | ||
23 | + return block; | ||
24 | + } | ||
25 | + } | ||
26 | + | ||
27 | + @Override | ||
28 | + public IdBlock allocateUniqueIdBlock(long range) { | ||
29 | + throw new UnsupportedOperationException("Not supported yet"); | ||
30 | + } | ||
31 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import java.util.Arrays; | ||
4 | +import java.util.List; | ||
5 | +import java.util.Set; | ||
6 | + | ||
7 | +import org.apache.felix.scr.annotations.Activate; | ||
8 | +import org.apache.felix.scr.annotations.Component; | ||
9 | +import org.apache.felix.scr.annotations.Deactivate; | ||
10 | +import org.apache.felix.scr.annotations.Reference; | ||
11 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
12 | +import org.onlab.onos.net.ConnectPoint; | ||
13 | +import org.onlab.onos.net.Path; | ||
14 | +import org.onlab.onos.net.PortNumber; | ||
15 | +import org.onlab.onos.net.intent.HostToHostIntent; | ||
16 | +import org.onlab.onos.net.intent.IdGenerator; | ||
17 | +import org.onlab.onos.net.intent.Intent; | ||
18 | +import org.onlab.onos.net.intent.IntentCompiler; | ||
19 | +import org.onlab.onos.net.intent.IntentExtensionService; | ||
20 | +import org.onlab.onos.net.intent.IntentId; | ||
21 | +import org.onlab.onos.net.intent.PathIntent; | ||
22 | +import org.onlab.onos.net.topology.PathService; | ||
23 | + | ||
24 | +/** | ||
25 | + * A intent compiler for {@link HostToHostIntent}. | ||
26 | + */ | ||
27 | +@Component(immediate = true) | ||
28 | +public class HostToHostIntentCompiler | ||
29 | + implements IntentCompiler<HostToHostIntent> { | ||
30 | + | ||
31 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
32 | + protected IntentExtensionService intentManager; | ||
33 | + | ||
34 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
35 | + protected PathService pathService; | ||
36 | + | ||
37 | + private IdGenerator<IntentId> intentIdGenerator; | ||
38 | + | ||
39 | + @Activate | ||
40 | + public void activate() { | ||
41 | + IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator(); | ||
42 | + intentIdGenerator = new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator); | ||
43 | + intentManager.registerCompiler(HostToHostIntent.class, this); | ||
44 | + } | ||
45 | + | ||
46 | + @Deactivate | ||
47 | + public void deactivate() { | ||
48 | + intentManager.unregisterCompiler(HostToHostIntent.class); | ||
49 | + } | ||
50 | + | ||
51 | + @Override | ||
52 | + public List<Intent> compile(HostToHostIntent intent) { | ||
53 | + Set<Path> paths = pathService.getPaths(intent.getSrc(), intent.getDst()); | ||
54 | + if (paths.isEmpty()) { | ||
55 | + throw new PathNotFoundException(); | ||
56 | + } | ||
57 | + Path path = paths.iterator().next(); | ||
58 | + | ||
59 | + return Arrays.asList((Intent) new PathIntent( | ||
60 | + intentIdGenerator.getNewId(), | ||
61 | + intent.getTrafficSelector(), | ||
62 | + intent.getTrafficTreatment(), | ||
63 | + new ConnectPoint(intent.getSrc(), PortNumber.ALL), | ||
64 | + new ConnectPoint(intent.getDst(), PortNumber.ALL), | ||
65 | + path)); | ||
66 | + } | ||
67 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkArgument; | ||
4 | + | ||
5 | +import java.util.Objects; | ||
6 | +import java.util.concurrent.atomic.AtomicLong; | ||
7 | + | ||
8 | +import com.google.common.base.MoreObjects; | ||
9 | + | ||
10 | +/** | ||
11 | + * A class representing an ID space. | ||
12 | + */ | ||
13 | +public final class IdBlock { | ||
14 | + private final long start; | ||
15 | + private final long size; | ||
16 | + | ||
17 | + private final AtomicLong currentId; | ||
18 | + | ||
19 | + /** | ||
20 | + * Constructs a new ID block with the specified size and initial value. | ||
21 | + * | ||
22 | + * @param start initial value of the block | ||
23 | + * @param size size of the block | ||
24 | + * @throws IllegalArgumentException if the size is less than or equal to 0 | ||
25 | + */ | ||
26 | + public IdBlock(long start, long size) { | ||
27 | + checkArgument(size > 0, "size should be more than 0, but %s", size); | ||
28 | + | ||
29 | + this.start = start; | ||
30 | + this.size = size; | ||
31 | + | ||
32 | + this.currentId = new AtomicLong(start); | ||
33 | + } | ||
34 | + | ||
35 | + // TODO: consider if this method is needed or not | ||
36 | + /** | ||
37 | + * Returns the initial value. | ||
38 | + * | ||
39 | + * @return initial value | ||
40 | + */ | ||
41 | + public long getStart() { | ||
42 | + return start; | ||
43 | + } | ||
44 | + | ||
45 | + // TODO: consider if this method is needed or not | ||
46 | + /** | ||
47 | + * Returns the last value. | ||
48 | + * | ||
49 | + * @return last value | ||
50 | + */ | ||
51 | + public long getEnd() { | ||
52 | + return start + size - 1; | ||
53 | + } | ||
54 | + | ||
55 | + /** | ||
56 | + * Returns the block size. | ||
57 | + * | ||
58 | + * @return block size | ||
59 | + */ | ||
60 | + public long getSize() { | ||
61 | + return size; | ||
62 | + } | ||
63 | + | ||
64 | + /** | ||
65 | + * Returns the next ID in the block. | ||
66 | + * | ||
67 | + * @return next ID | ||
68 | + * @throws UnavailableIdException if there is no available ID in the block. | ||
69 | + */ | ||
70 | + public long getNextId() { | ||
71 | + final long id = currentId.getAndIncrement(); | ||
72 | + if (id > getEnd()) { | ||
73 | + throw new UnavailableIdException(String.format( | ||
74 | + "used all IDs in allocated space (size: %d, end: %d, current: %d)", | ||
75 | + size, getEnd(), id | ||
76 | + )); | ||
77 | + } | ||
78 | + | ||
79 | + return id; | ||
80 | + } | ||
81 | + | ||
82 | + // TODO: Do we really need equals and hashCode? Should it contain currentId? | ||
83 | + @Override | ||
84 | + public boolean equals(Object o) { | ||
85 | + if (this == o) { | ||
86 | + return true; | ||
87 | + } | ||
88 | + if (o == null || getClass() != o.getClass()) { | ||
89 | + return false; | ||
90 | + } | ||
91 | + | ||
92 | + IdBlock that = (IdBlock) o; | ||
93 | + return Objects.equals(this.start, that.start) | ||
94 | + && Objects.equals(this.size, that.size) | ||
95 | + && Objects.equals(this.currentId.get(), that.currentId.get()); | ||
96 | + } | ||
97 | + | ||
98 | + @Override | ||
99 | + public int hashCode() { | ||
100 | + return Objects.hash(start, size, currentId); | ||
101 | + } | ||
102 | + | ||
103 | + @Override | ||
104 | + public String toString() { | ||
105 | + return MoreObjects.toStringHelper(getClass()) | ||
106 | + .add("start", start) | ||
107 | + .add("size", size) | ||
108 | + .add("currentId", currentId) | ||
109 | + .toString(); | ||
110 | + } | ||
111 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +/** | ||
4 | + * An interface that gives unique ID spaces. | ||
5 | + */ | ||
6 | +public interface IdBlockAllocator { | ||
7 | + /** | ||
8 | + * Allocates a unique Id Block. | ||
9 | + * | ||
10 | + * @return Id Block. | ||
11 | + */ | ||
12 | + IdBlock allocateUniqueIdBlock(); | ||
13 | + | ||
14 | + /** | ||
15 | + * Allocates next unique id and retrieve a new range of ids if needed. | ||
16 | + * | ||
17 | + * @param range range to use for the identifier | ||
18 | + * @return Id Block. | ||
19 | + */ | ||
20 | + IdBlock allocateUniqueIdBlock(long range); | ||
21 | +} |
core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocatorBasedIntentIdGenerator.java
0 → 100644
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import org.onlab.onos.net.intent.IntentId; | ||
4 | + | ||
5 | +/** | ||
6 | + * An implementation of {@link net.onrc.onos.core.util.IdGenerator} of intent ID, | ||
7 | + * which uses {@link IdBlockAllocator}. | ||
8 | + */ | ||
9 | +public class IdBlockAllocatorBasedIntentIdGenerator extends AbstractBlockAllocatorBasedIdGenerator<IntentId> { | ||
10 | + | ||
11 | + /** | ||
12 | + * Constructs an intent ID generator, which uses the specified ID block allocator | ||
13 | + * to generate a global unique intent ID. | ||
14 | + * | ||
15 | + * @param allocator the ID block allocator to use for generating intent IDs | ||
16 | + */ | ||
17 | + public IdBlockAllocatorBasedIntentIdGenerator(IdBlockAllocator allocator) { | ||
18 | + super(allocator); | ||
19 | + } | ||
20 | + | ||
21 | + @Override | ||
22 | + protected IntentId convertFrom(long value) { | ||
23 | + return new IntentId(value); | ||
24 | + } | ||
25 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import org.onlab.onos.net.intent.IntentException; | ||
4 | + | ||
5 | +/** | ||
6 | + * An exception thrown when a intent compilation fails. | ||
7 | + */ | ||
8 | +public class IntentCompilationException extends IntentException { | ||
9 | + private static final long serialVersionUID = 235237603018210810L; | ||
10 | + | ||
11 | + public IntentCompilationException() { | ||
12 | + super(); | ||
13 | + } | ||
14 | + | ||
15 | + public IntentCompilationException(String message) { | ||
16 | + super(message); | ||
17 | + } | ||
18 | + | ||
19 | + public IntentCompilationException(String message, Throwable cause) { | ||
20 | + super(message, cause); | ||
21 | + } | ||
22 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import org.onlab.onos.net.intent.IntentException; | ||
4 | + | ||
5 | +/** | ||
6 | + * An exception thrown when intent installation fails. | ||
7 | + */ | ||
8 | +public class IntentInstallationException extends IntentException { | ||
9 | + private static final long serialVersionUID = 3720268258616014168L; | ||
10 | + | ||
11 | + public IntentInstallationException() { | ||
12 | + super(); | ||
13 | + } | ||
14 | + | ||
15 | + public IntentInstallationException(String message) { | ||
16 | + super(message); | ||
17 | + } | ||
18 | + | ||
19 | + public IntentInstallationException(String message, Throwable cause) { | ||
20 | + super(message, cause); | ||
21 | + } | ||
22 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | +import static org.onlab.onos.net.intent.IntentState.FAILED; | ||
5 | +import static org.onlab.onos.net.intent.IntentState.INSTALLED; | ||
6 | +import static org.onlab.onos.net.intent.IntentState.WITHDRAWING; | ||
7 | +import static org.onlab.onos.net.intent.IntentState.WITHDRAWN; | ||
8 | +import static org.slf4j.LoggerFactory.getLogger; | ||
9 | + | ||
10 | +import java.util.ArrayList; | ||
11 | +import java.util.List; | ||
12 | +import java.util.Map; | ||
13 | +import java.util.concurrent.ConcurrentHashMap; | ||
14 | +import java.util.concurrent.ConcurrentMap; | ||
15 | +import java.util.concurrent.CopyOnWriteArrayList; | ||
16 | + | ||
17 | +import org.apache.felix.scr.annotations.Activate; | ||
18 | +import org.apache.felix.scr.annotations.Component; | ||
19 | +import org.apache.felix.scr.annotations.Deactivate; | ||
20 | +import org.apache.felix.scr.annotations.Reference; | ||
21 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
22 | +import org.apache.felix.scr.annotations.Service; | ||
23 | +import org.onlab.onos.event.AbstractListenerRegistry; | ||
24 | +import org.onlab.onos.event.EventDeliveryService; | ||
25 | +import org.onlab.onos.net.intent.InstallableIntent; | ||
26 | +import org.onlab.onos.net.intent.Intent; | ||
27 | +import org.onlab.onos.net.intent.IntentCompiler; | ||
28 | +import org.onlab.onos.net.intent.IntentEvent; | ||
29 | +import org.onlab.onos.net.intent.IntentException; | ||
30 | +import org.onlab.onos.net.intent.IntentExtensionService; | ||
31 | +import org.onlab.onos.net.intent.IntentId; | ||
32 | +import org.onlab.onos.net.intent.IntentInstaller; | ||
33 | +import org.onlab.onos.net.intent.IntentListener; | ||
34 | +import org.onlab.onos.net.intent.IntentOperations; | ||
35 | +import org.onlab.onos.net.intent.IntentService; | ||
36 | +import org.onlab.onos.net.intent.IntentState; | ||
37 | +import org.onlab.onos.net.intent.IntentStore; | ||
38 | +import org.onlab.onos.net.intent.IntentStoreDelegate; | ||
39 | +import org.slf4j.Logger; | ||
40 | + | ||
41 | +import com.google.common.collect.ImmutableMap; | ||
42 | + | ||
43 | +/** | ||
44 | + * An implementation of Intent Manager. | ||
45 | + */ | ||
46 | +@Component(immediate = true) | ||
47 | +@Service | ||
48 | +public class IntentManager | ||
49 | + implements IntentService, IntentExtensionService { | ||
50 | + private final Logger log = getLogger(getClass()); | ||
51 | + | ||
52 | + public static final String INTENT_NULL = "Intent cannot be null"; | ||
53 | + public static final String INTENT_ID_NULL = "Intent ID cannot be null"; | ||
54 | + | ||
55 | + // Collections for compiler, installer, and listener are ONOS instance local | ||
56 | + private final ConcurrentMap<Class<? extends Intent>, | ||
57 | + IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>(); | ||
58 | + private final ConcurrentMap<Class<? extends InstallableIntent>, | ||
59 | + IntentInstaller<? extends InstallableIntent>> installers = new ConcurrentHashMap<>(); | ||
60 | + private final CopyOnWriteArrayList<IntentListener> listeners = new CopyOnWriteArrayList<>(); | ||
61 | + | ||
62 | + private final AbstractListenerRegistry<IntentEvent, IntentListener> | ||
63 | + listenerRegistry = new AbstractListenerRegistry<>(); | ||
64 | + | ||
65 | + private final IntentStoreDelegate delegate = new InternalStoreDelegate(); | ||
66 | + | ||
67 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
68 | + protected IntentStore store; | ||
69 | + | ||
70 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
71 | + protected EventDeliveryService eventDispatcher; | ||
72 | + | ||
73 | + @Activate | ||
74 | + public void activate() { | ||
75 | + store.setDelegate(delegate); | ||
76 | + eventDispatcher.addSink(IntentEvent.class, listenerRegistry); | ||
77 | + | ||
78 | +// this.intentEvents = new IntentMap<>("intentState", IntentEvent.class, collectionsService); | ||
79 | +// this.installableIntents = | ||
80 | +// new IntentMap<>("installableIntents", IntentCompilationResult.class, collectionsService); | ||
81 | +// | ||
82 | +// | ||
83 | +// this.intentEvents.addListener(new InternalEntryListener(new InternalIntentEventListener())); | ||
84 | + | ||
85 | + log.info("Started"); | ||
86 | + } | ||
87 | + | ||
88 | + @Deactivate | ||
89 | + public void deactivate() { | ||
90 | + store.unsetDelegate(delegate); | ||
91 | + eventDispatcher.removeSink(IntentEvent.class); | ||
92 | + log.info("Stopped"); | ||
93 | + } | ||
94 | + | ||
95 | + @Override | ||
96 | + public void submit(Intent intent) { | ||
97 | + checkNotNull(intent, INTENT_NULL); | ||
98 | + registerSubclassCompilerIfNeeded(intent); | ||
99 | + IntentEvent event = store.createIntent(intent); | ||
100 | + eventDispatcher.post(event); | ||
101 | + processStoreEvent(event); | ||
102 | + } | ||
103 | + | ||
104 | + @Override | ||
105 | + public void withdraw(Intent intent) { | ||
106 | + checkNotNull(intent, INTENT_NULL); | ||
107 | + IntentEvent event = store.setState(intent, WITHDRAWING); | ||
108 | + eventDispatcher.post(event); | ||
109 | + processStoreEvent(event); | ||
110 | + } | ||
111 | + | ||
112 | + // FIXME: implement this method | ||
113 | + @Override | ||
114 | + public void execute(IntentOperations operations) { | ||
115 | + throw new UnsupportedOperationException("execute() is not implemented yet"); | ||
116 | + } | ||
117 | + | ||
118 | + @Override | ||
119 | + public Iterable<Intent> getIntents() { | ||
120 | + return store.getIntents(); | ||
121 | + } | ||
122 | + | ||
123 | + @Override | ||
124 | + public long getIntentCount() { | ||
125 | + return store.getIntentCount(); | ||
126 | + } | ||
127 | + | ||
128 | + @Override | ||
129 | + public Intent getIntent(IntentId id) { | ||
130 | + checkNotNull(id, INTENT_ID_NULL); | ||
131 | + return store.getIntent(id); | ||
132 | + } | ||
133 | + | ||
134 | + @Override | ||
135 | + public IntentState getIntentState(IntentId id) { | ||
136 | + checkNotNull(id, INTENT_ID_NULL); | ||
137 | + return store.getIntentState(id); | ||
138 | + } | ||
139 | + | ||
140 | + @Override | ||
141 | + public void addListener(IntentListener listener) { | ||
142 | + listenerRegistry.addListener(listener); | ||
143 | + } | ||
144 | + | ||
145 | + @Override | ||
146 | + public void removeListener(IntentListener listener) { | ||
147 | + listenerRegistry.removeListener(listener); | ||
148 | + } | ||
149 | + | ||
150 | + @Override | ||
151 | + public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) { | ||
152 | + compilers.put(cls, compiler); | ||
153 | + } | ||
154 | + | ||
155 | + @Override | ||
156 | + public <T extends Intent> void unregisterCompiler(Class<T> cls) { | ||
157 | + compilers.remove(cls); | ||
158 | + } | ||
159 | + | ||
160 | + @Override | ||
161 | + public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() { | ||
162 | + return ImmutableMap.copyOf(compilers); | ||
163 | + } | ||
164 | + | ||
165 | + @Override | ||
166 | + public <T extends InstallableIntent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) { | ||
167 | + installers.put(cls, installer); | ||
168 | + } | ||
169 | + | ||
170 | + @Override | ||
171 | + public <T extends InstallableIntent> void unregisterInstaller(Class<T> cls) { | ||
172 | + installers.remove(cls); | ||
173 | + } | ||
174 | + | ||
175 | + @Override | ||
176 | + public Map<Class<? extends InstallableIntent>, IntentInstaller<? extends InstallableIntent>> getInstallers() { | ||
177 | + return ImmutableMap.copyOf(installers); | ||
178 | + } | ||
179 | + | ||
180 | + /** | ||
181 | + * Invokes all of registered intent event listener. | ||
182 | + * | ||
183 | + * @param event event supplied to a listener as an argument | ||
184 | + */ | ||
185 | + private void invokeListeners(IntentEvent event) { | ||
186 | + for (IntentListener listener : listeners) { | ||
187 | + listener.event(event); | ||
188 | + } | ||
189 | + } | ||
190 | + | ||
191 | + /** | ||
192 | + * Returns the corresponding intent compiler to the specified intent. | ||
193 | + * | ||
194 | + * @param intent intent | ||
195 | + * @param <T> the type of intent | ||
196 | + * @return intent compiler corresponding to the specified intent | ||
197 | + */ | ||
198 | + private <T extends Intent> IntentCompiler<T> getCompiler(T intent) { | ||
199 | + @SuppressWarnings("unchecked") | ||
200 | + IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass()); | ||
201 | + if (compiler == null) { | ||
202 | + throw new IntentException("no compiler for class " + intent.getClass()); | ||
203 | + } | ||
204 | + return compiler; | ||
205 | + } | ||
206 | + | ||
207 | + /** | ||
208 | + * Returns the corresponding intent installer to the specified installable intent. | ||
209 | + * @param intent intent | ||
210 | + * @param <T> the type of installable intent | ||
211 | + * @return intent installer corresponding to the specified installable intent | ||
212 | + */ | ||
213 | + private <T extends InstallableIntent> IntentInstaller<T> getInstaller(T intent) { | ||
214 | + @SuppressWarnings("unchecked") | ||
215 | + IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass()); | ||
216 | + if (installer == null) { | ||
217 | + throw new IntentException("no installer for class " + intent.getClass()); | ||
218 | + } | ||
219 | + return installer; | ||
220 | + } | ||
221 | + | ||
222 | + /** | ||
223 | + * Compiles an intent. | ||
224 | + * | ||
225 | + * @param intent intent | ||
226 | + */ | ||
227 | + private void compileIntent(Intent intent) { | ||
228 | + // FIXME: To make SDN-IP workable ASAP, only single level compilation is implemented | ||
229 | + // TODO: implement compilation traversing tree structure | ||
230 | + List<InstallableIntent> installable = new ArrayList<>(); | ||
231 | + for (Intent compiled : getCompiler(intent).compile(intent)) { | ||
232 | + installable.add((InstallableIntent) compiled); | ||
233 | + } | ||
234 | + IntentEvent event = store.addInstallableIntents(intent.getId(), installable); | ||
235 | + eventDispatcher.post(event); | ||
236 | + processStoreEvent(event); | ||
237 | + } | ||
238 | + | ||
239 | + /** | ||
240 | + * Installs an intent. | ||
241 | + * | ||
242 | + * @param intent intent | ||
243 | + */ | ||
244 | + private void installIntent(Intent intent) { | ||
245 | + for (InstallableIntent installable : store.getInstallableIntents(intent.getId())) { | ||
246 | + registerSubclassInstallerIfNeeded(installable); | ||
247 | + getInstaller(installable).install(installable); | ||
248 | + } | ||
249 | + | ||
250 | + IntentEvent event = store.setState(intent, INSTALLED); | ||
251 | + eventDispatcher.post(event); | ||
252 | + processStoreEvent(event); | ||
253 | + | ||
254 | + } | ||
255 | + | ||
256 | + /** | ||
257 | + * Uninstalls an intent. | ||
258 | + * | ||
259 | + * @param intent intent | ||
260 | + */ | ||
261 | + private void uninstallIntent(Intent intent) { | ||
262 | + for (InstallableIntent installable : store.getInstallableIntents(intent.getId())) { | ||
263 | + getInstaller(installable).uninstall(installable); | ||
264 | + } | ||
265 | + | ||
266 | + store.removeInstalledIntents(intent.getId()); | ||
267 | + store.setState(intent, WITHDRAWN); | ||
268 | + } | ||
269 | + | ||
270 | + /** | ||
271 | + * Registers an intent compiler of the specified intent if an intent compiler | ||
272 | + * for the intent is not registered. This method traverses the class hierarchy of | ||
273 | + * the intent. Once an intent compiler for a parent type is found, this method | ||
274 | + * registers the found intent compiler. | ||
275 | + * | ||
276 | + * @param intent intent | ||
277 | + */ | ||
278 | + private void registerSubclassCompilerIfNeeded(Intent intent) { | ||
279 | + if (!compilers.containsKey(intent.getClass())) { | ||
280 | + Class<?> cls = intent.getClass(); | ||
281 | + while (cls != Object.class) { | ||
282 | + // As long as we're within the Intent class descendants | ||
283 | + if (Intent.class.isAssignableFrom(cls)) { | ||
284 | + IntentCompiler<?> compiler = compilers.get(cls); | ||
285 | + if (compiler != null) { | ||
286 | + compilers.put(intent.getClass(), compiler); | ||
287 | + return; | ||
288 | + } | ||
289 | + } | ||
290 | + cls = cls.getSuperclass(); | ||
291 | + } | ||
292 | + } | ||
293 | + } | ||
294 | + | ||
295 | + /** | ||
296 | + * Registers an intent installer of the specified intent if an intent installer | ||
297 | + * for the intent is not registered. This method traverses the class hierarchy of | ||
298 | + * the intent. Once an intent installer for a parent type is found, this method | ||
299 | + * registers the found intent installer. | ||
300 | + * | ||
301 | + * @param intent intent | ||
302 | + */ | ||
303 | + private void registerSubclassInstallerIfNeeded(InstallableIntent intent) { | ||
304 | + if (!installers.containsKey(intent.getClass())) { | ||
305 | + Class<?> cls = intent.getClass(); | ||
306 | + while (cls != Object.class) { | ||
307 | + // As long as we're within the InstallableIntent class descendants | ||
308 | + if (InstallableIntent.class.isAssignableFrom(cls)) { | ||
309 | + IntentInstaller<?> installer = installers.get(cls); | ||
310 | + if (installer != null) { | ||
311 | + installers.put(intent.getClass(), installer); | ||
312 | + return; | ||
313 | + } | ||
314 | + } | ||
315 | + cls = cls.getSuperclass(); | ||
316 | + } | ||
317 | + } | ||
318 | + } | ||
319 | + | ||
320 | + /** | ||
321 | + * Handles state transition of submitted intents. | ||
322 | + */ | ||
323 | + private void processStoreEvent(IntentEvent event) { | ||
324 | + invokeListeners(event); | ||
325 | + Intent intent = event.getIntent(); | ||
326 | + | ||
327 | + try { | ||
328 | + switch (event.getState()) { | ||
329 | + case SUBMITTED: | ||
330 | + compileIntent(intent); | ||
331 | + break; | ||
332 | + case COMPILED: | ||
333 | + installIntent(intent); | ||
334 | + break; | ||
335 | + case INSTALLED: | ||
336 | + break; | ||
337 | + case WITHDRAWING: | ||
338 | + uninstallIntent(intent); | ||
339 | + break; | ||
340 | + case WITHDRAWN: | ||
341 | + break; | ||
342 | + case FAILED: | ||
343 | + break; | ||
344 | + default: | ||
345 | + throw new IllegalStateException( | ||
346 | + "the state of IntentEvent is illegal: " + event.getState()); | ||
347 | + } | ||
348 | + } catch (IntentException e) { | ||
349 | + store.setState(intent, FAILED); | ||
350 | + } | ||
351 | + | ||
352 | + } | ||
353 | + | ||
354 | + // Store delegate to re-post events emitted from the store. | ||
355 | + private class InternalStoreDelegate implements IntentStoreDelegate { | ||
356 | + @Override | ||
357 | + public void notify(IntentEvent event) { | ||
358 | + processStoreEvent(event); | ||
359 | + eventDispatcher.post(event); | ||
360 | + } | ||
361 | + } | ||
362 | + | ||
363 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import org.onlab.onos.net.intent.IntentException; | ||
4 | + | ||
5 | +/** | ||
6 | + * An exception thrown when intent removal failed. | ||
7 | + */ | ||
8 | +public class IntentRemovalException extends IntentException { | ||
9 | + private static final long serialVersionUID = -5259226322037891951L; | ||
10 | + | ||
11 | + public IntentRemovalException() { | ||
12 | + super(); | ||
13 | + } | ||
14 | + | ||
15 | + public IntentRemovalException(String message) { | ||
16 | + super(message); | ||
17 | + } | ||
18 | + | ||
19 | + public IntentRemovalException(String message, Throwable cause) { | ||
20 | + super(message, cause); | ||
21 | + } | ||
22 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import java.util.Iterator; | ||
4 | + | ||
5 | +import org.apache.felix.scr.annotations.Activate; | ||
6 | +import org.apache.felix.scr.annotations.Component; | ||
7 | +import org.apache.felix.scr.annotations.Deactivate; | ||
8 | +import org.apache.felix.scr.annotations.Reference; | ||
9 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
10 | +import org.onlab.onos.ApplicationId; | ||
11 | +import org.onlab.onos.net.ConnectPoint; | ||
12 | +import org.onlab.onos.net.Link; | ||
13 | +import org.onlab.onos.net.flow.DefaultFlowRule; | ||
14 | +import org.onlab.onos.net.flow.DefaultTrafficSelector; | ||
15 | +import org.onlab.onos.net.flow.DefaultTrafficTreatment; | ||
16 | +import org.onlab.onos.net.flow.FlowRule; | ||
17 | +import org.onlab.onos.net.flow.FlowRuleService; | ||
18 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
19 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
20 | +import org.onlab.onos.net.flow.criteria.Criterion; | ||
21 | +import org.onlab.onos.net.intent.IntentExtensionService; | ||
22 | +import org.onlab.onos.net.intent.IntentInstaller; | ||
23 | +import org.onlab.onos.net.intent.PathIntent; | ||
24 | + | ||
25 | +/** | ||
26 | + * An intent installer for {@link PathIntent}. | ||
27 | + */ | ||
28 | +@Component(immediate = true) | ||
29 | +public class PathIntentInstaller | ||
30 | + implements IntentInstaller<PathIntent> { | ||
31 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
32 | + protected IntentExtensionService intentManager; | ||
33 | + | ||
34 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
35 | + private FlowRuleService flowRuleService; | ||
36 | + | ||
37 | + private final ApplicationId appId = ApplicationId.valueOf(1); | ||
38 | + | ||
39 | + @Activate | ||
40 | + public void activate() { | ||
41 | + intentManager.registerInstaller(PathIntent.class, this); | ||
42 | + } | ||
43 | + | ||
44 | + @Deactivate | ||
45 | + public void deactivate() { | ||
46 | + intentManager.unregisterInstaller(PathIntent.class); | ||
47 | + } | ||
48 | + | ||
49 | + @Override | ||
50 | + public void install(PathIntent intent) { | ||
51 | + TrafficSelector.Builder builder = new DefaultTrafficSelector.Builder(); | ||
52 | + TrafficSelector selector = intent.getTrafficSelector(); | ||
53 | + for (Criterion c : selector.criteria()) { | ||
54 | + builder.add(c); | ||
55 | + } | ||
56 | + | ||
57 | + Iterator<Link> links = intent.getPath().links().iterator(); | ||
58 | + ConnectPoint prev = links.next().dst(); | ||
59 | + while (links.hasNext()) { | ||
60 | + builder.matchInport(prev.port()); | ||
61 | + Link link = links.next(); | ||
62 | + | ||
63 | + TrafficTreatment.Builder treat = new DefaultTrafficTreatment.Builder(); | ||
64 | + treat.setOutput(link.src().port()); | ||
65 | + | ||
66 | + FlowRule f = new DefaultFlowRule(link.src().deviceId(), | ||
67 | + builder.build(), treat.build(), 0, appId); | ||
68 | + flowRuleService.applyFlowRules(f); | ||
69 | + | ||
70 | + prev = link.dst(); | ||
71 | + } | ||
72 | + | ||
73 | + } | ||
74 | + | ||
75 | + @Override | ||
76 | + public void uninstall(PathIntent intent) { | ||
77 | + //TODO | ||
78 | + } | ||
79 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import org.onlab.onos.net.intent.IntentException; | ||
4 | + | ||
5 | +/** | ||
6 | + * An exception thrown when a path is not found. | ||
7 | + */ | ||
8 | +public class PathNotFoundException extends IntentException { | ||
9 | + private static final long serialVersionUID = -2087045731049914733L; | ||
10 | + | ||
11 | + public PathNotFoundException() { | ||
12 | + super(); | ||
13 | + } | ||
14 | + | ||
15 | + public PathNotFoundException(String message) { | ||
16 | + super(message); | ||
17 | + } | ||
18 | + | ||
19 | + public PathNotFoundException(String message, Throwable cause) { | ||
20 | + super(message, cause); | ||
21 | + } | ||
22 | +} |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +/** | ||
4 | + * Represents that there is no available IDs. | ||
5 | + */ | ||
6 | +public class UnavailableIdException extends RuntimeException { | ||
7 | + | ||
8 | + private static final long serialVersionUID = -2287403908433720122L; | ||
9 | + | ||
10 | + /** | ||
11 | + * Constructs an exception with no message and no underlying cause. | ||
12 | + */ | ||
13 | + public UnavailableIdException() { | ||
14 | + } | ||
15 | + | ||
16 | + /** | ||
17 | + * Constructs an exception with the specified message. | ||
18 | + * | ||
19 | + * @param message the message describing the specific nature of the error | ||
20 | + */ | ||
21 | + public UnavailableIdException(String message) { | ||
22 | + super(message); | ||
23 | + } | ||
24 | + | ||
25 | + /** | ||
26 | + * Constructs an exception with the specified message and the underlying cause. | ||
27 | + * | ||
28 | + * @param message the message describing the specific nature of the error | ||
29 | + * @param cause the underlying cause of this error | ||
30 | + */ | ||
31 | + public UnavailableIdException(String message, Throwable cause) { | ||
32 | + super(message, cause); | ||
33 | + } | ||
34 | +} |
core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java
0 → 100644
1 | +package org.onlab.onos.store.trivial.impl; | ||
2 | + | ||
3 | +import static org.onlab.onos.net.intent.IntentState.COMPILED; | ||
4 | +import static org.slf4j.LoggerFactory.getLogger; | ||
5 | + | ||
6 | +import java.util.HashMap; | ||
7 | +import java.util.List; | ||
8 | +import java.util.Map; | ||
9 | + | ||
10 | +import org.apache.felix.scr.annotations.Activate; | ||
11 | +import org.apache.felix.scr.annotations.Component; | ||
12 | +import org.apache.felix.scr.annotations.Deactivate; | ||
13 | +import org.apache.felix.scr.annotations.Service; | ||
14 | +import org.onlab.onos.net.intent.InstallableIntent; | ||
15 | +import org.onlab.onos.net.intent.Intent; | ||
16 | +import org.onlab.onos.net.intent.IntentEvent; | ||
17 | +import org.onlab.onos.net.intent.IntentId; | ||
18 | +import org.onlab.onos.net.intent.IntentState; | ||
19 | +import org.onlab.onos.net.intent.IntentStore; | ||
20 | +import org.onlab.onos.net.intent.IntentStoreDelegate; | ||
21 | +import org.onlab.onos.store.AbstractStore; | ||
22 | +import org.slf4j.Logger; | ||
23 | + | ||
24 | +import com.google.common.collect.ImmutableSet; | ||
25 | + | ||
26 | +@Component(immediate = true) | ||
27 | +@Service | ||
28 | +public class SimpleIntentStore | ||
29 | + extends AbstractStore<IntentEvent, IntentStoreDelegate> | ||
30 | + implements IntentStore { | ||
31 | + | ||
32 | + private final Logger log = getLogger(getClass()); | ||
33 | + private final Map<IntentId, Intent> intents = new HashMap<>(); | ||
34 | + private final Map<IntentId, IntentState> states = new HashMap<>(); | ||
35 | + private final Map<IntentId, List<InstallableIntent>> installable = new HashMap<>(); | ||
36 | + | ||
37 | + @Activate | ||
38 | + public void activate() { | ||
39 | + log.info("Started"); | ||
40 | + } | ||
41 | + | ||
42 | + @Deactivate | ||
43 | + public void deactivate() { | ||
44 | + log.info("Stopped"); | ||
45 | + } | ||
46 | + | ||
47 | + @Override | ||
48 | + public IntentEvent createIntent(Intent intent) { | ||
49 | + intents.put(intent.getId(), intent); | ||
50 | + return this.setState(intent, IntentState.SUBMITTED); | ||
51 | + } | ||
52 | + | ||
53 | + @Override | ||
54 | + public IntentEvent removeIntent(IntentId intentId) { | ||
55 | + Intent intent = intents.remove(intentId); | ||
56 | + installable.remove(intentId); | ||
57 | + IntentEvent event = this.setState(intent, IntentState.WITHDRAWN); | ||
58 | + states.remove(intentId); | ||
59 | + return event; | ||
60 | + } | ||
61 | + | ||
62 | + @Override | ||
63 | + public long getIntentCount() { | ||
64 | + return intents.size(); | ||
65 | + } | ||
66 | + | ||
67 | + @Override | ||
68 | + public Iterable<Intent> getIntents() { | ||
69 | + return ImmutableSet.copyOf(intents.values()); | ||
70 | + } | ||
71 | + | ||
72 | + @Override | ||
73 | + public Intent getIntent(IntentId intentId) { | ||
74 | + return intents.get(intentId); | ||
75 | + } | ||
76 | + | ||
77 | + @Override | ||
78 | + public IntentState getIntentState(IntentId id) { | ||
79 | + return states.get(id); | ||
80 | + } | ||
81 | + | ||
82 | + // TODO return dispatch event here... replace with state transition methods | ||
83 | + @Override | ||
84 | + public IntentEvent setState(Intent intent, IntentState newState) { | ||
85 | + IntentId id = intent.getId(); | ||
86 | + IntentState oldState = states.get(id); | ||
87 | + states.put(id, newState); | ||
88 | + return new IntentEvent(intent, newState, oldState, System.currentTimeMillis()); | ||
89 | + } | ||
90 | + | ||
91 | + @Override | ||
92 | + public IntentEvent addInstallableIntents(IntentId intentId, List<InstallableIntent> result) { | ||
93 | + installable.put(intentId, result); | ||
94 | + return this.setState(intents.get(intentId), COMPILED); | ||
95 | + } | ||
96 | + | ||
97 | + @Override | ||
98 | + public List<InstallableIntent> getInstallableIntents(IntentId intentId) { | ||
99 | + return installable.get(intentId); | ||
100 | + } | ||
101 | + | ||
102 | + @Override | ||
103 | + public void removeInstalledIntents(IntentId intentId) { | ||
104 | + installable.remove(intentId); | ||
105 | + } | ||
106 | + | ||
107 | +} |
-
Please register or login to post a comment