Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Showing
106 changed files
with
2482 additions
and
429 deletions
... | @@ -100,6 +100,7 @@ public class ReactiveForwarding { | ... | @@ -100,6 +100,7 @@ public class ReactiveForwarding { |
100 | context.block(); | 100 | context.block(); |
101 | return; | 101 | return; |
102 | } | 102 | } |
103 | + | ||
103 | HostId id = HostId.hostId(ethPkt.getDestinationMAC()); | 104 | HostId id = HostId.hostId(ethPkt.getDestinationMAC()); |
104 | 105 | ||
105 | // Do we know who this is for? If not, flood and bail. | 106 | // Do we know who this is for? If not, flood and bail. |
... | @@ -112,7 +113,9 @@ public class ReactiveForwarding { | ... | @@ -112,7 +113,9 @@ public class ReactiveForwarding { |
112 | // Are we on an edge switch that our destination is on? If so, | 113 | // Are we on an edge switch that our destination is on? If so, |
113 | // simply forward out to the destination and bail. | 114 | // simply forward out to the destination and bail. |
114 | if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) { | 115 | if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) { |
116 | + if (!context.inPacket().receivedFrom().port().equals(dst.location().port())) { | ||
115 | installRule(context, dst.location().port()); | 117 | installRule(context, dst.location().port()); |
118 | + } | ||
116 | return; | 119 | return; |
117 | } | 120 | } |
118 | 121 | ||
... | @@ -175,6 +178,8 @@ public class ReactiveForwarding { | ... | @@ -175,6 +178,8 @@ public class ReactiveForwarding { |
175 | // We don't yet support bufferids in the flowservice so packet out first. | 178 | // We don't yet support bufferids in the flowservice so packet out first. |
176 | packetOut(context, portNumber); | 179 | packetOut(context, portNumber); |
177 | 180 | ||
181 | + if (context.inPacket().parsed().getEtherType() == Ethernet.TYPE_IPV4) { | ||
182 | + | ||
178 | // Install the flow rule to handle this type of message from now on. | 183 | // Install the flow rule to handle this type of message from now on. |
179 | Ethernet inPkt = context.inPacket().parsed(); | 184 | Ethernet inPkt = context.inPacket().parsed(); |
180 | TrafficSelector.Builder builder = new DefaultTrafficSelector.Builder(); | 185 | TrafficSelector.Builder builder = new DefaultTrafficSelector.Builder(); |
... | @@ -191,6 +196,7 @@ public class ReactiveForwarding { | ... | @@ -191,6 +196,7 @@ public class ReactiveForwarding { |
191 | 196 | ||
192 | flowRuleService.applyFlowRules(f); | 197 | flowRuleService.applyFlowRules(f); |
193 | } | 198 | } |
199 | + } | ||
194 | 200 | ||
195 | } | 201 | } |
196 | 202 | ... | ... |
... | @@ -56,7 +56,8 @@ public interface MastershipService { | ... | @@ -56,7 +56,8 @@ public interface MastershipService { |
56 | Set<DeviceId> getDevicesOf(NodeId nodeId); | 56 | Set<DeviceId> getDevicesOf(NodeId nodeId); |
57 | 57 | ||
58 | /** | 58 | /** |
59 | - * Returns the mastership term service for getting term information. | 59 | + * Returns the mastership term service for getting read-only |
60 | + * term information. | ||
60 | * | 61 | * |
61 | * @return the MastershipTermService for this mastership manager | 62 | * @return the MastershipTermService for this mastership manager |
62 | */ | 63 | */ | ... | ... |
... | @@ -64,4 +64,14 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD | ... | @@ -64,4 +64,14 @@ public interface MastershipStore extends Store<MastershipEvent, MastershipStoreD |
64 | * @return the current master's ID and the term value for device, or null | 64 | * @return the current master's ID and the term value for device, or null |
65 | */ | 65 | */ |
66 | MastershipTerm getTermFor(DeviceId deviceId); | 66 | MastershipTerm getTermFor(DeviceId deviceId); |
67 | + | ||
68 | + /** | ||
69 | + * Revokes a controller instance's mastership over a device and hands | ||
70 | + * over mastership to another controller instance. | ||
71 | + * | ||
72 | + * @param nodeId the controller instance identifier | ||
73 | + * @param deviceId device to revoke mastership for | ||
74 | + * @return a mastership event | ||
75 | + */ | ||
76 | + MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId); | ||
67 | } | 77 | } | ... | ... |
1 | +package org.onlab.onos.net; | ||
2 | + | ||
3 | +import com.google.common.collect.ImmutableSet; | ||
4 | + | ||
5 | +import java.util.HashMap; | ||
6 | +import java.util.Map; | ||
7 | +import java.util.Set; | ||
8 | + | ||
9 | +import static com.google.common.base.Preconditions.checkArgument; | ||
10 | + | ||
11 | +/** | ||
12 | + * Base abstraction of an annotated entity. | ||
13 | + */ | ||
14 | +public class AbstractAnnotated implements Annotated { | ||
15 | + | ||
16 | + private static final Map<String, String> EMPTY = new HashMap<>(); | ||
17 | + | ||
18 | + private final Map<String, String> annotations; | ||
19 | + | ||
20 | + // For serialization | ||
21 | + protected AbstractAnnotated() { | ||
22 | + this.annotations = EMPTY; | ||
23 | + } | ||
24 | + | ||
25 | + /** | ||
26 | + * Creates a new entity, annotated with the specified annotations. | ||
27 | + * | ||
28 | + * @param annotations optional key/value annotations map | ||
29 | + */ | ||
30 | + protected AbstractAnnotated(Map<String, String>[] annotations) { | ||
31 | + checkArgument(annotations.length <= 1, "Only one set of annotations is expected"); | ||
32 | + this.annotations = annotations.length == 1 ? annotations[0] : EMPTY; | ||
33 | + } | ||
34 | + | ||
35 | + @Override | ||
36 | + public Set<String> annotationKeys() { | ||
37 | + return ImmutableSet.copyOf(annotations.keySet()); | ||
38 | + } | ||
39 | + | ||
40 | + @Override | ||
41 | + public String annotation(String key) { | ||
42 | + return annotations.get(key); | ||
43 | + } | ||
44 | + | ||
45 | +} |
... | @@ -2,10 +2,12 @@ package org.onlab.onos.net; | ... | @@ -2,10 +2,12 @@ package org.onlab.onos.net; |
2 | 2 | ||
3 | import org.onlab.onos.net.provider.ProviderId; | 3 | import org.onlab.onos.net.provider.ProviderId; |
4 | 4 | ||
5 | +import java.util.Map; | ||
6 | + | ||
5 | /** | 7 | /** |
6 | * Base implementation of a network model entity. | 8 | * Base implementation of a network model entity. |
7 | */ | 9 | */ |
8 | -public class AbstractModel implements Provided { | 10 | +public class AbstractModel extends AbstractAnnotated implements Provided { |
9 | 11 | ||
10 | private final ProviderId providerId; | 12 | private final ProviderId providerId; |
11 | 13 | ||
... | @@ -15,11 +17,16 @@ public class AbstractModel implements Provided { | ... | @@ -15,11 +17,16 @@ public class AbstractModel implements Provided { |
15 | } | 17 | } |
16 | 18 | ||
17 | /** | 19 | /** |
18 | - * Creates a model entity attributed to the specified provider. | 20 | + * Creates a model entity attributed to the specified provider and |
21 | + * optionally annotated. | ||
19 | * | 22 | * |
20 | * @param providerId identity of the provider | 23 | * @param providerId identity of the provider |
24 | + * @param annotations optional key/value annotations | ||
21 | */ | 25 | */ |
22 | - protected AbstractModel(ProviderId providerId) { | 26 | + @SafeVarargs |
27 | + protected AbstractModel(ProviderId providerId, | ||
28 | + Map<String, String>... annotations) { | ||
29 | + super(annotations); | ||
23 | this.providerId = providerId; | 30 | this.providerId = providerId; |
24 | } | 31 | } |
25 | 32 | ... | ... |
1 | +package org.onlab.onos.net; | ||
2 | + | ||
3 | +import java.util.Set; | ||
4 | + | ||
5 | +/** | ||
6 | + * Represents an entity that carries arbitrary annotations. | ||
7 | + */ | ||
8 | +public interface Annotated { | ||
9 | + | ||
10 | + /** | ||
11 | + * Returns the set of annotation keys currently available. | ||
12 | + * | ||
13 | + * @return set of annotation keys | ||
14 | + */ | ||
15 | + Set<String> annotationKeys(); | ||
16 | + | ||
17 | + /** | ||
18 | + * Returns the annotation value for the specified key. | ||
19 | + * | ||
20 | + * @param key annotation key | ||
21 | + * @return annotation value; null if there is no annotation | ||
22 | + */ | ||
23 | + String annotation(String key); | ||
24 | + | ||
25 | +} |
... | @@ -3,5 +3,5 @@ package org.onlab.onos.net; | ... | @@ -3,5 +3,5 @@ package org.onlab.onos.net; |
3 | /** | 3 | /** |
4 | * Base abstraction of a piece of information about network elements. | 4 | * Base abstraction of a piece of information about network elements. |
5 | */ | 5 | */ |
6 | -public interface Description { | 6 | +public interface Description extends Annotated { |
7 | } | 7 | } | ... | ... |
1 | package org.onlab.onos.net.device; | 1 | package org.onlab.onos.net.device; |
2 | 2 | ||
3 | +import org.onlab.onos.net.AbstractAnnotated; | ||
4 | + | ||
3 | import java.net.URI; | 5 | import java.net.URI; |
6 | +import java.util.Map; | ||
4 | 7 | ||
5 | import static com.google.common.base.MoreObjects.toStringHelper; | 8 | import static com.google.common.base.MoreObjects.toStringHelper; |
6 | import static com.google.common.base.Preconditions.checkNotNull; | 9 | import static com.google.common.base.Preconditions.checkNotNull; |
... | @@ -9,7 +12,8 @@ import static org.onlab.onos.net.Device.Type; | ... | @@ -9,7 +12,8 @@ import static org.onlab.onos.net.Device.Type; |
9 | /** | 12 | /** |
10 | * Default implementation of immutable device description entity. | 13 | * Default implementation of immutable device description entity. |
11 | */ | 14 | */ |
12 | -public class DefaultDeviceDescription implements DeviceDescription { | 15 | +public class DefaultDeviceDescription extends AbstractAnnotated |
16 | + implements DeviceDescription { | ||
13 | private final URI uri; | 17 | private final URI uri; |
14 | private final Type type; | 18 | private final Type type; |
15 | private final String manufacturer; | 19 | private final String manufacturer; |
... | @@ -26,10 +30,14 @@ public class DefaultDeviceDescription implements DeviceDescription { | ... | @@ -26,10 +30,14 @@ public class DefaultDeviceDescription implements DeviceDescription { |
26 | * @param hwVersion device HW version | 30 | * @param hwVersion device HW version |
27 | * @param swVersion device SW version | 31 | * @param swVersion device SW version |
28 | * @param serialNumber device serial number | 32 | * @param serialNumber device serial number |
33 | + * @param annotations optional key/value annotations map | ||
29 | */ | 34 | */ |
35 | + @SafeVarargs | ||
30 | public DefaultDeviceDescription(URI uri, Type type, String manufacturer, | 36 | public DefaultDeviceDescription(URI uri, Type type, String manufacturer, |
31 | String hwVersion, String swVersion, | 37 | String hwVersion, String swVersion, |
32 | - String serialNumber) { | 38 | + String serialNumber, |
39 | + Map<String, String>... annotations) { | ||
40 | + super(annotations); | ||
33 | this.uri = checkNotNull(uri, "Device URI cannot be null"); | 41 | this.uri = checkNotNull(uri, "Device URI cannot be null"); |
34 | this.type = checkNotNull(type, "Device type cannot be null"); | 42 | this.type = checkNotNull(type, "Device type cannot be null"); |
35 | this.manufacturer = manufacturer; | 43 | this.manufacturer = manufacturer; | ... | ... |
... | @@ -48,6 +48,7 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { | ... | @@ -48,6 +48,7 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { |
48 | DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, | 48 | DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, |
49 | DeviceDescription deviceDescription); | 49 | DeviceDescription deviceDescription); |
50 | 50 | ||
51 | + // TODO: We may need to enforce that ancillary cannot interfere this state | ||
51 | /** | 52 | /** |
52 | * Removes the specified infrastructure device. | 53 | * Removes the specified infrastructure device. |
53 | * | 54 | * |
... | @@ -60,22 +61,24 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { | ... | @@ -60,22 +61,24 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { |
60 | * Updates the ports of the specified infrastructure device using the given | 61 | * Updates the ports of the specified infrastructure device using the given |
61 | * list of port descriptions. The list is assumed to be comprehensive. | 62 | * list of port descriptions. The list is assumed to be comprehensive. |
62 | * | 63 | * |
64 | + * @param providerId provider identifier | ||
63 | * @param deviceId device identifier | 65 | * @param deviceId device identifier |
64 | * @param portDescriptions list of port descriptions | 66 | * @param portDescriptions list of port descriptions |
65 | * @return ready to send events describing what occurred; empty list if no change | 67 | * @return ready to send events describing what occurred; empty list if no change |
66 | */ | 68 | */ |
67 | - List<DeviceEvent> updatePorts(DeviceId deviceId, | 69 | + List<DeviceEvent> updatePorts(ProviderId providerId, DeviceId deviceId, |
68 | List<PortDescription> portDescriptions); | 70 | List<PortDescription> portDescriptions); |
69 | 71 | ||
70 | /** | 72 | /** |
71 | * Updates the port status of the specified infrastructure device using the | 73 | * Updates the port status of the specified infrastructure device using the |
72 | * given port description. | 74 | * given port description. |
73 | * | 75 | * |
76 | + * @param providerId provider identifier | ||
74 | * @param deviceId device identifier | 77 | * @param deviceId device identifier |
75 | * @param portDescription port description | 78 | * @param portDescription port description |
76 | * @return ready to send event describing what occurred; null if no change | 79 | * @return ready to send event describing what occurred; null if no change |
77 | */ | 80 | */ |
78 | - DeviceEvent updatePortStatus(DeviceId deviceId, | 81 | + DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, |
79 | PortDescription portDescription); | 82 | PortDescription portDescription); |
80 | 83 | ||
81 | /** | 84 | /** | ... | ... |
... | @@ -27,9 +27,11 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -27,9 +27,11 @@ public class DefaultFlowRule implements FlowRule { |
27 | 27 | ||
28 | private final ApplicationId appId; | 28 | private final ApplicationId appId; |
29 | 29 | ||
30 | + private boolean expired; | ||
31 | + | ||
30 | public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector, | 32 | public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector, |
31 | TrafficTreatment treatment, int priority, FlowRuleState state, | 33 | TrafficTreatment treatment, int priority, FlowRuleState state, |
32 | - long life, long packets, long bytes, long flowId) { | 34 | + long life, long packets, long bytes, long flowId, boolean expired) { |
33 | this.deviceId = deviceId; | 35 | this.deviceId = deviceId; |
34 | this.priority = priority; | 36 | this.priority = priority; |
35 | this.selector = selector; | 37 | this.selector = selector; |
... | @@ -37,7 +39,7 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -37,7 +39,7 @@ public class DefaultFlowRule implements FlowRule { |
37 | this.state = state; | 39 | this.state = state; |
38 | this.appId = ApplicationId.valueOf((int) (flowId >> 32)); | 40 | this.appId = ApplicationId.valueOf((int) (flowId >> 32)); |
39 | this.id = FlowId.valueOf(flowId); | 41 | this.id = FlowId.valueOf(flowId); |
40 | - | 42 | + this.expired = expired; |
41 | this.life = life; | 43 | this.life = life; |
42 | this.packets = packets; | 44 | this.packets = packets; |
43 | this.bytes = bytes; | 45 | this.bytes = bytes; |
... | @@ -186,4 +188,9 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -186,4 +188,9 @@ public class DefaultFlowRule implements FlowRule { |
186 | .toString(); | 188 | .toString(); |
187 | } | 189 | } |
188 | 190 | ||
191 | + @Override | ||
192 | + public boolean expired() { | ||
193 | + return expired; | ||
194 | + } | ||
195 | + | ||
189 | } | 196 | } | ... | ... |
... | @@ -111,4 +111,11 @@ public interface FlowRule { | ... | @@ -111,4 +111,11 @@ public interface FlowRule { |
111 | */ | 111 | */ |
112 | long bytes(); | 112 | long bytes(); |
113 | 113 | ||
114 | + /** | ||
115 | + * Indicates that this flow has expired at the device. | ||
116 | + * | ||
117 | + * @return true if it has expired, false otherwise | ||
118 | + */ | ||
119 | + boolean expired(); | ||
120 | + | ||
114 | } | 121 | } | ... | ... |
1 | package org.onlab.onos.net.host; | 1 | package org.onlab.onos.net.host; |
2 | 2 | ||
3 | -import static com.google.common.base.MoreObjects.toStringHelper; | 3 | +import com.google.common.collect.ImmutableSet; |
4 | - | 4 | +import org.onlab.onos.net.AbstractAnnotated; |
5 | -import java.util.HashSet; | ||
6 | -import java.util.Set; | ||
7 | - | ||
8 | import org.onlab.onos.net.HostLocation; | 5 | import org.onlab.onos.net.HostLocation; |
9 | import org.onlab.packet.IpPrefix; | 6 | import org.onlab.packet.IpPrefix; |
10 | import org.onlab.packet.MacAddress; | 7 | import org.onlab.packet.MacAddress; |
11 | import org.onlab.packet.VlanId; | 8 | import org.onlab.packet.VlanId; |
12 | 9 | ||
13 | -import com.google.common.collect.ImmutableSet; | 10 | +import java.util.HashSet; |
11 | +import java.util.Map; | ||
12 | +import java.util.Set; | ||
13 | + | ||
14 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
14 | 15 | ||
15 | -public class DefaultHostDescription implements HostDescription { | 16 | +/** |
17 | + * Default implementation of an immutable host description. | ||
18 | + */ | ||
19 | +public class DefaultHostDescription extends AbstractAnnotated | ||
20 | + implements HostDescription { | ||
16 | 21 | ||
17 | private final MacAddress mac; | 22 | private final MacAddress mac; |
18 | private final VlanId vlan; | 23 | private final VlanId vlan; |
19 | private final HostLocation location; | 24 | private final HostLocation location; |
20 | private final Set<IpPrefix> ips; | 25 | private final Set<IpPrefix> ips; |
21 | 26 | ||
27 | + /** | ||
28 | + * Creates a host description using the supplied information. | ||
29 | + * | ||
30 | + * @param mac host MAC address | ||
31 | + * @param vlan host VLAN identifier | ||
32 | + * @param location host location | ||
33 | + * @param annotations optional key/value annotations map | ||
34 | + */ | ||
35 | + @SafeVarargs | ||
22 | public DefaultHostDescription(MacAddress mac, VlanId vlan, | 36 | public DefaultHostDescription(MacAddress mac, VlanId vlan, |
23 | - HostLocation loc) { | 37 | + HostLocation location, |
24 | - this.mac = mac; | 38 | + Map<String, String>... annotations) { |
25 | - this.vlan = vlan; | 39 | + this(mac, vlan, location, new HashSet<IpPrefix>(), annotations); |
26 | - this.location = loc; | ||
27 | - this.ips = new HashSet<IpPrefix>(); | ||
28 | } | 40 | } |
29 | 41 | ||
42 | + /** | ||
43 | + * Creates a host description using the supplied information. | ||
44 | + * | ||
45 | + * @param mac host MAC address | ||
46 | + * @param vlan host VLAN identifier | ||
47 | + * @param location host location | ||
48 | + * @param ips of host IP addresses | ||
49 | + * @param annotations optional key/value annotations map | ||
50 | + */ | ||
51 | + @SafeVarargs | ||
30 | public DefaultHostDescription(MacAddress mac, VlanId vlan, | 52 | public DefaultHostDescription(MacAddress mac, VlanId vlan, |
31 | - HostLocation loc, Set<IpPrefix> ips) { | 53 | + HostLocation location, Set<IpPrefix> ips, |
54 | + Map<String, String>... annotations) { | ||
55 | + super(annotations); | ||
32 | this.mac = mac; | 56 | this.mac = mac; |
33 | this.vlan = vlan; | 57 | this.vlan = vlan; |
34 | - this.location = loc; | 58 | + this.location = location; |
35 | - this.ips = new HashSet<IpPrefix>(ips); | 59 | + this.ips = new HashSet<>(ips); |
36 | } | 60 | } |
37 | 61 | ||
38 | @Override | 62 | @Override | ... | ... |
... | @@ -35,10 +35,22 @@ public abstract class AbstractProviderRegistry<P extends Provider, S extends Pro | ... | @@ -35,10 +35,22 @@ public abstract class AbstractProviderRegistry<P extends Provider, S extends Pro |
35 | public synchronized S register(P provider) { | 35 | public synchronized S register(P provider) { |
36 | checkNotNull(provider, "Provider cannot be null"); | 36 | checkNotNull(provider, "Provider cannot be null"); |
37 | checkState(!services.containsKey(provider.id()), "Provider %s already registered", provider.id()); | 37 | checkState(!services.containsKey(provider.id()), "Provider %s already registered", provider.id()); |
38 | + | ||
39 | + // If the provider is a primary one, check for a conflict. | ||
40 | + ProviderId pid = provider.id(); | ||
41 | + checkState(pid.isAncillary() || !providersByScheme.containsKey(pid.scheme()), | ||
42 | + "A primary provider with id %s is already registered", | ||
43 | + providersByScheme.get(pid.scheme())); | ||
44 | + | ||
38 | S service = createProviderService(provider); | 45 | S service = createProviderService(provider); |
39 | services.put(provider.id(), service); | 46 | services.put(provider.id(), service); |
40 | providers.put(provider.id(), provider); | 47 | providers.put(provider.id(), provider); |
41 | - // FIXME populate scheme look-up | 48 | + |
49 | + // Register the provider by URI scheme only if it is not ancillary. | ||
50 | + if (!pid.isAncillary()) { | ||
51 | + providersByScheme.put(pid.scheme(), provider); | ||
52 | + } | ||
53 | + | ||
42 | return service; | 54 | return service; |
43 | } | 55 | } |
44 | 56 | ... | ... |
... | @@ -5,15 +5,26 @@ import java.util.Objects; | ... | @@ -5,15 +5,26 @@ import java.util.Objects; |
5 | import static com.google.common.base.MoreObjects.toStringHelper; | 5 | import static com.google.common.base.MoreObjects.toStringHelper; |
6 | 6 | ||
7 | /** | 7 | /** |
8 | - * Notion of provider identity. | 8 | + * External identity of a {@link org.onlab.onos.net.provider.Provider} family. |
9 | + * It also carriers two designations of external characteristics, the URI | ||
10 | + * scheme and primary/ancillary indicator. | ||
11 | + * <p/> | ||
12 | + * The device URI scheme is used to determine applicability of a provider to | ||
13 | + * operations on a specific device. The ancillary indicator serves to designate | ||
14 | + * a provider as a primary or ancillary. | ||
15 | + * | ||
16 | + * A {@link org.onlab.onos.net.provider.ProviderRegistry} uses this designation | ||
17 | + * to permit only one primary provider per device URI scheme. Multiple | ||
18 | + * ancillary providers can register with the same device URI scheme however. | ||
9 | */ | 19 | */ |
10 | public class ProviderId { | 20 | public class ProviderId { |
11 | 21 | ||
12 | private final String scheme; | 22 | private final String scheme; |
13 | private final String id; | 23 | private final String id; |
24 | + private final boolean ancillary; | ||
14 | 25 | ||
15 | /** | 26 | /** |
16 | - * Creates a new provider identifier from the specified string. | 27 | + * Creates a new primary provider identifier from the specified string. |
17 | * The providers are expected to follow the reverse DNS convention, e.g. | 28 | * The providers are expected to follow the reverse DNS convention, e.g. |
18 | * {@code org.onlab.onos.provider.of.device} | 29 | * {@code org.onlab.onos.provider.of.device} |
19 | * | 30 | * |
... | @@ -21,8 +32,22 @@ public class ProviderId { | ... | @@ -21,8 +32,22 @@ public class ProviderId { |
21 | * @param id string identifier | 32 | * @param id string identifier |
22 | */ | 33 | */ |
23 | public ProviderId(String scheme, String id) { | 34 | public ProviderId(String scheme, String id) { |
35 | + this(scheme, id, false); | ||
36 | + } | ||
37 | + | ||
38 | + /** | ||
39 | + * Creates a new provider identifier from the specified string. | ||
40 | + * The providers are expected to follow the reverse DNS convention, e.g. | ||
41 | + * {@code org.onlab.onos.provider.of.device} | ||
42 | + * | ||
43 | + * @param scheme device URI scheme to which this provider is bound, e.g. "of", "snmp" | ||
44 | + * @param id string identifier | ||
45 | + * @param ancillary ancillary provider indicator | ||
46 | + */ | ||
47 | + public ProviderId(String scheme, String id, boolean ancillary) { | ||
24 | this.scheme = scheme; | 48 | this.scheme = scheme; |
25 | this.id = id; | 49 | this.id = id; |
50 | + this.ancillary = ancillary; | ||
26 | } | 51 | } |
27 | 52 | ||
28 | /** | 53 | /** |
... | @@ -43,6 +68,15 @@ public class ProviderId { | ... | @@ -43,6 +68,15 @@ public class ProviderId { |
43 | return id; | 68 | return id; |
44 | } | 69 | } |
45 | 70 | ||
71 | + /** | ||
72 | + * Indicates whether this identifier designates an ancillary providers. | ||
73 | + * | ||
74 | + * @return true if the provider is ancillary; false if primary | ||
75 | + */ | ||
76 | + public boolean isAncillary() { | ||
77 | + return ancillary; | ||
78 | + } | ||
79 | + | ||
46 | @Override | 80 | @Override |
47 | public int hashCode() { | 81 | public int hashCode() { |
48 | return Objects.hash(scheme, id); | 82 | return Objects.hash(scheme, id); |
... | @@ -56,14 +90,16 @@ public class ProviderId { | ... | @@ -56,14 +90,16 @@ public class ProviderId { |
56 | if (obj instanceof ProviderId) { | 90 | if (obj instanceof ProviderId) { |
57 | final ProviderId other = (ProviderId) obj; | 91 | final ProviderId other = (ProviderId) obj; |
58 | return Objects.equals(this.scheme, other.scheme) && | 92 | return Objects.equals(this.scheme, other.scheme) && |
59 | - Objects.equals(this.id, other.id); | 93 | + Objects.equals(this.id, other.id) && |
94 | + this.ancillary == other.ancillary; | ||
60 | } | 95 | } |
61 | return false; | 96 | return false; |
62 | } | 97 | } |
63 | 98 | ||
64 | @Override | 99 | @Override |
65 | public String toString() { | 100 | public String toString() { |
66 | - return toStringHelper(this).add("scheme", scheme).add("id", id).toString(); | 101 | + return toStringHelper(this).add("scheme", scheme).add("id", id) |
102 | + .add("ancillary", ancillary).toString(); | ||
67 | } | 103 | } |
68 | 104 | ||
69 | } | 105 | } | ... | ... |
... | @@ -2,6 +2,7 @@ package org.onlab.onos.net.topology; | ... | @@ -2,6 +2,7 @@ package org.onlab.onos.net.topology; |
2 | 2 | ||
3 | import com.google.common.collect.ImmutableSet; | 3 | import com.google.common.collect.ImmutableSet; |
4 | import com.google.common.collect.Maps; | 4 | import com.google.common.collect.Maps; |
5 | +import org.onlab.onos.net.AbstractAnnotated; | ||
5 | import org.onlab.onos.net.ConnectPoint; | 6 | import org.onlab.onos.net.ConnectPoint; |
6 | import org.onlab.onos.net.Device; | 7 | import org.onlab.onos.net.Device; |
7 | import org.onlab.onos.net.DeviceId; | 8 | import org.onlab.onos.net.DeviceId; |
... | @@ -12,7 +13,8 @@ import java.util.Map; | ... | @@ -12,7 +13,8 @@ import java.util.Map; |
12 | /** | 13 | /** |
13 | * Default implementation of an immutable topology graph data carrier. | 14 | * Default implementation of an immutable topology graph data carrier. |
14 | */ | 15 | */ |
15 | -public class DefaultGraphDescription implements GraphDescription { | 16 | +public class DefaultGraphDescription extends AbstractAnnotated |
17 | + implements GraphDescription { | ||
16 | 18 | ||
17 | private final long nanos; | 19 | private final long nanos; |
18 | private final ImmutableSet<TopologyVertex> vertexes; | 20 | private final ImmutableSet<TopologyVertex> vertexes; |
... | @@ -28,8 +30,13 @@ public class DefaultGraphDescription implements GraphDescription { | ... | @@ -28,8 +30,13 @@ public class DefaultGraphDescription implements GraphDescription { |
28 | * @param nanos time in nanos of when the topology description was created | 30 | * @param nanos time in nanos of when the topology description was created |
29 | * @param devices collection of infrastructure devices | 31 | * @param devices collection of infrastructure devices |
30 | * @param links collection of infrastructure links | 32 | * @param links collection of infrastructure links |
33 | + * @param annotations optional key/value annotations map | ||
31 | */ | 34 | */ |
32 | - public DefaultGraphDescription(long nanos, Iterable<Device> devices, Iterable<Link> links) { | 35 | + @SafeVarargs |
36 | + public DefaultGraphDescription(long nanos, Iterable<Device> devices, | ||
37 | + Iterable<Link> links, | ||
38 | + Map<String, String>... annotations) { | ||
39 | + super(annotations); | ||
33 | this.nanos = nanos; | 40 | this.nanos = nanos; |
34 | this.vertexes = buildVertexes(devices); | 41 | this.vertexes = buildVertexes(devices); |
35 | this.edges = buildEdges(links); | 42 | this.edges = buildEdges(links); | ... | ... |
1 | +package org.onlab.onos.cluster; | ||
2 | + | ||
3 | +import static org.junit.Assert.assertEquals; | ||
4 | + | ||
5 | +import org.junit.Test; | ||
6 | + | ||
7 | +import com.google.common.testing.EqualsTester; | ||
8 | + | ||
9 | +public class MastershipTermTest { | ||
10 | + | ||
11 | + private static final NodeId N1 = new NodeId("foo"); | ||
12 | + private static final NodeId N2 = new NodeId("bar"); | ||
13 | + | ||
14 | + private static final MastershipTerm TERM1 = MastershipTerm.of(N1, 0); | ||
15 | + private static final MastershipTerm TERM2 = MastershipTerm.of(N2, 1); | ||
16 | + private static final MastershipTerm TERM3 = MastershipTerm.of(N2, 1); | ||
17 | + private static final MastershipTerm TERM4 = MastershipTerm.of(N1, 1); | ||
18 | + | ||
19 | + @Test | ||
20 | + public void basics() { | ||
21 | + assertEquals("incorrect term number", 0, TERM1.termNumber()); | ||
22 | + assertEquals("incorrect master", new NodeId("foo"), TERM1.master()); | ||
23 | + } | ||
24 | + | ||
25 | + @Test | ||
26 | + public void testEquality() { | ||
27 | + new EqualsTester().addEqualityGroup(MastershipTerm.of(N1, 0), TERM1) | ||
28 | + .addEqualityGroup(TERM2, TERM3) | ||
29 | + .addEqualityGroup(TERM4); | ||
30 | + } | ||
31 | + | ||
32 | +} |
... | @@ -35,7 +35,7 @@ public class AbstractProviderRegistryTest { | ... | @@ -35,7 +35,7 @@ public class AbstractProviderRegistryTest { |
35 | assertThat("provider not found", registry.getProviders().contains(fooId)); | 35 | assertThat("provider not found", registry.getProviders().contains(fooId)); |
36 | assertEquals("incorrect provider", psFoo.provider(), pFoo); | 36 | assertEquals("incorrect provider", psFoo.provider(), pFoo); |
37 | 37 | ||
38 | - ProviderId barId = new ProviderId("of", "bar"); | 38 | + ProviderId barId = new ProviderId("snmp", "bar"); |
39 | TestProvider pBar = new TestProvider(barId); | 39 | TestProvider pBar = new TestProvider(barId); |
40 | TestProviderService psBar = registry.register(pBar); | 40 | TestProviderService psBar = registry.register(pBar); |
41 | assertEquals("incorrect provider count", 2, registry.getProviders().size()); | 41 | assertEquals("incorrect provider count", 2, registry.getProviders().size()); |
... | @@ -49,6 +49,16 @@ public class AbstractProviderRegistryTest { | ... | @@ -49,6 +49,16 @@ public class AbstractProviderRegistryTest { |
49 | assertThat("provider not found", registry.getProviders().contains(barId)); | 49 | assertThat("provider not found", registry.getProviders().contains(barId)); |
50 | } | 50 | } |
51 | 51 | ||
52 | + @Test | ||
53 | + public void ancillaryProviders() { | ||
54 | + TestProviderRegistry registry = new TestProviderRegistry(); | ||
55 | + TestProvider pFoo = new TestProvider(new ProviderId("of", "foo")); | ||
56 | + TestProvider pBar = new TestProvider(new ProviderId("of", "bar", true)); | ||
57 | + registry.register(pFoo); | ||
58 | + registry.register(pBar); | ||
59 | + assertEquals("incorrect provider count", 2, registry.getProviders().size()); | ||
60 | + } | ||
61 | + | ||
52 | @Test(expected = IllegalStateException.class) | 62 | @Test(expected = IllegalStateException.class) |
53 | public void duplicateRegistration() { | 63 | public void duplicateRegistration() { |
54 | TestProviderRegistry registry = new TestProviderRegistry(); | 64 | TestProviderRegistry registry = new TestProviderRegistry(); |
... | @@ -57,6 +67,15 @@ public class AbstractProviderRegistryTest { | ... | @@ -57,6 +67,15 @@ public class AbstractProviderRegistryTest { |
57 | registry.register(pFoo); | 67 | registry.register(pFoo); |
58 | } | 68 | } |
59 | 69 | ||
70 | + @Test(expected = IllegalStateException.class) | ||
71 | + public void duplicateSchemeRegistration() { | ||
72 | + TestProviderRegistry registry = new TestProviderRegistry(); | ||
73 | + TestProvider pFoo = new TestProvider(new ProviderId("of", "foo")); | ||
74 | + TestProvider pBar = new TestProvider(new ProviderId("of", "bar")); | ||
75 | + registry.register(pFoo); | ||
76 | + registry.register(pBar); | ||
77 | + } | ||
78 | + | ||
60 | @Test | 79 | @Test |
61 | public void voidUnregistration() { | 80 | public void voidUnregistration() { |
62 | TestProviderRegistry registry = new TestProviderRegistry(); | 81 | TestProviderRegistry registry = new TestProviderRegistry(); | ... | ... |
... | @@ -11,6 +11,8 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -11,6 +11,8 @@ import org.apache.felix.scr.annotations.Deactivate; |
11 | import org.apache.felix.scr.annotations.Reference; | 11 | import org.apache.felix.scr.annotations.Reference; |
12 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 12 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
13 | import org.apache.felix.scr.annotations.Service; | 13 | import org.apache.felix.scr.annotations.Service; |
14 | +import org.onlab.onos.cluster.ClusterEvent; | ||
15 | +import org.onlab.onos.cluster.ClusterEventListener; | ||
14 | import org.onlab.onos.cluster.ClusterService; | 16 | import org.onlab.onos.cluster.ClusterService; |
15 | import org.onlab.onos.cluster.MastershipAdminService; | 17 | import org.onlab.onos.cluster.MastershipAdminService; |
16 | import org.onlab.onos.cluster.MastershipEvent; | 18 | import org.onlab.onos.cluster.MastershipEvent; |
... | @@ -52,9 +54,12 @@ implements MastershipService, MastershipAdminService { | ... | @@ -52,9 +54,12 @@ implements MastershipService, MastershipAdminService { |
52 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 54 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
53 | protected ClusterService clusterService; | 55 | protected ClusterService clusterService; |
54 | 56 | ||
57 | + private ClusterEventListener clusterListener = new InternalClusterEventListener(); | ||
58 | + | ||
55 | @Activate | 59 | @Activate |
56 | public void activate() { | 60 | public void activate() { |
57 | eventDispatcher.addSink(MastershipEvent.class, listenerRegistry); | 61 | eventDispatcher.addSink(MastershipEvent.class, listenerRegistry); |
62 | + clusterService.addListener(clusterListener); | ||
58 | store.setDelegate(delegate); | 63 | store.setDelegate(delegate); |
59 | log.info("Started"); | 64 | log.info("Started"); |
60 | } | 65 | } |
... | @@ -62,6 +67,7 @@ implements MastershipService, MastershipAdminService { | ... | @@ -62,6 +67,7 @@ implements MastershipService, MastershipAdminService { |
62 | @Deactivate | 67 | @Deactivate |
63 | public void deactivate() { | 68 | public void deactivate() { |
64 | eventDispatcher.removeSink(MastershipEvent.class); | 69 | eventDispatcher.removeSink(MastershipEvent.class); |
70 | + clusterService.removeListener(clusterListener); | ||
65 | store.unsetDelegate(delegate); | 71 | store.unsetDelegate(delegate); |
66 | log.info("Stopped"); | 72 | log.info("Stopped"); |
67 | } | 73 | } |
... | @@ -71,14 +77,18 @@ implements MastershipService, MastershipAdminService { | ... | @@ -71,14 +77,18 @@ implements MastershipService, MastershipAdminService { |
71 | checkNotNull(nodeId, NODE_ID_NULL); | 77 | checkNotNull(nodeId, NODE_ID_NULL); |
72 | checkNotNull(deviceId, DEVICE_ID_NULL); | 78 | checkNotNull(deviceId, DEVICE_ID_NULL); |
73 | checkNotNull(role, ROLE_NULL); | 79 | checkNotNull(role, ROLE_NULL); |
74 | - //TODO figure out appropriate action for non-MASTER roles, if we even set those | 80 | + |
81 | + MastershipEvent event = null; | ||
75 | if (role.equals(MastershipRole.MASTER)) { | 82 | if (role.equals(MastershipRole.MASTER)) { |
76 | - MastershipEvent event = store.setMaster(nodeId, deviceId); | 83 | + event = store.setMaster(nodeId, deviceId); |
84 | + } else { | ||
85 | + event = store.unsetMaster(nodeId, deviceId); | ||
86 | + } | ||
87 | + | ||
77 | if (event != null) { | 88 | if (event != null) { |
78 | post(event); | 89 | post(event); |
79 | } | 90 | } |
80 | } | 91 | } |
81 | - } | ||
82 | 92 | ||
83 | @Override | 93 | @Override |
84 | public MastershipRole getLocalRole(DeviceId deviceId) { | 94 | public MastershipRole getLocalRole(DeviceId deviceId) { |
... | @@ -88,8 +98,16 @@ implements MastershipService, MastershipAdminService { | ... | @@ -88,8 +98,16 @@ implements MastershipService, MastershipAdminService { |
88 | 98 | ||
89 | @Override | 99 | @Override |
90 | public void relinquishMastership(DeviceId deviceId) { | 100 | public void relinquishMastership(DeviceId deviceId) { |
91 | - checkNotNull(deviceId, DEVICE_ID_NULL); | 101 | + MastershipRole role = getLocalRole(deviceId); |
92 | - // FIXME: add method to store to give up mastership and trigger new master selection process | 102 | + if (!role.equals(MastershipRole.MASTER)) { |
103 | + return; | ||
104 | + } | ||
105 | + | ||
106 | + MastershipEvent event = store.unsetMaster( | ||
107 | + clusterService.getLocalNode().id(), deviceId); | ||
108 | + if (event != null) { | ||
109 | + post(event); | ||
110 | + } | ||
93 | } | 111 | } |
94 | 112 | ||
95 | @Override | 113 | @Override |
... | @@ -146,6 +164,26 @@ implements MastershipService, MastershipAdminService { | ... | @@ -146,6 +164,26 @@ implements MastershipService, MastershipAdminService { |
146 | 164 | ||
147 | } | 165 | } |
148 | 166 | ||
167 | + //callback for reacting to cluster events | ||
168 | + private class InternalClusterEventListener implements ClusterEventListener { | ||
169 | + | ||
170 | + @Override | ||
171 | + public void event(ClusterEvent event) { | ||
172 | + switch (event.type()) { | ||
173 | + //FIXME: worry about addition when the time comes | ||
174 | + case INSTANCE_ADDED: | ||
175 | + case INSTANCE_ACTIVATED: | ||
176 | + break; | ||
177 | + case INSTANCE_REMOVED: | ||
178 | + case INSTANCE_DEACTIVATED: | ||
179 | + break; | ||
180 | + default: | ||
181 | + log.warn("unknown cluster event {}", event); | ||
182 | + } | ||
183 | + } | ||
184 | + | ||
185 | + } | ||
186 | + | ||
149 | public class InternalDelegate implements MastershipStoreDelegate { | 187 | public class InternalDelegate implements MastershipStoreDelegate { |
150 | 188 | ||
151 | @Override | 189 | @Override | ... | ... |
... | @@ -16,6 +16,7 @@ import org.onlab.onos.cluster.ClusterService; | ... | @@ -16,6 +16,7 @@ import org.onlab.onos.cluster.ClusterService; |
16 | import org.onlab.onos.cluster.MastershipEvent; | 16 | import org.onlab.onos.cluster.MastershipEvent; |
17 | import org.onlab.onos.cluster.MastershipListener; | 17 | import org.onlab.onos.cluster.MastershipListener; |
18 | import org.onlab.onos.cluster.MastershipService; | 18 | import org.onlab.onos.cluster.MastershipService; |
19 | +import org.onlab.onos.cluster.MastershipTermService; | ||
19 | import org.onlab.onos.cluster.MastershipTerm; | 20 | import org.onlab.onos.cluster.MastershipTerm; |
20 | import org.onlab.onos.event.AbstractListenerRegistry; | 21 | import org.onlab.onos.event.AbstractListenerRegistry; |
21 | import org.onlab.onos.event.EventDeliveryService; | 22 | import org.onlab.onos.event.EventDeliveryService; |
... | @@ -76,6 +77,8 @@ public class DeviceManager | ... | @@ -76,6 +77,8 @@ public class DeviceManager |
76 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 77 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
77 | protected MastershipService mastershipService; | 78 | protected MastershipService mastershipService; |
78 | 79 | ||
80 | + protected MastershipTermService termService; | ||
81 | + | ||
79 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 82 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
80 | protected ClockService clockService; | 83 | protected ClockService clockService; |
81 | 84 | ||
... | @@ -84,6 +87,7 @@ public class DeviceManager | ... | @@ -84,6 +87,7 @@ public class DeviceManager |
84 | store.setDelegate(delegate); | 87 | store.setDelegate(delegate); |
85 | eventDispatcher.addSink(DeviceEvent.class, listenerRegistry); | 88 | eventDispatcher.addSink(DeviceEvent.class, listenerRegistry); |
86 | mastershipService.addListener(mastershipListener); | 89 | mastershipService.addListener(mastershipListener); |
90 | + termService = mastershipService.requestTermService(); | ||
87 | log.info("Started"); | 91 | log.info("Started"); |
88 | } | 92 | } |
89 | 93 | ||
... | @@ -198,7 +202,7 @@ public class DeviceManager | ... | @@ -198,7 +202,7 @@ public class DeviceManager |
198 | log.info("Device {} connected", deviceId); | 202 | log.info("Device {} connected", deviceId); |
199 | mastershipService.requestRoleFor(deviceId); | 203 | mastershipService.requestRoleFor(deviceId); |
200 | provider().roleChanged(event.subject(), | 204 | provider().roleChanged(event.subject(), |
201 | - mastershipService.getLocalRole(deviceId)); | 205 | + mastershipService.requestRoleFor(deviceId)); |
202 | post(event); | 206 | post(event); |
203 | } | 207 | } |
204 | } | 208 | } |
... | @@ -208,8 +212,11 @@ public class DeviceManager | ... | @@ -208,8 +212,11 @@ public class DeviceManager |
208 | checkNotNull(deviceId, DEVICE_ID_NULL); | 212 | checkNotNull(deviceId, DEVICE_ID_NULL); |
209 | checkValidity(); | 213 | checkValidity(); |
210 | DeviceEvent event = store.markOffline(deviceId); | 214 | DeviceEvent event = store.markOffline(deviceId); |
215 | + | ||
216 | + //we're no longer capable of mastership. | ||
211 | if (event != null) { | 217 | if (event != null) { |
212 | log.info("Device {} disconnected", deviceId); | 218 | log.info("Device {} disconnected", deviceId); |
219 | + mastershipService.relinquishMastership(deviceId); | ||
213 | post(event); | 220 | post(event); |
214 | } | 221 | } |
215 | } | 222 | } |
... | @@ -221,8 +228,9 @@ public class DeviceManager | ... | @@ -221,8 +228,9 @@ public class DeviceManager |
221 | checkNotNull(portDescriptions, | 228 | checkNotNull(portDescriptions, |
222 | "Port descriptions list cannot be null"); | 229 | "Port descriptions list cannot be null"); |
223 | checkValidity(); | 230 | checkValidity(); |
224 | - List<DeviceEvent> events = store.updatePorts(deviceId, | 231 | + this.provider().id(); |
225 | - portDescriptions); | 232 | + List<DeviceEvent> events = store.updatePorts(this.provider().id(), |
233 | + deviceId, portDescriptions); | ||
226 | for (DeviceEvent event : events) { | 234 | for (DeviceEvent event : events) { |
227 | post(event); | 235 | post(event); |
228 | } | 236 | } |
... | @@ -234,8 +242,8 @@ public class DeviceManager | ... | @@ -234,8 +242,8 @@ public class DeviceManager |
234 | checkNotNull(deviceId, DEVICE_ID_NULL); | 242 | checkNotNull(deviceId, DEVICE_ID_NULL); |
235 | checkNotNull(portDescription, PORT_DESCRIPTION_NULL); | 243 | checkNotNull(portDescription, PORT_DESCRIPTION_NULL); |
236 | checkValidity(); | 244 | checkValidity(); |
237 | - DeviceEvent event = store.updatePortStatus(deviceId, | 245 | + DeviceEvent event = store.updatePortStatus(this.provider().id(), |
238 | - portDescription); | 246 | + deviceId, portDescription); |
239 | if (event != null) { | 247 | if (event != null) { |
240 | log.info("Device {} port {} status changed", deviceId, event | 248 | log.info("Device {} port {} status changed", deviceId, event |
241 | .port().number()); | 249 | .port().number()); | ... | ... |
... | @@ -161,7 +161,11 @@ implements FlowRuleService, FlowRuleProviderRegistry { | ... | @@ -161,7 +161,11 @@ implements FlowRuleService, FlowRuleProviderRegistry { |
161 | switch (stored.state()) { | 161 | switch (stored.state()) { |
162 | case ADDED: | 162 | case ADDED: |
163 | case PENDING_ADD: | 163 | case PENDING_ADD: |
164 | + if (flowRule.expired()) { | ||
165 | + event = store.removeFlowRule(flowRule); | ||
166 | + } else { | ||
164 | frp.applyFlowRule(stored); | 167 | frp.applyFlowRule(stored); |
168 | + } | ||
165 | break; | 169 | break; |
166 | case PENDING_REMOVE: | 170 | case PENDING_REMOVE: |
167 | case REMOVED: | 171 | case REMOVED: | ... | ... |
... | @@ -231,6 +231,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -231,6 +231,7 @@ public class ProxyArpManager implements ProxyArpService { |
231 | arp.setOpCode(ARP.OP_REPLY); | 231 | arp.setOpCode(ARP.OP_REPLY); |
232 | arp.setProtocolType(ARP.PROTO_TYPE_IP); | 232 | arp.setProtocolType(ARP.PROTO_TYPE_IP); |
233 | arp.setHardwareType(ARP.HW_TYPE_ETHERNET); | 233 | arp.setHardwareType(ARP.HW_TYPE_ETHERNET); |
234 | + | ||
234 | arp.setProtocolAddressLength((byte) IpPrefix.INET_LEN); | 235 | arp.setProtocolAddressLength((byte) IpPrefix.INET_LEN); |
235 | arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH); | 236 | arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH); |
236 | arp.setSenderHardwareAddress(h.mac().getAddress()); | 237 | arp.setSenderHardwareAddress(h.mac().getAddress()); |
... | @@ -238,7 +239,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -238,7 +239,7 @@ public class ProxyArpManager implements ProxyArpService { |
238 | 239 | ||
239 | arp.setTargetProtocolAddress(((ARP) request.getPayload()) | 240 | arp.setTargetProtocolAddress(((ARP) request.getPayload()) |
240 | .getSenderProtocolAddress()); | 241 | .getSenderProtocolAddress()); |
241 | - arp.setSenderProtocolAddress(h.ipAddresses().iterator().next().toInt()); | 242 | + arp.setSenderProtocolAddress(h.ipAddresses().iterator().next().toRealInt()); |
242 | eth.setPayload(arp); | 243 | eth.setPayload(arp); |
243 | return eth; | 244 | return eth; |
244 | } | 245 | } |
... | @@ -291,7 +292,6 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -291,7 +292,6 @@ public class ProxyArpManager implements ProxyArpService { |
291 | case DEVICE_MASTERSHIP_CHANGED: | 292 | case DEVICE_MASTERSHIP_CHANGED: |
292 | case DEVICE_SUSPENDED: | 293 | case DEVICE_SUSPENDED: |
293 | case DEVICE_UPDATED: | 294 | case DEVICE_UPDATED: |
294 | - case PORT_UPDATED: | ||
295 | // nothing to do in these cases; handled when links get reported | 295 | // nothing to do in these cases; handled when links get reported |
296 | break; | 296 | break; |
297 | case DEVICE_REMOVED: | 297 | case DEVICE_REMOVED: |
... | @@ -301,10 +301,13 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -301,10 +301,13 @@ public class ProxyArpManager implements ProxyArpService { |
301 | } | 301 | } |
302 | break; | 302 | break; |
303 | case PORT_ADDED: | 303 | case PORT_ADDED: |
304 | + case PORT_UPDATED: | ||
304 | synchronized (externalPorts) { | 305 | synchronized (externalPorts) { |
306 | + if (event.port().isEnabled()) { | ||
305 | externalPorts.put(device, event.port().number()); | 307 | externalPorts.put(device, event.port().number()); |
306 | internalPorts.remove(device, event.port().number()); | 308 | internalPorts.remove(device, event.port().number()); |
307 | } | 309 | } |
310 | + } | ||
308 | break; | 311 | break; |
309 | case PORT_REMOVED: | 312 | case PORT_REMOVED: |
310 | synchronized (externalPorts) { | 313 | synchronized (externalPorts) { | ... | ... |
... | @@ -65,8 +65,8 @@ public class DefaultTopologyProvider extends AbstractProvider | ... | @@ -65,8 +65,8 @@ public class DefaultTopologyProvider extends AbstractProvider |
65 | private volatile boolean isStarted = false; | 65 | private volatile boolean isStarted = false; |
66 | 66 | ||
67 | private TopologyProviderService providerService; | 67 | private TopologyProviderService providerService; |
68 | - private DeviceListener deviceListener = new InnerDeviceListener(); | 68 | + private DeviceListener deviceListener = new InternalDeviceListener(); |
69 | - private LinkListener linkListener = new InnerLinkListener(); | 69 | + private LinkListener linkListener = new InternalLinkListener(); |
70 | 70 | ||
71 | private EventAccumulator accumulator; | 71 | private EventAccumulator accumulator; |
72 | private ExecutorService executor; | 72 | private ExecutorService executor; |
... | @@ -132,7 +132,7 @@ public class DefaultTopologyProvider extends AbstractProvider | ... | @@ -132,7 +132,7 @@ public class DefaultTopologyProvider extends AbstractProvider |
132 | } | 132 | } |
133 | 133 | ||
134 | // Callback for device events | 134 | // Callback for device events |
135 | - private class InnerDeviceListener implements DeviceListener { | 135 | + private class InternalDeviceListener implements DeviceListener { |
136 | @Override | 136 | @Override |
137 | public void event(DeviceEvent event) { | 137 | public void event(DeviceEvent event) { |
138 | DeviceEvent.Type type = event.type(); | 138 | DeviceEvent.Type type = event.type(); |
... | @@ -144,7 +144,7 @@ public class DefaultTopologyProvider extends AbstractProvider | ... | @@ -144,7 +144,7 @@ public class DefaultTopologyProvider extends AbstractProvider |
144 | } | 144 | } |
145 | 145 | ||
146 | // Callback for link events | 146 | // Callback for link events |
147 | - private class InnerLinkListener implements LinkListener { | 147 | + private class InternalLinkListener implements LinkListener { |
148 | @Override | 148 | @Override |
149 | public void event(LinkEvent event) { | 149 | public void event(LinkEvent event) { |
150 | accumulator.add(event); | 150 | accumulator.add(event); | ... | ... |
... | @@ -15,10 +15,11 @@ import org.onlab.onos.cluster.MastershipTermService; | ... | @@ -15,10 +15,11 @@ import org.onlab.onos.cluster.MastershipTermService; |
15 | import org.onlab.onos.cluster.NodeId; | 15 | import org.onlab.onos.cluster.NodeId; |
16 | import org.onlab.onos.event.impl.TestEventDispatcher; | 16 | import org.onlab.onos.event.impl.TestEventDispatcher; |
17 | import org.onlab.onos.net.DeviceId; | 17 | import org.onlab.onos.net.DeviceId; |
18 | -import org.onlab.onos.net.trivial.impl.SimpleMastershipStore; | 18 | +import org.onlab.onos.store.trivial.impl.SimpleMastershipStore; |
19 | import org.onlab.packet.IpPrefix; | 19 | import org.onlab.packet.IpPrefix; |
20 | 20 | ||
21 | import static org.junit.Assert.assertEquals; | 21 | import static org.junit.Assert.assertEquals; |
22 | +import static org.junit.Assert.assertNull; | ||
22 | import static org.onlab.onos.net.MastershipRole.*; | 23 | import static org.onlab.onos.net.MastershipRole.*; |
23 | 24 | ||
24 | /** | 25 | /** |
... | @@ -65,7 +66,24 @@ public class MastershipManagerTest { | ... | @@ -65,7 +66,24 @@ public class MastershipManagerTest { |
65 | 66 | ||
66 | @Test | 67 | @Test |
67 | public void relinquishMastership() { | 68 | public void relinquishMastership() { |
68 | - //TODO | 69 | + //no backups - should turn to standby and no master for device |
70 | + mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | ||
71 | + assertEquals("wrong role:", MASTER, mgr.getLocalRole(DEV_MASTER)); | ||
72 | + mgr.relinquishMastership(DEV_MASTER); | ||
73 | + assertNull("wrong master:", mgr.getMasterFor(DEV_OTHER)); | ||
74 | + assertEquals("wrong role:", STANDBY, mgr.getLocalRole(DEV_MASTER)); | ||
75 | + | ||
76 | + //not master, nothing should happen | ||
77 | + mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY); | ||
78 | + mgr.relinquishMastership(DEV_OTHER); | ||
79 | + assertNull("wrong role:", mgr.getMasterFor(DEV_OTHER)); | ||
80 | + | ||
81 | + //provide NID_OTHER as backup and relinquish | ||
82 | + mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | ||
83 | + assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_MASTER)); | ||
84 | + mgr.setRole(NID_OTHER, DEV_MASTER, STANDBY); | ||
85 | + mgr.relinquishMastership(DEV_MASTER); | ||
86 | + assertEquals("wrong master:", NID_OTHER, mgr.getMasterFor(DEV_MASTER)); | ||
69 | } | 87 | } |
70 | 88 | ||
71 | @Test | 89 | @Test |
... | @@ -95,7 +113,6 @@ public class MastershipManagerTest { | ... | @@ -95,7 +113,6 @@ public class MastershipManagerTest { |
95 | mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); | 113 | mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER); |
96 | mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY); | 114 | mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY); |
97 | assertEquals("should be one device:", 1, mgr.getDevicesOf(NID_LOCAL).size()); | 115 | assertEquals("should be one device:", 1, mgr.getDevicesOf(NID_LOCAL).size()); |
98 | - | ||
99 | //hand both devices to NID_LOCAL | 116 | //hand both devices to NID_LOCAL |
100 | mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER); | 117 | mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER); |
101 | assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size()); | 118 | assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size()); | ... | ... |
... | @@ -27,7 +27,7 @@ import org.onlab.onos.net.device.DeviceService; | ... | @@ -27,7 +27,7 @@ import org.onlab.onos.net.device.DeviceService; |
27 | import org.onlab.onos.net.device.PortDescription; | 27 | import org.onlab.onos.net.device.PortDescription; |
28 | import org.onlab.onos.net.provider.AbstractProvider; | 28 | import org.onlab.onos.net.provider.AbstractProvider; |
29 | import org.onlab.onos.net.provider.ProviderId; | 29 | import org.onlab.onos.net.provider.ProviderId; |
30 | -import org.onlab.onos.net.trivial.impl.SimpleDeviceStore; | 30 | +import org.onlab.onos.store.trivial.impl.SimpleDeviceStore; |
31 | 31 | ||
32 | import java.util.ArrayList; | 32 | import java.util.ArrayList; |
33 | import java.util.Iterator; | 33 | import java.util.Iterator; | ... | ... |
... | @@ -40,7 +40,7 @@ import org.onlab.onos.net.flow.criteria.Criterion; | ... | @@ -40,7 +40,7 @@ import org.onlab.onos.net.flow.criteria.Criterion; |
40 | import org.onlab.onos.net.flow.instructions.Instruction; | 40 | import org.onlab.onos.net.flow.instructions.Instruction; |
41 | import org.onlab.onos.net.provider.AbstractProvider; | 41 | import org.onlab.onos.net.provider.AbstractProvider; |
42 | import org.onlab.onos.net.provider.ProviderId; | 42 | import org.onlab.onos.net.provider.ProviderId; |
43 | -import org.onlab.onos.net.trivial.impl.SimpleFlowRuleStore; | 43 | +import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore; |
44 | 44 | ||
45 | import com.google.common.collect.Lists; | 45 | import com.google.common.collect.Lists; |
46 | import com.google.common.collect.Sets; | 46 | import com.google.common.collect.Sets; | ... | ... |
... | @@ -34,7 +34,7 @@ import org.onlab.onos.net.host.HostProviderService; | ... | @@ -34,7 +34,7 @@ import org.onlab.onos.net.host.HostProviderService; |
34 | import org.onlab.onos.net.host.PortAddresses; | 34 | import org.onlab.onos.net.host.PortAddresses; |
35 | import org.onlab.onos.net.provider.AbstractProvider; | 35 | import org.onlab.onos.net.provider.AbstractProvider; |
36 | import org.onlab.onos.net.provider.ProviderId; | 36 | import org.onlab.onos.net.provider.ProviderId; |
37 | -import org.onlab.onos.net.trivial.impl.SimpleHostStore; | 37 | +import org.onlab.onos.store.trivial.impl.SimpleHostStore; |
38 | import org.onlab.packet.IpPrefix; | 38 | import org.onlab.packet.IpPrefix; |
39 | import org.onlab.packet.MacAddress; | 39 | import org.onlab.packet.MacAddress; |
40 | import org.onlab.packet.VlanId; | 40 | import org.onlab.packet.VlanId; | ... | ... |
... | @@ -23,7 +23,7 @@ import org.onlab.onos.net.provider.AbstractProvider; | ... | @@ -23,7 +23,7 @@ import org.onlab.onos.net.provider.AbstractProvider; |
23 | import org.onlab.onos.net.provider.ProviderId; | 23 | import org.onlab.onos.net.provider.ProviderId; |
24 | import org.onlab.onos.event.impl.TestEventDispatcher; | 24 | import org.onlab.onos.event.impl.TestEventDispatcher; |
25 | import org.onlab.onos.net.device.impl.DeviceManager; | 25 | import org.onlab.onos.net.device.impl.DeviceManager; |
26 | -import org.onlab.onos.net.trivial.impl.SimpleLinkStore; | 26 | +import org.onlab.onos.store.trivial.impl.SimpleLinkStore; |
27 | 27 | ||
28 | import java.util.ArrayList; | 28 | import java.util.ArrayList; |
29 | import java.util.Iterator; | 29 | import java.util.Iterator; | ... | ... |
... | @@ -24,7 +24,7 @@ import org.onlab.onos.net.topology.TopologyProvider; | ... | @@ -24,7 +24,7 @@ import org.onlab.onos.net.topology.TopologyProvider; |
24 | import org.onlab.onos.net.topology.TopologyProviderRegistry; | 24 | import org.onlab.onos.net.topology.TopologyProviderRegistry; |
25 | import org.onlab.onos.net.topology.TopologyProviderService; | 25 | import org.onlab.onos.net.topology.TopologyProviderService; |
26 | import org.onlab.onos.net.topology.TopologyService; | 26 | import org.onlab.onos.net.topology.TopologyService; |
27 | -import org.onlab.onos.net.trivial.impl.SimpleTopologyStore; | 27 | +import org.onlab.onos.store.trivial.impl.SimpleTopologyStore; |
28 | 28 | ||
29 | import java.util.ArrayList; | 29 | import java.util.ArrayList; |
30 | import java.util.List; | 30 | import java.util.List; | ... | ... |
core/store/dist/src/main/java/org/onlab/onos/store/cluster/messaging/AntiEntropyAdvertisement.java
0 → 100644
1 | +package org.onlab.onos.store.cluster.messaging; | ||
2 | + | ||
3 | +import static org.onlab.onos.store.cluster.messaging.MessageSubject.AE_ADVERTISEMENT; | ||
4 | +import java.util.Map; | ||
5 | + | ||
6 | +import org.onlab.onos.cluster.NodeId; | ||
7 | +import org.onlab.onos.store.Timestamp; | ||
8 | + | ||
9 | +import com.google.common.collect.ImmutableMap; | ||
10 | + | ||
11 | +/** | ||
12 | + * Anti-Entropy advertisement message. | ||
13 | + * <p> | ||
14 | + * Message to advertise the information this node holds. | ||
15 | + * | ||
16 | + * @param <ID> ID type | ||
17 | + */ | ||
18 | +public class AntiEntropyAdvertisement<ID> extends ClusterMessage { | ||
19 | + | ||
20 | + private final NodeId sender; | ||
21 | + private final ImmutableMap<ID, Timestamp> advertisement; | ||
22 | + | ||
23 | + /** | ||
24 | + * Creates anti-entropy advertisement message. | ||
25 | + * | ||
26 | + * @param sender sender of this message | ||
27 | + * @param advertisement timestamp information of the data sender holds | ||
28 | + */ | ||
29 | + public AntiEntropyAdvertisement(NodeId sender, Map<ID, Timestamp> advertisement) { | ||
30 | + super(AE_ADVERTISEMENT); | ||
31 | + this.sender = sender; | ||
32 | + this.advertisement = ImmutableMap.copyOf(advertisement); | ||
33 | + } | ||
34 | + | ||
35 | + public NodeId sender() { | ||
36 | + return sender; | ||
37 | + } | ||
38 | + | ||
39 | + public ImmutableMap<ID, Timestamp> advertisement() { | ||
40 | + return advertisement; | ||
41 | + } | ||
42 | + | ||
43 | + // Default constructor for serializer | ||
44 | + protected AntiEntropyAdvertisement() { | ||
45 | + super(AE_ADVERTISEMENT); | ||
46 | + this.sender = null; | ||
47 | + this.advertisement = null; | ||
48 | + } | ||
49 | +} |
core/store/dist/src/main/java/org/onlab/onos/store/cluster/messaging/AntiEntropyReply.java
0 → 100644
1 | +package org.onlab.onos.store.cluster.messaging; | ||
2 | + | ||
3 | +import static org.onlab.onos.store.cluster.messaging.MessageSubject.AE_REPLY; | ||
4 | + | ||
5 | +import java.util.Map; | ||
6 | +import java.util.Set; | ||
7 | + | ||
8 | +import org.onlab.onos.cluster.NodeId; | ||
9 | +import org.onlab.onos.store.device.impl.VersionedValue; | ||
10 | + | ||
11 | +import com.google.common.collect.ImmutableMap; | ||
12 | +import com.google.common.collect.ImmutableSet; | ||
13 | + | ||
14 | +/** | ||
15 | + * Anti-Entropy reply message. | ||
16 | + * <p> | ||
17 | + * Message to send in reply to advertisement or another reply. | ||
18 | + * Suggest to the sender about the more up-to-date data this node has, | ||
19 | + * and request for more recent data that the receiver has. | ||
20 | + */ | ||
21 | +public class AntiEntropyReply<ID, V extends VersionedValue<?>> extends ClusterMessage { | ||
22 | + | ||
23 | + private final NodeId sender; | ||
24 | + private final ImmutableMap<ID, V> suggestion; | ||
25 | + private final ImmutableSet<ID> request; | ||
26 | + | ||
27 | + /** | ||
28 | + * Creates a reply to anti-entropy message. | ||
29 | + * | ||
30 | + * @param sender sender of this message | ||
31 | + * @param suggestion collection of more recent values, sender had | ||
32 | + * @param request Collection of identifiers | ||
33 | + */ | ||
34 | + public AntiEntropyReply(NodeId sender, | ||
35 | + Map<ID, V> suggestion, | ||
36 | + Set<ID> request) { | ||
37 | + super(AE_REPLY); | ||
38 | + this.sender = sender; | ||
39 | + this.suggestion = ImmutableMap.copyOf(suggestion); | ||
40 | + this.request = ImmutableSet.copyOf(request); | ||
41 | + } | ||
42 | + | ||
43 | + public NodeId sender() { | ||
44 | + return sender; | ||
45 | + } | ||
46 | + | ||
47 | + /** | ||
48 | + * Returns collection of values, which the recipient of this reply is likely | ||
49 | + * to be missing or has outdated version. | ||
50 | + * | ||
51 | + * @return | ||
52 | + */ | ||
53 | + public ImmutableMap<ID, V> suggestion() { | ||
54 | + return suggestion; | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * Returns collection of identifier to request. | ||
59 | + * | ||
60 | + * @return collection of identifier to request | ||
61 | + */ | ||
62 | + public ImmutableSet<ID> request() { | ||
63 | + return request; | ||
64 | + } | ||
65 | + | ||
66 | + /** | ||
67 | + * Checks if reply contains any suggestion or request. | ||
68 | + * | ||
69 | + * @return true if nothing is suggested and requested | ||
70 | + */ | ||
71 | + public boolean isEmpty() { | ||
72 | + return suggestion.isEmpty() && request.isEmpty(); | ||
73 | + } | ||
74 | + | ||
75 | + // Default constructor for serializer | ||
76 | + protected AntiEntropyReply() { | ||
77 | + super(AE_REPLY); | ||
78 | + this.sender = null; | ||
79 | + this.suggestion = null; | ||
80 | + this.request = null; | ||
81 | + } | ||
82 | +} |
... | @@ -15,6 +15,12 @@ public enum MessageSubject { | ... | @@ -15,6 +15,12 @@ public enum MessageSubject { |
15 | LEAVING_MEMBER, | 15 | LEAVING_MEMBER, |
16 | 16 | ||
17 | /** Signifies a heart-beat message. */ | 17 | /** Signifies a heart-beat message. */ |
18 | - ECHO | 18 | + ECHO, |
19 | + | ||
20 | + /** Anti-Entropy advertisement message. */ | ||
21 | + AE_ADVERTISEMENT, | ||
22 | + | ||
23 | + /** Anti-Entropy reply message. */ | ||
24 | + AE_REPLY, | ||
19 | 25 | ||
20 | } | 26 | } | ... | ... |
core/store/dist/src/main/java/org/onlab/onos/store/device/impl/DeviceAntiEntropyAdvertisement.java
0 → 100644
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | +import java.util.HashMap; | ||
5 | +import java.util.Map; | ||
6 | + | ||
7 | +import org.onlab.onos.cluster.NodeId; | ||
8 | +import org.onlab.onos.net.Device; | ||
9 | +import org.onlab.onos.net.DeviceId; | ||
10 | +import org.onlab.onos.store.Timestamp; | ||
11 | +import org.onlab.onos.store.cluster.messaging.AntiEntropyAdvertisement; | ||
12 | + | ||
13 | +// TODO DeviceID needs to be changed to something like (ProviderID, DeviceID) | ||
14 | +// TODO: Handle Port as part of these messages, or separate messages for Ports? | ||
15 | + | ||
16 | +public class DeviceAntiEntropyAdvertisement | ||
17 | + extends AntiEntropyAdvertisement<DeviceId> { | ||
18 | + | ||
19 | + | ||
20 | + public DeviceAntiEntropyAdvertisement(NodeId sender, | ||
21 | + Map<DeviceId, Timestamp> advertisement) { | ||
22 | + super(sender, advertisement); | ||
23 | + } | ||
24 | + | ||
25 | + // May need to add ProviderID, etc. | ||
26 | + public static DeviceAntiEntropyAdvertisement create( | ||
27 | + NodeId self, | ||
28 | + Collection<VersionedValue<Device>> localValues) { | ||
29 | + | ||
30 | + Map<DeviceId, Timestamp> ads = new HashMap<>(localValues.size()); | ||
31 | + for (VersionedValue<Device> e : localValues) { | ||
32 | + ads.put(e.entity().id(), e.timestamp()); | ||
33 | + } | ||
34 | + return new DeviceAntiEntropyAdvertisement(self, ads); | ||
35 | + } | ||
36 | + | ||
37 | + // For serializer | ||
38 | + protected DeviceAntiEntropyAdvertisement() {} | ||
39 | +} |
core/store/dist/src/main/java/org/onlab/onos/store/device/impl/DeviceAntiEntropyReply.java
0 → 100644
1 | +package org.onlab.onos.store.device.impl; | ||
2 | + | ||
3 | +import java.util.Collection; | ||
4 | +import java.util.HashMap; | ||
5 | +import java.util.HashSet; | ||
6 | +import java.util.Map; | ||
7 | +import java.util.Set; | ||
8 | + | ||
9 | +import org.onlab.onos.cluster.NodeId; | ||
10 | +import org.onlab.onos.net.Device; | ||
11 | +import org.onlab.onos.net.DeviceId; | ||
12 | +import org.onlab.onos.store.Timestamp; | ||
13 | +import org.onlab.onos.store.cluster.messaging.AntiEntropyReply; | ||
14 | + | ||
15 | +import com.google.common.collect.ImmutableMap; | ||
16 | +import com.google.common.collect.ImmutableSet; | ||
17 | + | ||
18 | +public class DeviceAntiEntropyReply | ||
19 | + extends AntiEntropyReply<DeviceId, VersionedValue<Device>> { | ||
20 | + | ||
21 | + | ||
22 | + public DeviceAntiEntropyReply(NodeId sender, | ||
23 | + Map<DeviceId, VersionedValue<Device>> suggestion, | ||
24 | + Set<DeviceId> request) { | ||
25 | + super(sender, suggestion, request); | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * Creates a reply to Anti-Entropy advertisement. | ||
30 | + * | ||
31 | + * @param advertisement to respond to | ||
32 | + * @param self node identifier representing local node | ||
33 | + * @param localValues local values held on this node | ||
34 | + * @return reply message | ||
35 | + */ | ||
36 | + public static DeviceAntiEntropyReply reply( | ||
37 | + DeviceAntiEntropyAdvertisement advertisement, | ||
38 | + NodeId self, | ||
39 | + Collection<VersionedValue<Device>> localValues | ||
40 | + ) { | ||
41 | + | ||
42 | + ImmutableMap<DeviceId, Timestamp> ads = advertisement.advertisement(); | ||
43 | + | ||
44 | + ImmutableMap.Builder<DeviceId, VersionedValue<Device>> | ||
45 | + sug = ImmutableMap.builder(); | ||
46 | + | ||
47 | + Set<DeviceId> req = new HashSet<>(ads.keySet()); | ||
48 | + | ||
49 | + for (VersionedValue<Device> e : localValues) { | ||
50 | + final DeviceId id = e.entity().id(); | ||
51 | + final Timestamp local = e.timestamp(); | ||
52 | + final Timestamp theirs = ads.get(id); | ||
53 | + if (theirs == null) { | ||
54 | + // they don't have it, suggest | ||
55 | + sug.put(id, e); | ||
56 | + // don't need theirs | ||
57 | + req.remove(id); | ||
58 | + } else if (local.compareTo(theirs) < 0) { | ||
59 | + // they got older one, suggest | ||
60 | + sug.put(id, e); | ||
61 | + // don't need theirs | ||
62 | + req.remove(id); | ||
63 | + } else if (local.equals(theirs)) { | ||
64 | + // same, don't need theirs | ||
65 | + req.remove(id); | ||
66 | + } | ||
67 | + } | ||
68 | + | ||
69 | + return new DeviceAntiEntropyReply(self, sug.build(), req); | ||
70 | + } | ||
71 | + | ||
72 | + /** | ||
73 | + * Creates a reply to request for values held locally. | ||
74 | + * | ||
75 | + * @param requests message containing the request | ||
76 | + * @param self node identifier representing local node | ||
77 | + * @param localValues local valeds held on this node | ||
78 | + * @return reply message | ||
79 | + */ | ||
80 | + public static DeviceAntiEntropyReply reply( | ||
81 | + DeviceAntiEntropyReply requests, | ||
82 | + NodeId self, | ||
83 | + Map<DeviceId, VersionedValue<Device>> localValues | ||
84 | + ) { | ||
85 | + | ||
86 | + Set<DeviceId> reqs = requests.request(); | ||
87 | + | ||
88 | + Map<DeviceId, VersionedValue<Device>> requested = new HashMap<>(reqs.size()); | ||
89 | + for (DeviceId id : reqs) { | ||
90 | + final VersionedValue<Device> value = localValues.get(id); | ||
91 | + if (value != null) { | ||
92 | + requested.put(id, value); | ||
93 | + } | ||
94 | + } | ||
95 | + | ||
96 | + Set<DeviceId> empty = ImmutableSet.of(); | ||
97 | + return new DeviceAntiEntropyReply(self, requested, empty); | ||
98 | + } | ||
99 | + | ||
100 | + // For serializer | ||
101 | + protected DeviceAntiEntropyReply() {} | ||
102 | +} |
... | @@ -40,6 +40,7 @@ import java.util.Map; | ... | @@ -40,6 +40,7 @@ import java.util.Map; |
40 | import java.util.Objects; | 40 | import java.util.Objects; |
41 | import java.util.Set; | 41 | import java.util.Set; |
42 | import java.util.concurrent.ConcurrentHashMap; | 42 | import java.util.concurrent.ConcurrentHashMap; |
43 | +import java.util.concurrent.ConcurrentMap; | ||
43 | 44 | ||
44 | import static com.google.common.base.Preconditions.checkArgument; | 45 | import static com.google.common.base.Preconditions.checkArgument; |
45 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; | 46 | import static org.onlab.onos.net.device.DeviceEvent.Type.*; |
... | @@ -59,8 +60,8 @@ public class OnosDistributedDeviceStore | ... | @@ -59,8 +60,8 @@ public class OnosDistributedDeviceStore |
59 | 60 | ||
60 | public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; | 61 | public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; |
61 | 62 | ||
62 | - private ConcurrentHashMap<DeviceId, VersionedValue<Device>> devices; | 63 | + private ConcurrentMap<DeviceId, VersionedValue<Device>> devices; |
63 | - private ConcurrentHashMap<DeviceId, Map<PortNumber, VersionedValue<Port>>> devicePorts; | 64 | + private ConcurrentMap<DeviceId, Map<PortNumber, VersionedValue<Port>>> devicePorts; |
64 | 65 | ||
65 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 66 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
66 | protected ClockService clockService; | 67 | protected ClockService clockService; |
... | @@ -191,7 +192,7 @@ public class OnosDistributedDeviceStore | ... | @@ -191,7 +192,7 @@ public class OnosDistributedDeviceStore |
191 | } | 192 | } |
192 | 193 | ||
193 | @Override | 194 | @Override |
194 | - public List<DeviceEvent> updatePorts(DeviceId deviceId, | 195 | + public List<DeviceEvent> updatePorts(ProviderId providerId, DeviceId deviceId, |
195 | List<PortDescription> portDescriptions) { | 196 | List<PortDescription> portDescriptions) { |
196 | List<DeviceEvent> events = new ArrayList<>(); | 197 | List<DeviceEvent> events = new ArrayList<>(); |
197 | synchronized (this) { | 198 | synchronized (this) { |
... | @@ -295,7 +296,7 @@ public class OnosDistributedDeviceStore | ... | @@ -295,7 +296,7 @@ public class OnosDistributedDeviceStore |
295 | } | 296 | } |
296 | 297 | ||
297 | @Override | 298 | @Override |
298 | - public DeviceEvent updatePortStatus(DeviceId deviceId, | 299 | + public DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, |
299 | PortDescription portDescription) { | 300 | PortDescription portDescription) { |
300 | VersionedValue<Device> device = devices.get(deviceId); | 301 | VersionedValue<Device> device = devices.get(deviceId); |
301 | checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | 302 | checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ... | ... |
1 | package org.onlab.onos.store.device.impl; | 1 | package org.onlab.onos.store.device.impl; |
2 | 2 | ||
3 | +import java.util.Objects; | ||
4 | + | ||
3 | import org.onlab.onos.store.Timestamp; | 5 | import org.onlab.onos.store.Timestamp; |
4 | 6 | ||
5 | /** | 7 | /** |
... | @@ -42,4 +44,35 @@ public class VersionedValue<T> { | ... | @@ -42,4 +44,35 @@ public class VersionedValue<T> { |
42 | public Timestamp timestamp() { | 44 | public Timestamp timestamp() { |
43 | return timestamp; | 45 | return timestamp; |
44 | } | 46 | } |
47 | + | ||
48 | + | ||
49 | + @Override | ||
50 | + public int hashCode() { | ||
51 | + return Objects.hash(entity, timestamp, isUp); | ||
52 | + } | ||
53 | + | ||
54 | + @Override | ||
55 | + public boolean equals(Object obj) { | ||
56 | + if (this == obj) { | ||
57 | + return true; | ||
58 | + } | ||
59 | + if (obj == null) { | ||
60 | + return false; | ||
61 | + } | ||
62 | + if (getClass() != obj.getClass()) { | ||
63 | + return false; | ||
64 | + } | ||
65 | + @SuppressWarnings("unchecked") | ||
66 | + VersionedValue<T> that = (VersionedValue<T>) obj; | ||
67 | + return Objects.equals(this.entity, that.entity) && | ||
68 | + Objects.equals(this.timestamp, that.timestamp) && | ||
69 | + Objects.equals(this.isUp, that.isUp); | ||
70 | + } | ||
71 | + | ||
72 | + // Default constructor for serializer | ||
73 | + protected VersionedValue() { | ||
74 | + this.entity = null; | ||
75 | + this.isUp = false; | ||
76 | + this.timestamp = null; | ||
77 | + } | ||
45 | } | 78 | } | ... | ... |
core/store/dist/src/test/java/org/onlab/onos/store/cluster/impl/ClusterCommunicationManagerTest.java
... | @@ -2,6 +2,7 @@ package org.onlab.onos.store.cluster.impl; | ... | @@ -2,6 +2,7 @@ package org.onlab.onos.store.cluster.impl; |
2 | 2 | ||
3 | import org.junit.After; | 3 | import org.junit.After; |
4 | import org.junit.Before; | 4 | import org.junit.Before; |
5 | +import org.junit.Ignore; | ||
5 | import org.junit.Test; | 6 | import org.junit.Test; |
6 | import org.onlab.onos.cluster.DefaultControllerNode; | 7 | import org.onlab.onos.cluster.DefaultControllerNode; |
7 | import org.onlab.onos.cluster.NodeId; | 8 | import org.onlab.onos.cluster.NodeId; |
... | @@ -58,6 +59,7 @@ public class ClusterCommunicationManagerTest { | ... | @@ -58,6 +59,7 @@ public class ClusterCommunicationManagerTest { |
58 | ccm2.deactivate(); | 59 | ccm2.deactivate(); |
59 | } | 60 | } |
60 | 61 | ||
62 | + @Ignore("FIXME: failing randomly?") | ||
61 | @Test | 63 | @Test |
62 | public void connect() throws Exception { | 64 | public void connect() throws Exception { |
63 | cnd1.latch = new CountDownLatch(1); | 65 | cnd1.latch = new CountDownLatch(1); | ... | ... |
... | @@ -123,6 +123,12 @@ implements MastershipStore { | ... | @@ -123,6 +123,12 @@ implements MastershipStore { |
123 | return null; | 123 | return null; |
124 | } | 124 | } |
125 | 125 | ||
126 | + @Override | ||
127 | + public MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId) { | ||
128 | + // TODO Auto-generated method stub | ||
129 | + return null; | ||
130 | + } | ||
131 | + | ||
126 | private class RemoteMasterShipEventHandler extends RemoteCacheEventHandler<DeviceId, NodeId> { | 132 | private class RemoteMasterShipEventHandler extends RemoteCacheEventHandler<DeviceId, NodeId> { |
127 | public RemoteMasterShipEventHandler(LoadingCache<DeviceId, Optional<NodeId>> cache) { | 133 | public RemoteMasterShipEventHandler(LoadingCache<DeviceId, Optional<NodeId>> cache) { |
128 | super(cache); | 134 | super(cache); | ... | ... |
... | @@ -221,7 +221,7 @@ public class DistributedDeviceStore | ... | @@ -221,7 +221,7 @@ public class DistributedDeviceStore |
221 | } | 221 | } |
222 | 222 | ||
223 | @Override | 223 | @Override |
224 | - public List<DeviceEvent> updatePorts(DeviceId deviceId, | 224 | + public List<DeviceEvent> updatePorts(ProviderId providerId, DeviceId deviceId, |
225 | List<PortDescription> portDescriptions) { | 225 | List<PortDescription> portDescriptions) { |
226 | List<DeviceEvent> events = new ArrayList<>(); | 226 | List<DeviceEvent> events = new ArrayList<>(); |
227 | synchronized (this) { | 227 | synchronized (this) { |
... | @@ -319,7 +319,7 @@ public class DistributedDeviceStore | ... | @@ -319,7 +319,7 @@ public class DistributedDeviceStore |
319 | } | 319 | } |
320 | 320 | ||
321 | @Override | 321 | @Override |
322 | - public DeviceEvent updatePortStatus(DeviceId deviceId, | 322 | + public DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, |
323 | PortDescription portDescription) { | 323 | PortDescription portDescription) { |
324 | synchronized (this) { | 324 | synchronized (this) { |
325 | Device device = devices.getUnchecked(deviceId).orNull(); | 325 | Device device = devices.getUnchecked(deviceId).orNull(); | ... | ... |
... | @@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableSet; | ... | @@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableSet; |
28 | import com.google.common.collect.Multimap; | 28 | import com.google.common.collect.Multimap; |
29 | 29 | ||
30 | /** | 30 | /** |
31 | - * Manages inventory of flow rules using trivial in-memory implementation. | 31 | + * TEMPORARY: Manages inventory of flow rules using distributed store implementation. |
32 | */ | 32 | */ |
33 | //FIXME: I LIE I AM NOT DISTRIBUTED | 33 | //FIXME: I LIE I AM NOT DISTRIBUTED |
34 | @Component(immediate = true) | 34 | @Component(immediate = true) | ... | ... |
... | @@ -39,8 +39,8 @@ import com.google.common.collect.Multimap; | ... | @@ -39,8 +39,8 @@ import com.google.common.collect.Multimap; |
39 | import com.google.common.collect.Sets; | 39 | import com.google.common.collect.Sets; |
40 | 40 | ||
41 | /** | 41 | /** |
42 | - * Manages inventory of end-station hosts using trivial in-memory | 42 | + * TEMPORARY: Manages inventory of end-station hosts using distributed |
43 | - * implementation. | 43 | + * structures implementation. |
44 | */ | 44 | */ |
45 | //FIXME: I LIE I AM NOT DISTRIBUTED | 45 | //FIXME: I LIE I AM NOT DISTRIBUTED |
46 | @Component(immediate = true) | 46 | @Component(immediate = true) | ... | ... |
... | @@ -28,7 +28,7 @@ import org.onlab.onos.store.AbstractStore; | ... | @@ -28,7 +28,7 @@ import org.onlab.onos.store.AbstractStore; |
28 | import org.slf4j.Logger; | 28 | import org.slf4j.Logger; |
29 | 29 | ||
30 | /** | 30 | /** |
31 | - * Manages inventory of topology snapshots using trivial in-memory | 31 | + * TEMPORARY: Manages inventory of topology snapshots using distributed |
32 | * structures implementation. | 32 | * structures implementation. |
33 | */ | 33 | */ |
34 | //FIXME: I LIE I AM NOT DISTRIBUTED | 34 | //FIXME: I LIE I AM NOT DISTRIBUTED | ... | ... |
... | @@ -201,7 +201,7 @@ public class DistributedDeviceStoreTest { | ... | @@ -201,7 +201,7 @@ public class DistributedDeviceStoreTest { |
201 | new DefaultPortDescription(P2, true) | 201 | new DefaultPortDescription(P2, true) |
202 | ); | 202 | ); |
203 | 203 | ||
204 | - List<DeviceEvent> events = deviceStore.updatePorts(DID1, pds); | 204 | + List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds); |
205 | 205 | ||
206 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | 206 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
207 | for (DeviceEvent event : events) { | 207 | for (DeviceEvent event : events) { |
... | @@ -220,7 +220,7 @@ public class DistributedDeviceStoreTest { | ... | @@ -220,7 +220,7 @@ public class DistributedDeviceStoreTest { |
220 | new DefaultPortDescription(P3, true) | 220 | new DefaultPortDescription(P3, true) |
221 | ); | 221 | ); |
222 | 222 | ||
223 | - events = deviceStore.updatePorts(DID1, pds2); | 223 | + events = deviceStore.updatePorts(PID, DID1, pds2); |
224 | assertFalse("event should be triggered", events.isEmpty()); | 224 | assertFalse("event should be triggered", events.isEmpty()); |
225 | for (DeviceEvent event : events) { | 225 | for (DeviceEvent event : events) { |
226 | PortNumber num = event.port().number(); | 226 | PortNumber num = event.port().number(); |
... | @@ -243,7 +243,7 @@ public class DistributedDeviceStoreTest { | ... | @@ -243,7 +243,7 @@ public class DistributedDeviceStoreTest { |
243 | new DefaultPortDescription(P1, false), | 243 | new DefaultPortDescription(P1, false), |
244 | new DefaultPortDescription(P2, true) | 244 | new DefaultPortDescription(P2, true) |
245 | ); | 245 | ); |
246 | - events = deviceStore.updatePorts(DID1, pds3); | 246 | + events = deviceStore.updatePorts(PID, DID1, pds3); |
247 | assertFalse("event should be triggered", events.isEmpty()); | 247 | assertFalse("event should be triggered", events.isEmpty()); |
248 | for (DeviceEvent event : events) { | 248 | for (DeviceEvent event : events) { |
249 | PortNumber num = event.port().number(); | 249 | PortNumber num = event.port().number(); |
... | @@ -268,9 +268,9 @@ public class DistributedDeviceStoreTest { | ... | @@ -268,9 +268,9 @@ public class DistributedDeviceStoreTest { |
268 | List<PortDescription> pds = Arrays.<PortDescription>asList( | 268 | List<PortDescription> pds = Arrays.<PortDescription>asList( |
269 | new DefaultPortDescription(P1, true) | 269 | new DefaultPortDescription(P1, true) |
270 | ); | 270 | ); |
271 | - deviceStore.updatePorts(DID1, pds); | 271 | + deviceStore.updatePorts(PID, DID1, pds); |
272 | 272 | ||
273 | - DeviceEvent event = deviceStore.updatePortStatus(DID1, | 273 | + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, |
274 | new DefaultPortDescription(P1, false)); | 274 | new DefaultPortDescription(P1, false)); |
275 | assertEquals(PORT_UPDATED, event.type()); | 275 | assertEquals(PORT_UPDATED, event.type()); |
276 | assertDevice(DID1, SW1, event.subject()); | 276 | assertDevice(DID1, SW1, event.subject()); |
... | @@ -286,7 +286,7 @@ public class DistributedDeviceStoreTest { | ... | @@ -286,7 +286,7 @@ public class DistributedDeviceStoreTest { |
286 | new DefaultPortDescription(P1, true), | 286 | new DefaultPortDescription(P1, true), |
287 | new DefaultPortDescription(P2, true) | 287 | new DefaultPortDescription(P2, true) |
288 | ); | 288 | ); |
289 | - deviceStore.updatePorts(DID1, pds); | 289 | + deviceStore.updatePorts(PID, DID1, pds); |
290 | 290 | ||
291 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | 291 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
292 | List<Port> ports = deviceStore.getPorts(DID1); | 292 | List<Port> ports = deviceStore.getPorts(DID1); |
... | @@ -309,7 +309,7 @@ public class DistributedDeviceStoreTest { | ... | @@ -309,7 +309,7 @@ public class DistributedDeviceStoreTest { |
309 | new DefaultPortDescription(P1, true), | 309 | new DefaultPortDescription(P1, true), |
310 | new DefaultPortDescription(P2, false) | 310 | new DefaultPortDescription(P2, false) |
311 | ); | 311 | ); |
312 | - deviceStore.updatePorts(DID1, pds); | 312 | + deviceStore.updatePorts(PID, DID1, pds); |
313 | 313 | ||
314 | Port port1 = deviceStore.getPort(DID1, P1); | 314 | Port port1 = deviceStore.getPort(DID1, P1); |
315 | assertEquals(P1, port1.number()); | 315 | assertEquals(P1, port1.number()); | ... | ... |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/ImmutableMapSerializer.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import java.util.Collections; | ||
4 | +import java.util.HashMap; | ||
5 | +import java.util.Map; | ||
6 | + | ||
7 | +import org.onlab.util.KryoPool.FamilySerializer; | ||
8 | + | ||
9 | +import com.esotericsoftware.kryo.Kryo; | ||
10 | +import com.esotericsoftware.kryo.io.Input; | ||
11 | +import com.esotericsoftware.kryo.io.Output; | ||
12 | +import com.esotericsoftware.kryo.serializers.MapSerializer; | ||
13 | +import com.google.common.collect.ImmutableMap; | ||
14 | + | ||
15 | +/** | ||
16 | +* Kryo Serializer for {@link ImmutableMap}. | ||
17 | +*/ | ||
18 | +public class ImmutableMapSerializer extends FamilySerializer<ImmutableMap<?, ?>> { | ||
19 | + | ||
20 | + private final MapSerializer mapSerializer = new MapSerializer(); | ||
21 | + | ||
22 | + public ImmutableMapSerializer() { | ||
23 | + // non-null, immutable | ||
24 | + super(false, true); | ||
25 | + } | ||
26 | + | ||
27 | + @Override | ||
28 | + public void write(Kryo kryo, Output output, ImmutableMap<?, ?> object) { | ||
29 | + // wrapping with unmodifiableMap proxy | ||
30 | + // to avoid Kryo from writing only the reference marker of this instance, | ||
31 | + // which will be embedded right before this method call. | ||
32 | + kryo.writeObject(output, Collections.unmodifiableMap(object), mapSerializer); | ||
33 | + } | ||
34 | + | ||
35 | + @Override | ||
36 | + public ImmutableMap<?, ?> read(Kryo kryo, Input input, | ||
37 | + Class<ImmutableMap<?, ?>> type) { | ||
38 | + Map<?, ?> map = kryo.readObject(input, HashMap.class, mapSerializer); | ||
39 | + return ImmutableMap.copyOf(map); | ||
40 | + } | ||
41 | + | ||
42 | + @Override | ||
43 | + public void registerFamilies(Kryo kryo) { | ||
44 | + kryo.register(ImmutableMap.of().getClass(), this); | ||
45 | + kryo.register(ImmutableMap.of(1, 2).getClass(), this); | ||
46 | + kryo.register(ImmutableMap.of(1, 2, 3, 4).getClass(), this); | ||
47 | + // TODO register required ImmutableMap variants | ||
48 | + } | ||
49 | +} |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/ImmutableSetSerializer.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import java.util.ArrayList; | ||
4 | +import java.util.List; | ||
5 | + | ||
6 | +import org.onlab.util.KryoPool.FamilySerializer; | ||
7 | + | ||
8 | +import com.esotericsoftware.kryo.Kryo; | ||
9 | +import com.esotericsoftware.kryo.io.Input; | ||
10 | +import com.esotericsoftware.kryo.io.Output; | ||
11 | +import com.esotericsoftware.kryo.serializers.CollectionSerializer; | ||
12 | +import com.google.common.collect.ImmutableSet; | ||
13 | + | ||
14 | +/** | ||
15 | +* Kryo Serializer for {@link ImmutableSet}. | ||
16 | +*/ | ||
17 | +public class ImmutableSetSerializer extends FamilySerializer<ImmutableSet<?>> { | ||
18 | + | ||
19 | + private final CollectionSerializer serializer = new CollectionSerializer(); | ||
20 | + | ||
21 | + public ImmutableSetSerializer() { | ||
22 | + // non-null, immutable | ||
23 | + super(false, true); | ||
24 | + } | ||
25 | + | ||
26 | + @Override | ||
27 | + public void write(Kryo kryo, Output output, ImmutableSet<?> object) { | ||
28 | + kryo.writeObject(output, object.asList(), serializer); | ||
29 | + } | ||
30 | + | ||
31 | + @Override | ||
32 | + public ImmutableSet<?> read(Kryo kryo, Input input, | ||
33 | + Class<ImmutableSet<?>> type) { | ||
34 | + List<?> elms = kryo.readObject(input, ArrayList.class, serializer); | ||
35 | + return ImmutableSet.copyOf(elms); | ||
36 | + } | ||
37 | + | ||
38 | + @Override | ||
39 | + public void registerFamilies(Kryo kryo) { | ||
40 | + kryo.register(ImmutableSet.of().getClass(), this); | ||
41 | + kryo.register(ImmutableSet.of(1).getClass(), this); | ||
42 | + kryo.register(ImmutableSet.of(1, 2).getClass(), this); | ||
43 | + // TODO register required ImmutableSet variants | ||
44 | + } | ||
45 | +} |
1 | package org.onlab.onos.store.serializers; | 1 | package org.onlab.onos.store.serializers; |
2 | 2 | ||
3 | import java.net.URI; | 3 | import java.net.URI; |
4 | +import java.nio.ByteBuffer; | ||
4 | import java.util.ArrayList; | 5 | import java.util.ArrayList; |
5 | import java.util.HashMap; | 6 | import java.util.HashMap; |
6 | 7 | ||
... | @@ -100,4 +101,14 @@ public class KryoSerializationManager implements KryoSerializationService { | ... | @@ -100,4 +101,14 @@ public class KryoSerializationManager implements KryoSerializationService { |
100 | return serializerPool.deserialize(bytes); | 101 | return serializerPool.deserialize(bytes); |
101 | } | 102 | } |
102 | 103 | ||
104 | + @Override | ||
105 | + public void serialize(Object obj, ByteBuffer buffer) { | ||
106 | + serializerPool.serialize(obj, buffer); | ||
107 | + } | ||
108 | + | ||
109 | + @Override | ||
110 | + public <T> T deserialize(ByteBuffer buffer) { | ||
111 | + return serializerPool.deserialize(buffer); | ||
112 | + } | ||
113 | + | ||
103 | } | 114 | } | ... | ... |
1 | package org.onlab.onos.store.serializers; | 1 | package org.onlab.onos.store.serializers; |
2 | 2 | ||
3 | +import java.nio.ByteBuffer; | ||
4 | + | ||
3 | // TODO: To be replaced with SerializationService from IOLoop activity | 5 | // TODO: To be replaced with SerializationService from IOLoop activity |
4 | /** | 6 | /** |
5 | * Service to serialize Objects into byte array. | 7 | * Service to serialize Objects into byte array. |
... | @@ -16,6 +18,15 @@ public interface KryoSerializationService { | ... | @@ -16,6 +18,15 @@ public interface KryoSerializationService { |
16 | public byte[] serialize(final Object obj); | 18 | public byte[] serialize(final Object obj); |
17 | 19 | ||
18 | /** | 20 | /** |
21 | + * Serializes the specified object into bytes using one of the | ||
22 | + * pre-registered serializers. | ||
23 | + * | ||
24 | + * @param obj object to be serialized | ||
25 | + * @param buffer to write serialized bytes | ||
26 | + */ | ||
27 | + public void serialize(final Object obj, ByteBuffer buffer); | ||
28 | + | ||
29 | + /** | ||
19 | * Deserializes the specified bytes into an object using one of the | 30 | * Deserializes the specified bytes into an object using one of the |
20 | * pre-registered serializers. | 31 | * pre-registered serializers. |
21 | * | 32 | * |
... | @@ -24,4 +35,12 @@ public interface KryoSerializationService { | ... | @@ -24,4 +35,12 @@ public interface KryoSerializationService { |
24 | */ | 35 | */ |
25 | public <T> T deserialize(final byte[] bytes); | 36 | public <T> T deserialize(final byte[] bytes); |
26 | 37 | ||
38 | + /** | ||
39 | + * Deserializes the specified bytes into an object using one of the | ||
40 | + * pre-registered serializers. | ||
41 | + * | ||
42 | + * @param buffer bytes to be deserialized | ||
43 | + * @return deserialized object | ||
44 | + */ | ||
45 | + public <T> T deserialize(final ByteBuffer buffer); | ||
27 | } | 46 | } | ... | ... |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/MastershipRoleSerializer.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import org.onlab.onos.net.MastershipRole; | ||
4 | + | ||
5 | +import com.esotericsoftware.kryo.Kryo; | ||
6 | +import com.esotericsoftware.kryo.Serializer; | ||
7 | +import com.esotericsoftware.kryo.io.Input; | ||
8 | +import com.esotericsoftware.kryo.io.Output; | ||
9 | + | ||
10 | +/** | ||
11 | + * Kryo Serializer for {@link org.onlab.onos.net.MastershipRole}. | ||
12 | + */ | ||
13 | +public class MastershipRoleSerializer extends Serializer<MastershipRole> { | ||
14 | + | ||
15 | + @Override | ||
16 | + public MastershipRole read(Kryo kryo, Input input, Class<MastershipRole> type) { | ||
17 | + final String role = kryo.readObject(input, String.class); | ||
18 | + return MastershipRole.valueOf(role); | ||
19 | + } | ||
20 | + | ||
21 | + @Override | ||
22 | + public void write(Kryo kryo, Output output, MastershipRole object) { | ||
23 | + kryo.writeObject(output, object.toString()); | ||
24 | + } | ||
25 | + | ||
26 | +} |
core/store/serializers/src/main/java/org/onlab/onos/store/serializers/MastershipTermSerializer.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import org.onlab.onos.cluster.MastershipTerm; | ||
4 | +import org.onlab.onos.cluster.NodeId; | ||
5 | + | ||
6 | +import com.esotericsoftware.kryo.Kryo; | ||
7 | +import com.esotericsoftware.kryo.Serializer; | ||
8 | +import com.esotericsoftware.kryo.io.Input; | ||
9 | +import com.esotericsoftware.kryo.io.Output; | ||
10 | + | ||
11 | +/** | ||
12 | + * Kryo Serializer for {@link org.onlab.onos.cluster.MastershipTerm}. | ||
13 | + */ | ||
14 | +public class MastershipTermSerializer extends Serializer<MastershipTerm> { | ||
15 | + | ||
16 | + @Override | ||
17 | + public MastershipTerm read(Kryo kryo, Input input, Class<MastershipTerm> type) { | ||
18 | + final NodeId node = new NodeId(kryo.readObject(input, String.class)); | ||
19 | + final int term = input.readInt(); | ||
20 | + return MastershipTerm.of(node, term); | ||
21 | + } | ||
22 | + | ||
23 | + @Override | ||
24 | + public void write(Kryo kryo, Output output, MastershipTerm object) { | ||
25 | + output.writeString(object.master().toString()); | ||
26 | + output.writeInt(object.termNumber()); | ||
27 | + } | ||
28 | + | ||
29 | +} |
core/store/serializers/src/test/java/org/onlab/onos/store/serializers/KryoSerializerTests.java
0 → 100644
1 | +package org.onlab.onos.store.serializers; | ||
2 | + | ||
3 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
4 | +import static org.onlab.onos.net.PortNumber.portNumber; | ||
5 | + | ||
6 | +import java.net.URI; | ||
7 | +import java.nio.ByteBuffer; | ||
8 | +import java.util.ArrayList; | ||
9 | +import java.util.HashMap; | ||
10 | + | ||
11 | +import org.junit.After; | ||
12 | +import org.junit.Before; | ||
13 | +import org.junit.BeforeClass; | ||
14 | +import org.junit.Test; | ||
15 | +import org.onlab.onos.cluster.MastershipTerm; | ||
16 | +import org.onlab.onos.cluster.NodeId; | ||
17 | +import org.onlab.onos.net.ConnectPoint; | ||
18 | +import org.onlab.onos.net.DefaultDevice; | ||
19 | +import org.onlab.onos.net.DefaultLink; | ||
20 | +import org.onlab.onos.net.DefaultPort; | ||
21 | +import org.onlab.onos.net.Device; | ||
22 | +import org.onlab.onos.net.DeviceId; | ||
23 | +import org.onlab.onos.net.Link; | ||
24 | +import org.onlab.onos.net.LinkKey; | ||
25 | +import org.onlab.onos.net.MastershipRole; | ||
26 | +import org.onlab.onos.net.PortNumber; | ||
27 | +import org.onlab.onos.net.provider.ProviderId; | ||
28 | +import org.onlab.packet.IpPrefix; | ||
29 | +import org.onlab.util.KryoPool; | ||
30 | + | ||
31 | +import com.google.common.collect.ImmutableMap; | ||
32 | +import com.google.common.collect.ImmutableSet; | ||
33 | +import com.google.common.testing.EqualsTester; | ||
34 | + | ||
35 | +import de.javakaffee.kryoserializers.URISerializer; | ||
36 | + | ||
37 | +public class KryoSerializerTests { | ||
38 | + private static final ProviderId PID = new ProviderId("of", "foo"); | ||
39 | + private static final DeviceId DID1 = deviceId("of:foo"); | ||
40 | + private static final DeviceId DID2 = deviceId("of:bar"); | ||
41 | + private static final PortNumber P1 = portNumber(1); | ||
42 | + private static final PortNumber P2 = portNumber(2); | ||
43 | + private static final ConnectPoint CP1 = new ConnectPoint(DID1, P1); | ||
44 | + private static final ConnectPoint CP2 = new ConnectPoint(DID2, P2); | ||
45 | + private static final String MFR = "whitebox"; | ||
46 | + private static final String HW = "1.1.x"; | ||
47 | + private static final String SW1 = "3.8.1"; | ||
48 | + private static final String SW2 = "3.9.5"; | ||
49 | + private static final String SN = "43311-12345"; | ||
50 | + private static final Device DEV1 = new DefaultDevice(PID, DID1, Device.Type.SWITCH, MFR, HW, SW1, SN); | ||
51 | + | ||
52 | + private static KryoPool kryos; | ||
53 | + | ||
54 | + @BeforeClass | ||
55 | + public static void setUpBeforeClass() throws Exception { | ||
56 | + kryos = KryoPool.newBuilder() | ||
57 | + .register( | ||
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()) | ||
76 | + .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 | + | ||
83 | + .register(DefaultDevice.class) | ||
84 | + | ||
85 | + .register(URI.class, new URISerializer()) | ||
86 | + | ||
87 | + .register(MastershipRole.class, new MastershipRoleSerializer()) | ||
88 | + .register(MastershipTerm.class, new MastershipTermSerializer()) | ||
89 | + .build(); | ||
90 | + } | ||
91 | + | ||
92 | + @Before | ||
93 | + public void setUp() throws Exception { | ||
94 | + } | ||
95 | + | ||
96 | + @After | ||
97 | + public void tearDown() throws Exception { | ||
98 | + // removing Kryo instance to use fresh Kryo on each tests | ||
99 | + kryos.getKryo(); | ||
100 | + } | ||
101 | + | ||
102 | + private static <T> void testSerialized(T original) { | ||
103 | + ByteBuffer buffer = ByteBuffer.allocate(1 * 1024 * 1024); | ||
104 | + kryos.serialize(original, buffer); | ||
105 | + buffer.flip(); | ||
106 | + T copy = kryos.deserialize(buffer); | ||
107 | + | ||
108 | + new EqualsTester() | ||
109 | + .addEqualityGroup(original, copy) | ||
110 | + .testEquals(); | ||
111 | + } | ||
112 | + | ||
113 | + | ||
114 | + @Test | ||
115 | + public final void test() { | ||
116 | + testSerialized(new ConnectPoint(DID1, P1)); | ||
117 | + testSerialized(new DefaultLink(PID, CP1, CP2, Link.Type.DIRECT)); | ||
118 | + testSerialized(new DefaultPort(DEV1, P1, true)); | ||
119 | + testSerialized(DID1); | ||
120 | + testSerialized(ImmutableMap.of(DID1, DEV1, DID2, DEV1)); | ||
121 | + testSerialized(ImmutableMap.of(DID1, DEV1)); | ||
122 | + testSerialized(ImmutableMap.of()); | ||
123 | + testSerialized(ImmutableSet.of(DID1, DID2)); | ||
124 | + testSerialized(ImmutableSet.of(DID1)); | ||
125 | + testSerialized(ImmutableSet.of()); | ||
126 | + testSerialized(IpPrefix.valueOf("192.168.0.1/24")); | ||
127 | + testSerialized(new LinkKey(CP1, CP2)); | ||
128 | + testSerialized(new NodeId("SomeNodeIdentifier")); | ||
129 | + testSerialized(P1); | ||
130 | + testSerialized(PID); | ||
131 | + } | ||
132 | + | ||
133 | +} |
... | @@ -25,6 +25,10 @@ | ... | @@ -25,6 +25,10 @@ |
25 | <groupId>org.apache.felix</groupId> | 25 | <groupId>org.apache.felix</groupId> |
26 | <artifactId>org.apache.felix.scr.annotations</artifactId> | 26 | <artifactId>org.apache.felix.scr.annotations</artifactId> |
27 | </dependency> | 27 | </dependency> |
28 | + <dependency> | ||
29 | + <groupId>org.apache.commons</groupId> | ||
30 | + <artifactId>commons-lang3</artifactId> | ||
31 | + </dependency> | ||
28 | </dependencies> | 32 | </dependencies> |
29 | 33 | ||
30 | <build> | 34 | <build> | ... | ... |
core/store/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
deleted
100644 → 0
1 | -package org.onlab.onos.net.trivial.impl; | ||
2 | - | ||
3 | -import com.google.common.collect.FluentIterable; | ||
4 | -import com.google.common.collect.ImmutableList; | ||
5 | - | ||
6 | -import org.apache.felix.scr.annotations.Activate; | ||
7 | -import org.apache.felix.scr.annotations.Component; | ||
8 | -import org.apache.felix.scr.annotations.Deactivate; | ||
9 | -import org.apache.felix.scr.annotations.Service; | ||
10 | -import org.onlab.onos.net.DefaultDevice; | ||
11 | -import org.onlab.onos.net.DefaultPort; | ||
12 | -import org.onlab.onos.net.Device; | ||
13 | -import org.onlab.onos.net.DeviceId; | ||
14 | -import org.onlab.onos.net.Port; | ||
15 | -import org.onlab.onos.net.PortNumber; | ||
16 | -import org.onlab.onos.net.device.DeviceDescription; | ||
17 | -import org.onlab.onos.net.device.DeviceEvent; | ||
18 | -import org.onlab.onos.net.device.DeviceStore; | ||
19 | -import org.onlab.onos.net.device.DeviceStoreDelegate; | ||
20 | -import org.onlab.onos.net.device.PortDescription; | ||
21 | -import org.onlab.onos.net.provider.ProviderId; | ||
22 | -import org.onlab.onos.store.AbstractStore; | ||
23 | -import org.slf4j.Logger; | ||
24 | - | ||
25 | -import java.util.ArrayList; | ||
26 | -import java.util.Collections; | ||
27 | -import java.util.HashMap; | ||
28 | -import java.util.HashSet; | ||
29 | -import java.util.Iterator; | ||
30 | -import java.util.List; | ||
31 | -import java.util.Map; | ||
32 | -import java.util.Objects; | ||
33 | -import java.util.Set; | ||
34 | -import java.util.concurrent.ConcurrentHashMap; | ||
35 | - | ||
36 | -import static com.google.common.base.Preconditions.checkArgument; | ||
37 | -import static com.google.common.base.Predicates.notNull; | ||
38 | -import static org.onlab.onos.net.device.DeviceEvent.Type.*; | ||
39 | -import static org.slf4j.LoggerFactory.getLogger; | ||
40 | - | ||
41 | -/** | ||
42 | - * Manages inventory of infrastructure devices using trivial in-memory | ||
43 | - * structures implementation. | ||
44 | - */ | ||
45 | -@Component(immediate = true) | ||
46 | -@Service | ||
47 | -public class SimpleDeviceStore | ||
48 | - extends AbstractStore<DeviceEvent, DeviceStoreDelegate> | ||
49 | - implements DeviceStore { | ||
50 | - | ||
51 | - private final Logger log = getLogger(getClass()); | ||
52 | - | ||
53 | - public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; | ||
54 | - | ||
55 | - private final Map<DeviceId, DefaultDevice> devices = new ConcurrentHashMap<>(); | ||
56 | - private final Set<DeviceId> availableDevices = new HashSet<>(); | ||
57 | - private final Map<DeviceId, Map<PortNumber, Port>> devicePorts = new HashMap<>(); | ||
58 | - | ||
59 | - @Activate | ||
60 | - public void activate() { | ||
61 | - log.info("Started"); | ||
62 | - } | ||
63 | - | ||
64 | - @Deactivate | ||
65 | - public void deactivate() { | ||
66 | - log.info("Stopped"); | ||
67 | - } | ||
68 | - | ||
69 | - @Override | ||
70 | - public int getDeviceCount() { | ||
71 | - return devices.size(); | ||
72 | - } | ||
73 | - | ||
74 | - @Override | ||
75 | - public Iterable<Device> getDevices() { | ||
76 | - return Collections.unmodifiableSet(new HashSet<Device>(devices.values())); | ||
77 | - } | ||
78 | - | ||
79 | - @Override | ||
80 | - public Device getDevice(DeviceId deviceId) { | ||
81 | - return devices.get(deviceId); | ||
82 | - } | ||
83 | - | ||
84 | - @Override | ||
85 | - public DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, | ||
86 | - DeviceDescription deviceDescription) { | ||
87 | - DefaultDevice device = devices.get(deviceId); | ||
88 | - if (device == null) { | ||
89 | - return createDevice(providerId, deviceId, deviceDescription); | ||
90 | - } | ||
91 | - return updateDevice(providerId, device, deviceDescription); | ||
92 | - } | ||
93 | - | ||
94 | - // Creates the device and returns the appropriate event if necessary. | ||
95 | - private DeviceEvent createDevice(ProviderId providerId, DeviceId deviceId, | ||
96 | - DeviceDescription desc) { | ||
97 | - DefaultDevice device = new DefaultDevice(providerId, deviceId, desc.type(), | ||
98 | - desc.manufacturer(), | ||
99 | - desc.hwVersion(), desc.swVersion(), | ||
100 | - desc.serialNumber()); | ||
101 | - synchronized (this) { | ||
102 | - devices.put(deviceId, device); | ||
103 | - availableDevices.add(deviceId); | ||
104 | - } | ||
105 | - return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device, null); | ||
106 | - } | ||
107 | - | ||
108 | - // Updates the device and returns the appropriate event if necessary. | ||
109 | - private DeviceEvent updateDevice(ProviderId providerId, DefaultDevice device, | ||
110 | - DeviceDescription desc) { | ||
111 | - // We allow only certain attributes to trigger update | ||
112 | - if (!Objects.equals(device.hwVersion(), desc.hwVersion()) || | ||
113 | - !Objects.equals(device.swVersion(), desc.swVersion())) { | ||
114 | - DefaultDevice updated = new DefaultDevice(providerId, device.id(), | ||
115 | - desc.type(), | ||
116 | - desc.manufacturer(), | ||
117 | - desc.hwVersion(), | ||
118 | - desc.swVersion(), | ||
119 | - desc.serialNumber()); | ||
120 | - synchronized (this) { | ||
121 | - devices.put(device.id(), updated); | ||
122 | - availableDevices.add(device.id()); | ||
123 | - } | ||
124 | - return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, updated, null); | ||
125 | - } | ||
126 | - | ||
127 | - // Otherwise merely attempt to change availability | ||
128 | - synchronized (this) { | ||
129 | - boolean added = availableDevices.add(device.id()); | ||
130 | - return !added ? null : | ||
131 | - new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null); | ||
132 | - } | ||
133 | - } | ||
134 | - | ||
135 | - @Override | ||
136 | - public DeviceEvent markOffline(DeviceId deviceId) { | ||
137 | - synchronized (this) { | ||
138 | - Device device = devices.get(deviceId); | ||
139 | - boolean removed = device != null && availableDevices.remove(deviceId); | ||
140 | - return !removed ? null : | ||
141 | - new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null); | ||
142 | - } | ||
143 | - } | ||
144 | - | ||
145 | - @Override | ||
146 | - public List<DeviceEvent> updatePorts(DeviceId deviceId, | ||
147 | - List<PortDescription> portDescriptions) { | ||
148 | - List<DeviceEvent> events = new ArrayList<>(); | ||
149 | - synchronized (this) { | ||
150 | - Device device = devices.get(deviceId); | ||
151 | - checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
152 | - Map<PortNumber, Port> ports = getPortMap(deviceId); | ||
153 | - | ||
154 | - // Add new ports | ||
155 | - Set<PortNumber> processed = new HashSet<>(); | ||
156 | - for (PortDescription portDescription : portDescriptions) { | ||
157 | - Port port = ports.get(portDescription.portNumber()); | ||
158 | - events.add(port == null ? | ||
159 | - createPort(device, portDescription, ports) : | ||
160 | - updatePort(device, port, portDescription, ports)); | ||
161 | - processed.add(portDescription.portNumber()); | ||
162 | - } | ||
163 | - | ||
164 | - events.addAll(pruneOldPorts(device, ports, processed)); | ||
165 | - } | ||
166 | - return FluentIterable.from(events).filter(notNull()).toList(); | ||
167 | - } | ||
168 | - | ||
169 | - // Creates a new port based on the port description adds it to the map and | ||
170 | - // Returns corresponding event. | ||
171 | - private DeviceEvent createPort(Device device, PortDescription portDescription, | ||
172 | - Map<PortNumber, Port> ports) { | ||
173 | - DefaultPort port = new DefaultPort(device, portDescription.portNumber(), | ||
174 | - portDescription.isEnabled()); | ||
175 | - ports.put(port.number(), port); | ||
176 | - return new DeviceEvent(PORT_ADDED, device, port); | ||
177 | - } | ||
178 | - | ||
179 | - // CHecks if the specified port requires update and if so, it replaces the | ||
180 | - // existing entry in the map and returns corresponding event. | ||
181 | - private DeviceEvent updatePort(Device device, Port port, | ||
182 | - PortDescription portDescription, | ||
183 | - Map<PortNumber, Port> ports) { | ||
184 | - if (port.isEnabled() != portDescription.isEnabled()) { | ||
185 | - DefaultPort updatedPort = | ||
186 | - new DefaultPort(device, portDescription.portNumber(), | ||
187 | - portDescription.isEnabled()); | ||
188 | - ports.put(port.number(), updatedPort); | ||
189 | - return new DeviceEvent(PORT_UPDATED, device, updatedPort); | ||
190 | - } | ||
191 | - return null; | ||
192 | - } | ||
193 | - | ||
194 | - // Prunes the specified list of ports based on which ports are in the | ||
195 | - // processed list and returns list of corresponding events. | ||
196 | - private List<DeviceEvent> pruneOldPorts(Device device, | ||
197 | - Map<PortNumber, Port> ports, | ||
198 | - Set<PortNumber> processed) { | ||
199 | - List<DeviceEvent> events = new ArrayList<>(); | ||
200 | - Iterator<PortNumber> iterator = ports.keySet().iterator(); | ||
201 | - while (iterator.hasNext()) { | ||
202 | - PortNumber portNumber = iterator.next(); | ||
203 | - if (!processed.contains(portNumber)) { | ||
204 | - events.add(new DeviceEvent(PORT_REMOVED, device, | ||
205 | - ports.get(portNumber))); | ||
206 | - iterator.remove(); | ||
207 | - } | ||
208 | - } | ||
209 | - return events; | ||
210 | - } | ||
211 | - | ||
212 | - // Gets the map of ports for the specified device; if one does not already | ||
213 | - // exist, it creates and registers a new one. | ||
214 | - private Map<PortNumber, Port> getPortMap(DeviceId deviceId) { | ||
215 | - Map<PortNumber, Port> ports = devicePorts.get(deviceId); | ||
216 | - if (ports == null) { | ||
217 | - ports = new HashMap<>(); | ||
218 | - devicePorts.put(deviceId, ports); | ||
219 | - } | ||
220 | - return ports; | ||
221 | - } | ||
222 | - | ||
223 | - @Override | ||
224 | - public DeviceEvent updatePortStatus(DeviceId deviceId, | ||
225 | - PortDescription portDescription) { | ||
226 | - synchronized (this) { | ||
227 | - Device device = devices.get(deviceId); | ||
228 | - checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
229 | - Map<PortNumber, Port> ports = getPortMap(deviceId); | ||
230 | - Port port = ports.get(portDescription.portNumber()); | ||
231 | - return updatePort(device, port, portDescription, ports); | ||
232 | - } | ||
233 | - } | ||
234 | - | ||
235 | - @Override | ||
236 | - public List<Port> getPorts(DeviceId deviceId) { | ||
237 | - Map<PortNumber, Port> ports = devicePorts.get(deviceId); | ||
238 | - return ports == null ? new ArrayList<Port>() : ImmutableList.copyOf(ports.values()); | ||
239 | - } | ||
240 | - | ||
241 | - @Override | ||
242 | - public Port getPort(DeviceId deviceId, PortNumber portNumber) { | ||
243 | - Map<PortNumber, Port> ports = devicePorts.get(deviceId); | ||
244 | - return ports == null ? null : ports.get(portNumber); | ||
245 | - } | ||
246 | - | ||
247 | - @Override | ||
248 | - public boolean isAvailable(DeviceId deviceId) { | ||
249 | - return availableDevices.contains(deviceId); | ||
250 | - } | ||
251 | - | ||
252 | - @Override | ||
253 | - public DeviceEvent removeDevice(DeviceId deviceId) { | ||
254 | - synchronized (this) { | ||
255 | - Device device = devices.remove(deviceId); | ||
256 | - return device == null ? null : | ||
257 | - new DeviceEvent(DEVICE_REMOVED, device, null); | ||
258 | - } | ||
259 | - } | ||
260 | -} |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import org.apache.felix.scr.annotations.Component; | 3 | import org.apache.felix.scr.annotations.Component; |
4 | import org.apache.felix.scr.annotations.Service; | 4 | import org.apache.felix.scr.annotations.Service; | ... | ... |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import com.google.common.collect.ImmutableSet; | 3 | import com.google.common.collect.ImmutableSet; |
4 | import org.apache.felix.scr.annotations.Activate; | 4 | import org.apache.felix.scr.annotations.Activate; | ... | ... |
core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java
0 → 100644
1 | +package org.onlab.onos.store.trivial.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.Service; | ||
12 | +import org.onlab.onos.net.DefaultDevice; | ||
13 | +import org.onlab.onos.net.DefaultPort; | ||
14 | +import org.onlab.onos.net.Device; | ||
15 | +import org.onlab.onos.net.Device.Type; | ||
16 | +import org.onlab.onos.net.DeviceId; | ||
17 | +import org.onlab.onos.net.Port; | ||
18 | +import org.onlab.onos.net.PortNumber; | ||
19 | +import org.onlab.onos.net.device.DeviceDescription; | ||
20 | +import org.onlab.onos.net.device.DeviceEvent; | ||
21 | +import org.onlab.onos.net.device.DeviceStore; | ||
22 | +import org.onlab.onos.net.device.DeviceStoreDelegate; | ||
23 | +import org.onlab.onos.net.device.PortDescription; | ||
24 | +import org.onlab.onos.net.provider.ProviderId; | ||
25 | +import org.onlab.onos.store.AbstractStore; | ||
26 | +import org.slf4j.Logger; | ||
27 | + | ||
28 | +import java.util.ArrayList; | ||
29 | +import java.util.Collection; | ||
30 | +import java.util.Collections; | ||
31 | +import java.util.HashSet; | ||
32 | +import java.util.Iterator; | ||
33 | +import java.util.List; | ||
34 | +import java.util.Map; | ||
35 | +import java.util.Map.Entry; | ||
36 | +import java.util.Objects; | ||
37 | +import java.util.Set; | ||
38 | +import java.util.concurrent.ConcurrentHashMap; | ||
39 | +import java.util.concurrent.ConcurrentMap; | ||
40 | +import java.util.concurrent.atomic.AtomicReference; | ||
41 | + | ||
42 | +import static com.google.common.base.Preconditions.checkArgument; | ||
43 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
44 | +import static com.google.common.base.Predicates.notNull; | ||
45 | +import static org.onlab.onos.net.device.DeviceEvent.Type.*; | ||
46 | +import static org.slf4j.LoggerFactory.getLogger; | ||
47 | +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | ||
48 | + | ||
49 | +// TODO: synchronization should be done in more fine-grained manner. | ||
50 | +/** | ||
51 | + * Manages inventory of infrastructure devices using trivial in-memory | ||
52 | + * structures implementation. | ||
53 | + */ | ||
54 | +@Component(immediate = true) | ||
55 | +@Service | ||
56 | +public class SimpleDeviceStore | ||
57 | + extends AbstractStore<DeviceEvent, DeviceStoreDelegate> | ||
58 | + implements DeviceStore { | ||
59 | + | ||
60 | + private final Logger log = getLogger(getClass()); | ||
61 | + | ||
62 | + public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; | ||
63 | + | ||
64 | + // collection of Description given from various providers | ||
65 | + private final ConcurrentMap<DeviceId, | ||
66 | + ConcurrentMap<ProviderId, DeviceDescriptions>> | ||
67 | + deviceDescs = new ConcurrentHashMap<>(); | ||
68 | + | ||
69 | + // cache of Device and Ports generated by compositing descriptions from providers | ||
70 | + private final ConcurrentMap<DeviceId, Device> devices = new ConcurrentHashMap<>(); | ||
71 | + private final ConcurrentMap<DeviceId, ConcurrentMap<PortNumber, Port>> devicePorts = new ConcurrentHashMap<>(); | ||
72 | + | ||
73 | + // available(=UP) devices | ||
74 | + private final Set<DeviceId> availableDevices = new HashSet<>(); | ||
75 | + | ||
76 | + | ||
77 | + @Activate | ||
78 | + public void activate() { | ||
79 | + log.info("Started"); | ||
80 | + } | ||
81 | + | ||
82 | + @Deactivate | ||
83 | + public void deactivate() { | ||
84 | + log.info("Stopped"); | ||
85 | + } | ||
86 | + | ||
87 | + @Override | ||
88 | + public int getDeviceCount() { | ||
89 | + return devices.size(); | ||
90 | + } | ||
91 | + | ||
92 | + @Override | ||
93 | + public Iterable<Device> getDevices() { | ||
94 | + return Collections.unmodifiableCollection(devices.values()); | ||
95 | + } | ||
96 | + | ||
97 | + @Override | ||
98 | + public Device getDevice(DeviceId deviceId) { | ||
99 | + return devices.get(deviceId); | ||
100 | + } | ||
101 | + | ||
102 | + @Override | ||
103 | + public synchronized DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, | ||
104 | + DeviceDescription deviceDescription) { | ||
105 | + ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs | ||
106 | + = createIfAbsentUnchecked(deviceDescs, deviceId, | ||
107 | + new InitConcurrentHashMap<ProviderId, DeviceDescriptions>()); | ||
108 | + | ||
109 | + Device oldDevice = devices.get(deviceId); | ||
110 | + | ||
111 | + DeviceDescriptions descs | ||
112 | + = createIfAbsentUnchecked(providerDescs, providerId, | ||
113 | + new InitDeviceDescs(deviceDescription)); | ||
114 | + | ||
115 | + descs.putDeviceDesc(deviceDescription); | ||
116 | + | ||
117 | + Device newDevice = composeDevice(deviceId, providerDescs); | ||
118 | + | ||
119 | + if (oldDevice == null) { | ||
120 | + // ADD | ||
121 | + return createDevice(providerId, newDevice); | ||
122 | + } else { | ||
123 | + // UPDATE or ignore (no change or stale) | ||
124 | + return updateDevice(providerId, oldDevice, newDevice); | ||
125 | + } | ||
126 | + } | ||
127 | + | ||
128 | + // Creates the device and returns the appropriate event if necessary. | ||
129 | + private DeviceEvent createDevice(ProviderId providerId, Device newDevice) { | ||
130 | + | ||
131 | + // update composed device cache | ||
132 | + synchronized (this) { | ||
133 | + devices.putIfAbsent(newDevice.id(), newDevice); | ||
134 | + if (!providerId.isAncillary()) { | ||
135 | + availableDevices.add(newDevice.id()); | ||
136 | + } | ||
137 | + } | ||
138 | + | ||
139 | + return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, newDevice, null); | ||
140 | + } | ||
141 | + | ||
142 | + // Updates the device and returns the appropriate event if necessary. | ||
143 | + private DeviceEvent updateDevice(ProviderId providerId, Device oldDevice, Device newDevice) { | ||
144 | + | ||
145 | + // We allow only certain attributes to trigger update | ||
146 | + if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || | ||
147 | + !Objects.equals(oldDevice.swVersion(), newDevice.swVersion())) { | ||
148 | + | ||
149 | + synchronized (this) { | ||
150 | + devices.replace(newDevice.id(), oldDevice, newDevice); | ||
151 | + if (!providerId.isAncillary()) { | ||
152 | + availableDevices.add(newDevice.id()); | ||
153 | + } | ||
154 | + } | ||
155 | + return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null); | ||
156 | + } | ||
157 | + | ||
158 | + // Otherwise merely attempt to change availability if primary provider | ||
159 | + if (!providerId.isAncillary()) { | ||
160 | + synchronized (this) { | ||
161 | + boolean added = availableDevices.add(newDevice.id()); | ||
162 | + return !added ? null : | ||
163 | + new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, newDevice, null); | ||
164 | + } | ||
165 | + } | ||
166 | + return null; | ||
167 | + } | ||
168 | + | ||
169 | + @Override | ||
170 | + public DeviceEvent markOffline(DeviceId deviceId) { | ||
171 | + synchronized (this) { | ||
172 | + Device device = devices.get(deviceId); | ||
173 | + boolean removed = (device != null) && availableDevices.remove(deviceId); | ||
174 | + return !removed ? null : | ||
175 | + new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null); | ||
176 | + } | ||
177 | + } | ||
178 | + | ||
179 | + @Override | ||
180 | + public synchronized List<DeviceEvent> updatePorts(ProviderId providerId, DeviceId deviceId, | ||
181 | + List<PortDescription> portDescriptions) { | ||
182 | + | ||
183 | + // TODO: implement multi-provider | ||
184 | + Device device = devices.get(deviceId); | ||
185 | + checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
186 | + | ||
187 | + ConcurrentMap<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId); | ||
188 | + checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId); | ||
189 | + | ||
190 | + DeviceDescriptions descs = descsMap.get(providerId); | ||
191 | + checkArgument(descs != null, | ||
192 | + "Device description for Device ID %s from Provider %s was not found", | ||
193 | + deviceId, providerId); | ||
194 | + | ||
195 | + | ||
196 | + List<DeviceEvent> events = new ArrayList<>(); | ||
197 | + synchronized (this) { | ||
198 | + ConcurrentMap<PortNumber, Port> ports = getPortMap(deviceId); | ||
199 | + | ||
200 | + // Add new ports | ||
201 | + Set<PortNumber> processed = new HashSet<>(); | ||
202 | + for (PortDescription portDescription : portDescriptions) { | ||
203 | + PortNumber number = portDescription.portNumber(); | ||
204 | + Port oldPort = ports.get(number); | ||
205 | + // update description | ||
206 | + descs.putPortDesc(number, portDescription); | ||
207 | + Port newPort = composePort(device, number, descsMap); | ||
208 | + | ||
209 | + events.add(oldPort == null ? | ||
210 | + createPort(device, newPort, ports) : | ||
211 | + updatePort(device, oldPort, newPort, ports)); | ||
212 | + processed.add(portDescription.portNumber()); | ||
213 | + } | ||
214 | + | ||
215 | + events.addAll(pruneOldPorts(device, ports, processed)); | ||
216 | + } | ||
217 | + return FluentIterable.from(events).filter(notNull()).toList(); | ||
218 | + } | ||
219 | + | ||
220 | + // Creates a new port based on the port description adds it to the map and | ||
221 | + // Returns corresponding event. | ||
222 | + private DeviceEvent createPort(Device device, Port newPort, | ||
223 | + ConcurrentMap<PortNumber, Port> ports) { | ||
224 | + ports.put(newPort.number(), newPort); | ||
225 | + return new DeviceEvent(PORT_ADDED, device, newPort); | ||
226 | + } | ||
227 | + | ||
228 | + // CHecks if the specified port requires update and if so, it replaces the | ||
229 | + // existing entry in the map and returns corresponding event. | ||
230 | + private DeviceEvent updatePort(Device device, Port oldPort, | ||
231 | + Port newPort, | ||
232 | + ConcurrentMap<PortNumber, Port> ports) { | ||
233 | + if (oldPort.isEnabled() != newPort.isEnabled()) { | ||
234 | + ports.put(oldPort.number(), newPort); | ||
235 | + return new DeviceEvent(PORT_UPDATED, device, newPort); | ||
236 | + } | ||
237 | + return null; | ||
238 | + } | ||
239 | + | ||
240 | + // Prunes the specified list of ports based on which ports are in the | ||
241 | + // processed list and returns list of corresponding events. | ||
242 | + private List<DeviceEvent> pruneOldPorts(Device device, | ||
243 | + Map<PortNumber, Port> ports, | ||
244 | + Set<PortNumber> processed) { | ||
245 | + List<DeviceEvent> events = new ArrayList<>(); | ||
246 | + Iterator<PortNumber> iterator = ports.keySet().iterator(); | ||
247 | + while (iterator.hasNext()) { | ||
248 | + PortNumber portNumber = iterator.next(); | ||
249 | + if (!processed.contains(portNumber)) { | ||
250 | + events.add(new DeviceEvent(PORT_REMOVED, device, | ||
251 | + ports.get(portNumber))); | ||
252 | + iterator.remove(); | ||
253 | + } | ||
254 | + } | ||
255 | + return events; | ||
256 | + } | ||
257 | + | ||
258 | + // Gets the map of ports for the specified device; if one does not already | ||
259 | + // exist, it creates and registers a new one. | ||
260 | + private ConcurrentMap<PortNumber, Port> getPortMap(DeviceId deviceId) { | ||
261 | + return createIfAbsentUnchecked(devicePorts, deviceId, | ||
262 | + new InitConcurrentHashMap<PortNumber, Port>()); | ||
263 | + } | ||
264 | + | ||
265 | + @Override | ||
266 | + public synchronized DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, | ||
267 | + PortDescription portDescription) { | ||
268 | + Device device = devices.get(deviceId); | ||
269 | + checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); | ||
270 | + | ||
271 | + ConcurrentMap<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId); | ||
272 | + checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId); | ||
273 | + | ||
274 | + DeviceDescriptions descs = descsMap.get(providerId); | ||
275 | + checkArgument(descs != null, | ||
276 | + "Device description for Device ID %s from Provider %s was not found", | ||
277 | + deviceId, providerId); | ||
278 | + | ||
279 | + // TODO: implement multi-provider | ||
280 | + synchronized (this) { | ||
281 | + ConcurrentMap<PortNumber, Port> ports = getPortMap(deviceId); | ||
282 | + final PortNumber number = portDescription.portNumber(); | ||
283 | + Port oldPort = ports.get(number); | ||
284 | + // update description | ||
285 | + descs.putPortDesc(number, portDescription); | ||
286 | + Port newPort = composePort(device, number, descsMap); | ||
287 | + if (oldPort == null) { | ||
288 | + return createPort(device, newPort, ports); | ||
289 | + } else { | ||
290 | + return updatePort(device, oldPort, newPort, ports); | ||
291 | + } | ||
292 | + } | ||
293 | + } | ||
294 | + | ||
295 | + @Override | ||
296 | + public List<Port> getPorts(DeviceId deviceId) { | ||
297 | + Map<PortNumber, Port> ports = devicePorts.get(deviceId); | ||
298 | + if (ports == null) { | ||
299 | + return Collections.emptyList(); | ||
300 | + } | ||
301 | + return ImmutableList.copyOf(ports.values()); | ||
302 | + } | ||
303 | + | ||
304 | + @Override | ||
305 | + public Port getPort(DeviceId deviceId, PortNumber portNumber) { | ||
306 | + Map<PortNumber, Port> ports = devicePorts.get(deviceId); | ||
307 | + return ports == null ? null : ports.get(portNumber); | ||
308 | + } | ||
309 | + | ||
310 | + @Override | ||
311 | + public boolean isAvailable(DeviceId deviceId) { | ||
312 | + return availableDevices.contains(deviceId); | ||
313 | + } | ||
314 | + | ||
315 | + @Override | ||
316 | + public DeviceEvent removeDevice(DeviceId deviceId) { | ||
317 | + synchronized (this) { | ||
318 | + Device device = devices.remove(deviceId); | ||
319 | + return device == null ? null : | ||
320 | + new DeviceEvent(DEVICE_REMOVED, device, null); | ||
321 | + } | ||
322 | + } | ||
323 | + | ||
324 | + /** | ||
325 | + * Returns a Device, merging description given from multiple Providers. | ||
326 | + * | ||
327 | + * @param deviceId device identifier | ||
328 | + * @param providerDescs Collection of Descriptions from multiple providers | ||
329 | + * @return Device instance | ||
330 | + */ | ||
331 | + private Device composeDevice(DeviceId deviceId, | ||
332 | + ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { | ||
333 | + | ||
334 | + checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied"); | ||
335 | + | ||
336 | + ProviderId primary = pickPrimaryPID(providerDescs); | ||
337 | + | ||
338 | + DeviceDescriptions desc = providerDescs.get(primary); | ||
339 | + Type type = desc.getDeviceDesc().type(); | ||
340 | + String manufacturer = desc.getDeviceDesc().manufacturer(); | ||
341 | + String hwVersion = desc.getDeviceDesc().hwVersion(); | ||
342 | + String swVersion = desc.getDeviceDesc().swVersion(); | ||
343 | + String serialNumber = desc.getDeviceDesc().serialNumber(); | ||
344 | + | ||
345 | + for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) { | ||
346 | + if (e.getKey().equals(primary)) { | ||
347 | + continue; | ||
348 | + } | ||
349 | + // FIXME: implement attribute merging once we have K-V attributes | ||
350 | + } | ||
351 | + | ||
352 | + return new DefaultDevice(primary, deviceId , type, manufacturer, hwVersion, swVersion, serialNumber); | ||
353 | + } | ||
354 | + | ||
355 | + // probably want composePorts | ||
356 | + private Port composePort(Device device, PortNumber number, | ||
357 | + ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { | ||
358 | + | ||
359 | + ProviderId primary = pickPrimaryPID(providerDescs); | ||
360 | + DeviceDescriptions primDescs = providerDescs.get(primary); | ||
361 | + final PortDescription portDesc = primDescs.getPortDesc(number); | ||
362 | + boolean isEnabled; | ||
363 | + if (portDesc != null) { | ||
364 | + isEnabled = portDesc.isEnabled(); | ||
365 | + } else { | ||
366 | + // if no primary, assume not enabled | ||
367 | + // TODO: revisit this port enabled/disabled behavior | ||
368 | + isEnabled = false; | ||
369 | + } | ||
370 | + | ||
371 | + for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) { | ||
372 | + if (e.getKey().equals(primary)) { | ||
373 | + continue; | ||
374 | + } | ||
375 | + // FIXME: implement attribute merging once we have K-V attributes | ||
376 | + } | ||
377 | + | ||
378 | + return new DefaultPort(device, number, isEnabled); | ||
379 | + } | ||
380 | + | ||
381 | + /** | ||
382 | + * @return primary ProviderID, or randomly chosen one if none exists | ||
383 | + */ | ||
384 | + private ProviderId pickPrimaryPID( | ||
385 | + ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) { | ||
386 | + ProviderId fallBackPrimary = null; | ||
387 | + for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) { | ||
388 | + if (!e.getKey().isAncillary()) { | ||
389 | + return e.getKey(); | ||
390 | + } else if (fallBackPrimary == null) { | ||
391 | + // pick randomly as a fallback in case there is no primary | ||
392 | + fallBackPrimary = e.getKey(); | ||
393 | + } | ||
394 | + } | ||
395 | + return fallBackPrimary; | ||
396 | + } | ||
397 | + | ||
398 | + // TODO: can be made generic | ||
399 | + private static final class InitConcurrentHashMap<K, V> implements | ||
400 | + ConcurrentInitializer<ConcurrentMap<K, V>> { | ||
401 | + @Override | ||
402 | + public ConcurrentMap<K, V> get() throws ConcurrentException { | ||
403 | + return new ConcurrentHashMap<>(); | ||
404 | + } | ||
405 | + } | ||
406 | + | ||
407 | + public static final class InitDeviceDescs | ||
408 | + implements ConcurrentInitializer<DeviceDescriptions> { | ||
409 | + private final DeviceDescription deviceDesc; | ||
410 | + public InitDeviceDescs(DeviceDescription deviceDesc) { | ||
411 | + this.deviceDesc = checkNotNull(deviceDesc); | ||
412 | + } | ||
413 | + @Override | ||
414 | + public DeviceDescriptions get() throws ConcurrentException { | ||
415 | + return new DeviceDescriptions(deviceDesc); | ||
416 | + } | ||
417 | + } | ||
418 | + | ||
419 | + | ||
420 | + /** | ||
421 | + * Collection of Description of a Device and it's Ports given from a Provider. | ||
422 | + */ | ||
423 | + private static class DeviceDescriptions { | ||
424 | + // private final DeviceId id; | ||
425 | + // private final ProviderId pid; | ||
426 | + | ||
427 | + private final AtomicReference<DeviceDescription> deviceDesc; | ||
428 | + private final ConcurrentMap<PortNumber, PortDescription> portDescs; | ||
429 | + | ||
430 | + public DeviceDescriptions(DeviceDescription desc) { | ||
431 | + this.deviceDesc = new AtomicReference<>(desc); | ||
432 | + this.portDescs = new ConcurrentHashMap<>(); | ||
433 | + } | ||
434 | + | ||
435 | + public DeviceDescription getDeviceDesc() { | ||
436 | + return deviceDesc.get(); | ||
437 | + } | ||
438 | + | ||
439 | + public PortDescription getPortDesc(PortNumber number) { | ||
440 | + return portDescs.get(number); | ||
441 | + } | ||
442 | + | ||
443 | + public Collection<PortDescription> getPortDescs() { | ||
444 | + return Collections.unmodifiableCollection(portDescs.values()); | ||
445 | + } | ||
446 | + | ||
447 | + public DeviceDescription putDeviceDesc(DeviceDescription newDesc) { | ||
448 | + return deviceDesc.getAndSet(newDesc); | ||
449 | + } | ||
450 | + | ||
451 | + public PortDescription putPortDesc(PortNumber number, PortDescription newDesc) { | ||
452 | + return portDescs.put(number, newDesc); | ||
453 | + } | ||
454 | + } | ||
455 | +} |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED; | 3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED; |
4 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | 4 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | ... | ... |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED; | 3 | import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED; |
4 | import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED; | 4 | import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED; | ... | ... |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import static org.slf4j.LoggerFactory.getLogger; | 3 | import static org.slf4j.LoggerFactory.getLogger; |
4 | 4 | ||
... | @@ -7,8 +7,6 @@ import java.util.HashMap; | ... | @@ -7,8 +7,6 @@ import java.util.HashMap; |
7 | import java.util.HashSet; | 7 | import java.util.HashSet; |
8 | import java.util.Map; | 8 | import java.util.Map; |
9 | import java.util.Set; | 9 | import java.util.Set; |
10 | -import java.util.concurrent.ConcurrentHashMap; | ||
11 | -import java.util.concurrent.ConcurrentMap; | ||
12 | import java.util.concurrent.atomic.AtomicInteger; | 10 | import java.util.concurrent.atomic.AtomicInteger; |
13 | 11 | ||
14 | import org.apache.felix.scr.annotations.Activate; | 12 | import org.apache.felix.scr.annotations.Activate; |
... | @@ -48,8 +46,10 @@ public class SimpleMastershipStore | ... | @@ -48,8 +46,10 @@ public class SimpleMastershipStore |
48 | new DefaultControllerNode(new NodeId("local"), LOCALHOST); | 46 | new DefaultControllerNode(new NodeId("local"), LOCALHOST); |
49 | 47 | ||
50 | //devices mapped to their masters, to emulate multiple nodes | 48 | //devices mapped to their masters, to emulate multiple nodes |
51 | - protected final ConcurrentMap<DeviceId, NodeId> masterMap = | 49 | + protected final Map<DeviceId, NodeId> masterMap = new HashMap<>(); |
52 | - new ConcurrentHashMap<>(); | 50 | + //emulate backups with pile of nodes |
51 | + protected final Set<NodeId> backups = new HashSet<>(); | ||
52 | + //terms | ||
53 | protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>(); | 53 | protected final Map<DeviceId, AtomicInteger> termMap = new HashMap<>(); |
54 | 54 | ||
55 | @Activate | 55 | @Activate |
... | @@ -64,26 +64,30 @@ public class SimpleMastershipStore | ... | @@ -64,26 +64,30 @@ public class SimpleMastershipStore |
64 | 64 | ||
65 | @Override | 65 | @Override |
66 | public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { | 66 | public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { |
67 | + MastershipRole role = getRole(nodeId, deviceId); | ||
67 | 68 | ||
68 | - NodeId node = masterMap.get(deviceId); | ||
69 | - if (node == null) { | ||
70 | synchronized (this) { | 69 | synchronized (this) { |
70 | + switch (role) { | ||
71 | + case MASTER: | ||
72 | + return null; | ||
73 | + case STANDBY: | ||
74 | + masterMap.put(deviceId, nodeId); | ||
75 | + termMap.get(deviceId).incrementAndGet(); | ||
76 | + backups.add(nodeId); | ||
77 | + break; | ||
78 | + case NONE: | ||
71 | masterMap.put(deviceId, nodeId); | 79 | masterMap.put(deviceId, nodeId); |
72 | termMap.put(deviceId, new AtomicInteger()); | 80 | termMap.put(deviceId, new AtomicInteger()); |
81 | + backups.add(nodeId); | ||
82 | + break; | ||
83 | + default: | ||
84 | + log.warn("unknown Mastership Role {}", role); | ||
85 | + return null; | ||
73 | } | 86 | } |
74 | - return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); | ||
75 | } | 87 | } |
76 | 88 | ||
77 | - if (node.equals(nodeId)) { | ||
78 | - return null; | ||
79 | - } else { | ||
80 | - synchronized (this) { | ||
81 | - masterMap.put(deviceId, nodeId); | ||
82 | - termMap.get(deviceId).incrementAndGet(); | ||
83 | return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); | 89 | return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId); |
84 | } | 90 | } |
85 | - } | ||
86 | - } | ||
87 | 91 | ||
88 | @Override | 92 | @Override |
89 | public NodeId getMaster(DeviceId deviceId) { | 93 | public NodeId getMaster(DeviceId deviceId) { |
... | @@ -103,34 +107,111 @@ public class SimpleMastershipStore | ... | @@ -103,34 +107,111 @@ public class SimpleMastershipStore |
103 | 107 | ||
104 | @Override | 108 | @Override |
105 | public MastershipRole requestRole(DeviceId deviceId) { | 109 | public MastershipRole requestRole(DeviceId deviceId) { |
106 | - return getRole(instance.id(), deviceId); | 110 | + //query+possible reelection |
111 | + NodeId node = instance.id(); | ||
112 | + MastershipRole role = getRole(node, deviceId); | ||
113 | + | ||
114 | + switch (role) { | ||
115 | + case MASTER: | ||
116 | + break; | ||
117 | + case STANDBY: | ||
118 | + synchronized (this) { | ||
119 | + //try to "re-elect", since we're really not distributed | ||
120 | + NodeId rel = reelect(node); | ||
121 | + if (rel == null) { | ||
122 | + masterMap.put(deviceId, node); | ||
123 | + termMap.put(deviceId, new AtomicInteger()); | ||
124 | + role = MastershipRole.MASTER; | ||
125 | + } | ||
126 | + backups.add(node); | ||
127 | + } | ||
128 | + break; | ||
129 | + case NONE: | ||
130 | + //first to get to it, say we are master | ||
131 | + synchronized (this) { | ||
132 | + masterMap.put(deviceId, node); | ||
133 | + termMap.put(deviceId, new AtomicInteger()); | ||
134 | + backups.add(node); | ||
135 | + role = MastershipRole.MASTER; | ||
136 | + } | ||
137 | + break; | ||
138 | + default: | ||
139 | + log.warn("unknown Mastership Role {}", role); | ||
140 | + } | ||
141 | + return role; | ||
107 | } | 142 | } |
108 | 143 | ||
109 | @Override | 144 | @Override |
110 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { | 145 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { |
111 | - NodeId node = masterMap.get(deviceId); | 146 | + //just query |
147 | + NodeId current = masterMap.get(deviceId); | ||
112 | MastershipRole role; | 148 | MastershipRole role; |
113 | - if (node != null) { | 149 | + |
114 | - if (node.equals(nodeId)) { | 150 | + if (current == null) { |
115 | - role = MastershipRole.MASTER; | 151 | + if (backups.contains(nodeId)) { |
116 | - } else { | ||
117 | role = MastershipRole.STANDBY; | 152 | role = MastershipRole.STANDBY; |
153 | + } else { | ||
154 | + role = MastershipRole.NONE; | ||
118 | } | 155 | } |
119 | } else { | 156 | } else { |
120 | - //masterMap doesn't contain it. | 157 | + if (current.equals(nodeId)) { |
121 | role = MastershipRole.MASTER; | 158 | role = MastershipRole.MASTER; |
122 | - masterMap.put(deviceId, nodeId); | 159 | + } else { |
160 | + role = MastershipRole.STANDBY; | ||
161 | + } | ||
123 | } | 162 | } |
124 | return role; | 163 | return role; |
125 | } | 164 | } |
126 | 165 | ||
127 | @Override | 166 | @Override |
128 | public MastershipTerm getTermFor(DeviceId deviceId) { | 167 | public MastershipTerm getTermFor(DeviceId deviceId) { |
129 | - if (masterMap.get(deviceId) == null) { | 168 | + if ((masterMap.get(deviceId) == null) || |
169 | + (termMap.get(deviceId) == null)) { | ||
130 | return null; | 170 | return null; |
131 | } | 171 | } |
132 | return MastershipTerm.of( | 172 | return MastershipTerm.of( |
133 | masterMap.get(deviceId), termMap.get(deviceId).get()); | 173 | masterMap.get(deviceId), termMap.get(deviceId).get()); |
134 | } | 174 | } |
135 | 175 | ||
176 | + @Override | ||
177 | + public MastershipEvent unsetMaster(NodeId nodeId, DeviceId deviceId) { | ||
178 | + MastershipRole role = getRole(nodeId, deviceId); | ||
179 | + synchronized (this) { | ||
180 | + switch (role) { | ||
181 | + case MASTER: | ||
182 | + NodeId backup = reelect(nodeId); | ||
183 | + if (backup == null) { | ||
184 | + masterMap.remove(deviceId); | ||
185 | + } else { | ||
186 | + masterMap.put(deviceId, backup); | ||
187 | + termMap.get(deviceId).incrementAndGet(); | ||
188 | + return new MastershipEvent(MASTER_CHANGED, deviceId, backup); | ||
189 | + } | ||
190 | + case STANDBY: | ||
191 | + case NONE: | ||
192 | + if (!termMap.containsKey(deviceId)) { | ||
193 | + termMap.put(deviceId, new AtomicInteger()); | ||
194 | + } | ||
195 | + backups.add(nodeId); | ||
196 | + break; | ||
197 | + default: | ||
198 | + log.warn("unknown Mastership Role {}", role); | ||
199 | + } | ||
200 | + } | ||
201 | + return null; | ||
202 | + } | ||
203 | + | ||
204 | + //dumbly selects next-available node that's not the current one | ||
205 | + //emulate leader election | ||
206 | + private NodeId reelect(NodeId nodeId) { | ||
207 | + NodeId backup = null; | ||
208 | + for (NodeId n : backups) { | ||
209 | + if (!n.equals(nodeId)) { | ||
210 | + backup = n; | ||
211 | + break; | ||
212 | + } | ||
213 | + } | ||
214 | + return backup; | ||
215 | + } | ||
216 | + | ||
136 | } | 217 | } | ... | ... |
1 | -package org.onlab.onos.net.trivial.impl; | 1 | +package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | import org.apache.felix.scr.annotations.Activate; | 3 | import org.apache.felix.scr.annotations.Activate; |
4 | import org.apache.felix.scr.annotations.Component; | 4 | import org.apache.felix.scr.annotations.Component; | ... | ... |
... | @@ -2,4 +2,4 @@ | ... | @@ -2,4 +2,4 @@ |
2 | * Implementations of in-memory stores suitable for unit testing and | 2 | * Implementations of in-memory stores suitable for unit testing and |
3 | * experimentation; not for production use. | 3 | * experimentation; not for production use. |
4 | */ | 4 | */ |
5 | -package org.onlab.onos.net.trivial.impl; | 5 | +package org.onlab.onos.store.trivial.impl; | ... | ... |
1 | /** | 1 | /** |
2 | * | 2 | * |
3 | */ | 3 | */ |
4 | -package org.onlab.onos.net.trivial.impl; | 4 | +package org.onlab.onos.store.trivial.impl; |
5 | 5 | ||
6 | import static org.junit.Assert.*; | 6 | import static org.junit.Assert.*; |
7 | import static org.onlab.onos.net.Device.Type.SWITCH; | 7 | import static org.onlab.onos.net.Device.Type.SWITCH; |
... | @@ -44,6 +44,7 @@ import com.google.common.collect.Sets; | ... | @@ -44,6 +44,7 @@ import com.google.common.collect.Sets; |
44 | public class SimpleDeviceStoreTest { | 44 | public class SimpleDeviceStoreTest { |
45 | 45 | ||
46 | private static final ProviderId PID = new ProviderId("of", "foo"); | 46 | private static final ProviderId PID = new ProviderId("of", "foo"); |
47 | + private static final ProviderId PIDA = new ProviderId("of", "bar", true); | ||
47 | private static final DeviceId DID1 = deviceId("of:foo"); | 48 | private static final DeviceId DID1 = deviceId("of:foo"); |
48 | private static final DeviceId DID2 = deviceId("of:bar"); | 49 | private static final DeviceId DID2 = deviceId("of:bar"); |
49 | private static final String MFR = "whitebox"; | 50 | private static final String MFR = "whitebox"; |
... | @@ -89,6 +90,13 @@ public class SimpleDeviceStoreTest { | ... | @@ -89,6 +90,13 @@ public class SimpleDeviceStoreTest { |
89 | deviceStore.createOrUpdateDevice(PID, deviceId, description); | 90 | deviceStore.createOrUpdateDevice(PID, deviceId, description); |
90 | } | 91 | } |
91 | 92 | ||
93 | + private void putDeviceAncillary(DeviceId deviceId, String swVersion) { | ||
94 | + DeviceDescription description = | ||
95 | + new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, | ||
96 | + HW, swVersion, SN); | ||
97 | + deviceStore.createOrUpdateDevice(PIDA, deviceId, description); | ||
98 | + } | ||
99 | + | ||
92 | private static void assertDevice(DeviceId id, String swVersion, Device device) { | 100 | private static void assertDevice(DeviceId id, String swVersion, Device device) { |
93 | assertNotNull(device); | 101 | assertNotNull(device); |
94 | assertEquals(id, device.id()); | 102 | assertEquals(id, device.id()); |
... | @@ -160,6 +168,33 @@ public class SimpleDeviceStoreTest { | ... | @@ -160,6 +168,33 @@ public class SimpleDeviceStoreTest { |
160 | } | 168 | } |
161 | 169 | ||
162 | @Test | 170 | @Test |
171 | + public final void testCreateOrUpdateDeviceAncillary() { | ||
172 | + DeviceDescription description = | ||
173 | + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | ||
174 | + HW, SW1, SN); | ||
175 | + DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description); | ||
176 | + assertEquals(DEVICE_ADDED, event.type()); | ||
177 | + assertDevice(DID1, SW1, event.subject()); | ||
178 | + assertEquals(PIDA, event.subject().providerId()); | ||
179 | + assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1)); | ||
180 | + | ||
181 | + DeviceDescription description2 = | ||
182 | + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, | ||
183 | + HW, SW2, SN); | ||
184 | + DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); | ||
185 | + assertEquals(DEVICE_UPDATED, event2.type()); | ||
186 | + assertDevice(DID1, SW2, event2.subject()); | ||
187 | + assertEquals(PID, event2.subject().providerId()); | ||
188 | + assertTrue(deviceStore.isAvailable(DID1)); | ||
189 | + | ||
190 | + assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); | ||
191 | + | ||
192 | + // For now, Ancillary is ignored once primary appears | ||
193 | + assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description)); | ||
194 | + } | ||
195 | + | ||
196 | + | ||
197 | + @Test | ||
163 | public final void testMarkOffline() { | 198 | public final void testMarkOffline() { |
164 | 199 | ||
165 | putDevice(DID1, SW1); | 200 | putDevice(DID1, SW1); |
... | @@ -182,7 +217,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -182,7 +217,7 @@ public class SimpleDeviceStoreTest { |
182 | new DefaultPortDescription(P2, true) | 217 | new DefaultPortDescription(P2, true) |
183 | ); | 218 | ); |
184 | 219 | ||
185 | - List<DeviceEvent> events = deviceStore.updatePorts(DID1, pds); | 220 | + List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds); |
186 | 221 | ||
187 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | 222 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
188 | for (DeviceEvent event : events) { | 223 | for (DeviceEvent event : events) { |
... | @@ -201,7 +236,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -201,7 +236,7 @@ public class SimpleDeviceStoreTest { |
201 | new DefaultPortDescription(P3, true) | 236 | new DefaultPortDescription(P3, true) |
202 | ); | 237 | ); |
203 | 238 | ||
204 | - events = deviceStore.updatePorts(DID1, pds2); | 239 | + events = deviceStore.updatePorts(PID, DID1, pds2); |
205 | assertFalse("event should be triggered", events.isEmpty()); | 240 | assertFalse("event should be triggered", events.isEmpty()); |
206 | for (DeviceEvent event : events) { | 241 | for (DeviceEvent event : events) { |
207 | PortNumber num = event.port().number(); | 242 | PortNumber num = event.port().number(); |
... | @@ -224,7 +259,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -224,7 +259,7 @@ public class SimpleDeviceStoreTest { |
224 | new DefaultPortDescription(P1, false), | 259 | new DefaultPortDescription(P1, false), |
225 | new DefaultPortDescription(P2, true) | 260 | new DefaultPortDescription(P2, true) |
226 | ); | 261 | ); |
227 | - events = deviceStore.updatePorts(DID1, pds3); | 262 | + events = deviceStore.updatePorts(PID, DID1, pds3); |
228 | assertFalse("event should be triggered", events.isEmpty()); | 263 | assertFalse("event should be triggered", events.isEmpty()); |
229 | for (DeviceEvent event : events) { | 264 | for (DeviceEvent event : events) { |
230 | PortNumber num = event.port().number(); | 265 | PortNumber num = event.port().number(); |
... | @@ -249,14 +284,42 @@ public class SimpleDeviceStoreTest { | ... | @@ -249,14 +284,42 @@ public class SimpleDeviceStoreTest { |
249 | List<PortDescription> pds = Arrays.<PortDescription>asList( | 284 | List<PortDescription> pds = Arrays.<PortDescription>asList( |
250 | new DefaultPortDescription(P1, true) | 285 | new DefaultPortDescription(P1, true) |
251 | ); | 286 | ); |
252 | - deviceStore.updatePorts(DID1, pds); | 287 | + deviceStore.updatePorts(PID, DID1, pds); |
288 | + | ||
289 | + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, | ||
290 | + new DefaultPortDescription(P1, false)); | ||
291 | + assertEquals(PORT_UPDATED, event.type()); | ||
292 | + assertDevice(DID1, SW1, event.subject()); | ||
293 | + assertEquals(P1, event.port().number()); | ||
294 | + assertFalse("Port is disabled", event.port().isEnabled()); | ||
295 | + | ||
296 | + } | ||
297 | + @Test | ||
298 | + public final void testUpdatePortStatusAncillary() { | ||
299 | + putDeviceAncillary(DID1, SW1); | ||
300 | + putDevice(DID1, SW1); | ||
301 | + List<PortDescription> pds = Arrays.<PortDescription>asList( | ||
302 | + new DefaultPortDescription(P1, true) | ||
303 | + ); | ||
304 | + deviceStore.updatePorts(PID, DID1, pds); | ||
253 | 305 | ||
254 | - DeviceEvent event = deviceStore.updatePortStatus(DID1, | 306 | + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, |
255 | new DefaultPortDescription(P1, false)); | 307 | new DefaultPortDescription(P1, false)); |
256 | assertEquals(PORT_UPDATED, event.type()); | 308 | assertEquals(PORT_UPDATED, event.type()); |
257 | assertDevice(DID1, SW1, event.subject()); | 309 | assertDevice(DID1, SW1, event.subject()); |
258 | assertEquals(P1, event.port().number()); | 310 | assertEquals(P1, event.port().number()); |
259 | assertFalse("Port is disabled", event.port().isEnabled()); | 311 | assertFalse("Port is disabled", event.port().isEnabled()); |
312 | + | ||
313 | + DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, | ||
314 | + new DefaultPortDescription(P1, true)); | ||
315 | + assertNull("Ancillary is ignored if primary exists", event2); | ||
316 | + | ||
317 | + DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, | ||
318 | + new DefaultPortDescription(P2, true)); | ||
319 | + assertEquals(PORT_ADDED, event3.type()); | ||
320 | + assertDevice(DID1, SW1, event3.subject()); | ||
321 | + assertEquals(P2, event3.port().number()); | ||
322 | + assertFalse("Port is disabled if not given from provider", event3.port().isEnabled()); | ||
260 | } | 323 | } |
261 | 324 | ||
262 | @Test | 325 | @Test |
... | @@ -267,7 +330,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -267,7 +330,7 @@ public class SimpleDeviceStoreTest { |
267 | new DefaultPortDescription(P1, true), | 330 | new DefaultPortDescription(P1, true), |
268 | new DefaultPortDescription(P2, true) | 331 | new DefaultPortDescription(P2, true) |
269 | ); | 332 | ); |
270 | - deviceStore.updatePorts(DID1, pds); | 333 | + deviceStore.updatePorts(PID, DID1, pds); |
271 | 334 | ||
272 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); | 335 | Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2); |
273 | List<Port> ports = deviceStore.getPorts(DID1); | 336 | List<Port> ports = deviceStore.getPorts(DID1); |
... | @@ -290,7 +353,7 @@ public class SimpleDeviceStoreTest { | ... | @@ -290,7 +353,7 @@ public class SimpleDeviceStoreTest { |
290 | new DefaultPortDescription(P1, true), | 353 | new DefaultPortDescription(P1, true), |
291 | new DefaultPortDescription(P2, false) | 354 | new DefaultPortDescription(P2, false) |
292 | ); | 355 | ); |
293 | - deviceStore.updatePorts(DID1, pds); | 356 | + deviceStore.updatePorts(PID, DID1, pds); |
294 | 357 | ||
295 | Port port1 = deviceStore.getPort(DID1, P1); | 358 | Port port1 = deviceStore.getPort(DID1, P1); |
296 | assertEquals(P1, port1.number()); | 359 | assertEquals(P1, port1.number()); | ... | ... |
core/store/trivial/src/test/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStoreTest.java
0 → 100644
1 | +package org.onlab.onos.store.trivial.impl; | ||
2 | + | ||
3 | +import java.util.Set; | ||
4 | +import java.util.concurrent.atomic.AtomicInteger; | ||
5 | + | ||
6 | +import org.junit.After; | ||
7 | +import org.junit.Before; | ||
8 | +import org.junit.Test; | ||
9 | +import org.onlab.onos.cluster.MastershipTerm; | ||
10 | +import org.onlab.onos.cluster.NodeId; | ||
11 | +import org.onlab.onos.net.DeviceId; | ||
12 | + | ||
13 | +import com.google.common.collect.Sets; | ||
14 | + | ||
15 | +import static org.junit.Assert.assertEquals; | ||
16 | +import static org.junit.Assert.assertNull; | ||
17 | +import static org.junit.Assert.assertTrue; | ||
18 | +import static org.onlab.onos.net.MastershipRole.*; | ||
19 | +import static org.onlab.onos.cluster.MastershipEvent.Type.*; | ||
20 | + | ||
21 | +/** | ||
22 | + * Test for the simple MastershipStore implementation. | ||
23 | + */ | ||
24 | +public class SimpleMastershipStoreTest { | ||
25 | + | ||
26 | + private static final DeviceId DID1 = DeviceId.deviceId("of:01"); | ||
27 | + private static final DeviceId DID2 = DeviceId.deviceId("of:02"); | ||
28 | + private static final DeviceId DID3 = DeviceId.deviceId("of:03"); | ||
29 | + private static final DeviceId DID4 = DeviceId.deviceId("of:04"); | ||
30 | + | ||
31 | + private static final NodeId N1 = new NodeId("local"); | ||
32 | + private static final NodeId N2 = new NodeId("other"); | ||
33 | + | ||
34 | + private SimpleMastershipStore sms; | ||
35 | + | ||
36 | + @Before | ||
37 | + public void setUp() throws Exception { | ||
38 | + sms = new SimpleMastershipStore(); | ||
39 | + sms.activate(); | ||
40 | + } | ||
41 | + | ||
42 | + @After | ||
43 | + public void tearDown() throws Exception { | ||
44 | + sms.deactivate(); | ||
45 | + } | ||
46 | + | ||
47 | + @Test | ||
48 | + public void getRole() { | ||
49 | + //special case, no backup or master | ||
50 | + put(DID1, N1, false, false); | ||
51 | + assertEquals("wrong role", NONE, sms.getRole(N1, DID1)); | ||
52 | + | ||
53 | + //backup exists but we aren't mapped | ||
54 | + put(DID2, N1, false, true); | ||
55 | + assertEquals("wrong role", STANDBY, sms.getRole(N1, DID2)); | ||
56 | + | ||
57 | + //N2 is master | ||
58 | + put(DID3, N2, true, true); | ||
59 | + assertEquals("wrong role", MASTER, sms.getRole(N2, DID3)); | ||
60 | + | ||
61 | + //N2 is master but N1 is only in backups set | ||
62 | + put(DID4, N2, true, false); | ||
63 | + assertEquals("wrong role", STANDBY, sms.getRole(N1, DID4)); | ||
64 | + } | ||
65 | + | ||
66 | + @Test | ||
67 | + public void getMaster() { | ||
68 | + put(DID3, N2, true, true); | ||
69 | + assertEquals("wrong role", MASTER, sms.getRole(N2, DID3)); | ||
70 | + assertEquals("wrong device", N2, sms.getMaster(DID3)); | ||
71 | + } | ||
72 | + | ||
73 | + @Test | ||
74 | + public void setMaster() { | ||
75 | + put(DID1, N1, false, false); | ||
76 | + assertEquals("wrong event", MASTER_CHANGED, sms.setMaster(N1, DID1).type()); | ||
77 | + assertEquals("wrong role", MASTER, sms.getRole(N1, DID1)); | ||
78 | + //set node that's already master - should be ignored | ||
79 | + assertNull("wrong event", sms.setMaster(N1, DID1)); | ||
80 | + | ||
81 | + //set STANDBY to MASTER | ||
82 | + put(DID2, N1, false, true); | ||
83 | + assertEquals("wrong role", STANDBY, sms.getRole(N1, DID2)); | ||
84 | + assertEquals("wrong event", MASTER_CHANGED, sms.setMaster(N1, DID2).type()); | ||
85 | + assertEquals("wrong role", MASTER, sms.getRole(N1, DID2)); | ||
86 | + } | ||
87 | + | ||
88 | + @Test | ||
89 | + public void getDevices() { | ||
90 | + Set<DeviceId> d = Sets.newHashSet(DID1, DID2); | ||
91 | + | ||
92 | + put(DID1, N2, true, true); | ||
93 | + put(DID2, N2, true, true); | ||
94 | + put(DID3, N1, true, true); | ||
95 | + assertTrue("wrong devices", d.equals(sms.getDevices(N2))); | ||
96 | + } | ||
97 | + | ||
98 | + @Test | ||
99 | + public void getTermFor() { | ||
100 | + put(DID1, N1, true, true); | ||
101 | + assertEquals("wrong term", MastershipTerm.of(N1, 0), sms.getTermFor(DID1)); | ||
102 | + | ||
103 | + //switch to N2 and back - 2 term switches | ||
104 | + sms.setMaster(N2, DID1); | ||
105 | + sms.setMaster(N1, DID1); | ||
106 | + assertEquals("wrong term", MastershipTerm.of(N1, 2), sms.getTermFor(DID1)); | ||
107 | + } | ||
108 | + | ||
109 | + @Test | ||
110 | + public void requestRole() { | ||
111 | + //NONE - become MASTER | ||
112 | + put(DID1, N1, false, false); | ||
113 | + assertEquals("wrong role", MASTER, sms.requestRole(DID1)); | ||
114 | + | ||
115 | + //STANDBY without backup - become MASTER | ||
116 | + put(DID2, N1, false, true); | ||
117 | + assertEquals("wrong role", MASTER, sms.requestRole(DID2)); | ||
118 | + | ||
119 | + //STANDBY with backup - stay STANDBY | ||
120 | + put(DID3, N2, false, true); | ||
121 | + assertEquals("wrong role", STANDBY, sms.requestRole(DID3)); | ||
122 | + | ||
123 | + //local (N1) is MASTER - stay MASTER | ||
124 | + put(DID4, N1, true, true); | ||
125 | + assertEquals("wrong role", MASTER, sms.requestRole(DID4)); | ||
126 | + } | ||
127 | + | ||
128 | + @Test | ||
129 | + public void unsetMaster() { | ||
130 | + //NONE - record backup but take no other action | ||
131 | + put(DID1, N1, false, false); | ||
132 | + sms.unsetMaster(N1, DID1); | ||
133 | + assertTrue("not backed up", sms.backups.contains(N1)); | ||
134 | + sms.termMap.clear(); | ||
135 | + sms.unsetMaster(N1, DID1); | ||
136 | + assertTrue("term not set", sms.termMap.containsKey(DID1)); | ||
137 | + | ||
138 | + //no backup, MASTER | ||
139 | + put(DID1, N1, true, true); | ||
140 | + assertNull("wrong event", sms.unsetMaster(N1, DID1)); | ||
141 | + assertNull("wrong node", sms.masterMap.get(DID1)); | ||
142 | + | ||
143 | + //backup, switch | ||
144 | + sms.masterMap.clear(); | ||
145 | + put(DID1, N1, true, true); | ||
146 | + put(DID2, N2, true, true); | ||
147 | + assertEquals("wrong event", MASTER_CHANGED, sms.unsetMaster(N1, DID1).type()); | ||
148 | + } | ||
149 | + | ||
150 | + //helper to populate master/backup structures | ||
151 | + private void put(DeviceId dev, NodeId node, boolean store, boolean backup) { | ||
152 | + if (store) { | ||
153 | + sms.masterMap.put(dev, node); | ||
154 | + } | ||
155 | + if (backup) { | ||
156 | + sms.backups.add(node); | ||
157 | + } | ||
158 | + sms.termMap.put(dev, new AtomicInteger()); | ||
159 | + } | ||
160 | +} |
... | @@ -11,6 +11,7 @@ | ... | @@ -11,6 +11,7 @@ |
11 | <bundle>mvn:io.netty/netty/3.9.2.Final</bundle> | 11 | <bundle>mvn:io.netty/netty/3.9.2.Final</bundle> |
12 | 12 | ||
13 | <bundle>mvn:com.hazelcast/hazelcast/3.3</bundle> | 13 | <bundle>mvn:com.hazelcast/hazelcast/3.3</bundle> |
14 | + <bundle>mvn:com.codahale.metrics/metrics-core/3.0.2</bundle> | ||
14 | <bundle>mvn:com.eclipsesource.minimal-json/minimal-json/0.9.1</bundle> | 15 | <bundle>mvn:com.eclipsesource.minimal-json/minimal-json/0.9.1</bundle> |
15 | 16 | ||
16 | <bundle>mvn:com.esotericsoftware.kryo/kryo/2.24.0</bundle> | 17 | <bundle>mvn:com.esotericsoftware.kryo/kryo/2.24.0</bundle> | ... | ... |
... | @@ -48,7 +48,7 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext | ... | @@ -48,7 +48,7 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext |
48 | OFPacketOut.Builder builder = sw.factory().buildPacketOut(); | 48 | OFPacketOut.Builder builder = sw.factory().buildPacketOut(); |
49 | OFAction act = buildOutput(outPort.getPortNumber()); | 49 | OFAction act = buildOutput(outPort.getPortNumber()); |
50 | pktout = builder.setXid(pktin.getXid()) | 50 | pktout = builder.setXid(pktin.getXid()) |
51 | - .setInPort(pktin.getInPort()) | 51 | + .setInPort(inport()) |
52 | .setBufferId(pktin.getBufferId()) | 52 | .setBufferId(pktin.getBufferId()) |
53 | .setActions(Collections.singletonList(act)) | 53 | .setActions(Collections.singletonList(act)) |
54 | .build(); | 54 | .build(); |
... | @@ -63,7 +63,7 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext | ... | @@ -63,7 +63,7 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext |
63 | OFAction act = buildOutput(outPort.getPortNumber()); | 63 | OFAction act = buildOutput(outPort.getPortNumber()); |
64 | pktout = builder.setXid(pktin.getXid()) | 64 | pktout = builder.setXid(pktin.getXid()) |
65 | .setBufferId(OFBufferId.NO_BUFFER) | 65 | .setBufferId(OFBufferId.NO_BUFFER) |
66 | - .setInPort(pktin.getInPort()) | 66 | + .setInPort(inport()) |
67 | .setActions(Collections.singletonList(act)) | 67 | .setActions(Collections.singletonList(act)) |
68 | .setData(ethFrame.serialize()) | 68 | .setData(ethFrame.serialize()) |
69 | .build(); | 69 | .build(); |
... | @@ -88,10 +88,16 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext | ... | @@ -88,10 +88,16 @@ public final class DefaultOpenFlowPacketContext implements OpenFlowPacketContext |
88 | 88 | ||
89 | @Override | 89 | @Override |
90 | public Integer inPort() { | 90 | public Integer inPort() { |
91 | + return inport().getPortNumber(); | ||
92 | + } | ||
93 | + | ||
94 | + | ||
95 | + private OFPort inport() { | ||
96 | + //FIXME: this has to change in fucking loxi | ||
91 | try { | 97 | try { |
92 | - return pktin.getInPort().getPortNumber(); | 98 | + return pktin.getInPort(); |
93 | } catch (UnsupportedOperationException e) { | 99 | } catch (UnsupportedOperationException e) { |
94 | - return pktin.getMatch().get(MatchField.IN_PORT).getPortNumber(); | 100 | + return pktin.getMatch().get(MatchField.IN_PORT); |
95 | } | 101 | } |
96 | } | 102 | } |
97 | 103 | ... | ... |
... | @@ -243,6 +243,8 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver { | ... | @@ -243,6 +243,8 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver { |
243 | if (role == RoleState.SLAVE || role == RoleState.EQUAL) { | 243 | if (role == RoleState.SLAVE || role == RoleState.EQUAL) { |
244 | this.role = role; | 244 | this.role = role; |
245 | } | 245 | } |
246 | + } else { | ||
247 | + this.role = role; | ||
246 | } | 248 | } |
247 | } catch (IOException e) { | 249 | } catch (IOException e) { |
248 | log.error("Unable to write to switch {}.", this.dpid); | 250 | log.error("Unable to write to switch {}.", this.dpid); | ... | ... |
... | @@ -651,7 +651,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { | ... | @@ -651,7 +651,7 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { |
651 | * @param error The error message | 651 | * @param error The error message |
652 | */ | 652 | */ |
653 | protected void logError(OFChannelHandler h, OFErrorMsg error) { | 653 | protected void logError(OFChannelHandler h, OFErrorMsg error) { |
654 | - log.error("{} from switch {} in state {}", | 654 | + log.info("{} from switch {} in state {}", |
655 | new Object[] { | 655 | new Object[] { |
656 | error, | 656 | error, |
657 | h.getSwitchInfoString(), | 657 | h.getSwitchInfoString(), | ... | ... |
... | @@ -6,6 +6,7 @@ import java.util.Collections; | ... | @@ -6,6 +6,7 @@ import java.util.Collections; |
6 | import java.util.List; | 6 | import java.util.List; |
7 | 7 | ||
8 | import org.onlab.onos.openflow.controller.Dpid; | 8 | import org.onlab.onos.openflow.controller.Dpid; |
9 | +import org.onlab.onos.openflow.controller.RoleState; | ||
9 | import org.onlab.onos.openflow.controller.driver.AbstractOpenFlowSwitch; | 10 | import org.onlab.onos.openflow.controller.driver.AbstractOpenFlowSwitch; |
10 | import org.onlab.onos.openflow.controller.driver.OpenFlowSwitchDriver; | 11 | import org.onlab.onos.openflow.controller.driver.OpenFlowSwitchDriver; |
11 | import org.onlab.onos.openflow.controller.driver.OpenFlowSwitchDriverFactory; | 12 | import org.onlab.onos.openflow.controller.driver.OpenFlowSwitchDriverFactory; |
... | @@ -61,6 +62,11 @@ public final class DriverManager implements OpenFlowSwitchDriverFactory { | ... | @@ -61,6 +62,11 @@ public final class DriverManager implements OpenFlowSwitchDriverFactory { |
61 | return new AbstractOpenFlowSwitch(dpid, desc) { | 62 | return new AbstractOpenFlowSwitch(dpid, desc) { |
62 | 63 | ||
63 | @Override | 64 | @Override |
65 | + public void setRole(RoleState state) { | ||
66 | + this.role = RoleState.MASTER; | ||
67 | + } | ||
68 | + | ||
69 | + @Override | ||
64 | public void write(List<OFMessage> msgs) { | 70 | public void write(List<OFMessage> msgs) { |
65 | channel.write(msgs); | 71 | channel.write(msgs); |
66 | } | 72 | } | ... | ... |
... | @@ -425,7 +425,7 @@ | ... | @@ -425,7 +425,7 @@ |
425 | <group> | 425 | <group> |
426 | <title>Core Subsystems</title> | 426 | <title>Core Subsystems</title> |
427 | <packages> | 427 | <packages> |
428 | - 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.net.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.* | 428 | + 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.* |
429 | </packages> | 429 | </packages> |
430 | </group> | 430 | </group> |
431 | <group> | 431 | <group> | ... | ... |
... | @@ -73,10 +73,11 @@ public class FlowModBuilder { | ... | @@ -73,10 +73,11 @@ public class FlowModBuilder { |
73 | List<OFAction> actions = buildActions(); | 73 | List<OFAction> actions = buildActions(); |
74 | 74 | ||
75 | //TODO: what to do without bufferid? do we assume that there will be a pktout as well? | 75 | //TODO: what to do without bufferid? do we assume that there will be a pktout as well? |
76 | - OFFlowMod fm = factory.buildFlowModify() | 76 | + OFFlowMod fm = factory.buildFlowAdd() |
77 | .setCookie(U64.of(cookie.value())) | 77 | .setCookie(U64.of(cookie.value())) |
78 | .setBufferId(OFBufferId.NO_BUFFER) | 78 | .setBufferId(OFBufferId.NO_BUFFER) |
79 | .setActions(actions) | 79 | .setActions(actions) |
80 | + .setIdleTimeout(10) | ||
80 | .setMatch(match) | 81 | .setMatch(match) |
81 | .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) | 82 | .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) |
82 | .setPriority(priority) | 83 | .setPriority(priority) |
... | @@ -93,7 +94,7 @@ public class FlowModBuilder { | ... | @@ -93,7 +94,7 @@ public class FlowModBuilder { |
93 | OFFlowMod fm = factory.buildFlowDelete() | 94 | OFFlowMod fm = factory.buildFlowDelete() |
94 | .setCookie(U64.of(cookie.value())) | 95 | .setCookie(U64.of(cookie.value())) |
95 | .setBufferId(OFBufferId.NO_BUFFER) | 96 | .setBufferId(OFBufferId.NO_BUFFER) |
96 | - //.setActions(actions) | 97 | + .setActions(actions) |
97 | .setMatch(match) | 98 | .setMatch(match) |
98 | .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) | 99 | .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) |
99 | .setPriority(priority) | 100 | .setPriority(priority) | ... | ... |
... | @@ -18,6 +18,7 @@ import org.onlab.packet.IpPrefix; | ... | @@ -18,6 +18,7 @@ import org.onlab.packet.IpPrefix; |
18 | import org.onlab.packet.MacAddress; | 18 | import org.onlab.packet.MacAddress; |
19 | import org.onlab.packet.VlanId; | 19 | import org.onlab.packet.VlanId; |
20 | import org.projectfloodlight.openflow.protocol.OFFlowRemoved; | 20 | import org.projectfloodlight.openflow.protocol.OFFlowRemoved; |
21 | +import org.projectfloodlight.openflow.protocol.OFFlowRemovedReason; | ||
21 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; | 22 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; |
22 | import org.projectfloodlight.openflow.protocol.action.OFAction; | 23 | import org.projectfloodlight.openflow.protocol.action.OFAction; |
23 | import org.projectfloodlight.openflow.protocol.action.OFActionOutput; | 24 | import org.projectfloodlight.openflow.protocol.action.OFActionOutput; |
... | @@ -70,14 +71,15 @@ public class FlowRuleBuilder { | ... | @@ -70,14 +71,15 @@ public class FlowRuleBuilder { |
70 | buildSelector(), buildTreatment(), stat.getPriority(), | 71 | buildSelector(), buildTreatment(), stat.getPriority(), |
71 | FlowRuleState.ADDED, stat.getDurationNsec() / 1000000, | 72 | FlowRuleState.ADDED, stat.getDurationNsec() / 1000000, |
72 | stat.getPacketCount().getValue(), stat.getByteCount().getValue(), | 73 | stat.getPacketCount().getValue(), stat.getByteCount().getValue(), |
73 | - stat.getCookie().getValue()); | 74 | + stat.getCookie().getValue(), false); |
74 | } else { | 75 | } else { |
75 | // TODO: revisit potentially. | 76 | // TODO: revisit potentially. |
76 | return new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), | 77 | return new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), |
77 | buildSelector(), null, removed.getPriority(), | 78 | buildSelector(), null, removed.getPriority(), |
78 | FlowRuleState.REMOVED, removed.getDurationNsec() / 1000000, | 79 | FlowRuleState.REMOVED, removed.getDurationNsec() / 1000000, |
79 | removed.getPacketCount().getValue(), removed.getByteCount().getValue(), | 80 | removed.getPacketCount().getValue(), removed.getByteCount().getValue(), |
80 | - removed.getCookie().getValue()); | 81 | + removed.getCookie().getValue(), |
82 | + removed.getReason() == OFFlowRemovedReason.IDLE_TIMEOUT.ordinal()); | ||
81 | } | 83 | } |
82 | } | 84 | } |
83 | 85 | ... | ... |
providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
... | @@ -158,7 +158,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -158,7 +158,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
158 | case BARRIER_REPLY: | 158 | case BARRIER_REPLY: |
159 | case ERROR: | 159 | case ERROR: |
160 | default: | 160 | default: |
161 | - log.warn("Unhandled message type: {}", msg.getType()); | 161 | + log.debug("Unhandled message type: {}", msg.getType()); |
162 | } | 162 | } |
163 | 163 | ||
164 | } | 164 | } | ... | ... |
... | @@ -131,7 +131,7 @@ public class LinkDiscovery implements TimerTask { | ... | @@ -131,7 +131,7 @@ public class LinkDiscovery implements TimerTask { |
131 | } | 131 | } |
132 | timeout = Timer.getTimer().newTimeout(this, 0, | 132 | timeout = Timer.getTimer().newTimeout(this, 0, |
133 | TimeUnit.MILLISECONDS); | 133 | TimeUnit.MILLISECONDS); |
134 | - this.log.debug("Started discovery manager for switch {}", | 134 | + this.log.info("Started discovery manager for switch {}", |
135 | sw.getId()); | 135 | sw.getId()); |
136 | 136 | ||
137 | } | 137 | } | ... | ... |
1 | package org.onlab.onos.provider.of.packet.impl; | 1 | package org.onlab.onos.provider.of.packet.impl; |
2 | 2 | ||
3 | -import static org.onlab.onos.openflow.controller.RoleState.SLAVE; | ||
4 | import static org.slf4j.LoggerFactory.getLogger; | 3 | import static org.slf4j.LoggerFactory.getLogger; |
5 | 4 | ||
6 | import java.nio.ByteBuffer; | 5 | import java.nio.ByteBuffer; |
... | @@ -95,9 +94,6 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr | ... | @@ -95,9 +94,6 @@ public class OpenFlowPacketProvider extends AbstractProvider implements PacketPr |
95 | if (sw == null) { | 94 | if (sw == null) { |
96 | log.warn("Device {} isn't available?", devId); | 95 | log.warn("Device {} isn't available?", devId); |
97 | return; | 96 | return; |
98 | - } else if (sw.getRole().equals(SLAVE)) { | ||
99 | - log.warn("Can't write to Device {} as slave", devId); | ||
100 | - return; | ||
101 | } | 97 | } |
102 | 98 | ||
103 | Ethernet eth = new Ethernet(); | 99 | Ethernet eth = new Ethernet(); | ... | ... |
... | @@ -140,12 +140,12 @@ public class OpenFlowPacketProviderTest { | ... | @@ -140,12 +140,12 @@ public class OpenFlowPacketProviderTest { |
140 | sw.sent.clear(); | 140 | sw.sent.clear(); |
141 | 141 | ||
142 | //wrong Role | 142 | //wrong Role |
143 | - sw.setRole(RoleState.SLAVE); | 143 | + //sw.setRole(RoleState.SLAVE); |
144 | - provider.emit(passPkt); | 144 | + //provider.emit(passPkt); |
145 | - assertEquals("invalid switch", sw, controller.current); | 145 | + //assertEquals("invalid switch", sw, controller.current); |
146 | - assertEquals("message sent incorrectly", 0, sw.sent.size()); | 146 | + //assertEquals("message sent incorrectly", 0, sw.sent.size()); |
147 | 147 | ||
148 | - sw.setRole(RoleState.MASTER); | 148 | + //sw.setRole(RoleState.MASTER); |
149 | 149 | ||
150 | //missing switch | 150 | //missing switch |
151 | OutboundPacket swFailPkt = outPacket(DID_MISSING, TR, eth); | 151 | OutboundPacket swFailPkt = outPacket(DID_MISSING, TR, eth); | ... | ... |
... | @@ -34,6 +34,8 @@ cp -r $ONOS_ROOT/tools/package/etc/* $KARAF_DIST/etc | ... | @@ -34,6 +34,8 @@ cp -r $ONOS_ROOT/tools/package/etc/* $KARAF_DIST/etc |
34 | mkdir -p $KARAF_DIST/system/org/onlab | 34 | mkdir -p $KARAF_DIST/system/org/onlab |
35 | cp -r $M2_REPO/org/onlab $KARAF_DIST/system/org/ | 35 | cp -r $M2_REPO/org/onlab $KARAF_DIST/system/org/ |
36 | 36 | ||
37 | +export ONOS_FEATURES="${ONOS_FEATURES:-webconsole,onos-api,onos-core,onos-cli,onos-rest,onos-gui,onos-openflow,onos-app-fwd,onos-app-foo}" | ||
38 | + | ||
37 | # Cellar Patching -------------------------------------------------------------- | 39 | # Cellar Patching -------------------------------------------------------------- |
38 | 40 | ||
39 | # Patch the Apache Karaf distribution file to add Cellar features repository | 41 | # Patch the Apache Karaf distribution file to add Cellar features repository |
... | @@ -51,7 +53,7 @@ perl -pi.old -e "s|^(featuresRepositories=.*)|\1,mvn:org.onlab.onos/onos-feature | ... | @@ -51,7 +53,7 @@ perl -pi.old -e "s|^(featuresRepositories=.*)|\1,mvn:org.onlab.onos/onos-feature |
51 | $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg | 53 | $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg |
52 | 54 | ||
53 | # Patch the Apache Karaf distribution file to load ONOS features | 55 | # Patch the Apache Karaf distribution file to load ONOS features |
54 | -perl -pi.old -e 's|^(featuresBoot=.*)|\1,webconsole,onos-api,onos-core,onos-cli,onos-rest,onos-gui,onos-openflow,onos-app-fwd,onos-app-foo|' \ | 56 | +perl -pi.old -e "s|^(featuresBoot=.*)|\1,$ONOS_FEATURES|" \ |
55 | $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg | 57 | $ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg |
56 | 58 | ||
57 | # Patch the Apache Karaf distribution with ONOS branding bundle | 59 | # Patch the Apache Karaf distribution with ONOS branding bundle | ... | ... |
... | @@ -9,5 +9,10 @@ | ... | @@ -9,5 +9,10 @@ |
9 | nodes=$(env | sort | egrep "OC[0-9]+" | cut -d= -f2) | 9 | nodes=$(env | sort | egrep "OC[0-9]+" | cut -d= -f2) |
10 | 10 | ||
11 | onos-package | 11 | onos-package |
12 | -for node in $nodes; do (printf "%s: %s\n" "$node" "`onos-install -f $node`")& done | 12 | +for node in $nodes; do onos-install -f $node 1>/dev/null & done |
13 | + | ||
14 | +# Wait for shutdown before waiting for restart | ||
15 | +sleep 3 | ||
16 | + | ||
13 | for node in $nodes; do onos-wait-for-start $node; done | 17 | for node in $nodes; do onos-wait-for-start $node; done |
18 | +for node in $nodes; do onos-check-logs $node; done | ... | ... |
... | @@ -6,22 +6,21 @@ | ... | @@ -6,22 +6,21 @@ |
6 | export ONOS_ROOT=${ONOS_ROOT:-~/onos-next} | 6 | export ONOS_ROOT=${ONOS_ROOT:-~/onos-next} |
7 | 7 | ||
8 | # Setup some environmental context for developers | 8 | # Setup some environmental context for developers |
9 | -export JAVA_HOME=$(/usr/libexec/java_home) | 9 | +export JAVA_HOME=$(/usr/libexec/java_home -v 1.7) |
10 | export MAVEN=${MAVEN:-~/Applications/apache-maven-3.2.2} | 10 | export MAVEN=${MAVEN:-~/Applications/apache-maven-3.2.2} |
11 | export KARAF=${KARAF:-~/Applications/apache-karaf-3.0.1} | 11 | export KARAF=${KARAF:-~/Applications/apache-karaf-3.0.1} |
12 | export KARAF_LOG=$KARAF/data/log/karaf.log | 12 | export KARAF_LOG=$KARAF/data/log/karaf.log |
13 | 13 | ||
14 | # Setup a path | 14 | # Setup a path |
15 | -export PS=":" | 15 | +export PATH="$PATH:$ONOS_ROOT/tools/dev/bin:$ONOS_ROOT/tools/test/bin" |
16 | -export PATH="$PATH:$ONOS_ROOT/tools/dev:$ONOS_ROOT/tools/build" | 16 | +export PATH="$PATH:$ONOS_ROOT/tools/build" |
17 | -export PATH="$PATH:$ONOS_ROOT/tools/test/bin" | ||
18 | export PATH="$PATH:$MAVEN/bin:$KARAF/bin" | 17 | export PATH="$PATH:$MAVEN/bin:$KARAF/bin" |
19 | export PATH="$PATH:." | 18 | export PATH="$PATH:." |
20 | 19 | ||
21 | # Convenience utility to warp to various ONOS source projects | 20 | # Convenience utility to warp to various ONOS source projects |
22 | # e.g. 'o api', 'o dev', 'o' | 21 | # e.g. 'o api', 'o dev', 'o' |
23 | function o { | 22 | function o { |
24 | - cd $(find $ONOS_ROOT/ -type d | egrep -v '\.git|target|src' | \ | 23 | + cd $(find $ONOS_ROOT/ -type d | egrep -v '\.git|target' | \ |
25 | egrep "${1:-$ONOS_ROOT}" | head -n 1) | 24 | egrep "${1:-$ONOS_ROOT}" | head -n 1) |
26 | } | 25 | } |
27 | 26 | ||
... | @@ -30,11 +29,12 @@ alias mci='mvn clean install' | ... | @@ -30,11 +29,12 @@ alias mci='mvn clean install' |
30 | 29 | ||
31 | # Short-hand for ONOS build, package and test. | 30 | # Short-hand for ONOS build, package and test. |
32 | alias ob='onos-build' | 31 | alias ob='onos-build' |
32 | +alias obs='onos-build-selective' | ||
33 | alias op='onos-package' | 33 | alias op='onos-package' |
34 | alias ot='onos-test' | 34 | alias ot='onos-test' |
35 | 35 | ||
36 | # Short-hand for tailing the ONOS (karaf) log | 36 | # Short-hand for tailing the ONOS (karaf) log |
37 | -alias tl='$ONOS_ROOT/tools/dev/watchLog' | 37 | +alias tl='$ONOS_ROOT/tools/dev/bin/onos-local-log' |
38 | alias tlo='tl | grep --colour=always org.onlab' | 38 | alias tlo='tl | grep --colour=always org.onlab' |
39 | 39 | ||
40 | # Pretty-print JSON output | 40 | # Pretty-print JSON output |
... | @@ -57,6 +57,7 @@ function cell { | ... | @@ -57,6 +57,7 @@ function cell { |
57 | if [ -n "$1" ]; then | 57 | if [ -n "$1" ]; then |
58 | [ ! -f $ONOS_ROOT/tools/test/cells/$1 ] && \ | 58 | [ ! -f $ONOS_ROOT/tools/test/cells/$1 ] && \ |
59 | echo "No such cell: $1" >&2 && return 1 | 59 | echo "No such cell: $1" >&2 && return 1 |
60 | + unset OC1 OC2 OC3 OC4 OC5 OC6 OC7 OC8 OC9 OCN OCI | ||
60 | . $ONOS_ROOT/tools/test/cells/$1 | 61 | . $ONOS_ROOT/tools/test/cells/$1 |
61 | export OCI=$OC1 | 62 | export OCI=$OC1 |
62 | export ONOS_CELL=$1 | 63 | export ONOS_CELL=$1 |
... | @@ -66,6 +67,7 @@ function cell { | ... | @@ -66,6 +67,7 @@ function cell { |
66 | env | egrep "OCI" | 67 | env | egrep "OCI" |
67 | env | egrep "OC[0-9]+" | sort | 68 | env | egrep "OC[0-9]+" | sort |
68 | env | egrep "OCN" | 69 | env | egrep "OCN" |
70 | + env | egrep "ONOS_" | egrep -v 'ONOS_ROOT|ONOS_CELL' | ||
69 | fi | 71 | fi |
70 | } | 72 | } |
71 | 73 | ||
... | @@ -73,7 +75,11 @@ cell local >/dev/null # Default cell is the local VMs | ... | @@ -73,7 +75,11 @@ cell local >/dev/null # Default cell is the local VMs |
73 | 75 | ||
74 | # Lists available cells | 76 | # Lists available cells |
75 | function cells { | 77 | function cells { |
76 | - ls -1 $ONOS_ROOT/tools/test/cells | 78 | + for cell in $(ls -1 $ONOS_ROOT/tools/test/cells); do |
79 | + printf "%-12s %s\n" \ | ||
80 | + "$([ $cell = $ONOS_CELL ] && echo $cell '*' || echo $cell)" \ | ||
81 | + "$(grep '^#' $ONOS_ROOT/tools/test/cells/$cell | head -n 1)" | ||
82 | + done | ||
77 | } | 83 | } |
78 | 84 | ||
79 | # Miscellaneous | 85 | # Miscellaneous | ... | ... |
tools/dev/bin/onos-build-selective
0 → 100755
1 | +#!/bin/bash | ||
2 | +#------------------------------------------------------------------------------ | ||
3 | +# Selectively builds only those projects that contained modified Java files. | ||
4 | +#------------------------------------------------------------------------------ | ||
5 | + | ||
6 | +projects=$(find $ONOS_ROOT -name '*.java' \ | ||
7 | + -not -path '*/openflowj/*' -and -not -path '.git/*' \ | ||
8 | + -exec $ONOS_ROOT/tools/dev/bin/onos-build-selective-hook {} \; | \ | ||
9 | + sort -u | sed "s:$ONOS_ROOT::g" | tr '\n' ',' | \ | ||
10 | + sed 's:/,:,:g;s:,/:,:g;s:^/::g;s:,$::g') | ||
11 | + | ||
12 | +[ -n "$projects" ] && cd $ONOS_ROOT && mvn --projects $projects ${@:-clean install} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
tools/dev/bin/onos-build-selective-hook
0 → 100755
1 | +#------------------------------------------------------------------------------ | ||
2 | +# Echoes project-level directory if a Java file within is newer than its | ||
3 | +# class file counterpart | ||
4 | +#------------------------------------------------------------------------------ | ||
5 | + | ||
6 | +javaFile=${1#*\/src\/*\/java/} | ||
7 | +basename=${1/*\//} | ||
8 | + | ||
9 | +[ $basename = "package-info.java" ] && exit 0 | ||
10 | + | ||
11 | +src=${1/$javaFile/} | ||
12 | +project=${src/src*/} | ||
13 | +classFile=${javaFile/.java/.class} | ||
14 | + | ||
15 | +[ ${project}target/classes/$classFile -nt ${src}$javaFile -o \ | ||
16 | + ${project}target/test-classes/$classFile -nt ${src}$javaFile ] \ | ||
17 | + || echo ${src/src*/} | ||
18 | + |
tools/test/cells/.reset
deleted
100644 → 0
1 | -unset OC1 OC2 OC3 OC4 OC5 OC6 OC7 OC8 OC9 OCN ONOS_NIC |
1 | -# Default virtual box ONOS instances 1,2 & ONOS mininet box | 1 | +# Local VirtualBox-based ONOS instances 1,2 & ONOS mininet box |
2 | -. $ONOS_ROOT/tools/test/cells/.reset | ||
3 | 2 | ||
4 | export ONOS_NIC=192.168.56.* | 3 | export ONOS_NIC=192.168.56.* |
5 | - | ||
6 | export OC1="192.168.56.101" | 4 | export OC1="192.168.56.101" |
7 | export OC2="192.168.56.102" | 5 | export OC2="192.168.56.102" |
8 | 6 | ... | ... |
tools/test/cells/office
0 → 100644
1 | # ProxMox-based cell of ONOS instances 1,2 & ONOS mininet box | 1 | # ProxMox-based cell of ONOS instances 1,2 & ONOS mininet box |
2 | -. $ONOS_ROOT/tools/test/cells/.reset | ||
3 | 2 | ||
4 | export ONOS_NIC="10.1.9.*" | 3 | export ONOS_NIC="10.1.9.*" |
5 | - | ||
6 | export OC1="10.1.9.94" | 4 | export OC1="10.1.9.94" |
7 | export OC2="10.1.9.82" | 5 | export OC2="10.1.9.82" |
8 | 6 | ... | ... |
tools/test/cells/single
0 → 100644
tools/test/cells/tom
deleted
100644 → 0
tools/test/cells/triple
0 → 100644
... | @@ -55,6 +55,11 @@ | ... | @@ -55,6 +55,11 @@ |
55 | <groupId>org.objenesis</groupId> | 55 | <groupId>org.objenesis</groupId> |
56 | <artifactId>objenesis</artifactId> | 56 | <artifactId>objenesis</artifactId> |
57 | </dependency> | 57 | </dependency> |
58 | + <dependency> | ||
59 | + <groupId>com.codahale.metrics</groupId> | ||
60 | + <artifactId>metrics-core</artifactId> | ||
61 | + <version>3.0.2</version> | ||
62 | + </dependency> | ||
58 | </dependencies> | 63 | </dependencies> |
59 | 64 | ||
60 | </project> | 65 | </project> | ... | ... |
1 | +package org.onlab.metrics; | ||
2 | + | ||
3 | +import java.util.concurrent.ConcurrentHashMap; | ||
4 | +import java.util.concurrent.ConcurrentMap; | ||
5 | + | ||
6 | +/** | ||
7 | + * Components to register for metrics. | ||
8 | + */ | ||
9 | +public class MetricsComponent implements MetricsComponentRegistry { | ||
10 | + private final String name; | ||
11 | + | ||
12 | + /** | ||
13 | + * Registry to hold the Features defined in this Component. | ||
14 | + */ | ||
15 | + private final ConcurrentMap<String, MetricsFeature> featuresRegistry = | ||
16 | + new ConcurrentHashMap<>(); | ||
17 | + | ||
18 | + /** | ||
19 | + * Constructs a component from a name. | ||
20 | + * | ||
21 | + * @param newName name of the component | ||
22 | + */ | ||
23 | + MetricsComponent(final String newName) { | ||
24 | + name = newName; | ||
25 | + } | ||
26 | + | ||
27 | + @Override public String getName() { | ||
28 | + return name; | ||
29 | + } | ||
30 | + | ||
31 | + @Override public MetricsFeature registerFeature(final String featureName) { | ||
32 | + MetricsFeature feature = featuresRegistry.get(featureName); | ||
33 | + if (feature == null) { | ||
34 | + final MetricsFeature createdFeature = new MetricsFeature(featureName); | ||
35 | + feature = featuresRegistry.putIfAbsent(featureName, createdFeature); | ||
36 | + if (feature == null) { | ||
37 | + feature = createdFeature; | ||
38 | + } | ||
39 | + } | ||
40 | + return feature; | ||
41 | + } | ||
42 | +} |
1 | +package org.onlab.metrics; | ||
2 | + | ||
3 | +/** | ||
4 | + * Features to tag metrics. | ||
5 | + */ | ||
6 | +public class MetricsFeature { | ||
7 | + private final String name; | ||
8 | + | ||
9 | + /** | ||
10 | + * Constructs a Feature from a name. | ||
11 | + * | ||
12 | + * @param newName name of the Feature | ||
13 | + */ | ||
14 | + MetricsFeature(final String newName) { | ||
15 | + name = newName; | ||
16 | + } | ||
17 | + | ||
18 | + public String getName() { | ||
19 | + return name; | ||
20 | + } | ||
21 | +} |
1 | +package org.onlab.metrics; | ||
2 | + | ||
3 | +import java.util.Map; | ||
4 | +import java.util.concurrent.ConcurrentHashMap; | ||
5 | +import java.util.concurrent.ConcurrentMap; | ||
6 | + | ||
7 | +import com.codahale.metrics.Counter; | ||
8 | +import com.codahale.metrics.Gauge; | ||
9 | +import com.codahale.metrics.Histogram; | ||
10 | +import com.codahale.metrics.Meter; | ||
11 | +import com.codahale.metrics.Metric; | ||
12 | +import com.codahale.metrics.MetricFilter; | ||
13 | +import com.codahale.metrics.MetricRegistry; | ||
14 | +import com.codahale.metrics.Timer; | ||
15 | + | ||
16 | +/** | ||
17 | + * This class holds the Metrics registry for ONOS. | ||
18 | + * All metrics (Counter, Histogram, Timer, Meter, Gauge) use a hierarchical | ||
19 | + * string-based naming scheme: COMPONENT.FEATURE.NAME. | ||
20 | + * Example: "Topology.Counters.TopologyUpdates". | ||
21 | + * The COMPONENT and FEATURE names have to be registered in advance before | ||
22 | + * a metric can be created. Example: | ||
23 | + * <pre> | ||
24 | + * <code> | ||
25 | + * private final MetricsManager.MetricsComponent COMPONENT = | ||
26 | + * MetricsManager.registerComponent("Topology"); | ||
27 | + * private final MetricsManager.MetricsFeature FEATURE = | ||
28 | + * COMPONENT.registerFeature("Counters"); | ||
29 | + * private final Counter counterTopologyUpdates = | ||
30 | + * MetricsManager.createCounter(COMPONENT, FEATURE, "TopologyUpdates"); | ||
31 | + * </code> | ||
32 | + * </pre> | ||
33 | + * Gauges are slightly different because they are not created directly in | ||
34 | + * this class, but are allocated by the caller and passed in for registration: | ||
35 | + * <pre> | ||
36 | + * <code> | ||
37 | + * private final Gauge<Long> gauge = | ||
38 | + * new {@literal Gauge<Long>}() { | ||
39 | + * {@literal @}Override | ||
40 | + * public Long getValue() { | ||
41 | + * return gaugeValue; | ||
42 | + * } | ||
43 | + * }; | ||
44 | + * MetricsManager.registerMetric(COMPONENT, FEATURE, GAUGE_NAME, gauge); | ||
45 | + * </code> | ||
46 | + * </pre> | ||
47 | + */ | ||
48 | +public final class MetricsManager implements MetricsService { | ||
49 | + | ||
50 | + /** | ||
51 | + * Registry to hold the Components defined in the system. | ||
52 | + */ | ||
53 | + private ConcurrentMap<String, MetricsComponent> componentsRegistry = | ||
54 | + new ConcurrentHashMap<>(); | ||
55 | + | ||
56 | + /** | ||
57 | + * Registry for the Metrics objects created in the system. | ||
58 | + */ | ||
59 | + private final MetricRegistry metricsRegistry = new MetricRegistry(); | ||
60 | + | ||
61 | + /** | ||
62 | + * Hide constructor. The only way to get the registry is through the | ||
63 | + * singleton getter. | ||
64 | + */ | ||
65 | + private MetricsManager() {} | ||
66 | + | ||
67 | + /** | ||
68 | + * Registers a component. | ||
69 | + * | ||
70 | + * @param name name of the Component to register | ||
71 | + * @return MetricsComponent object that can be used to create Metrics. | ||
72 | + */ | ||
73 | + @Override | ||
74 | + public MetricsComponent registerComponent(final String name) { | ||
75 | + MetricsComponent component = componentsRegistry.get(name); | ||
76 | + if (component == null) { | ||
77 | + final MetricsComponent createdComponent = new MetricsComponent(name); | ||
78 | + component = componentsRegistry.putIfAbsent(name, createdComponent); | ||
79 | + if (component == null) { | ||
80 | + component = createdComponent; | ||
81 | + } | ||
82 | + } | ||
83 | + return component; | ||
84 | + } | ||
85 | + | ||
86 | + /** | ||
87 | + * Generates a name for a Metric from its component and feature. | ||
88 | + * | ||
89 | + * @param component component the metric is defined in | ||
90 | + * @param feature feature the metric is defined in | ||
91 | + * @param metricName local name of the metric | ||
92 | + * | ||
93 | + * @return full name of the metric | ||
94 | + */ | ||
95 | + private String generateName(final MetricsComponent component, | ||
96 | + final MetricsFeature feature, | ||
97 | + final String metricName) { | ||
98 | + return MetricRegistry.name(component.getName(), | ||
99 | + feature.getName(), | ||
100 | + metricName); | ||
101 | + } | ||
102 | + | ||
103 | + /** | ||
104 | + * Creates a Counter metric. | ||
105 | + * | ||
106 | + * @param component component the Counter is defined in | ||
107 | + * @param feature feature the Counter is defined in | ||
108 | + * @param metricName local name of the metric | ||
109 | + * @return the created Counter Meteric | ||
110 | + */ | ||
111 | + @Override | ||
112 | + public Counter createCounter(final MetricsComponent component, | ||
113 | + final MetricsFeature feature, | ||
114 | + final String metricName) { | ||
115 | + final String name = generateName(component, feature, metricName); | ||
116 | + return metricsRegistry.counter(name); | ||
117 | + } | ||
118 | + | ||
119 | + /** | ||
120 | + * Creates a Histogram metric. | ||
121 | + * | ||
122 | + * @param component component the Histogram is defined in | ||
123 | + * @param feature feature the Histogram is defined in | ||
124 | + * @param metricName local name of the metric | ||
125 | + * @return the created Histogram Metric | ||
126 | + */ | ||
127 | + @Override | ||
128 | + public Histogram createHistogram(final MetricsComponent component, | ||
129 | + final MetricsFeature feature, | ||
130 | + final String metricName) { | ||
131 | + final String name = generateName(component, feature, metricName); | ||
132 | + return metricsRegistry.histogram(name); | ||
133 | + } | ||
134 | + | ||
135 | + /** | ||
136 | + * Creates a Timer metric. | ||
137 | + * | ||
138 | + * @param component component the Timer is defined in | ||
139 | + * @param feature feature the Timeer is defined in | ||
140 | + * @param metricName local name of the metric | ||
141 | + * @return the created Timer Metric | ||
142 | + */ | ||
143 | + @Override | ||
144 | + public Timer createTimer(final MetricsComponent component, | ||
145 | + final MetricsFeature feature, | ||
146 | + final String metricName) { | ||
147 | + final String name = generateName(component, feature, metricName); | ||
148 | + return metricsRegistry.timer(name); | ||
149 | + } | ||
150 | + | ||
151 | + /** | ||
152 | + * Creates a Meter metric. | ||
153 | + * | ||
154 | + * @param component component the Meter is defined in | ||
155 | + * @param feature feature the Meter is defined in | ||
156 | + * @param metricName local name of the metric | ||
157 | + * @return the created Meter Metric | ||
158 | + */ | ||
159 | + @Override | ||
160 | + public Meter createMeter(final MetricsComponent component, | ||
161 | + final MetricsFeature feature, | ||
162 | + final String metricName) { | ||
163 | + final String name = generateName(component, feature, metricName); | ||
164 | + return metricsRegistry.meter(name); | ||
165 | + } | ||
166 | + | ||
167 | + /** | ||
168 | + * Registers an already created Metric. This is used for situation where a | ||
169 | + * caller needs to allocate its own Metric, but still register it with the | ||
170 | + * system. | ||
171 | + * | ||
172 | + * @param <T> Metric type | ||
173 | + * @param component component the Metric is defined in | ||
174 | + * @param feature feature the Metric is defined in | ||
175 | + * @param metricName local name of the metric | ||
176 | + * @param metric Metric to register | ||
177 | + * @return the registered Metric | ||
178 | + */ | ||
179 | + @Override | ||
180 | + public <T extends Metric> T registerMetric( | ||
181 | + final MetricsComponent component, | ||
182 | + final MetricsFeature feature, | ||
183 | + final String metricName, | ||
184 | + final T metric) { | ||
185 | + final String name = generateName(component, feature, metricName); | ||
186 | + metricsRegistry.register(name, metric); | ||
187 | + return metric; | ||
188 | + } | ||
189 | + | ||
190 | + /** | ||
191 | + * Fetches the existing Timers. | ||
192 | + * | ||
193 | + * @param filter filter to use to select Timers | ||
194 | + * @return a map of the Timers that match the filter, with the key as the | ||
195 | + * name String to the Timer. | ||
196 | + */ | ||
197 | + @Override | ||
198 | + public Map<String, Timer> getTimers(final MetricFilter filter) { | ||
199 | + return metricsRegistry.getTimers(filter); | ||
200 | + } | ||
201 | + | ||
202 | + /** | ||
203 | + * Fetches the existing Gauges. | ||
204 | + * | ||
205 | + * @param filter filter to use to select Gauges | ||
206 | + * @return a map of the Gauges that match the filter, with the key as the | ||
207 | + * name String to the Gauge. | ||
208 | + */ | ||
209 | + @Override | ||
210 | + public Map<String, Gauge> getGauges(final MetricFilter filter) { | ||
211 | + return metricsRegistry.getGauges(filter); | ||
212 | + } | ||
213 | + | ||
214 | + /** | ||
215 | + * Fetches the existing Counters. | ||
216 | + * | ||
217 | + * @param filter filter to use to select Counters | ||
218 | + * @return a map of the Counters that match the filter, with the key as the | ||
219 | + * name String to the Counter. | ||
220 | + */ | ||
221 | + @Override | ||
222 | + public Map<String, Counter> getCounters(final MetricFilter filter) { | ||
223 | + return metricsRegistry.getCounters(filter); | ||
224 | + } | ||
225 | + | ||
226 | + /** | ||
227 | + * Fetches the existing Meters. | ||
228 | + * | ||
229 | + * @param filter filter to use to select Meters | ||
230 | + * @return a map of the Meters that match the filter, with the key as the | ||
231 | + * name String to the Meter. | ||
232 | + */ | ||
233 | + @Override | ||
234 | + public Map<String, Meter> getMeters(final MetricFilter filter) { | ||
235 | + return metricsRegistry.getMeters(filter); | ||
236 | + } | ||
237 | + | ||
238 | + /** | ||
239 | + * Fetches the existing Histograms. | ||
240 | + * | ||
241 | + * @param filter filter to use to select Histograms | ||
242 | + * @return a map of the Histograms that match the filter, with the key as the | ||
243 | + * name String to the Histogram. | ||
244 | + */ | ||
245 | + @Override | ||
246 | + public Map<String, Histogram> getHistograms(final MetricFilter filter) { | ||
247 | + return metricsRegistry.getHistograms(filter); | ||
248 | + } | ||
249 | + | ||
250 | + /** | ||
251 | + * Removes all Metrics that match a given filter. | ||
252 | + * | ||
253 | + * @param filter filter to use to select the Metrics to remove. | ||
254 | + */ | ||
255 | + @Override | ||
256 | + public void removeMatching(final MetricFilter filter) { | ||
257 | + metricsRegistry.removeMatching(filter); | ||
258 | + } | ||
259 | +} | ||
260 | + |
1 | +package org.onlab.metrics; | ||
2 | + | ||
3 | +import java.util.Map; | ||
4 | + | ||
5 | +import com.codahale.metrics.Counter; | ||
6 | +import com.codahale.metrics.Gauge; | ||
7 | +import com.codahale.metrics.Histogram; | ||
8 | +import com.codahale.metrics.Meter; | ||
9 | +import com.codahale.metrics.Metric; | ||
10 | +import com.codahale.metrics.MetricFilter; | ||
11 | +import com.codahale.metrics.Timer; | ||
12 | + | ||
13 | +/** | ||
14 | + * Metrics Service to collect metrics. | ||
15 | + */ | ||
16 | +interface MetricsService { | ||
17 | + | ||
18 | + /** | ||
19 | + * Registers a component. | ||
20 | + * | ||
21 | + * @param name name of the Component to register | ||
22 | + * @return MetricsComponent object that can be used to create Metrics. | ||
23 | + */ | ||
24 | + MetricsComponent registerComponent(String name); | ||
25 | + | ||
26 | + /** | ||
27 | + * Creates a Counter metric. | ||
28 | + * | ||
29 | + * @param component component the Counter is defined in | ||
30 | + * @param feature feature the Counter is defined in | ||
31 | + * @param metricName local name of the metric | ||
32 | + * @return the created Counter Meteric | ||
33 | + */ | ||
34 | + Counter createCounter(MetricsComponent component, | ||
35 | + MetricsFeature feature, | ||
36 | + String metricName); | ||
37 | + | ||
38 | + /** | ||
39 | + * Creates a Histogram metric. | ||
40 | + * | ||
41 | + * @param component component the Histogram is defined in | ||
42 | + * @param feature feature the Histogram is defined in | ||
43 | + * @param metricName local name of the metric | ||
44 | + * @return the created Histogram Metric | ||
45 | + */ | ||
46 | + Histogram createHistogram(MetricsComponent component, | ||
47 | + MetricsFeature feature, | ||
48 | + String metricName); | ||
49 | + | ||
50 | + /** | ||
51 | + * Creates a Timer metric. | ||
52 | + * | ||
53 | + * @param component component the Timer is defined in | ||
54 | + * @param feature feature the Timer is defined in | ||
55 | + * @param metricName local name of the metric | ||
56 | + * @return the created Timer Metric | ||
57 | + */ | ||
58 | + Timer createTimer(MetricsComponent component, | ||
59 | + MetricsFeature feature, | ||
60 | + String metricName); | ||
61 | + | ||
62 | + /** | ||
63 | + * Creates a Meter metric. | ||
64 | + * | ||
65 | + * @param component component the Meter is defined in | ||
66 | + * @param feature feature the Meter is defined in | ||
67 | + * @param metricName local name of the metric | ||
68 | + * @return the created Meter Metric | ||
69 | + */ | ||
70 | + Meter createMeter(MetricsComponent component, | ||
71 | + MetricsFeature feature, | ||
72 | + String metricName); | ||
73 | + | ||
74 | + /** | ||
75 | + * Registers an already created Metric. This is used for situation where a | ||
76 | + * caller needs to allocate its own Metric, but still register it with the | ||
77 | + * system. | ||
78 | + * | ||
79 | + * @param <T> Metric type | ||
80 | + * @param component component the Metric is defined in | ||
81 | + * @param feature feature the Metric is defined in | ||
82 | + * @param metricName local name of the metric | ||
83 | + * @param metric Metric to register | ||
84 | + * @return the registered Metric | ||
85 | + */ | ||
86 | + <T extends Metric> T registerMetric( | ||
87 | + MetricsComponent component, | ||
88 | + MetricsFeature feature, | ||
89 | + String metricName, | ||
90 | + T metric); | ||
91 | + | ||
92 | + /** | ||
93 | + * Fetches the existing Timers. | ||
94 | + * | ||
95 | + * @param filter filter to use to select Timers | ||
96 | + * @return a map of the Timers that match the filter, with the key as the | ||
97 | + * name String to the Timer. | ||
98 | + */ | ||
99 | + Map<String, Timer> getTimers(MetricFilter filter); | ||
100 | + | ||
101 | + /** | ||
102 | + * Fetches the existing Gauges. | ||
103 | + * | ||
104 | + * @param filter filter to use to select Gauges | ||
105 | + * @return a map of the Gauges that match the filter, with the key as the | ||
106 | + * name String to the Gauge. | ||
107 | + */ | ||
108 | + Map<String, Gauge> getGauges(MetricFilter filter); | ||
109 | + | ||
110 | + /** | ||
111 | + * Fetches the existing Counters. | ||
112 | + * | ||
113 | + * @param filter filter to use to select Counters | ||
114 | + * @return a map of the Counters that match the filter, with the key as the | ||
115 | + * name String to the Counter. | ||
116 | + */ | ||
117 | + Map<String, Counter> getCounters(MetricFilter filter); | ||
118 | + | ||
119 | + /** | ||
120 | + * Fetches the existing Meters. | ||
121 | + * | ||
122 | + * @param filter filter to use to select Meters | ||
123 | + * @return a map of the Meters that match the filter, with the key as the | ||
124 | + * name String to the Meter. | ||
125 | + */ | ||
126 | + Map<String, Meter> getMeters(MetricFilter filter); | ||
127 | + | ||
128 | + /** | ||
129 | + * Fetches the existing Histograms. | ||
130 | + * | ||
131 | + * @param filter filter to use to select Histograms | ||
132 | + * @return a map of the Histograms that match the filter, with the key as the | ||
133 | + * name String to the Histogram. | ||
134 | + */ | ||
135 | + Map<String, Histogram> getHistograms(MetricFilter filter); | ||
136 | + /** | ||
137 | + * Removes all Metrics that match a given filter. | ||
138 | + * | ||
139 | + * @param filter filter to use to select the Metrics to remove. | ||
140 | + */ | ||
141 | + void removeMatching(MetricFilter filter); | ||
142 | + | ||
143 | +} |
... | @@ -180,6 +180,15 @@ public final class IpPrefix { | ... | @@ -180,6 +180,15 @@ public final class IpPrefix { |
180 | return address; | 180 | return address; |
181 | } | 181 | } |
182 | 182 | ||
183 | + public int toRealInt() { | ||
184 | + int val = 0; | ||
185 | + for (int i = 0; i < octets.length; i++) { | ||
186 | + val <<= 8; | ||
187 | + val |= octets[i] & 0xff; | ||
188 | + } | ||
189 | + return val; | ||
190 | + } | ||
191 | + | ||
183 | /** | 192 | /** |
184 | * Helper for computing the mask value from CIDR. | 193 | * Helper for computing the mask value from CIDR. |
185 | * | 194 | * | ... | ... |
... | @@ -239,12 +239,41 @@ public final class KryoPool { | ... | @@ -239,12 +239,41 @@ public final class KryoPool { |
239 | Kryo kryo = new Kryo(); | 239 | Kryo kryo = new Kryo(); |
240 | kryo.setRegistrationRequired(registrationRequired); | 240 | kryo.setRegistrationRequired(registrationRequired); |
241 | for (Pair<Class<?>, Serializer<?>> registry : registeredTypes) { | 241 | for (Pair<Class<?>, Serializer<?>> registry : registeredTypes) { |
242 | - if (registry.getRight() == null) { | 242 | + final Serializer<?> serializer = registry.getRight(); |
243 | + if (serializer == null) { | ||
243 | kryo.register(registry.getLeft()); | 244 | kryo.register(registry.getLeft()); |
244 | } else { | 245 | } else { |
245 | - kryo.register(registry.getLeft(), registry.getRight()); | 246 | + kryo.register(registry.getLeft(), serializer); |
247 | + if (serializer instanceof FamilySerializer) { | ||
248 | + FamilySerializer<?> fser = (FamilySerializer<?>) serializer; | ||
249 | + fser.registerFamilies(kryo); | ||
250 | + } | ||
246 | } | 251 | } |
247 | } | 252 | } |
248 | return kryo; | 253 | return kryo; |
249 | } | 254 | } |
255 | + | ||
256 | + /** | ||
257 | + * Serializer implementation, which required registration of family of Classes. | ||
258 | + * @param <T> base type of this serializer. | ||
259 | + */ | ||
260 | + public abstract static class FamilySerializer<T> extends Serializer<T> { | ||
261 | + | ||
262 | + | ||
263 | + public FamilySerializer(boolean acceptsNull) { | ||
264 | + super(acceptsNull); | ||
265 | + } | ||
266 | + | ||
267 | + public FamilySerializer(boolean acceptsNull, boolean immutable) { | ||
268 | + super(acceptsNull, immutable); | ||
269 | + } | ||
270 | + | ||
271 | + /** | ||
272 | + * Registers other classes this Serializer supports. | ||
273 | + * | ||
274 | + * @param kryo instance to register classes to | ||
275 | + */ | ||
276 | + public void registerFamilies(Kryo kryo) { | ||
277 | + } | ||
278 | + } | ||
250 | } | 279 | } | ... | ... |
-
Please register or login to post a comment