tom

Implementing port update in trivial core.

1 +package org.onlab.onos.net;
2 +
3 +import java.util.Objects;
4 +
5 +import static com.google.common.base.Objects.toStringHelper;
6 +
7 +/**
8 + * Default port implementation.
9 + */
10 +public class DefaultPort implements Port {
11 +
12 + private final Element element;
13 + private final PortNumber number;
14 + private final boolean isEnabled;
15 +
16 + /**
17 + * Creates a network element attributed to the specified provider.
18 + *
19 + * @param element parent network element
20 + * @param number port number
21 + * @param isEnabled indicator whether the port is up and active
22 + */
23 + public DefaultPort(Element element, PortNumber number,
24 + boolean isEnabled) {
25 + this.element = element;
26 + this.number = number;
27 + this.isEnabled = isEnabled;
28 + }
29 +
30 + @Override
31 + public int hashCode() {
32 + return Objects.hash(number, isEnabled);
33 + }
34 +
35 + @Override
36 + public boolean equals(Object obj) {
37 + if (obj instanceof DefaultPort) {
38 + final DefaultPort other = (DefaultPort) obj;
39 + return Objects.equals(this.element.id(), other.element.id()) &&
40 + Objects.equals(this.number, other.number) &&
41 + Objects.equals(this.isEnabled, other.isEnabled);
42 + }
43 + return false;
44 + }
45 +
46 + @Override
47 + public String toString() {
48 + return toStringHelper(this)
49 + .add("element", element.id())
50 + .add("number", number)
51 + .add("isEnabled", isEnabled)
52 + .toString();
53 + }
54 +
55 + @Override
56 + public PortNumber number() {
57 + return number;
58 + }
59 +
60 + @Override
61 + public boolean isEnabled() {
62 + return isEnabled;
63 + }
64 +
65 + @Override
66 + public Element element() {
67 + return element;
68 + }
69 +
70 +}
...@@ -20,11 +20,11 @@ public interface Port { ...@@ -20,11 +20,11 @@ public interface Port {
20 boolean isEnabled(); 20 boolean isEnabled();
21 21
22 /** 22 /**
23 - * Returns the identifier of the network element to which this port belongs. 23 + * Returns the parent network element to which this port belongs.
24 * 24 *
25 * @return parent network element 25 * @return parent network element
26 */ 26 */
27 - Element parent(); 27 + Element element();
28 28
29 // set of port attributes 29 // set of port attributes
30 30
......
...@@ -2,12 +2,15 @@ package org.onlab.onos.net.device; ...@@ -2,12 +2,15 @@ package org.onlab.onos.net.device;
2 2
3 import org.onlab.onos.event.AbstractEvent; 3 import org.onlab.onos.event.AbstractEvent;
4 import org.onlab.onos.net.Device; 4 import org.onlab.onos.net.Device;
5 +import org.onlab.onos.net.Port;
5 6
6 /** 7 /**
7 * Describes infrastructure device event. 8 * Describes infrastructure device event.
8 */ 9 */
9 public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> { 10 public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> {
10 11
12 + private final Port port;
13 +
11 /** 14 /**
12 * Type of device events. 15 * Type of device events.
13 */ 16 */
...@@ -42,7 +45,22 @@ public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> { ...@@ -42,7 +45,22 @@ public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> {
42 * Signifies that the current controller instance relationship has 45 * Signifies that the current controller instance relationship has
43 * changed with respect to a device. 46 * changed with respect to a device.
44 */ 47 */
45 - DEVICE_MASTERSHIP_CHANGED 48 + DEVICE_MASTERSHIP_CHANGED,
49 +
50 + /**
51 + * Signifies that a port has been added.
52 + */
53 + PORT_ADDED,
54 +
55 + /**
56 + * Signifies that a port has been updated.
57 + */
58 + PORT_UPDATED,
59 +
60 + /**
61 + * Signifies that a port has been removed.
62 + */
63 + PORT_REMOVED
46 } 64 }
47 65
48 /** 66 /**
...@@ -53,7 +71,20 @@ public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> { ...@@ -53,7 +71,20 @@ public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> {
53 * @param device event device subject 71 * @param device event device subject
54 */ 72 */
55 public DeviceEvent(Type type, Device device) { 73 public DeviceEvent(Type type, Device device) {
74 + this(type, device, null);
75 + }
76 +
77 + /**
78 + * Creates an event of a given type and for the specified device, port
79 + * and the current time.
80 + *
81 + * @param type device event type
82 + * @param device event device subject
83 + * @param port optional port subject
84 + */
85 + public DeviceEvent(Type type, Device device, Port port) {
56 super(type, device); 86 super(type, device);
87 + this.port = port;
57 } 88 }
58 89
59 /** 90 /**
...@@ -61,10 +92,21 @@ public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> { ...@@ -61,10 +92,21 @@ public class DeviceEvent extends AbstractEvent<DeviceEvent.Type, Device> {
61 * 92 *
62 * @param type device event type 93 * @param type device event type
63 * @param device event device subject 94 * @param device event device subject
95 + * @param port optional port subject
64 * @param time occurrence time 96 * @param time occurrence time
65 */ 97 */
66 - public DeviceEvent(Type type, Device device, long time) { 98 + public DeviceEvent(Type type, Device device, Port port, long time) {
67 super(type, device, time); 99 super(type, device, time);
100 + this.port = port;
101 + }
102 +
103 + /**
104 + * Returns the port subject.
105 + *
106 + * @return port subject or null if the event is not port specific.
107 + */
108 + Port port() {
109 + return port;
68 } 110 }
69 111
70 } 112 }
......
...@@ -3,9 +3,13 @@ package org.onlab.onos.net.device; ...@@ -3,9 +3,13 @@ package org.onlab.onos.net.device;
3 import org.junit.Test; 3 import org.junit.Test;
4 import org.onlab.onos.event.AbstractEventTest; 4 import org.onlab.onos.event.AbstractEventTest;
5 import org.onlab.onos.net.DefaultDevice; 5 import org.onlab.onos.net.DefaultDevice;
6 +import org.onlab.onos.net.DefaultPort;
6 import org.onlab.onos.net.Device; 7 import org.onlab.onos.net.Device;
8 +import org.onlab.onos.net.Port;
9 +import org.onlab.onos.net.PortNumber;
7 import org.onlab.onos.net.provider.ProviderId; 10 import org.onlab.onos.net.provider.ProviderId;
8 11
12 +import static org.junit.Assert.assertEquals;
9 import static org.onlab.onos.net.DeviceId.deviceId; 13 import static org.onlab.onos.net.DeviceId.deviceId;
10 14
11 /** 15 /**
...@@ -21,17 +25,19 @@ public class DeviceEventTest extends AbstractEventTest { ...@@ -21,17 +25,19 @@ public class DeviceEventTest extends AbstractEventTest {
21 @Test 25 @Test
22 public void withTime() { 26 public void withTime() {
23 Device device = createDevice(); 27 Device device = createDevice();
28 + Port port = new DefaultPort(device, PortNumber.portNumber(123L), true);
24 DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, 29 DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED,
25 - device, 123L); 30 + device, port, 123L);
26 validateEvent(event, DeviceEvent.Type.DEVICE_ADDED, device, 123L); 31 validateEvent(event, DeviceEvent.Type.DEVICE_ADDED, device, 123L);
32 + assertEquals("incorrect port", port, event.port());
27 } 33 }
28 34
29 @Test 35 @Test
30 public void withoutTime() { 36 public void withoutTime() {
31 Device device = createDevice(); 37 Device device = createDevice();
38 + Port port = new DefaultPort(device, PortNumber.portNumber(123L), true);
32 long before = System.currentTimeMillis(); 39 long before = System.currentTimeMillis();
33 - DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, 40 + DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
34 - device);
35 long after = System.currentTimeMillis(); 41 long after = System.currentTimeMillis();
36 validateEvent(event, DeviceEvent.Type.DEVICE_ADDED, device, before, after); 42 validateEvent(event, DeviceEvent.Type.DEVICE_ADDED, device, before, after);
37 } 43 }
......
1 package org.onlab.onos.net.trivial.impl; 1 package org.onlab.onos.net.trivial.impl;
2 2
3 import org.onlab.onos.net.DefaultDevice; 3 import org.onlab.onos.net.DefaultDevice;
4 +import org.onlab.onos.net.DefaultPort;
4 import org.onlab.onos.net.Device; 5 import org.onlab.onos.net.Device;
5 import org.onlab.onos.net.DeviceId; 6 import org.onlab.onos.net.DeviceId;
6 import org.onlab.onos.net.MastershipRole; 7 import org.onlab.onos.net.MastershipRole;
...@@ -13,7 +14,9 @@ import org.onlab.onos.net.provider.ProviderId; ...@@ -13,7 +14,9 @@ import org.onlab.onos.net.provider.ProviderId;
13 14
14 import java.util.ArrayList; 15 import java.util.ArrayList;
15 import java.util.Collections; 16 import java.util.Collections;
17 +import java.util.HashMap;
16 import java.util.HashSet; 18 import java.util.HashSet;
19 +import java.util.Iterator;
17 import java.util.List; 20 import java.util.List;
18 import java.util.Map; 21 import java.util.Map;
19 import java.util.Objects; 22 import java.util.Objects;
...@@ -21,18 +24,19 @@ import java.util.Set; ...@@ -21,18 +24,19 @@ import java.util.Set;
21 import java.util.concurrent.ConcurrentHashMap; 24 import java.util.concurrent.ConcurrentHashMap;
22 25
23 import static com.google.common.base.Preconditions.checkArgument; 26 import static com.google.common.base.Preconditions.checkArgument;
24 -import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED; 27 +import static org.onlab.onos.net.device.DeviceEvent.Type.*;
25 -import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_MASTERSHIP_CHANGED;
26 -import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_REMOVED;
27 28
28 /** 29 /**
29 * Manages inventory of infrastructure devices. 30 * Manages inventory of infrastructure devices.
30 */ 31 */
31 class SimpleDeviceStore { 32 class SimpleDeviceStore {
32 33
34 + public static final String DEVICE_NOT_FOUND = "Device with ID %s not found";
35 +
33 private final Map<DeviceId, DefaultDevice> devices = new ConcurrentHashMap<>(); 36 private final Map<DeviceId, DefaultDevice> devices = new ConcurrentHashMap<>();
34 private final Map<DeviceId, MastershipRole> roles = new ConcurrentHashMap<>(); 37 private final Map<DeviceId, MastershipRole> roles = new ConcurrentHashMap<>();
35 private final Set<DeviceId> availableDevices = new HashSet<>(); 38 private final Set<DeviceId> availableDevices = new HashSet<>();
39 + private final Map<DeviceId, Map<PortNumber, Port>> devicePorts = new HashMap<>();
36 40
37 /** 41 /**
38 * Returns an iterable collection of all devices known to the system. 42 * Returns an iterable collection of all devices known to the system.
...@@ -82,7 +86,7 @@ class SimpleDeviceStore { ...@@ -82,7 +86,7 @@ class SimpleDeviceStore {
82 devices.put(deviceId, device); 86 devices.put(deviceId, device);
83 availableDevices.add(deviceId); 87 availableDevices.add(deviceId);
84 } 88 }
85 - return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device); 89 + return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device, null);
86 } 90 }
87 91
88 // Updates the device and returns the appropriate event if necessary. 92 // Updates the device and returns the appropriate event if necessary.
...@@ -101,13 +105,14 @@ class SimpleDeviceStore { ...@@ -101,13 +105,14 @@ class SimpleDeviceStore {
101 devices.put(device.id(), updated); 105 devices.put(device.id(), updated);
102 availableDevices.add(device.id()); 106 availableDevices.add(device.id());
103 } 107 }
104 - return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, device); 108 + return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, device, null);
105 } 109 }
106 110
107 // Otherwise merely attempt to change availability 111 // Otherwise merely attempt to change availability
108 synchronized (this) { 112 synchronized (this) {
109 boolean added = availableDevices.add(device.id()); 113 boolean added = availableDevices.add(device.id());
110 - return added ? new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device) : null; 114 + return !added ? null :
115 + new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null);
111 } 116 }
112 } 117 }
113 118
...@@ -120,9 +125,10 @@ class SimpleDeviceStore { ...@@ -120,9 +125,10 @@ class SimpleDeviceStore {
120 DeviceEvent markOffline(DeviceId deviceId) { 125 DeviceEvent markOffline(DeviceId deviceId) {
121 synchronized (this) { 126 synchronized (this) {
122 Device device = devices.get(deviceId); 127 Device device = devices.get(deviceId);
123 - checkArgument(device != null, "Device with ID %s is not found", deviceId); 128 + checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
124 boolean removed = availableDevices.remove(deviceId); 129 boolean removed = availableDevices.remove(deviceId);
125 - return removed ? new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device) : null; 130 + return !removed ? null :
131 + new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null);
126 } 132 }
127 } 133 }
128 134
...@@ -136,7 +142,79 @@ class SimpleDeviceStore { ...@@ -136,7 +142,79 @@ class SimpleDeviceStore {
136 */ 142 */
137 List<DeviceEvent> updatePorts(DeviceId deviceId, 143 List<DeviceEvent> updatePorts(DeviceId deviceId,
138 List<PortDescription> portDescriptions) { 144 List<PortDescription> portDescriptions) {
139 - return new ArrayList<>(); 145 + List<DeviceEvent> events = new ArrayList<>();
146 + synchronized (this) {
147 + Device device = devices.get(deviceId);
148 + checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
149 + Map<PortNumber, Port> ports = getPortMap(deviceId);
150 +
151 + // Add new ports
152 + Set<PortNumber> processed = new HashSet<>();
153 + for (PortDescription portDescription : portDescriptions) {
154 + Port port = ports.get(portDescription.portNumber());
155 + DeviceEvent event = port == null ?
156 + createPort(device, portDescription, ports) :
157 + updatePort(device, port, portDescription, ports);
158 + processed.add(portDescription.portNumber());
159 + }
160 +
161 + events.addAll(pruneOldPorts(device, ports, processed));
162 + }
163 + return events;
164 + }
165 +
166 + // Creates a new port based on the port description adds it to the map and
167 + // Returns corresponding event.
168 + private DeviceEvent createPort(Device device, PortDescription portDescription,
169 + Map<PortNumber, Port> ports) {
170 + DefaultPort port = new DefaultPort(device, portDescription.portNumber(),
171 + portDescription.isEnabled());
172 + ports.put(port.number(), port);
173 + return new DeviceEvent(PORT_ADDED, device, port);
174 + }
175 +
176 + // CHecks if the specified port requires update and if so, it replaces the
177 + // existing entry in the map and returns corresponding event.
178 + private DeviceEvent updatePort(Device device, Port port,
179 + PortDescription portDescription,
180 + Map<PortNumber, Port> ports) {
181 + if (port.isEnabled() != portDescription.isEnabled()) {
182 + DefaultPort updatedPort =
183 + new DefaultPort(device, portDescription.portNumber(),
184 + portDescription.isEnabled());
185 + ports.put(port.number(), updatedPort);
186 + return new DeviceEvent(PORT_UPDATED, device, port);
187 + }
188 + return null;
189 + }
190 +
191 + // Prunes the specified list of ports based on which ports are in the
192 + // processed list and returns list of corresponding events.
193 + private List<DeviceEvent> pruneOldPorts(Device device,
194 + Map<PortNumber, Port> ports,
195 + Set<PortNumber> processed) {
196 + List<DeviceEvent> events = new ArrayList<>();
197 + Iterator<PortNumber> iterator = ports.keySet().iterator();
198 + while (iterator.hasNext()) {
199 + PortNumber portNumber = iterator.next();
200 + if (processed.contains(portNumber)) {
201 + events.add(new DeviceEvent(PORT_REMOVED, device,
202 + ports.get(portNumber)));
203 + iterator.remove();
204 + }
205 + }
206 + return events;
207 + }
208 +
209 + // Gets the map of ports for the specified device; if one does not already
210 + // exist, it creates and registers a new one.
211 + private Map<PortNumber, Port> getPortMap(DeviceId deviceId) {
212 + Map<PortNumber, Port> ports = devicePorts.get(deviceId);
213 + if (ports == null) {
214 + ports = new HashMap<>();
215 + devicePorts.put(deviceId, ports);
216 + }
217 + return ports;
140 } 218 }
141 219
142 /** 220 /**
...@@ -194,9 +272,10 @@ class SimpleDeviceStore { ...@@ -194,9 +272,10 @@ class SimpleDeviceStore {
194 DeviceEvent setRole(DeviceId deviceId, MastershipRole role) { 272 DeviceEvent setRole(DeviceId deviceId, MastershipRole role) {
195 synchronized (this) { 273 synchronized (this) {
196 Device device = getDevice(deviceId); 274 Device device = getDevice(deviceId);
197 - checkArgument(device != null, "Device with ID %s not found"); 275 + checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
198 MastershipRole oldRole = roles.put(deviceId, role); 276 MastershipRole oldRole = roles.put(deviceId, role);
199 - return oldRole == role ? null : new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device); 277 + return oldRole == role ? null :
278 + new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device, null);
200 } 279 }
201 } 280 }
202 281
...@@ -209,7 +288,9 @@ class SimpleDeviceStore { ...@@ -209,7 +288,9 @@ class SimpleDeviceStore {
209 synchronized (this) { 288 synchronized (this) {
210 roles.remove(deviceId); 289 roles.remove(deviceId);
211 Device device = devices.remove(deviceId); 290 Device device = devices.remove(deviceId);
212 - return device != null ? new DeviceEvent(DEVICE_REMOVED, device) : null; 291 + return device == null ? null :
292 + new DeviceEvent(DEVICE_REMOVED, device, null);
213 } 293 }
214 } 294 }
295 +
215 } 296 }
......
...@@ -24,6 +24,8 @@ import org.projectfloodlight.openflow.types.*; ...@@ -24,6 +24,8 @@ import org.projectfloodlight.openflow.types.*;
24 import org.projectfloodlight.openflow.util.*; 24 import org.projectfloodlight.openflow.util.*;
25 import org.projectfloodlight.openflow.exceptions.*; 25 import org.projectfloodlight.openflow.exceptions.*;
26 import org.jboss.netty.buffer.ChannelBuffer; 26 import org.jboss.netty.buffer.ChannelBuffer;
27 +
28 +import java.nio.ByteBuffer;
27 import java.util.Set; 29 import java.util.Set;
28 30
29 abstract class OFActionBsnVer13 { 31 abstract class OFActionBsnVer13 {
...@@ -36,7 +38,7 @@ abstract class OFActionBsnVer13 { ...@@ -36,7 +38,7 @@ abstract class OFActionBsnVer13 {
36 38
37 static class Reader implements OFMessageReader<OFActionBsn> { 39 static class Reader implements OFMessageReader<OFActionBsn> {
38 @Override 40 @Override
39 - public OFActionBsn readFrom(ChannelBuffer bb) throws OFParseError { 41 + public OFActionBsn readFrom(ByteBuffer bb) throws OFParseError {
40 if(bb.readableBytes() < MINIMUM_LENGTH) 42 if(bb.readableBytes() < MINIMUM_LENGTH)
41 return null; 43 return null;
42 int start = bb.readerIndex(); 44 int start = bb.readerIndex();
......