Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Showing
50 changed files
with
1342 additions
and
197 deletions
... | @@ -3,8 +3,6 @@ package org.onlab.onos.config; | ... | @@ -3,8 +3,6 @@ package org.onlab.onos.config; |
3 | import java.util.List; | 3 | import java.util.List; |
4 | 4 | ||
5 | import org.codehaus.jackson.annotate.JsonProperty; | 5 | import org.codehaus.jackson.annotate.JsonProperty; |
6 | -import org.onlab.packet.IpPrefix; | ||
7 | -import org.onlab.packet.MacAddress; | ||
8 | 6 | ||
9 | /** | 7 | /** |
10 | * Represents a set of addresses bound to a port. | 8 | * Represents a set of addresses bound to a port. |
... | @@ -12,8 +10,8 @@ import org.onlab.packet.MacAddress; | ... | @@ -12,8 +10,8 @@ import org.onlab.packet.MacAddress; |
12 | public class AddressEntry { | 10 | public class AddressEntry { |
13 | private String dpid; | 11 | private String dpid; |
14 | private short portNumber; | 12 | private short portNumber; |
15 | - private List<IpPrefix> ipAddresses; | 13 | + private List<String> ipAddresses; |
16 | - private MacAddress macAddress; | 14 | + private String macAddress; |
17 | 15 | ||
18 | public String getDpid() { | 16 | public String getDpid() { |
19 | return dpid; | 17 | return dpid; |
... | @@ -33,21 +31,21 @@ public class AddressEntry { | ... | @@ -33,21 +31,21 @@ public class AddressEntry { |
33 | this.portNumber = portNumber; | 31 | this.portNumber = portNumber; |
34 | } | 32 | } |
35 | 33 | ||
36 | - public List<IpPrefix> getIpAddresses() { | 34 | + public List<String> getIpAddresses() { |
37 | return ipAddresses; | 35 | return ipAddresses; |
38 | } | 36 | } |
39 | 37 | ||
40 | @JsonProperty("ips") | 38 | @JsonProperty("ips") |
41 | - public void setIpAddresses(List<IpPrefix> ipAddresses) { | 39 | + public void setIpAddresses(List<String> strIps) { |
42 | - this.ipAddresses = ipAddresses; | 40 | + this.ipAddresses = strIps; |
43 | } | 41 | } |
44 | 42 | ||
45 | - public MacAddress getMacAddress() { | 43 | + public String getMacAddress() { |
46 | return macAddress; | 44 | return macAddress; |
47 | } | 45 | } |
48 | 46 | ||
49 | @JsonProperty("mac") | 47 | @JsonProperty("mac") |
50 | - public void setMacAddress(MacAddress macAddress) { | 48 | + public void setMacAddress(String macAddress) { |
51 | this.macAddress = macAddress; | 49 | this.macAddress = macAddress; |
52 | } | 50 | } |
53 | } | 51 | } | ... | ... |
... | @@ -5,6 +5,8 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -5,6 +5,8 @@ import static org.slf4j.LoggerFactory.getLogger; |
5 | import java.io.File; | 5 | import java.io.File; |
6 | import java.io.FileNotFoundException; | 6 | import java.io.FileNotFoundException; |
7 | import java.io.IOException; | 7 | import java.io.IOException; |
8 | +import java.util.HashSet; | ||
9 | +import java.util.Set; | ||
8 | 10 | ||
9 | import org.apache.felix.scr.annotations.Activate; | 11 | import org.apache.felix.scr.annotations.Activate; |
10 | import org.apache.felix.scr.annotations.Component; | 12 | import org.apache.felix.scr.annotations.Component; |
... | @@ -17,10 +19,10 @@ import org.onlab.onos.net.DeviceId; | ... | @@ -17,10 +19,10 @@ import org.onlab.onos.net.DeviceId; |
17 | import org.onlab.onos.net.PortNumber; | 19 | import org.onlab.onos.net.PortNumber; |
18 | import org.onlab.onos.net.host.HostAdminService; | 20 | import org.onlab.onos.net.host.HostAdminService; |
19 | import org.onlab.onos.net.host.PortAddresses; | 21 | import org.onlab.onos.net.host.PortAddresses; |
22 | +import org.onlab.packet.IpPrefix; | ||
23 | +import org.onlab.packet.MacAddress; | ||
20 | import org.slf4j.Logger; | 24 | import org.slf4j.Logger; |
21 | 25 | ||
22 | -import com.google.common.collect.Sets; | ||
23 | - | ||
24 | /** | 26 | /** |
25 | * Simple configuration module to read in supplementary network configuration | 27 | * Simple configuration module to read in supplementary network configuration |
26 | * from a file. | 28 | * from a file. |
... | @@ -51,9 +53,29 @@ public class NetworkConfigReader { | ... | @@ -51,9 +53,29 @@ public class NetworkConfigReader { |
51 | DeviceId.deviceId(dpidToUri(entry.getDpid())), | 53 | DeviceId.deviceId(dpidToUri(entry.getDpid())), |
52 | PortNumber.portNumber(entry.getPortNumber())); | 54 | PortNumber.portNumber(entry.getPortNumber())); |
53 | 55 | ||
54 | - PortAddresses addresses = new PortAddresses(cp, | 56 | + Set<IpPrefix> ipAddresses = new HashSet<IpPrefix>(); |
55 | - Sets.newHashSet(entry.getIpAddresses()), | 57 | + |
58 | + for (String strIp : entry.getIpAddresses()) { | ||
59 | + try { | ||
60 | + IpPrefix address = IpPrefix.valueOf(strIp); | ||
61 | + ipAddresses.add(address); | ||
62 | + } catch (IllegalArgumentException e) { | ||
63 | + log.warn("Bad format for IP address in config: {}", strIp); | ||
64 | + } | ||
65 | + } | ||
66 | + | ||
67 | + MacAddress macAddress = null; | ||
68 | + if (entry.getMacAddress() != null) { | ||
69 | + try { | ||
70 | + macAddress = MacAddress.valueOf(entry.getMacAddress()); | ||
71 | + } catch (IllegalArgumentException e) { | ||
72 | + log.warn("Bad format for MAC address in config: {}", | ||
56 | entry.getMacAddress()); | 73 | entry.getMacAddress()); |
74 | + } | ||
75 | + } | ||
76 | + | ||
77 | + PortAddresses addresses = new PortAddresses(cp, | ||
78 | + ipAddresses, macAddress); | ||
57 | 79 | ||
58 | hostAdminService.bindAddressesToPort(addresses); | 80 | hostAdminService.bindAddressesToPort(addresses); |
59 | } | 81 | } | ... | ... |
... | @@ -38,6 +38,8 @@ import org.slf4j.Logger; | ... | @@ -38,6 +38,8 @@ import org.slf4j.Logger; |
38 | @Component(immediate = true) | 38 | @Component(immediate = true) |
39 | public class ReactiveForwarding { | 39 | public class ReactiveForwarding { |
40 | 40 | ||
41 | + private static final int TIMEOUT = 10; | ||
42 | + | ||
41 | private final Logger log = getLogger(getClass()); | 43 | private final Logger log = getLogger(getClass()); |
42 | 44 | ||
43 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 45 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
... | @@ -192,7 +194,7 @@ public class ReactiveForwarding { | ... | @@ -192,7 +194,7 @@ public class ReactiveForwarding { |
192 | treat.setOutput(portNumber); | 194 | treat.setOutput(portNumber); |
193 | 195 | ||
194 | FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(), | 196 | FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(), |
195 | - builder.build(), treat.build(), 0, appId); | 197 | + builder.build(), treat.build(), 0, appId, TIMEOUT); |
196 | 198 | ||
197 | flowRuleService.applyFlowRules(f); | 199 | flowRuleService.applyFlowRules(f); |
198 | } | 200 | } | ... | ... |
... | @@ -27,11 +27,12 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -27,11 +27,12 @@ public class DefaultFlowRule implements FlowRule { |
27 | 27 | ||
28 | private final ApplicationId appId; | 28 | private final ApplicationId appId; |
29 | 29 | ||
30 | - private boolean expired; | 30 | + private final int timeout; |
31 | 31 | ||
32 | public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector, | 32 | public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector, |
33 | TrafficTreatment treatment, int priority, FlowRuleState state, | 33 | TrafficTreatment treatment, int priority, FlowRuleState state, |
34 | - long life, long packets, long bytes, long flowId, boolean expired) { | 34 | + long life, long packets, long bytes, long flowId, boolean expired, |
35 | + int timeout) { | ||
35 | this.deviceId = deviceId; | 36 | this.deviceId = deviceId; |
36 | this.priority = priority; | 37 | this.priority = priority; |
37 | this.selector = selector; | 38 | this.selector = selector; |
... | @@ -39,26 +40,30 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -39,26 +40,30 @@ public class DefaultFlowRule implements FlowRule { |
39 | this.state = state; | 40 | this.state = state; |
40 | this.appId = ApplicationId.valueOf((int) (flowId >> 32)); | 41 | this.appId = ApplicationId.valueOf((int) (flowId >> 32)); |
41 | this.id = FlowId.valueOf(flowId); | 42 | this.id = FlowId.valueOf(flowId); |
42 | - this.expired = expired; | ||
43 | this.life = life; | 43 | this.life = life; |
44 | this.packets = packets; | 44 | this.packets = packets; |
45 | this.bytes = bytes; | 45 | this.bytes = bytes; |
46 | this.created = System.currentTimeMillis(); | 46 | this.created = System.currentTimeMillis(); |
47 | + this.timeout = timeout; | ||
47 | } | 48 | } |
48 | 49 | ||
49 | public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector, | 50 | public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector, |
50 | - TrafficTreatment treatement, int priority, ApplicationId appId) { | 51 | + TrafficTreatment treatement, int priority, ApplicationId appId, |
51 | - this(deviceId, selector, treatement, priority, FlowRuleState.CREATED, appId); | 52 | + int timeout) { |
53 | + this(deviceId, selector, treatement, priority, | ||
54 | + FlowRuleState.CREATED, appId, timeout); | ||
52 | } | 55 | } |
53 | 56 | ||
54 | public DefaultFlowRule(FlowRule rule, FlowRuleState state) { | 57 | public DefaultFlowRule(FlowRule rule, FlowRuleState state) { |
55 | this(rule.deviceId(), rule.selector(), rule.treatment(), | 58 | this(rule.deviceId(), rule.selector(), rule.treatment(), |
56 | - rule.priority(), state, rule.id(), rule.appId()); | 59 | + rule.priority(), state, rule.id(), rule.appId(), |
60 | + rule.timeout()); | ||
57 | } | 61 | } |
58 | 62 | ||
59 | private DefaultFlowRule(DeviceId deviceId, | 63 | private DefaultFlowRule(DeviceId deviceId, |
60 | TrafficSelector selector, TrafficTreatment treatment, | 64 | TrafficSelector selector, TrafficTreatment treatment, |
61 | - int priority, FlowRuleState state, ApplicationId appId) { | 65 | + int priority, FlowRuleState state, ApplicationId appId, |
66 | + int timeout) { | ||
62 | this.deviceId = deviceId; | 67 | this.deviceId = deviceId; |
63 | this.priority = priority; | 68 | this.priority = priority; |
64 | this.selector = selector; | 69 | this.selector = selector; |
... | @@ -69,13 +74,16 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -69,13 +74,16 @@ public class DefaultFlowRule implements FlowRule { |
69 | this.bytes = 0; | 74 | this.bytes = 0; |
70 | this.appId = appId; | 75 | this.appId = appId; |
71 | 76 | ||
77 | + this.timeout = timeout; | ||
78 | + | ||
72 | this.id = FlowId.valueOf((((long) appId().id()) << 32) | (this.hash() & 0xffffffffL)); | 79 | this.id = FlowId.valueOf((((long) appId().id()) << 32) | (this.hash() & 0xffffffffL)); |
73 | this.created = System.currentTimeMillis(); | 80 | this.created = System.currentTimeMillis(); |
74 | } | 81 | } |
75 | 82 | ||
76 | private DefaultFlowRule(DeviceId deviceId, | 83 | private DefaultFlowRule(DeviceId deviceId, |
77 | TrafficSelector selector, TrafficTreatment treatment, | 84 | TrafficSelector selector, TrafficTreatment treatment, |
78 | - int priority, FlowRuleState state, FlowId flowId, ApplicationId appId) { | 85 | + int priority, FlowRuleState state, FlowId flowId, ApplicationId appId, |
86 | + int timeout) { | ||
79 | this.deviceId = deviceId; | 87 | this.deviceId = deviceId; |
80 | this.priority = priority; | 88 | this.priority = priority; |
81 | this.selector = selector; | 89 | this.selector = selector; |
... | @@ -86,6 +94,7 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -86,6 +94,7 @@ public class DefaultFlowRule implements FlowRule { |
86 | this.bytes = 0; | 94 | this.bytes = 0; |
87 | this.appId = appId; | 95 | this.appId = appId; |
88 | this.id = flowId; | 96 | this.id = flowId; |
97 | + this.timeout = timeout; | ||
89 | this.created = System.currentTimeMillis(); | 98 | this.created = System.currentTimeMillis(); |
90 | } | 99 | } |
91 | 100 | ||
... | @@ -149,7 +158,7 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -149,7 +158,7 @@ public class DefaultFlowRule implements FlowRule { |
149 | * @see java.lang.Object#equals(java.lang.Object) | 158 | * @see java.lang.Object#equals(java.lang.Object) |
150 | */ | 159 | */ |
151 | public int hashCode() { | 160 | public int hashCode() { |
152 | - return Objects.hash(deviceId, id); | 161 | + return Objects.hash(deviceId, selector, priority); |
153 | } | 162 | } |
154 | 163 | ||
155 | public int hash() { | 164 | public int hash() { |
... | @@ -170,7 +179,10 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -170,7 +179,10 @@ public class DefaultFlowRule implements FlowRule { |
170 | if (obj instanceof DefaultFlowRule) { | 179 | if (obj instanceof DefaultFlowRule) { |
171 | DefaultFlowRule that = (DefaultFlowRule) obj; | 180 | DefaultFlowRule that = (DefaultFlowRule) obj; |
172 | return Objects.equals(deviceId, that.deviceId) && | 181 | return Objects.equals(deviceId, that.deviceId) && |
173 | - Objects.equals(id, that.id); | 182 | + //Objects.equals(id, that.id) && |
183 | + Objects.equals(priority, that.priority) && | ||
184 | + Objects.equals(selector, that.selector); | ||
185 | + | ||
174 | } | 186 | } |
175 | return false; | 187 | return false; |
176 | } | 188 | } |
... | @@ -181,16 +193,16 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -181,16 +193,16 @@ public class DefaultFlowRule implements FlowRule { |
181 | .add("id", id) | 193 | .add("id", id) |
182 | .add("deviceId", deviceId) | 194 | .add("deviceId", deviceId) |
183 | .add("priority", priority) | 195 | .add("priority", priority) |
184 | - .add("selector", selector) | 196 | + .add("selector", selector.criteria()) |
185 | - .add("treatment", treatment) | 197 | + .add("treatment", treatment == null ? "N/A" : treatment.instructions()) |
186 | .add("created", created) | 198 | .add("created", created) |
187 | .add("state", state) | 199 | .add("state", state) |
188 | .toString(); | 200 | .toString(); |
189 | } | 201 | } |
190 | 202 | ||
191 | @Override | 203 | @Override |
192 | - public boolean expired() { | 204 | + public int timeout() { |
193 | - return expired; | 205 | + return timeout > MAX_TIMEOUT ? MAX_TIMEOUT : this.timeout; |
194 | } | 206 | } |
195 | 207 | ||
196 | } | 208 | } | ... | ... |
... | @@ -3,8 +3,9 @@ package org.onlab.onos.net.flow; | ... | @@ -3,8 +3,9 @@ package org.onlab.onos.net.flow; |
3 | import static org.slf4j.LoggerFactory.getLogger; | 3 | import static org.slf4j.LoggerFactory.getLogger; |
4 | 4 | ||
5 | import java.util.Collections; | 5 | import java.util.Collections; |
6 | -import java.util.LinkedList; | 6 | +import java.util.HashSet; |
7 | -import java.util.List; | 7 | +import java.util.Objects; |
8 | +import java.util.Set; | ||
8 | 9 | ||
9 | import org.onlab.onos.net.PortNumber; | 10 | import org.onlab.onos.net.PortNumber; |
10 | import org.onlab.onos.net.flow.criteria.Criteria; | 11 | import org.onlab.onos.net.flow.criteria.Criteria; |
... | @@ -16,22 +17,42 @@ import org.slf4j.Logger; | ... | @@ -16,22 +17,42 @@ import org.slf4j.Logger; |
16 | 17 | ||
17 | public final class DefaultTrafficSelector implements TrafficSelector { | 18 | public final class DefaultTrafficSelector implements TrafficSelector { |
18 | 19 | ||
19 | - private final List<Criterion> selector; | 20 | + private final Set<Criterion> selector; |
20 | 21 | ||
21 | - private DefaultTrafficSelector(List<Criterion> selector) { | 22 | + private DefaultTrafficSelector(Set<Criterion> selector) { |
22 | - this.selector = Collections.unmodifiableList(selector); | 23 | + this.selector = Collections.unmodifiableSet(selector); |
23 | } | 24 | } |
24 | 25 | ||
25 | @Override | 26 | @Override |
26 | - public List<Criterion> criteria() { | 27 | + public Set<Criterion> criteria() { |
27 | return selector; | 28 | return selector; |
28 | } | 29 | } |
29 | 30 | ||
31 | + @Override | ||
32 | + public int hashCode() { | ||
33 | + return Objects.hash(selector); | ||
34 | + } | ||
35 | + | ||
36 | + @Override | ||
37 | + public boolean equals(Object obj) { | ||
38 | + if (this == obj) { | ||
39 | + return true; | ||
40 | + } | ||
41 | + if (obj instanceof DefaultTrafficSelector) { | ||
42 | + DefaultTrafficSelector that = (DefaultTrafficSelector) obj; | ||
43 | + return Objects.equals(selector, that.selector); | ||
44 | + | ||
45 | + } | ||
46 | + return false; | ||
47 | + } | ||
48 | + | ||
49 | + | ||
50 | + | ||
30 | public static class Builder implements TrafficSelector.Builder { | 51 | public static class Builder implements TrafficSelector.Builder { |
31 | 52 | ||
32 | private final Logger log = getLogger(getClass()); | 53 | private final Logger log = getLogger(getClass()); |
33 | 54 | ||
34 | - private final List<Criterion> selector = new LinkedList<>(); | 55 | + private final Set<Criterion> selector = new HashSet<>(); |
35 | 56 | ||
36 | @Override | 57 | @Override |
37 | public Builder add(Criterion criterion) { | 58 | public Builder add(Criterion criterion) { |
... | @@ -39,38 +60,47 @@ public final class DefaultTrafficSelector implements TrafficSelector { | ... | @@ -39,38 +60,47 @@ public final class DefaultTrafficSelector implements TrafficSelector { |
39 | return this; | 60 | return this; |
40 | } | 61 | } |
41 | 62 | ||
63 | + @Override | ||
42 | public Builder matchInport(PortNumber port) { | 64 | public Builder matchInport(PortNumber port) { |
43 | return add(Criteria.matchInPort(port)); | 65 | return add(Criteria.matchInPort(port)); |
44 | } | 66 | } |
45 | 67 | ||
68 | + @Override | ||
46 | public Builder matchEthSrc(MacAddress addr) { | 69 | public Builder matchEthSrc(MacAddress addr) { |
47 | return add(Criteria.matchEthSrc(addr)); | 70 | return add(Criteria.matchEthSrc(addr)); |
48 | } | 71 | } |
49 | 72 | ||
73 | + @Override | ||
50 | public Builder matchEthDst(MacAddress addr) { | 74 | public Builder matchEthDst(MacAddress addr) { |
51 | return add(Criteria.matchEthDst(addr)); | 75 | return add(Criteria.matchEthDst(addr)); |
52 | } | 76 | } |
53 | 77 | ||
78 | + @Override | ||
54 | public Builder matchEthType(short ethType) { | 79 | public Builder matchEthType(short ethType) { |
55 | return add(Criteria.matchEthType(ethType)); | 80 | return add(Criteria.matchEthType(ethType)); |
56 | } | 81 | } |
57 | 82 | ||
83 | + @Override | ||
58 | public Builder matchVlanId(VlanId vlanId) { | 84 | public Builder matchVlanId(VlanId vlanId) { |
59 | return add(Criteria.matchVlanId(vlanId)); | 85 | return add(Criteria.matchVlanId(vlanId)); |
60 | } | 86 | } |
61 | 87 | ||
88 | + @Override | ||
62 | public Builder matchVlanPcp(Byte vlanPcp) { | 89 | public Builder matchVlanPcp(Byte vlanPcp) { |
63 | return add(Criteria.matchVlanPcp(vlanPcp)); | 90 | return add(Criteria.matchVlanPcp(vlanPcp)); |
64 | } | 91 | } |
65 | 92 | ||
93 | + @Override | ||
66 | public Builder matchIPProtocol(Byte proto) { | 94 | public Builder matchIPProtocol(Byte proto) { |
67 | return add(Criteria.matchIPProtocol(proto)); | 95 | return add(Criteria.matchIPProtocol(proto)); |
68 | } | 96 | } |
69 | 97 | ||
98 | + @Override | ||
70 | public Builder matchIPSrc(IpPrefix ip) { | 99 | public Builder matchIPSrc(IpPrefix ip) { |
71 | return add(Criteria.matchIPSrc(ip)); | 100 | return add(Criteria.matchIPSrc(ip)); |
72 | } | 101 | } |
73 | 102 | ||
103 | + @Override | ||
74 | public Builder matchIPDst(IpPrefix ip) { | 104 | public Builder matchIPDst(IpPrefix ip) { |
75 | return add(Criteria.matchIPDst(ip)); | 105 | return add(Criteria.matchIPDst(ip)); |
76 | } | 106 | } | ... | ... |
... | @@ -9,6 +9,7 @@ import org.onlab.onos.net.DeviceId; | ... | @@ -9,6 +9,7 @@ import org.onlab.onos.net.DeviceId; |
9 | */ | 9 | */ |
10 | public interface FlowRule { | 10 | public interface FlowRule { |
11 | 11 | ||
12 | + static final int MAX_TIMEOUT = 60; | ||
12 | 13 | ||
13 | public enum FlowRuleState { | 14 | public enum FlowRuleState { |
14 | /** | 15 | /** |
... | @@ -112,10 +113,9 @@ public interface FlowRule { | ... | @@ -112,10 +113,9 @@ public interface FlowRule { |
112 | long bytes(); | 113 | long bytes(); |
113 | 114 | ||
114 | /** | 115 | /** |
115 | - * Indicates that this flow has expired at the device. | 116 | + * Returns the timeout for this flow requested by an application. |
116 | - * | 117 | + * @return integer value of the timeout |
117 | - * @return true if it has expired, false otherwise | ||
118 | */ | 118 | */ |
119 | - boolean expired(); | 119 | + int timeout(); |
120 | 120 | ||
121 | } | 121 | } | ... | ... |
... | @@ -8,6 +8,8 @@ import org.onlab.onos.net.provider.Provider; | ... | @@ -8,6 +8,8 @@ import org.onlab.onos.net.provider.Provider; |
8 | */ | 8 | */ |
9 | public interface FlowRuleProvider extends Provider { | 9 | public interface FlowRuleProvider extends Provider { |
10 | 10 | ||
11 | + static final int POLL_INTERVAL = 5; | ||
12 | + | ||
11 | /** | 13 | /** |
12 | * Instructs the provider to apply the specified flow rules to their | 14 | * Instructs the provider to apply the specified flow rules to their |
13 | * respective devices. | 15 | * respective devices. | ... | ... |
... | @@ -17,27 +17,6 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide | ... | @@ -17,27 +17,6 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide |
17 | void flowRemoved(FlowRule flowRule); | 17 | void flowRemoved(FlowRule flowRule); |
18 | 18 | ||
19 | /** | 19 | /** |
20 | - * Signals that a flow rule is missing for some network traffic. | ||
21 | - * | ||
22 | - * @param flowRule information about traffic in need of flow rule(s) | ||
23 | - */ | ||
24 | - void flowMissing(FlowRule flowRule); | ||
25 | - | ||
26 | - /** | ||
27 | - * Signals that a flow rule is on the switch but not in the store. | ||
28 | - * | ||
29 | - * @param flowRule the extra flow rule | ||
30 | - */ | ||
31 | - void extraneousFlow(FlowRule flowRule); | ||
32 | - | ||
33 | - /** | ||
34 | - * Signals that a flow rule was indeed added. | ||
35 | - * | ||
36 | - * @param flowRule the added flow rule | ||
37 | - */ | ||
38 | - void flowAdded(FlowRule flowRule); | ||
39 | - | ||
40 | - /** | ||
41 | * Pushes the collection of flow entries currently applied on the given | 20 | * Pushes the collection of flow entries currently applied on the given |
42 | * device. | 21 | * device. |
43 | * | 22 | * | ... | ... |
1 | package org.onlab.onos.net.flow; | 1 | package org.onlab.onos.net.flow; |
2 | 2 | ||
3 | -import java.util.List; | 3 | +import java.util.Set; |
4 | 4 | ||
5 | import org.onlab.onos.net.PortNumber; | 5 | import org.onlab.onos.net.PortNumber; |
6 | import org.onlab.onos.net.flow.criteria.Criterion; | 6 | import org.onlab.onos.net.flow.criteria.Criterion; |
... | @@ -18,7 +18,7 @@ public interface TrafficSelector { | ... | @@ -18,7 +18,7 @@ public interface TrafficSelector { |
18 | * | 18 | * |
19 | * @return list of criteria | 19 | * @return list of criteria |
20 | */ | 20 | */ |
21 | - List<Criterion> criteria(); | 21 | + Set<Criterion> criteria(); |
22 | 22 | ||
23 | /** | 23 | /** |
24 | * Builder of traffic selector entities. | 24 | * Builder of traffic selector entities. | ... | ... |
... | @@ -2,6 +2,8 @@ package org.onlab.onos.net.flow.criteria; | ... | @@ -2,6 +2,8 @@ package org.onlab.onos.net.flow.criteria; |
2 | 2 | ||
3 | import static com.google.common.base.MoreObjects.toStringHelper; | 3 | import static com.google.common.base.MoreObjects.toStringHelper; |
4 | 4 | ||
5 | +import java.util.Objects; | ||
6 | + | ||
5 | import org.onlab.onos.net.PortNumber; | 7 | import org.onlab.onos.net.PortNumber; |
6 | import org.onlab.onos.net.flow.criteria.Criterion.Type; | 8 | import org.onlab.onos.net.flow.criteria.Criterion.Type; |
7 | import org.onlab.packet.IpPrefix; | 9 | import org.onlab.packet.IpPrefix; |
... | @@ -137,6 +139,25 @@ public final class Criteria { | ... | @@ -137,6 +139,25 @@ public final class Criteria { |
137 | return toStringHelper(type().toString()) | 139 | return toStringHelper(type().toString()) |
138 | .add("port", port).toString(); | 140 | .add("port", port).toString(); |
139 | } | 141 | } |
142 | + | ||
143 | + @Override | ||
144 | + public int hashCode() { | ||
145 | + return Objects.hash(port); | ||
146 | + } | ||
147 | + | ||
148 | + @Override | ||
149 | + public boolean equals(Object obj) { | ||
150 | + if (this == obj) { | ||
151 | + return true; | ||
152 | + } | ||
153 | + if (obj instanceof PortCriterion) { | ||
154 | + PortCriterion that = (PortCriterion) obj; | ||
155 | + return Objects.equals(port, that.port); | ||
156 | + | ||
157 | + } | ||
158 | + return false; | ||
159 | + } | ||
160 | + | ||
140 | } | 161 | } |
141 | 162 | ||
142 | 163 | ||
... | @@ -164,6 +185,27 @@ public final class Criteria { | ... | @@ -164,6 +185,27 @@ public final class Criteria { |
164 | .add("mac", mac).toString(); | 185 | .add("mac", mac).toString(); |
165 | } | 186 | } |
166 | 187 | ||
188 | + @Override | ||
189 | + public int hashCode() { | ||
190 | + return Objects.hash(mac, type); | ||
191 | + } | ||
192 | + | ||
193 | + @Override | ||
194 | + public boolean equals(Object obj) { | ||
195 | + if (this == obj) { | ||
196 | + return true; | ||
197 | + } | ||
198 | + if (obj instanceof EthCriterion) { | ||
199 | + EthCriterion that = (EthCriterion) obj; | ||
200 | + return Objects.equals(mac, that.mac) && | ||
201 | + Objects.equals(type, that.type); | ||
202 | + | ||
203 | + | ||
204 | + } | ||
205 | + return false; | ||
206 | + } | ||
207 | + | ||
208 | + | ||
167 | } | 209 | } |
168 | 210 | ||
169 | public static final class EthTypeCriterion implements Criterion { | 211 | public static final class EthTypeCriterion implements Criterion { |
... | @@ -189,6 +231,25 @@ public final class Criteria { | ... | @@ -189,6 +231,25 @@ public final class Criteria { |
189 | .add("ethType", Long.toHexString(ethType)).toString(); | 231 | .add("ethType", Long.toHexString(ethType)).toString(); |
190 | } | 232 | } |
191 | 233 | ||
234 | + @Override | ||
235 | + public int hashCode() { | ||
236 | + return Objects.hash(ethType); | ||
237 | + } | ||
238 | + | ||
239 | + @Override | ||
240 | + public boolean equals(Object obj) { | ||
241 | + if (this == obj) { | ||
242 | + return true; | ||
243 | + } | ||
244 | + if (obj instanceof EthTypeCriterion) { | ||
245 | + EthTypeCriterion that = (EthTypeCriterion) obj; | ||
246 | + return Objects.equals(ethType, that.ethType); | ||
247 | + | ||
248 | + | ||
249 | + } | ||
250 | + return false; | ||
251 | + } | ||
252 | + | ||
192 | } | 253 | } |
193 | 254 | ||
194 | 255 | ||
... | @@ -217,6 +278,26 @@ public final class Criteria { | ... | @@ -217,6 +278,26 @@ public final class Criteria { |
217 | .add("ip", ip).toString(); | 278 | .add("ip", ip).toString(); |
218 | } | 279 | } |
219 | 280 | ||
281 | + @Override | ||
282 | + public int hashCode() { | ||
283 | + return Objects.hash(ip, type); | ||
284 | + } | ||
285 | + | ||
286 | + @Override | ||
287 | + public boolean equals(Object obj) { | ||
288 | + if (this == obj) { | ||
289 | + return true; | ||
290 | + } | ||
291 | + if (obj instanceof IPCriterion) { | ||
292 | + IPCriterion that = (IPCriterion) obj; | ||
293 | + return Objects.equals(ip, that.ip) && | ||
294 | + Objects.equals(type, that.type); | ||
295 | + | ||
296 | + | ||
297 | + } | ||
298 | + return false; | ||
299 | + } | ||
300 | + | ||
220 | } | 301 | } |
221 | 302 | ||
222 | 303 | ||
... | @@ -243,6 +324,25 @@ public final class Criteria { | ... | @@ -243,6 +324,25 @@ public final class Criteria { |
243 | .add("protocol", Long.toHexString(proto)).toString(); | 324 | .add("protocol", Long.toHexString(proto)).toString(); |
244 | } | 325 | } |
245 | 326 | ||
327 | + @Override | ||
328 | + public int hashCode() { | ||
329 | + return Objects.hash(proto); | ||
330 | + } | ||
331 | + | ||
332 | + @Override | ||
333 | + public boolean equals(Object obj) { | ||
334 | + if (this == obj) { | ||
335 | + return true; | ||
336 | + } | ||
337 | + if (obj instanceof IPProtocolCriterion) { | ||
338 | + IPProtocolCriterion that = (IPProtocolCriterion) obj; | ||
339 | + return Objects.equals(proto, that.proto); | ||
340 | + | ||
341 | + | ||
342 | + } | ||
343 | + return false; | ||
344 | + } | ||
345 | + | ||
246 | } | 346 | } |
247 | 347 | ||
248 | 348 | ||
... | @@ -269,6 +369,25 @@ public final class Criteria { | ... | @@ -269,6 +369,25 @@ public final class Criteria { |
269 | .add("pcp", Long.toHexString(vlanPcp)).toString(); | 369 | .add("pcp", Long.toHexString(vlanPcp)).toString(); |
270 | } | 370 | } |
271 | 371 | ||
372 | + @Override | ||
373 | + public int hashCode() { | ||
374 | + return Objects.hash(vlanPcp); | ||
375 | + } | ||
376 | + | ||
377 | + @Override | ||
378 | + public boolean equals(Object obj) { | ||
379 | + if (this == obj) { | ||
380 | + return true; | ||
381 | + } | ||
382 | + if (obj instanceof VlanPcpCriterion) { | ||
383 | + VlanPcpCriterion that = (VlanPcpCriterion) obj; | ||
384 | + return Objects.equals(vlanPcp, that.vlanPcp); | ||
385 | + | ||
386 | + | ||
387 | + } | ||
388 | + return false; | ||
389 | + } | ||
390 | + | ||
272 | } | 391 | } |
273 | 392 | ||
274 | 393 | ||
... | @@ -296,6 +415,25 @@ public final class Criteria { | ... | @@ -296,6 +415,25 @@ public final class Criteria { |
296 | .add("id", vlanId).toString(); | 415 | .add("id", vlanId).toString(); |
297 | } | 416 | } |
298 | 417 | ||
418 | + @Override | ||
419 | + public int hashCode() { | ||
420 | + return Objects.hash(vlanId); | ||
421 | + } | ||
422 | + | ||
423 | + @Override | ||
424 | + public boolean equals(Object obj) { | ||
425 | + if (this == obj) { | ||
426 | + return true; | ||
427 | + } | ||
428 | + if (obj instanceof VlanIdCriterion) { | ||
429 | + VlanIdCriterion that = (VlanIdCriterion) obj; | ||
430 | + return Objects.equals(vlanId, that.vlanId); | ||
431 | + | ||
432 | + | ||
433 | + } | ||
434 | + return false; | ||
435 | + } | ||
436 | + | ||
299 | } | 437 | } |
300 | 438 | ||
301 | 439 | ... | ... |
... | @@ -5,6 +5,9 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -5,6 +5,9 @@ import static org.slf4j.LoggerFactory.getLogger; |
5 | 5 | ||
6 | import java.util.Iterator; | 6 | import java.util.Iterator; |
7 | import java.util.List; | 7 | import java.util.List; |
8 | +import java.util.Map; | ||
9 | +import java.util.concurrent.ConcurrentHashMap; | ||
10 | +import java.util.concurrent.atomic.AtomicInteger; | ||
8 | 11 | ||
9 | import org.apache.felix.scr.annotations.Activate; | 12 | import org.apache.felix.scr.annotations.Activate; |
10 | import org.apache.felix.scr.annotations.Component; | 13 | import org.apache.felix.scr.annotations.Component; |
... | @@ -59,6 +62,8 @@ implements FlowRuleService, FlowRuleProviderRegistry { | ... | @@ -59,6 +62,8 @@ implements FlowRuleService, FlowRuleProviderRegistry { |
59 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 62 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
60 | protected DeviceService deviceService; | 63 | protected DeviceService deviceService; |
61 | 64 | ||
65 | + private final Map<FlowRule, AtomicInteger> deadRounds = new ConcurrentHashMap<>(); | ||
66 | + | ||
62 | @Activate | 67 | @Activate |
63 | public void activate() { | 68 | public void activate() { |
64 | store.setDelegate(delegate); | 69 | store.setDelegate(delegate); |
... | @@ -84,6 +89,7 @@ implements FlowRuleService, FlowRuleProviderRegistry { | ... | @@ -84,6 +89,7 @@ implements FlowRuleService, FlowRuleProviderRegistry { |
84 | FlowRule f = flowRules[i]; | 89 | FlowRule f = flowRules[i]; |
85 | final Device device = deviceService.getDevice(f.deviceId()); | 90 | final Device device = deviceService.getDevice(f.deviceId()); |
86 | final FlowRuleProvider frp = getProvider(device.providerId()); | 91 | final FlowRuleProvider frp = getProvider(device.providerId()); |
92 | + deadRounds.put(f, new AtomicInteger(0)); | ||
87 | store.storeFlowRule(f); | 93 | store.storeFlowRule(f); |
88 | frp.applyFlowRule(f); | 94 | frp.applyFlowRule(f); |
89 | } | 95 | } |
... | @@ -98,6 +104,7 @@ implements FlowRuleService, FlowRuleProviderRegistry { | ... | @@ -98,6 +104,7 @@ implements FlowRuleService, FlowRuleProviderRegistry { |
98 | f = flowRules[i]; | 104 | f = flowRules[i]; |
99 | device = deviceService.getDevice(f.deviceId()); | 105 | device = deviceService.getDevice(f.deviceId()); |
100 | frp = getProvider(device.providerId()); | 106 | frp = getProvider(device.providerId()); |
107 | + deadRounds.remove(f); | ||
101 | store.deleteFlowRule(f); | 108 | store.deleteFlowRule(f); |
102 | frp.removeFlowRule(f); | 109 | frp.removeFlowRule(f); |
103 | } | 110 | } |
... | @@ -161,11 +168,7 @@ implements FlowRuleService, FlowRuleProviderRegistry { | ... | @@ -161,11 +168,7 @@ implements FlowRuleService, FlowRuleProviderRegistry { |
161 | switch (stored.state()) { | 168 | switch (stored.state()) { |
162 | case ADDED: | 169 | case ADDED: |
163 | case PENDING_ADD: | 170 | case PENDING_ADD: |
164 | - if (flowRule.expired()) { | ||
165 | - event = store.removeFlowRule(flowRule); | ||
166 | - } else { | ||
167 | frp.applyFlowRule(stored); | 171 | frp.applyFlowRule(stored); |
168 | - } | ||
169 | break; | 172 | break; |
170 | case PENDING_REMOVE: | 173 | case PENDING_REMOVE: |
171 | case REMOVED: | 174 | case REMOVED: |
... | @@ -181,8 +184,8 @@ implements FlowRuleService, FlowRuleProviderRegistry { | ... | @@ -181,8 +184,8 @@ implements FlowRuleService, FlowRuleProviderRegistry { |
181 | } | 184 | } |
182 | } | 185 | } |
183 | 186 | ||
184 | - @Override | 187 | + |
185 | - public void flowMissing(FlowRule flowRule) { | 188 | + private void flowMissing(FlowRule flowRule) { |
186 | checkNotNull(flowRule, FLOW_RULE_NULL); | 189 | checkNotNull(flowRule, FLOW_RULE_NULL); |
187 | checkValidity(); | 190 | checkValidity(); |
188 | Device device = deviceService.getDevice(flowRule.deviceId()); | 191 | Device device = deviceService.getDevice(flowRule.deviceId()); |
... | @@ -209,19 +212,22 @@ implements FlowRuleService, FlowRuleProviderRegistry { | ... | @@ -209,19 +212,22 @@ implements FlowRuleService, FlowRuleProviderRegistry { |
209 | 212 | ||
210 | } | 213 | } |
211 | 214 | ||
212 | - @Override | 215 | + |
213 | - public void extraneousFlow(FlowRule flowRule) { | 216 | + private void extraneousFlow(FlowRule flowRule) { |
214 | checkNotNull(flowRule, FLOW_RULE_NULL); | 217 | checkNotNull(flowRule, FLOW_RULE_NULL); |
215 | checkValidity(); | 218 | checkValidity(); |
216 | removeFlowRules(flowRule); | 219 | removeFlowRules(flowRule); |
217 | log.debug("Flow {} is on switch but not in store.", flowRule); | 220 | log.debug("Flow {} is on switch but not in store.", flowRule); |
218 | } | 221 | } |
219 | 222 | ||
220 | - @Override | 223 | + |
221 | - public void flowAdded(FlowRule flowRule) { | 224 | + private void flowAdded(FlowRule flowRule) { |
222 | checkNotNull(flowRule, FLOW_RULE_NULL); | 225 | checkNotNull(flowRule, FLOW_RULE_NULL); |
223 | checkValidity(); | 226 | checkValidity(); |
224 | 227 | ||
228 | + if (deadRounds.containsKey(flowRule) && | ||
229 | + checkRuleLiveness(flowRule, store.getFlowRule(flowRule))) { | ||
230 | + | ||
225 | FlowRuleEvent event = store.addOrUpdateFlowRule(flowRule); | 231 | FlowRuleEvent event = store.addOrUpdateFlowRule(flowRule); |
226 | if (event == null) { | 232 | if (event == null) { |
227 | log.debug("No flow store event generated."); | 233 | log.debug("No flow store event generated."); |
... | @@ -229,6 +235,21 @@ implements FlowRuleService, FlowRuleProviderRegistry { | ... | @@ -229,6 +235,21 @@ implements FlowRuleService, FlowRuleProviderRegistry { |
229 | log.debug("Flow {} {}", flowRule, event.type()); | 235 | log.debug("Flow {} {}", flowRule, event.type()); |
230 | post(event); | 236 | post(event); |
231 | } | 237 | } |
238 | + } else { | ||
239 | + removeFlowRules(flowRule); | ||
240 | + } | ||
241 | + | ||
242 | + } | ||
243 | + | ||
244 | + private boolean checkRuleLiveness(FlowRule swRule, FlowRule storedRule) { | ||
245 | + int timeout = storedRule.timeout(); | ||
246 | + if (storedRule.packets() != swRule.packets()) { | ||
247 | + deadRounds.get(swRule).set(0); | ||
248 | + return true; | ||
249 | + } | ||
250 | + | ||
251 | + return (deadRounds.get(swRule).getAndIncrement() * | ||
252 | + FlowRuleProvider.POLL_INTERVAL) <= timeout; | ||
232 | 253 | ||
233 | } | 254 | } |
234 | 255 | ... | ... |
1 | package org.onlab.onos.net.host.impl; | 1 | package org.onlab.onos.net.host.impl; |
2 | 2 | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
4 | +import static org.slf4j.LoggerFactory.getLogger; | ||
5 | + | ||
6 | +import java.util.Set; | ||
7 | + | ||
3 | import org.apache.felix.scr.annotations.Activate; | 8 | import org.apache.felix.scr.annotations.Activate; |
4 | import org.apache.felix.scr.annotations.Component; | 9 | import org.apache.felix.scr.annotations.Component; |
5 | import org.apache.felix.scr.annotations.Deactivate; | 10 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -12,6 +17,7 @@ import org.onlab.onos.net.ConnectPoint; | ... | @@ -12,6 +17,7 @@ import org.onlab.onos.net.ConnectPoint; |
12 | import org.onlab.onos.net.DeviceId; | 17 | import org.onlab.onos.net.DeviceId; |
13 | import org.onlab.onos.net.Host; | 18 | import org.onlab.onos.net.Host; |
14 | import org.onlab.onos.net.HostId; | 19 | import org.onlab.onos.net.HostId; |
20 | +import org.onlab.onos.net.device.DeviceService; | ||
15 | import org.onlab.onos.net.host.HostAdminService; | 21 | import org.onlab.onos.net.host.HostAdminService; |
16 | import org.onlab.onos.net.host.HostDescription; | 22 | import org.onlab.onos.net.host.HostDescription; |
17 | import org.onlab.onos.net.host.HostEvent; | 23 | import org.onlab.onos.net.host.HostEvent; |
... | @@ -23,6 +29,7 @@ import org.onlab.onos.net.host.HostService; | ... | @@ -23,6 +29,7 @@ import org.onlab.onos.net.host.HostService; |
23 | import org.onlab.onos.net.host.HostStore; | 29 | import org.onlab.onos.net.host.HostStore; |
24 | import org.onlab.onos.net.host.HostStoreDelegate; | 30 | import org.onlab.onos.net.host.HostStoreDelegate; |
25 | import org.onlab.onos.net.host.PortAddresses; | 31 | import org.onlab.onos.net.host.PortAddresses; |
32 | +import org.onlab.onos.net.packet.PacketService; | ||
26 | import org.onlab.onos.net.provider.AbstractProviderRegistry; | 33 | import org.onlab.onos.net.provider.AbstractProviderRegistry; |
27 | import org.onlab.onos.net.provider.AbstractProviderService; | 34 | import org.onlab.onos.net.provider.AbstractProviderService; |
28 | import org.onlab.packet.IpAddress; | 35 | import org.onlab.packet.IpAddress; |
... | @@ -31,11 +38,6 @@ import org.onlab.packet.MacAddress; | ... | @@ -31,11 +38,6 @@ import org.onlab.packet.MacAddress; |
31 | import org.onlab.packet.VlanId; | 38 | import org.onlab.packet.VlanId; |
32 | import org.slf4j.Logger; | 39 | import org.slf4j.Logger; |
33 | 40 | ||
34 | -import java.util.Set; | ||
35 | - | ||
36 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
37 | -import static org.slf4j.LoggerFactory.getLogger; | ||
38 | - | ||
39 | /** | 41 | /** |
40 | * Provides basic implementation of the host SB & NB APIs. | 42 | * Provides basic implementation of the host SB & NB APIs. |
41 | */ | 43 | */ |
... | @@ -59,12 +61,22 @@ public class HostManager | ... | @@ -59,12 +61,22 @@ public class HostManager |
59 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 61 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
60 | protected EventDeliveryService eventDispatcher; | 62 | protected EventDeliveryService eventDispatcher; |
61 | 63 | ||
64 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
65 | + protected DeviceService deviceService; | ||
66 | + | ||
67 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
68 | + protected PacketService packetService; | ||
69 | + | ||
70 | + private HostMonitor monitor; | ||
62 | 71 | ||
63 | @Activate | 72 | @Activate |
64 | public void activate() { | 73 | public void activate() { |
74 | + log.info("Started"); | ||
65 | store.setDelegate(delegate); | 75 | store.setDelegate(delegate); |
66 | eventDispatcher.addSink(HostEvent.class, listenerRegistry); | 76 | eventDispatcher.addSink(HostEvent.class, listenerRegistry); |
67 | - log.info("Started"); | 77 | + |
78 | + monitor = new HostMonitor(deviceService, packetService, this); | ||
79 | + | ||
68 | } | 80 | } |
69 | 81 | ||
70 | @Deactivate | 82 | @Deactivate |
... | @@ -76,6 +88,8 @@ public class HostManager | ... | @@ -76,6 +88,8 @@ public class HostManager |
76 | 88 | ||
77 | @Override | 89 | @Override |
78 | protected HostProviderService createProviderService(HostProvider provider) { | 90 | protected HostProviderService createProviderService(HostProvider provider) { |
91 | + monitor.registerHostProvider(provider); | ||
92 | + | ||
79 | return new InternalHostProviderService(provider); | 93 | return new InternalHostProviderService(provider); |
80 | } | 94 | } |
81 | 95 | ||
... | @@ -126,12 +140,12 @@ public class HostManager | ... | @@ -126,12 +140,12 @@ public class HostManager |
126 | 140 | ||
127 | @Override | 141 | @Override |
128 | public void startMonitoringIp(IpAddress ip) { | 142 | public void startMonitoringIp(IpAddress ip) { |
129 | - // TODO pass through to HostMonitor | 143 | + monitor.addMonitoringFor(ip); |
130 | } | 144 | } |
131 | 145 | ||
132 | @Override | 146 | @Override |
133 | public void stopMonitoringIp(IpAddress ip) { | 147 | public void stopMonitoringIp(IpAddress ip) { |
134 | - // TODO pass through to HostMonitor | 148 | + monitor.stopMonitoring(ip); |
135 | } | 149 | } |
136 | 150 | ||
137 | @Override | 151 | @Override | ... | ... |
... | @@ -2,10 +2,11 @@ package org.onlab.onos.net.host.impl; | ... | @@ -2,10 +2,11 @@ package org.onlab.onos.net.host.impl; |
2 | 2 | ||
3 | import java.nio.ByteBuffer; | 3 | import java.nio.ByteBuffer; |
4 | import java.util.ArrayList; | 4 | import java.util.ArrayList; |
5 | -import java.util.Collections; | ||
6 | import java.util.HashSet; | 5 | import java.util.HashSet; |
7 | import java.util.List; | 6 | import java.util.List; |
7 | +import java.util.Map; | ||
8 | import java.util.Set; | 8 | import java.util.Set; |
9 | +import java.util.concurrent.ConcurrentHashMap; | ||
9 | import java.util.concurrent.TimeUnit; | 10 | import java.util.concurrent.TimeUnit; |
10 | 11 | ||
11 | import org.jboss.netty.util.Timeout; | 12 | import org.jboss.netty.util.Timeout; |
... | @@ -21,19 +22,19 @@ import org.onlab.onos.net.flow.TrafficTreatment; | ... | @@ -21,19 +22,19 @@ import org.onlab.onos.net.flow.TrafficTreatment; |
21 | import org.onlab.onos.net.flow.instructions.Instruction; | 22 | import org.onlab.onos.net.flow.instructions.Instruction; |
22 | import org.onlab.onos.net.flow.instructions.Instructions; | 23 | import org.onlab.onos.net.flow.instructions.Instructions; |
23 | import org.onlab.onos.net.host.HostProvider; | 24 | import org.onlab.onos.net.host.HostProvider; |
24 | -import org.onlab.onos.net.host.HostService; | ||
25 | -import org.onlab.onos.net.host.HostStore; | ||
26 | import org.onlab.onos.net.host.PortAddresses; | 25 | import org.onlab.onos.net.host.PortAddresses; |
27 | import org.onlab.onos.net.packet.DefaultOutboundPacket; | 26 | import org.onlab.onos.net.packet.DefaultOutboundPacket; |
28 | import org.onlab.onos.net.packet.OutboundPacket; | 27 | import org.onlab.onos.net.packet.OutboundPacket; |
29 | import org.onlab.onos.net.packet.PacketService; | 28 | import org.onlab.onos.net.packet.PacketService; |
30 | -import org.onlab.onos.net.topology.TopologyService; | 29 | +import org.onlab.onos.net.provider.ProviderId; |
31 | import org.onlab.packet.ARP; | 30 | import org.onlab.packet.ARP; |
32 | import org.onlab.packet.Ethernet; | 31 | import org.onlab.packet.Ethernet; |
33 | import org.onlab.packet.IpAddress; | 32 | import org.onlab.packet.IpAddress; |
34 | import org.onlab.packet.IpPrefix; | 33 | import org.onlab.packet.IpPrefix; |
35 | import org.onlab.packet.MacAddress; | 34 | import org.onlab.packet.MacAddress; |
36 | import org.onlab.util.Timer; | 35 | import org.onlab.util.Timer; |
36 | +import org.slf4j.Logger; | ||
37 | +import org.slf4j.LoggerFactory; | ||
37 | 38 | ||
38 | /** | 39 | /** |
39 | * Monitors hosts on the dataplane to detect changes in host data. | 40 | * Monitors hosts on the dataplane to detect changes in host data. |
... | @@ -43,9 +44,7 @@ import org.onlab.util.Timer; | ... | @@ -43,9 +44,7 @@ import org.onlab.util.Timer; |
43 | * probe for hosts that have not yet been detected (specified by IP address). | 44 | * probe for hosts that have not yet been detected (specified by IP address). |
44 | */ | 45 | */ |
45 | public class HostMonitor implements TimerTask { | 46 | public class HostMonitor implements TimerTask { |
46 | - | 47 | + private static final Logger log = LoggerFactory.getLogger(HostMonitor.class); |
47 | - private static final byte[] DEFAULT_MAC_ADDRESS = | ||
48 | - MacAddress.valueOf("00:00:00:00:00:01").getAddress(); | ||
49 | 48 | ||
50 | private static final byte[] ZERO_MAC_ADDRESS = | 49 | private static final byte[] ZERO_MAC_ADDRESS = |
51 | MacAddress.valueOf("00:00:00:00:00:00").getAddress(); | 50 | MacAddress.valueOf("00:00:00:00:00:00").getAddress(); |
... | @@ -54,59 +53,77 @@ public class HostMonitor implements TimerTask { | ... | @@ -54,59 +53,77 @@ public class HostMonitor implements TimerTask { |
54 | private static final byte[] BROADCAST_MAC = | 53 | private static final byte[] BROADCAST_MAC = |
55 | MacAddress.valueOf("ff:ff:ff:ff:ff:ff").getAddress(); | 54 | MacAddress.valueOf("ff:ff:ff:ff:ff:ff").getAddress(); |
56 | 55 | ||
57 | - private final HostService hostService; | 56 | + private DeviceService deviceService; |
58 | - private final TopologyService topologyService; | 57 | + private PacketService packetService; |
59 | - private final DeviceService deviceService; | 58 | + private HostManager hostManager; |
60 | - private final HostProvider hostProvider; | ||
61 | - private final PacketService packetService; | ||
62 | - private final HostStore hostStore; | ||
63 | 59 | ||
64 | private final Set<IpAddress> monitoredAddresses; | 60 | private final Set<IpAddress> monitoredAddresses; |
65 | 61 | ||
62 | + private final Map<ProviderId, HostProvider> hostProviders; | ||
63 | + | ||
66 | private final long probeRate; | 64 | private final long probeRate; |
67 | 65 | ||
68 | private final Timeout timeout; | 66 | private final Timeout timeout; |
69 | 67 | ||
70 | - public HostMonitor(HostService hostService, TopologyService topologyService, | 68 | + public HostMonitor( |
71 | DeviceService deviceService, | 69 | DeviceService deviceService, |
72 | - HostProvider hostProvider, PacketService packetService, | 70 | + PacketService packetService, |
73 | - HostStore hostStore) { | 71 | + HostManager hostService) { |
74 | - this.hostService = hostService; | 72 | + |
75 | - this.topologyService = topologyService; | ||
76 | this.deviceService = deviceService; | 73 | this.deviceService = deviceService; |
77 | - this.hostProvider = hostProvider; | ||
78 | this.packetService = packetService; | 74 | this.packetService = packetService; |
79 | - this.hostStore = hostStore; | 75 | + this.hostManager = hostService; |
80 | 76 | ||
81 | monitoredAddresses = new HashSet<>(); | 77 | monitoredAddresses = new HashSet<>(); |
78 | + hostProviders = new ConcurrentHashMap<>(); | ||
82 | 79 | ||
83 | probeRate = 30000; // milliseconds | 80 | probeRate = 30000; // milliseconds |
84 | 81 | ||
85 | timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS); | 82 | timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS); |
83 | + | ||
84 | + addDefaultAddresses(); | ||
86 | } | 85 | } |
87 | 86 | ||
88 | - public void addMonitoringFor(IpAddress ip) { | 87 | + private void addDefaultAddresses() { |
88 | + //monitoredAddresses.add(IpAddress.valueOf("10.0.0.1")); | ||
89 | + } | ||
90 | + | ||
91 | + void addMonitoringFor(IpAddress ip) { | ||
89 | monitoredAddresses.add(ip); | 92 | monitoredAddresses.add(ip); |
90 | } | 93 | } |
91 | 94 | ||
92 | - public void stopMonitoring(IpAddress ip) { | 95 | + void stopMonitoring(IpAddress ip) { |
93 | monitoredAddresses.remove(ip); | 96 | monitoredAddresses.remove(ip); |
94 | } | 97 | } |
95 | 98 | ||
96 | - public void shutdown() { | 99 | + void shutdown() { |
97 | timeout.cancel(); | 100 | timeout.cancel(); |
98 | } | 101 | } |
99 | 102 | ||
103 | + void registerHostProvider(HostProvider provider) { | ||
104 | + hostProviders.put(provider.id(), provider); | ||
105 | + } | ||
106 | + | ||
107 | + void unregisterHostProvider(HostProvider provider) { | ||
108 | + // TODO find out how to call this | ||
109 | + } | ||
110 | + | ||
100 | @Override | 111 | @Override |
101 | public void run(Timeout timeout) throws Exception { | 112 | public void run(Timeout timeout) throws Exception { |
102 | for (IpAddress ip : monitoredAddresses) { | 113 | for (IpAddress ip : monitoredAddresses) { |
103 | - Set<Host> hosts = Collections.emptySet(); //TODO hostService.getHostsByIp(ip); | 114 | + // TODO have to convert right now because the HostService API uses IpPrefix |
115 | + IpPrefix prefix = IpPrefix.valueOf(ip.toOctets()); | ||
116 | + | ||
117 | + Set<Host> hosts = hostManager.getHostsByIp(prefix); | ||
104 | 118 | ||
105 | if (hosts.isEmpty()) { | 119 | if (hosts.isEmpty()) { |
106 | sendArpRequest(ip); | 120 | sendArpRequest(ip); |
107 | } else { | 121 | } else { |
108 | for (Host host : hosts) { | 122 | for (Host host : hosts) { |
109 | - hostProvider.triggerProbe(host); | 123 | + HostProvider provider = hostProviders.get(host.providerId()); |
124 | + if (provider != null) { | ||
125 | + provider.triggerProbe(host); | ||
126 | + } | ||
110 | } | 127 | } |
111 | } | 128 | } |
112 | } | 129 | } |
... | @@ -120,29 +137,26 @@ public class HostMonitor implements TimerTask { | ... | @@ -120,29 +137,26 @@ public class HostMonitor implements TimerTask { |
120 | * @param targetIp IP address to ARP for | 137 | * @param targetIp IP address to ARP for |
121 | */ | 138 | */ |
122 | private void sendArpRequest(IpAddress targetIp) { | 139 | private void sendArpRequest(IpAddress targetIp) { |
123 | - | ||
124 | // Find ports with an IP address in the target's subnet and sent ARP | 140 | // Find ports with an IP address in the target's subnet and sent ARP |
125 | // probes out those ports. | 141 | // probes out those ports. |
126 | for (Device device : deviceService.getDevices()) { | 142 | for (Device device : deviceService.getDevices()) { |
127 | for (Port port : deviceService.getPorts(device.id())) { | 143 | for (Port port : deviceService.getPorts(device.id())) { |
128 | ConnectPoint cp = new ConnectPoint(device.id(), port.number()); | 144 | ConnectPoint cp = new ConnectPoint(device.id(), port.number()); |
129 | - PortAddresses addresses = hostStore.getAddressBindingsForPort(cp); | 145 | + PortAddresses addresses = hostManager.getAddressBindingsForPort(cp); |
130 | 146 | ||
131 | - /*for (IpPrefix prefix : addresses.ips()) { | 147 | + for (IpPrefix prefix : addresses.ips()) { |
132 | if (prefix.contains(targetIp)) { | 148 | if (prefix.contains(targetIp)) { |
133 | - sendProbe(device.id(), port, addresses, targetIp); | 149 | + sendProbe(device.id(), port, targetIp, |
150 | + prefix.toIpAddress(), addresses.mac()); | ||
151 | + } | ||
134 | } | 152 | } |
135 | - }*/ | ||
136 | } | 153 | } |
137 | } | 154 | } |
138 | - | ||
139 | - // TODO case where no address was found. | ||
140 | - // Broadcast out internal edge ports? | ||
141 | } | 155 | } |
142 | 156 | ||
143 | - private void sendProbe(DeviceId deviceId, Port port, PortAddresses portAddresses, | 157 | + private void sendProbe(DeviceId deviceId, Port port, IpAddress targetIp, |
144 | - IpAddress targetIp) { | 158 | + IpAddress sourceIp, MacAddress sourceMac) { |
145 | - Ethernet arpPacket = createArpFor(targetIp, portAddresses); | 159 | + Ethernet arpPacket = buildArpRequest(targetIp, sourceIp, sourceMac); |
146 | 160 | ||
147 | List<Instruction> instructions = new ArrayList<>(); | 161 | List<Instruction> instructions = new ArrayList<>(); |
148 | instructions.add(Instructions.createOutput(port.number())); | 162 | instructions.add(Instructions.createOutput(port.number())); |
... | @@ -158,30 +172,25 @@ public class HostMonitor implements TimerTask { | ... | @@ -158,30 +172,25 @@ public class HostMonitor implements TimerTask { |
158 | packetService.emit(outboundPacket); | 172 | packetService.emit(outboundPacket); |
159 | } | 173 | } |
160 | 174 | ||
161 | - private Ethernet createArpFor(IpAddress targetIp, PortAddresses portAddresses) { | 175 | + private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp, |
176 | + MacAddress sourceMac) { | ||
162 | 177 | ||
163 | ARP arp = new ARP(); | 178 | ARP arp = new ARP(); |
164 | arp.setHardwareType(ARP.HW_TYPE_ETHERNET) | 179 | arp.setHardwareType(ARP.HW_TYPE_ETHERNET) |
165 | .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH) | 180 | .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH) |
166 | .setProtocolType(ARP.PROTO_TYPE_IP) | 181 | .setProtocolType(ARP.PROTO_TYPE_IP) |
167 | - .setProtocolAddressLength((byte) IpPrefix.INET_LEN); | 182 | + .setProtocolAddressLength((byte) IpPrefix.INET_LEN) |
168 | - | 183 | + .setOpCode(ARP.OP_REQUEST); |
169 | - byte[] sourceMacAddress; | ||
170 | - if (portAddresses.mac() == null) { | ||
171 | - sourceMacAddress = DEFAULT_MAC_ADDRESS; | ||
172 | - } else { | ||
173 | - sourceMacAddress = portAddresses.mac().getAddress(); | ||
174 | - } | ||
175 | 184 | ||
176 | - arp.setSenderHardwareAddress(sourceMacAddress) | 185 | + arp.setSenderHardwareAddress(sourceMac.getAddress()) |
177 | - //TODO .setSenderProtocolAddress(portAddresses.ips().toOctets()) | 186 | + .setSenderProtocolAddress(sourceIp.toOctets()) |
178 | .setTargetHardwareAddress(ZERO_MAC_ADDRESS) | 187 | .setTargetHardwareAddress(ZERO_MAC_ADDRESS) |
179 | .setTargetProtocolAddress(targetIp.toOctets()); | 188 | .setTargetProtocolAddress(targetIp.toOctets()); |
180 | 189 | ||
181 | Ethernet ethernet = new Ethernet(); | 190 | Ethernet ethernet = new Ethernet(); |
182 | ethernet.setEtherType(Ethernet.TYPE_ARP) | 191 | ethernet.setEtherType(Ethernet.TYPE_ARP) |
183 | .setDestinationMACAddress(BROADCAST_MAC) | 192 | .setDestinationMACAddress(BROADCAST_MAC) |
184 | - .setSourceMACAddress(sourceMacAddress) | 193 | + .setSourceMACAddress(sourceMac.getAddress()) |
185 | .setPayload(arp); | 194 | .setPayload(arp); |
186 | 195 | ||
187 | return ethernet; | 196 | return ethernet; | ... | ... |
... | @@ -9,7 +9,9 @@ import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | ... | @@ -9,7 +9,9 @@ import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; |
9 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED; | 9 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED; |
10 | 10 | ||
11 | import java.util.ArrayList; | 11 | import java.util.ArrayList; |
12 | +import java.util.Collections; | ||
12 | import java.util.List; | 13 | import java.util.List; |
14 | +import java.util.Set; | ||
13 | 15 | ||
14 | import org.junit.After; | 16 | import org.junit.After; |
15 | import org.junit.Before; | 17 | import org.junit.Before; |
... | @@ -42,6 +44,7 @@ import org.onlab.onos.net.provider.AbstractProvider; | ... | @@ -42,6 +44,7 @@ import org.onlab.onos.net.provider.AbstractProvider; |
42 | import org.onlab.onos.net.provider.ProviderId; | 44 | import org.onlab.onos.net.provider.ProviderId; |
43 | import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore; | 45 | import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore; |
44 | 46 | ||
47 | +import com.google.common.collect.ImmutableList; | ||
45 | import com.google.common.collect.Lists; | 48 | import com.google.common.collect.Lists; |
46 | import com.google.common.collect.Sets; | 49 | import com.google.common.collect.Sets; |
47 | 50 | ||
... | @@ -52,6 +55,7 @@ public class FlowRuleManagerTest { | ... | @@ -52,6 +55,7 @@ public class FlowRuleManagerTest { |
52 | 55 | ||
53 | private static final ProviderId PID = new ProviderId("of", "foo"); | 56 | private static final ProviderId PID = new ProviderId("of", "foo"); |
54 | private static final DeviceId DID = DeviceId.deviceId("of:001"); | 57 | private static final DeviceId DID = DeviceId.deviceId("of:001"); |
58 | + private static final int TIMEOUT = 10; | ||
55 | private static final Device DEV = new DefaultDevice( | 59 | private static final Device DEV = new DefaultDevice( |
56 | PID, DID, Type.SWITCH, "", "", "", ""); | 60 | PID, DID, Type.SWITCH, "", "", "", ""); |
57 | 61 | ||
... | @@ -96,7 +100,7 @@ public class FlowRuleManagerTest { | ... | @@ -96,7 +100,7 @@ public class FlowRuleManagerTest { |
96 | private FlowRule flowRule(int tsval, int trval) { | 100 | private FlowRule flowRule(int tsval, int trval) { |
97 | TestSelector ts = new TestSelector(tsval); | 101 | TestSelector ts = new TestSelector(tsval); |
98 | TestTreatment tr = new TestTreatment(trval); | 102 | TestTreatment tr = new TestTreatment(trval); |
99 | - return new DefaultFlowRule(DID, ts, tr, 0, appId); | 103 | + return new DefaultFlowRule(DID, ts, tr, 0, appId, TIMEOUT); |
100 | } | 104 | } |
101 | 105 | ||
102 | private FlowRule flowRule(FlowRule rule, FlowRuleState state) { | 106 | private FlowRule flowRule(FlowRule rule, FlowRuleState state) { |
... | @@ -105,7 +109,8 @@ public class FlowRuleManagerTest { | ... | @@ -105,7 +109,8 @@ public class FlowRuleManagerTest { |
105 | 109 | ||
106 | private FlowRule addFlowRule(int hval) { | 110 | private FlowRule addFlowRule(int hval) { |
107 | FlowRule rule = flowRule(hval, hval); | 111 | FlowRule rule = flowRule(hval, hval); |
108 | - providerService.flowAdded(rule); | 112 | + service.applyFlowRules(rule); |
113 | + | ||
109 | assertNotNull("rule should be found", service.getFlowEntries(DID)); | 114 | assertNotNull("rule should be found", service.getFlowEntries(DID)); |
110 | return rule; | 115 | return rule; |
111 | } | 116 | } |
... | @@ -135,13 +140,18 @@ public class FlowRuleManagerTest { | ... | @@ -135,13 +140,18 @@ public class FlowRuleManagerTest { |
135 | public void getFlowEntries() { | 140 | public void getFlowEntries() { |
136 | assertTrue("store should be empty", | 141 | assertTrue("store should be empty", |
137 | Sets.newHashSet(service.getFlowEntries(DID)).isEmpty()); | 142 | Sets.newHashSet(service.getFlowEntries(DID)).isEmpty()); |
138 | - addFlowRule(1); | 143 | + FlowRule f1 = addFlowRule(1); |
139 | - addFlowRule(2); | 144 | + FlowRule f2 = addFlowRule(2); |
145 | + | ||
140 | assertEquals("2 rules should exist", 2, flowCount()); | 146 | assertEquals("2 rules should exist", 2, flowCount()); |
147 | + | ||
148 | + providerService.pushFlowMetrics(DID, ImmutableList.of(f1, f2)); | ||
141 | validateEvents(RULE_ADDED, RULE_ADDED); | 149 | validateEvents(RULE_ADDED, RULE_ADDED); |
142 | 150 | ||
143 | addFlowRule(1); | 151 | addFlowRule(1); |
144 | assertEquals("should still be 2 rules", 2, flowCount()); | 152 | assertEquals("should still be 2 rules", 2, flowCount()); |
153 | + | ||
154 | + providerService.pushFlowMetrics(DID, ImmutableList.of(f1)); | ||
145 | validateEvents(RULE_UPDATED); | 155 | validateEvents(RULE_UPDATED); |
146 | } | 156 | } |
147 | 157 | ||
... | @@ -179,8 +189,10 @@ public class FlowRuleManagerTest { | ... | @@ -179,8 +189,10 @@ public class FlowRuleManagerTest { |
179 | public void removeFlowRules() { | 189 | public void removeFlowRules() { |
180 | FlowRule f1 = addFlowRule(1); | 190 | FlowRule f1 = addFlowRule(1); |
181 | FlowRule f2 = addFlowRule(2); | 191 | FlowRule f2 = addFlowRule(2); |
182 | - addFlowRule(3); | 192 | + FlowRule f3 = addFlowRule(3); |
183 | assertEquals("3 rules should exist", 3, flowCount()); | 193 | assertEquals("3 rules should exist", 3, flowCount()); |
194 | + | ||
195 | + providerService.pushFlowMetrics(DID, ImmutableList.of(f1, f2, f3)); | ||
184 | validateEvents(RULE_ADDED, RULE_ADDED, RULE_ADDED); | 196 | validateEvents(RULE_ADDED, RULE_ADDED, RULE_ADDED); |
185 | 197 | ||
186 | FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED); | 198 | FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED); |
... | @@ -200,8 +212,9 @@ public class FlowRuleManagerTest { | ... | @@ -200,8 +212,9 @@ public class FlowRuleManagerTest { |
200 | @Test | 212 | @Test |
201 | public void flowRemoved() { | 213 | public void flowRemoved() { |
202 | FlowRule f1 = addFlowRule(1); | 214 | FlowRule f1 = addFlowRule(1); |
215 | + FlowRule f2 = addFlowRule(2); | ||
216 | + providerService.pushFlowMetrics(f1.deviceId(), ImmutableList.of(f1, f2)); | ||
203 | service.removeFlowRules(f1); | 217 | service.removeFlowRules(f1); |
204 | - addFlowRule(2); | ||
205 | FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED); | 218 | FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED); |
206 | providerService.flowRemoved(rem1); | 219 | providerService.flowRemoved(rem1); |
207 | validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED); | 220 | validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED); |
... | @@ -209,9 +222,11 @@ public class FlowRuleManagerTest { | ... | @@ -209,9 +222,11 @@ public class FlowRuleManagerTest { |
209 | providerService.flowRemoved(rem1); | 222 | providerService.flowRemoved(rem1); |
210 | validateEvents(); | 223 | validateEvents(); |
211 | 224 | ||
212 | - FlowRule f3 = flowRule(flowRule(3, 3), FlowRuleState.ADDED); | 225 | + FlowRule f3 = flowRule(3, 3); |
213 | - providerService.flowAdded(f3); | 226 | + service.applyFlowRules(f3); |
227 | + providerService.pushFlowMetrics(f3.deviceId(), Collections.singletonList(f3)); | ||
214 | validateEvents(RULE_ADDED); | 228 | validateEvents(RULE_ADDED); |
229 | + | ||
215 | providerService.flowRemoved(f3); | 230 | providerService.flowRemoved(f3); |
216 | validateEvents(); | 231 | validateEvents(); |
217 | } | 232 | } |
... | @@ -223,9 +238,10 @@ public class FlowRuleManagerTest { | ... | @@ -223,9 +238,10 @@ public class FlowRuleManagerTest { |
223 | FlowRule f3 = flowRule(3, 3); | 238 | FlowRule f3 = flowRule(3, 3); |
224 | 239 | ||
225 | 240 | ||
241 | + | ||
242 | + mgr.applyFlowRules(f1, f2, f3); | ||
226 | FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED); | 243 | FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED); |
227 | FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED); | 244 | FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED); |
228 | - mgr.applyFlowRules(f1, f2, f3); | ||
229 | 245 | ||
230 | providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2)); | 246 | providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2)); |
231 | 247 | ||
... | @@ -233,7 +249,7 @@ public class FlowRuleManagerTest { | ... | @@ -233,7 +249,7 @@ public class FlowRuleManagerTest { |
233 | validateState(FlowRuleState.PENDING_ADD, FlowRuleState.ADDED, | 249 | validateState(FlowRuleState.PENDING_ADD, FlowRuleState.ADDED, |
234 | FlowRuleState.ADDED)); | 250 | FlowRuleState.ADDED)); |
235 | 251 | ||
236 | - validateEvents(RULE_UPDATED, RULE_UPDATED); | 252 | + validateEvents(RULE_ADDED, RULE_ADDED); |
237 | } | 253 | } |
238 | 254 | ||
239 | @Test | 255 | @Test |
... | @@ -241,15 +257,15 @@ public class FlowRuleManagerTest { | ... | @@ -241,15 +257,15 @@ public class FlowRuleManagerTest { |
241 | FlowRule f1 = flowRule(1, 1); | 257 | FlowRule f1 = flowRule(1, 1); |
242 | FlowRule f2 = flowRule(2, 2); | 258 | FlowRule f2 = flowRule(2, 2); |
243 | FlowRule f3 = flowRule(3, 3); | 259 | FlowRule f3 = flowRule(3, 3); |
260 | + mgr.applyFlowRules(f1, f2); | ||
244 | 261 | ||
245 | FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED); | 262 | FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED); |
246 | FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED); | 263 | FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED); |
247 | FlowRule updatedF3 = flowRule(f3, FlowRuleState.ADDED); | 264 | FlowRule updatedF3 = flowRule(f3, FlowRuleState.ADDED); |
248 | - mgr.applyFlowRules(f1, f2); | ||
249 | 265 | ||
250 | providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2, updatedF3)); | 266 | providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2, updatedF3)); |
251 | 267 | ||
252 | - validateEvents(RULE_UPDATED, RULE_UPDATED); | 268 | + validateEvents(RULE_ADDED, RULE_ADDED); |
253 | 269 | ||
254 | } | 270 | } |
255 | 271 | ||
... | @@ -271,7 +287,7 @@ public class FlowRuleManagerTest { | ... | @@ -271,7 +287,7 @@ public class FlowRuleManagerTest { |
271 | 287 | ||
272 | providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2)); | 288 | providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2)); |
273 | 289 | ||
274 | - validateEvents(RULE_UPDATED, RULE_UPDATED, RULE_REMOVED); | 290 | + validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED); |
275 | 291 | ||
276 | } | 292 | } |
277 | 293 | ||
... | @@ -386,7 +402,7 @@ public class FlowRuleManagerTest { | ... | @@ -386,7 +402,7 @@ public class FlowRuleManagerTest { |
386 | } | 402 | } |
387 | 403 | ||
388 | @Override | 404 | @Override |
389 | - public List<Criterion> criteria() { | 405 | + public Set<Criterion> criteria() { |
390 | return null; | 406 | return null; |
391 | } | 407 | } |
392 | 408 | ... | ... |
... | @@ -20,7 +20,7 @@ import org.onlab.onos.cluster.DefaultControllerNode; | ... | @@ -20,7 +20,7 @@ import org.onlab.onos.cluster.DefaultControllerNode; |
20 | import org.onlab.onos.cluster.NodeId; | 20 | import org.onlab.onos.cluster.NodeId; |
21 | import org.onlab.onos.store.AbstractStore; | 21 | import org.onlab.onos.store.AbstractStore; |
22 | import org.onlab.onos.store.cluster.messaging.ClusterCommunicationAdminService; | 22 | import org.onlab.onos.store.cluster.messaging.ClusterCommunicationAdminService; |
23 | -import org.onlab.onos.store.cluster.messaging.impl.OnosClusterCommunicationManager; | 23 | +import org.onlab.onos.store.cluster.messaging.impl.ClusterCommunicationManager; |
24 | import org.onlab.packet.IpPrefix; | 24 | import org.onlab.packet.IpPrefix; |
25 | import org.slf4j.Logger; | 25 | import org.slf4j.Logger; |
26 | import org.slf4j.LoggerFactory; | 26 | import org.slf4j.LoggerFactory; |
... | @@ -50,7 +50,7 @@ public class DistributedClusterStore | ... | @@ -50,7 +50,7 @@ public class DistributedClusterStore |
50 | private final Map<NodeId, State> states = new ConcurrentHashMap<>(); | 50 | private final Map<NodeId, State> states = new ConcurrentHashMap<>(); |
51 | private final Cache<NodeId, ControllerNode> livenessCache = CacheBuilder.newBuilder() | 51 | private final Cache<NodeId, ControllerNode> livenessCache = CacheBuilder.newBuilder() |
52 | .maximumSize(1000) | 52 | .maximumSize(1000) |
53 | - .expireAfterWrite(OnosClusterCommunicationManager.HEART_BEAT_INTERVAL_MILLIS * 3, TimeUnit.MILLISECONDS) | 53 | + .expireAfterWrite(ClusterCommunicationManager.HEART_BEAT_INTERVAL_MILLIS * 3, TimeUnit.MILLISECONDS) |
54 | .removalListener(new LivenessCacheRemovalListener()).build(); | 54 | .removalListener(new LivenessCacheRemovalListener()).build(); |
55 | 55 | ||
56 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 56 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ... | ... |
1 | package org.onlab.onos.store.cluster.messaging; | 1 | package org.onlab.onos.store.cluster.messaging; |
2 | 2 | ||
3 | +/** | ||
4 | + * Interface for handling cluster messages. | ||
5 | + */ | ||
3 | public interface ClusterMessageHandler { | 6 | public interface ClusterMessageHandler { |
7 | + | ||
8 | + /** | ||
9 | + * Handles/Processes the cluster message. | ||
10 | + * @param message cluster message. | ||
11 | + */ | ||
4 | public void handle(ClusterMessage message); | 12 | public void handle(ClusterMessage message); |
5 | } | 13 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -2,6 +2,8 @@ package org.onlab.onos.store.cluster.messaging; | ... | @@ -2,6 +2,8 @@ package org.onlab.onos.store.cluster.messaging; |
2 | 2 | ||
3 | /** | 3 | /** |
4 | * Representation of a message subject. | 4 | * Representation of a message subject. |
5 | + * Cluster messages have associated subjects that dictate how they get handled | ||
6 | + * on the receiving side. | ||
5 | */ | 7 | */ |
6 | public class MessageSubject { | 8 | public class MessageSubject { |
7 | 9 | ... | ... |
core/store/dist/src/main/java/org/onlab/onos/store/cluster/messaging/MessageSubscriber.java
deleted
100644 → 0
1 | -package org.onlab.onos.store.cluster.messaging; | ||
2 | - | ||
3 | -import org.onlab.onos.cluster.NodeId; | ||
4 | - | ||
5 | -/** | ||
6 | - * Represents a message consumer. | ||
7 | - */ | ||
8 | -public interface MessageSubscriber { | ||
9 | - | ||
10 | - /** | ||
11 | - * Receives the specified cluster message. | ||
12 | - * | ||
13 | - * @param message message to be received | ||
14 | - * @param fromNodeId node from which the message was received | ||
15 | - */ | ||
16 | - void receive(Object messagePayload, NodeId fromNodeId); | ||
17 | - | ||
18 | -} |
... | @@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory; | ... | @@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory; |
32 | 32 | ||
33 | @Component(immediate = true) | 33 | @Component(immediate = true) |
34 | @Service | 34 | @Service |
35 | -public class OnosClusterCommunicationManager | 35 | +public class ClusterCommunicationManager |
36 | implements ClusterCommunicationService, ClusterCommunicationAdminService { | 36 | implements ClusterCommunicationService, ClusterCommunicationAdminService { |
37 | 37 | ||
38 | private final Logger log = LoggerFactory.getLogger(getClass()); | 38 | private final Logger log = LoggerFactory.getLogger(getClass()); | ... | ... |
core/store/dist/src/test/java/org/onlab/onos/store/cluster/impl/ClusterCommunicationManagerTest.java
... | @@ -6,7 +6,7 @@ import org.junit.Ignore; | ... | @@ -6,7 +6,7 @@ import org.junit.Ignore; |
6 | import org.junit.Test; | 6 | import org.junit.Test; |
7 | import org.onlab.onos.cluster.DefaultControllerNode; | 7 | import org.onlab.onos.cluster.DefaultControllerNode; |
8 | import org.onlab.onos.cluster.NodeId; | 8 | import org.onlab.onos.cluster.NodeId; |
9 | -import org.onlab.onos.store.cluster.messaging.impl.OnosClusterCommunicationManager; | 9 | +import org.onlab.onos.store.cluster.messaging.impl.ClusterCommunicationManager; |
10 | import org.onlab.netty.NettyMessagingService; | 10 | import org.onlab.netty.NettyMessagingService; |
11 | import org.onlab.packet.IpPrefix; | 11 | import org.onlab.packet.IpPrefix; |
12 | 12 | ||
... | @@ -29,8 +29,8 @@ public class ClusterCommunicationManagerTest { | ... | @@ -29,8 +29,8 @@ public class ClusterCommunicationManagerTest { |
29 | 29 | ||
30 | private static final IpPrefix IP = IpPrefix.valueOf("127.0.0.1"); | 30 | private static final IpPrefix IP = IpPrefix.valueOf("127.0.0.1"); |
31 | 31 | ||
32 | - private OnosClusterCommunicationManager ccm1; | 32 | + private ClusterCommunicationManager ccm1; |
33 | - private OnosClusterCommunicationManager ccm2; | 33 | + private ClusterCommunicationManager ccm2; |
34 | 34 | ||
35 | private TestDelegate cnd1 = new TestDelegate(); | 35 | private TestDelegate cnd1 = new TestDelegate(); |
36 | private TestDelegate cnd2 = new TestDelegate(); | 36 | private TestDelegate cnd2 = new TestDelegate(); |
... | @@ -46,11 +46,11 @@ public class ClusterCommunicationManagerTest { | ... | @@ -46,11 +46,11 @@ public class ClusterCommunicationManagerTest { |
46 | NettyMessagingService messagingService = new NettyMessagingService(); | 46 | NettyMessagingService messagingService = new NettyMessagingService(); |
47 | messagingService.activate(); | 47 | messagingService.activate(); |
48 | 48 | ||
49 | - ccm1 = new OnosClusterCommunicationManager(); | 49 | + ccm1 = new ClusterCommunicationManager(); |
50 | // ccm1.serializationService = messageSerializer; | 50 | // ccm1.serializationService = messageSerializer; |
51 | ccm1.activate(); | 51 | ccm1.activate(); |
52 | 52 | ||
53 | - ccm2 = new OnosClusterCommunicationManager(); | 53 | + ccm2 = new ClusterCommunicationManager(); |
54 | // ccm2.serializationService = messageSerializer; | 54 | // ccm2.serializationService = messageSerializer; |
55 | ccm2.activate(); | 55 | ccm2.activate(); |
56 | 56 | ... | ... |
1 | package org.onlab.onos.store.trivial.impl; | 1 | package org.onlab.onos.store.trivial.impl; |
2 | 2 | ||
3 | -import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED; | ||
4 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | 3 | import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; |
5 | import static org.slf4j.LoggerFactory.getLogger; | 4 | import static org.slf4j.LoggerFactory.getLogger; |
6 | 5 | ||
... | @@ -116,18 +115,21 @@ public class SimpleFlowRuleStore | ... | @@ -116,18 +115,21 @@ public class SimpleFlowRuleStore |
116 | DeviceId did = rule.deviceId(); | 115 | DeviceId did = rule.deviceId(); |
117 | 116 | ||
118 | // check if this new rule is an update to an existing entry | 117 | // check if this new rule is an update to an existing entry |
119 | - if (flowEntries.containsEntry(did, rule)) { | 118 | + FlowRule stored = getFlowRule(rule); |
120 | - //synchronized (flowEntries) { | 119 | + if (stored != null) { |
121 | // Multimaps support duplicates so we have to remove our rule | 120 | // Multimaps support duplicates so we have to remove our rule |
122 | // and replace it with the current version. | 121 | // and replace it with the current version. |
123 | flowEntries.remove(did, rule); | 122 | flowEntries.remove(did, rule); |
124 | flowEntries.put(did, rule); | 123 | flowEntries.put(did, rule); |
125 | - //} | 124 | + |
125 | + if (stored.state() == FlowRuleState.PENDING_ADD) { | ||
126 | + return new FlowRuleEvent(Type.RULE_ADDED, rule); | ||
127 | + } | ||
126 | return new FlowRuleEvent(Type.RULE_UPDATED, rule); | 128 | return new FlowRuleEvent(Type.RULE_UPDATED, rule); |
127 | } | 129 | } |
128 | 130 | ||
129 | flowEntries.put(did, rule); | 131 | flowEntries.put(did, rule); |
130 | - return new FlowRuleEvent(RULE_ADDED, rule); | 132 | + return null; |
131 | } | 133 | } |
132 | 134 | ||
133 | @Override | 135 | @Override |
... | @@ -140,11 +142,4 @@ public class SimpleFlowRuleStore | ... | @@ -140,11 +142,4 @@ public class SimpleFlowRuleStore |
140 | } | 142 | } |
141 | //} | 143 | //} |
142 | } | 144 | } |
143 | - | ||
144 | - | ||
145 | - | ||
146 | - | ||
147 | - | ||
148 | - | ||
149 | - | ||
150 | } | 145 | } | ... | ... |
... | @@ -11,7 +11,7 @@ | ... | @@ -11,7 +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:io.dropwizard.metrics/metrics-core/3.1.0</bundle> |
15 | <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> |
16 | 16 | ||
17 | <bundle>mvn:com.esotericsoftware.kryo/kryo/2.24.0</bundle> | 17 | <bundle>mvn:com.esotericsoftware.kryo/kryo/2.24.0</bundle> | ... | ... |
... | @@ -169,7 +169,12 @@ public class OpenFlowControllerImpl implements OpenFlowController { | ... | @@ -169,7 +169,12 @@ public class OpenFlowControllerImpl implements OpenFlowController { |
169 | 169 | ||
170 | @Override | 170 | @Override |
171 | public void setRole(Dpid dpid, RoleState role) { | 171 | public void setRole(Dpid dpid, RoleState role) { |
172 | - getSwitch(dpid).setRole(role); | 172 | + final OpenFlowSwitch sw = getSwitch(dpid); |
173 | + if (sw == null) { | ||
174 | + log.debug("Switch not connected. Ignoring setRole({}, {})", dpid, role); | ||
175 | + return; | ||
176 | + } | ||
177 | + sw.setRole(role); | ||
173 | } | 178 | } |
174 | 179 | ||
175 | /** | 180 | /** | ... | ... |
... | @@ -248,6 +248,11 @@ | ... | @@ -248,6 +248,11 @@ |
248 | <classifier>tests</classifier> | 248 | <classifier>tests</classifier> |
249 | <scope>test</scope> | 249 | <scope>test</scope> |
250 | </dependency> | 250 | </dependency> |
251 | + <dependency> | ||
252 | + <groupId>commons-pool</groupId> | ||
253 | + <artifactId>commons-pool</artifactId> | ||
254 | + <version>1.6</version> | ||
255 | + </dependency> | ||
251 | </dependencies> | 256 | </dependencies> |
252 | </dependencyManagement> | 257 | </dependencyManagement> |
253 | 258 | ... | ... |
... | @@ -77,7 +77,6 @@ public class FlowModBuilder { | ... | @@ -77,7 +77,6 @@ public class FlowModBuilder { |
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) | ||
81 | .setMatch(match) | 80 | .setMatch(match) |
82 | .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) | 81 | .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM)) |
83 | .setPriority(priority) | 82 | .setPriority(priority) | ... | ... |
... | @@ -71,7 +71,7 @@ public class FlowRuleBuilder { | ... | @@ -71,7 +71,7 @@ public class FlowRuleBuilder { |
71 | buildSelector(), buildTreatment(), stat.getPriority(), | 71 | buildSelector(), buildTreatment(), stat.getPriority(), |
72 | FlowRuleState.ADDED, stat.getDurationNsec() / 1000000, | 72 | FlowRuleState.ADDED, stat.getDurationNsec() / 1000000, |
73 | stat.getPacketCount().getValue(), stat.getByteCount().getValue(), | 73 | stat.getPacketCount().getValue(), stat.getByteCount().getValue(), |
74 | - stat.getCookie().getValue(), false); | 74 | + stat.getCookie().getValue(), false, stat.getIdleTimeout()); |
75 | } else { | 75 | } else { |
76 | // TODO: revisit potentially. | 76 | // TODO: revisit potentially. |
77 | return new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), | 77 | return new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), |
... | @@ -79,7 +79,8 @@ public class FlowRuleBuilder { | ... | @@ -79,7 +79,8 @@ public class FlowRuleBuilder { |
79 | FlowRuleState.REMOVED, removed.getDurationNsec() / 1000000, | 79 | FlowRuleState.REMOVED, removed.getDurationNsec() / 1000000, |
80 | removed.getPacketCount().getValue(), removed.getByteCount().getValue(), | 80 | removed.getPacketCount().getValue(), removed.getByteCount().getValue(), |
81 | removed.getCookie().getValue(), | 81 | removed.getCookie().getValue(), |
82 | - removed.getReason() == OFFlowRemovedReason.IDLE_TIMEOUT.ordinal()); | 82 | + removed.getReason() == OFFlowRemovedReason.IDLE_TIMEOUT.ordinal(), |
83 | + stat.getIdleTimeout()); | ||
83 | } | 84 | } |
84 | } | 85 | } |
85 | 86 | ... | ... |
providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
... | @@ -127,7 +127,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -127,7 +127,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
127 | 127 | ||
128 | @Override | 128 | @Override |
129 | public void switchAdded(Dpid dpid) { | 129 | public void switchAdded(Dpid dpid) { |
130 | - FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), 5); | 130 | + FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL); |
131 | fsc.start(); | 131 | fsc.start(); |
132 | collectors.put(dpid, fsc); | 132 | collectors.put(dpid, fsc); |
133 | } | 133 | } | ... | ... |
... | @@ -176,7 +176,7 @@ | ... | @@ -176,7 +176,7 @@ |
176 | </module> | 176 | </module> |
177 | 177 | ||
178 | <module name="ParameterNumber"> | 178 | <module name="ParameterNumber"> |
179 | - <property name="max" value="10"/> | 179 | + <property name="max" value="15"/> |
180 | <property name="tokens" value="CTOR_DEF"/> | 180 | <property name="tokens" value="CTOR_DEF"/> |
181 | </module> | 181 | </module> |
182 | <!-- Checks for whitespace --> | 182 | <!-- Checks for whitespace --> | ... | ... |
... | @@ -56,9 +56,13 @@ | ... | @@ -56,9 +56,13 @@ |
56 | <artifactId>objenesis</artifactId> | 56 | <artifactId>objenesis</artifactId> |
57 | </dependency> | 57 | </dependency> |
58 | <dependency> | 58 | <dependency> |
59 | - <groupId>com.codahale.metrics</groupId> | 59 | + <groupId>io.dropwizard.metrics</groupId> |
60 | <artifactId>metrics-core</artifactId> | 60 | <artifactId>metrics-core</artifactId> |
61 | - <version>3.0.2</version> | 61 | + <version>3.1.0</version> |
62 | + </dependency> | ||
63 | + <dependency> | ||
64 | + <groupId>org.apache.felix</groupId> | ||
65 | + <artifactId>org.apache.felix.scr.annotations</artifactId> | ||
62 | </dependency> | 66 | </dependency> |
63 | </dependencies> | 67 | </dependencies> |
64 | 68 | ... | ... |
1 | package org.onlab.metrics; | 1 | package org.onlab.metrics; |
2 | 2 | ||
3 | +import java.io.File; | ||
4 | +import java.util.Locale; | ||
3 | import java.util.Map; | 5 | import java.util.Map; |
4 | import java.util.concurrent.ConcurrentHashMap; | 6 | import java.util.concurrent.ConcurrentHashMap; |
5 | import java.util.concurrent.ConcurrentMap; | 7 | import java.util.concurrent.ConcurrentMap; |
8 | +import java.util.concurrent.TimeUnit; | ||
9 | + | ||
10 | +import org.apache.felix.scr.annotations.Activate; | ||
11 | +import org.apache.felix.scr.annotations.Component; | ||
12 | +import org.apache.felix.scr.annotations.Deactivate; | ||
6 | 13 | ||
7 | import com.codahale.metrics.Counter; | 14 | import com.codahale.metrics.Counter; |
15 | +import com.codahale.metrics.CsvReporter; | ||
8 | import com.codahale.metrics.Gauge; | 16 | import com.codahale.metrics.Gauge; |
9 | import com.codahale.metrics.Histogram; | 17 | import com.codahale.metrics.Histogram; |
10 | import com.codahale.metrics.Meter; | 18 | import com.codahale.metrics.Meter; |
... | @@ -45,24 +53,44 @@ import com.codahale.metrics.Timer; | ... | @@ -45,24 +53,44 @@ import com.codahale.metrics.Timer; |
45 | * </code> | 53 | * </code> |
46 | * </pre> | 54 | * </pre> |
47 | */ | 55 | */ |
56 | +@Component(immediate = true) | ||
48 | public final class MetricsManager implements MetricsService { | 57 | public final class MetricsManager implements MetricsService { |
49 | 58 | ||
50 | /** | 59 | /** |
51 | * Registry to hold the Components defined in the system. | 60 | * Registry to hold the Components defined in the system. |
52 | */ | 61 | */ |
53 | - private ConcurrentMap<String, MetricsComponent> componentsRegistry = | 62 | + private ConcurrentMap<String, MetricsComponent> componentsRegistry; |
54 | - new ConcurrentHashMap<>(); | ||
55 | 63 | ||
56 | /** | 64 | /** |
57 | * Registry for the Metrics objects created in the system. | 65 | * Registry for the Metrics objects created in the system. |
58 | */ | 66 | */ |
59 | - private final MetricRegistry metricsRegistry = new MetricRegistry(); | 67 | + private final MetricRegistry metricsRegistry; |
60 | 68 | ||
61 | /** | 69 | /** |
62 | - * Hide constructor. The only way to get the registry is through the | 70 | + * Default Reporter for this metrics manager. |
63 | - * singleton getter. | ||
64 | */ | 71 | */ |
65 | - private MetricsManager() {} | 72 | + private final CsvReporter reporter; |
73 | + | ||
74 | + public MetricsManager() { | ||
75 | + this.componentsRegistry = new ConcurrentHashMap<>(); | ||
76 | + this.metricsRegistry = new MetricRegistry(); | ||
77 | + | ||
78 | + this.reporter = CsvReporter.forRegistry(metricsRegistry) | ||
79 | + .formatFor(Locale.US) | ||
80 | + .convertRatesTo(TimeUnit.SECONDS) | ||
81 | + .convertDurationsTo(TimeUnit.MICROSECONDS) | ||
82 | + .build(new File("/tmp/")); | ||
83 | + | ||
84 | + reporter.start(10, TimeUnit.SECONDS); | ||
85 | + } | ||
86 | + | ||
87 | + @Activate | ||
88 | + public void activate() { | ||
89 | + } | ||
90 | + | ||
91 | + @Deactivate | ||
92 | + public void deactivate() { | ||
93 | + } | ||
66 | 94 | ||
67 | /** | 95 | /** |
68 | * Registers a component. | 96 | * Registers a component. | ... | ... |
... | @@ -250,6 +250,17 @@ public final class IpPrefix { | ... | @@ -250,6 +250,17 @@ public final class IpPrefix { |
250 | return new IpPrefix(version, host, netmask); | 250 | return new IpPrefix(version, host, netmask); |
251 | } | 251 | } |
252 | 252 | ||
253 | + /** | ||
254 | + * Returns an IpAddress of the bytes contained in this prefix. | ||
255 | + * FIXME this is a hack for now and only works because IpPrefix doesn't | ||
256 | + * mask the input bytes on creation. | ||
257 | + * | ||
258 | + * @return the IpAddress | ||
259 | + */ | ||
260 | + public IpAddress toIpAddress() { | ||
261 | + return IpAddress.valueOf(octets); | ||
262 | + } | ||
263 | + | ||
253 | public boolean isMasked() { | 264 | public boolean isMasked() { |
254 | return mask() != 0; | 265 | return mask() != 0; |
255 | } | 266 | } |
... | @@ -278,6 +289,17 @@ public final class IpPrefix { | ... | @@ -278,6 +289,17 @@ public final class IpPrefix { |
278 | return false; | 289 | return false; |
279 | } | 290 | } |
280 | 291 | ||
292 | + public boolean contains(IpAddress address) { | ||
293 | + // Need to get the network address because prefixes aren't automatically | ||
294 | + // masked on creation | ||
295 | + IpPrefix meMasked = network(); | ||
296 | + | ||
297 | + IpPrefix otherMasked = | ||
298 | + IpPrefix.valueOf(address.octets, netmask).network(); | ||
299 | + | ||
300 | + return Arrays.equals(meMasked.octets, otherMasked.octets); | ||
301 | + } | ||
302 | + | ||
281 | @Override | 303 | @Override |
282 | public int hashCode() { | 304 | public int hashCode() { |
283 | final int prime = 31; | 305 | final int prime = 31; |
... | @@ -303,6 +325,7 @@ public final class IpPrefix { | ... | @@ -303,6 +325,7 @@ public final class IpPrefix { |
303 | if (netmask != other.netmask) { | 325 | if (netmask != other.netmask) { |
304 | return false; | 326 | return false; |
305 | } | 327 | } |
328 | + // TODO not quite right until we mask the input | ||
306 | if (!Arrays.equals(octets, other.octets)) { | 329 | if (!Arrays.equals(octets, other.octets)) { |
307 | return false; | 330 | return false; |
308 | } | 331 | } | ... | ... |
... | @@ -76,7 +76,7 @@ public class IpPrefixTest { | ... | @@ -76,7 +76,7 @@ public class IpPrefixTest { |
76 | } | 76 | } |
77 | 77 | ||
78 | @Test | 78 | @Test |
79 | - public void testContains() { | 79 | + public void testContainsIpPrefix() { |
80 | IpPrefix slash31 = IpPrefix.valueOf(BYTES1, 31); | 80 | IpPrefix slash31 = IpPrefix.valueOf(BYTES1, 31); |
81 | IpPrefix slash32 = IpPrefix.valueOf(BYTES1, 32); | 81 | IpPrefix slash32 = IpPrefix.valueOf(BYTES1, 32); |
82 | IpPrefix differentSlash32 = IpPrefix.valueOf(BYTES2, 32); | 82 | IpPrefix differentSlash32 = IpPrefix.valueOf(BYTES2, 32); |
... | @@ -96,4 +96,17 @@ public class IpPrefixTest { | ... | @@ -96,4 +96,17 @@ public class IpPrefixTest { |
96 | assertTrue(slash8.contains(slash31)); | 96 | assertTrue(slash8.contains(slash31)); |
97 | assertFalse(slash31.contains(slash8)); | 97 | assertFalse(slash31.contains(slash8)); |
98 | } | 98 | } |
99 | + | ||
100 | + @Test | ||
101 | + public void testContainsIpAddress() { | ||
102 | + IpPrefix slash31 = IpPrefix.valueOf(BYTES1, 31); | ||
103 | + IpAddress slash32 = IpAddress.valueOf(BYTES1, 32); | ||
104 | + | ||
105 | + assertTrue(slash31.contains(slash32)); | ||
106 | + | ||
107 | + IpPrefix intf = IpPrefix.valueOf("192.168.10.101/24"); | ||
108 | + IpAddress addr = IpAddress.valueOf("192.168.10.1"); | ||
109 | + | ||
110 | + assertTrue(intf.contains(addr)); | ||
111 | + } | ||
99 | } | 112 | } | ... | ... |
... | @@ -42,7 +42,6 @@ | ... | @@ -42,7 +42,6 @@ |
42 | <dependency> | 42 | <dependency> |
43 | <groupId>commons-pool</groupId> | 43 | <groupId>commons-pool</groupId> |
44 | <artifactId>commons-pool</artifactId> | 44 | <artifactId>commons-pool</artifactId> |
45 | - <version>1.6</version> | ||
46 | </dependency> | 45 | </dependency> |
47 | </dependencies> | 46 | </dependencies> |
48 | 47 | ... | ... |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import java.util.concurrent.TimeUnit; | ||
4 | +import java.util.concurrent.TimeoutException; | ||
5 | + | ||
6 | +/** | ||
7 | + * An asynchronous response. | ||
8 | + * This class provides a base implementation of Response, with methods to retrieve the | ||
9 | + * result and query to see if the result is ready. The result can only be retrieved when | ||
10 | + * it is ready and the get methods will block if the result is not ready yet. | ||
11 | + * @param <T> type of response. | ||
12 | + */ | ||
13 | +public class AsyncResponse<T> implements Response<T> { | ||
14 | + | ||
15 | + private T value; | ||
16 | + private boolean done = false; | ||
17 | + private final long start = System.nanoTime(); | ||
18 | + | ||
19 | + @Override | ||
20 | + public T get(long timeout, TimeUnit tu) throws TimeoutException { | ||
21 | + timeout = tu.toNanos(timeout); | ||
22 | + boolean interrupted = false; | ||
23 | + try { | ||
24 | + synchronized (this) { | ||
25 | + while (!done) { | ||
26 | + try { | ||
27 | + long timeRemaining = timeout - (System.nanoTime() - start); | ||
28 | + if (timeRemaining <= 0) { | ||
29 | + throw new TimeoutException("Operation timed out."); | ||
30 | + } | ||
31 | + TimeUnit.NANOSECONDS.timedWait(this, timeRemaining); | ||
32 | + } catch (InterruptedException e) { | ||
33 | + interrupted = true; | ||
34 | + } | ||
35 | + } | ||
36 | + } | ||
37 | + } finally { | ||
38 | + if (interrupted) { | ||
39 | + Thread.currentThread().interrupt(); | ||
40 | + } | ||
41 | + } | ||
42 | + return value; | ||
43 | + } | ||
44 | + | ||
45 | + @Override | ||
46 | + public T get() throws InterruptedException { | ||
47 | + throw new UnsupportedOperationException(); | ||
48 | + } | ||
49 | + | ||
50 | + @Override | ||
51 | + public boolean isReady() { | ||
52 | + return done; | ||
53 | + } | ||
54 | + | ||
55 | + /** | ||
56 | + * Sets response value and unblocks any thread blocking on the response to become | ||
57 | + * available. | ||
58 | + * @param data response data. | ||
59 | + */ | ||
60 | + @SuppressWarnings("unchecked") | ||
61 | + public synchronized void setResponse(Object data) { | ||
62 | + if (!done) { | ||
63 | + done = true; | ||
64 | + value = (T) data; | ||
65 | + this.notifyAll(); | ||
66 | + } | ||
67 | + } | ||
68 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | + | ||
5 | +/** | ||
6 | + * Message handler that echos the message back to the sender. | ||
7 | + */ | ||
8 | +public class EchoHandler implements MessageHandler { | ||
9 | + | ||
10 | + @Override | ||
11 | + public void handle(Message message) throws IOException { | ||
12 | + System.out.println("Received: " + message.payload() + ". Echoing it back to the sender."); | ||
13 | + message.respond(message.payload()); | ||
14 | + } | ||
15 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +/** | ||
4 | + * Representation of a TCP/UDP communication end point. | ||
5 | + */ | ||
6 | +public class Endpoint { | ||
7 | + | ||
8 | + private final int port; | ||
9 | + private final String host; | ||
10 | + | ||
11 | + public Endpoint(String host, int port) { | ||
12 | + this.host = host; | ||
13 | + this.port = port; | ||
14 | + } | ||
15 | + | ||
16 | + public String host() { | ||
17 | + return host; | ||
18 | + } | ||
19 | + | ||
20 | + public int port() { | ||
21 | + return port; | ||
22 | + } | ||
23 | + | ||
24 | + @Override | ||
25 | + public String toString() { | ||
26 | + return "Endpoint [port=" + port + ", host=" + host + "]"; | ||
27 | + } | ||
28 | + | ||
29 | + @Override | ||
30 | + public int hashCode() { | ||
31 | + final int prime = 31; | ||
32 | + int result = 1; | ||
33 | + result = prime * result + ((host == null) ? 0 : host.hashCode()); | ||
34 | + result = prime * result + port; | ||
35 | + return result; | ||
36 | + } | ||
37 | + | ||
38 | + @Override | ||
39 | + public boolean equals(Object obj) { | ||
40 | + if (this == obj) { | ||
41 | + return true; | ||
42 | + } | ||
43 | + if (obj == null) { | ||
44 | + return false; | ||
45 | + } | ||
46 | + if (getClass() != obj.getClass()) { | ||
47 | + return false; | ||
48 | + } | ||
49 | + Endpoint other = (Endpoint) obj; | ||
50 | + if (host == null) { | ||
51 | + if (other.host != null) { | ||
52 | + return false; | ||
53 | + } | ||
54 | + } else if (!host.equals(other.host)) { | ||
55 | + return false; | ||
56 | + } | ||
57 | + if (port != other.port) { | ||
58 | + return false; | ||
59 | + } | ||
60 | + return true; | ||
61 | + } | ||
62 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | + | ||
5 | +/** | ||
6 | + * Internal message representation with additional attributes | ||
7 | + * for supporting, synchronous request/reply behavior. | ||
8 | + */ | ||
9 | +public final class InternalMessage implements Message { | ||
10 | + | ||
11 | + private long id; | ||
12 | + private Endpoint sender; | ||
13 | + private String type; | ||
14 | + private Object payload; | ||
15 | + private transient NettyMessagingService messagingService; | ||
16 | + public static final String REPLY_MESSAGE_TYPE = "NETTY_MESSAGIG_REQUEST_REPLY"; | ||
17 | + | ||
18 | + // Must be created using the Builder. | ||
19 | + private InternalMessage() {} | ||
20 | + | ||
21 | + public long id() { | ||
22 | + return id; | ||
23 | + } | ||
24 | + | ||
25 | + public String type() { | ||
26 | + return type; | ||
27 | + } | ||
28 | + | ||
29 | + public Endpoint sender() { | ||
30 | + return sender; | ||
31 | + } | ||
32 | + | ||
33 | + @Override | ||
34 | + public Object payload() { | ||
35 | + return payload; | ||
36 | + } | ||
37 | + | ||
38 | + @Override | ||
39 | + public void respond(Object data) throws IOException { | ||
40 | + Builder builder = new Builder(messagingService); | ||
41 | + InternalMessage message = builder.withId(this.id) | ||
42 | + // FIXME: Sender should be messagingService.localEp. | ||
43 | + .withSender(this.sender) | ||
44 | + .withPayload(data) | ||
45 | + .withType(REPLY_MESSAGE_TYPE) | ||
46 | + .build(); | ||
47 | + messagingService.sendAsync(sender, message); | ||
48 | + } | ||
49 | + | ||
50 | + | ||
51 | + /** | ||
52 | + * Builder for InternalMessages. | ||
53 | + */ | ||
54 | + public static class Builder { | ||
55 | + private InternalMessage message; | ||
56 | + | ||
57 | + public Builder(NettyMessagingService messagingService) { | ||
58 | + message = new InternalMessage(); | ||
59 | + message.messagingService = messagingService; | ||
60 | + } | ||
61 | + | ||
62 | + public Builder withId(long id) { | ||
63 | + message.id = id; | ||
64 | + return this; | ||
65 | + } | ||
66 | + | ||
67 | + public Builder withType(String type) { | ||
68 | + message.type = type; | ||
69 | + return this; | ||
70 | + } | ||
71 | + | ||
72 | + public Builder withSender(Endpoint sender) { | ||
73 | + message.sender = sender; | ||
74 | + return this; | ||
75 | + } | ||
76 | + public Builder withPayload(Object payload) { | ||
77 | + message.payload = payload; | ||
78 | + return this; | ||
79 | + } | ||
80 | + | ||
81 | + public InternalMessage build() { | ||
82 | + return message; | ||
83 | + } | ||
84 | + } | ||
85 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import org.onlab.util.KryoPool; | ||
4 | +import org.slf4j.Logger; | ||
5 | +import org.slf4j.LoggerFactory; | ||
6 | + | ||
7 | +import java.util.ArrayList; | ||
8 | +import java.util.HashMap; | ||
9 | + | ||
10 | +/** | ||
11 | + * Kryo Serializer. | ||
12 | + */ | ||
13 | +public class KryoSerializer implements Serializer { | ||
14 | + | ||
15 | + private final Logger log = LoggerFactory.getLogger(getClass()); | ||
16 | + | ||
17 | + private KryoPool serializerPool; | ||
18 | + | ||
19 | + public KryoSerializer() { | ||
20 | + setupKryoPool(); | ||
21 | + } | ||
22 | + | ||
23 | + /** | ||
24 | + * Sets up the common serialzers pool. | ||
25 | + */ | ||
26 | + protected void setupKryoPool() { | ||
27 | + // FIXME Slice out types used in common to separate pool/namespace. | ||
28 | + serializerPool = KryoPool.newBuilder() | ||
29 | + .register(ArrayList.class, | ||
30 | + HashMap.class, | ||
31 | + ArrayList.class | ||
32 | + ) | ||
33 | + .build() | ||
34 | + .populate(1); | ||
35 | + } | ||
36 | + | ||
37 | + | ||
38 | + @Override | ||
39 | + public Object decode(byte[] data) { | ||
40 | + return serializerPool.deserialize(data); | ||
41 | + } | ||
42 | + | ||
43 | + @Override | ||
44 | + public byte[] encode(Object payload) { | ||
45 | + return serializerPool.serialize(payload); | ||
46 | + } | ||
47 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | + | ||
5 | +/** | ||
6 | + * A unit of communication. | ||
7 | + * Has a payload. Also supports a feature to respond back to the sender. | ||
8 | + */ | ||
9 | +public interface Message { | ||
10 | + | ||
11 | + /** | ||
12 | + * Returns the payload of this message. | ||
13 | + * @return message payload. | ||
14 | + */ | ||
15 | + public Object payload(); | ||
16 | + | ||
17 | + /** | ||
18 | + * Sends a reply back to the sender of this messge. | ||
19 | + * @param data payload of the response. | ||
20 | + * @throws IOException if there is a communication error. | ||
21 | + */ | ||
22 | + public void respond(Object data) throws IOException; | ||
23 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import java.util.Arrays; | ||
4 | +import java.util.List; | ||
5 | + | ||
6 | +import static com.google.common.base.Preconditions.checkState; | ||
7 | + | ||
8 | +import io.netty.buffer.ByteBuf; | ||
9 | +import io.netty.channel.ChannelHandlerContext; | ||
10 | +import io.netty.handler.codec.ByteToMessageDecoder; | ||
11 | + | ||
12 | +/** | ||
13 | + * Decode bytes into a InternalMessage. | ||
14 | + */ | ||
15 | +public class MessageDecoder extends ByteToMessageDecoder { | ||
16 | + | ||
17 | + private final NettyMessagingService messagingService; | ||
18 | + private final Serializer serializer; | ||
19 | + | ||
20 | + public MessageDecoder(NettyMessagingService messagingService, Serializer serializer) { | ||
21 | + this.messagingService = messagingService; | ||
22 | + this.serializer = serializer; | ||
23 | + } | ||
24 | + | ||
25 | + @Override | ||
26 | + protected void decode(ChannelHandlerContext context, ByteBuf in, | ||
27 | + List<Object> messages) throws Exception { | ||
28 | + | ||
29 | + byte[] preamble = in.readBytes(MessageEncoder.PREAMBLE.length).array(); | ||
30 | + checkState(Arrays.equals(MessageEncoder.PREAMBLE, preamble), "Message has wrong preamble"); | ||
31 | + | ||
32 | + // read message Id. | ||
33 | + long id = in.readLong(); | ||
34 | + | ||
35 | + // read message type; first read size and then bytes. | ||
36 | + String type = new String(in.readBytes(in.readInt()).array()); | ||
37 | + | ||
38 | + // read sender host name; first read size and then bytes. | ||
39 | + String host = new String(in.readBytes(in.readInt()).array()); | ||
40 | + | ||
41 | + // read sender port. | ||
42 | + int port = in.readInt(); | ||
43 | + | ||
44 | + Endpoint sender = new Endpoint(host, port); | ||
45 | + | ||
46 | + // read message payload; first read size and then bytes. | ||
47 | + Object payload = serializer.decode(in.readBytes(in.readInt()).array()); | ||
48 | + | ||
49 | + InternalMessage message = new InternalMessage.Builder(messagingService) | ||
50 | + .withId(id) | ||
51 | + .withSender(sender) | ||
52 | + .withType(type) | ||
53 | + .withPayload(payload) | ||
54 | + .build(); | ||
55 | + | ||
56 | + messages.add(message); | ||
57 | + } | ||
58 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import io.netty.buffer.ByteBuf; | ||
4 | +import io.netty.channel.ChannelHandlerContext; | ||
5 | +import io.netty.handler.codec.MessageToByteEncoder; | ||
6 | + | ||
7 | +/** | ||
8 | + * Encode InternalMessage out into a byte buffer. | ||
9 | + */ | ||
10 | +public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { | ||
11 | + | ||
12 | + // onosiscool in ascii | ||
13 | + public static final byte[] PREAMBLE = "onosiscool".getBytes(); | ||
14 | + | ||
15 | + private final Serializer serializer; | ||
16 | + | ||
17 | + public MessageEncoder(Serializer serializer) { | ||
18 | + this.serializer = serializer; | ||
19 | + } | ||
20 | + | ||
21 | + @Override | ||
22 | + protected void encode(ChannelHandlerContext context, InternalMessage message, | ||
23 | + ByteBuf out) throws Exception { | ||
24 | + | ||
25 | + // write preamble | ||
26 | + out.writeBytes(PREAMBLE); | ||
27 | + | ||
28 | + // write id | ||
29 | + out.writeLong(message.id()); | ||
30 | + | ||
31 | + // write type length | ||
32 | + out.writeInt(message.type().length()); | ||
33 | + | ||
34 | + // write type | ||
35 | + out.writeBytes(message.type().getBytes()); | ||
36 | + | ||
37 | + // write sender host name size | ||
38 | + out.writeInt(message.sender().host().length()); | ||
39 | + | ||
40 | + // write sender host name. | ||
41 | + out.writeBytes(message.sender().host().getBytes()); | ||
42 | + | ||
43 | + // write port | ||
44 | + out.writeInt(message.sender().port()); | ||
45 | + | ||
46 | + try { | ||
47 | + serializer.encode(message.payload()); | ||
48 | + } catch (Exception e) { | ||
49 | + e.printStackTrace(); | ||
50 | + } | ||
51 | + | ||
52 | + byte[] payload = serializer.encode(message.payload()); | ||
53 | + | ||
54 | + // write payload length. | ||
55 | + out.writeInt(payload.length); | ||
56 | + | ||
57 | + // write payload bytes | ||
58 | + out.writeBytes(payload); | ||
59 | + } | ||
60 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | + | ||
5 | +/** | ||
6 | + * Handler for a message. | ||
7 | + */ | ||
8 | +public interface MessageHandler { | ||
9 | + | ||
10 | + /** | ||
11 | + * Handles the message. | ||
12 | + * @param message message. | ||
13 | + * @throws IOException. | ||
14 | + */ | ||
15 | + public void handle(Message message) throws IOException; | ||
16 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | + | ||
5 | +/** | ||
6 | + * Interface for low level messaging primitives. | ||
7 | + */ | ||
8 | +public interface MessagingService { | ||
9 | + /** | ||
10 | + * Sends a message asynchronously to the specified communication end point. | ||
11 | + * The message is specified using the type and payload. | ||
12 | + * @param ep end point to send the message to. | ||
13 | + * @param type type of message. | ||
14 | + * @param payload message payload. | ||
15 | + * @throws IOException | ||
16 | + */ | ||
17 | + public void sendAsync(Endpoint ep, String type, Object payload) throws IOException; | ||
18 | + | ||
19 | + /** | ||
20 | + * Sends a message synchronously and waits for a response. | ||
21 | + * @param ep end point to send the message to. | ||
22 | + * @param type type of message. | ||
23 | + * @param payload message payload. | ||
24 | + * @return a response future | ||
25 | + * @throws IOException | ||
26 | + */ | ||
27 | + public <T> Response<T> sendAndReceive(Endpoint ep, String type, Object payload) throws IOException; | ||
28 | + | ||
29 | + /** | ||
30 | + * Registers a new message handler for message type. | ||
31 | + * @param type message type. | ||
32 | + * @param handler message handler | ||
33 | + */ | ||
34 | + public void registerHandler(String type, MessageHandler handler); | ||
35 | + | ||
36 | + /** | ||
37 | + * Unregister current handler, if one exists for message type. | ||
38 | + * @param type message type | ||
39 | + */ | ||
40 | + public void unregisterHandler(String type); | ||
41 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import java.io.IOException; | ||
4 | +import java.net.UnknownHostException; | ||
5 | +import java.util.concurrent.ConcurrentHashMap; | ||
6 | +import java.util.concurrent.ConcurrentMap; | ||
7 | +import java.util.concurrent.TimeUnit; | ||
8 | + | ||
9 | +import io.netty.bootstrap.Bootstrap; | ||
10 | +import io.netty.bootstrap.ServerBootstrap; | ||
11 | +import io.netty.buffer.PooledByteBufAllocator; | ||
12 | +import io.netty.channel.Channel; | ||
13 | +import io.netty.channel.ChannelFuture; | ||
14 | +import io.netty.channel.ChannelHandlerContext; | ||
15 | +import io.netty.channel.ChannelInitializer; | ||
16 | +import io.netty.channel.ChannelOption; | ||
17 | +import io.netty.channel.EventLoopGroup; | ||
18 | +import io.netty.channel.SimpleChannelInboundHandler; | ||
19 | +import io.netty.channel.nio.NioEventLoopGroup; | ||
20 | +import io.netty.channel.socket.SocketChannel; | ||
21 | +import io.netty.channel.socket.nio.NioServerSocketChannel; | ||
22 | +import io.netty.channel.socket.nio.NioSocketChannel; | ||
23 | + | ||
24 | +import org.apache.commons.lang.math.RandomUtils; | ||
25 | +import org.apache.commons.pool.KeyedObjectPool; | ||
26 | +import org.apache.commons.pool.KeyedPoolableObjectFactory; | ||
27 | +import org.apache.commons.pool.impl.GenericKeyedObjectPool; | ||
28 | +import org.slf4j.Logger; | ||
29 | +import org.slf4j.LoggerFactory; | ||
30 | + | ||
31 | +import com.google.common.cache.Cache; | ||
32 | +import com.google.common.cache.CacheBuilder; | ||
33 | + | ||
34 | +/** | ||
35 | + * A Netty based implementation of MessagingService. | ||
36 | + */ | ||
37 | +public class NettyMessagingService implements MessagingService { | ||
38 | + | ||
39 | + private final Logger log = LoggerFactory.getLogger(getClass()); | ||
40 | + | ||
41 | + private KeyedObjectPool<Endpoint, Channel> channels = | ||
42 | + new GenericKeyedObjectPool<Endpoint, Channel>(new OnosCommunicationChannelFactory()); | ||
43 | + private final int port; | ||
44 | + private final EventLoopGroup bossGroup = new NioEventLoopGroup(); | ||
45 | + private final EventLoopGroup workerGroup = new NioEventLoopGroup(); | ||
46 | + private final ConcurrentMap<String, MessageHandler> handlers = new ConcurrentHashMap<>(); | ||
47 | + private Cache<Long, AsyncResponse<?>> responseFutures; | ||
48 | + private final Endpoint localEp; | ||
49 | + | ||
50 | + protected Serializer serializer; | ||
51 | + | ||
52 | + public NettyMessagingService() { | ||
53 | + // TODO: Default port should be configurable. | ||
54 | + this(8080); | ||
55 | + } | ||
56 | + | ||
57 | + // FIXME: Constructor should not throw exceptions. | ||
58 | + public NettyMessagingService(int port) { | ||
59 | + this.port = port; | ||
60 | + try { | ||
61 | + localEp = new Endpoint(java.net.InetAddress.getLocalHost().getHostName(), port); | ||
62 | + } catch (UnknownHostException e) { | ||
63 | + // bailing out. | ||
64 | + throw new RuntimeException(e); | ||
65 | + } | ||
66 | + } | ||
67 | + | ||
68 | + public void activate() throws Exception { | ||
69 | + responseFutures = CacheBuilder.newBuilder() | ||
70 | + .maximumSize(100000) | ||
71 | + .weakValues() | ||
72 | + // TODO: Once the entry expires, notify blocking threads (if any). | ||
73 | + .expireAfterWrite(10, TimeUnit.MINUTES) | ||
74 | + .build(); | ||
75 | + startAcceptingConnections(); | ||
76 | + } | ||
77 | + | ||
78 | + public void deactivate() throws Exception { | ||
79 | + channels.close(); | ||
80 | + bossGroup.shutdownGracefully(); | ||
81 | + workerGroup.shutdownGracefully(); | ||
82 | + } | ||
83 | + | ||
84 | + @Override | ||
85 | + public void sendAsync(Endpoint ep, String type, Object payload) throws IOException { | ||
86 | + InternalMessage message = new InternalMessage.Builder(this) | ||
87 | + .withId(RandomUtils.nextLong()) | ||
88 | + .withSender(localEp) | ||
89 | + .withType(type) | ||
90 | + .withPayload(payload) | ||
91 | + .build(); | ||
92 | + sendAsync(ep, message); | ||
93 | + } | ||
94 | + | ||
95 | + protected void sendAsync(Endpoint ep, InternalMessage message) throws IOException { | ||
96 | + Channel channel = null; | ||
97 | + try { | ||
98 | + channel = channels.borrowObject(ep); | ||
99 | + channel.eventLoop().execute(new WriteTask(channel, message)); | ||
100 | + } catch (Exception e) { | ||
101 | + throw new IOException(e); | ||
102 | + } finally { | ||
103 | + try { | ||
104 | + channels.returnObject(ep, channel); | ||
105 | + } catch (Exception e) { | ||
106 | + log.warn("Error returning object back to the pool", e); | ||
107 | + // ignored. | ||
108 | + } | ||
109 | + } | ||
110 | + } | ||
111 | + | ||
112 | + @Override | ||
113 | + public <T> Response<T> sendAndReceive(Endpoint ep, String type, Object payload) | ||
114 | + throws IOException { | ||
115 | + AsyncResponse<T> futureResponse = new AsyncResponse<T>(); | ||
116 | + Long messageId = RandomUtils.nextLong(); | ||
117 | + responseFutures.put(messageId, futureResponse); | ||
118 | + InternalMessage message = new InternalMessage.Builder(this) | ||
119 | + .withId(messageId) | ||
120 | + .withSender(localEp) | ||
121 | + .withType(type) | ||
122 | + .withPayload(payload) | ||
123 | + .build(); | ||
124 | + sendAsync(ep, message); | ||
125 | + return futureResponse; | ||
126 | + } | ||
127 | + | ||
128 | + @Override | ||
129 | + public void registerHandler(String type, MessageHandler handler) { | ||
130 | + // TODO: Is this the right semantics for handler registration? | ||
131 | + handlers.putIfAbsent(type, handler); | ||
132 | + } | ||
133 | + | ||
134 | + public void unregisterHandler(String type) { | ||
135 | + handlers.remove(type); | ||
136 | + } | ||
137 | + | ||
138 | + private MessageHandler getMessageHandler(String type) { | ||
139 | + return handlers.get(type); | ||
140 | + } | ||
141 | + | ||
142 | + private void startAcceptingConnections() throws InterruptedException { | ||
143 | + ServerBootstrap b = new ServerBootstrap(); | ||
144 | + b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); | ||
145 | + b.group(bossGroup, workerGroup) | ||
146 | + .channel(NioServerSocketChannel.class) | ||
147 | + .childHandler(new OnosCommunicationChannelInitializer()) | ||
148 | + .option(ChannelOption.SO_BACKLOG, 128) | ||
149 | + .childOption(ChannelOption.SO_KEEPALIVE, true); | ||
150 | + | ||
151 | + // Bind and start to accept incoming connections. | ||
152 | + b.bind(port).sync(); | ||
153 | + } | ||
154 | + | ||
155 | + private class OnosCommunicationChannelFactory | ||
156 | + implements KeyedPoolableObjectFactory<Endpoint, Channel> { | ||
157 | + | ||
158 | + @Override | ||
159 | + public void activateObject(Endpoint endpoint, Channel channel) | ||
160 | + throws Exception { | ||
161 | + } | ||
162 | + | ||
163 | + @Override | ||
164 | + public void destroyObject(Endpoint ep, Channel channel) throws Exception { | ||
165 | + channel.close(); | ||
166 | + } | ||
167 | + | ||
168 | + @Override | ||
169 | + public Channel makeObject(Endpoint ep) throws Exception { | ||
170 | + Bootstrap b = new Bootstrap(); | ||
171 | + b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); | ||
172 | + b.group(workerGroup); | ||
173 | + // TODO: Make this faster: | ||
174 | + // http://normanmaurer.me/presentations/2014-facebook-eng-netty/slides.html#37.0 | ||
175 | + b.channel(NioSocketChannel.class); | ||
176 | + b.option(ChannelOption.SO_KEEPALIVE, true); | ||
177 | + b.handler(new OnosCommunicationChannelInitializer()); | ||
178 | + | ||
179 | + // Start the client. | ||
180 | + ChannelFuture f = b.connect(ep.host(), ep.port()).sync(); | ||
181 | + return f.channel(); | ||
182 | + } | ||
183 | + | ||
184 | + @Override | ||
185 | + public void passivateObject(Endpoint ep, Channel channel) | ||
186 | + throws Exception { | ||
187 | + } | ||
188 | + | ||
189 | + @Override | ||
190 | + public boolean validateObject(Endpoint ep, Channel channel) { | ||
191 | + return channel.isOpen(); | ||
192 | + } | ||
193 | + } | ||
194 | + | ||
195 | + private class OnosCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> { | ||
196 | + | ||
197 | + @Override | ||
198 | + protected void initChannel(SocketChannel channel) throws Exception { | ||
199 | + channel.pipeline() | ||
200 | + .addLast(new MessageEncoder(serializer)) | ||
201 | + .addLast(new MessageDecoder(NettyMessagingService.this, serializer)) | ||
202 | + .addLast(new NettyMessagingService.InboundMessageDispatcher()); | ||
203 | + } | ||
204 | + } | ||
205 | + | ||
206 | + private class WriteTask implements Runnable { | ||
207 | + | ||
208 | + private final Object message; | ||
209 | + private final Channel channel; | ||
210 | + | ||
211 | + public WriteTask(Channel channel, Object message) { | ||
212 | + this.message = message; | ||
213 | + this.channel = channel; | ||
214 | + } | ||
215 | + | ||
216 | + @Override | ||
217 | + public void run() { | ||
218 | + channel.writeAndFlush(message); | ||
219 | + } | ||
220 | + } | ||
221 | + | ||
222 | + private class InboundMessageDispatcher extends SimpleChannelInboundHandler<InternalMessage> { | ||
223 | + | ||
224 | + @Override | ||
225 | + protected void channelRead0(ChannelHandlerContext ctx, InternalMessage message) throws Exception { | ||
226 | + String type = message.type(); | ||
227 | + if (type.equals(InternalMessage.REPLY_MESSAGE_TYPE)) { | ||
228 | + try { | ||
229 | + AsyncResponse<?> futureResponse = | ||
230 | + NettyMessagingService.this.responseFutures.getIfPresent(message.id()); | ||
231 | + if (futureResponse != null) { | ||
232 | + futureResponse.setResponse(message.payload()); | ||
233 | + } | ||
234 | + log.warn("Received a reply. But was unable to locate the request handle"); | ||
235 | + } finally { | ||
236 | + NettyMessagingService.this.responseFutures.invalidate(message.id()); | ||
237 | + } | ||
238 | + return; | ||
239 | + } | ||
240 | + MessageHandler handler = NettyMessagingService.this.getMessageHandler(type); | ||
241 | + handler.handle(message); | ||
242 | + } | ||
243 | + } | ||
244 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import java.util.concurrent.TimeUnit; | ||
4 | +import java.util.concurrent.TimeoutException; | ||
5 | + | ||
6 | +/** | ||
7 | + * Response object returned when making synchronous requests. | ||
8 | + * Can you used to check is a response is ready and/or wait for a response | ||
9 | + * to become available. | ||
10 | + * | ||
11 | + * @param <T> type of response. | ||
12 | + */ | ||
13 | +public interface Response<T> { | ||
14 | + | ||
15 | + /** | ||
16 | + * Gets the response waiting for a designated timeout period. | ||
17 | + * @param timeout timeout period (since request was sent out) | ||
18 | + * @param tu unit of time. | ||
19 | + * @return response | ||
20 | + * @throws TimeoutException if the timeout expires before the response arrives. | ||
21 | + */ | ||
22 | + public T get(long timeout, TimeUnit tu) throws TimeoutException; | ||
23 | + | ||
24 | + /** | ||
25 | + * Gets the response waiting for indefinite timeout period. | ||
26 | + * @return response | ||
27 | + * @throws InterruptedException if the thread is interrupted before the response arrives. | ||
28 | + */ | ||
29 | + public T get() throws InterruptedException; | ||
30 | + | ||
31 | + /** | ||
32 | + * Checks if the response is ready without blocking. | ||
33 | + * @return true if response is ready, false otherwise. | ||
34 | + */ | ||
35 | + public boolean isReady(); | ||
36 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +/** | ||
4 | + * Interface for encoding/decoding message payloads. | ||
5 | + */ | ||
6 | +public interface Serializer { | ||
7 | + | ||
8 | + /** | ||
9 | + * Decodes the specified byte array to a POJO. | ||
10 | + * | ||
11 | + * @param data byte array. | ||
12 | + * @return POJO | ||
13 | + */ | ||
14 | + Object decode(byte[] data); | ||
15 | + | ||
16 | + /** | ||
17 | + * Encodes the specified POJO into a byte array. | ||
18 | + * | ||
19 | + * @param data POJO to be encoded | ||
20 | + * @return byte array. | ||
21 | + */ | ||
22 | + byte[] encode(Object message); | ||
23 | + | ||
24 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +import java.util.concurrent.TimeUnit; | ||
4 | + | ||
5 | +public final class SimpleClient { | ||
6 | + private SimpleClient() {} | ||
7 | + | ||
8 | + public static void main(String... args) throws Exception { | ||
9 | + NettyMessagingService messaging = new TestNettyMessagingService(9081); | ||
10 | + messaging.activate(); | ||
11 | + | ||
12 | + messaging.sendAsync(new Endpoint("localhost", 8080), "simple", "Hello World"); | ||
13 | + Response<String> response = messaging.sendAndReceive(new Endpoint("localhost", 8080), "echo", "Hello World"); | ||
14 | + System.out.println("Got back:" + response.get(2, TimeUnit.SECONDS)); | ||
15 | + } | ||
16 | + | ||
17 | + public static class TestNettyMessagingService extends NettyMessagingService { | ||
18 | + public TestNettyMessagingService(int port) throws Exception { | ||
19 | + super(port); | ||
20 | + Serializer serializer = new KryoSerializer(); | ||
21 | + this.serializer = serializer; | ||
22 | + } | ||
23 | + } | ||
24 | +} |
1 | +package org.onlab.netty; | ||
2 | + | ||
3 | +public final class SimpleServer { | ||
4 | + private SimpleServer() {} | ||
5 | + | ||
6 | + public static void main(String... args) throws Exception { | ||
7 | + NettyMessagingService server = new TestNettyMessagingService(); | ||
8 | + server.activate(); | ||
9 | + server.registerHandler("simple", new LoggingHandler()); | ||
10 | + server.registerHandler("echo", new EchoHandler()); | ||
11 | + } | ||
12 | + | ||
13 | + public static class TestNettyMessagingService extends NettyMessagingService { | ||
14 | + protected TestNettyMessagingService() { | ||
15 | + Serializer serializer = new KryoSerializer(); | ||
16 | + this.serializer = serializer; | ||
17 | + } | ||
18 | + } | ||
19 | +} |
-
Please register or login to post a comment