alshabib

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 60 changed files with 1428 additions and 191 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 }
......
1 package org.onlab.onos.net.intent; 1 package org.onlab.onos.net.intent;
2 +//TODO is this the right package?
2 3
3 import static com.google.common.base.Preconditions.checkNotNull; 4 import static com.google.common.base.Preconditions.checkNotNull;
4 5
......
1 package org.onlab.onos.net.intent; 1 package org.onlab.onos.net.intent;
2 +//TODO is this the right package?
2 3
3 import java.util.Objects; 4 import java.util.Objects;
4 5
......
1 package org.onlab.onos.net.intent; 1 package org.onlab.onos.net.intent;
2 +//TODO is this the right package?
2 3
3 /** 4 /**
4 * An interface of the class which is assigned to BatchOperation. 5 * An interface of the class which is assigned to BatchOperation.
......
1 +package org.onlab.onos.net.intent;
2 +//TODO is this the right package?
3 +
4 +/**
5 + * A generalized interface for ID generation
6 + *
7 + * {@link #getNewId()} generates a globally unique ID instance on
8 + * each invocation.
9 + *
10 + * @param <T> the type of ID
11 + */
12 +// TODO: do we need to define a base marker interface for ID,
13 +// then changed the type parameter to <T extends BaseId> something
14 +// like that?
15 +public interface IdGenerator<T> {
16 + /**
17 + * Returns a globally unique ID instance.
18 + *
19 + * @return globally unique ID instance
20 + */
21 + T getNewId();
22 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import java.util.Set;
4 +
5 +import org.onlab.onos.net.ConnectPoint;
6 +import org.onlab.onos.net.DeviceId;
7 +import org.onlab.onos.net.PortNumber;
8 +import org.onlab.onos.net.flow.DefaultTrafficSelector;
9 +import org.onlab.onos.net.flow.DefaultTrafficTreatment;
10 +import org.onlab.onos.net.flow.TrafficSelector;
11 +import org.onlab.onos.net.flow.TrafficTreatment;
12 +
13 +/**
14 + * Base facilities to test various connectivity tests.
15 + */
16 +public abstract class ConnectivityIntentTest extends IntentTest {
17 +
18 + public static final IntentId IID = new IntentId(123);
19 + public static final TrafficSelector MATCH = (new DefaultTrafficSelector.Builder()).build();
20 + public static final TrafficTreatment NOP = (new DefaultTrafficTreatment.Builder()).build();
21 +
22 + public static final ConnectPoint P1 = new ConnectPoint(DeviceId.deviceId("111"), PortNumber.portNumber(0x1));
23 + public static final ConnectPoint P2 = new ConnectPoint(DeviceId.deviceId("222"), PortNumber.portNumber(0x2));
24 + public static final ConnectPoint P3 = new ConnectPoint(DeviceId.deviceId("333"), PortNumber.portNumber(0x3));
25 +
26 + public static final Set<ConnectPoint> PS1 = itemSet(new ConnectPoint[]{P1, P3});
27 + public static final Set<ConnectPoint> PS2 = itemSet(new ConnectPoint[]{P2, P3});
28 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import java.util.ArrayList;
4 +import java.util.Collections;
5 +import java.util.HashMap;
6 +import java.util.HashSet;
7 +import java.util.List;
8 +import java.util.Map;
9 +import java.util.Set;
10 +import java.util.concurrent.ExecutorService;
11 +import java.util.concurrent.Executors;
12 +
13 +/**
14 + * Fake implementation of the intent service to assist in developing tests
15 + * of the interface contract.
16 + */
17 +public class FakeIntentManager implements TestableIntentService {
18 +
19 + private final Map<IntentId, Intent> intents = new HashMap<>();
20 + private final Map<IntentId, IntentState> intentStates = new HashMap<>();
21 + private final Map<IntentId, List<InstallableIntent>> installables = new HashMap<>();
22 + private final Set<IntentEventListener> listeners = new HashSet<>();
23 +
24 + private final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers = new HashMap<>();
25 + private final Map<Class<? extends InstallableIntent>,
26 + IntentInstaller<? extends InstallableIntent>> installers = new HashMap<>();
27 +
28 + private final ExecutorService executor = Executors.newSingleThreadExecutor();
29 + private final List<IntentException> exceptions = new ArrayList<>();
30 +
31 + @Override
32 + public List<IntentException> getExceptions() {
33 + return exceptions;
34 + }
35 +
36 + // Provides an out-of-thread simulation of intent submit life-cycle
37 + private void executeSubmit(final Intent intent) {
38 + registerSubclassCompilerIfNeeded(intent);
39 + executor.execute(new Runnable() {
40 + @Override
41 + public void run() {
42 + try {
43 + List<InstallableIntent> installable = compileIntent(intent);
44 + installIntents(intent, installable);
45 + } catch (IntentException e) {
46 + exceptions.add(e);
47 + }
48 + }
49 + });
50 + }
51 +
52 + // Provides an out-of-thread simulation of intent withdraw life-cycle
53 + private void executeWithdraw(final Intent intent) {
54 + executor.execute(new Runnable() {
55 + @Override
56 + public void run() {
57 + try {
58 + List<InstallableIntent> installable = getInstallable(intent.getId());
59 + uninstallIntents(intent, installable);
60 + } catch (IntentException e) {
61 + exceptions.add(e);
62 + }
63 +
64 + }
65 + });
66 + }
67 +
68 + private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
69 + @SuppressWarnings("unchecked")
70 + IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
71 + if (compiler == null) {
72 + throw new IntentException("no compiler for class " + intent.getClass());
73 + }
74 + return compiler;
75 + }
76 +
77 + private <T extends InstallableIntent> IntentInstaller<T> getInstaller(T intent) {
78 + @SuppressWarnings("unchecked")
79 + IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
80 + if (installer == null) {
81 + throw new IntentException("no installer for class " + intent.getClass());
82 + }
83 + return installer;
84 + }
85 +
86 + private <T extends Intent> List<InstallableIntent> compileIntent(T intent) {
87 + try {
88 + // For the fake, we compile using a single level pass
89 + List<InstallableIntent> installable = new ArrayList<>();
90 + for (Intent compiled : getCompiler(intent).compile(intent)) {
91 + installable.add((InstallableIntent) compiled);
92 + }
93 + setState(intent, IntentState.COMPILED);
94 + return installable;
95 + } catch (IntentException e) {
96 + setState(intent, IntentState.FAILED);
97 + throw e;
98 + }
99 + }
100 +
101 + private void installIntents(Intent intent, List<InstallableIntent> installable) {
102 + try {
103 + for (InstallableIntent ii : installable) {
104 + registerSubclassInstallerIfNeeded(ii);
105 + getInstaller(ii).install(ii);
106 + }
107 + setState(intent, IntentState.INSTALLED);
108 + putInstallable(intent.getId(), installable);
109 + } catch (IntentException e) {
110 + setState(intent, IntentState.FAILED);
111 + throw e;
112 + }
113 + }
114 +
115 + private void uninstallIntents(Intent intent, List<InstallableIntent> installable) {
116 + try {
117 + for (InstallableIntent ii : installable) {
118 + getInstaller(ii).uninstall(ii);
119 + }
120 + setState(intent, IntentState.WITHDRAWN);
121 + removeInstallable(intent.getId());
122 + } catch (IntentException e) {
123 + setState(intent, IntentState.FAILED);
124 + throw e;
125 + }
126 + }
127 +
128 +
129 + // Sets the internal state for the given intent and dispatches an event
130 + private void setState(Intent intent, IntentState state) {
131 + IntentState previous = intentStates.get(intent.getId());
132 + intentStates.put(intent.getId(), state);
133 + dispatch(new IntentEvent(intent, state, previous, System.currentTimeMillis()));
134 + }
135 +
136 + private void putInstallable(IntentId id, List<InstallableIntent> installable) {
137 + installables.put(id, installable);
138 + }
139 +
140 + private void removeInstallable(IntentId id) {
141 + installables.remove(id);
142 + }
143 +
144 + private List<InstallableIntent> getInstallable(IntentId id) {
145 + List<InstallableIntent> installable = installables.get(id);
146 + if (installable != null) {
147 + return installable;
148 + } else {
149 + return Collections.emptyList();
150 + }
151 + }
152 +
153 + @Override
154 + public void submit(Intent intent) {
155 + intents.put(intent.getId(), intent);
156 + setState(intent, IntentState.SUBMITTED);
157 + executeSubmit(intent);
158 + }
159 +
160 + @Override
161 + public void withdraw(Intent intent) {
162 + intents.remove(intent.getId());
163 + setState(intent, IntentState.WITHDRAWING);
164 + executeWithdraw(intent);
165 + }
166 +
167 + @Override
168 + public void execute(IntentOperations operations) {
169 + // TODO: implement later
170 + }
171 +
172 + @Override
173 + public Set<Intent> getIntents() {
174 + return Collections.unmodifiableSet(new HashSet<>(intents.values()));
175 + }
176 +
177 + @Override
178 + public Intent getIntent(IntentId id) {
179 + return intents.get(id);
180 + }
181 +
182 + @Override
183 + public IntentState getIntentState(IntentId id) {
184 + return intentStates.get(id);
185 + }
186 +
187 + @Override
188 + public void addListener(IntentEventListener listener) {
189 + listeners.add(listener);
190 + }
191 +
192 + @Override
193 + public void removeListener(IntentEventListener listener) {
194 + listeners.remove(listener);
195 + }
196 +
197 + private void dispatch(IntentEvent event) {
198 + for (IntentEventListener listener : listeners) {
199 + listener.event(event);
200 + }
201 + }
202 +
203 + @Override
204 + public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
205 + compilers.put(cls, compiler);
206 + }
207 +
208 + @Override
209 + public <T extends Intent> void unregisterCompiler(Class<T> cls) {
210 + compilers.remove(cls);
211 + }
212 +
213 + @Override
214 + public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
215 + return Collections.unmodifiableMap(compilers);
216 + }
217 +
218 + @Override
219 + public <T extends InstallableIntent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
220 + installers.put(cls, installer);
221 + }
222 +
223 + @Override
224 + public <T extends InstallableIntent> void unregisterInstaller(Class<T> cls) {
225 + installers.remove(cls);
226 + }
227 +
228 + @Override
229 + public Map<Class<? extends InstallableIntent>,
230 + IntentInstaller<? extends InstallableIntent>> getInstallers() {
231 + return Collections.unmodifiableMap(installers);
232 + }
233 +
234 + private void registerSubclassCompilerIfNeeded(Intent intent) {
235 + if (!compilers.containsKey(intent.getClass())) {
236 + Class<?> cls = intent.getClass();
237 + while (cls != Object.class) {
238 + // As long as we're within the Intent class descendants
239 + if (Intent.class.isAssignableFrom(cls)) {
240 + IntentCompiler<?> compiler = compilers.get(cls);
241 + if (compiler != null) {
242 + compilers.put(intent.getClass(), compiler);
243 + return;
244 + }
245 + }
246 + cls = cls.getSuperclass();
247 + }
248 + }
249 + }
250 +
251 + private void registerSubclassInstallerIfNeeded(InstallableIntent intent) {
252 + if (!installers.containsKey(intent.getClass())) {
253 + Class<?> cls = intent.getClass();
254 + while (cls != Object.class) {
255 + // As long as we're within the InstallableIntent class descendants
256 + if (InstallableIntent.class.isAssignableFrom(cls)) {
257 + IntentInstaller<?> installer = installers.get(cls);
258 + if (installer != null) {
259 + installers.put(intent.getClass(), installer);
260 + return;
261 + }
262 + }
263 + cls = cls.getSuperclass();
264 + }
265 + }
266 + }
267 +
268 +}
1 +package org.onlab.onos.net.intent;
2 +//TODO is this the right package?
3 +
4 +import org.hamcrest.Description;
5 +import org.hamcrest.StringDescription;
6 +
7 +import java.lang.reflect.Field;
8 +import java.lang.reflect.Method;
9 +import java.lang.reflect.Modifier;
10 +
11 +/**
12 + * Hamcrest style class for verifying that a class follows the
13 + * accepted rules for immutable classes.
14 + *
15 + * The rules that are enforced for immutable classes:
16 + * - the class must be declared final
17 + * - all data members of the class must be declared private and final
18 + * - the class must not define any setter methods
19 + */
20 +
21 +public class ImmutableClassChecker {
22 +
23 + private String failureReason = "";
24 +
25 + /**
26 + * Method to determine if a given class is a properly specified
27 + * immutable class.
28 + *
29 + * @param clazz the class to check
30 + * @return true if the given class is a properly specified immutable class.
31 + */
32 + private boolean isImmutableClass(Class<?> clazz) {
33 + // class must be declared final
34 + if (!Modifier.isFinal(clazz.getModifiers())) {
35 + failureReason = "a class that is not final";
36 + return false;
37 + }
38 +
39 + // class must have only final and private data members
40 + for (final Field field : clazz.getDeclaredFields()) {
41 + if (field.getName().startsWith("__cobertura")) {
42 + // cobertura sticks these fields into classes - ignore them
43 + continue;
44 + }
45 + if (!Modifier.isFinal(field.getModifiers())) {
46 + failureReason = "a field named '" + field.getName() +
47 + "' that is not final";
48 + return false;
49 + }
50 + if (!Modifier.isPrivate(field.getModifiers())) {
51 + //
52 + // NOTE: We relax the recommended rules for defining immutable
53 + // objects and allow "static final" fields that are not
54 + // private. The "final" check was already done above so we
55 + // don't repeat it here.
56 + //
57 + if (!Modifier.isStatic(field.getModifiers())) {
58 + failureReason = "a field named '" + field.getName() +
59 + "' that is not private and is not static";
60 + return false;
61 + }
62 + }
63 + }
64 +
65 + // class must not define any setters
66 + for (final Method method : clazz.getMethods()) {
67 + if (method.getDeclaringClass().equals(clazz)) {
68 + if (method.getName().startsWith("set")) {
69 + failureReason = "a class with a setter named '" + method.getName() + "'";
70 + return false;
71 + }
72 + }
73 + }
74 +
75 + return true;
76 + }
77 +
78 + /**
79 + * Describe why an error was reported. Uses Hamcrest style Description
80 + * interfaces.
81 + *
82 + * @param description the Description object to use for reporting the
83 + * mismatch
84 + */
85 + public void describeMismatch(Description description) {
86 + description.appendText(failureReason);
87 + }
88 +
89 + /**
90 + * Describe the source object that caused an error, using a Hamcrest
91 + * Matcher style interface. In this case, it always returns
92 + * that we are looking for a properly defined utility class.
93 + *
94 + * @param description the Description object to use to report the "to"
95 + * object
96 + */
97 + public void describeTo(Description description) {
98 + description.appendText("a properly defined immutable class");
99 + }
100 +
101 + /**
102 + * Assert that the given class adheres to the utility class rules.
103 + *
104 + * @param clazz the class to check
105 + *
106 + * @throws java.lang.AssertionError if the class is not a valid
107 + * utility class
108 + */
109 + public static void assertThatClassIsImmutable(Class<?> clazz) {
110 + final ImmutableClassChecker checker = new ImmutableClassChecker();
111 + if (!checker.isImmutableClass(clazz)) {
112 + final Description toDescription = new StringDescription();
113 + final Description mismatchDescription = new StringDescription();
114 +
115 + checker.describeTo(toDescription);
116 + checker.describeMismatch(mismatchDescription);
117 + final String reason =
118 + "\n" +
119 + "Expected: is \"" + toDescription.toString() + "\"\n" +
120 + " but : was \"" + mismatchDescription.toString() + "\"";
121 +
122 + throw new AssertionError(reason);
123 + }
124 + }
125 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import org.junit.Test;
4 +
5 +import static org.junit.Assert.assertEquals;
6 +
7 +/**
8 + * Test of the intent exception.
9 + */
10 +public class IntentExceptionTest {
11 +
12 + @Test
13 + public void basics() {
14 + validate(new IntentException(), null, null);
15 + validate(new IntentException("foo"), "foo", null);
16 +
17 + Throwable cause = new NullPointerException("bar");
18 + validate(new IntentException("foo", cause), "foo", cause);
19 + }
20 +
21 + /**
22 + * Validates that the specified exception has the correct message and cause.
23 + *
24 + * @param e exception to test
25 + * @param message expected message
26 + * @param cause expected cause
27 + */
28 + protected void validate(RuntimeException e, String message, Throwable cause) {
29 + assertEquals("incorrect message", message, e.getMessage());
30 + assertEquals("incorrect cause", cause, e.getCause());
31 + }
32 +
33 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +/**
4 + * This interface is for generator of IntentId. It is defined only for
5 + * testing purpose to keep type safety on mock creation.
6 + *
7 + * <p>
8 + * {@link #getNewId()} generates a globally unique {@link IntentId} instance
9 + * on each invocation. Application developers should not generate IntentId
10 + * by themselves. Instead use an implementation of this interface.
11 + * </p>
12 + */
13 +public interface IntentIdGenerator extends IdGenerator<IntentId> {
14 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import org.junit.Test;
4 +
5 +import static org.hamcrest.Matchers.is;
6 +import static org.hamcrest.Matchers.not;
7 +import static org.junit.Assert.assertEquals;
8 +import static org.junit.Assert.assertThat;
9 +
10 +/**
11 + * This class tests the immutability, equality, and non-equality of
12 + * {@link IntentId}.
13 + */
14 +public class IntentIdTest {
15 + /**
16 + * Tests the immutability of {@link IntentId}.
17 + */
18 + @Test
19 + public void intentIdFollowsGuidelineForImmutableObject() {
20 + ImmutableClassChecker.assertThatClassIsImmutable(IntentId.class);
21 + }
22 +
23 + /**
24 + * Tests equality of {@link IntentId}.
25 + */
26 + @Test
27 + public void testEquality() {
28 + IntentId id1 = new IntentId(1L);
29 + IntentId id2 = new IntentId(1L);
30 +
31 + assertThat(id1, is(id2));
32 + }
33 +
34 + /**
35 + * Tests non-equality of {@link IntentId}.
36 + */
37 + @Test
38 + public void testNonEquality() {
39 + IntentId id1 = new IntentId(1L);
40 + IntentId id2 = new IntentId(2L);
41 +
42 + assertThat(id1, is(not(id2)));
43 + }
44 +
45 + @Test
46 + public void valueOf() {
47 + IntentId id = new IntentId(12345);
48 + assertEquals("incorrect valueOf", id, IntentId.valueOf("12345"));
49 + }
50 +
51 + @Test
52 + public void valueOfHex() {
53 + IntentId id = new IntentId(0xdeadbeefL);
54 + assertEquals("incorrect valueOf", id, IntentId.valueOf(id.toString()));
55 + }
56 +
57 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import static org.junit.Assert.assertEquals;
4 +import static org.junit.Assert.assertFalse;
5 +import static org.junit.Assert.assertTrue;
6 +
7 +import java.util.Arrays;
8 +import java.util.HashSet;
9 +import java.util.Set;
10 +
11 +import org.junit.Test;
12 +
13 +/**
14 + * Base facilities to test various intent tests.
15 + */
16 +public abstract class IntentTest {
17 + /**
18 + * Produces a set of items from the supplied items.
19 + *
20 + * @param items items to be placed in set
21 + * @param <T> item type
22 + * @return set of items
23 + */
24 + protected static <T> Set<T> itemSet(T[] items) {
25 + return new HashSet<>(Arrays.asList(items));
26 + }
27 +
28 + @Test
29 + public void equalsAndHashCode() {
30 + Intent one = createOne();
31 + Intent like = createOne();
32 + Intent another = createAnother();
33 +
34 + assertTrue("should be equal", one.equals(like));
35 + assertEquals("incorrect hashCode", one.hashCode(), like.hashCode());
36 +
37 + assertFalse("should not be equal", one.equals(another));
38 +
39 + assertFalse("should not be equal", one.equals(null));
40 + assertFalse("should not be equal", one.equals("foo"));
41 + }
42 +
43 + @Test
44 + public void testToString() {
45 + Intent one = createOne();
46 + Intent like = createOne();
47 + assertEquals("incorrect toString", one.toString(), like.toString());
48 + }
49 +
50 + /**
51 + * Creates a new intent, but always a like intent, i.e. all instances will
52 + * be equal, but should not be the same.
53 + *
54 + * @return intent
55 + */
56 + protected abstract Intent createOne();
57 +
58 + /**
59 + * Creates another intent, not equals to the one created by
60 + * {@link #createOne()} and with a different hash code.
61 + *
62 + * @return another intent
63 + */
64 + protected abstract Intent createAnother();
65 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import org.junit.Test;
4 +
5 +import static org.junit.Assert.assertEquals;
6 +
7 +/**
8 + * Suite of tests of the multi-to-single point intent descriptor.
9 + */
10 +public class MultiPointToSinglePointIntentTest extends ConnectivityIntentTest {
11 +
12 + @Test
13 + public void basics() {
14 + MultiPointToSinglePointIntent intent = createOne();
15 + assertEquals("incorrect id", IID, intent.getId());
16 + assertEquals("incorrect match", MATCH, intent.getTrafficSelector());
17 + assertEquals("incorrect ingress", PS1, intent.getIngressPorts());
18 + assertEquals("incorrect egress", P2, intent.getEgressPort());
19 + }
20 +
21 + @Override
22 + protected MultiPointToSinglePointIntent createOne() {
23 + return new MultiPointToSinglePointIntent(IID, MATCH, NOP, PS1, P2);
24 + }
25 +
26 + @Override
27 + protected MultiPointToSinglePointIntent createAnother() {
28 + return new MultiPointToSinglePointIntent(IID, MATCH, NOP, PS2, P1);
29 + }
30 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import static org.junit.Assert.assertEquals;
4 +
5 +import org.junit.Test;
6 +import org.onlab.onos.net.NetTestTools;
7 +import org.onlab.onos.net.Path;
8 +
9 +public class PathIntentTest extends ConnectivityIntentTest {
10 + // 111:11 --> 222:22
11 + private static final Path PATH1 = NetTestTools.createPath("111", "222");
12 +
13 + // 111:11 --> 333:33
14 + private static final Path PATH2 = NetTestTools.createPath("222", "333");
15 +
16 + @Test
17 + public void basics() {
18 + PathIntent intent = createOne();
19 + assertEquals("incorrect id", IID, intent.getId());
20 + assertEquals("incorrect match", MATCH, intent.getTrafficSelector());
21 + assertEquals("incorrect action", NOP, intent.getTrafficTreatment());
22 + assertEquals("incorrect ingress", P1, intent.getIngressPort());
23 + assertEquals("incorrect egress", P2, intent.getEgressPort());
24 + assertEquals("incorrect path", PATH1, intent.getPath());
25 + }
26 +
27 + @Override
28 + protected PathIntent createOne() {
29 + return new PathIntent(IID, MATCH, NOP, P1, P2, PATH1);
30 + }
31 +
32 + @Override
33 + protected PathIntent createAnother() {
34 + return new PathIntent(IID, MATCH, NOP, P1, P3, PATH2);
35 + }
36 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import org.junit.Test;
4 +
5 +import static org.junit.Assert.assertEquals;
6 +
7 +/**
8 + * Suite of tests of the point-to-point intent descriptor.
9 + */
10 +public class PointToPointIntentTest extends ConnectivityIntentTest {
11 +
12 + @Test
13 + public void basics() {
14 + PointToPointIntent intent = createOne();
15 + assertEquals("incorrect id", IID, intent.getId());
16 + assertEquals("incorrect match", MATCH, intent.getTrafficSelector());
17 + assertEquals("incorrect ingress", P1, intent.getIngressPort());
18 + assertEquals("incorrect egress", P2, intent.getEgressPort());
19 + }
20 +
21 + @Override
22 + protected PointToPointIntent createOne() {
23 + return new PointToPointIntent(IID, MATCH, NOP, P1, P2);
24 + }
25 +
26 + @Override
27 + protected PointToPointIntent createAnother() {
28 + return new PointToPointIntent(IID, MATCH, NOP, P2, P1);
29 + }
30 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import org.junit.Test;
4 +
5 +import static org.junit.Assert.assertEquals;
6 +
7 +/**
8 + * Suite of tests of the single-to-multi point intent descriptor.
9 + */
10 +public class SinglePointToMultiPointIntentTest extends ConnectivityIntentTest {
11 +
12 + @Test
13 + public void basics() {
14 + SinglePointToMultiPointIntent intent = createOne();
15 + assertEquals("incorrect id", IID, intent.getId());
16 + assertEquals("incorrect match", MATCH, intent.getTrafficSelector());
17 + assertEquals("incorrect ingress", P1, intent.getIngressPort());
18 + assertEquals("incorrect egress", PS2, intent.getEgressPorts());
19 + }
20 +
21 + @Override
22 + protected SinglePointToMultiPointIntent createOne() {
23 + return new SinglePointToMultiPointIntent(IID, MATCH, NOP, P1, PS2);
24 + }
25 +
26 + @Override
27 + protected SinglePointToMultiPointIntent createAnother() {
28 + return new SinglePointToMultiPointIntent(IID, MATCH, NOP, P2, PS1);
29 + }
30 +}
1 +package org.onlab.onos.net.intent;
2 +//TODO is this the right package?
3 +
4 +/**
5 + * An installable intent used in the unit test.
6 + *
7 + * FIXME: we don't want to expose this class publicly, but the current Kryo
8 + * serialization mechanism does not allow this class to be private and placed
9 + * on testing directory.
10 + */
11 +public class TestInstallableIntent extends AbstractIntent implements InstallableIntent {
12 + /**
13 + * Constructs an instance with the specified intent ID.
14 + *
15 + * @param id intent ID
16 + */
17 + public TestInstallableIntent(IntentId id) {
18 + super(id);
19 + }
20 +
21 + /**
22 + * Constructor for serializer.
23 + */
24 + protected TestInstallableIntent() {
25 + super();
26 + }
27 +
28 +}
1 +package org.onlab.onos.net.intent;
2 +//TODO is this the right package?
3 +
4 +/**
5 + * An intent used in the unit test.
6 + *
7 + * FIXME: we don't want to expose this class publicly, but the current Kryo
8 + * serialization mechanism does not allow this class to be private and placed
9 + * on testing directory.
10 + */
11 +public class TestIntent extends AbstractIntent {
12 + /**
13 + * Constructs an instance with the specified intent ID.
14 + *
15 + * @param id intent ID
16 + */
17 + public TestIntent(IntentId id) {
18 + super(id);
19 + }
20 +
21 + /**
22 + * Constructor for serializer.
23 + */
24 + protected TestIntent() {
25 + super();
26 + }
27 +}
1 +package org.onlab.onos.net.intent;
2 +//TODO is this the right package?
3 +
4 +/**
5 + * An intent used in the unit test.
6 + *
7 + * FIXME: we don't want to expose this class publicly, but the current Kryo
8 + * serialization mechanism does not allow this class to be private and placed
9 + * on testing directory.
10 + */
11 +public class TestSubclassInstallableIntent extends TestInstallableIntent implements InstallableIntent {
12 + /**
13 + * Constructs an instance with the specified intent ID.
14 + *
15 + * @param id intent ID
16 + */
17 + public TestSubclassInstallableIntent(IntentId id) {
18 + super(id);
19 + }
20 +
21 + /**
22 + * Constructor for serializer.
23 + */
24 + protected TestSubclassInstallableIntent() {
25 + super();
26 + }
27 +}
1 +package org.onlab.onos.net.intent;
2 +//TODO is this the right package?
3 +
4 +/**
5 + * An intent used in the unit test.
6 + *
7 + * FIXME: we don't want to expose this class publicly, but the current Kryo
8 + * serialization mechanism does not allow this class to be private and placed
9 + * on testing directory.
10 + */
11 +public class TestSubclassIntent extends TestIntent {
12 + /**
13 + * Constructs an instance with the specified intent ID.
14 + *
15 + * @param id intent ID
16 + */
17 + public TestSubclassIntent(IntentId id) {
18 + super(id);
19 + }
20 +
21 + /**
22 + * Constructor for serializer.
23 + */
24 + protected TestSubclassIntent() {
25 + super();
26 + }
27 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import static org.junit.Assert.fail;
4 +
5 +/**
6 + * Set of test tools.
7 + */
8 +public final class TestTools {
9 +
10 + // Disallow construction
11 + private TestTools() {
12 + }
13 +
14 + /**
15 + * Utility method to pause the current thread for the specified number of
16 + * milliseconds.
17 + *
18 + * @param ms number of milliseconds to pause
19 + */
20 + public static void delay(int ms) {
21 + try {
22 + Thread.sleep(ms);
23 + } catch (InterruptedException e) {
24 + fail("unexpected interrupt");
25 + }
26 + }
27 +
28 + /**
29 + * Periodically runs the given runnable, which should contain a series of
30 + * test assertions until all the assertions succeed, in which case it will
31 + * return, or until the the time expires, in which case it will throw the
32 + * first failed assertion error.
33 + *
34 + * @param start start time, in millis since start of epoch from which the
35 + * duration will be measured
36 + * @param delay initial delay (in milliseconds) before the first assertion
37 + * attempt
38 + * @param step delay (in milliseconds) between successive assertion
39 + * attempts
40 + * @param duration number of milliseconds beyond the given start time,
41 + * after which the failed assertions will be propagated and allowed
42 + * to fail the test
43 + * @param assertions runnable housing the test assertions
44 + */
45 + public static void assertAfter(long start, int delay, int step,
46 + int duration, Runnable assertions) {
47 + delay(delay);
48 + while (true) {
49 + try {
50 + assertions.run();
51 + break;
52 + } catch (AssertionError e) {
53 + if (System.currentTimeMillis() - start > duration) {
54 + throw e;
55 + }
56 + }
57 + delay(step);
58 + }
59 + }
60 +
61 + /**
62 + * Periodically runs the given runnable, which should contain a series of
63 + * test assertions until all the assertions succeed, in which case it will
64 + * return, or until the the time expires, in which case it will throw the
65 + * first failed assertion error.
66 + * <p>
67 + * The start of the period is the current time.
68 + *
69 + * @param delay initial delay (in milliseconds) before the first assertion
70 + * attempt
71 + * @param step delay (in milliseconds) between successive assertion
72 + * attempts
73 + * @param duration number of milliseconds beyond the current time time,
74 + * after which the failed assertions will be propagated and allowed
75 + * to fail the test
76 + * @param assertions runnable housing the test assertions
77 + */
78 + public static void assertAfter(int delay, int step, int duration,
79 + Runnable assertions) {
80 + assertAfter(System.currentTimeMillis(), delay, step, duration,
81 + assertions);
82 + }
83 +
84 + /**
85 + * Periodically runs the given runnable, which should contain a series of
86 + * test assertions until all the assertions succeed, in which case it will
87 + * return, or until the the time expires, in which case it will throw the
88 + * first failed assertion error.
89 + * <p>
90 + * The start of the period is the current time and the first assertion
91 + * attempt is delayed by the value of {@code step} parameter.
92 + *
93 + * @param step delay (in milliseconds) between successive assertion
94 + * attempts
95 + * @param duration number of milliseconds beyond the current time time,
96 + * after which the failed assertions will be propagated and allowed
97 + * to fail the test
98 + * @param assertions runnable housing the test assertions
99 + */
100 + public static void assertAfter(int step, int duration,
101 + Runnable assertions) {
102 + assertAfter(step, step, duration, assertions);
103 + }
104 +
105 + /**
106 + * Periodically runs the given runnable, which should contain a series of
107 + * test assertions until all the assertions succeed, in which case it will
108 + * return, or until the the time expires, in which case it will throw the
109 + * first failed assertion error.
110 + * <p>
111 + * The start of the period is the current time and each successive
112 + * assertion attempt is delayed by at least 10 milliseconds unless the
113 + * {@code duration} is less than that, in which case the one and only
114 + * assertion is made after that delay.
115 + *
116 + * @param duration number of milliseconds beyond the current time,
117 + * after which the failed assertions will be propagated and allowed
118 + * to fail the test
119 + * @param assertions runnable housing the test assertions
120 + */
121 + public static void assertAfter(int duration, Runnable assertions) {
122 + int step = Math.min(duration, Math.max(10, duration / 10));
123 + assertAfter(step, duration, assertions);
124 + }
125 +
126 +}
1 +package org.onlab.onos.net.intent;
2 +
3 +import java.util.List;
4 +
5 +/**
6 + * Abstraction of an extensible intent service enabled for unit tests.
7 + */
8 +public interface TestableIntentService extends IntentService, IntentExtensionService {
9 +
10 + List<IntentException> getExceptions();
11 +
12 +}
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 &amp; NB APIs. 42 * Provides basic implementation of the host SB &amp; 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;
......
...@@ -35,6 +35,12 @@ ...@@ -35,6 +35,12 @@
35 </dependency> 35 </dependency>
36 36
37 <dependency> 37 <dependency>
38 + <groupId>org.onlab.onos</groupId>
39 + <artifactId>onlab-netty</artifactId>
40 + <version>${project.version}</version>
41 + </dependency>
42 +
43 + <dependency>
38 <groupId>com.fasterxml.jackson.core</groupId> 44 <groupId>com.fasterxml.jackson.core</groupId>
39 <artifactId>jackson-databind</artifactId> 45 <artifactId>jackson-databind</artifactId>
40 </dependency> 46 </dependency>
...@@ -51,15 +57,6 @@ ...@@ -51,15 +57,6 @@
51 <groupId>de.javakaffee</groupId> 57 <groupId>de.javakaffee</groupId>
52 <artifactId>kryo-serializers</artifactId> 58 <artifactId>kryo-serializers</artifactId>
53 </dependency> 59 </dependency>
54 - <dependency>
55 - <groupId>io.netty</groupId>
56 - <artifactId>netty-all</artifactId>
57 - </dependency>
58 - <dependency>
59 - <groupId>commons-pool</groupId>
60 - <artifactId>commons-pool</artifactId>
61 - <version>1.6</version>
62 - </dependency>
63 </dependencies> 60 </dependencies>
64 61
65 <build> 62 <build>
......
...@@ -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
......
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 -}
...@@ -23,16 +23,16 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService; ...@@ -23,16 +23,16 @@ import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
23 import org.onlab.onos.store.cluster.messaging.ClusterMessage; 23 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
24 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler; 24 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
25 import org.onlab.onos.store.cluster.messaging.MessageSubject; 25 import org.onlab.onos.store.cluster.messaging.MessageSubject;
26 -import org.onlab.onos.store.messaging.Endpoint; 26 +import org.onlab.netty.Endpoint;
27 -import org.onlab.onos.store.messaging.Message; 27 +import org.onlab.netty.Message;
28 -import org.onlab.onos.store.messaging.MessageHandler; 28 +import org.onlab.netty.MessageHandler;
29 -import org.onlab.onos.store.messaging.MessagingService; 29 +import org.onlab.netty.MessagingService;
30 import org.slf4j.Logger; 30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory; 31 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());
......
...@@ -6,8 +6,8 @@ import org.junit.Ignore; ...@@ -6,8 +6,8 @@ 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.onos.store.messaging.impl.NettyMessagingService; 10 +import org.onlab.netty.NettyMessagingService;
11 import org.onlab.packet.IpPrefix; 11 import org.onlab.packet.IpPrefix;
12 12
13 import java.util.concurrent.CountDownLatch; 13 import java.util.concurrent.CountDownLatch;
...@@ -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
......
...@@ -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 /**
......
...@@ -48,6 +48,19 @@ ...@@ -48,6 +48,19 @@
48 </dependency> 48 </dependency>
49 49
50 <dependency> 50 <dependency>
51 + <groupId>org.hamcrest</groupId>
52 + <artifactId>hamcrest-core</artifactId>
53 + <version>1.3</version>
54 + <scope>test</scope>
55 + </dependency>
56 + <dependency>
57 + <groupId>org.hamcrest</groupId>
58 + <artifactId>hamcrest-library</artifactId>
59 + <version>1.3</version>
60 + <scope>test</scope>
61 + </dependency>
62 +
63 + <dependency>
51 <groupId>org.slf4j</groupId> 64 <groupId>org.slf4j</groupId>
52 <artifactId>slf4j-api</artifactId> 65 <artifactId>slf4j-api</artifactId>
53 <version>1.7.6</version> 66 <version>1.7.6</version>
...@@ -235,6 +248,11 @@ ...@@ -235,6 +248,11 @@
235 <classifier>tests</classifier> 248 <classifier>tests</classifier>
236 <scope>test</scope> 249 <scope>test</scope>
237 </dependency> 250 </dependency>
251 + <dependency>
252 + <groupId>commons-pool</groupId>
253 + <artifactId>commons-pool</artifactId>
254 + <version>1.6</version>
255 + </dependency>
238 </dependencies> 256 </dependencies>
239 </dependencyManagement> 257 </dependencyManagement>
240 258
...@@ -244,6 +262,14 @@ ...@@ -244,6 +262,14 @@
244 <artifactId>junit</artifactId> 262 <artifactId>junit</artifactId>
245 </dependency> 263 </dependency>
246 <dependency> 264 <dependency>
265 + <groupId>org.hamcrest</groupId>
266 + <artifactId>hamcrest-core</artifactId>
267 + </dependency>
268 + <dependency>
269 + <groupId>org.hamcrest</groupId>
270 + <artifactId>hamcrest-library</artifactId>
271 + </dependency>
272 + <dependency>
247 <groupId>org.slf4j</groupId> 273 <groupId>org.slf4j</groupId>
248 <artifactId>slf4j-jdk14</artifactId> 274 <artifactId>slf4j-jdk14</artifactId>
249 </dependency> 275 </dependency>
...@@ -320,6 +346,35 @@ ...@@ -320,6 +346,35 @@
320 </plugin> 346 </plugin>
321 347
322 <!-- TODO: add findbugs plugin for static code analysis; for explicit invocation only --> 348 <!-- TODO: add findbugs plugin for static code analysis; for explicit invocation only -->
349 + <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
350 + <plugin>
351 + <groupId>org.eclipse.m2e</groupId>
352 + <artifactId>lifecycle-mapping</artifactId>
353 + <version>1.0.0</version>
354 + <configuration>
355 + <lifecycleMappingMetadata>
356 + <pluginExecutions>
357 + <pluginExecution>
358 + <pluginExecutionFilter>
359 + <groupId>org.jacoco</groupId>
360 + <artifactId>
361 + jacoco-maven-plugin
362 + </artifactId>
363 + <versionRange>
364 + [0.7.1.201405082137,)
365 + </versionRange>
366 + <goals>
367 + <goal>prepare-agent</goal>
368 + </goals>
369 + </pluginExecutionFilter>
370 + <action>
371 + <ignore></ignore>
372 + </action>
373 + </pluginExecution>
374 + </pluginExecutions>
375 + </lifecycleMappingMetadata>
376 + </configuration>
377 + </plugin>
323 </plugins> 378 </plugins>
324 </pluginManagement> 379 </pluginManagement>
325 380
......
...@@ -6,5 +6,10 @@ ...@@ -6,5 +6,10 @@
6 <groupId>org.onlab.tools</groupId> 6 <groupId>org.onlab.tools</groupId>
7 <artifactId>onos-build-conf</artifactId> 7 <artifactId>onos-build-conf</artifactId>
8 <version>1.0</version> 8 <version>1.0</version>
9 +
10 + <properties>
11 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
12 + </properties>
13 +
9 </project> 14 </project>
10 15
......
...@@ -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 }
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5 + <modelVersion>4.0.0</modelVersion>
6 +
7 + <parent>
8 + <groupId>org.onlab.onos</groupId>
9 + <artifactId>onlab-utils</artifactId>
10 + <version>1.0.0-SNAPSHOT</version>
11 + <relativePath>../pom.xml</relativePath>
12 + </parent>
13 +
14 + <artifactId>onlab-netty</artifactId>
15 + <packaging>bundle</packaging>
16 +
17 + <description>Network I/O using Netty framework</description>
18 +
19 + <dependencies>
20 + <dependency>
21 + <groupId>com.google.guava</groupId>
22 + <artifactId>guava-testlib</artifactId>
23 + <scope>test</scope>
24 + </dependency>
25 + <dependency>
26 + <groupId>org.onlab.onos</groupId>
27 + <artifactId>onlab-misc</artifactId>
28 + </dependency>
29 + <dependency>
30 + <groupId>org.onlab.onos</groupId>
31 + <artifactId>onlab-junit</artifactId>
32 + <scope>test</scope>
33 + </dependency>
34 + <dependency>
35 + <groupId>de.javakaffee</groupId>
36 + <artifactId>kryo-serializers</artifactId>
37 + </dependency>
38 + <dependency>
39 + <groupId>io.netty</groupId>
40 + <artifactId>netty-all</artifactId>
41 + </dependency>
42 + <dependency>
43 + <groupId>commons-pool</groupId>
44 + <artifactId>commons-pool</artifactId>
45 + </dependency>
46 + </dependencies>
47 +
48 +</project>
1 -package org.onlab.onos.store.messaging.impl; 1 +package org.onlab.netty;
2 2
3 import java.util.concurrent.TimeUnit; 3 import java.util.concurrent.TimeUnit;
4 import java.util.concurrent.TimeoutException; 4 import java.util.concurrent.TimeoutException;
5 5
6 -import org.onlab.onos.store.messaging.Response;
7 -
8 /** 6 /**
9 * An asynchronous response. 7 * An asynchronous response.
10 * This class provides a base implementation of Response, with methods to retrieve the 8 * This class provides a base implementation of Response, with methods to retrieve the
......
1 -package org.onlab.onos.store.messaging.impl; 1 +package org.onlab.netty;
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 4
5 -import org.onlab.onos.store.messaging.Message;
6 -import org.onlab.onos.store.messaging.MessageHandler;
7 -
8 /** 5 /**
9 * Message handler that echos the message back to the sender. 6 * Message handler that echos the message back to the sender.
10 */ 7 */
......
1 -package org.onlab.onos.store.messaging; 1 +package org.onlab.netty;
2 2
3 /** 3 /**
4 * Representation of a TCP/UDP communication end point. 4 * Representation of a TCP/UDP communication end point.
......
1 -package org.onlab.onos.store.messaging.impl; 1 +package org.onlab.netty;
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 4
5 -import org.onlab.onos.store.messaging.Endpoint;
6 -import org.onlab.onos.store.messaging.Message;
7 -
8 /** 5 /**
9 * Internal message representation with additional attributes 6 * Internal message representation with additional attributes
10 * for supporting, synchronous request/reply behavior. 7 * for supporting, synchronous request/reply behavior.
......
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.onos.store.messaging.impl; 1 +package org.onlab.netty;
2 -
3 -import org.onlab.onos.store.messaging.Message;
4 -import org.onlab.onos.store.messaging.MessageHandler;
5 2
6 /** 3 /**
7 * A MessageHandler that simply logs the information. 4 * A MessageHandler that simply logs the information.
......
1 -package org.onlab.onos.store.messaging; 1 +package org.onlab.netty;
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 4
......
1 -package org.onlab.onos.store.messaging.impl; 1 +package org.onlab.netty;
2 2
3 import java.util.Arrays; 3 import java.util.Arrays;
4 import java.util.List; 4 import java.util.List;
5 5
6 import static com.google.common.base.Preconditions.checkState; 6 import static com.google.common.base.Preconditions.checkState;
7 7
8 -import org.onlab.onos.store.cluster.messaging.SerializationService;
9 -import org.onlab.onos.store.messaging.Endpoint;
10 -
11 import io.netty.buffer.ByteBuf; 8 import io.netty.buffer.ByteBuf;
12 import io.netty.channel.ChannelHandlerContext; 9 import io.netty.channel.ChannelHandlerContext;
13 import io.netty.handler.codec.ByteToMessageDecoder; 10 import io.netty.handler.codec.ByteToMessageDecoder;
14 11
15 /** 12 /**
16 - * Decode bytes into a InrenalMessage. 13 + * Decode bytes into a InternalMessage.
17 */ 14 */
18 public class MessageDecoder extends ByteToMessageDecoder { 15 public class MessageDecoder extends ByteToMessageDecoder {
19 16
20 private final NettyMessagingService messagingService; 17 private final NettyMessagingService messagingService;
21 - private final SerializationService serializationService; 18 + private final Serializer serializer;
22 19
23 - public MessageDecoder(NettyMessagingService messagingService, SerializationService serializationService) { 20 + public MessageDecoder(NettyMessagingService messagingService, Serializer serializer) {
24 this.messagingService = messagingService; 21 this.messagingService = messagingService;
25 - this.serializationService = serializationService; 22 + this.serializer = serializer;
26 } 23 }
27 24
28 @Override 25 @Override
...@@ -47,7 +44,7 @@ public class MessageDecoder extends ByteToMessageDecoder { ...@@ -47,7 +44,7 @@ public class MessageDecoder extends ByteToMessageDecoder {
47 Endpoint sender = new Endpoint(host, port); 44 Endpoint sender = new Endpoint(host, port);
48 45
49 // read message payload; first read size and then bytes. 46 // read message payload; first read size and then bytes.
50 - Object payload = serializationService.decode(in.readBytes(in.readInt()).array()); 47 + Object payload = serializer.decode(in.readBytes(in.readInt()).array());
51 48
52 InternalMessage message = new InternalMessage.Builder(messagingService) 49 InternalMessage message = new InternalMessage.Builder(messagingService)
53 .withId(id) 50 .withId(id)
......
1 -package org.onlab.onos.store.messaging.impl; 1 +package org.onlab.netty;
2 -
3 -import org.onlab.onos.store.cluster.messaging.SerializationService;
4 2
5 import io.netty.buffer.ByteBuf; 3 import io.netty.buffer.ByteBuf;
6 import io.netty.channel.ChannelHandlerContext; 4 import io.netty.channel.ChannelHandlerContext;
...@@ -14,10 +12,10 @@ public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { ...@@ -14,10 +12,10 @@ public class MessageEncoder extends MessageToByteEncoder<InternalMessage> {
14 // onosiscool in ascii 12 // onosiscool in ascii
15 public static final byte[] PREAMBLE = "onosiscool".getBytes(); 13 public static final byte[] PREAMBLE = "onosiscool".getBytes();
16 14
17 - private final SerializationService serializationService; 15 + private final Serializer serializer;
18 16
19 - public MessageEncoder(SerializationService serializationService) { 17 + public MessageEncoder(Serializer serializer) {
20 - this.serializationService = serializationService; 18 + this.serializer = serializer;
21 } 19 }
22 20
23 @Override 21 @Override
...@@ -46,12 +44,12 @@ public class MessageEncoder extends MessageToByteEncoder<InternalMessage> { ...@@ -46,12 +44,12 @@ public class MessageEncoder extends MessageToByteEncoder<InternalMessage> {
46 out.writeInt(message.sender().port()); 44 out.writeInt(message.sender().port());
47 45
48 try { 46 try {
49 - serializationService.encode(message.payload()); 47 + serializer.encode(message.payload());
50 } catch (Exception e) { 48 } catch (Exception e) {
51 e.printStackTrace(); 49 e.printStackTrace();
52 } 50 }
53 51
54 - byte[] payload = serializationService.encode(message.payload()); 52 + byte[] payload = serializer.encode(message.payload());
55 53
56 // write payload length. 54 // write payload length.
57 out.writeInt(payload.length); 55 out.writeInt(payload.length);
......
1 -package org.onlab.onos.store.messaging; 1 +package org.onlab.netty;
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 4
......
1 -package org.onlab.onos.store.messaging; 1 +package org.onlab.netty;
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 4
......
1 -package org.onlab.onos.store.messaging.impl; 1 +package org.onlab.netty;
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 import java.net.UnknownHostException; 4 import java.net.UnknownHostException;
...@@ -25,17 +25,6 @@ import org.apache.commons.lang.math.RandomUtils; ...@@ -25,17 +25,6 @@ import org.apache.commons.lang.math.RandomUtils;
25 import org.apache.commons.pool.KeyedObjectPool; 25 import org.apache.commons.pool.KeyedObjectPool;
26 import org.apache.commons.pool.KeyedPoolableObjectFactory; 26 import org.apache.commons.pool.KeyedPoolableObjectFactory;
27 import org.apache.commons.pool.impl.GenericKeyedObjectPool; 27 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
28 -import org.apache.felix.scr.annotations.Activate;
29 -import org.apache.felix.scr.annotations.Component;
30 -import org.apache.felix.scr.annotations.Deactivate;
31 -import org.apache.felix.scr.annotations.Reference;
32 -import org.apache.felix.scr.annotations.ReferenceCardinality;
33 -import org.apache.felix.scr.annotations.Service;
34 -import org.onlab.onos.store.cluster.messaging.SerializationService;
35 -import org.onlab.onos.store.messaging.Endpoint;
36 -import org.onlab.onos.store.messaging.MessageHandler;
37 -import org.onlab.onos.store.messaging.MessagingService;
38 -import org.onlab.onos.store.messaging.Response;
39 import org.slf4j.Logger; 28 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory; 29 import org.slf4j.LoggerFactory;
41 30
...@@ -45,8 +34,6 @@ import com.google.common.cache.CacheBuilder; ...@@ -45,8 +34,6 @@ import com.google.common.cache.CacheBuilder;
45 /** 34 /**
46 * A Netty based implementation of MessagingService. 35 * A Netty based implementation of MessagingService.
47 */ 36 */
48 -@Component(immediate = true)
49 -@Service
50 public class NettyMessagingService implements MessagingService { 37 public class NettyMessagingService implements MessagingService {
51 38
52 private final Logger log = LoggerFactory.getLogger(getClass()); 39 private final Logger log = LoggerFactory.getLogger(getClass());
...@@ -60,8 +47,7 @@ public class NettyMessagingService implements MessagingService { ...@@ -60,8 +47,7 @@ public class NettyMessagingService implements MessagingService {
60 private Cache<Long, AsyncResponse<?>> responseFutures; 47 private Cache<Long, AsyncResponse<?>> responseFutures;
61 private final Endpoint localEp; 48 private final Endpoint localEp;
62 49
63 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 50 + protected Serializer serializer;
64 - protected SerializationService serializationService;
65 51
66 public NettyMessagingService() { 52 public NettyMessagingService() {
67 // TODO: Default port should be configurable. 53 // TODO: Default port should be configurable.
...@@ -79,7 +65,6 @@ public class NettyMessagingService implements MessagingService { ...@@ -79,7 +65,6 @@ public class NettyMessagingService implements MessagingService {
79 } 65 }
80 } 66 }
81 67
82 - @Activate
83 public void activate() throws Exception { 68 public void activate() throws Exception {
84 responseFutures = CacheBuilder.newBuilder() 69 responseFutures = CacheBuilder.newBuilder()
85 .maximumSize(100000) 70 .maximumSize(100000)
...@@ -90,7 +75,6 @@ public class NettyMessagingService implements MessagingService { ...@@ -90,7 +75,6 @@ public class NettyMessagingService implements MessagingService {
90 startAcceptingConnections(); 75 startAcceptingConnections();
91 } 76 }
92 77
93 - @Deactivate
94 public void deactivate() throws Exception { 78 public void deactivate() throws Exception {
95 channels.close(); 79 channels.close();
96 bossGroup.shutdownGracefully(); 80 bossGroup.shutdownGracefully();
...@@ -213,8 +197,8 @@ public class NettyMessagingService implements MessagingService { ...@@ -213,8 +197,8 @@ public class NettyMessagingService implements MessagingService {
213 @Override 197 @Override
214 protected void initChannel(SocketChannel channel) throws Exception { 198 protected void initChannel(SocketChannel channel) throws Exception {
215 channel.pipeline() 199 channel.pipeline()
216 - .addLast(new MessageEncoder(serializationService)) 200 + .addLast(new MessageEncoder(serializer))
217 - .addLast(new MessageDecoder(NettyMessagingService.this, serializationService)) 201 + .addLast(new MessageDecoder(NettyMessagingService.this, serializer))
218 .addLast(new NettyMessagingService.InboundMessageDispatcher()); 202 .addLast(new NettyMessagingService.InboundMessageDispatcher());
219 } 203 }
220 } 204 }
......
1 -package org.onlab.onos.store.messaging; 1 +package org.onlab.netty;
2 2
3 import java.util.concurrent.TimeUnit; 3 import java.util.concurrent.TimeUnit;
4 import java.util.concurrent.TimeoutException; 4 import java.util.concurrent.TimeoutException;
......
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.onos.store.messaging.impl; 1 +package org.onlab.netty;
2 2
3 import java.util.concurrent.TimeUnit; 3 import java.util.concurrent.TimeUnit;
4 4
5 -import org.onlab.onos.store.cluster.impl.MessageSerializer;
6 -import org.onlab.onos.store.messaging.Endpoint;
7 -import org.onlab.onos.store.messaging.Response;
8 -
9 public final class SimpleClient { 5 public final class SimpleClient {
10 private SimpleClient() {} 6 private SimpleClient() {}
11 7
...@@ -21,9 +17,8 @@ public final class SimpleClient { ...@@ -21,9 +17,8 @@ public final class SimpleClient {
21 public static class TestNettyMessagingService extends NettyMessagingService { 17 public static class TestNettyMessagingService extends NettyMessagingService {
22 public TestNettyMessagingService(int port) throws Exception { 18 public TestNettyMessagingService(int port) throws Exception {
23 super(port); 19 super(port);
24 - MessageSerializer mgr = new MessageSerializer(); 20 + Serializer serializer = new KryoSerializer();
25 - mgr.activate(); 21 + this.serializer = serializer;
26 - this.serializationService = mgr;
27 } 22 }
28 } 23 }
29 } 24 }
......
1 -package org.onlab.onos.store.messaging.impl; 1 +package org.onlab.netty;
2 -
3 -import org.onlab.onos.store.cluster.impl.MessageSerializer;
4 2
5 public final class SimpleServer { 3 public final class SimpleServer {
6 private SimpleServer() {} 4 private SimpleServer() {}
...@@ -14,9 +12,8 @@ public final class SimpleServer { ...@@ -14,9 +12,8 @@ public final class SimpleServer {
14 12
15 public static class TestNettyMessagingService extends NettyMessagingService { 13 public static class TestNettyMessagingService extends NettyMessagingService {
16 protected TestNettyMessagingService() { 14 protected TestNettyMessagingService() {
17 - MessageSerializer mgr = new MessageSerializer(); 15 + Serializer serializer = new KryoSerializer();
18 - mgr.activate(); 16 + this.serializer = serializer;
19 - this.serializationService = mgr;
20 } 17 }
21 } 18 }
22 } 19 }
......
1 +/**
2 + * Asynchronous messaging APIs implemented using the Netty framework.
3 + */
4 +package org.onlab.netty;
...\ No newline at end of file ...\ No newline at end of file
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
19 <modules> 19 <modules>
20 <module>junit</module> 20 <module>junit</module>
21 <module>misc</module> 21 <module>misc</module>
22 + <module>netty</module>
22 <module>nio</module> 23 <module>nio</module>
23 <module>osgi</module> 24 <module>osgi</module>
24 <module>rest</module> 25 <module>rest</module>
......