Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Showing
96 changed files
with
3230 additions
and
739 deletions
... | @@ -184,13 +184,13 @@ public class ReactiveForwarding { | ... | @@ -184,13 +184,13 @@ public class ReactiveForwarding { |
184 | 184 | ||
185 | // Install the flow rule to handle this type of message from now on. | 185 | // Install the flow rule to handle this type of message from now on. |
186 | Ethernet inPkt = context.inPacket().parsed(); | 186 | Ethernet inPkt = context.inPacket().parsed(); |
187 | - TrafficSelector.Builder builder = new DefaultTrafficSelector.Builder(); | 187 | + TrafficSelector.Builder builder = DefaultTrafficSelector.builder(); |
188 | builder.matchEthType(inPkt.getEtherType()) | 188 | builder.matchEthType(inPkt.getEtherType()) |
189 | .matchEthSrc(inPkt.getSourceMAC()) | 189 | .matchEthSrc(inPkt.getSourceMAC()) |
190 | .matchEthDst(inPkt.getDestinationMAC()) | 190 | .matchEthDst(inPkt.getDestinationMAC()) |
191 | .matchInport(context.inPacket().receivedFrom().port()); | 191 | .matchInport(context.inPacket().receivedFrom().port()); |
192 | 192 | ||
193 | - TrafficTreatment.Builder treat = new DefaultTrafficTreatment.Builder(); | 193 | + TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(); |
194 | treat.setOutput(portNumber); | 194 | treat.setOutput(portNumber); |
195 | 195 | ||
196 | FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(), | 196 | FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(), | ... | ... |
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 = DefaultTrafficSelector.builder(); | ||
43 | + builder.matchEthSrc(hosts.getHost(srcId).mac()) | ||
44 | + .matchEthDst(hosts.getHost(dstId).mac()); | ||
45 | + | ||
46 | + TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(); | ||
47 | + | ||
48 | + HostToHostIntent intent = | ||
49 | + new HostToHostIntent(new IntentId(id++), srcId, dstId, | ||
50 | + builder.build(), treat.build()); | ||
51 | + | ||
52 | + log.info("Adding intent {}", intent); | ||
53 | + | ||
54 | + service.submit(intent); | ||
55 | + } | ||
56 | + | ||
57 | +} |
... | @@ -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> | ... | ... |
... | @@ -18,7 +18,7 @@ public class DefaultEdgeLink extends DefaultLink implements EdgeLink { | ... | @@ -18,7 +18,7 @@ public class DefaultEdgeLink extends DefaultLink implements EdgeLink { |
18 | * @param providerId provider identity | 18 | * @param providerId provider identity |
19 | * @param hostPoint host-side connection point | 19 | * @param hostPoint host-side connection point |
20 | * @param hostLocation location where host attaches to the network | 20 | * @param hostLocation location where host attaches to the network |
21 | - * @param isIngress true to indicated host-to-network direction; false | 21 | + * @param isIngress true to indicate host-to-network direction; false |
22 | * for network-to-host direction | 22 | * for network-to-host direction |
23 | * @param annotations optional key/value annotations | 23 | * @param annotations optional key/value annotations |
24 | */ | 24 | */ |
... | @@ -42,4 +42,20 @@ public class DefaultEdgeLink extends DefaultLink implements EdgeLink { | ... | @@ -42,4 +42,20 @@ public class DefaultEdgeLink extends DefaultLink implements EdgeLink { |
42 | public HostLocation hostLocation() { | 42 | public HostLocation hostLocation() { |
43 | return hostLocation; | 43 | return hostLocation; |
44 | } | 44 | } |
45 | + | ||
46 | + /** | ||
47 | + * Creates a phantom edge link, to an unspecified end-station. This link | ||
48 | + * does not represent any actually discovered link stored in the system. | ||
49 | + * | ||
50 | + * @param edgePort network edge port | ||
51 | + * @param isIngress true to indicate host-to-network direction; false | ||
52 | + * for network-to-host direction | ||
53 | + * @return new phantom edge link | ||
54 | + */ | ||
55 | + public static DefaultEdgeLink createEdgeLink(HostLocation edgePort, | ||
56 | + boolean isIngress) { | ||
57 | + return new DefaultEdgeLink(ProviderId.NONE, | ||
58 | + new ConnectPoint(HostId.NONE, PortNumber.P0), | ||
59 | + edgePort, isIngress); | ||
60 | + } | ||
45 | } | 61 | } | ... | ... |
... | @@ -10,6 +10,14 @@ import java.net.URI; | ... | @@ -10,6 +10,14 @@ import java.net.URI; |
10 | */ | 10 | */ |
11 | public final class HostId extends ElementId { | 11 | public final class HostId extends ElementId { |
12 | 12 | ||
13 | + private static final String NIC = "nic"; | ||
14 | + | ||
15 | + /** | ||
16 | + * Represents either no host, or an unspecified host; used for creating | ||
17 | + * open ingress/egress edge links. | ||
18 | + */ | ||
19 | + public static final HostId NONE = hostId(NIC + ":none-0"); | ||
20 | + | ||
13 | // Public construction is prohibited | 21 | // Public construction is prohibited |
14 | private HostId(URI uri) { | 22 | private HostId(URI uri) { |
15 | super(uri); | 23 | super(uri); |
... | @@ -43,8 +51,7 @@ public final class HostId extends ElementId { | ... | @@ -43,8 +51,7 @@ public final class HostId extends ElementId { |
43 | * @return host identifier | 51 | * @return host identifier |
44 | */ | 52 | */ |
45 | public static HostId hostId(MacAddress mac, VlanId vlanId) { | 53 | public static HostId hostId(MacAddress mac, VlanId vlanId) { |
46 | - // FIXME: use more efficient means of encoding | 54 | + return hostId(NIC + ":" + mac + "-" + vlanId); |
47 | - return hostId("nic" + ":" + mac + "-" + vlanId); | ||
48 | } | 55 | } |
49 | 56 | ||
50 | /** | 57 | /** | ... | ... |
... | @@ -9,6 +9,8 @@ import com.google.common.primitives.UnsignedLongs; | ... | @@ -9,6 +9,8 @@ import com.google.common.primitives.UnsignedLongs; |
9 | */ | 9 | */ |
10 | public final class PortNumber { | 10 | public final class PortNumber { |
11 | 11 | ||
12 | + public static final PortNumber P0 = portNumber(0); | ||
13 | + | ||
12 | // TODO: revisit the max and the logical port value assignments | 14 | // TODO: revisit the max and the logical port value assignments |
13 | 15 | ||
14 | private static final long MAX_NUMBER = (2L * Integer.MAX_VALUE) + 1; | 16 | private static final long MAX_NUMBER = (2L * Integer.MAX_VALUE) + 1; | ... | ... |
1 | package org.onlab.onos.net.flow; | 1 | package org.onlab.onos.net.flow; |
2 | 2 | ||
3 | -import static org.slf4j.LoggerFactory.getLogger; | 3 | +import com.google.common.collect.ImmutableSet; |
4 | - | ||
5 | -import java.util.Collections; | ||
6 | -import java.util.HashSet; | ||
7 | -import java.util.Objects; | ||
8 | -import java.util.Set; | ||
9 | - | ||
10 | import org.onlab.onos.net.PortNumber; | 4 | import org.onlab.onos.net.PortNumber; |
11 | import org.onlab.onos.net.flow.criteria.Criteria; | 5 | import org.onlab.onos.net.flow.criteria.Criteria; |
12 | import org.onlab.onos.net.flow.criteria.Criterion; | 6 | import org.onlab.onos.net.flow.criteria.Criterion; |
13 | import org.onlab.packet.IpPrefix; | 7 | import org.onlab.packet.IpPrefix; |
14 | import org.onlab.packet.MacAddress; | 8 | import org.onlab.packet.MacAddress; |
15 | import org.onlab.packet.VlanId; | 9 | import org.onlab.packet.VlanId; |
16 | -import org.slf4j.Logger; | ||
17 | 10 | ||
11 | +import java.util.Collections; | ||
12 | +import java.util.HashMap; | ||
13 | +import java.util.Map; | ||
14 | +import java.util.Objects; | ||
15 | +import java.util.Set; | ||
16 | + | ||
17 | +/** | ||
18 | + * Default traffic selector implementation. | ||
19 | + */ | ||
18 | public final class DefaultTrafficSelector implements TrafficSelector { | 20 | public final class DefaultTrafficSelector implements TrafficSelector { |
19 | 21 | ||
20 | - private final Set<Criterion> selector; | 22 | + private final Set<Criterion> criteria; |
21 | 23 | ||
22 | - private DefaultTrafficSelector(Set<Criterion> selector) { | 24 | + /** |
23 | - this.selector = Collections.unmodifiableSet(selector); | 25 | + * Creates a new traffic selector with the specified criteria. |
26 | + * | ||
27 | + * @param criteria criteria | ||
28 | + */ | ||
29 | + private DefaultTrafficSelector(Set<Criterion> criteria) { | ||
30 | + this.criteria = Collections.unmodifiableSet(criteria); | ||
24 | } | 31 | } |
25 | 32 | ||
26 | @Override | 33 | @Override |
27 | public Set<Criterion> criteria() { | 34 | public Set<Criterion> criteria() { |
28 | - return selector; | 35 | + return criteria; |
29 | } | 36 | } |
30 | 37 | ||
31 | @Override | 38 | @Override |
32 | public int hashCode() { | 39 | public int hashCode() { |
33 | - return Objects.hash(selector); | 40 | + return Objects.hash(criteria); |
34 | } | 41 | } |
35 | 42 | ||
36 | @Override | 43 | @Override |
... | @@ -40,23 +47,50 @@ public final class DefaultTrafficSelector implements TrafficSelector { | ... | @@ -40,23 +47,50 @@ public final class DefaultTrafficSelector implements TrafficSelector { |
40 | } | 47 | } |
41 | if (obj instanceof DefaultTrafficSelector) { | 48 | if (obj instanceof DefaultTrafficSelector) { |
42 | DefaultTrafficSelector that = (DefaultTrafficSelector) obj; | 49 | DefaultTrafficSelector that = (DefaultTrafficSelector) obj; |
43 | - return Objects.equals(selector, that.selector); | 50 | + return Objects.equals(criteria, that.criteria); |
44 | 51 | ||
45 | } | 52 | } |
46 | return false; | 53 | return false; |
47 | } | 54 | } |
48 | 55 | ||
56 | + /** | ||
57 | + * Returns a new traffic selector builder. | ||
58 | + * | ||
59 | + * @return traffic selector builder | ||
60 | + */ | ||
61 | + public static TrafficSelector.Builder builder() { | ||
62 | + return new Builder(); | ||
63 | + } | ||
49 | 64 | ||
65 | + /** | ||
66 | + * Returns a new traffic selector builder primed to produce entities | ||
67 | + * patterned after the supplied selector. | ||
68 | + * | ||
69 | + * @return traffic selector builder | ||
70 | + */ | ||
71 | + public static TrafficSelector.Builder builder(TrafficSelector selector) { | ||
72 | + return new Builder(selector); | ||
73 | + } | ||
50 | 74 | ||
51 | - public static class Builder implements TrafficSelector.Builder { | 75 | + /** |
76 | + * Builder of traffic selector entities. | ||
77 | + */ | ||
78 | + public static final class Builder implements TrafficSelector.Builder { | ||
52 | 79 | ||
53 | - private final Logger log = getLogger(getClass()); | 80 | + private final Map<Criterion.Type, Criterion> selector = new HashMap<>(); |
54 | 81 | ||
55 | - private final Set<Criterion> selector = new HashSet<>(); | 82 | + private Builder() { |
83 | + } | ||
84 | + | ||
85 | + private Builder(TrafficSelector selector) { | ||
86 | + for (Criterion c : selector.criteria()) { | ||
87 | + add(c); | ||
88 | + } | ||
89 | + } | ||
56 | 90 | ||
57 | @Override | 91 | @Override |
58 | public Builder add(Criterion criterion) { | 92 | public Builder add(Criterion criterion) { |
59 | - selector.add(criterion); | 93 | + selector.put(criterion.type(), criterion); |
60 | return this; | 94 | return this; |
61 | } | 95 | } |
62 | 96 | ||
... | @@ -107,7 +141,7 @@ public final class DefaultTrafficSelector implements TrafficSelector { | ... | @@ -107,7 +141,7 @@ public final class DefaultTrafficSelector implements TrafficSelector { |
107 | 141 | ||
108 | @Override | 142 | @Override |
109 | public TrafficSelector build() { | 143 | public TrafficSelector build() { |
110 | - return new DefaultTrafficSelector(selector); | 144 | + return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values())); |
111 | } | 145 | } |
112 | 146 | ||
113 | } | 147 | } | ... | ... |
1 | package org.onlab.onos.net.flow; | 1 | package org.onlab.onos.net.flow; |
2 | 2 | ||
3 | -import static org.slf4j.LoggerFactory.getLogger; | ||
4 | - | ||
5 | -import java.util.Collections; | ||
6 | -import java.util.LinkedList; | ||
7 | -import java.util.List; | ||
8 | - | ||
9 | import org.onlab.onos.net.PortNumber; | 3 | import org.onlab.onos.net.PortNumber; |
10 | import org.onlab.onos.net.flow.instructions.Instruction; | 4 | import org.onlab.onos.net.flow.instructions.Instruction; |
11 | import org.onlab.onos.net.flow.instructions.Instructions; | 5 | import org.onlab.onos.net.flow.instructions.Instructions; |
... | @@ -14,10 +8,24 @@ import org.onlab.packet.MacAddress; | ... | @@ -14,10 +8,24 @@ import org.onlab.packet.MacAddress; |
14 | import org.onlab.packet.VlanId; | 8 | import org.onlab.packet.VlanId; |
15 | import org.slf4j.Logger; | 9 | import org.slf4j.Logger; |
16 | 10 | ||
11 | +import java.util.Collections; | ||
12 | +import java.util.LinkedList; | ||
13 | +import java.util.List; | ||
14 | + | ||
15 | +import static org.slf4j.LoggerFactory.getLogger; | ||
16 | + | ||
17 | +/** | ||
18 | + * Default traffic treatment implementation. | ||
19 | + */ | ||
17 | public final class DefaultTrafficTreatment implements TrafficTreatment { | 20 | public final class DefaultTrafficTreatment implements TrafficTreatment { |
18 | 21 | ||
19 | private final List<Instruction> instructions; | 22 | private final List<Instruction> instructions; |
20 | 23 | ||
24 | + /** | ||
25 | + * Creates a new traffic treatment from the specified list of instructions. | ||
26 | + * | ||
27 | + * @param instructions treatment instructions | ||
28 | + */ | ||
21 | private DefaultTrafficTreatment(List<Instruction> instructions) { | 29 | private DefaultTrafficTreatment(List<Instruction> instructions) { |
22 | this.instructions = Collections.unmodifiableList(instructions); | 30 | this.instructions = Collections.unmodifiableList(instructions); |
23 | } | 31 | } |
... | @@ -28,12 +36,19 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { | ... | @@ -28,12 +36,19 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { |
28 | } | 36 | } |
29 | 37 | ||
30 | /** | 38 | /** |
31 | - * Builds a list of treatments following the following order. | 39 | + * Returns a new traffic treatment builder. |
32 | - * Modifications -> Group -> Output (including drop) | ||
33 | * | 40 | * |
41 | + * @return traffic treatment builder | ||
34 | */ | 42 | */ |
43 | + public static TrafficTreatment.Builder builder() { | ||
44 | + return new Builder(); | ||
45 | + } | ||
35 | 46 | ||
36 | - public static class Builder implements TrafficTreatment.Builder { | 47 | + /** |
48 | + * Builds a list of treatments following the following order. | ||
49 | + * Modifications -> Group -> Output (including drop) | ||
50 | + */ | ||
51 | + public static final class Builder implements TrafficTreatment.Builder { | ||
37 | 52 | ||
38 | private final Logger log = getLogger(getClass()); | 53 | private final Logger log = getLogger(getClass()); |
39 | 54 | ||
... | @@ -47,6 +62,10 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { | ... | @@ -47,6 +62,10 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { |
47 | // TODO: should be a list of instructions based on modification objects | 62 | // TODO: should be a list of instructions based on modification objects |
48 | List<Instruction> modifications = new LinkedList<>(); | 63 | List<Instruction> modifications = new LinkedList<>(); |
49 | 64 | ||
65 | + // Creates a new builder | ||
66 | + private Builder() { | ||
67 | + } | ||
68 | + | ||
50 | public Builder add(Instruction instruction) { | 69 | public Builder add(Instruction instruction) { |
51 | if (drop) { | 70 | if (drop) { |
52 | return this; | 71 | return this; | ... | ... |
1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
2 | //TODO is this the right package? | 2 | //TODO is this the right package? |
3 | 3 | ||
4 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
5 | - | ||
6 | import java.util.Collections; | 4 | import java.util.Collections; |
7 | import java.util.LinkedList; | 5 | import java.util.LinkedList; |
8 | import java.util.List; | 6 | import java.util.List; |
9 | 7 | ||
8 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
9 | + | ||
10 | /** | 10 | /** |
11 | * A list of BatchOperationEntry. | 11 | * A list of BatchOperationEntry. |
12 | * | 12 | * |
13 | * @param <T> the enum of operators <br> | 13 | * @param <T> the enum of operators <br> |
14 | * This enum must be defined in each sub-classes. | 14 | * This enum must be defined in each sub-classes. |
15 | - * | ||
16 | */ | 15 | */ |
17 | public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> { | 16 | public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> { |
17 | + | ||
18 | private List<T> ops; | 18 | private List<T> ops; |
19 | 19 | ||
20 | /** | 20 | /** | ... | ... |
1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | -import static com.google.common.base.Preconditions.checkNotNull; | 3 | +import com.google.common.base.Objects; |
4 | - | ||
5 | import org.onlab.onos.net.flow.TrafficSelector; | 4 | import org.onlab.onos.net.flow.TrafficSelector; |
6 | import org.onlab.onos.net.flow.TrafficTreatment; | 5 | import org.onlab.onos.net.flow.TrafficTreatment; |
7 | 6 | ||
8 | -import com.google.common.base.Objects; | 7 | +import static com.google.common.base.Preconditions.checkNotNull; |
9 | 8 | ||
10 | /** | 9 | /** |
11 | * Abstraction of connectivity intent for traffic matching some criteria. | 10 | * Abstraction of connectivity intent for traffic matching some criteria. |
... | @@ -26,17 +25,18 @@ public abstract class ConnectivityIntent extends AbstractIntent { | ... | @@ -26,17 +25,18 @@ public abstract class ConnectivityIntent extends AbstractIntent { |
26 | 25 | ||
27 | /** | 26 | /** |
28 | * Creates a connectivity intent that matches on the specified intent | 27 | * Creates a connectivity intent that matches on the specified intent |
29 | - * and applies the specified action. | 28 | + * and applies the specified treatement. |
30 | * | 29 | * |
31 | - * @param id intent identifier | 30 | + * @param intentId intent identifier |
32 | - * @param match traffic match | 31 | + * @param selector traffic selector |
33 | - * @param action action | 32 | + * @param treatement treatement |
34 | - * @throws NullPointerException if the match or action is null | 33 | + * @throws NullPointerException if the selector or treatement is null |
35 | */ | 34 | */ |
36 | - protected ConnectivityIntent(IntentId id, TrafficSelector match, TrafficTreatment action) { | 35 | + protected ConnectivityIntent(IntentId intentId, TrafficSelector selector, |
37 | - super(id); | 36 | + TrafficTreatment treatement) { |
38 | - this.selector = checkNotNull(match); | 37 | + super(intentId); |
39 | - this.treatment = checkNotNull(action); | 38 | + this.selector = checkNotNull(selector); |
39 | + this.treatment = checkNotNull(treatement); | ||
40 | } | 40 | } |
41 | 41 | ||
42 | /** | 42 | /** | ... | ... |
1 | +package org.onlab.onos.net.intent; | ||
2 | + | ||
3 | +import com.google.common.base.MoreObjects; | ||
4 | +import org.onlab.onos.net.HostId; | ||
5 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
6 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
7 | + | ||
8 | +import java.util.Objects; | ||
9 | + | ||
10 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
11 | + | ||
12 | +/** | ||
13 | + * Abstraction of end-station to end-station connectivity. | ||
14 | + */ | ||
15 | +public class HostToHostIntent extends ConnectivityIntent { | ||
16 | + | ||
17 | + private final HostId src; | ||
18 | + private final HostId dst; | ||
19 | + | ||
20 | + /** | ||
21 | + * Creates a new point-to-point intent with the supplied ingress/egress | ||
22 | + * ports. | ||
23 | + * | ||
24 | + * @param intentId intent identifier | ||
25 | + * @param selector action | ||
26 | + * @param treatment ingress port | ||
27 | + * @throws NullPointerException if {@code ingressPort} or {@code egressPort} | ||
28 | + * is null. | ||
29 | + */ | ||
30 | + public HostToHostIntent(IntentId intentId, HostId src, HostId dst, | ||
31 | + TrafficSelector selector, TrafficTreatment treatment) { | ||
32 | + super(intentId, selector, treatment); | ||
33 | + this.src = checkNotNull(src); | ||
34 | + this.dst = checkNotNull(dst); | ||
35 | + } | ||
36 | + | ||
37 | + /** | ||
38 | + * Returns the port on which the ingress traffic should be connected to the | ||
39 | + * egress. | ||
40 | + * | ||
41 | + * @return ingress port | ||
42 | + */ | ||
43 | + public HostId getSrc() { | ||
44 | + return src; | ||
45 | + } | ||
46 | + | ||
47 | + /** | ||
48 | + * Returns the port on which the traffic should egress. | ||
49 | + * | ||
50 | + * @return egress port | ||
51 | + */ | ||
52 | + public HostId getDst() { | ||
53 | + return dst; | ||
54 | + } | ||
55 | + | ||
56 | + @Override | ||
57 | + public boolean equals(Object o) { | ||
58 | + if (this == o) { | ||
59 | + return true; | ||
60 | + } | ||
61 | + if (o == null || getClass() != o.getClass()) { | ||
62 | + return false; | ||
63 | + } | ||
64 | + if (!super.equals(o)) { | ||
65 | + return false; | ||
66 | + } | ||
67 | + | ||
68 | + HostToHostIntent that = (HostToHostIntent) o; | ||
69 | + return Objects.equals(this.src, that.src) | ||
70 | + && Objects.equals(this.dst, that.dst); | ||
71 | + } | ||
72 | + | ||
73 | + @Override | ||
74 | + public int hashCode() { | ||
75 | + return Objects.hash(super.hashCode(), src, dst); | ||
76 | + } | ||
77 | + | ||
78 | + @Override | ||
79 | + public String toString() { | ||
80 | + return MoreObjects.toStringHelper(getClass()) | ||
81 | + .add("id", getId()) | ||
82 | + .add("selector", getTrafficSelector()) | ||
83 | + .add("treatmetn", getTrafficTreatment()) | ||
84 | + .add("src", src) | ||
85 | + .add("dst", dst) | ||
86 | + .toString(); | ||
87 | + } | ||
88 | + | ||
89 | +} |
... | @@ -2,7 +2,7 @@ package org.onlab.onos.net.intent; | ... | @@ -2,7 +2,7 @@ package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | /** | 3 | /** |
4 | * Abstraction of an application level intent. | 4 | * Abstraction of an application level intent. |
5 | - * | 5 | + * <p/> |
6 | * Make sure that an Intent should be immutable when a new type is defined. | 6 | * Make sure that an Intent should be immutable when a new type is defined. |
7 | */ | 7 | */ |
8 | public interface Intent extends BatchOperationTarget { | 8 | public interface Intent extends BatchOperationTarget { | ... | ... |
1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | -import static com.google.common.base.Preconditions.checkNotNull; | 3 | +import com.google.common.base.MoreObjects; |
4 | +import org.onlab.onos.event.AbstractEvent; | ||
4 | 5 | ||
5 | import java.util.Objects; | 6 | import java.util.Objects; |
6 | 7 | ||
7 | -import com.google.common.base.MoreObjects; | 8 | +import static com.google.common.base.Preconditions.checkNotNull; |
8 | 9 | ||
9 | /** | 10 | /** |
10 | * A class to represent an intent related event. | 11 | * A class to represent an intent related event. |
11 | */ | 12 | */ |
12 | -public class IntentEvent { | 13 | +public class IntentEvent extends AbstractEvent<IntentState, Intent> { |
13 | 14 | ||
14 | - // TODO: determine a suitable parent class; if one does not exist, consider introducing one | 15 | + // TODO: determine a suitable parent class; if one does not exist, consider |
16 | + // introducing one | ||
15 | 17 | ||
16 | private final long time; | 18 | private final long time; |
17 | private final Intent intent; | 19 | private final Intent intent; |
... | @@ -28,6 +30,7 @@ public class IntentEvent { | ... | @@ -28,6 +30,7 @@ public class IntentEvent { |
28 | * @throws NullPointerException if the intent or state is null | 30 | * @throws NullPointerException if the intent or state is null |
29 | */ | 31 | */ |
30 | public IntentEvent(Intent intent, IntentState state, IntentState previous, long time) { | 32 | public IntentEvent(Intent intent, IntentState state, IntentState previous, long time) { |
33 | + super(state, intent); | ||
31 | this.intent = checkNotNull(intent); | 34 | this.intent = checkNotNull(intent); |
32 | this.state = checkNotNull(state); | 35 | this.state = checkNotNull(state); |
33 | this.previous = previous; | 36 | this.previous = previous; |
... | @@ -35,16 +38,6 @@ public class IntentEvent { | ... | @@ -35,16 +38,6 @@ public class IntentEvent { |
35 | } | 38 | } |
36 | 39 | ||
37 | /** | 40 | /** |
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. | 41 | * Returns the state of the intent which caused the event. |
49 | * | 42 | * |
50 | * @return the state of the intent | 43 | * @return the state of the intent | ... | ... |
... | @@ -2,7 +2,7 @@ package org.onlab.onos.net.intent; | ... | @@ -2,7 +2,7 @@ package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | /** | 3 | /** |
4 | * Intent identifier suitable as an external key. | 4 | * Intent identifier suitable as an external key. |
5 | - * | 5 | + * <p/> |
6 | * This class is immutable. | 6 | * This class is immutable. |
7 | */ | 7 | */ |
8 | public final class IntentId implements BatchOperationTarget { | 8 | public final class IntentId implements BatchOperationTarget { | ... | ... |
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. |
... | @@ -8,9 +7,9 @@ import java.util.Set; | ... | @@ -8,9 +7,9 @@ import java.util.Set; |
8 | public interface IntentService { | 7 | public interface IntentService { |
9 | /** | 8 | /** |
10 | * Submits an intent into the system. | 9 | * Submits an intent into the system. |
11 | - * | 10 | + * <p/> |
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 | */ |
... | @@ -18,9 +17,9 @@ public interface IntentService { | ... | @@ -18,9 +17,9 @@ public interface IntentService { |
18 | 17 | ||
19 | /** | 18 | /** |
20 | * Withdraws an intent from the system. | 19 | * Withdraws an intent from the system. |
21 | - * | 20 | + * <p/> |
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 | */ |
... | @@ -29,20 +28,27 @@ public interface IntentService { | ... | @@ -29,20 +28,27 @@ public interface IntentService { |
29 | /** | 28 | /** |
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 | + * <p/> |
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 org.onlab.onos.store.Store; | ||
4 | + | ||
5 | +import java.util.List; | ||
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 removed state transition event or null if intent was not found | ||
25 | + */ | ||
26 | + IntentEvent removeIntent(IntentId intentId); | ||
27 | + | ||
28 | + /** | ||
29 | + * Returns the number of intents in the store. | ||
30 | + */ | ||
31 | + long getIntentCount(); | ||
32 | + | ||
33 | + /** | ||
34 | + * Returns a collection of all intents in the store. | ||
35 | + * | ||
36 | + * @return iterable collection of all intents | ||
37 | + */ | ||
38 | + Iterable<Intent> getIntents(); | ||
39 | + | ||
40 | + /** | ||
41 | + * Returns the intent with the specified identifer. | ||
42 | + * | ||
43 | + * @param intentId intent identification | ||
44 | + * @return intent or null if not found | ||
45 | + */ | ||
46 | + Intent getIntent(IntentId intentId); | ||
47 | + | ||
48 | + /** | ||
49 | + * Returns the state of the specified intent. | ||
50 | + * | ||
51 | + * @param intentId intent identification | ||
52 | + * @return current intent state | ||
53 | + */ | ||
54 | + IntentState getIntentState(IntentId intentId); | ||
55 | + | ||
56 | + /** | ||
57 | + * Sets the state of the specified intent to the new state. | ||
58 | + * | ||
59 | + * @param intent intent whose state is to be changed | ||
60 | + * @param newState new state | ||
61 | + * @return state transition event | ||
62 | + */ | ||
63 | + IntentEvent setState(Intent intent, IntentState newState); | ||
64 | + | ||
65 | + /** | ||
66 | + * Adds the installable intents which resulted from compilation of the | ||
67 | + * specified original intent. | ||
68 | + * | ||
69 | + * @param intentId original intent identifier | ||
70 | + * @param installableIntents compiled installable intents | ||
71 | + * @return compiled state transition event | ||
72 | + */ | ||
73 | + IntentEvent addInstallableIntents(IntentId intentId, | ||
74 | + List<InstallableIntent> installableIntents); | ||
75 | + | ||
76 | + /** | ||
77 | + * Returns the list of the installable events associated with the specified | ||
78 | + * original intent. | ||
79 | + * | ||
80 | + * @param intentId original intent identifier | ||
81 | + * @return compiled installable intents | ||
82 | + */ | ||
83 | + List<InstallableIntent> getInstallableIntents(IntentId intentId); | ||
84 | + | ||
85 | + // TODO: this should be triggered from with the store as a result of removeIntent call | ||
86 | + | ||
87 | + /** | ||
88 | + * Removes any installable intents which resulted from compilation of the | ||
89 | + * specified original intent. | ||
90 | + * | ||
91 | + * @param intentId original intent identifier | ||
92 | + * @return compiled state transition event | ||
93 | + */ | ||
94 | + void removeInstalledIntents(IntentId intentId); | ||
95 | + | ||
96 | +} |
... | @@ -35,8 +35,10 @@ public class MultiPointToSinglePointIntent extends ConnectivityIntent { | ... | @@ -35,8 +35,10 @@ public class MultiPointToSinglePointIntent extends ConnectivityIntent { |
35 | * @throws IllegalArgumentException if the size of {@code ingressPorts} is | 35 | * @throws IllegalArgumentException if the size of {@code ingressPorts} is |
36 | * not more than 1 | 36 | * not more than 1 |
37 | */ | 37 | */ |
38 | - public MultiPointToSinglePointIntent(IntentId id, TrafficSelector match, TrafficTreatment action, | 38 | + public MultiPointToSinglePointIntent(IntentId id, TrafficSelector match, |
39 | - Set<ConnectPoint> ingressPorts, ConnectPoint egressPort) { | 39 | + TrafficTreatment action, |
40 | + Set<ConnectPoint> ingressPorts, | ||
41 | + ConnectPoint egressPort) { | ||
40 | super(id, match, action); | 42 | super(id, match, action); |
41 | 43 | ||
42 | checkNotNull(ingressPorts); | 44 | checkNotNull(ingressPorts); | ... | ... |
... | @@ -3,30 +3,30 @@ package org.onlab.onos.net.intent; | ... | @@ -3,30 +3,30 @@ package org.onlab.onos.net.intent; |
3 | import org.onlab.onos.net.ConnectPoint; | 3 | import org.onlab.onos.net.ConnectPoint; |
4 | 4 | ||
5 | // TODO: consider if this intent should be sub-class of ConnectivityIntent | 5 | // TODO: consider if this intent should be sub-class of ConnectivityIntent |
6 | + | ||
6 | /** | 7 | /** |
7 | * An optical layer Intent for a connectivity from a transponder port to another | 8 | * An optical layer Intent for a connectivity from a transponder port to another |
8 | * transponder port. | 9 | * transponder port. |
9 | - * <p> | 10 | + * <p/> |
10 | * This class doesn't accepts lambda specifier. This class computes path between | 11 | * This class doesn't accepts lambda specifier. This class computes path between |
11 | * ports and assign lambda automatically. The lambda can be specified using | 12 | * ports and assign lambda automatically. The lambda can be specified using |
12 | * OpticalPathFlow class. | 13 | * OpticalPathFlow class. |
13 | */ | 14 | */ |
14 | public class OpticalConnectivityIntent extends AbstractIntent { | 15 | public class OpticalConnectivityIntent extends AbstractIntent { |
15 | - protected ConnectPoint srcConnectPoint; | 16 | + protected ConnectPoint src; |
16 | - protected ConnectPoint dstConnectPoint; | 17 | + protected ConnectPoint dst; |
17 | 18 | ||
18 | /** | 19 | /** |
19 | * Constructor. | 20 | * Constructor. |
20 | * | 21 | * |
21 | * @param id ID for this new Intent object. | 22 | * @param id ID for this new Intent object. |
22 | - * @param srcConnectPoint The source transponder port. | 23 | + * @param src The source transponder port. |
23 | - * @param dstConnectPoint The destination transponder port. | 24 | + * @param dst The destination transponder port. |
24 | */ | 25 | */ |
25 | - public OpticalConnectivityIntent(IntentId id, | 26 | + public OpticalConnectivityIntent(IntentId id, ConnectPoint src, ConnectPoint dst) { |
26 | - ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) { | ||
27 | super(id); | 27 | super(id); |
28 | - this.srcConnectPoint = srcConnectPoint; | 28 | + this.src = src; |
29 | - this.dstConnectPoint = dstConnectPoint; | 29 | + this.dst = dst; |
30 | } | 30 | } |
31 | 31 | ||
32 | /** | 32 | /** |
... | @@ -34,8 +34,8 @@ public class OpticalConnectivityIntent extends AbstractIntent { | ... | @@ -34,8 +34,8 @@ public class OpticalConnectivityIntent extends AbstractIntent { |
34 | */ | 34 | */ |
35 | protected OpticalConnectivityIntent() { | 35 | protected OpticalConnectivityIntent() { |
36 | super(); | 36 | super(); |
37 | - this.srcConnectPoint = null; | 37 | + this.src = null; |
38 | - this.dstConnectPoint = null; | 38 | + this.dst = null; |
39 | } | 39 | } |
40 | 40 | ||
41 | /** | 41 | /** |
... | @@ -44,7 +44,7 @@ public class OpticalConnectivityIntent extends AbstractIntent { | ... | @@ -44,7 +44,7 @@ public class OpticalConnectivityIntent extends AbstractIntent { |
44 | * @return The source transponder port. | 44 | * @return The source transponder port. |
45 | */ | 45 | */ |
46 | public ConnectPoint getSrcConnectPoint() { | 46 | public ConnectPoint getSrcConnectPoint() { |
47 | - return srcConnectPoint; | 47 | + return src; |
48 | } | 48 | } |
49 | 49 | ||
50 | /** | 50 | /** |
... | @@ -52,7 +52,7 @@ public class OpticalConnectivityIntent extends AbstractIntent { | ... | @@ -52,7 +52,7 @@ public class OpticalConnectivityIntent extends AbstractIntent { |
52 | * | 52 | * |
53 | * @return The source transponder port. | 53 | * @return The source transponder port. |
54 | */ | 54 | */ |
55 | - public ConnectPoint getDstConnectPoint() { | 55 | + public ConnectPoint getDst() { |
56 | - return dstConnectPoint; | 56 | + return dst; |
57 | } | 57 | } |
58 | } | 58 | } | ... | ... |
... | @@ -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 | ... | ... |
1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | -import static com.google.common.base.Preconditions.checkNotNull; | 3 | +import com.google.common.base.MoreObjects; |
4 | - | ||
5 | -import java.util.Objects; | ||
6 | - | ||
7 | import org.onlab.onos.net.ConnectPoint; | 4 | import org.onlab.onos.net.ConnectPoint; |
8 | import org.onlab.onos.net.flow.TrafficSelector; | 5 | import org.onlab.onos.net.flow.TrafficSelector; |
9 | import org.onlab.onos.net.flow.TrafficTreatment; | 6 | import org.onlab.onos.net.flow.TrafficTreatment; |
10 | 7 | ||
11 | -import com.google.common.base.MoreObjects; | 8 | +import java.util.Objects; |
9 | + | ||
10 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
12 | 11 | ||
13 | /** | 12 | /** |
14 | * Abstraction of point-to-point connectivity. | 13 | * Abstraction of point-to-point connectivity. |
... | @@ -23,15 +22,17 @@ public class PointToPointIntent extends ConnectivityIntent { | ... | @@ -23,15 +22,17 @@ public class PointToPointIntent extends ConnectivityIntent { |
23 | * ports. | 22 | * ports. |
24 | * | 23 | * |
25 | * @param id intent identifier | 24 | * @param id intent identifier |
26 | - * @param match traffic match | 25 | + * @param selector traffic selector |
27 | - * @param action action | 26 | + * @param treatment treatment |
28 | * @param ingressPort ingress port | 27 | * @param ingressPort ingress port |
29 | * @param egressPort egress port | 28 | * @param egressPort egress port |
30 | * @throws NullPointerException if {@code ingressPort} or {@code egressPort} is null. | 29 | * @throws NullPointerException if {@code ingressPort} or {@code egressPort} is null. |
31 | */ | 30 | */ |
32 | - public PointToPointIntent(IntentId id, TrafficSelector match, TrafficTreatment action, | 31 | + public PointToPointIntent(IntentId id, TrafficSelector selector, |
33 | - ConnectPoint ingressPort, ConnectPoint egressPort) { | 32 | + TrafficTreatment treatment, |
34 | - super(id, match, action); | 33 | + ConnectPoint ingressPort, |
34 | + ConnectPoint egressPort) { | ||
35 | + super(id, selector, treatment); | ||
35 | this.ingressPort = checkNotNull(ingressPort); | 36 | this.ingressPort = checkNotNull(ingressPort); |
36 | this.egressPort = checkNotNull(egressPort); | 37 | this.egressPort = checkNotNull(egressPort); |
37 | } | 38 | } | ... | ... |
1 | package org.onlab.onos.net.intent; | 1 | package org.onlab.onos.net.intent; |
2 | 2 | ||
3 | -import static com.google.common.base.Preconditions.checkArgument; | 3 | +import com.google.common.base.MoreObjects; |
4 | -import static com.google.common.base.Preconditions.checkNotNull; | 4 | +import com.google.common.collect.Sets; |
5 | - | ||
6 | -import java.util.Objects; | ||
7 | -import java.util.Set; | ||
8 | - | ||
9 | import org.onlab.onos.net.ConnectPoint; | 5 | import org.onlab.onos.net.ConnectPoint; |
10 | import org.onlab.onos.net.flow.TrafficSelector; | 6 | import org.onlab.onos.net.flow.TrafficSelector; |
11 | import org.onlab.onos.net.flow.TrafficTreatment; | 7 | import org.onlab.onos.net.flow.TrafficTreatment; |
12 | 8 | ||
13 | -import com.google.common.base.MoreObjects; | 9 | +import java.util.Objects; |
14 | -import com.google.common.collect.Sets; | 10 | +import java.util.Set; |
11 | + | ||
12 | +import static com.google.common.base.Preconditions.checkArgument; | ||
13 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
15 | 14 | ||
16 | /** | 15 | /** |
17 | * Abstraction of single source, multiple destination connectivity intent. | 16 | * Abstraction of single source, multiple destination connectivity intent. |
... | @@ -25,8 +24,8 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent { | ... | @@ -25,8 +24,8 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent { |
25 | * Creates a new single-to-multi point connectivity intent. | 24 | * Creates a new single-to-multi point connectivity intent. |
26 | * | 25 | * |
27 | * @param id intent identifier | 26 | * @param id intent identifier |
28 | - * @param match traffic match | 27 | + * @param selector traffic selector |
29 | - * @param action action | 28 | + * @param treatment treatment |
30 | * @param ingressPort port on which traffic will ingress | 29 | * @param ingressPort port on which traffic will ingress |
31 | * @param egressPorts set of ports on which traffic will egress | 30 | * @param egressPorts set of ports on which traffic will egress |
32 | * @throws NullPointerException if {@code ingressPort} or | 31 | * @throws NullPointerException if {@code ingressPort} or |
... | @@ -34,10 +33,11 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent { | ... | @@ -34,10 +33,11 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent { |
34 | * @throws IllegalArgumentException if the size of {@code egressPorts} is | 33 | * @throws IllegalArgumentException if the size of {@code egressPorts} is |
35 | * not more than 1 | 34 | * not more than 1 |
36 | */ | 35 | */ |
37 | - public SinglePointToMultiPointIntent(IntentId id, TrafficSelector match, TrafficTreatment action, | 36 | + public SinglePointToMultiPointIntent(IntentId id, TrafficSelector selector, |
37 | + TrafficTreatment treatment, | ||
38 | ConnectPoint ingressPort, | 38 | ConnectPoint ingressPort, |
39 | Set<ConnectPoint> egressPorts) { | 39 | Set<ConnectPoint> egressPorts) { |
40 | - super(id, match, action); | 40 | + super(id, selector, treatment); |
41 | 41 | ||
42 | checkNotNull(egressPorts); | 42 | checkNotNull(egressPorts); |
43 | checkArgument(!egressPorts.isEmpty(), | 43 | checkArgument(!egressPorts.isEmpty(), | ... | ... |
1 | /** | 1 | /** |
2 | - * Intent Package. TODO | 2 | + * Set of abstractions for conveying high-level intents for treatment of |
3 | + * selected network traffic by allowing applications to express the | ||
4 | + * <em>what</em> rather than the <em>how</em>. This makes such instructions | ||
5 | + * largely independent of topology and device specifics, thus allowing them to | ||
6 | + * survive topology mutations. | ||
3 | */ | 7 | */ |
4 | - | ||
5 | package org.onlab.onos.net.intent; | 8 | package org.onlab.onos.net.intent; |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -24,7 +24,7 @@ public abstract class DefaultPacketContext implements PacketContext { | ... | @@ -24,7 +24,7 @@ public abstract class DefaultPacketContext implements PacketContext { |
24 | this.inPkt = inPkt; | 24 | this.inPkt = inPkt; |
25 | this.outPkt = outPkt; | 25 | this.outPkt = outPkt; |
26 | this.block = new AtomicBoolean(block); | 26 | this.block = new AtomicBoolean(block); |
27 | - this.builder = new DefaultTrafficTreatment.Builder(); | 27 | + this.builder = DefaultTrafficTreatment.builder(); |
28 | } | 28 | } |
29 | 29 | ||
30 | @Override | 30 | @Override | ... | ... |
... | @@ -3,6 +3,7 @@ package org.onlab.onos.net.provider; | ... | @@ -3,6 +3,7 @@ package org.onlab.onos.net.provider; |
3 | import java.util.Objects; | 3 | import java.util.Objects; |
4 | 4 | ||
5 | import static com.google.common.base.MoreObjects.toStringHelper; | 5 | import static com.google.common.base.MoreObjects.toStringHelper; |
6 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
6 | 7 | ||
7 | /** | 8 | /** |
8 | * External identity of a {@link org.onlab.onos.net.provider.Provider} family. | 9 | * External identity of a {@link org.onlab.onos.net.provider.Provider} family. |
... | @@ -19,10 +20,22 @@ import static com.google.common.base.MoreObjects.toStringHelper; | ... | @@ -19,10 +20,22 @@ import static com.google.common.base.MoreObjects.toStringHelper; |
19 | */ | 20 | */ |
20 | public class ProviderId { | 21 | public class ProviderId { |
21 | 22 | ||
23 | + /** | ||
24 | + * Represents no provider ID. | ||
25 | + */ | ||
26 | + public static final ProviderId NONE = new ProviderId(); | ||
27 | + | ||
22 | private final String scheme; | 28 | private final String scheme; |
23 | private final String id; | 29 | private final String id; |
24 | private final boolean ancillary; | 30 | private final boolean ancillary; |
25 | 31 | ||
32 | + // For serialization | ||
33 | + private ProviderId() { | ||
34 | + scheme = null; | ||
35 | + id = null; | ||
36 | + ancillary = false; | ||
37 | + } | ||
38 | + | ||
26 | /** | 39 | /** |
27 | * Creates a new primary provider identifier from the specified string. | 40 | * Creates a new primary provider identifier from the specified string. |
28 | * The providers are expected to follow the reverse DNS convention, e.g. | 41 | * The providers are expected to follow the reverse DNS convention, e.g. |
... | @@ -45,8 +58,8 @@ public class ProviderId { | ... | @@ -45,8 +58,8 @@ public class ProviderId { |
45 | * @param ancillary ancillary provider indicator | 58 | * @param ancillary ancillary provider indicator |
46 | */ | 59 | */ |
47 | public ProviderId(String scheme, String id, boolean ancillary) { | 60 | public ProviderId(String scheme, String id, boolean ancillary) { |
48 | - this.scheme = scheme; | 61 | + this.scheme = checkNotNull(scheme, "Scheme cannot be null"); |
49 | - this.id = id; | 62 | + this.id = checkNotNull(id, "ID cannot be null"); |
50 | this.ancillary = ancillary; | 63 | this.ancillary = ancillary; |
51 | } | 64 | } |
52 | 65 | ... | ... |
1 | +package org.onlab.onos.store; | ||
2 | + | ||
3 | +import org.onlab.onos.cluster.MastershipTerm; | ||
4 | +import org.onlab.onos.net.DeviceId; | ||
5 | + | ||
6 | +//TODO: Consider renaming to DeviceClockProviderService? | ||
7 | +/** | ||
8 | +* Interface for feeding term information to a logical clock service | ||
9 | +* that vends per device timestamps. | ||
10 | +*/ | ||
11 | +public interface ClockProviderService { | ||
12 | + | ||
13 | + /** | ||
14 | + * Updates the mastership term for the specified deviceId. | ||
15 | + * @param deviceId device identifier. | ||
16 | + * @param term mastership term. | ||
17 | + */ | ||
18 | + public void setMastershipTerm(DeviceId deviceId, MastershipTerm term); | ||
19 | +} |
1 | package org.onlab.onos.store; | 1 | package org.onlab.onos.store; |
2 | 2 | ||
3 | -import org.onlab.onos.cluster.MastershipTerm; | ||
4 | import org.onlab.onos.net.DeviceId; | 3 | import org.onlab.onos.net.DeviceId; |
5 | 4 | ||
6 | // TODO: Consider renaming to DeviceClockService? | 5 | // TODO: Consider renaming to DeviceClockService? |
... | @@ -15,12 +14,4 @@ public interface ClockService { | ... | @@ -15,12 +14,4 @@ public interface ClockService { |
15 | * @return timestamp. | 14 | * @return timestamp. |
16 | */ | 15 | */ |
17 | public Timestamp getTimestamp(DeviceId deviceId); | 16 | public Timestamp getTimestamp(DeviceId deviceId); |
18 | - | ||
19 | - // TODO: Should this be here or separate as Admin service, etc.? | ||
20 | - /** | ||
21 | - * Updates the mastership term for the specified deviceId. | ||
22 | - * @param deviceId device identifier. | ||
23 | - * @param term mastership term. | ||
24 | - */ | ||
25 | - public void setMastershipTerm(DeviceId deviceId, MastershipTerm term); | ||
26 | } | 17 | } | ... | ... |
... | @@ -2,7 +2,15 @@ package org.onlab.onos.store; | ... | @@ -2,7 +2,15 @@ package org.onlab.onos.store; |
2 | 2 | ||
3 | /** | 3 | /** |
4 | * Opaque version structure. | 4 | * Opaque version structure. |
5 | + * <p> | ||
6 | + * Classes implementing this interface must also implement | ||
7 | + * {@link #hashCode()} and {@link #equals(Object)}. | ||
5 | */ | 8 | */ |
6 | public interface Timestamp extends Comparable<Timestamp> { | 9 | public interface Timestamp extends Comparable<Timestamp> { |
7 | 10 | ||
11 | + @Override | ||
12 | + public abstract int hashCode(); | ||
13 | + | ||
14 | + @Override | ||
15 | + public abstract boolean equals(Object obj); | ||
8 | } | 16 | } | ... | ... |
... | @@ -16,8 +16,8 @@ import org.onlab.onos.net.flow.TrafficTreatment; | ... | @@ -16,8 +16,8 @@ import org.onlab.onos.net.flow.TrafficTreatment; |
16 | public abstract class ConnectivityIntentTest extends IntentTest { | 16 | public abstract class ConnectivityIntentTest extends IntentTest { |
17 | 17 | ||
18 | public static final IntentId IID = new IntentId(123); | 18 | public static final IntentId IID = new IntentId(123); |
19 | - public static final TrafficSelector MATCH = (new DefaultTrafficSelector.Builder()).build(); | 19 | + public static final TrafficSelector MATCH = DefaultTrafficSelector.builder().build(); |
20 | - public static final TrafficTreatment NOP = (new DefaultTrafficTreatment.Builder()).build(); | 20 | + public static final TrafficTreatment NOP = DefaultTrafficTreatment.builder().build(); |
21 | 21 | ||
22 | public static final ConnectPoint P1 = new ConnectPoint(DeviceId.deviceId("111"), PortNumber.portNumber(0x1)); | 22 | public static final ConnectPoint P1 = new ConnectPoint(DeviceId.deviceId("111"), PortNumber.portNumber(0x1)); |
23 | public static final ConnectPoint P2 = new ConnectPoint(DeviceId.deviceId("222"), PortNumber.portNumber(0x2)); | 23 | public static final ConnectPoint P2 = new ConnectPoint(DeviceId.deviceId("222"), PortNumber.portNumber(0x2)); | ... | ... |
... | @@ -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 | ... | ... |
... | @@ -38,7 +38,7 @@ import org.onlab.onos.net.device.DeviceStoreDelegate; | ... | @@ -38,7 +38,7 @@ import org.onlab.onos.net.device.DeviceStoreDelegate; |
38 | import org.onlab.onos.net.device.PortDescription; | 38 | import org.onlab.onos.net.device.PortDescription; |
39 | import org.onlab.onos.net.provider.AbstractProviderRegistry; | 39 | import org.onlab.onos.net.provider.AbstractProviderRegistry; |
40 | import org.onlab.onos.net.provider.AbstractProviderService; | 40 | import org.onlab.onos.net.provider.AbstractProviderService; |
41 | -import org.onlab.onos.store.ClockService; | 41 | +import org.onlab.onos.store.ClockProviderService; |
42 | import org.slf4j.Logger; | 42 | import org.slf4j.Logger; |
43 | 43 | ||
44 | /** | 44 | /** |
... | @@ -80,7 +80,7 @@ public class DeviceManager | ... | @@ -80,7 +80,7 @@ public class DeviceManager |
80 | protected MastershipTermService termService; | 80 | protected MastershipTermService termService; |
81 | 81 | ||
82 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 82 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
83 | - protected ClockService clockService; | 83 | + protected ClockProviderService clockProviderService; |
84 | 84 | ||
85 | @Activate | 85 | @Activate |
86 | public void activate() { | 86 | public void activate() { |
... | @@ -274,7 +274,7 @@ public class DeviceManager | ... | @@ -274,7 +274,7 @@ public class DeviceManager |
274 | if (event.master().equals(clusterService.getLocalNode().id())) { | 274 | if (event.master().equals(clusterService.getLocalNode().id())) { |
275 | MastershipTerm term = mastershipService.requestTermService() | 275 | MastershipTerm term = mastershipService.requestTermService() |
276 | .getMastershipTerm(event.subject()); | 276 | .getMastershipTerm(event.subject()); |
277 | - clockService.setMastershipTerm(event.subject(), term); | 277 | + clockProviderService.setMastershipTerm(event.subject(), term); |
278 | applyRole(event.subject(), MastershipRole.MASTER); | 278 | applyRole(event.subject(), MastershipRole.MASTER); |
279 | } else { | 279 | } else { |
280 | applyRole(event.subject(), MastershipRole.STANDBY); | 280 | applyRole(event.subject(), MastershipRole.STANDBY); | ... | ... |
... | @@ -242,15 +242,16 @@ implements FlowRuleService, FlowRuleProviderRegistry { | ... | @@ -242,15 +242,16 @@ implements FlowRuleService, FlowRuleProviderRegistry { |
242 | } | 242 | } |
243 | 243 | ||
244 | private boolean checkRuleLiveness(FlowRule swRule, FlowRule storedRule) { | 244 | private boolean checkRuleLiveness(FlowRule swRule, FlowRule storedRule) { |
245 | - int timeout = storedRule.timeout(); | ||
246 | - if (storedRule.packets() != swRule.packets()) { | ||
247 | - deadRounds.get(swRule).set(0); | ||
248 | return true; | 245 | return true; |
249 | - } | 246 | +// int timeout = storedRule.timeout(); |
250 | - | 247 | +// if (storedRule.packets() != swRule.packets()) { |
251 | - return (deadRounds.get(swRule).getAndIncrement() * | 248 | +// deadRounds.get(swRule).set(0); |
252 | - FlowRuleProvider.POLL_INTERVAL) <= timeout; | 249 | +// return true; |
253 | - | 250 | +// } |
251 | +// | ||
252 | +// return (deadRounds.get(swRule).getAndIncrement() * | ||
253 | +// FlowRuleProvider.POLL_INTERVAL) <= timeout; | ||
254 | +// | ||
254 | } | 255 | } |
255 | 256 | ||
256 | // Posts the specified event to the local event dispatcher. | 257 | // Posts the specified event to the local event dispatcher. | ... | ... |
... | @@ -4,9 +4,9 @@ import java.nio.ByteBuffer; | ... | @@ -4,9 +4,9 @@ import java.nio.ByteBuffer; |
4 | import java.util.ArrayList; | 4 | import java.util.ArrayList; |
5 | import java.util.HashSet; | 5 | import java.util.HashSet; |
6 | import java.util.List; | 6 | import java.util.List; |
7 | -import java.util.Map; | ||
8 | import java.util.Set; | 7 | import java.util.Set; |
9 | import java.util.concurrent.ConcurrentHashMap; | 8 | import java.util.concurrent.ConcurrentHashMap; |
9 | +import java.util.concurrent.ConcurrentMap; | ||
10 | import java.util.concurrent.TimeUnit; | 10 | import java.util.concurrent.TimeUnit; |
11 | 11 | ||
12 | import org.jboss.netty.util.Timeout; | 12 | import org.jboss.netty.util.Timeout; |
... | @@ -59,15 +59,14 @@ public class HostMonitor implements TimerTask { | ... | @@ -59,15 +59,14 @@ public class HostMonitor implements TimerTask { |
59 | 59 | ||
60 | private final Set<IpAddress> monitoredAddresses; | 60 | private final Set<IpAddress> monitoredAddresses; |
61 | 61 | ||
62 | - private final Map<ProviderId, HostProvider> hostProviders; | 62 | + private final ConcurrentMap<ProviderId, HostProvider> hostProviders; |
63 | 63 | ||
64 | - private final long probeRate; | 64 | + private static final long DEFAULT_PROBE_RATE = 30000; // milliseconds |
65 | + private long probeRate = DEFAULT_PROBE_RATE; | ||
65 | 66 | ||
66 | private final Timeout timeout; | 67 | private final Timeout timeout; |
67 | 68 | ||
68 | - public HostMonitor( | 69 | + public HostMonitor(DeviceService deviceService, PacketService packetService, |
69 | - DeviceService deviceService, | ||
70 | - PacketService packetService, | ||
71 | HostManager hostService) { | 70 | HostManager hostService) { |
72 | 71 | ||
73 | this.deviceService = deviceService; | 72 | this.deviceService = deviceService; |
... | @@ -77,15 +76,7 @@ public class HostMonitor implements TimerTask { | ... | @@ -77,15 +76,7 @@ public class HostMonitor implements TimerTask { |
77 | monitoredAddresses = new HashSet<>(); | 76 | monitoredAddresses = new HashSet<>(); |
78 | hostProviders = new ConcurrentHashMap<>(); | 77 | hostProviders = new ConcurrentHashMap<>(); |
79 | 78 | ||
80 | - probeRate = 30000; // milliseconds | ||
81 | - | ||
82 | timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS); | 79 | timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS); |
83 | - | ||
84 | - addDefaultAddresses(); | ||
85 | - } | ||
86 | - | ||
87 | - private void addDefaultAddresses() { | ||
88 | - //monitoredAddresses.add(IpAddress.valueOf("10.0.0.1")); | ||
89 | } | 80 | } |
90 | 81 | ||
91 | void addMonitoringFor(IpAddress ip) { | 82 | void addMonitoringFor(IpAddress ip) { |
... | @@ -104,10 +95,6 @@ public class HostMonitor implements TimerTask { | ... | @@ -104,10 +95,6 @@ public class HostMonitor implements TimerTask { |
104 | hostProviders.put(provider.id(), provider); | 95 | hostProviders.put(provider.id(), provider); |
105 | } | 96 | } |
106 | 97 | ||
107 | - void unregisterHostProvider(HostProvider provider) { | ||
108 | - // TODO find out how to call this | ||
109 | - } | ||
110 | - | ||
111 | @Override | 98 | @Override |
112 | public void run(Timeout timeout) throws Exception { | 99 | public void run(Timeout timeout) throws Exception { |
113 | for (IpAddress ip : monitoredAddresses) { | 100 | for (IpAddress ip : monitoredAddresses) { |
... | @@ -121,7 +108,9 @@ public class HostMonitor implements TimerTask { | ... | @@ -121,7 +108,9 @@ public class HostMonitor implements TimerTask { |
121 | } else { | 108 | } else { |
122 | for (Host host : hosts) { | 109 | for (Host host : hosts) { |
123 | HostProvider provider = hostProviders.get(host.providerId()); | 110 | HostProvider provider = hostProviders.get(host.providerId()); |
124 | - if (provider != null) { | 111 | + if (provider == null) { |
112 | + hostProviders.remove(host.providerId(), null); | ||
113 | + } else { | ||
125 | provider.triggerProbe(host); | 114 | provider.triggerProbe(host); |
126 | } | 115 | } |
127 | } | 116 | } |
... | @@ -161,7 +150,7 @@ public class HostMonitor implements TimerTask { | ... | @@ -161,7 +150,7 @@ public class HostMonitor implements TimerTask { |
161 | List<Instruction> instructions = new ArrayList<>(); | 150 | List<Instruction> instructions = new ArrayList<>(); |
162 | instructions.add(Instructions.createOutput(port.number())); | 151 | instructions.add(Instructions.createOutput(port.number())); |
163 | 152 | ||
164 | - TrafficTreatment treatment = new DefaultTrafficTreatment.Builder() | 153 | + TrafficTreatment treatment = DefaultTrafficTreatment.builder() |
165 | .setOutput(port.number()) | 154 | .setOutput(port.number()) |
166 | .build(); | 155 | .build(); |
167 | 156 | ... | ... |
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 org.onlab.onos.net.intent.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 org.apache.felix.scr.annotations.Activate; | ||
4 | +import org.apache.felix.scr.annotations.Component; | ||
5 | +import org.apache.felix.scr.annotations.Deactivate; | ||
6 | +import org.apache.felix.scr.annotations.Reference; | ||
7 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
8 | +import org.onlab.onos.ApplicationId; | ||
9 | +import org.onlab.onos.net.ConnectPoint; | ||
10 | +import org.onlab.onos.net.Link; | ||
11 | +import org.onlab.onos.net.flow.DefaultFlowRule; | ||
12 | +import org.onlab.onos.net.flow.DefaultTrafficSelector; | ||
13 | +import org.onlab.onos.net.flow.DefaultTrafficTreatment; | ||
14 | +import org.onlab.onos.net.flow.FlowRule; | ||
15 | +import org.onlab.onos.net.flow.FlowRuleService; | ||
16 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
17 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
18 | +import org.onlab.onos.net.intent.IntentExtensionService; | ||
19 | +import org.onlab.onos.net.intent.IntentInstaller; | ||
20 | +import org.onlab.onos.net.intent.PathIntent; | ||
21 | + | ||
22 | +import java.util.Iterator; | ||
23 | + | ||
24 | +/** | ||
25 | + * Installer for {@link PathIntent path connectivity intents}. | ||
26 | + */ | ||
27 | +@Component(immediate = true) | ||
28 | +public class PathIntentInstaller implements IntentInstaller<PathIntent> { | ||
29 | + | ||
30 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
31 | + protected IntentExtensionService intentManager; | ||
32 | + | ||
33 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
34 | + protected FlowRuleService flowRuleService; | ||
35 | + | ||
36 | + private final ApplicationId appId = ApplicationId.getAppId(); | ||
37 | + | ||
38 | + @Activate | ||
39 | + public void activate() { | ||
40 | + intentManager.registerInstaller(PathIntent.class, this); | ||
41 | + } | ||
42 | + | ||
43 | + @Deactivate | ||
44 | + public void deactivate() { | ||
45 | + intentManager.unregisterInstaller(PathIntent.class); | ||
46 | + } | ||
47 | + | ||
48 | + @Override | ||
49 | + public void install(PathIntent intent) { | ||
50 | + TrafficSelector.Builder builder = | ||
51 | + DefaultTrafficSelector.builder(intent.getTrafficSelector()); | ||
52 | + Iterator<Link> links = intent.getPath().links().iterator(); | ||
53 | + ConnectPoint prev = links.next().dst(); | ||
54 | + while (links.hasNext()) { | ||
55 | + builder.matchInport(prev.port()); | ||
56 | + Link link = links.next(); | ||
57 | + | ||
58 | + TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(); | ||
59 | + treat.setOutput(link.src().port()); | ||
60 | + | ||
61 | + FlowRule rule = new DefaultFlowRule(link.src().deviceId(), | ||
62 | + builder.build(), treat.build(), | ||
63 | + 0, appId, 30); | ||
64 | + flowRuleService.applyFlowRules(rule); | ||
65 | + | ||
66 | + prev = link.dst(); | ||
67 | + } | ||
68 | + | ||
69 | + } | ||
70 | + | ||
71 | + @Override | ||
72 | + public void uninstall(PathIntent intent) { | ||
73 | + //TODO | ||
74 | + } | ||
75 | +} |
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 | +} |
... | @@ -43,7 +43,6 @@ import com.google.common.collect.HashMultimap; | ... | @@ -43,7 +43,6 @@ import com.google.common.collect.HashMultimap; |
43 | import com.google.common.collect.Lists; | 43 | import com.google.common.collect.Lists; |
44 | import com.google.common.collect.Multimap; | 44 | import com.google.common.collect.Multimap; |
45 | 45 | ||
46 | - | ||
47 | @Component(immediate = true) | 46 | @Component(immediate = true) |
48 | @Service | 47 | @Service |
49 | public class ProxyArpManager implements ProxyArpService { | 48 | public class ProxyArpManager implements ProxyArpService { |
... | @@ -128,7 +127,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -128,7 +127,7 @@ public class ProxyArpManager implements ProxyArpService { |
128 | 127 | ||
129 | Ethernet arpReply = buildArpReply(dst, eth); | 128 | Ethernet arpReply = buildArpReply(dst, eth); |
130 | // TODO: check send status with host service. | 129 | // TODO: check send status with host service. |
131 | - TrafficTreatment.Builder builder = new DefaultTrafficTreatment.Builder(); | 130 | + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); |
132 | builder.setOutput(src.location().port()); | 131 | builder.setOutput(src.location().port()); |
133 | packetService.emit(new DefaultOutboundPacket(src.location().deviceId(), | 132 | packetService.emit(new DefaultOutboundPacket(src.location().deviceId(), |
134 | builder.build(), ByteBuffer.wrap(arpReply.serialize()))); | 133 | builder.build(), ByteBuffer.wrap(arpReply.serialize()))); |
... | @@ -148,7 +147,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -148,7 +147,7 @@ public class ProxyArpManager implements ProxyArpService { |
148 | if (h == null) { | 147 | if (h == null) { |
149 | flood(eth); | 148 | flood(eth); |
150 | } else { | 149 | } else { |
151 | - TrafficTreatment.Builder builder = new DefaultTrafficTreatment.Builder(); | 150 | + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); |
152 | builder.setOutput(h.location().port()); | 151 | builder.setOutput(h.location().port()); |
153 | packetService.emit(new DefaultOutboundPacket(h.location().deviceId(), | 152 | packetService.emit(new DefaultOutboundPacket(h.location().deviceId(), |
154 | builder.build(), ByteBuffer.wrap(eth.serialize()))); | 153 | builder.build(), ByteBuffer.wrap(eth.serialize()))); |
... | @@ -166,7 +165,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -166,7 +165,7 @@ public class ProxyArpManager implements ProxyArpService { |
166 | 165 | ||
167 | synchronized (externalPorts) { | 166 | synchronized (externalPorts) { |
168 | for (Entry<Device, PortNumber> entry : externalPorts.entries()) { | 167 | for (Entry<Device, PortNumber> entry : externalPorts.entries()) { |
169 | - builder = new DefaultTrafficTreatment.Builder(); | 168 | + builder = DefaultTrafficTreatment.builder(); |
170 | builder.setOutput(entry.getValue()); | 169 | builder.setOutput(entry.getValue()); |
171 | packetService.emit(new DefaultOutboundPacket(entry.getKey().id(), | 170 | packetService.emit(new DefaultOutboundPacket(entry.getKey().id(), |
172 | builder.build(), buf)); | 171 | builder.build(), buf)); | ... | ... |
1 | package org.onlab.onos.store.cluster.impl; | 1 | package org.onlab.onos.store.cluster.impl; |
2 | 2 | ||
3 | -import de.javakaffee.kryoserializers.URISerializer; | ||
4 | import org.apache.felix.scr.annotations.Activate; | 3 | import org.apache.felix.scr.annotations.Activate; |
5 | import org.apache.felix.scr.annotations.Component; | 4 | import org.apache.felix.scr.annotations.Component; |
6 | import org.apache.felix.scr.annotations.Deactivate; | 5 | import org.apache.felix.scr.annotations.Deactivate; |
7 | import org.apache.felix.scr.annotations.Service; | 6 | import org.apache.felix.scr.annotations.Service; |
8 | -import org.onlab.onos.cluster.ControllerNode; | ||
9 | -import org.onlab.onos.cluster.DefaultControllerNode; | ||
10 | -import org.onlab.onos.cluster.NodeId; | ||
11 | -import org.onlab.onos.net.ConnectPoint; | ||
12 | -import org.onlab.onos.net.DefaultDevice; | ||
13 | -import org.onlab.onos.net.DefaultLink; | ||
14 | -import org.onlab.onos.net.DefaultPort; | ||
15 | -import org.onlab.onos.net.Device; | ||
16 | -import org.onlab.onos.net.DeviceId; | ||
17 | -import org.onlab.onos.net.Element; | ||
18 | -import org.onlab.onos.net.Link; | ||
19 | -import org.onlab.onos.net.LinkKey; | ||
20 | -import org.onlab.onos.net.MastershipRole; | ||
21 | -import org.onlab.onos.net.Port; | ||
22 | -import org.onlab.onos.net.PortNumber; | ||
23 | -import org.onlab.onos.net.provider.ProviderId; | ||
24 | import org.onlab.onos.store.cluster.messaging.MessageSubject; | 7 | import org.onlab.onos.store.cluster.messaging.MessageSubject; |
25 | import org.onlab.onos.store.cluster.messaging.SerializationService; | 8 | import org.onlab.onos.store.cluster.messaging.SerializationService; |
26 | -import org.onlab.onos.store.serializers.ConnectPointSerializer; | 9 | +import org.onlab.onos.store.serializers.KryoPoolUtil; |
27 | -import org.onlab.onos.store.serializers.DefaultLinkSerializer; | ||
28 | -import org.onlab.onos.store.serializers.DefaultPortSerializer; | ||
29 | -import org.onlab.onos.store.serializers.DeviceIdSerializer; | ||
30 | -import org.onlab.onos.store.serializers.IpPrefixSerializer; | ||
31 | -import org.onlab.onos.store.serializers.LinkKeySerializer; | ||
32 | -import org.onlab.onos.store.serializers.NodeIdSerializer; | ||
33 | -import org.onlab.onos.store.serializers.PortNumberSerializer; | ||
34 | -import org.onlab.onos.store.serializers.ProviderIdSerializer; | ||
35 | -import org.onlab.packet.IpPrefix; | ||
36 | import org.onlab.util.KryoPool; | 10 | import org.onlab.util.KryoPool; |
37 | import org.slf4j.Logger; | 11 | import org.slf4j.Logger; |
38 | import org.slf4j.LoggerFactory; | 12 | import org.slf4j.LoggerFactory; |
39 | 13 | ||
40 | -import java.net.URI; | ||
41 | -import java.util.ArrayList; | ||
42 | -import java.util.HashMap; | ||
43 | - | ||
44 | /** | 14 | /** |
45 | * Factory for parsing messages sent between cluster members. | 15 | * Factory for parsing messages sent between cluster members. |
46 | */ | 16 | */ |
... | @@ -72,34 +42,10 @@ public class MessageSerializer implements SerializationService { | ... | @@ -72,34 +42,10 @@ public class MessageSerializer implements SerializationService { |
72 | * Sets up the common serialzers pool. | 42 | * Sets up the common serialzers pool. |
73 | */ | 43 | */ |
74 | protected void setupKryoPool() { | 44 | protected void setupKryoPool() { |
75 | - // FIXME Slice out types used in common to separate pool/namespace. | ||
76 | serializerPool = KryoPool.newBuilder() | 45 | serializerPool = KryoPool.newBuilder() |
77 | - .register(ArrayList.class, | 46 | + .register(KryoPoolUtil.API) |
78 | - HashMap.class, | 47 | + // TODO: Should MessageSubject be in API bundle? |
79 | - | 48 | + .register(MessageSubject.class) |
80 | - ControllerNode.State.class, | ||
81 | - Device.Type.class, | ||
82 | - | ||
83 | - DefaultControllerNode.class, | ||
84 | - DefaultDevice.class, | ||
85 | - MastershipRole.class, | ||
86 | - Port.class, | ||
87 | - Element.class, | ||
88 | - | ||
89 | - Link.Type.class, | ||
90 | - | ||
91 | - MessageSubject.class | ||
92 | - ) | ||
93 | - .register(IpPrefix.class, new IpPrefixSerializer()) | ||
94 | - .register(URI.class, new URISerializer()) | ||
95 | - .register(NodeId.class, new NodeIdSerializer()) | ||
96 | - .register(ProviderId.class, new ProviderIdSerializer()) | ||
97 | - .register(DeviceId.class, new DeviceIdSerializer()) | ||
98 | - .register(PortNumber.class, new PortNumberSerializer()) | ||
99 | - .register(DefaultPort.class, new DefaultPortSerializer()) | ||
100 | - .register(LinkKey.class, new LinkKeySerializer()) | ||
101 | - .register(ConnectPoint.class, new ConnectPointSerializer()) | ||
102 | - .register(DefaultLink.class, new DefaultLinkSerializer()) | ||
103 | .build() | 49 | .build() |
104 | .populate(1); | 50 | .populate(1); |
105 | } | 51 | } | ... | ... |
1 | -package org.onlab.onos.store.impl; | 1 | +package org.onlab.onos.store.common.impl; |
2 | 2 | ||
3 | import static com.google.common.base.Preconditions.checkArgument; | 3 | import static com.google.common.base.Preconditions.checkArgument; |
4 | 4 | ||
... | @@ -9,12 +9,11 @@ import org.onlab.onos.store.Timestamp; | ... | @@ -9,12 +9,11 @@ import org.onlab.onos.store.Timestamp; |
9 | import com.google.common.base.MoreObjects; | 9 | import com.google.common.base.MoreObjects; |
10 | import com.google.common.collect.ComparisonChain; | 10 | import com.google.common.collect.ComparisonChain; |
11 | 11 | ||
12 | -// If it is store specific, implement serializable interfaces? | ||
13 | /** | 12 | /** |
14 | * Default implementation of Timestamp. | 13 | * Default implementation of Timestamp. |
15 | * TODO: Better documentation. | 14 | * TODO: Better documentation. |
16 | */ | 15 | */ |
17 | -public final class OnosTimestamp implements Timestamp { | 16 | +public final class MastershipBasedTimestamp implements Timestamp { |
18 | 17 | ||
19 | private final int termNumber; | 18 | private final int termNumber; |
20 | private final int sequenceNumber; | 19 | private final int sequenceNumber; |
... | @@ -25,15 +24,16 @@ public final class OnosTimestamp implements Timestamp { | ... | @@ -25,15 +24,16 @@ public final class OnosTimestamp implements Timestamp { |
25 | * @param termNumber the mastership termNumber | 24 | * @param termNumber the mastership termNumber |
26 | * @param sequenceNumber the sequenceNumber number within the termNumber | 25 | * @param sequenceNumber the sequenceNumber number within the termNumber |
27 | */ | 26 | */ |
28 | - public OnosTimestamp(int termNumber, int sequenceNumber) { | 27 | + public MastershipBasedTimestamp(int termNumber, int sequenceNumber) { |
29 | this.termNumber = termNumber; | 28 | this.termNumber = termNumber; |
30 | this.sequenceNumber = sequenceNumber; | 29 | this.sequenceNumber = sequenceNumber; |
31 | } | 30 | } |
32 | 31 | ||
33 | @Override | 32 | @Override |
34 | public int compareTo(Timestamp o) { | 33 | public int compareTo(Timestamp o) { |
35 | - checkArgument(o instanceof OnosTimestamp, "Must be OnosTimestamp", o); | 34 | + checkArgument(o instanceof MastershipBasedTimestamp, |
36 | - OnosTimestamp that = (OnosTimestamp) o; | 35 | + "Must be MastershipBasedTimestamp", o); |
36 | + MastershipBasedTimestamp that = (MastershipBasedTimestamp) o; | ||
37 | 37 | ||
38 | return ComparisonChain.start() | 38 | return ComparisonChain.start() |
39 | .compare(this.termNumber, that.termNumber) | 39 | .compare(this.termNumber, that.termNumber) |
... | @@ -51,10 +51,10 @@ public final class OnosTimestamp implements Timestamp { | ... | @@ -51,10 +51,10 @@ public final class OnosTimestamp implements Timestamp { |
51 | if (this == obj) { | 51 | if (this == obj) { |
52 | return true; | 52 | return true; |
53 | } | 53 | } |
54 | - if (!(obj instanceof OnosTimestamp)) { | 54 | + if (!(obj instanceof MastershipBasedTimestamp)) { |
55 | return false; | 55 | return false; |
56 | } | 56 | } |
57 | - OnosTimestamp that = (OnosTimestamp) obj; | 57 | + MastershipBasedTimestamp that = (MastershipBasedTimestamp) obj; |
58 | return Objects.equals(this.termNumber, that.termNumber) && | 58 | return Objects.equals(this.termNumber, that.termNumber) && |
59 | Objects.equals(this.sequenceNumber, that.sequenceNumber); | 59 | Objects.equals(this.sequenceNumber, that.sequenceNumber); |
60 | } | 60 | } |
... | @@ -84,4 +84,11 @@ public final class OnosTimestamp implements Timestamp { | ... | @@ -84,4 +84,11 @@ public final class OnosTimestamp implements Timestamp { |
84 | public int sequenceNumber() { | 84 | public int sequenceNumber() { |
85 | return sequenceNumber; | 85 | return sequenceNumber; |
86 | } | 86 | } |
87 | + | ||
88 | + // Default constructor for serialization | ||
89 | + @Deprecated | ||
90 | + protected MastershipBasedTimestamp() { | ||
91 | + this.termNumber = -1; | ||
92 | + this.sequenceNumber = -1; | ||
93 | + } | ||
87 | } | 94 | } | ... | ... |
1 | +package org.onlab.onos.store.common.impl; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | + | ||
5 | +import java.util.Objects; | ||
6 | + | ||
7 | +import org.onlab.onos.store.Timestamp; | ||
8 | + | ||
9 | +/** | ||
10 | + * Wrapper class to store Timestamped value. | ||
11 | + * @param <T> | ||
12 | + */ | ||
13 | +public final class Timestamped<T> { | ||
14 | + | ||
15 | + private final Timestamp timestamp; | ||
16 | + private final T value; | ||
17 | + | ||
18 | + /** | ||
19 | + * Creates a time stamped value. | ||
20 | + * | ||
21 | + * @param value to be timestamp | ||
22 | + * @param timestamp the timestamp | ||
23 | + */ | ||
24 | + public Timestamped(T value, Timestamp timestamp) { | ||
25 | + this.value = checkNotNull(value); | ||
26 | + this.timestamp = checkNotNull(timestamp); | ||
27 | + } | ||
28 | + | ||
29 | + /** | ||
30 | + * Returns the value. | ||
31 | + * @return value | ||
32 | + */ | ||
33 | + public T value() { | ||
34 | + return value; | ||
35 | + } | ||
36 | + | ||
37 | + /** | ||
38 | + * Returns the time stamp. | ||
39 | + * @return time stamp | ||
40 | + */ | ||
41 | + public Timestamp timestamp() { | ||
42 | + return timestamp; | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * Tests if this timestamped value is newer than the other. | ||
47 | + * | ||
48 | + * @param other timestamped value | ||
49 | + * @return true if this instance is newer. | ||
50 | + */ | ||
51 | + public boolean isNewer(Timestamped<T> other) { | ||
52 | + return this.timestamp.compareTo(checkNotNull(other).timestamp()) > 0; | ||
53 | + } | ||
54 | + | ||
55 | + @Override | ||
56 | + public int hashCode() { | ||
57 | + return timestamp.hashCode(); | ||
58 | + } | ||
59 | + | ||
60 | + @Override | ||
61 | + public boolean equals(Object obj) { | ||
62 | + if (this == obj) { | ||
63 | + return true; | ||
64 | + } | ||
65 | + if (!(obj instanceof Timestamped)) { | ||
66 | + return false; | ||
67 | + } | ||
68 | + @SuppressWarnings("unchecked") | ||
69 | + Timestamped<T> that = (Timestamped<T>) obj; | ||
70 | + return Objects.equals(this.timestamp, that.timestamp); | ||
71 | + } | ||
72 | + | ||
73 | + // Default constructor for serialization | ||
74 | + @Deprecated | ||
75 | + protected Timestamped() { | ||
76 | + this.value = null; | ||
77 | + this.timestamp = null; | ||
78 | + } | ||
79 | +} |
... | @@ -12,14 +12,18 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -12,14 +12,18 @@ import org.apache.felix.scr.annotations.Deactivate; |
12 | import org.apache.felix.scr.annotations.Service; | 12 | import org.apache.felix.scr.annotations.Service; |
13 | import org.onlab.onos.cluster.MastershipTerm; | 13 | import org.onlab.onos.cluster.MastershipTerm; |
14 | import org.onlab.onos.net.DeviceId; | 14 | import org.onlab.onos.net.DeviceId; |
15 | +import org.onlab.onos.store.ClockProviderService; | ||
15 | import org.onlab.onos.store.ClockService; | 16 | import org.onlab.onos.store.ClockService; |
16 | import org.onlab.onos.store.Timestamp; | 17 | import org.onlab.onos.store.Timestamp; |
17 | -import org.onlab.onos.store.impl.OnosTimestamp; | 18 | +import org.onlab.onos.store.common.impl.MastershipBasedTimestamp; |
18 | import org.slf4j.Logger; | 19 | import org.slf4j.Logger; |
19 | 20 | ||
21 | +/** | ||
22 | + * Clock service to issue Timestamp based on Device Mastership. | ||
23 | + */ | ||
20 | @Component(immediate = true) | 24 | @Component(immediate = true) |
21 | @Service | 25 | @Service |
22 | -public class OnosClockService implements ClockService { | 26 | +public class DeviceClockManager implements ClockService, ClockProviderService { |
23 | 27 | ||
24 | private final Logger log = getLogger(getClass()); | 28 | private final Logger log = getLogger(getClass()); |
25 | 29 | ||
... | @@ -43,7 +47,7 @@ public class OnosClockService implements ClockService { | ... | @@ -43,7 +47,7 @@ public class OnosClockService implements ClockService { |
43 | if (term == null) { | 47 | if (term == null) { |
44 | throw new IllegalStateException("Requesting timestamp for a deviceId without mastership"); | 48 | throw new IllegalStateException("Requesting timestamp for a deviceId without mastership"); |
45 | } | 49 | } |
46 | - return new OnosTimestamp(term.termNumber(), ticker.incrementAndGet()); | 50 | + return new MastershipBasedTimestamp(term.termNumber(), ticker.incrementAndGet()); |
47 | } | 51 | } |
48 | 52 | ||
49 | @Override | 53 | @Override | ... | ... |
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import com.google.common.collect.FluentIterable; | ||
4 | +import com.google.common.collect.ImmutableList; | ||
5 | + | ||
6 | +import org.apache.commons.lang3.concurrent.ConcurrentException; | ||
7 | +import org.apache.commons.lang3.concurrent.ConcurrentInitializer; | ||
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.apache.felix.scr.annotations.Reference; | ||
12 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
13 | +import org.apache.felix.scr.annotations.Service; | ||
14 | +import org.onlab.onos.net.Annotations; | ||
15 | +import org.onlab.onos.net.DefaultAnnotations; | ||
16 | +import org.onlab.onos.net.DefaultDevice; | ||
17 | +import org.onlab.onos.net.DefaultPort; | ||
18 | +import org.onlab.onos.net.Device; | ||
19 | +import org.onlab.onos.net.Device.Type; | ||
20 | +import org.onlab.onos.net.DeviceId; | ||
21 | +import org.onlab.onos.net.Port; | ||
22 | +import org.onlab.onos.net.PortNumber; | ||
23 | +import org.onlab.onos.net.SparseAnnotations; | ||
24 | +import org.onlab.onos.net.device.DefaultDeviceDescription; | ||
25 | +import org.onlab.onos.net.device.DefaultPortDescription; | ||
26 | +import org.onlab.onos.net.device.DeviceDescription; | ||
27 | +import org.onlab.onos.net.device.DeviceEvent; | ||
28 | +import org.onlab.onos.net.device.DeviceStore; | ||
29 | +import org.onlab.onos.net.device.DeviceStoreDelegate; | ||
30 | +import org.onlab.onos.net.device.PortDescription; | ||
31 | +import org.onlab.onos.net.provider.ProviderId; | ||
32 | +import org.onlab.onos.store.AbstractStore; | ||
33 | +import org.onlab.onos.store.ClockService; | ||
34 | +import org.onlab.onos.store.Timestamp; | ||
35 | +import org.onlab.onos.store.common.impl.Timestamped; | ||
36 | +import org.slf4j.Logger; | ||
37 | + | ||
38 | +import java.util.ArrayList; | ||
39 | +import java.util.Collections; | ||
40 | +import java.util.HashSet; | ||
41 | +import java.util.Iterator; | ||
42 | +import java.util.List; | ||
43 | +import java.util.Map; | ||
44 | +import java.util.Map.Entry; | ||
45 | +import java.util.Objects; | ||
46 | +import java.util.Set; | ||
47 | +import java.util.concurrent.ConcurrentHashMap; | ||
48 | +import java.util.concurrent.ConcurrentMap; | ||
49 | +import java.util.concurrent.atomic.AtomicReference; | ||
50 | + | ||
51 | +import static com.google.common.base.Preconditions.checkArgument; | ||
52 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
53 | +import static com.google.common.base.Predicates.notNull; | ||
54 | +import static org.onlab.onos.net.device.DeviceEvent.Type.*; | ||
55 | +import static org.slf4j.LoggerFactory.getLogger; | ||
56 | +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | ||
57 | +import static org.onlab.onos.net.DefaultAnnotations.merge; | ||
58 | +import static com.google.common.base.Verify.verify; | ||
59 | + | ||
60 | +// TODO: implement remove event handling and call *Internal | ||
61 | +/** | ||
62 | + * Manages inventory of infrastructure devices using gossip protocol to distribute | ||
63 | + * information. | ||
64 | + */ | ||
65 | +@Component(immediate = true) | ||
66 | +@Service | ||
67 | +public class GossipDeviceStore | ||
68 | + extends AbstractStore<DeviceEvent, DeviceStoreDelegate> | ||
69 | + implements DeviceStore { | ||
70 | + | ||
71 | + private final Logger log = getLogger(getClass()); | ||
72 | + | ||
73 | + public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; | ||
74 | + | ||
75 | + // TODO: Check if inner Map can be replaced with plain Map | ||
76 | + // innerMap is used to lock a Device, thus instance should never be replaced. | ||
77 | + // collection of Description given from various providers | ||
78 | + private final ConcurrentMap<DeviceId, | ||
79 | + ConcurrentMap<ProviderId, DeviceDescriptions>> | ||
80 | + deviceDescs = new ConcurrentHashMap<>(); | ||
81 | + | ||
82 | + // cache of Device and Ports generated by compositing descriptions from providers | ||
83 | + private final ConcurrentMap<DeviceId, Device> devices = new ConcurrentHashMap<>(); | ||
84 | + private final ConcurrentMap<DeviceId, ConcurrentMap<PortNumber, Port>> devicePorts = new ConcurrentHashMap<>(); | ||
85 | + | ||
86 | + // available(=UP) devices | ||
87 | + private final Set<DeviceId> availableDevices = new HashSet<>(); | ||
88 | + | ||
89 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
90 | + protected ClockService clockService; | ||
91 | + | ||
92 | + @Activate | ||
93 | + public void activate() { | ||
94 | + log.info("Started"); | ||
95 | + } | ||
96 | + | ||
97 | + @Deactivate | ||
98 | + public void deactivate() { | ||
99 | + deviceDescs.clear(); | ||
100 | + devices.clear(); | ||
101 | + devicePorts.clear(); | ||
102 | + availableDevices.clear(); | ||
103 | + log.info("Stopped"); | ||
104 | + } | ||
105 | + | ||
106 | + @Override | ||
107 | + public int getDeviceCount() { | ||
108 | + return devices.size(); | ||
109 | + } | ||
110 | + | ||
111 | + @Override | ||
112 | + public Iterable<Device> getDevices() { | ||
113 | + return Collections.unmodifiableCollection(devices.values()); | ||
114 | + } | ||
115 | + | ||
116 | + @Override | ||
117 | + public Device getDevice(DeviceId deviceId) { | ||
118 | + return devices.get(deviceId); | ||
119 | + } | ||
120 | + | ||
121 | + @Override | ||
122 | + public synchronized DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, | ||
123 | + DeviceDescription deviceDescription) { | ||
124 | + Timestamp newTimestamp = clockService.getTimestamp(deviceId); | ||
125 | + final Timestamped<DeviceDescription> deltaDesc = new Timestamped<>(deviceDescription, newTimestamp); | ||
126 | + DeviceEvent event = createOrUpdateDeviceInternal(providerId, deviceId, deltaDesc); | ||
127 | + if (event != null) { | ||
128 | + // FIXME: broadcast deltaDesc, UP | ||
129 | + log.debug("broadcast deltaDesc"); | ||
130 | + } | ||
131 | + return event; | ||
132 | + } | ||
133 | + | ||
134 | + private DeviceEvent createOrUpdateDeviceInternal(ProviderId providerId, DeviceId deviceId, | ||
135 | + Timestamped<DeviceDescription> deltaDesc) { | ||
136 | + | ||
137 | + // Collection of DeviceDescriptions for a Device | ||
138 | + ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs | ||
139 | + = createIfAbsentUnchecked(deviceDescs, deviceId, | ||
140 | + new InitConcurrentHashMap<ProviderId, DeviceDescriptions>()); | ||
141 | + | ||
142 | + | ||
143 | + DeviceDescriptions descs | ||
144 | + = createIfAbsentUnchecked(providerDescs, providerId, | ||
145 | + new InitDeviceDescs(deltaDesc)); | ||
146 | + | ||
147 | + // update description | ||
148 | + synchronized (providerDescs) { | ||
149 | + // locking per device | ||
150 | + | ||
151 | + final Device oldDevice = devices.get(deviceId); | ||
152 | + final Device newDevice; | ||
153 | + | ||
154 | + if (deltaDesc == descs.getDeviceDesc() || | ||
155 | + deltaDesc.isNewer(descs.getDeviceDesc())) { | ||
156 | + // on new device or valid update | ||
157 | + descs.putDeviceDesc(deltaDesc); | ||
158 | + newDevice = composeDevice(deviceId, providerDescs); | ||
159 | + } else { | ||
160 | + // outdated event, ignored. | ||
161 | + return null; | ||
162 | + } | ||
163 | + if (oldDevice == null) { | ||
164 | + // ADD | ||
165 | + return createDevice(providerId, newDevice); | ||
166 | + } else { | ||
167 | + // UPDATE or ignore (no change or stale) | ||
168 | + return updateDevice(providerId, oldDevice, newDevice); | ||
169 | + } | ||
170 | + } | ||
171 | + } | ||
172 | + | ||
173 | + // Creates the device and returns the appropriate event if necessary. | ||
174 | + // Guarded by deviceDescs value (=locking Device) | ||
175 | + private DeviceEvent createDevice(ProviderId providerId, | ||
176 | + Device newDevice) { | ||
177 | + | ||
178 | + // update composed device cache | ||
179 | + Device oldDevice = devices.putIfAbsent(newDevice.id(), newDevice); | ||
180 | + verify(oldDevice == null, | ||
181 | + "Unexpected Device in cache. PID:%s [old=%s, new=%s]", | ||
182 | + providerId, oldDevice, newDevice); | ||
183 | + | ||
184 | + if (!providerId.isAncillary()) { | ||
185 | + availableDevices.add(newDevice.id()); | ||
186 | + } | ||
187 | + | ||
188 | + return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, newDevice, null); | ||
189 | + } | ||
190 | + | ||
191 | + // Updates the device and returns the appropriate event if necessary. | ||
192 | + // Guarded by deviceDescs value (=locking Device) | ||
193 | + private DeviceEvent updateDevice(ProviderId providerId, | ||
194 | + Device oldDevice, Device newDevice) { | ||
195 | + | ||
196 | + // We allow only certain attributes to trigger update | ||
197 | + if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || | ||
198 | + !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()) || | ||
199 | + !isAnnotationsEqual(oldDevice.annotations(), newDevice.annotations())) { | ||
200 | + | ||
201 | + boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice); | ||
202 | + if (!replaced) { | ||
203 | + verify(replaced, | ||
204 | + "Replacing devices cache failed. PID:%s [expected:%s, found:%s, new=%s]", | ||
205 | + providerId, oldDevice, devices.get(newDevice.id()) | ||
206 | + , newDevice); | ||
207 | + } | ||
208 | + if (!providerId.isAncillary()) { | ||
209 | + availableDevices.add(newDevice.id()); | ||
210 | + } | ||
211 | + return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null); | ||
212 | + } | ||
213 | + | ||
214 | + // Otherwise merely attempt to change availability if primary provider | ||
215 | + if (!providerId.isAncillary()) { | ||
216 | + boolean added = availableDevices.add(newDevice.id()); | ||
217 | + return !added ? null : | ||
218 | + new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, newDevice, null); | ||
219 | + } | ||
220 | + return null; | ||
221 | + } | ||
222 | + | ||
223 | + @Override | ||
224 | + public DeviceEvent markOffline(DeviceId deviceId) { | ||
225 | + ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs | ||
226 | + = createIfAbsentUnchecked(deviceDescs, deviceId, | ||
227 | + new InitConcurrentHashMap<ProviderId, DeviceDescriptions>()); | ||
228 | + | ||
229 | + // locking device | ||
230 | + synchronized (providerDescs) { | ||
231 | + Device device = devices.get(deviceId); | ||
232 | + if (device == null) { | ||
233 | + return null; | ||
234 | + } | ||
235 | + boolean removed = availableDevices.remove(deviceId); | ||
236 | + if (removed) { | ||
237 | + // TODO: broadcast ... DOWN only? | ||
238 | + return new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null); | ||
239 | + | ||
240 | + } | ||
241 | + return null; | ||
242 | + } | ||
243 | + } | ||
244 | + | ||
245 | + @Override | ||
246 | + public synchronized List<DeviceEvent> updatePorts(ProviderId providerId, DeviceId deviceId, | ||
247 | + List<PortDescription> portDescriptions) { | ||
248 | + Timestamp newTimestamp = clockService.getTimestamp(deviceId); | ||
249 | + | ||
250 | + List<Timestamped<PortDescription>> deltaDescs = new ArrayList<>(portDescriptions.size()); | ||
251 | + for (PortDescription e : portDescriptions) { | ||
252 | + deltaDescs.add(new Timestamped<PortDescription>(e, newTimestamp)); | ||
253 | + } | ||
254 | + | ||
255 | + List<DeviceEvent> events = updatePortsInternal(providerId, deviceId, deltaDescs); | ||
256 | + if (!events.isEmpty()) { | ||
257 | + // FIXME: broadcast deltaDesc, UP | ||
258 | + log.debug("broadcast deltaDesc"); | ||
259 | + } | ||
260 | + return events; | ||
261 | + | ||
262 | + } | ||
263 | + | ||
264 | + private List<DeviceEvent> updatePortsInternal(ProviderId providerId, DeviceId deviceId, | ||
265 | + List<Timestamped<PortDescription>> deltaDescs) { | ||
266 | + | ||
267 | + Device device = devices.get(deviceId); | ||
268 | + checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
269 | + | ||
270 | + ConcurrentMap<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId); | ||
271 | + checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId); | ||
272 | + | ||
273 | + DeviceDescriptions descs = descsMap.get(providerId); | ||
274 | + // every provider must provide DeviceDescription. | ||
275 | + checkArgument(descs != null, | ||
276 | + "Device description for Device ID %s from Provider %s was not found", | ||
277 | + deviceId, providerId); | ||
278 | + | ||
279 | + List<DeviceEvent> events = new ArrayList<>(); | ||
280 | + synchronized (descsMap) { | ||
281 | + Map<PortNumber, Port> ports = getPortMap(deviceId); | ||
282 | + | ||
283 | + // Add new ports | ||
284 | + Set<PortNumber> processed = new HashSet<>(); | ||
285 | + for (Timestamped<PortDescription> deltaDesc : deltaDescs) { | ||
286 | + final PortNumber number = deltaDesc.value().portNumber(); | ||
287 | + final Port oldPort = ports.get(number); | ||
288 | + final Port newPort; | ||
289 | + | ||
290 | + final Timestamped<PortDescription> existingPortDesc = descs.getPortDesc(number); | ||
291 | + if (existingPortDesc == null || | ||
292 | + deltaDesc == existingPortDesc || | ||
293 | + deltaDesc.isNewer(existingPortDesc)) { | ||
294 | + // on new port or valid update | ||
295 | + // update description | ||
296 | + descs.putPortDesc(deltaDesc); | ||
297 | + newPort = composePort(device, number, descsMap); | ||
298 | + } else { | ||
299 | + // outdated event, ignored. | ||
300 | + continue; | ||
301 | + } | ||
302 | + | ||
303 | + events.add(oldPort == null ? | ||
304 | + createPort(device, newPort, ports) : | ||
305 | + updatePort(device, oldPort, newPort, ports)); | ||
306 | + processed.add(number); | ||
307 | + } | ||
308 | + | ||
309 | + events.addAll(pruneOldPorts(device, ports, processed)); | ||
310 | + } | ||
311 | + return FluentIterable.from(events).filter(notNull()).toList(); | ||
312 | + } | ||
313 | + | ||
314 | + // Creates a new port based on the port description adds it to the map and | ||
315 | + // Returns corresponding event. | ||
316 | + // Guarded by deviceDescs value (=locking Device) | ||
317 | + private DeviceEvent createPort(Device device, Port newPort, | ||
318 | + Map<PortNumber, Port> ports) { | ||
319 | + ports.put(newPort.number(), newPort); | ||
320 | + return new DeviceEvent(PORT_ADDED, device, newPort); | ||
321 | + } | ||
322 | + | ||
323 | + // Checks if the specified port requires update and if so, it replaces the | ||
324 | + // existing entry in the map and returns corresponding event. | ||
325 | + // Guarded by deviceDescs value (=locking Device) | ||
326 | + private DeviceEvent updatePort(Device device, Port oldPort, | ||
327 | + Port newPort, | ||
328 | + Map<PortNumber, Port> ports) { | ||
329 | + if (oldPort.isEnabled() != newPort.isEnabled() || | ||
330 | + !isAnnotationsEqual(oldPort.annotations(), newPort.annotations())) { | ||
331 | + | ||
332 | + ports.put(oldPort.number(), newPort); | ||
333 | + return new DeviceEvent(PORT_UPDATED, device, newPort); | ||
334 | + } | ||
335 | + return null; | ||
336 | + } | ||
337 | + | ||
338 | + // Prunes the specified list of ports based on which ports are in the | ||
339 | + // processed list and returns list of corresponding events. | ||
340 | + // Guarded by deviceDescs value (=locking Device) | ||
341 | + private List<DeviceEvent> pruneOldPorts(Device device, | ||
342 | + Map<PortNumber, Port> ports, | ||
343 | + Set<PortNumber> processed) { | ||
344 | + List<DeviceEvent> events = new ArrayList<>(); | ||
345 | + Iterator<PortNumber> iterator = ports.keySet().iterator(); | ||
346 | + while (iterator.hasNext()) { | ||
347 | + PortNumber portNumber = iterator.next(); | ||
348 | + if (!processed.contains(portNumber)) { | ||
349 | + events.add(new DeviceEvent(PORT_REMOVED, device, | ||
350 | + ports.get(portNumber))); | ||
351 | + iterator.remove(); | ||
352 | + } | ||
353 | + } | ||
354 | + return events; | ||
355 | + } | ||
356 | + | ||
357 | + // Gets the map of ports for the specified device; if one does not already | ||
358 | + // exist, it creates and registers a new one. | ||
359 | + private ConcurrentMap<PortNumber, Port> getPortMap(DeviceId deviceId) { | ||
360 | + return createIfAbsentUnchecked(devicePorts, deviceId, | ||
361 | + new InitConcurrentHashMap<PortNumber, Port>()); | ||
362 | + } | ||
363 | + | ||
364 | + @Override | ||
365 | + public synchronized DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, | ||
366 | + PortDescription portDescription) { | ||
367 | + Timestamp newTimestamp = clockService.getTimestamp(deviceId); | ||
368 | + final Timestamped<PortDescription> deltaDesc = new Timestamped<>(portDescription, newTimestamp); | ||
369 | + DeviceEvent event = updatePortStatusInternal(providerId, deviceId, deltaDesc); | ||
370 | + if (event != null) { | ||
371 | + // FIXME: broadcast deltaDesc | ||
372 | + log.debug("broadcast deltaDesc"); | ||
373 | + } | ||
374 | + return event; | ||
375 | + } | ||
376 | + | ||
377 | + private DeviceEvent updatePortStatusInternal(ProviderId providerId, DeviceId deviceId, | ||
378 | + Timestamped<PortDescription> deltaDesc) { | ||
379 | + | ||
380 | + Device device = devices.get(deviceId); | ||
381 | + checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
382 | + | ||
383 | + ConcurrentMap<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId); | ||
384 | + checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId); | ||
385 | + | ||
386 | + DeviceDescriptions descs = descsMap.get(providerId); | ||
387 | + // assuming all providers must to give DeviceDescription | ||
388 | + checkArgument(descs != null, | ||
389 | + "Device description for Device ID %s from Provider %s was not found", | ||
390 | + deviceId, providerId); | ||
391 | + | ||
392 | + synchronized (descsMap) { | ||
393 | + ConcurrentMap<PortNumber, Port> ports = getPortMap(deviceId); | ||
394 | + final PortNumber number = deltaDesc.value().portNumber(); | ||
395 | + final Port oldPort = ports.get(number); | ||
396 | + final Port newPort; | ||
397 | + | ||
398 | + final Timestamped<PortDescription> existingPortDesc = descs.getPortDesc(number); | ||
399 | + if (existingPortDesc == null || | ||
400 | + deltaDesc == existingPortDesc || | ||
401 | + deltaDesc.isNewer(existingPortDesc)) { | ||
402 | + // on new port or valid update | ||
403 | + // update description | ||
404 | + descs.putPortDesc(deltaDesc); | ||
405 | + newPort = composePort(device, number, descsMap); | ||
406 | + } else { | ||
407 | + // outdated event, ignored. | ||
408 | + return null; | ||
409 | + } | ||
410 | + | ||
411 | + if (oldPort == null) { | ||
412 | + return createPort(device, newPort, ports); | ||
413 | + } else { | ||
414 | + return updatePort(device, oldPort, newPort, ports); | ||
415 | + } | ||
416 | + } | ||
417 | + } | ||
418 | + | ||
419 | + @Override | ||
420 | + public List<Port> getPorts(DeviceId deviceId) { | ||
421 | + Map<PortNumber, Port> ports = devicePorts.get(deviceId); | ||
422 | + if (ports == null) { | ||
423 | + return Collections.emptyList(); | ||
424 | + } | ||
425 | + return ImmutableList.copyOf(ports.values()); | ||
426 | + } | ||
427 | + | ||
428 | + @Override | ||
429 | + public Port getPort(DeviceId deviceId, PortNumber portNumber) { | ||
430 | + Map<PortNumber, Port> ports = devicePorts.get(deviceId); | ||
431 | + return ports == null ? null : ports.get(portNumber); | ||
432 | + } | ||
433 | + | ||
434 | + @Override | ||
435 | + public boolean isAvailable(DeviceId deviceId) { | ||
436 | + return availableDevices.contains(deviceId); | ||
437 | + } | ||
438 | + | ||
439 | + @Override | ||
440 | + public DeviceEvent removeDevice(DeviceId deviceId) { | ||
441 | + synchronized (this) { | ||
442 | + Device device = devices.remove(deviceId); | ||
443 | + return device == null ? null : | ||
444 | + new DeviceEvent(DEVICE_REMOVED, device, null); | ||
445 | + } | ||
446 | + } | ||
447 | + | ||
448 | + private static boolean isAnnotationsEqual(Annotations lhs, Annotations rhs) { | ||
449 | + if (lhs == rhs) { | ||
450 | + return true; | ||
451 | + } | ||
452 | + if (lhs == null || rhs == null) { | ||
453 | + return false; | ||
454 | + } | ||
455 | + | ||
456 | + if (!lhs.keys().equals(rhs.keys())) { | ||
457 | + return false; | ||
458 | + } | ||
459 | + | ||
460 | + for (String key : lhs.keys()) { | ||
461 | + if (!lhs.value(key).equals(rhs.value(key))) { | ||
462 | + return false; | ||
463 | + } | ||
464 | + } | ||
465 | + return true; | ||
466 | + } | ||
467 | + | ||
468 | + /** | ||
469 | + * Returns a Device, merging description given from multiple Providers. | ||
470 | + * | ||
471 | + * @param deviceId device identifier | ||
472 | + * @param providerDescs Collection of Descriptions from multiple providers | ||
473 | + * @return Device instance | ||
474 | + */ | ||
475 | + private Device composeDevice(DeviceId deviceId, | ||
476 | + ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { | ||
477 | + | ||
478 | + checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied"); | ||
479 | + | ||
480 | + ProviderId primary = pickPrimaryPID(providerDescs); | ||
481 | + | ||
482 | + DeviceDescriptions desc = providerDescs.get(primary); | ||
483 | + | ||
484 | + DeviceDescription base = desc.getDeviceDesc().value(); | ||
485 | + Type type = base.type(); | ||
486 | + String manufacturer = base.manufacturer(); | ||
487 | + String hwVersion = base.hwVersion(); | ||
488 | + String swVersion = base.swVersion(); | ||
489 | + String serialNumber = base.serialNumber(); | ||
490 | + DefaultAnnotations annotations = DefaultAnnotations.builder().build(); | ||
491 | + annotations = merge(annotations, base.annotations()); | ||
492 | + | ||
493 | + for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) { | ||
494 | + if (e.getKey().equals(primary)) { | ||
495 | + continue; | ||
496 | + } | ||
497 | + // TODO: should keep track of Description timestamp | ||
498 | + // and only merge conflicting keys when timestamp is newer | ||
499 | + // Currently assuming there will never be a key conflict between | ||
500 | + // providers | ||
501 | + | ||
502 | + // annotation merging. not so efficient, should revisit later | ||
503 | + annotations = merge(annotations, e.getValue().getDeviceDesc().value().annotations()); | ||
504 | + } | ||
505 | + | ||
506 | + return new DefaultDevice(primary, deviceId , type, manufacturer, | ||
507 | + hwVersion, swVersion, serialNumber, annotations); | ||
508 | + } | ||
509 | + | ||
510 | + /** | ||
511 | + * Returns a Port, merging description given from multiple Providers. | ||
512 | + * | ||
513 | + * @param device device the port is on | ||
514 | + * @param number port number | ||
515 | + * @param providerDescs Collection of Descriptions from multiple providers | ||
516 | + * @return Port instance | ||
517 | + */ | ||
518 | + private Port composePort(Device device, PortNumber number, | ||
519 | + ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { | ||
520 | + | ||
521 | + ProviderId primary = pickPrimaryPID(providerDescs); | ||
522 | + DeviceDescriptions primDescs = providerDescs.get(primary); | ||
523 | + // if no primary, assume not enabled | ||
524 | + // TODO: revisit this default port enabled/disabled behavior | ||
525 | + boolean isEnabled = false; | ||
526 | + DefaultAnnotations annotations = DefaultAnnotations.builder().build(); | ||
527 | + | ||
528 | + final Timestamped<PortDescription> portDesc = primDescs.getPortDesc(number); | ||
529 | + if (portDesc != null) { | ||
530 | + isEnabled = portDesc.value().isEnabled(); | ||
531 | + annotations = merge(annotations, portDesc.value().annotations()); | ||
532 | + } | ||
533 | + | ||
534 | + for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) { | ||
535 | + if (e.getKey().equals(primary)) { | ||
536 | + continue; | ||
537 | + } | ||
538 | + // TODO: should keep track of Description timestamp | ||
539 | + // and only merge conflicting keys when timestamp is newer | ||
540 | + // Currently assuming there will never be a key conflict between | ||
541 | + // providers | ||
542 | + | ||
543 | + // annotation merging. not so efficient, should revisit later | ||
544 | + final Timestamped<PortDescription> otherPortDesc = e.getValue().getPortDesc(number); | ||
545 | + if (otherPortDesc != null) { | ||
546 | + annotations = merge(annotations, otherPortDesc.value().annotations()); | ||
547 | + } | ||
548 | + } | ||
549 | + | ||
550 | + return new DefaultPort(device, number, isEnabled, annotations); | ||
551 | + } | ||
552 | + | ||
553 | + /** | ||
554 | + * @return primary ProviderID, or randomly chosen one if none exists | ||
555 | + */ | ||
556 | + private ProviderId pickPrimaryPID( | ||
557 | + ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { | ||
558 | + ProviderId fallBackPrimary = null; | ||
559 | + for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) { | ||
560 | + if (!e.getKey().isAncillary()) { | ||
561 | + return e.getKey(); | ||
562 | + } else if (fallBackPrimary == null) { | ||
563 | + // pick randomly as a fallback in case there is no primary | ||
564 | + fallBackPrimary = e.getKey(); | ||
565 | + } | ||
566 | + } | ||
567 | + return fallBackPrimary; | ||
568 | + } | ||
569 | + | ||
570 | + private static final class InitConcurrentHashMap<K, V> implements | ||
571 | + ConcurrentInitializer<ConcurrentMap<K, V>> { | ||
572 | + @Override | ||
573 | + public ConcurrentMap<K, V> get() throws ConcurrentException { | ||
574 | + return new ConcurrentHashMap<>(); | ||
575 | + } | ||
576 | + } | ||
577 | + | ||
578 | + public static final class InitDeviceDescs | ||
579 | + implements ConcurrentInitializer<DeviceDescriptions> { | ||
580 | + | ||
581 | + private final Timestamped<DeviceDescription> deviceDesc; | ||
582 | + | ||
583 | + public InitDeviceDescs(Timestamped<DeviceDescription> deviceDesc) { | ||
584 | + this.deviceDesc = checkNotNull(deviceDesc); | ||
585 | + } | ||
586 | + @Override | ||
587 | + public DeviceDescriptions get() throws ConcurrentException { | ||
588 | + return new DeviceDescriptions(deviceDesc); | ||
589 | + } | ||
590 | + } | ||
591 | + | ||
592 | + | ||
593 | + /** | ||
594 | + * Collection of Description of a Device and it's Ports given from a Provider. | ||
595 | + */ | ||
596 | + public static class DeviceDescriptions { | ||
597 | + | ||
598 | + private final AtomicReference<Timestamped<DeviceDescription>> deviceDesc; | ||
599 | + private final ConcurrentMap<PortNumber, Timestamped<PortDescription>> portDescs; | ||
600 | + | ||
601 | + public DeviceDescriptions(Timestamped<DeviceDescription> desc) { | ||
602 | + this.deviceDesc = new AtomicReference<>(checkNotNull(desc)); | ||
603 | + this.portDescs = new ConcurrentHashMap<>(); | ||
604 | + } | ||
605 | + | ||
606 | + public Timestamped<DeviceDescription> getDeviceDesc() { | ||
607 | + return deviceDesc.get(); | ||
608 | + } | ||
609 | + | ||
610 | + public Timestamped<PortDescription> getPortDesc(PortNumber number) { | ||
611 | + return portDescs.get(number); | ||
612 | + } | ||
613 | + | ||
614 | + /** | ||
615 | + * Puts DeviceDescription, merging annotations as necessary. | ||
616 | + * | ||
617 | + * @param newDesc new DeviceDescription | ||
618 | + * @return previous DeviceDescription | ||
619 | + */ | ||
620 | + public synchronized Timestamped<DeviceDescription> putDeviceDesc(Timestamped<DeviceDescription> newDesc) { | ||
621 | + Timestamped<DeviceDescription> oldOne = deviceDesc.get(); | ||
622 | + Timestamped<DeviceDescription> newOne = newDesc; | ||
623 | + if (oldOne != null) { | ||
624 | + SparseAnnotations merged = merge(oldOne.value().annotations(), | ||
625 | + newDesc.value().annotations()); | ||
626 | + newOne = new Timestamped<DeviceDescription>( | ||
627 | + new DefaultDeviceDescription(newDesc.value(), merged), | ||
628 | + newDesc.timestamp()); | ||
629 | + } | ||
630 | + return deviceDesc.getAndSet(newOne); | ||
631 | + } | ||
632 | + | ||
633 | + /** | ||
634 | + * Puts PortDescription, merging annotations as necessary. | ||
635 | + * | ||
636 | + * @param newDesc new PortDescription | ||
637 | + * @return previous PortDescription | ||
638 | + */ | ||
639 | + public synchronized Timestamped<PortDescription> putPortDesc(Timestamped<PortDescription> newDesc) { | ||
640 | + Timestamped<PortDescription> oldOne = portDescs.get(newDesc.value().portNumber()); | ||
641 | + Timestamped<PortDescription> newOne = newDesc; | ||
642 | + if (oldOne != null) { | ||
643 | + SparseAnnotations merged = merge(oldOne.value().annotations(), | ||
644 | + newDesc.value().annotations()); | ||
645 | + newOne = new Timestamped<PortDescription>( | ||
646 | + new DefaultPortDescription(newDesc.value(), merged), | ||
647 | + newDesc.timestamp()); | ||
648 | + } | ||
649 | + return portDescs.put(newOne.value().portNumber(), newOne); | ||
650 | + } | ||
651 | + } | ||
652 | +} |
1 | -package org.onlab.onos.store.device.impl; | ||
2 | - | ||
3 | -import static com.google.common.base.Predicates.notNull; | ||
4 | -import static com.google.common.base.Preconditions.checkState; | ||
5 | - | ||
6 | -import com.google.common.collect.FluentIterable; | ||
7 | -import com.google.common.collect.ImmutableSet; | ||
8 | -import com.google.common.collect.ImmutableSet.Builder; | ||
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.Reference; | ||
14 | -import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
15 | -import org.apache.felix.scr.annotations.Service; | ||
16 | -import org.onlab.onos.net.DefaultDevice; | ||
17 | -import org.onlab.onos.net.DefaultPort; | ||
18 | -import org.onlab.onos.net.Device; | ||
19 | -import org.onlab.onos.net.DeviceId; | ||
20 | -import org.onlab.onos.net.Port; | ||
21 | -import org.onlab.onos.net.PortNumber; | ||
22 | -import org.onlab.onos.net.device.DeviceDescription; | ||
23 | -import org.onlab.onos.net.device.DeviceEvent; | ||
24 | -import org.onlab.onos.net.device.DeviceStore; | ||
25 | -import org.onlab.onos.net.device.DeviceStoreDelegate; | ||
26 | -import org.onlab.onos.net.device.PortDescription; | ||
27 | -import org.onlab.onos.net.provider.ProviderId; | ||
28 | -import org.onlab.onos.store.AbstractStore; | ||
29 | -import org.onlab.onos.store.ClockService; | ||
30 | -import org.onlab.onos.store.Timestamp; | ||
31 | -import org.slf4j.Logger; | ||
32 | - | ||
33 | -import java.util.ArrayList; | ||
34 | -import java.util.Collections; | ||
35 | -import java.util.HashMap; | ||
36 | -import java.util.HashSet; | ||
37 | -import java.util.Iterator; | ||
38 | -import java.util.List; | ||
39 | -import java.util.Map; | ||
40 | -import java.util.Objects; | ||
41 | -import java.util.Set; | ||
42 | -import java.util.concurrent.ConcurrentHashMap; | ||
43 | -import java.util.concurrent.ConcurrentMap; | ||
44 | - | ||
45 | -import static com.google.common.base.Preconditions.checkArgument; | ||
46 | -import static org.onlab.onos.net.device.DeviceEvent.Type.*; | ||
47 | -import static org.slf4j.LoggerFactory.getLogger; | ||
48 | - | ||
49 | -/** | ||
50 | - * Manages inventory of infrastructure devices using a protocol that takes into consideration | ||
51 | - * the order in which device events occur. | ||
52 | - */ | ||
53 | -@Component(immediate = true) | ||
54 | -@Service | ||
55 | -public class OnosDistributedDeviceStore | ||
56 | - extends AbstractStore<DeviceEvent, DeviceStoreDelegate> | ||
57 | - implements DeviceStore { | ||
58 | - | ||
59 | - private final Logger log = getLogger(getClass()); | ||
60 | - | ||
61 | - public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; | ||
62 | - | ||
63 | - private ConcurrentMap<DeviceId, VersionedValue<Device>> devices; | ||
64 | - private ConcurrentMap<DeviceId, Map<PortNumber, VersionedValue<Port>>> devicePorts; | ||
65 | - | ||
66 | - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
67 | - protected ClockService clockService; | ||
68 | - | ||
69 | - @Activate | ||
70 | - public void activate() { | ||
71 | - | ||
72 | - devices = new ConcurrentHashMap<>(); | ||
73 | - devicePorts = new ConcurrentHashMap<>(); | ||
74 | - | ||
75 | - log.info("Started"); | ||
76 | - } | ||
77 | - | ||
78 | - @Deactivate | ||
79 | - public void deactivate() { | ||
80 | - log.info("Stopped"); | ||
81 | - } | ||
82 | - | ||
83 | - @Override | ||
84 | - public int getDeviceCount() { | ||
85 | - return devices.size(); | ||
86 | - } | ||
87 | - | ||
88 | - @Override | ||
89 | - public Iterable<Device> getDevices() { | ||
90 | - Builder<Device> builder = ImmutableSet.builder(); | ||
91 | - synchronized (this) { | ||
92 | - for (VersionedValue<Device> device : devices.values()) { | ||
93 | - builder.add(device.entity()); | ||
94 | - } | ||
95 | - return builder.build(); | ||
96 | - } | ||
97 | - } | ||
98 | - | ||
99 | - @Override | ||
100 | - public Device getDevice(DeviceId deviceId) { | ||
101 | - VersionedValue<Device> device = devices.get(deviceId); | ||
102 | - checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
103 | - return device.entity(); | ||
104 | - } | ||
105 | - | ||
106 | - @Override | ||
107 | - public DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, | ||
108 | - DeviceDescription deviceDescription) { | ||
109 | - Timestamp newTimestamp = clockService.getTimestamp(deviceId); | ||
110 | - VersionedValue<Device> device = devices.get(deviceId); | ||
111 | - | ||
112 | - if (device == null) { | ||
113 | - return createDevice(providerId, deviceId, deviceDescription, newTimestamp); | ||
114 | - } | ||
115 | - | ||
116 | - checkState(newTimestamp.compareTo(device.timestamp()) > 0, | ||
117 | - "Existing device has a timestamp in the future!"); | ||
118 | - | ||
119 | - return updateDevice(providerId, device.entity(), deviceDescription, newTimestamp); | ||
120 | - } | ||
121 | - | ||
122 | - // Creates the device and returns the appropriate event if necessary. | ||
123 | - private DeviceEvent createDevice(ProviderId providerId, DeviceId deviceId, | ||
124 | - DeviceDescription desc, Timestamp timestamp) { | ||
125 | - Device device = new DefaultDevice(providerId, deviceId, desc.type(), | ||
126 | - desc.manufacturer(), | ||
127 | - desc.hwVersion(), desc.swVersion(), | ||
128 | - desc.serialNumber()); | ||
129 | - | ||
130 | - devices.put(deviceId, new VersionedValue<>(device, true, timestamp)); | ||
131 | - // TODO,FIXME: broadcast a message telling peers of a device event. | ||
132 | - return new DeviceEvent(DEVICE_ADDED, device, null); | ||
133 | - } | ||
134 | - | ||
135 | - // Updates the device and returns the appropriate event if necessary. | ||
136 | - private DeviceEvent updateDevice(ProviderId providerId, Device device, | ||
137 | - DeviceDescription desc, Timestamp timestamp) { | ||
138 | - // We allow only certain attributes to trigger update | ||
139 | - if (!Objects.equals(device.hwVersion(), desc.hwVersion()) || | ||
140 | - !Objects.equals(device.swVersion(), desc.swVersion())) { | ||
141 | - | ||
142 | - Device updated = new DefaultDevice(providerId, device.id(), | ||
143 | - desc.type(), | ||
144 | - desc.manufacturer(), | ||
145 | - desc.hwVersion(), | ||
146 | - desc.swVersion(), | ||
147 | - desc.serialNumber()); | ||
148 | - devices.put(device.id(), new VersionedValue<Device>(updated, true, timestamp)); | ||
149 | - // FIXME: broadcast a message telling peers of a device event. | ||
150 | - return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, updated, null); | ||
151 | - } | ||
152 | - | ||
153 | - // Otherwise merely attempt to change availability | ||
154 | - Device updated = new DefaultDevice(providerId, device.id(), | ||
155 | - desc.type(), | ||
156 | - desc.manufacturer(), | ||
157 | - desc.hwVersion(), | ||
158 | - desc.swVersion(), | ||
159 | - desc.serialNumber()); | ||
160 | - | ||
161 | - VersionedValue<Device> oldDevice = devices.put(device.id(), | ||
162 | - new VersionedValue<Device>(updated, true, timestamp)); | ||
163 | - if (!oldDevice.isUp()) { | ||
164 | - return new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null); | ||
165 | - } else { | ||
166 | - return null; | ||
167 | - } | ||
168 | - } | ||
169 | - | ||
170 | - @Override | ||
171 | - public DeviceEvent markOffline(DeviceId deviceId) { | ||
172 | - VersionedValue<Device> device = devices.get(deviceId); | ||
173 | - boolean willRemove = device != null && device.isUp(); | ||
174 | - if (!willRemove) { | ||
175 | - return null; | ||
176 | - } | ||
177 | - Timestamp timestamp = clockService.getTimestamp(deviceId); | ||
178 | - if (replaceIfLatest(device.entity(), false, timestamp)) { | ||
179 | - return new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device.entity(), null); | ||
180 | - } | ||
181 | - return null; | ||
182 | - } | ||
183 | - | ||
184 | - // Replace existing value if its timestamp is older. | ||
185 | - private synchronized boolean replaceIfLatest(Device device, boolean isUp, Timestamp timestamp) { | ||
186 | - VersionedValue<Device> existingValue = devices.get(device.id()); | ||
187 | - if (timestamp.compareTo(existingValue.timestamp()) > 0) { | ||
188 | - devices.put(device.id(), new VersionedValue<Device>(device, isUp, timestamp)); | ||
189 | - return true; | ||
190 | - } | ||
191 | - return false; | ||
192 | - } | ||
193 | - | ||
194 | - @Override | ||
195 | - public List<DeviceEvent> updatePorts(ProviderId providerId, DeviceId deviceId, | ||
196 | - List<PortDescription> portDescriptions) { | ||
197 | - List<DeviceEvent> events = new ArrayList<>(); | ||
198 | - synchronized (this) { | ||
199 | - VersionedValue<Device> device = devices.get(deviceId); | ||
200 | - checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
201 | - Map<PortNumber, VersionedValue<Port>> ports = getPortMap(deviceId); | ||
202 | - Timestamp newTimestamp = clockService.getTimestamp(deviceId); | ||
203 | - | ||
204 | - // Add new ports | ||
205 | - Set<PortNumber> processed = new HashSet<>(); | ||
206 | - for (PortDescription portDescription : portDescriptions) { | ||
207 | - VersionedValue<Port> port = ports.get(portDescription.portNumber()); | ||
208 | - if (port == null) { | ||
209 | - events.add(createPort(device, portDescription, ports, newTimestamp)); | ||
210 | - } | ||
211 | - checkState(newTimestamp.compareTo(port.timestamp()) > 0, | ||
212 | - "Existing port state has a timestamp in the future!"); | ||
213 | - events.add(updatePort(device.entity(), port.entity(), portDescription, ports, newTimestamp)); | ||
214 | - processed.add(portDescription.portNumber()); | ||
215 | - } | ||
216 | - | ||
217 | - updatePortMap(deviceId, ports); | ||
218 | - | ||
219 | - events.addAll(pruneOldPorts(device.entity(), ports, processed)); | ||
220 | - } | ||
221 | - return FluentIterable.from(events).filter(notNull()).toList(); | ||
222 | - } | ||
223 | - | ||
224 | - // Creates a new port based on the port description adds it to the map and | ||
225 | - // Returns corresponding event. | ||
226 | - //@GuardedBy("this") | ||
227 | - private DeviceEvent createPort(VersionedValue<Device> device, PortDescription portDescription, | ||
228 | - Map<PortNumber, VersionedValue<Port>> ports, Timestamp timestamp) { | ||
229 | - Port port = new DefaultPort(device.entity(), portDescription.portNumber(), | ||
230 | - portDescription.isEnabled()); | ||
231 | - ports.put(port.number(), new VersionedValue<Port>(port, true, timestamp)); | ||
232 | - updatePortMap(device.entity().id(), ports); | ||
233 | - return new DeviceEvent(PORT_ADDED, device.entity(), port); | ||
234 | - } | ||
235 | - | ||
236 | - // Checks if the specified port requires update and if so, it replaces the | ||
237 | - // existing entry in the map and returns corresponding event. | ||
238 | - //@GuardedBy("this") | ||
239 | - private DeviceEvent updatePort(Device device, Port port, | ||
240 | - PortDescription portDescription, | ||
241 | - Map<PortNumber, VersionedValue<Port>> ports, | ||
242 | - Timestamp timestamp) { | ||
243 | - if (port.isEnabled() != portDescription.isEnabled()) { | ||
244 | - VersionedValue<Port> updatedPort = new VersionedValue<Port>( | ||
245 | - new DefaultPort(device, portDescription.portNumber(), | ||
246 | - portDescription.isEnabled()), | ||
247 | - portDescription.isEnabled(), | ||
248 | - timestamp); | ||
249 | - ports.put(port.number(), updatedPort); | ||
250 | - updatePortMap(device.id(), ports); | ||
251 | - return new DeviceEvent(PORT_UPDATED, device, updatedPort.entity()); | ||
252 | - } | ||
253 | - return null; | ||
254 | - } | ||
255 | - | ||
256 | - // Prunes the specified list of ports based on which ports are in the | ||
257 | - // processed list and returns list of corresponding events. | ||
258 | - //@GuardedBy("this") | ||
259 | - private List<DeviceEvent> pruneOldPorts(Device device, | ||
260 | - Map<PortNumber, VersionedValue<Port>> ports, | ||
261 | - Set<PortNumber> processed) { | ||
262 | - List<DeviceEvent> events = new ArrayList<>(); | ||
263 | - Iterator<PortNumber> iterator = ports.keySet().iterator(); | ||
264 | - while (iterator.hasNext()) { | ||
265 | - PortNumber portNumber = iterator.next(); | ||
266 | - if (!processed.contains(portNumber)) { | ||
267 | - events.add(new DeviceEvent(PORT_REMOVED, device, | ||
268 | - ports.get(portNumber).entity())); | ||
269 | - iterator.remove(); | ||
270 | - } | ||
271 | - } | ||
272 | - if (!events.isEmpty()) { | ||
273 | - updatePortMap(device.id(), ports); | ||
274 | - } | ||
275 | - return events; | ||
276 | - } | ||
277 | - | ||
278 | - // Gets the map of ports for the specified device; if one does not already | ||
279 | - // exist, it creates and registers a new one. | ||
280 | - // WARN: returned value is a copy, changes made to the Map | ||
281 | - // needs to be written back using updatePortMap | ||
282 | - //@GuardedBy("this") | ||
283 | - private Map<PortNumber, VersionedValue<Port>> getPortMap(DeviceId deviceId) { | ||
284 | - Map<PortNumber, VersionedValue<Port>> ports = devicePorts.get(deviceId); | ||
285 | - if (ports == null) { | ||
286 | - ports = new HashMap<>(); | ||
287 | - // this probably is waste of time in most cases. | ||
288 | - updatePortMap(deviceId, ports); | ||
289 | - } | ||
290 | - return ports; | ||
291 | - } | ||
292 | - | ||
293 | - //@GuardedBy("this") | ||
294 | - private void updatePortMap(DeviceId deviceId, Map<PortNumber, VersionedValue<Port>> ports) { | ||
295 | - devicePorts.put(deviceId, ports); | ||
296 | - } | ||
297 | - | ||
298 | - @Override | ||
299 | - public DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, | ||
300 | - PortDescription portDescription) { | ||
301 | - VersionedValue<Device> device = devices.get(deviceId); | ||
302 | - checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
303 | - Map<PortNumber, VersionedValue<Port>> ports = getPortMap(deviceId); | ||
304 | - VersionedValue<Port> port = ports.get(portDescription.portNumber()); | ||
305 | - Timestamp timestamp = clockService.getTimestamp(deviceId); | ||
306 | - return updatePort(device.entity(), port.entity(), portDescription, ports, timestamp); | ||
307 | - } | ||
308 | - | ||
309 | - @Override | ||
310 | - public List<Port> getPorts(DeviceId deviceId) { | ||
311 | - Map<PortNumber, VersionedValue<Port>> versionedPorts = devicePorts.get(deviceId); | ||
312 | - if (versionedPorts == null) { | ||
313 | - return Collections.emptyList(); | ||
314 | - } | ||
315 | - List<Port> ports = new ArrayList<>(); | ||
316 | - for (VersionedValue<Port> port : versionedPorts.values()) { | ||
317 | - ports.add(port.entity()); | ||
318 | - } | ||
319 | - return ports; | ||
320 | - } | ||
321 | - | ||
322 | - @Override | ||
323 | - public Port getPort(DeviceId deviceId, PortNumber portNumber) { | ||
324 | - Map<PortNumber, VersionedValue<Port>> ports = devicePorts.get(deviceId); | ||
325 | - return ports == null ? null : ports.get(portNumber).entity(); | ||
326 | - } | ||
327 | - | ||
328 | - @Override | ||
329 | - public boolean isAvailable(DeviceId deviceId) { | ||
330 | - return devices.get(deviceId).isUp(); | ||
331 | - } | ||
332 | - | ||
333 | - @Override | ||
334 | - public DeviceEvent removeDevice(DeviceId deviceId) { | ||
335 | - VersionedValue<Device> previousDevice = devices.remove(deviceId); | ||
336 | - return previousDevice == null ? null : | ||
337 | - new DeviceEvent(DEVICE_REMOVED, previousDevice.entity(), null); | ||
338 | - } | ||
339 | -} |
... | @@ -42,6 +42,7 @@ import com.google.common.collect.ImmutableSet.Builder; | ... | @@ -42,6 +42,7 @@ import com.google.common.collect.ImmutableSet.Builder; |
42 | import static com.google.common.base.Preconditions.checkArgument; | 42 | import static com.google.common.base.Preconditions.checkArgument; |
43 | import static com.google.common.base.Preconditions.checkState; | 43 | import static com.google.common.base.Preconditions.checkState; |
44 | 44 | ||
45 | +//TODO: Add support for multiple provider and annotations | ||
45 | /** | 46 | /** |
46 | * Manages inventory of infrastructure links using a protocol that takes into consideration | 47 | * Manages inventory of infrastructure links using a protocol that takes into consideration |
47 | * the order in which events occur. | 48 | * the order in which events occur. | ... | ... |
1 | package org.onlab.onos.store.serializers; | 1 | package org.onlab.onos.store.serializers; |
2 | 2 | ||
3 | -import org.onlab.onos.store.impl.OnosTimestamp; | 3 | +import org.onlab.onos.store.common.impl.MastershipBasedTimestamp; |
4 | 4 | ||
5 | import com.esotericsoftware.kryo.Kryo; | 5 | import com.esotericsoftware.kryo.Kryo; |
6 | import com.esotericsoftware.kryo.Serializer; | 6 | import com.esotericsoftware.kryo.Serializer; |
7 | import com.esotericsoftware.kryo.io.Input; | 7 | import com.esotericsoftware.kryo.io.Input; |
8 | import com.esotericsoftware.kryo.io.Output; | 8 | import com.esotericsoftware.kryo.io.Output; |
9 | 9 | ||
10 | +// To be used if Timestamp ever needs to cross bundle boundary. | ||
10 | /** | 11 | /** |
11 | - * Kryo Serializer for {@link OnosTimestamp}. | 12 | + * Kryo Serializer for {@link MastershipBasedTimestamp}. |
12 | */ | 13 | */ |
13 | -public class OnosTimestampSerializer extends Serializer<OnosTimestamp> { | 14 | +public class MastershipBasedTimestampSerializer extends Serializer<MastershipBasedTimestamp> { |
14 | 15 | ||
15 | /** | 16 | /** |
16 | * Default constructor. | 17 | * Default constructor. |
17 | */ | 18 | */ |
18 | - public OnosTimestampSerializer() { | 19 | + public MastershipBasedTimestampSerializer() { |
19 | // non-null, immutable | 20 | // non-null, immutable |
20 | super(false, true); | 21 | super(false, true); |
21 | } | 22 | } |
22 | 23 | ||
23 | @Override | 24 | @Override |
24 | - public void write(Kryo kryo, Output output, OnosTimestamp object) { | 25 | + public void write(Kryo kryo, Output output, MastershipBasedTimestamp object) { |
25 | output.writeInt(object.termNumber()); | 26 | output.writeInt(object.termNumber()); |
26 | output.writeInt(object.sequenceNumber()); | 27 | output.writeInt(object.sequenceNumber()); |
27 | } | 28 | } |
28 | 29 | ||
29 | @Override | 30 | @Override |
30 | - public OnosTimestamp read(Kryo kryo, Input input, Class<OnosTimestamp> type) { | 31 | + public MastershipBasedTimestamp read(Kryo kryo, Input input, Class<MastershipBasedTimestamp> type) { |
31 | final int term = input.readInt(); | 32 | final int term = input.readInt(); |
32 | final int sequence = input.readInt(); | 33 | final int sequence = input.readInt(); |
33 | - return new OnosTimestamp(term, sequence); | 34 | + return new MastershipBasedTimestamp(term, sequence); |
34 | } | 35 | } |
35 | } | 36 | } | ... | ... |
core/store/dist/src/test/java/org/onlab/onos/store/common/impl/MastershipBasedTimestampTest.java
0 → 100644
1 | +package org.onlab.onos.store.common.impl; | ||
2 | + | ||
3 | +import static org.junit.Assert.*; | ||
4 | + | ||
5 | +import java.nio.ByteBuffer; | ||
6 | + | ||
7 | +import org.junit.Test; | ||
8 | +import org.onlab.onos.store.Timestamp; | ||
9 | +import org.onlab.onos.store.serializers.MastershipBasedTimestampSerializer; | ||
10 | +import org.onlab.util.KryoPool; | ||
11 | + | ||
12 | +import com.google.common.testing.EqualsTester; | ||
13 | + | ||
14 | +/** | ||
15 | + * Test of {@link MastershipBasedTimestamp}. | ||
16 | + */ | ||
17 | +public class MastershipBasedTimestampTest { | ||
18 | + | ||
19 | + private static final Timestamp TS_1_1 = new MastershipBasedTimestamp(1, 1); | ||
20 | + private static final Timestamp TS_1_2 = new MastershipBasedTimestamp(1, 2); | ||
21 | + private static final Timestamp TS_2_1 = new MastershipBasedTimestamp(2, 1); | ||
22 | + private static final Timestamp TS_2_2 = new MastershipBasedTimestamp(2, 2); | ||
23 | + | ||
24 | + @Test | ||
25 | + public final void testBasic() { | ||
26 | + final int termNumber = 5; | ||
27 | + final int sequenceNumber = 6; | ||
28 | + MastershipBasedTimestamp ts = new MastershipBasedTimestamp(termNumber, | ||
29 | + sequenceNumber); | ||
30 | + | ||
31 | + assertEquals(termNumber, ts.termNumber()); | ||
32 | + assertEquals(sequenceNumber, ts.sequenceNumber()); | ||
33 | + } | ||
34 | + | ||
35 | + @Test | ||
36 | + public final void testCompareTo() { | ||
37 | + assertTrue(TS_1_1.compareTo(TS_1_1) == 0); | ||
38 | + assertTrue(TS_1_1.compareTo(new MastershipBasedTimestamp(1, 1)) == 0); | ||
39 | + | ||
40 | + assertTrue(TS_1_1.compareTo(TS_1_2) < 0); | ||
41 | + assertTrue(TS_1_2.compareTo(TS_1_1) > 0); | ||
42 | + | ||
43 | + assertTrue(TS_1_2.compareTo(TS_2_1) < 0); | ||
44 | + assertTrue(TS_1_2.compareTo(TS_2_2) < 0); | ||
45 | + assertTrue(TS_2_1.compareTo(TS_1_1) > 0); | ||
46 | + assertTrue(TS_2_2.compareTo(TS_1_1) > 0); | ||
47 | + } | ||
48 | + | ||
49 | + @Test | ||
50 | + public final void testEqualsObject() { | ||
51 | + new EqualsTester() | ||
52 | + .addEqualityGroup(new MastershipBasedTimestamp(1, 1), | ||
53 | + new MastershipBasedTimestamp(1, 1), TS_1_1) | ||
54 | + .addEqualityGroup(new MastershipBasedTimestamp(1, 2), | ||
55 | + new MastershipBasedTimestamp(1, 2), TS_1_2) | ||
56 | + .addEqualityGroup(new MastershipBasedTimestamp(2, 1), | ||
57 | + new MastershipBasedTimestamp(2, 1), TS_2_1) | ||
58 | + .addEqualityGroup(new MastershipBasedTimestamp(2, 2), | ||
59 | + new MastershipBasedTimestamp(2, 2), TS_2_2) | ||
60 | + .testEquals(); | ||
61 | + } | ||
62 | + | ||
63 | + @Test | ||
64 | + public final void testKryoSerializable() { | ||
65 | + final ByteBuffer buffer = ByteBuffer.allocate(1 * 1024 * 1024); | ||
66 | + final KryoPool kryos = KryoPool.newBuilder() | ||
67 | + .register(MastershipBasedTimestamp.class) | ||
68 | + .build(); | ||
69 | + | ||
70 | + kryos.serialize(TS_2_1, buffer); | ||
71 | + buffer.flip(); | ||
72 | + Timestamp copy = kryos.deserialize(buffer); | ||
73 | + | ||
74 | + new EqualsTester() | ||
75 | + .addEqualityGroup(TS_2_1, copy) | ||
76 | + .testEquals(); | ||
77 | + } | ||
78 | + | ||
79 | + @Test | ||
80 | + public final void testKryoSerializableWithHandcraftedSerializer() { | ||
81 | + final ByteBuffer buffer = ByteBuffer.allocate(1 * 1024 * 1024); | ||
82 | + final KryoPool kryos = KryoPool.newBuilder() | ||
83 | + .register(MastershipBasedTimestamp.class, new MastershipBasedTimestampSerializer()) | ||
84 | + .build(); | ||
85 | + | ||
86 | + kryos.serialize(TS_1_2, buffer); | ||
87 | + buffer.flip(); | ||
88 | + Timestamp copy = kryos.deserialize(buffer); | ||
89 | + | ||
90 | + new EqualsTester() | ||
91 | + .addEqualityGroup(TS_1_2, copy) | ||
92 | + .testEquals(); | ||
93 | + } | ||
94 | + | ||
95 | +} |
1 | +package org.onlab.onos.store.common.impl; | ||
2 | + | ||
3 | +import static org.junit.Assert.*; | ||
4 | + | ||
5 | +import java.nio.ByteBuffer; | ||
6 | + | ||
7 | +import org.junit.Test; | ||
8 | +import org.onlab.onos.store.Timestamp; | ||
9 | +import org.onlab.util.KryoPool; | ||
10 | + | ||
11 | +import com.google.common.testing.EqualsTester; | ||
12 | + | ||
13 | +/** | ||
14 | + * Test of {@link Timestamped}. | ||
15 | + */ | ||
16 | +public class TimestampedTest { | ||
17 | + | ||
18 | + private static final Timestamp TS_1_1 = new MastershipBasedTimestamp(1, 1); | ||
19 | + private static final Timestamp TS_1_2 = new MastershipBasedTimestamp(1, 2); | ||
20 | + private static final Timestamp TS_2_1 = new MastershipBasedTimestamp(2, 1); | ||
21 | + | ||
22 | + @Test | ||
23 | + public final void testHashCode() { | ||
24 | + Timestamped<String> a = new Timestamped<>("a", TS_1_1); | ||
25 | + Timestamped<String> b = new Timestamped<>("b", TS_1_1); | ||
26 | + assertTrue("value does not impact hashCode", | ||
27 | + a.hashCode() == b.hashCode()); | ||
28 | + } | ||
29 | + | ||
30 | + @Test | ||
31 | + public final void testEquals() { | ||
32 | + Timestamped<String> a = new Timestamped<>("a", TS_1_1); | ||
33 | + Timestamped<String> b = new Timestamped<>("b", TS_1_1); | ||
34 | + assertTrue("value does not impact equality", | ||
35 | + a.equals(b)); | ||
36 | + | ||
37 | + new EqualsTester() | ||
38 | + .addEqualityGroup(new Timestamped<>("a", TS_1_1), | ||
39 | + new Timestamped<>("b", TS_1_1), | ||
40 | + new Timestamped<>("c", TS_1_1)) | ||
41 | + .addEqualityGroup(new Timestamped<>("a", TS_1_2), | ||
42 | + new Timestamped<>("b", TS_1_2), | ||
43 | + new Timestamped<>("c", TS_1_2)) | ||
44 | + .addEqualityGroup(new Timestamped<>("a", TS_2_1), | ||
45 | + new Timestamped<>("b", TS_2_1), | ||
46 | + new Timestamped<>("c", TS_2_1)) | ||
47 | + .testEquals(); | ||
48 | + | ||
49 | + } | ||
50 | + | ||
51 | + @Test | ||
52 | + public final void testValue() { | ||
53 | + final Integer n = Integer.valueOf(42); | ||
54 | + Timestamped<Integer> tsv = new Timestamped<>(n, TS_1_1); | ||
55 | + assertSame(n, tsv.value()); | ||
56 | + | ||
57 | + } | ||
58 | + | ||
59 | + @Test(expected = NullPointerException.class) | ||
60 | + public final void testValueNonNull() { | ||
61 | + new Timestamped<>(null, TS_1_1); | ||
62 | + } | ||
63 | + | ||
64 | + @Test(expected = NullPointerException.class) | ||
65 | + public final void testTimestampNonNull() { | ||
66 | + new Timestamped<>("Foo", null); | ||
67 | + } | ||
68 | + | ||
69 | + @Test | ||
70 | + public final void testIsNewer() { | ||
71 | + Timestamped<String> a = new Timestamped<>("a", TS_1_2); | ||
72 | + Timestamped<String> b = new Timestamped<>("b", TS_1_1); | ||
73 | + assertTrue(a.isNewer(b)); | ||
74 | + assertFalse(b.isNewer(a)); | ||
75 | + } | ||
76 | + | ||
77 | + @Test | ||
78 | + public final void testKryoSerializable() { | ||
79 | + final ByteBuffer buffer = ByteBuffer.allocate(1 * 1024 * 1024); | ||
80 | + final KryoPool kryos = KryoPool.newBuilder() | ||
81 | + .register(Timestamped.class, | ||
82 | + MastershipBasedTimestamp.class) | ||
83 | + .build(); | ||
84 | + | ||
85 | + Timestamped<String> original = new Timestamped<>("foobar", TS_1_1); | ||
86 | + kryos.serialize(original, buffer); | ||
87 | + buffer.flip(); | ||
88 | + Timestamped<String> copy = kryos.deserialize(buffer); | ||
89 | + | ||
90 | + new EqualsTester() | ||
91 | + .addEqualityGroup(original, copy) | ||
92 | + .testEquals(); | ||
93 | + } | ||
94 | +} |
core/store/dist/src/test/java/org/onlab/onos/store/device/impl/GossipDeviceStoreTest.java
0 → 100644
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import static org.junit.Assert.*; | ||
4 | +import static org.onlab.onos.net.Device.Type.SWITCH; | ||
5 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
6 | +import static org.onlab.onos.net.device.DeviceEvent.Type.*; | ||
7 | + | ||
8 | +import java.util.Arrays; | ||
9 | +import java.util.HashMap; | ||
10 | +import java.util.List; | ||
11 | +import java.util.Map; | ||
12 | +import java.util.Set; | ||
13 | +import java.util.concurrent.CountDownLatch; | ||
14 | +import java.util.concurrent.TimeUnit; | ||
15 | + | ||
16 | +import org.junit.After; | ||
17 | +import org.junit.AfterClass; | ||
18 | +import org.junit.Before; | ||
19 | +import org.junit.BeforeClass; | ||
20 | +import org.junit.Ignore; | ||
21 | +import org.junit.Test; | ||
22 | +import org.onlab.onos.cluster.MastershipTerm; | ||
23 | +import org.onlab.onos.cluster.NodeId; | ||
24 | +import org.onlab.onos.net.Annotations; | ||
25 | +import org.onlab.onos.net.DefaultAnnotations; | ||
26 | +import org.onlab.onos.net.Device; | ||
27 | +import org.onlab.onos.net.DeviceId; | ||
28 | +import org.onlab.onos.net.Port; | ||
29 | +import org.onlab.onos.net.PortNumber; | ||
30 | +import org.onlab.onos.net.SparseAnnotations; | ||
31 | +import org.onlab.onos.net.device.DefaultDeviceDescription; | ||
32 | +import org.onlab.onos.net.device.DefaultPortDescription; | ||
33 | +import org.onlab.onos.net.device.DeviceDescription; | ||
34 | +import org.onlab.onos.net.device.DeviceEvent; | ||
35 | +import org.onlab.onos.net.device.DeviceStore; | ||
36 | +import org.onlab.onos.net.device.DeviceStoreDelegate; | ||
37 | +import org.onlab.onos.net.device.PortDescription; | ||
38 | +import org.onlab.onos.net.provider.ProviderId; | ||
39 | +import org.onlab.onos.store.ClockService; | ||
40 | + | ||
41 | +import com.google.common.collect.Iterables; | ||
42 | +import com.google.common.collect.Sets; | ||
43 | + | ||
44 | + | ||
45 | +// TODO add tests for remote replication | ||
46 | +/** | ||
47 | + * Test of the gossip based distributed DeviceStore implementation. | ||
48 | + */ | ||
49 | +public class GossipDeviceStoreTest { | ||
50 | + | ||
51 | + private static final ProviderId PID = new ProviderId("of", "foo"); | ||
52 | + private static final ProviderId PIDA = new ProviderId("of", "bar", true); | ||
53 | + private static final DeviceId DID1 = deviceId("of:foo"); | ||
54 | + private static final DeviceId DID2 = deviceId("of:bar"); | ||
55 | + private static final String MFR = "whitebox"; | ||
56 | + private static final String HW = "1.1.x"; | ||
57 | + private static final String SW1 = "3.8.1"; | ||
58 | + private static final String SW2 = "3.9.5"; | ||
59 | + private static final String SN = "43311-12345"; | ||
60 | + | ||
61 | + private static final PortNumber P1 = PortNumber.portNumber(1); | ||
62 | + private static final PortNumber P2 = PortNumber.portNumber(2); | ||
63 | + private static final PortNumber P3 = PortNumber.portNumber(3); | ||
64 | + | ||
65 | + private static final SparseAnnotations A1 = DefaultAnnotations.builder() | ||
66 | + .set("A1", "a1") | ||
67 | + .set("B1", "b1") | ||
68 | + .build(); | ||
69 | + private static final SparseAnnotations A1_2 = DefaultAnnotations.builder() | ||
70 | + .remove("A1") | ||
71 | + .set("B3", "b3") | ||
72 | + .build(); | ||
73 | + private static final SparseAnnotations A2 = DefaultAnnotations.builder() | ||
74 | + .set("A2", "a2") | ||
75 | + .set("B2", "b2") | ||
76 | + .build(); | ||
77 | + private static final SparseAnnotations A2_2 = DefaultAnnotations.builder() | ||
78 | + .remove("A2") | ||
79 | + .set("B4", "b4") | ||
80 | + .build(); | ||
81 | + | ||
82 | + private static final NodeId MYSELF = new NodeId("myself"); | ||
83 | + | ||
84 | + private GossipDeviceStore gossipDeviceStore; | ||
85 | + private DeviceStore deviceStore; | ||
86 | + | ||
87 | + private DeviceClockManager deviceClockManager; | ||
88 | + private ClockService clockService; | ||
89 | + | ||
90 | + @BeforeClass | ||
91 | + public static void setUpBeforeClass() throws Exception { | ||
92 | + } | ||
93 | + | ||
94 | + @AfterClass | ||
95 | + public static void tearDownAfterClass() throws Exception { | ||
96 | + } | ||
97 | + | ||
98 | + | ||
99 | + @Before | ||
100 | + public void setUp() throws Exception { | ||
101 | + deviceClockManager = new DeviceClockManager(); | ||
102 | + deviceClockManager.activate(); | ||
103 | + clockService = deviceClockManager; | ||
104 | + | ||
105 | + deviceClockManager.setMastershipTerm(DID1, MastershipTerm.of(MYSELF, 1)); | ||
106 | + deviceClockManager.setMastershipTerm(DID2, MastershipTerm.of(MYSELF, 2)); | ||
107 | + | ||
108 | + gossipDeviceStore = new TestGossipDeviceStore(clockService); | ||
109 | + gossipDeviceStore.activate(); | ||
110 | + deviceStore = gossipDeviceStore; | ||
111 | + } | ||
112 | + | ||
113 | + @After | ||
114 | + public void tearDown() throws Exception { | ||
115 | + gossipDeviceStore.deactivate(); | ||
116 | + deviceClockManager.deactivate(); | ||
117 | + } | ||
118 | + | ||
119 | + private void putDevice(DeviceId deviceId, String swVersion) { | ||
120 | + DeviceDescription description = | ||
121 | + new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, | ||
122 | + HW, swVersion, SN); | ||
123 | + deviceStore.createOrUpdateDevice(PID, deviceId, description); | ||
124 | + } | ||
125 | + | ||
126 | + private void putDeviceAncillary(DeviceId deviceId, String swVersion) { | ||
127 | + DeviceDescription description = | ||
128 | + new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, | ||
129 | + HW, swVersion, SN); | ||
130 | + deviceStore.createOrUpdateDevice(PIDA, deviceId, description); | ||
131 | + } | ||
132 | + | ||
133 | + private static void assertDevice(DeviceId id, String swVersion, Device device) { | ||
134 | + assertNotNull(device); | ||
135 | + assertEquals(id, device.id()); | ||
136 | + assertEquals(MFR, device.manufacturer()); | ||
137 | + assertEquals(HW, device.hwVersion()); | ||
138 | + assertEquals(swVersion, device.swVersion()); | ||
139 | + assertEquals(SN, device.serialNumber()); | ||
140 | + } | ||
141 | + | ||
142 | + /** | ||
143 | + * Verifies that Annotations created by merging {@code annotations} is | ||
144 | + * equal to actual Annotations. | ||
145 | + * | ||
146 | + * @param actual Annotations to check | ||
147 | + * @param annotations | ||
148 | + */ | ||
149 | + private static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) { | ||
150 | + DefaultAnnotations expected = DefaultAnnotations.builder().build(); | ||
151 | + for (SparseAnnotations a : annotations) { | ||
152 | + expected = DefaultAnnotations.merge(expected, a); | ||
153 | + } | ||
154 | + assertEquals(expected.keys(), actual.keys()); | ||
155 | + for (String key : expected.keys()) { | ||
156 | + assertEquals(expected.value(key), actual.value(key)); | ||
157 | + } | ||
158 | + } | ||
159 | + | ||
160 | + @Test | ||
161 | + public final void testGetDeviceCount() { | ||
162 | + assertEquals("initialy empty", 0, deviceStore.getDeviceCount()); | ||
163 | + | ||
164 | + putDevice(DID1, SW1); | ||
165 | + putDevice(DID2, SW2); | ||
166 | + putDevice(DID1, SW1); | ||
167 | + | ||
168 | + assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount()); | ||
169 | + } | ||
170 | + | ||
171 | + @Test | ||
172 | + public final void testGetDevices() { | ||
173 | + assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices())); | ||
174 | + | ||
175 | + putDevice(DID1, SW1); | ||
176 | + putDevice(DID2, SW2); | ||
177 | + putDevice(DID1, SW1); | ||
178 | + | ||
179 | + assertEquals("expect 2 uniq devices", | ||
180 | + 2, Iterables.size(deviceStore.getDevices())); | ||
181 | + | ||
182 | + Map<DeviceId, Device> devices = new HashMap<>(); | ||
183 | + for (Device device : deviceStore.getDevices()) { | ||
184 | + devices.put(device.id(), device); | ||
185 | + } | ||
186 | + | ||
187 | + assertDevice(DID1, SW1, devices.get(DID1)); | ||
188 | + assertDevice(DID2, SW2, devices.get(DID2)); | ||
189 | + | ||
190 | + // add case for new node? | ||
191 | + } | ||
192 | + | ||
193 | + @Test | ||
194 | + public final void testGetDevice() { | ||
195 | + | ||
196 | + putDevice(DID1, SW1); | ||
197 | + | ||
198 | + assertDevice(DID1, SW1, deviceStore.getDevice(DID1)); | ||
199 | + assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2)); | ||
200 | + } | ||
201 | + | ||
202 | + @Test | ||
203 | + public final void testCreateOrUpdateDevice() { | ||
204 | + DeviceDescription description = | ||
205 | + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | ||
206 | + HW, SW1, SN); | ||
207 | + DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description); | ||
208 | + assertEquals(DEVICE_ADDED, event.type()); | ||
209 | + assertDevice(DID1, SW1, event.subject()); | ||
210 | + | ||
211 | + DeviceDescription description2 = | ||
212 | + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | ||
213 | + HW, SW2, SN); | ||
214 | + DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); | ||
215 | + assertEquals(DEVICE_UPDATED, event2.type()); | ||
216 | + assertDevice(DID1, SW2, event2.subject()); | ||
217 | + | ||
218 | + assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); | ||
219 | + } | ||
220 | + | ||
221 | + @Test | ||
222 | + public final void testCreateOrUpdateDeviceAncillary() { | ||
223 | + DeviceDescription description = | ||
224 | + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | ||
225 | + HW, SW1, SN, A2); | ||
226 | + DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description); | ||
227 | + assertEquals(DEVICE_ADDED, event.type()); | ||
228 | + assertDevice(DID1, SW1, event.subject()); | ||
229 | + assertEquals(PIDA, event.subject().providerId()); | ||
230 | + assertAnnotationsEquals(event.subject().annotations(), A2); | ||
231 | + assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1)); | ||
232 | + | ||
233 | + DeviceDescription description2 = | ||
234 | + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | ||
235 | + HW, SW2, SN, A1); | ||
236 | + DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); | ||
237 | + assertEquals(DEVICE_UPDATED, event2.type()); | ||
238 | + assertDevice(DID1, SW2, event2.subject()); | ||
239 | + assertEquals(PID, event2.subject().providerId()); | ||
240 | + assertAnnotationsEquals(event2.subject().annotations(), A1, A2); | ||
241 | + assertTrue(deviceStore.isAvailable(DID1)); | ||
242 | + | ||
243 | + assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); | ||
244 | + | ||
245 | + // For now, Ancillary is ignored once primary appears | ||
246 | + assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description)); | ||
247 | + | ||
248 | + // But, Ancillary annotations will be in effect | ||
249 | + DeviceDescription description3 = | ||
250 | + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | ||
251 | + HW, SW1, SN, A2_2); | ||
252 | + DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3); | ||
253 | + assertEquals(DEVICE_UPDATED, event3.type()); | ||
254 | + // basic information will be the one from Primary | ||
255 | + assertDevice(DID1, SW2, event3.subject()); | ||
256 | + assertEquals(PID, event3.subject().providerId()); | ||
257 | + // but annotation from Ancillary will be merged | ||
258 | + assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2); | ||
259 | + assertTrue(deviceStore.isAvailable(DID1)); | ||
260 | + } | ||
261 | + | ||
262 | + | ||
263 | + @Test | ||
264 | + public final void testMarkOffline() { | ||
265 | + | ||
266 | + putDevice(DID1, SW1); | ||
267 | + assertTrue(deviceStore.isAvailable(DID1)); | ||
268 | + | ||
269 | + DeviceEvent event = deviceStore.markOffline(DID1); | ||
270 | + assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type()); | ||
271 | + assertDevice(DID1, SW1, event.subject()); | ||
272 | + assertFalse(deviceStore.isAvailable(DID1)); | ||
273 | + | ||
274 | + DeviceEvent event2 = deviceStore.markOffline(DID1); | ||
275 | + assertNull("No change, no event", event2); | ||
276 | +} | ||
277 | + | ||
278 | + @Test | ||
279 | + public final void testUpdatePorts() { | ||
280 | + putDevice(DID1, SW1); | ||
281 | + List<PortDescription> pds = Arrays.<PortDescription>asList( | ||
282 | + new DefaultPortDescription(P1, true), | ||
283 | + new DefaultPortDescription(P2, true) | ||
284 | + ); | ||
285 | + | ||
286 | + List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds); | ||
287 | + | ||
288 | + Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | ||
289 | + for (DeviceEvent event : events) { | ||
290 | + assertEquals(PORT_ADDED, event.type()); | ||
291 | + assertDevice(DID1, SW1, event.subject()); | ||
292 | + assertTrue("PortNumber is one of expected", | ||
293 | + expectedPorts.remove(event.port().number())); | ||
294 | + assertTrue("Port is enabled", event.port().isEnabled()); | ||
295 | + } | ||
296 | + assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty()); | ||
297 | + | ||
298 | + | ||
299 | + List<PortDescription> pds2 = Arrays.<PortDescription>asList( | ||
300 | + new DefaultPortDescription(P1, false), | ||
301 | + new DefaultPortDescription(P2, true), | ||
302 | + new DefaultPortDescription(P3, true) | ||
303 | + ); | ||
304 | + | ||
305 | + events = deviceStore.updatePorts(PID, DID1, pds2); | ||
306 | + assertFalse("event should be triggered", events.isEmpty()); | ||
307 | + for (DeviceEvent event : events) { | ||
308 | + PortNumber num = event.port().number(); | ||
309 | + if (P1.equals(num)) { | ||
310 | + assertEquals(PORT_UPDATED, event.type()); | ||
311 | + assertDevice(DID1, SW1, event.subject()); | ||
312 | + assertFalse("Port is disabled", event.port().isEnabled()); | ||
313 | + } else if (P2.equals(num)) { | ||
314 | + fail("P2 event not expected."); | ||
315 | + } else if (P3.equals(num)) { | ||
316 | + assertEquals(PORT_ADDED, event.type()); | ||
317 | + assertDevice(DID1, SW1, event.subject()); | ||
318 | + assertTrue("Port is enabled", event.port().isEnabled()); | ||
319 | + } else { | ||
320 | + fail("Unknown port number encountered: " + num); | ||
321 | + } | ||
322 | + } | ||
323 | + | ||
324 | + List<PortDescription> pds3 = Arrays.<PortDescription>asList( | ||
325 | + new DefaultPortDescription(P1, false), | ||
326 | + new DefaultPortDescription(P2, true) | ||
327 | + ); | ||
328 | + events = deviceStore.updatePorts(PID, DID1, pds3); | ||
329 | + assertFalse("event should be triggered", events.isEmpty()); | ||
330 | + for (DeviceEvent event : events) { | ||
331 | + PortNumber num = event.port().number(); | ||
332 | + if (P1.equals(num)) { | ||
333 | + fail("P1 event not expected."); | ||
334 | + } else if (P2.equals(num)) { | ||
335 | + fail("P2 event not expected."); | ||
336 | + } else if (P3.equals(num)) { | ||
337 | + assertEquals(PORT_REMOVED, event.type()); | ||
338 | + assertDevice(DID1, SW1, event.subject()); | ||
339 | + assertTrue("Port was enabled", event.port().isEnabled()); | ||
340 | + } else { | ||
341 | + fail("Unknown port number encountered: " + num); | ||
342 | + } | ||
343 | + } | ||
344 | + | ||
345 | + } | ||
346 | + | ||
347 | + @Test | ||
348 | + public final void testUpdatePortStatus() { | ||
349 | + putDevice(DID1, SW1); | ||
350 | + List<PortDescription> pds = Arrays.<PortDescription>asList( | ||
351 | + new DefaultPortDescription(P1, true) | ||
352 | + ); | ||
353 | + deviceStore.updatePorts(PID, DID1, pds); | ||
354 | + | ||
355 | + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, | ||
356 | + new DefaultPortDescription(P1, false)); | ||
357 | + assertEquals(PORT_UPDATED, event.type()); | ||
358 | + assertDevice(DID1, SW1, event.subject()); | ||
359 | + assertEquals(P1, event.port().number()); | ||
360 | + assertFalse("Port is disabled", event.port().isEnabled()); | ||
361 | + | ||
362 | + } | ||
363 | + @Test | ||
364 | + public final void testUpdatePortStatusAncillary() { | ||
365 | + putDeviceAncillary(DID1, SW1); | ||
366 | + putDevice(DID1, SW1); | ||
367 | + List<PortDescription> pds = Arrays.<PortDescription>asList( | ||
368 | + new DefaultPortDescription(P1, true, A1) | ||
369 | + ); | ||
370 | + deviceStore.updatePorts(PID, DID1, pds); | ||
371 | + | ||
372 | + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, | ||
373 | + new DefaultPortDescription(P1, false, A1_2)); | ||
374 | + assertEquals(PORT_UPDATED, event.type()); | ||
375 | + assertDevice(DID1, SW1, event.subject()); | ||
376 | + assertEquals(P1, event.port().number()); | ||
377 | + assertAnnotationsEquals(event.port().annotations(), A1, A1_2); | ||
378 | + assertFalse("Port is disabled", event.port().isEnabled()); | ||
379 | + | ||
380 | + DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, | ||
381 | + new DefaultPortDescription(P1, true)); | ||
382 | + assertNull("Ancillary is ignored if primary exists", event2); | ||
383 | + | ||
384 | + // but, Ancillary annotation update will be notified | ||
385 | + DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, | ||
386 | + new DefaultPortDescription(P1, true, A2)); | ||
387 | + assertEquals(PORT_UPDATED, event3.type()); | ||
388 | + assertDevice(DID1, SW1, event3.subject()); | ||
389 | + assertEquals(P1, event3.port().number()); | ||
390 | + assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2); | ||
391 | + assertFalse("Port is disabled", event3.port().isEnabled()); | ||
392 | + | ||
393 | + // port only reported from Ancillary will be notified as down | ||
394 | + DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, | ||
395 | + new DefaultPortDescription(P2, true)); | ||
396 | + assertEquals(PORT_ADDED, event4.type()); | ||
397 | + assertDevice(DID1, SW1, event4.subject()); | ||
398 | + assertEquals(P2, event4.port().number()); | ||
399 | + assertAnnotationsEquals(event4.port().annotations()); | ||
400 | + assertFalse("Port is disabled if not given from primary provider", | ||
401 | + event4.port().isEnabled()); | ||
402 | + } | ||
403 | + | ||
404 | + @Test | ||
405 | + public final void testGetPorts() { | ||
406 | + putDevice(DID1, SW1); | ||
407 | + putDevice(DID2, SW1); | ||
408 | + List<PortDescription> pds = Arrays.<PortDescription>asList( | ||
409 | + new DefaultPortDescription(P1, true), | ||
410 | + new DefaultPortDescription(P2, true) | ||
411 | + ); | ||
412 | + deviceStore.updatePorts(PID, DID1, pds); | ||
413 | + | ||
414 | + Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | ||
415 | + List<Port> ports = deviceStore.getPorts(DID1); | ||
416 | + for (Port port : ports) { | ||
417 | + assertTrue("Port is enabled", port.isEnabled()); | ||
418 | + assertTrue("PortNumber is one of expected", | ||
419 | + expectedPorts.remove(port.number())); | ||
420 | + } | ||
421 | + assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty()); | ||
422 | + | ||
423 | + | ||
424 | + assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty()); | ||
425 | + } | ||
426 | + | ||
427 | + @Test | ||
428 | + public final void testGetPort() { | ||
429 | + putDevice(DID1, SW1); | ||
430 | + putDevice(DID2, SW1); | ||
431 | + List<PortDescription> pds = Arrays.<PortDescription>asList( | ||
432 | + new DefaultPortDescription(P1, true), | ||
433 | + new DefaultPortDescription(P2, false) | ||
434 | + ); | ||
435 | + deviceStore.updatePorts(PID, DID1, pds); | ||
436 | + | ||
437 | + Port port1 = deviceStore.getPort(DID1, P1); | ||
438 | + assertEquals(P1, port1.number()); | ||
439 | + assertTrue("Port is enabled", port1.isEnabled()); | ||
440 | + | ||
441 | + Port port2 = deviceStore.getPort(DID1, P2); | ||
442 | + assertEquals(P2, port2.number()); | ||
443 | + assertFalse("Port is disabled", port2.isEnabled()); | ||
444 | + | ||
445 | + Port port3 = deviceStore.getPort(DID1, P3); | ||
446 | + assertNull("P3 not expected", port3); | ||
447 | + } | ||
448 | + | ||
449 | + @Test | ||
450 | + public final void testRemoveDevice() { | ||
451 | + putDevice(DID1, SW1); | ||
452 | + putDevice(DID2, SW1); | ||
453 | + | ||
454 | + assertEquals(2, deviceStore.getDeviceCount()); | ||
455 | + | ||
456 | + DeviceEvent event = deviceStore.removeDevice(DID1); | ||
457 | + assertEquals(DEVICE_REMOVED, event.type()); | ||
458 | + assertDevice(DID1, SW1, event.subject()); | ||
459 | + | ||
460 | + assertEquals(1, deviceStore.getDeviceCount()); | ||
461 | + } | ||
462 | + | ||
463 | + // If Delegates should be called only on remote events, | ||
464 | + // then Simple* should never call them, thus not test required. | ||
465 | + // TODO add test for Port events when we have them | ||
466 | + @Ignore("Ignore until Delegate spec. is clear.") | ||
467 | + @Test | ||
468 | + public final void testEvents() throws InterruptedException { | ||
469 | + final CountDownLatch addLatch = new CountDownLatch(1); | ||
470 | + DeviceStoreDelegate checkAdd = new DeviceStoreDelegate() { | ||
471 | + @Override | ||
472 | + public void notify(DeviceEvent event) { | ||
473 | + assertEquals(DEVICE_ADDED, event.type()); | ||
474 | + assertDevice(DID1, SW1, event.subject()); | ||
475 | + addLatch.countDown(); | ||
476 | + } | ||
477 | + }; | ||
478 | + final CountDownLatch updateLatch = new CountDownLatch(1); | ||
479 | + DeviceStoreDelegate checkUpdate = new DeviceStoreDelegate() { | ||
480 | + @Override | ||
481 | + public void notify(DeviceEvent event) { | ||
482 | + assertEquals(DEVICE_UPDATED, event.type()); | ||
483 | + assertDevice(DID1, SW2, event.subject()); | ||
484 | + updateLatch.countDown(); | ||
485 | + } | ||
486 | + }; | ||
487 | + final CountDownLatch removeLatch = new CountDownLatch(1); | ||
488 | + DeviceStoreDelegate checkRemove = new DeviceStoreDelegate() { | ||
489 | + @Override | ||
490 | + public void notify(DeviceEvent event) { | ||
491 | + assertEquals(DEVICE_REMOVED, event.type()); | ||
492 | + assertDevice(DID1, SW2, event.subject()); | ||
493 | + removeLatch.countDown(); | ||
494 | + } | ||
495 | + }; | ||
496 | + | ||
497 | + DeviceDescription description = | ||
498 | + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | ||
499 | + HW, SW1, SN); | ||
500 | + deviceStore.setDelegate(checkAdd); | ||
501 | + deviceStore.createOrUpdateDevice(PID, DID1, description); | ||
502 | + assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS)); | ||
503 | + | ||
504 | + | ||
505 | + DeviceDescription description2 = | ||
506 | + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | ||
507 | + HW, SW2, SN); | ||
508 | + deviceStore.unsetDelegate(checkAdd); | ||
509 | + deviceStore.setDelegate(checkUpdate); | ||
510 | + deviceStore.createOrUpdateDevice(PID, DID1, description2); | ||
511 | + assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS)); | ||
512 | + | ||
513 | + deviceStore.unsetDelegate(checkUpdate); | ||
514 | + deviceStore.setDelegate(checkRemove); | ||
515 | + deviceStore.removeDevice(DID1); | ||
516 | + assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS)); | ||
517 | + } | ||
518 | + | ||
519 | + private static final class TestGossipDeviceStore extends GossipDeviceStore { | ||
520 | + | ||
521 | + public TestGossipDeviceStore(ClockService clockService) { | ||
522 | + this.clockService = clockService; | ||
523 | + } | ||
524 | + } | ||
525 | +} |
... | @@ -47,6 +47,7 @@ import static com.google.common.cache.CacheBuilder.newBuilder; | ... | @@ -47,6 +47,7 @@ import static com.google.common.cache.CacheBuilder.newBuilder; |
47 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; | 47 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; |
48 | import static org.slf4j.LoggerFactory.getLogger; | 48 | import static org.slf4j.LoggerFactory.getLogger; |
49 | 49 | ||
50 | +//TODO: Add support for multiple provider and annotations | ||
50 | /** | 51 | /** |
51 | * Manages inventory of infrastructure devices using Hazelcast-backed map. | 52 | * Manages inventory of infrastructure devices using Hazelcast-backed map. |
52 | */ | 53 | */ | ... | ... |
... | @@ -4,27 +4,15 @@ import org.apache.felix.scr.annotations.Component; | ... | @@ -4,27 +4,15 @@ import org.apache.felix.scr.annotations.Component; |
4 | import org.apache.felix.scr.annotations.Service; | 4 | import org.apache.felix.scr.annotations.Service; |
5 | import org.onlab.onos.cluster.MastershipTerm; | 5 | import org.onlab.onos.cluster.MastershipTerm; |
6 | import org.onlab.onos.net.DeviceId; | 6 | import org.onlab.onos.net.DeviceId; |
7 | -import org.onlab.onos.store.ClockService; | 7 | +import org.onlab.onos.store.ClockProviderService; |
8 | -import org.onlab.onos.store.Timestamp; | ||
9 | 8 | ||
10 | // FIXME: Code clone in onos-core-trivial, onos-core-hz-net | 9 | // FIXME: Code clone in onos-core-trivial, onos-core-hz-net |
11 | /** | 10 | /** |
12 | - * Dummy implementation of {@link ClockService}. | 11 | + * Dummy implementation of {@link ClockProviderService}. |
13 | */ | 12 | */ |
14 | @Component(immediate = true) | 13 | @Component(immediate = true) |
15 | @Service | 14 | @Service |
16 | -public class NoOpClockService implements ClockService { | 15 | +public class NoOpClockProviderService implements ClockProviderService { |
17 | - | ||
18 | - @Override | ||
19 | - public Timestamp getTimestamp(DeviceId deviceId) { | ||
20 | - return new Timestamp() { | ||
21 | - | ||
22 | - @Override | ||
23 | - public int compareTo(Timestamp o) { | ||
24 | - throw new IllegalStateException("Never expected to be used."); | ||
25 | - } | ||
26 | - }; | ||
27 | - } | ||
28 | 16 | ||
29 | @Override | 17 | @Override |
30 | public void setMastershipTerm(DeviceId deviceId, MastershipTerm term) { | 18 | public void setMastershipTerm(DeviceId deviceId, MastershipTerm term) { | ... | ... |
... | @@ -38,6 +38,7 @@ import com.google.common.collect.Multimap; | ... | @@ -38,6 +38,7 @@ import com.google.common.collect.Multimap; |
38 | import com.google.common.collect.ImmutableSet.Builder; | 38 | import com.google.common.collect.ImmutableSet.Builder; |
39 | import com.hazelcast.core.IMap; | 39 | import com.hazelcast.core.IMap; |
40 | 40 | ||
41 | +//TODO: Add support for multiple provider and annotations | ||
41 | /** | 42 | /** |
42 | * Manages inventory of infrastructure links using Hazelcast-backed map. | 43 | * Manages inventory of infrastructure links using Hazelcast-backed map. |
43 | */ | 44 | */ | ... | ... |
... | @@ -3,7 +3,6 @@ package org.onlab.onos.store.serializers; | ... | @@ -3,7 +3,6 @@ package org.onlab.onos.store.serializers; |
3 | import org.onlab.onos.net.ConnectPoint; | 3 | import org.onlab.onos.net.ConnectPoint; |
4 | import org.onlab.onos.net.ElementId; | 4 | import org.onlab.onos.net.ElementId; |
5 | import org.onlab.onos.net.PortNumber; | 5 | import org.onlab.onos.net.PortNumber; |
6 | - | ||
7 | import com.esotericsoftware.kryo.Kryo; | 6 | import com.esotericsoftware.kryo.Kryo; |
8 | import com.esotericsoftware.kryo.Serializer; | 7 | import com.esotericsoftware.kryo.Serializer; |
9 | import com.esotericsoftware.kryo.io.Input; | 8 | import com.esotericsoftware.kryo.io.Input; |
... | @@ -15,7 +14,7 @@ import com.esotericsoftware.kryo.io.Output; | ... | @@ -15,7 +14,7 @@ import com.esotericsoftware.kryo.io.Output; |
15 | public class ConnectPointSerializer extends Serializer<ConnectPoint> { | 14 | public class ConnectPointSerializer extends Serializer<ConnectPoint> { |
16 | 15 | ||
17 | /** | 16 | /** |
18 | - * Default constructor. | 17 | + * Creates {@link ConnectPointSerializer} serializer instance. |
19 | */ | 18 | */ |
20 | public ConnectPointSerializer() { | 19 | public ConnectPointSerializer() { |
21 | // non-null, immutable | 20 | // non-null, immutable | ... | ... |
... | @@ -16,7 +16,7 @@ import com.esotericsoftware.kryo.io.Output; | ... | @@ -16,7 +16,7 @@ import com.esotericsoftware.kryo.io.Output; |
16 | public class DefaultLinkSerializer extends Serializer<DefaultLink> { | 16 | public class DefaultLinkSerializer extends Serializer<DefaultLink> { |
17 | 17 | ||
18 | /** | 18 | /** |
19 | - * Default constructor. | 19 | + * Creates {@link DefaultLink} serializer instance. |
20 | */ | 20 | */ |
21 | public DefaultLinkSerializer() { | 21 | public DefaultLinkSerializer() { |
22 | // non-null, immutable | 22 | // non-null, immutable | ... | ... |
... | @@ -16,7 +16,7 @@ public final class DefaultPortSerializer extends | ... | @@ -16,7 +16,7 @@ public final class DefaultPortSerializer extends |
16 | Serializer<DefaultPort> { | 16 | Serializer<DefaultPort> { |
17 | 17 | ||
18 | /** | 18 | /** |
19 | - * Default constructor. | 19 | + * Creates {@link DefaultPort} serializer instance. |
20 | */ | 20 | */ |
21 | public DefaultPortSerializer() { | 21 | public DefaultPortSerializer() { |
22 | // non-null, immutable | 22 | // non-null, immutable | ... | ... |
... | @@ -14,6 +14,14 @@ import com.esotericsoftware.kryo.io.Output; | ... | @@ -14,6 +14,14 @@ import com.esotericsoftware.kryo.io.Output; |
14 | */ | 14 | */ |
15 | public final class DeviceIdSerializer extends Serializer<DeviceId> { | 15 | public final class DeviceIdSerializer extends Serializer<DeviceId> { |
16 | 16 | ||
17 | + /** | ||
18 | + * Creates {@link DeviceId} serializer instance. | ||
19 | + */ | ||
20 | + public DeviceIdSerializer() { | ||
21 | + // non-null, immutable | ||
22 | + super(false, true); | ||
23 | + } | ||
24 | + | ||
17 | @Override | 25 | @Override |
18 | public void write(Kryo kryo, Output output, DeviceId object) { | 26 | public void write(Kryo kryo, Output output, DeviceId object) { |
19 | kryo.writeObject(output, object.uri()); | 27 | kryo.writeObject(output, object.uri()); | ... | ... |
... | @@ -19,6 +19,9 @@ public class ImmutableMapSerializer extends FamilySerializer<ImmutableMap<?, ?>> | ... | @@ -19,6 +19,9 @@ public class ImmutableMapSerializer extends FamilySerializer<ImmutableMap<?, ?>> |
19 | 19 | ||
20 | private final MapSerializer mapSerializer = new MapSerializer(); | 20 | private final MapSerializer mapSerializer = new MapSerializer(); |
21 | 21 | ||
22 | + /** | ||
23 | + * Creates {@link ImmutableMap} serializer instance. | ||
24 | + */ | ||
22 | public ImmutableMapSerializer() { | 25 | public ImmutableMapSerializer() { |
23 | // non-null, immutable | 26 | // non-null, immutable |
24 | super(false, true); | 27 | super(false, true); | ... | ... |
... | @@ -18,6 +18,9 @@ public class ImmutableSetSerializer extends FamilySerializer<ImmutableSet<?>> { | ... | @@ -18,6 +18,9 @@ public class ImmutableSetSerializer extends FamilySerializer<ImmutableSet<?>> { |
18 | 18 | ||
19 | private final CollectionSerializer serializer = new CollectionSerializer(); | 19 | private final CollectionSerializer serializer = new CollectionSerializer(); |
20 | 20 | ||
21 | + /** | ||
22 | + * Creates {@link ImmutableSet} serializer instance. | ||
23 | + */ | ||
21 | public ImmutableSetSerializer() { | 24 | public ImmutableSetSerializer() { |
22 | // non-null, immutable | 25 | // non-null, immutable |
23 | super(false, true); | 26 | super(false, true); | ... | ... |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/IpAddressSerializer.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import org.onlab.packet.IpAddress; | ||
4 | +import com.esotericsoftware.kryo.Kryo; | ||
5 | +import com.esotericsoftware.kryo.Serializer; | ||
6 | +import com.esotericsoftware.kryo.io.Input; | ||
7 | +import com.esotericsoftware.kryo.io.Output; | ||
8 | + | ||
9 | +/** | ||
10 | + * Kryo Serializer for {@link IpAddress}. | ||
11 | + */ | ||
12 | +public class IpAddressSerializer extends Serializer<IpAddress> { | ||
13 | + | ||
14 | + /** | ||
15 | + * Creates {@link IpAddress} serializer instance. | ||
16 | + */ | ||
17 | + public IpAddressSerializer() { | ||
18 | + // non-null, immutable | ||
19 | + super(false, true); | ||
20 | + } | ||
21 | + | ||
22 | + @Override | ||
23 | + public void write(Kryo kryo, Output output, | ||
24 | + IpAddress object) { | ||
25 | + byte[] octs = object.toOctets(); | ||
26 | + output.writeInt(octs.length); | ||
27 | + output.writeBytes(octs); | ||
28 | + output.writeInt(object.prefixLength()); | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public IpAddress read(Kryo kryo, Input input, | ||
33 | + Class<IpAddress> type) { | ||
34 | + int octLen = input.readInt(); | ||
35 | + byte[] octs = new byte[octLen]; | ||
36 | + input.read(octs); | ||
37 | + int prefLen = input.readInt(); | ||
38 | + return IpAddress.valueOf(octs, prefLen); | ||
39 | + } | ||
40 | + | ||
41 | +} |
... | @@ -13,7 +13,7 @@ import com.esotericsoftware.kryo.io.Output; | ... | @@ -13,7 +13,7 @@ import com.esotericsoftware.kryo.io.Output; |
13 | public final class IpPrefixSerializer extends Serializer<IpPrefix> { | 13 | public final class IpPrefixSerializer extends Serializer<IpPrefix> { |
14 | 14 | ||
15 | /** | 15 | /** |
16 | - * Default constructor. | 16 | + * Creates {@link IpPrefix} serializer instance. |
17 | */ | 17 | */ |
18 | public IpPrefixSerializer() { | 18 | public IpPrefixSerializer() { |
19 | // non-null, immutable | 19 | // non-null, immutable | ... | ... |
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import java.net.URI; | ||
4 | +import java.util.ArrayList; | ||
5 | +import java.util.HashMap; | ||
6 | + | ||
7 | +import org.onlab.onos.cluster.ControllerNode; | ||
8 | +import org.onlab.onos.cluster.DefaultControllerNode; | ||
9 | +import org.onlab.onos.cluster.MastershipTerm; | ||
10 | +import org.onlab.onos.cluster.NodeId; | ||
11 | +import org.onlab.onos.net.ConnectPoint; | ||
12 | +import org.onlab.onos.net.DefaultAnnotations; | ||
13 | +import org.onlab.onos.net.DefaultDevice; | ||
14 | +import org.onlab.onos.net.DefaultLink; | ||
15 | +import org.onlab.onos.net.DefaultPort; | ||
16 | +import org.onlab.onos.net.Device; | ||
17 | +import org.onlab.onos.net.DeviceId; | ||
18 | +import org.onlab.onos.net.Element; | ||
19 | +import org.onlab.onos.net.Link; | ||
20 | +import org.onlab.onos.net.LinkKey; | ||
21 | +import org.onlab.onos.net.MastershipRole; | ||
22 | +import org.onlab.onos.net.Port; | ||
23 | +import org.onlab.onos.net.PortNumber; | ||
24 | +import org.onlab.onos.net.provider.ProviderId; | ||
25 | +import org.onlab.packet.IpAddress; | ||
26 | +import org.onlab.packet.IpPrefix; | ||
27 | +import org.onlab.util.KryoPool; | ||
28 | + | ||
29 | +import de.javakaffee.kryoserializers.URISerializer; | ||
30 | + | ||
31 | +public final class KryoPoolUtil { | ||
32 | + | ||
33 | + /** | ||
34 | + * KryoPool which can serialize ON.lab misc classes. | ||
35 | + */ | ||
36 | + public static final KryoPool MISC = KryoPool.newBuilder() | ||
37 | + .register(IpPrefix.class, new IpPrefixSerializer()) | ||
38 | + .register(IpAddress.class, new IpAddressSerializer()) | ||
39 | + .build(); | ||
40 | + | ||
41 | + // TODO: Populate other classes | ||
42 | + /** | ||
43 | + * KryoPool which can serialize API bundle classes. | ||
44 | + */ | ||
45 | + public static final KryoPool API = KryoPool.newBuilder() | ||
46 | + .register(MISC) | ||
47 | + .register( | ||
48 | + // | ||
49 | + ArrayList.class, | ||
50 | + HashMap.class, | ||
51 | + // | ||
52 | + ControllerNode.State.class, | ||
53 | + Device.Type.class, | ||
54 | + DefaultAnnotations.class, | ||
55 | + DefaultControllerNode.class, | ||
56 | + DefaultDevice.class, | ||
57 | + MastershipRole.class, | ||
58 | + Port.class, | ||
59 | + Element.class, | ||
60 | + Link.Type.class | ||
61 | + ) | ||
62 | + .register(URI.class, new URISerializer()) | ||
63 | + .register(NodeId.class, new NodeIdSerializer()) | ||
64 | + .register(ProviderId.class, new ProviderIdSerializer()) | ||
65 | + .register(DeviceId.class, new DeviceIdSerializer()) | ||
66 | + .register(PortNumber.class, new PortNumberSerializer()) | ||
67 | + .register(DefaultPort.class, new DefaultPortSerializer()) | ||
68 | + .register(LinkKey.class, new LinkKeySerializer()) | ||
69 | + .register(ConnectPoint.class, new ConnectPointSerializer()) | ||
70 | + .register(DefaultLink.class, new DefaultLinkSerializer()) | ||
71 | + .register(MastershipTerm.class, new MastershipTermSerializer()) | ||
72 | + .register(MastershipRole.class, new MastershipRoleSerializer()) | ||
73 | + | ||
74 | + .build(); | ||
75 | + | ||
76 | + | ||
77 | + // not to be instantiated | ||
78 | + private KryoPoolUtil() {} | ||
79 | +} |
1 | package org.onlab.onos.store.serializers; | 1 | package org.onlab.onos.store.serializers; |
2 | 2 | ||
3 | -import de.javakaffee.kryoserializers.URISerializer; | ||
4 | import org.apache.felix.scr.annotations.Activate; | 3 | import org.apache.felix.scr.annotations.Activate; |
5 | import org.apache.felix.scr.annotations.Component; | 4 | import org.apache.felix.scr.annotations.Component; |
6 | import org.apache.felix.scr.annotations.Deactivate; | 5 | import org.apache.felix.scr.annotations.Deactivate; |
7 | import org.apache.felix.scr.annotations.Service; | 6 | import org.apache.felix.scr.annotations.Service; |
8 | -import org.onlab.onos.cluster.ControllerNode; | ||
9 | -import org.onlab.onos.cluster.DefaultControllerNode; | ||
10 | -import org.onlab.onos.cluster.NodeId; | ||
11 | -import org.onlab.onos.net.ConnectPoint; | ||
12 | -import org.onlab.onos.net.DefaultAnnotations; | ||
13 | -import org.onlab.onos.net.DefaultDevice; | ||
14 | -import org.onlab.onos.net.DefaultLink; | ||
15 | -import org.onlab.onos.net.DefaultPort; | ||
16 | -import org.onlab.onos.net.Device; | ||
17 | -import org.onlab.onos.net.DeviceId; | ||
18 | -import org.onlab.onos.net.Element; | ||
19 | -import org.onlab.onos.net.Link; | ||
20 | -import org.onlab.onos.net.LinkKey; | ||
21 | -import org.onlab.onos.net.MastershipRole; | ||
22 | -import org.onlab.onos.net.Port; | ||
23 | -import org.onlab.onos.net.PortNumber; | ||
24 | -import org.onlab.onos.net.provider.ProviderId; | ||
25 | -import org.onlab.packet.IpPrefix; | ||
26 | import org.onlab.util.KryoPool; | 7 | import org.onlab.util.KryoPool; |
27 | import org.slf4j.Logger; | 8 | import org.slf4j.Logger; |
28 | import org.slf4j.LoggerFactory; | 9 | import org.slf4j.LoggerFactory; |
29 | 10 | ||
30 | -import java.net.URI; | ||
31 | import java.nio.ByteBuffer; | 11 | import java.nio.ByteBuffer; |
32 | -import java.util.ArrayList; | ||
33 | -import java.util.HashMap; | ||
34 | 12 | ||
35 | /** | 13 | /** |
36 | * Serialization service using Kryo. | 14 | * Serialization service using Kryo. |
... | @@ -58,33 +36,8 @@ public class KryoSerializationManager implements KryoSerializationService { | ... | @@ -58,33 +36,8 @@ public class KryoSerializationManager implements KryoSerializationService { |
58 | * Sets up the common serialzers pool. | 36 | * Sets up the common serialzers pool. |
59 | */ | 37 | */ |
60 | protected void setupKryoPool() { | 38 | protected void setupKryoPool() { |
61 | - // FIXME Slice out types used in common to separate pool/namespace. | ||
62 | serializerPool = KryoPool.newBuilder() | 39 | serializerPool = KryoPool.newBuilder() |
63 | - .register(ArrayList.class, | 40 | + .register(KryoPoolUtil.API) |
64 | - HashMap.class, | ||
65 | - | ||
66 | - ControllerNode.State.class, | ||
67 | - Device.Type.class, | ||
68 | - | ||
69 | - DefaultAnnotations.class, | ||
70 | - DefaultControllerNode.class, | ||
71 | - DefaultDevice.class, | ||
72 | - MastershipRole.class, | ||
73 | - Port.class, | ||
74 | - Element.class, | ||
75 | - | ||
76 | - Link.Type.class | ||
77 | - ) | ||
78 | - .register(IpPrefix.class, new IpPrefixSerializer()) | ||
79 | - .register(URI.class, new URISerializer()) | ||
80 | - .register(NodeId.class, new NodeIdSerializer()) | ||
81 | - .register(ProviderId.class, new ProviderIdSerializer()) | ||
82 | - .register(DeviceId.class, new DeviceIdSerializer()) | ||
83 | - .register(PortNumber.class, new PortNumberSerializer()) | ||
84 | - .register(DefaultPort.class, new DefaultPortSerializer()) | ||
85 | - .register(LinkKey.class, new LinkKeySerializer()) | ||
86 | - .register(ConnectPoint.class, new ConnectPointSerializer()) | ||
87 | - .register(DefaultLink.class, new DefaultLinkSerializer()) | ||
88 | .build() | 41 | .build() |
89 | .populate(1); | 42 | .populate(1); |
90 | } | 43 | } | ... | ... |
... | @@ -2,6 +2,7 @@ package org.onlab.onos.store.serializers; | ... | @@ -2,6 +2,7 @@ package org.onlab.onos.store.serializers; |
2 | 2 | ||
3 | import org.onlab.onos.net.ConnectPoint; | 3 | import org.onlab.onos.net.ConnectPoint; |
4 | import org.onlab.onos.net.LinkKey; | 4 | import org.onlab.onos.net.LinkKey; |
5 | + | ||
5 | import com.esotericsoftware.kryo.Kryo; | 6 | import com.esotericsoftware.kryo.Kryo; |
6 | import com.esotericsoftware.kryo.Serializer; | 7 | import com.esotericsoftware.kryo.Serializer; |
7 | import com.esotericsoftware.kryo.io.Input; | 8 | import com.esotericsoftware.kryo.io.Input; |
... | @@ -13,7 +14,7 @@ import com.esotericsoftware.kryo.io.Output; | ... | @@ -13,7 +14,7 @@ import com.esotericsoftware.kryo.io.Output; |
13 | public class LinkKeySerializer extends Serializer<LinkKey> { | 14 | public class LinkKeySerializer extends Serializer<LinkKey> { |
14 | 15 | ||
15 | /** | 16 | /** |
16 | - * Default constructor. | 17 | + * Creates {@link LinkKey} serializer instance. |
17 | */ | 18 | */ |
18 | public LinkKeySerializer() { | 19 | public LinkKeySerializer() { |
19 | // non-null, immutable | 20 | // non-null, immutable | ... | ... |
... | @@ -12,6 +12,14 @@ import com.esotericsoftware.kryo.io.Output; | ... | @@ -12,6 +12,14 @@ import com.esotericsoftware.kryo.io.Output; |
12 | */ | 12 | */ |
13 | public class MastershipRoleSerializer extends Serializer<MastershipRole> { | 13 | public class MastershipRoleSerializer extends Serializer<MastershipRole> { |
14 | 14 | ||
15 | + /** | ||
16 | + * Creates {@link MastershipRole} serializer instance. | ||
17 | + */ | ||
18 | + public MastershipRoleSerializer() { | ||
19 | + // non-null, immutable | ||
20 | + super(false, true); | ||
21 | + } | ||
22 | + | ||
15 | @Override | 23 | @Override |
16 | public MastershipRole read(Kryo kryo, Input input, Class<MastershipRole> type) { | 24 | public MastershipRole read(Kryo kryo, Input input, Class<MastershipRole> type) { |
17 | final String role = kryo.readObject(input, String.class); | 25 | final String role = kryo.readObject(input, String.class); | ... | ... |
... | @@ -2,7 +2,6 @@ package org.onlab.onos.store.serializers; | ... | @@ -2,7 +2,6 @@ package org.onlab.onos.store.serializers; |
2 | 2 | ||
3 | import org.onlab.onos.cluster.MastershipTerm; | 3 | import org.onlab.onos.cluster.MastershipTerm; |
4 | import org.onlab.onos.cluster.NodeId; | 4 | import org.onlab.onos.cluster.NodeId; |
5 | - | ||
6 | import com.esotericsoftware.kryo.Kryo; | 5 | import com.esotericsoftware.kryo.Kryo; |
7 | import com.esotericsoftware.kryo.Serializer; | 6 | import com.esotericsoftware.kryo.Serializer; |
8 | import com.esotericsoftware.kryo.io.Input; | 7 | import com.esotericsoftware.kryo.io.Input; |
... | @@ -13,6 +12,14 @@ import com.esotericsoftware.kryo.io.Output; | ... | @@ -13,6 +12,14 @@ import com.esotericsoftware.kryo.io.Output; |
13 | */ | 12 | */ |
14 | public class MastershipTermSerializer extends Serializer<MastershipTerm> { | 13 | public class MastershipTermSerializer extends Serializer<MastershipTerm> { |
15 | 14 | ||
15 | + /** | ||
16 | + * Creates {@link MastershipTerm} serializer instance. | ||
17 | + */ | ||
18 | + public MastershipTermSerializer() { | ||
19 | + // non-null, immutable | ||
20 | + super(false, true); | ||
21 | + } | ||
22 | + | ||
16 | @Override | 23 | @Override |
17 | public MastershipTerm read(Kryo kryo, Input input, Class<MastershipTerm> type) { | 24 | public MastershipTerm read(Kryo kryo, Input input, Class<MastershipTerm> type) { |
18 | final NodeId node = new NodeId(kryo.readObject(input, String.class)); | 25 | final NodeId node = new NodeId(kryo.readObject(input, String.class)); | ... | ... |
... | @@ -4,6 +4,7 @@ import com.esotericsoftware.kryo.Kryo; | ... | @@ -4,6 +4,7 @@ import com.esotericsoftware.kryo.Kryo; |
4 | import com.esotericsoftware.kryo.Serializer; | 4 | import com.esotericsoftware.kryo.Serializer; |
5 | import com.esotericsoftware.kryo.io.Input; | 5 | import com.esotericsoftware.kryo.io.Input; |
6 | import com.esotericsoftware.kryo.io.Output; | 6 | import com.esotericsoftware.kryo.io.Output; |
7 | + | ||
7 | import org.onlab.onos.cluster.NodeId; | 8 | import org.onlab.onos.cluster.NodeId; |
8 | 9 | ||
9 | /** | 10 | /** |
... | @@ -11,6 +12,14 @@ import org.onlab.onos.cluster.NodeId; | ... | @@ -11,6 +12,14 @@ import org.onlab.onos.cluster.NodeId; |
11 | */ | 12 | */ |
12 | public final class NodeIdSerializer extends Serializer<NodeId> { | 13 | public final class NodeIdSerializer extends Serializer<NodeId> { |
13 | 14 | ||
15 | + /** | ||
16 | + * Creates {@link NodeId} serializer instance. | ||
17 | + */ | ||
18 | + public NodeIdSerializer() { | ||
19 | + // non-null, immutable | ||
20 | + super(false, true); | ||
21 | + } | ||
22 | + | ||
14 | @Override | 23 | @Override |
15 | public void write(Kryo kryo, Output output, NodeId object) { | 24 | public void write(Kryo kryo, Output output, NodeId object) { |
16 | kryo.writeObject(output, object.toString()); | 25 | kryo.writeObject(output, object.toString()); | ... | ... |
... | @@ -14,7 +14,7 @@ public final class PortNumberSerializer extends | ... | @@ -14,7 +14,7 @@ public final class PortNumberSerializer extends |
14 | Serializer<PortNumber> { | 14 | Serializer<PortNumber> { |
15 | 15 | ||
16 | /** | 16 | /** |
17 | - * Default constructor. | 17 | + * Creates {@link PortNumber} serializer instance. |
18 | */ | 18 | */ |
19 | public PortNumberSerializer() { | 19 | public PortNumberSerializer() { |
20 | // non-null, immutable | 20 | // non-null, immutable | ... | ... |
... | @@ -13,7 +13,7 @@ import com.esotericsoftware.kryo.io.Output; | ... | @@ -13,7 +13,7 @@ import com.esotericsoftware.kryo.io.Output; |
13 | public class ProviderIdSerializer extends Serializer<ProviderId> { | 13 | public class ProviderIdSerializer extends Serializer<ProviderId> { |
14 | 14 | ||
15 | /** | 15 | /** |
16 | - * Default constructor. | 16 | + * Creates {@link ProviderId} serializer instance. |
17 | */ | 17 | */ |
18 | public ProviderIdSerializer() { | 18 | public ProviderIdSerializer() { |
19 | // non-null, immutable | 19 | // non-null, immutable | ... | ... |
... | @@ -3,16 +3,11 @@ package org.onlab.onos.store.serializers; | ... | @@ -3,16 +3,11 @@ package org.onlab.onos.store.serializers; |
3 | import static org.onlab.onos.net.DeviceId.deviceId; | 3 | import static org.onlab.onos.net.DeviceId.deviceId; |
4 | import static org.onlab.onos.net.PortNumber.portNumber; | 4 | import static org.onlab.onos.net.PortNumber.portNumber; |
5 | 5 | ||
6 | -import java.net.URI; | ||
7 | import java.nio.ByteBuffer; | 6 | import java.nio.ByteBuffer; |
8 | -import java.util.ArrayList; | ||
9 | -import java.util.HashMap; | ||
10 | - | ||
11 | import org.junit.After; | 7 | import org.junit.After; |
12 | import org.junit.Before; | 8 | import org.junit.Before; |
13 | import org.junit.BeforeClass; | 9 | import org.junit.BeforeClass; |
14 | import org.junit.Test; | 10 | import org.junit.Test; |
15 | -import org.onlab.onos.cluster.MastershipTerm; | ||
16 | import org.onlab.onos.cluster.NodeId; | 11 | import org.onlab.onos.cluster.NodeId; |
17 | import org.onlab.onos.net.ConnectPoint; | 12 | import org.onlab.onos.net.ConnectPoint; |
18 | import org.onlab.onos.net.DefaultDevice; | 13 | import org.onlab.onos.net.DefaultDevice; |
... | @@ -22,7 +17,6 @@ import org.onlab.onos.net.Device; | ... | @@ -22,7 +17,6 @@ import org.onlab.onos.net.Device; |
22 | import org.onlab.onos.net.DeviceId; | 17 | import org.onlab.onos.net.DeviceId; |
23 | import org.onlab.onos.net.Link; | 18 | import org.onlab.onos.net.Link; |
24 | import org.onlab.onos.net.LinkKey; | 19 | import org.onlab.onos.net.LinkKey; |
25 | -import org.onlab.onos.net.MastershipRole; | ||
26 | import org.onlab.onos.net.PortNumber; | 20 | import org.onlab.onos.net.PortNumber; |
27 | import org.onlab.onos.net.provider.ProviderId; | 21 | import org.onlab.onos.net.provider.ProviderId; |
28 | import org.onlab.packet.IpPrefix; | 22 | import org.onlab.packet.IpPrefix; |
... | @@ -32,8 +26,6 @@ import com.google.common.collect.ImmutableMap; | ... | @@ -32,8 +26,6 @@ import com.google.common.collect.ImmutableMap; |
32 | import com.google.common.collect.ImmutableSet; | 26 | import com.google.common.collect.ImmutableSet; |
33 | import com.google.common.testing.EqualsTester; | 27 | import com.google.common.testing.EqualsTester; |
34 | 28 | ||
35 | -import de.javakaffee.kryoserializers.URISerializer; | ||
36 | - | ||
37 | public class KryoSerializerTests { | 29 | public class KryoSerializerTests { |
38 | private static final ProviderId PID = new ProviderId("of", "foo"); | 30 | private static final ProviderId PID = new ProviderId("of", "foo"); |
39 | private static final DeviceId DID1 = deviceId("of:foo"); | 31 | private static final DeviceId DID1 = deviceId("of:foo"); |
... | @@ -54,38 +46,12 @@ public class KryoSerializerTests { | ... | @@ -54,38 +46,12 @@ public class KryoSerializerTests { |
54 | @BeforeClass | 46 | @BeforeClass |
55 | public static void setUpBeforeClass() throws Exception { | 47 | public static void setUpBeforeClass() throws Exception { |
56 | kryos = KryoPool.newBuilder() | 48 | kryos = KryoPool.newBuilder() |
57 | - .register( | 49 | + .register(KryoPoolUtil.API) |
58 | - ArrayList.class, | ||
59 | - HashMap.class | ||
60 | - ) | ||
61 | - .register( | ||
62 | - Device.Type.class, | ||
63 | - Link.Type.class | ||
64 | - | ||
65 | -// ControllerNode.State.class, | ||
66 | -// DefaultControllerNode.class, | ||
67 | -// MastershipRole.class, | ||
68 | -// Port.class, | ||
69 | -// Element.class, | ||
70 | - ) | ||
71 | - .register(ConnectPoint.class, new ConnectPointSerializer()) | ||
72 | - .register(DefaultLink.class, new DefaultLinkSerializer()) | ||
73 | - .register(DefaultPort.class, new DefaultPortSerializer()) | ||
74 | - .register(DeviceId.class, new DeviceIdSerializer()) | ||
75 | .register(ImmutableMap.class, new ImmutableMapSerializer()) | 50 | .register(ImmutableMap.class, new ImmutableMapSerializer()) |
76 | .register(ImmutableSet.class, new ImmutableSetSerializer()) | 51 | .register(ImmutableSet.class, new ImmutableSetSerializer()) |
77 | - .register(IpPrefix.class, new IpPrefixSerializer()) | ||
78 | - .register(LinkKey.class, new LinkKeySerializer()) | ||
79 | - .register(NodeId.class, new NodeIdSerializer()) | ||
80 | - .register(PortNumber.class, new PortNumberSerializer()) | ||
81 | - .register(ProviderId.class, new ProviderIdSerializer()) | ||
82 | 52 | ||
83 | - .register(DefaultDevice.class) | ||
84 | 53 | ||
85 | - .register(URI.class, new URISerializer()) | ||
86 | 54 | ||
87 | - .register(MastershipRole.class, new MastershipRoleSerializer()) | ||
88 | - .register(MastershipTerm.class, new MastershipTermSerializer()) | ||
89 | .build(); | 55 | .build(); |
90 | } | 56 | } |
91 | 57 | ... | ... |
... | @@ -4,27 +4,15 @@ import org.apache.felix.scr.annotations.Component; | ... | @@ -4,27 +4,15 @@ import org.apache.felix.scr.annotations.Component; |
4 | import org.apache.felix.scr.annotations.Service; | 4 | import org.apache.felix.scr.annotations.Service; |
5 | import org.onlab.onos.cluster.MastershipTerm; | 5 | import org.onlab.onos.cluster.MastershipTerm; |
6 | import org.onlab.onos.net.DeviceId; | 6 | import org.onlab.onos.net.DeviceId; |
7 | -import org.onlab.onos.store.ClockService; | 7 | +import org.onlab.onos.store.ClockProviderService; |
8 | -import org.onlab.onos.store.Timestamp; | ||
9 | 8 | ||
10 | //FIXME: Code clone in onos-core-trivial, onos-core-hz-net | 9 | //FIXME: Code clone in onos-core-trivial, onos-core-hz-net |
11 | /** | 10 | /** |
12 | - * Dummy implementation of {@link ClockService}. | 11 | + * Dummy implementation of {@link ClockProviderService}. |
13 | */ | 12 | */ |
14 | @Component(immediate = true) | 13 | @Component(immediate = true) |
15 | @Service | 14 | @Service |
16 | -public class NoOpClockService implements ClockService { | 15 | +public class NoOpClockProviderService implements ClockProviderService { |
17 | - | ||
18 | - @Override | ||
19 | - public Timestamp getTimestamp(DeviceId deviceId) { | ||
20 | - return new Timestamp() { | ||
21 | - | ||
22 | - @Override | ||
23 | - public int compareTo(Timestamp o) { | ||
24 | - throw new IllegalStateException("Never expected to be used."); | ||
25 | - } | ||
26 | - }; | ||
27 | - } | ||
28 | 16 | ||
29 | @Override | 17 | @Override |
30 | public void setMastershipTerm(DeviceId deviceId, MastershipTerm term) { | 18 | public void setMastershipTerm(DeviceId deviceId, MastershipTerm term) { | ... | ... |
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 | +} |
... | @@ -32,6 +32,7 @@ import static org.onlab.onos.net.Link.Type.INDIRECT; | ... | @@ -32,6 +32,7 @@ import static org.onlab.onos.net.Link.Type.INDIRECT; |
32 | import static org.onlab.onos.net.link.LinkEvent.Type.*; | 32 | import static org.onlab.onos.net.link.LinkEvent.Type.*; |
33 | import static org.slf4j.LoggerFactory.getLogger; | 33 | import static org.slf4j.LoggerFactory.getLogger; |
34 | 34 | ||
35 | +// TODO: Add support for multiple provider and annotations | ||
35 | /** | 36 | /** |
36 | * Manages inventory of infrastructure links using trivial in-memory structures | 37 | * Manages inventory of infrastructure links using trivial in-memory structures |
37 | * implementation. | 38 | * implementation. | ... | ... |
... | @@ -480,7 +480,7 @@ | ... | @@ -480,7 +480,7 @@ |
480 | <group> | 480 | <group> |
481 | <title>Core Subsystems</title> | 481 | <title>Core Subsystems</title> |
482 | <packages> | 482 | <packages> |
483 | - org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.* | 483 | + org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl |
484 | </packages> | 484 | </packages> |
485 | </group> | 485 | </group> |
486 | <group> | 486 | <group> | ... | ... |
... | @@ -113,7 +113,7 @@ public class FlowRuleBuilder { | ... | @@ -113,7 +113,7 @@ public class FlowRuleBuilder { |
113 | } | 113 | } |
114 | 114 | ||
115 | private TrafficTreatment buildTreatment() { | 115 | private TrafficTreatment buildTreatment() { |
116 | - TrafficTreatment.Builder builder = new DefaultTrafficTreatment.Builder(); | 116 | + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); |
117 | // If this is a drop rule | 117 | // If this is a drop rule |
118 | if (actions.size() == 0) { | 118 | if (actions.size() == 0) { |
119 | builder.drop(); | 119 | builder.drop(); |
... | @@ -198,7 +198,7 @@ public class FlowRuleBuilder { | ... | @@ -198,7 +198,7 @@ public class FlowRuleBuilder { |
198 | } | 198 | } |
199 | 199 | ||
200 | private TrafficSelector buildSelector() { | 200 | private TrafficSelector buildSelector() { |
201 | - TrafficSelector.Builder builder = new DefaultTrafficSelector.Builder(); | 201 | + TrafficSelector.Builder builder = DefaultTrafficSelector.builder(); |
202 | for (MatchField<?> field : match.getMatchFields()) { | 202 | for (MatchField<?> field : match.getMatchFields()) { |
203 | switch (field.id) { | 203 | switch (field.id) { |
204 | case IN_PORT: | 204 | case IN_PORT: | ... | ... |
... | @@ -181,7 +181,7 @@ public class OpenFlowPacketProviderTest { | ... | @@ -181,7 +181,7 @@ public class OpenFlowPacketProviderTest { |
181 | } | 181 | } |
182 | 182 | ||
183 | private static TrafficTreatment treatment(Instruction ... insts) { | 183 | private static TrafficTreatment treatment(Instruction ... insts) { |
184 | - TrafficTreatment.Builder builder = new DefaultTrafficTreatment.Builder(); | 184 | + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); |
185 | for (Instruction i : insts) { | 185 | for (Instruction i : insts) { |
186 | builder.add(i); | 186 | builder.add(i); |
187 | } | 187 | } | ... | ... |
... | @@ -21,7 +21,7 @@ export PATH="$PATH:." | ... | @@ -21,7 +21,7 @@ export PATH="$PATH:." |
21 | # e.g. 'o api', 'o dev', 'o' | 21 | # e.g. 'o api', 'o dev', 'o' |
22 | function o { | 22 | function o { |
23 | cd $(find $ONOS_ROOT/ -type d | egrep -v '\.git|target' | \ | 23 | cd $(find $ONOS_ROOT/ -type d | egrep -v '\.git|target' | \ |
24 | - egrep "${1:-$ONOS_ROOT}" | head -n 1) | 24 | + egrep "${1:-$ONOS_ROOT}" | egrep -v "$ONOS_ROOT/.+/src/" | head -n 1) |
25 | } | 25 | } |
26 | 26 | ||
27 | # Short-hand for 'mvn clean install' for us lazy folk | 27 | # Short-hand for 'mvn clean install' for us lazy folk | ... | ... |
... | @@ -11,7 +11,7 @@ public class MetricsFeature { | ... | @@ -11,7 +11,7 @@ public class MetricsFeature { |
11 | * | 11 | * |
12 | * @param newName name of the Feature | 12 | * @param newName name of the Feature |
13 | */ | 13 | */ |
14 | - MetricsFeature(final String newName) { | 14 | + public MetricsFeature(final String newName) { |
15 | name = newName; | 15 | name = newName; |
16 | } | 16 | } |
17 | 17 | ... | ... |
... | @@ -2,16 +2,43 @@ package org.onlab.netty; | ... | @@ -2,16 +2,43 @@ package org.onlab.netty; |
2 | 2 | ||
3 | import java.util.concurrent.TimeUnit; | 3 | import java.util.concurrent.TimeUnit; |
4 | 4 | ||
5 | +import org.onlab.metrics.MetricsComponent; | ||
6 | +import org.onlab.metrics.MetricsFeature; | ||
7 | +import org.onlab.metrics.MetricsManager; | ||
8 | + | ||
9 | +import com.codahale.metrics.Timer; | ||
10 | + | ||
5 | public final class SimpleClient { | 11 | public final class SimpleClient { |
6 | - private SimpleClient() {} | 12 | + private SimpleClient() { |
13 | + } | ||
7 | 14 | ||
8 | public static void main(String... args) throws Exception { | 15 | public static void main(String... args) throws Exception { |
9 | NettyMessagingService messaging = new TestNettyMessagingService(9081); | 16 | NettyMessagingService messaging = new TestNettyMessagingService(9081); |
17 | + MetricsManager metrics = new MetricsManager(); | ||
10 | messaging.activate(); | 18 | messaging.activate(); |
11 | - | 19 | + metrics.activate(); |
20 | + MetricsFeature feature = new MetricsFeature("timers"); | ||
21 | + MetricsComponent component = metrics.registerComponent("NettyMessaging"); | ||
22 | + Timer sendAsyncTimer = metrics.createTimer(component, feature, "AsyncSender"); | ||
23 | + final int warmup = 100; | ||
24 | + for (int i = 0; i < warmup; i++) { | ||
25 | + Timer.Context context = sendAsyncTimer.time(); | ||
12 | messaging.sendAsync(new Endpoint("localhost", 8080), "simple", "Hello World"); | 26 | messaging.sendAsync(new Endpoint("localhost", 8080), "simple", "Hello World"); |
13 | - Response<String> response = messaging.sendAndReceive(new Endpoint("localhost", 8080), "echo", "Hello World"); | 27 | + context.stop(); |
28 | + } | ||
29 | + metrics.registerMetric(component, feature, "AsyncTimer", sendAsyncTimer); | ||
30 | + | ||
31 | + Timer sendAndReceiveTimer = metrics.createTimer(component, feature, "SendAndReceive"); | ||
32 | + final int iterations = 1000000; | ||
33 | + for (int i = 0; i < iterations; i++) { | ||
34 | + Timer.Context context = sendAndReceiveTimer.time(); | ||
35 | + Response<String> response = messaging | ||
36 | + .sendAndReceive(new Endpoint("localhost", 8080), "echo", | ||
37 | + "Hello World"); | ||
14 | System.out.println("Got back:" + response.get(2, TimeUnit.SECONDS)); | 38 | System.out.println("Got back:" + response.get(2, TimeUnit.SECONDS)); |
39 | + context.stop(); | ||
40 | + } | ||
41 | + metrics.registerMetric(component, feature, "AsyncTimer", sendAndReceiveTimer); | ||
15 | } | 42 | } |
16 | 43 | ||
17 | public static class TestNettyMessagingService extends NettyMessagingService { | 44 | public static class TestNettyMessagingService extends NettyMessagingService { | ... | ... |
-
Please register or login to post a comment