tom

Merge remote-tracking branch 'origin/master'

1 +package org.onlab.onos.cli.net;
2 +
3 +import static com.google.common.collect.Lists.newArrayList;
4 +
5 +import java.util.Collections;
6 +import java.util.Comparator;
7 +import java.util.List;
8 +import java.util.Map;
9 +
10 +import org.apache.karaf.shell.commands.Command;
11 +import org.onlab.onos.cli.AbstractShellCommand;
12 +import org.onlab.onos.net.Device;
13 +import org.onlab.onos.net.device.DeviceService;
14 +import org.onlab.onos.net.flow.FlowRule;
15 +import org.onlab.onos.net.flow.FlowRuleService;
16 +
17 +import com.google.common.collect.Maps;
18 +
19 +/**
20 + * Lists all currently-known hosts.
21 + */
22 +@Command(scope = "onos", name = "flows",
23 +description = "Lists all currently-known flows.")
24 +public class FlowsListCommand extends AbstractShellCommand {
25 +
26 + private static final String FMT =
27 + " id=%s, selector=%s, treatment=%s, state=%s";
28 +
29 + protected static final Comparator<FlowRule> ID_COMPARATOR = new Comparator<FlowRule>() {
30 + @Override
31 + public int compare(FlowRule f1, FlowRule f2) {
32 + return Long.valueOf(f1.id().value()).compareTo(f2.id().value());
33 + }
34 + };
35 +
36 + @Override
37 + protected Object doExecute() throws Exception {
38 + DeviceService deviceService = getService(DeviceService.class);
39 + FlowRuleService service = getService(FlowRuleService.class);
40 + Map<Device, List<FlowRule>> flows = getSortedFlows(deviceService, service);
41 + for (Device d : deviceService.getDevices()) {
42 + printFlows(d, flows.get(d));
43 + }
44 + return null;
45 + }
46 +
47 +
48 + /**
49 + * Returns the list of devices sorted using the device ID URIs.
50 + *
51 + * @param service device service
52 + * @return sorted device list
53 + */
54 + protected Map<Device, List<FlowRule>> getSortedFlows(DeviceService deviceService, FlowRuleService service) {
55 + Map<Device, List<FlowRule>> flows = Maps.newHashMap();
56 + List<FlowRule> rules;
57 + for (Device d : deviceService.getDevices()) {
58 + rules = newArrayList(service.getFlowEntries(d.id()));
59 + Collections.sort(rules, ID_COMPARATOR);
60 + flows.put(d, rules);
61 + }
62 + return flows;
63 + }
64 +
65 + /**
66 + * Prints flows.
67 + * @param d the device
68 + * @param flows the set of flows for that device.
69 + */
70 + protected void printFlows(Device d, List<FlowRule> flows) {
71 + print("Device: " + d.id());
72 + for (FlowRule f : flows) {
73 + print(FMT, f.id().value(), f.selector(), f.treatment(), f.state());
74 + }
75 +
76 + }
77 +
78 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
2 2
3 <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> 3 <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
4 <command> 4 <command>
5 + <action class="org.onlab.onos.cli.net.FlowsListCommand"/>
6 + </command>
7 + <command>
5 <action class="org.onlab.onos.cli.net.DevicesListCommand"/> 8 <action class="org.onlab.onos.cli.net.DevicesListCommand"/>
6 </command> 9 </command>
7 <command> 10 <command>
......
1 +package org.onlab.onos.cluster;
2 +
3 +import org.onlab.onos.event.AbstractEvent;
4 +import org.onlab.onos.net.DeviceId;
5 +
6 +/**
7 + * Describes infrastructure device event.
8 + */
9 +public class MastershipEvent extends AbstractEvent<MastershipEvent.Type, DeviceId> {
10 +
11 + InstanceId master;
12 +
13 + /**
14 + * Type of mastership events.
15 + */
16 + public enum Type {
17 + /**
18 + * Signifies that the master for a device has changed.
19 + */
20 + MASTER_CHANGED
21 + }
22 +
23 + /**
24 + * Creates an event of a given type and for the specified device, master,
25 + * and the current time.
26 + *
27 + * @param type device event type
28 + * @param device event device subject
29 + * @param master master ID subject
30 + */
31 + protected MastershipEvent(Type type, DeviceId device, InstanceId master) {
32 + super(type, device);
33 + this.master = master;
34 + }
35 +
36 + /**
37 + * Creates an event of a given type and for the specified device, master,
38 + * and time.
39 + *
40 + * @param type mastership event type
41 + * @param device event device subject
42 + * @param master master ID subject
43 + * @param time occurrence time
44 + */
45 + protected MastershipEvent(Type type, DeviceId device, InstanceId master, long time) {
46 + super(type, device, time);
47 + this.master = master;
48 + }
49 +
50 + /**
51 + * Returns the current master's ID as a subject.
52 + *
53 + * @return master ID subject
54 + */
55 + public InstanceId master() {
56 + return master;
57 + }
58 +}
1 +package org.onlab.onos.cluster;
2 +
3 +import org.onlab.onos.event.EventListener;
4 +
5 +/**
6 + * Entity capable of receiving device mastership-related events.
7 + */
8 +public interface MastershipListener extends EventListener<MastershipEvent> {
9 +
10 +}
1 package org.onlab.onos.cluster; 1 package org.onlab.onos.cluster;
2 2
3 +import java.util.Set;
4 +
5 +import org.onlab.onos.net.DeviceId;
6 +import org.onlab.onos.net.MastershipRole;
7 +
3 /** 8 /**
4 * Service responsible for determining the controller instance mastership of 9 * Service responsible for determining the controller instance mastership of
5 * a device in a clustered environment. This is the central authority for 10 * a device in a clustered environment. This is the central authority for
...@@ -8,12 +13,42 @@ package org.onlab.onos.cluster; ...@@ -8,12 +13,42 @@ package org.onlab.onos.cluster;
8 */ 13 */
9 public interface MastershipService { 14 public interface MastershipService {
10 15
11 - // InstanceId getMasterFor(DeviceId deviceId) 16 + /**
12 - // Set<DeviceId> getDevicesOf(InstanceId instanceId); 17 + * Returns the current master for a given device.
18 + *
19 + * @param deviceId the identifier of the device
20 + * @return the ID of the master controller for the device
21 + */
22 + InstanceId getMasterFor(DeviceId deviceId);
23 +
24 + /**
25 + * Returns the devices for which a controller is master.
26 + *
27 + * @param instanceId the ID of the controller
28 + * @return a set of device IDs
29 + */
30 + Set<DeviceId> getDevicesOf(InstanceId instanceId);
31 +
32 + /**
33 + * Returns the mastership status of this controller for a given device.
34 + *
35 + * @param deviceId the the identifier of the device
36 + * @return the role of this controller instance
37 + */
38 + MastershipRole requestRoleFor(DeviceId deviceId);
13 39
14 - // MastershipRole requestRoleFor(DeviceId deviceId); 40 + /**
41 + * Adds the specified mastership listener.
42 + *
43 + * @param listener the mastership listener
44 + */
45 + void addListener(MastershipListener listener);
15 46
16 - // addListener/removeLister(MastershipListener listener); 47 + /**
17 - // types of events would be MASTER_CHANGED (subject ==> deviceId; master ==> instanceId) 48 + * Removes the specified device listener.
49 + *
50 + * @param listener the mastership listener
51 + */
52 + void removeListemer(MastershipListener listener);
18 53
19 } 54 }
......
1 package org.onlab.onos.net.flow; 1 package org.onlab.onos.net.flow;
2 2
3 import static com.google.common.base.MoreObjects.toStringHelper; 3 import static com.google.common.base.MoreObjects.toStringHelper;
4 +import static org.slf4j.LoggerFactory.getLogger;
4 5
5 import java.util.Objects; 6 import java.util.Objects;
6 7
7 import org.onlab.onos.net.DeviceId; 8 import org.onlab.onos.net.DeviceId;
9 +import org.slf4j.Logger;
8 10
9 public class DefaultFlowRule implements FlowRule { 11 public class DefaultFlowRule implements FlowRule {
10 12
13 + private final Logger log = getLogger(getClass());
14 +
11 private final DeviceId deviceId; 15 private final DeviceId deviceId;
12 private final int priority; 16 private final int priority;
13 private final TrafficSelector selector; 17 private final TrafficSelector selector;
14 private final TrafficTreatment treatment; 18 private final TrafficTreatment treatment;
15 - private final FlowId id;
16 private final long created; 19 private final long created;
17 private final long life; 20 private final long life;
18 - private final long idle;
19 private final long packets; 21 private final long packets;
20 private final long bytes; 22 private final long bytes;
23 + private final FlowRuleState state;
24 +
25 + private final FlowId id;
26 +
27 + public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
28 + TrafficTreatment treatment, int priority, FlowRuleState state,
29 + long life, long packets, long bytes, long flowId) {
30 + this.deviceId = deviceId;
31 + this.priority = priority;
32 + this.selector = selector;
33 + this.treatment = treatment;
34 + this.state = state;
35 +
36 + this.id = FlowId.valueOf(flowId);
21 37
38 + this.life = life;
39 + this.packets = packets;
40 + this.bytes = bytes;
41 + this.created = System.currentTimeMillis();
42 + }
43 +
44 + public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
45 + TrafficTreatment treatement, int priority) {
46 + this(deviceId, selector, treatement, priority, FlowRuleState.CREATED);
47 + }
48 +
49 + public DefaultFlowRule(FlowRule rule, FlowRuleState state) {
50 + this(rule.deviceId(), rule.selector(), rule.treatment(),
51 + rule.priority(), state, rule.id());
52 + }
22 53
23 - public DefaultFlowRule(DeviceId deviceId, 54 + private DefaultFlowRule(DeviceId deviceId,
24 - TrafficSelector selector, TrafficTreatment treatment, int priority) { 55 + TrafficSelector selector, TrafficTreatment treatment,
56 + int priority, FlowRuleState state) {
25 this.deviceId = deviceId; 57 this.deviceId = deviceId;
26 this.priority = priority; 58 this.priority = priority;
27 this.selector = selector; 59 this.selector = selector;
28 this.treatment = treatment; 60 this.treatment = treatment;
61 + this.state = state;
29 this.life = 0; 62 this.life = 0;
30 - this.idle = 0;
31 this.packets = 0; 63 this.packets = 0;
32 this.bytes = 0; 64 this.bytes = 0;
33 this.id = FlowId.valueOf(this.hashCode()); 65 this.id = FlowId.valueOf(this.hashCode());
34 this.created = System.currentTimeMillis(); 66 this.created = System.currentTimeMillis();
35 } 67 }
36 68
37 - public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector, 69 + private DefaultFlowRule(DeviceId deviceId,
38 - TrafficTreatment treatment, int priority, 70 + TrafficSelector selector, TrafficTreatment treatment,
39 - long life, long idle, long packets, long bytes, Integer flowId) { 71 + int priority, FlowRuleState state, FlowId flowId) {
40 this.deviceId = deviceId; 72 this.deviceId = deviceId;
41 this.priority = priority; 73 this.priority = priority;
42 this.selector = selector; 74 this.selector = selector;
43 this.treatment = treatment; 75 this.treatment = treatment;
44 - 76 + this.state = state;
45 - this.id = FlowId.valueOf(flowId); 77 + this.life = 0;
46 - 78 + this.packets = 0;
47 - this.life = life; 79 + this.bytes = 0;
48 - this.idle = idle; 80 + this.id = flowId;
49 - this.packets = packets;
50 - this.bytes = bytes;
51 this.created = System.currentTimeMillis(); 81 this.created = System.currentTimeMillis();
52 } 82 }
53 83
...@@ -83,11 +113,6 @@ public class DefaultFlowRule implements FlowRule { ...@@ -83,11 +113,6 @@ public class DefaultFlowRule implements FlowRule {
83 } 113 }
84 114
85 @Override 115 @Override
86 - public long idleMillis() {
87 - return idle;
88 - }
89 -
90 - @Override
91 public long packets() { 116 public long packets() {
92 return packets; 117 return packets;
93 } 118 }
...@@ -98,6 +123,12 @@ public class DefaultFlowRule implements FlowRule { ...@@ -98,6 +123,12 @@ public class DefaultFlowRule implements FlowRule {
98 } 123 }
99 124
100 @Override 125 @Override
126 + public FlowRuleState state() {
127 + return this.state;
128 + }
129 +
130 +
131 + @Override
101 /* 132 /*
102 * The priority and statistics can change on a given treatment and selector 133 * The priority and statistics can change on a given treatment and selector
103 * 134 *
...@@ -116,18 +147,14 @@ public class DefaultFlowRule implements FlowRule { ...@@ -116,18 +147,14 @@ public class DefaultFlowRule implements FlowRule {
116 * @see java.lang.Object#equals(java.lang.Object) 147 * @see java.lang.Object#equals(java.lang.Object)
117 */ 148 */
118 public boolean equals(Object obj) { 149 public boolean equals(Object obj) {
150 +
151 + if (this == obj) {
152 + return true;
153 + }
119 if (obj instanceof FlowRule) { 154 if (obj instanceof FlowRule) {
120 DefaultFlowRule that = (DefaultFlowRule) obj; 155 DefaultFlowRule that = (DefaultFlowRule) obj;
121 - if (!this.deviceId().equals(that.deviceId())) { 156 + return Objects.equals(deviceId, that.deviceId) &&
122 - return false; 157 + Objects.equals(id, that.id);
123 - }
124 - if (!this.treatment().equals(that.treatment())) {
125 - return false;
126 - }
127 - if (!this.selector().equals(that.selector())) {
128 - return false;
129 - }
130 - return true;
131 } 158 }
132 return false; 159 return false;
133 } 160 }
...@@ -141,8 +168,8 @@ public class DefaultFlowRule implements FlowRule { ...@@ -141,8 +168,8 @@ public class DefaultFlowRule implements FlowRule {
141 .add("selector", selector) 168 .add("selector", selector)
142 .add("treatment", treatment) 169 .add("treatment", treatment)
143 .add("created", created) 170 .add("created", created)
171 + .add("state", state)
144 .toString(); 172 .toString();
145 } 173 }
146 174
147 -
148 } 175 }
......
1 package org.onlab.onos.net.flow; 1 package org.onlab.onos.net.flow;
2 2
3 +import com.google.common.base.Objects;
4 +
3 /** 5 /**
4 * Representation of a Flow ID. 6 * Representation of a Flow ID.
5 */ 7 */
6 public final class FlowId { 8 public final class FlowId {
7 9
8 - private final int flowid; 10 + private final long flowid;
9 11
10 - private FlowId(int id) { 12 + private FlowId(long id) {
11 this.flowid = id; 13 this.flowid = id;
12 } 14 }
13 15
14 - public static FlowId valueOf(int id) { 16 + public static FlowId valueOf(long id) {
15 return new FlowId(id); 17 return new FlowId(id);
16 } 18 }
17 19
18 - public int value() { 20 + public long value() {
19 return flowid; 21 return flowid;
20 } 22 }
23 +
24 + @Override
25 + public boolean equals(Object obj) {
26 + if (this == obj) {
27 + return true;
28 + }
29 + if (obj.getClass() == this.getClass()) {
30 + FlowId that = (FlowId) obj;
31 + return Objects.equal(this.flowid, that.flowid);
32 + }
33 + return false;
34 + }
35 +
36 + @Override
37 + public int hashCode() {
38 + return Objects.hashCode(this.flowid);
39 + }
21 } 40 }
......
...@@ -8,6 +8,42 @@ import org.onlab.onos.net.DeviceId; ...@@ -8,6 +8,42 @@ import org.onlab.onos.net.DeviceId;
8 */ 8 */
9 public interface FlowRule { 9 public interface FlowRule {
10 10
11 +
12 + public enum FlowRuleState {
13 + /**
14 + * Indicates that this rule has been created.
15 + */
16 + CREATED,
17 +
18 + /**
19 + * Indicates that this rule has been submitted for addition.
20 + * Not necessarily in the flow table.
21 + */
22 + PENDING_ADD,
23 +
24 + /**
25 + * Rule has been added which means it is in the flow table.
26 + */
27 + ADDED,
28 +
29 + /**
30 + * Flow has been marked for removal, might still be in flow table.
31 + */
32 + PENDING_REMOVE,
33 +
34 + /**
35 + * Flow has been removed from flow table and can be purged.
36 + */
37 + REMOVED
38 + }
39 +
40 + /**
41 + * Returns the flow rule state.
42 + *
43 + * @return flow rule state
44 + */
45 + FlowRuleState state();
46 +
11 //TODO: build cookie value 47 //TODO: build cookie value
12 /** 48 /**
13 * Returns the ID of this flow. 49 * Returns the ID of this flow.
...@@ -54,13 +90,6 @@ public interface FlowRule { ...@@ -54,13 +90,6 @@ public interface FlowRule {
54 long lifeMillis(); 90 long lifeMillis();
55 91
56 /** 92 /**
57 - * Returns the number of milliseconds this flow rule has been idle.
58 - *
59 - * @return number of millis
60 - */
61 - long idleMillis();
62 -
63 - /**
64 * Returns the number of packets this flow rule has matched. 93 * Returns the number of packets this flow rule has matched.
65 * 94 *
66 * @return number of packets 95 * @return number of packets
......
...@@ -19,7 +19,12 @@ public class FlowRuleEvent extends AbstractEvent<FlowRuleEvent.Type, FlowRule> { ...@@ -19,7 +19,12 @@ public class FlowRuleEvent extends AbstractEvent<FlowRuleEvent.Type, FlowRule> {
19 /** 19 /**
20 * Signifies that a flow rule has been removed. 20 * Signifies that a flow rule has been removed.
21 */ 21 */
22 - RULE_REMOVED 22 + RULE_REMOVED,
23 +
24 + /**
25 + * Signifies that a rule has been updated.
26 + */
27 + RULE_UPDATED
23 } 28 }
24 29
25 /** 30 /**
......
1 package org.onlab.onos.net.flow; 1 package org.onlab.onos.net.flow;
2 2
3 +import org.onlab.onos.net.DeviceId;
3 import org.onlab.onos.net.provider.ProviderService; 4 import org.onlab.onos.net.provider.ProviderService;
4 5
5 /** 6 /**
...@@ -23,6 +24,13 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide ...@@ -23,6 +24,13 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide
23 void flowMissing(FlowRule flowRule); 24 void flowMissing(FlowRule flowRule);
24 25
25 /** 26 /**
27 + * Signals that a flow rule is on the switch but not in the store.
28 + *
29 + * @param flowRule the extra flow rule
30 + */
31 + void extraneousFlow(FlowRule flowRule);
32 +
33 + /**
26 * Signals that a flow rule was indeed added. 34 * Signals that a flow rule was indeed added.
27 * 35 *
28 * @param flowRule the added flow rule 36 * @param flowRule the added flow rule
...@@ -35,6 +43,8 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide ...@@ -35,6 +43,8 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide
35 * 43 *
36 * @param flowRules collection of flow rules 44 * @param flowRules collection of flow rules
37 */ 45 */
38 - void pushFlowMetrics(Iterable<FlowRule> flowRules); 46 + void pushFlowMetrics(DeviceId deviceId, Iterable<FlowRule> flowRules);
47 +
48 +
39 49
40 } 50 }
......
1 package org.onlab.onos.net.flow; 1 package org.onlab.onos.net.flow;
2 2
3 -import java.util.List;
4 -
5 import org.onlab.onos.net.DeviceId; 3 import org.onlab.onos.net.DeviceId;
6 4
7 /** 5 /**
...@@ -31,10 +29,8 @@ public interface FlowRuleService { ...@@ -31,10 +29,8 @@ public interface FlowRuleService {
31 * device reconnects to the controller. 29 * device reconnects to the controller.
32 * 30 *
33 * @param flowRules one or more flow rules 31 * @param flowRules one or more flow rules
34 - * throws SomeKindOfException that indicates which ones were applied and
35 - * which ones failed
36 */ 32 */
37 - List<FlowRule> applyFlowRules(FlowRule... flowRules); 33 + void applyFlowRules(FlowRule... flowRules);
38 34
39 /** 35 /**
40 * Removes the specified flow rules from their respective devices. If the 36 * Removes the specified flow rules from their respective devices. If the
......
...@@ -16,12 +16,18 @@ public interface FlowRuleStore { ...@@ -16,12 +16,18 @@ public interface FlowRuleStore {
16 Iterable<FlowRule> getFlowEntries(DeviceId deviceId); 16 Iterable<FlowRule> getFlowEntries(DeviceId deviceId);
17 17
18 /** 18 /**
19 - * Stores a new flow rule, and generates a FlowRule for it. 19 + * Stores a new flow rule without generating events.
20 * 20 *
21 * @param rule the flow rule to add 21 * @param rule the flow rule to add
22 - * @return a flow entry
23 */ 22 */
24 - FlowRule storeFlowRule(FlowRule rule); 23 + void storeFlowRule(FlowRule rule);
24 +
25 + /**
26 + * Deletes a flow rule without generating events.
27 + *
28 + * @param rule the flow rule to delete
29 + */
30 + void deleteFlowRule(FlowRule rule);
25 31
26 /** 32 /**
27 * Stores a new flow rule, or updates an existing entry. 33 * Stores a new flow rule, or updates an existing entry.
......
...@@ -3,7 +3,7 @@ package org.onlab.onos.net.flow.impl; ...@@ -3,7 +3,7 @@ package org.onlab.onos.net.flow.impl;
3 import static com.google.common.base.Preconditions.checkNotNull; 3 import static com.google.common.base.Preconditions.checkNotNull;
4 import static org.slf4j.LoggerFactory.getLogger; 4 import static org.slf4j.LoggerFactory.getLogger;
5 5
6 -import java.util.ArrayList; 6 +import java.util.Iterator;
7 import java.util.List; 7 import java.util.List;
8 8
9 import org.apache.felix.scr.annotations.Activate; 9 import org.apache.felix.scr.annotations.Activate;
...@@ -17,7 +17,9 @@ import org.onlab.onos.event.EventDeliveryService; ...@@ -17,7 +17,9 @@ import org.onlab.onos.event.EventDeliveryService;
17 import org.onlab.onos.net.Device; 17 import org.onlab.onos.net.Device;
18 import org.onlab.onos.net.DeviceId; 18 import org.onlab.onos.net.DeviceId;
19 import org.onlab.onos.net.device.DeviceService; 19 import org.onlab.onos.net.device.DeviceService;
20 +import org.onlab.onos.net.flow.DefaultFlowRule;
20 import org.onlab.onos.net.flow.FlowRule; 21 import org.onlab.onos.net.flow.FlowRule;
22 +import org.onlab.onos.net.flow.FlowRule.FlowRuleState;
21 import org.onlab.onos.net.flow.FlowRuleEvent; 23 import org.onlab.onos.net.flow.FlowRuleEvent;
22 import org.onlab.onos.net.flow.FlowRuleListener; 24 import org.onlab.onos.net.flow.FlowRuleListener;
23 import org.onlab.onos.net.flow.FlowRuleProvider; 25 import org.onlab.onos.net.flow.FlowRuleProvider;
...@@ -29,17 +31,19 @@ import org.onlab.onos.net.provider.AbstractProviderRegistry; ...@@ -29,17 +31,19 @@ import org.onlab.onos.net.provider.AbstractProviderRegistry;
29 import org.onlab.onos.net.provider.AbstractProviderService; 31 import org.onlab.onos.net.provider.AbstractProviderService;
30 import org.slf4j.Logger; 32 import org.slf4j.Logger;
31 33
34 +import com.google.common.collect.Lists;
35 +
32 @Component(immediate = true) 36 @Component(immediate = true)
33 @Service 37 @Service
34 public class FlowRuleManager 38 public class FlowRuleManager
35 - extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService> 39 +extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService>
36 - implements FlowRuleService, FlowRuleProviderRegistry { 40 +implements FlowRuleService, FlowRuleProviderRegistry {
37 41
38 public static final String FLOW_RULE_NULL = "FlowRule cannot be null"; 42 public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
39 private final Logger log = getLogger(getClass()); 43 private final Logger log = getLogger(getClass());
40 44
41 private final AbstractListenerRegistry<FlowRuleEvent, FlowRuleListener> 45 private final AbstractListenerRegistry<FlowRuleEvent, FlowRuleListener>
42 - listenerRegistry = new AbstractListenerRegistry<>(); 46 + listenerRegistry = new AbstractListenerRegistry<>();
43 47
44 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 48 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
45 protected FlowRuleStore store; 49 protected FlowRuleStore store;
...@@ -68,27 +72,24 @@ public class FlowRuleManager ...@@ -68,27 +72,24 @@ public class FlowRuleManager
68 } 72 }
69 73
70 @Override 74 @Override
71 - public List<FlowRule> applyFlowRules(FlowRule... flowRules) { 75 + public void applyFlowRules(FlowRule... flowRules) {
72 - List<FlowRule> entries = new ArrayList<FlowRule>();
73 -
74 for (int i = 0; i < flowRules.length; i++) { 76 for (int i = 0; i < flowRules.length; i++) {
75 - FlowRule f = flowRules[i]; 77 + FlowRule f = new DefaultFlowRule(flowRules[i], FlowRuleState.PENDING_ADD);
76 final Device device = deviceService.getDevice(f.deviceId()); 78 final Device device = deviceService.getDevice(f.deviceId());
77 final FlowRuleProvider frp = getProvider(device.providerId()); 79 final FlowRuleProvider frp = getProvider(device.providerId());
78 - entries.add(store.storeFlowRule(f)); 80 + store.storeFlowRule(f);
79 frp.applyFlowRule(f); 81 frp.applyFlowRule(f);
80 } 82 }
81 -
82 - return entries;
83 } 83 }
84 84
85 @Override 85 @Override
86 public void removeFlowRules(FlowRule... flowRules) { 86 public void removeFlowRules(FlowRule... flowRules) {
87 + FlowRule f;
87 for (int i = 0; i < flowRules.length; i++) { 88 for (int i = 0; i < flowRules.length; i++) {
88 - FlowRule f = flowRules[i]; 89 + f = new DefaultFlowRule(flowRules[i], FlowRuleState.PENDING_REMOVE);
89 final Device device = deviceService.getDevice(f.deviceId()); 90 final Device device = deviceService.getDevice(f.deviceId());
90 final FlowRuleProvider frp = getProvider(device.providerId()); 91 final FlowRuleProvider frp = getProvider(device.providerId());
91 - store.removeFlowRule(f); 92 + store.deleteFlowRule(f);
92 frp.removeFlowRule(f); 93 frp.removeFlowRule(f);
93 } 94 }
94 95
...@@ -111,8 +112,8 @@ public class FlowRuleManager ...@@ -111,8 +112,8 @@ public class FlowRuleManager
111 } 112 }
112 113
113 private class InternalFlowRuleProviderService 114 private class InternalFlowRuleProviderService
114 - extends AbstractProviderService<FlowRuleProvider> 115 + extends AbstractProviderService<FlowRuleProvider>
115 - implements FlowRuleProviderService { 116 + implements FlowRuleProviderService {
116 117
117 protected InternalFlowRuleProviderService(FlowRuleProvider provider) { 118 protected InternalFlowRuleProviderService(FlowRuleProvider provider) {
118 super(provider); 119 super(provider);
...@@ -134,22 +135,30 @@ public class FlowRuleManager ...@@ -134,22 +135,30 @@ public class FlowRuleManager
134 public void flowMissing(FlowRule flowRule) { 135 public void flowMissing(FlowRule flowRule) {
135 checkNotNull(flowRule, FLOW_RULE_NULL); 136 checkNotNull(flowRule, FLOW_RULE_NULL);
136 checkValidity(); 137 checkValidity();
137 - // TODO Auto-generated method stub 138 + log.info("Flow {} has not been installed.", flowRule);
138 139
139 } 140 }
140 141
141 @Override 142 @Override
143 + public void extraneousFlow(FlowRule flowRule) {
144 + checkNotNull(flowRule, FLOW_RULE_NULL);
145 + checkValidity();
146 + log.info("Flow {} is on switch but not in store.", flowRule);
147 + }
148 +
149 + @Override
142 public void flowAdded(FlowRule flowRule) { 150 public void flowAdded(FlowRule flowRule) {
143 checkNotNull(flowRule, FLOW_RULE_NULL); 151 checkNotNull(flowRule, FLOW_RULE_NULL);
144 checkValidity(); 152 checkValidity();
145 153
146 FlowRuleEvent event = store.addOrUpdateFlowRule(flowRule); 154 FlowRuleEvent event = store.addOrUpdateFlowRule(flowRule);
147 if (event == null) { 155 if (event == null) {
148 - log.debug("Flow {} updated", flowRule); 156 + log.debug("No flow store event generated.");
149 } else { 157 } else {
150 - log.debug("Flow {} added", flowRule); 158 + log.debug("Flow {} {}", flowRule, event.type());
151 post(event); 159 post(event);
152 } 160 }
161 +
153 } 162 }
154 163
155 // Posts the specified event to the local event dispatcher. 164 // Posts the specified event to the local event dispatcher.
...@@ -160,9 +169,25 @@ public class FlowRuleManager ...@@ -160,9 +169,25 @@ public class FlowRuleManager
160 } 169 }
161 170
162 @Override 171 @Override
163 - public void pushFlowMetrics(Iterable<FlowRule> flowEntries) { 172 + public void pushFlowMetrics(DeviceId deviceId, Iterable<FlowRule> flowEntries) {
164 - // TODO Auto-generated method stub 173 + List<FlowRule> storedRules = Lists.newLinkedList(store.getFlowEntries(deviceId));
165 - 174 +
175 + Iterator<FlowRule> switchRulesIterator = flowEntries.iterator();
176 +
177 + while (switchRulesIterator.hasNext()) {
178 + FlowRule rule = switchRulesIterator.next();
179 + if (storedRules.remove(rule)) {
180 + // we both have the rule, let's update some info then.
181 + flowAdded(rule);
182 + } else {
183 + // the device has a rule the store does not have
184 + extraneousFlow(rule);
185 + }
186 + }
187 + for (FlowRule rule : storedRules) {
188 + // there are rules in the store that aren't on the switch
189 + flowMissing(rule);
190 + }
166 } 191 }
167 } 192 }
168 193
......
...@@ -6,6 +6,7 @@ import static org.junit.Assert.assertNotNull; ...@@ -6,6 +6,7 @@ import static org.junit.Assert.assertNotNull;
6 import static org.junit.Assert.assertTrue; 6 import static org.junit.Assert.assertTrue;
7 import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED; 7 import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
8 import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; 8 import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
9 +import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
9 10
10 import java.util.ArrayList; 11 import java.util.ArrayList;
11 import java.util.List; 12 import java.util.List;
...@@ -25,6 +26,7 @@ import org.onlab.onos.net.device.DeviceListener; ...@@ -25,6 +26,7 @@ import org.onlab.onos.net.device.DeviceListener;
25 import org.onlab.onos.net.device.DeviceService; 26 import org.onlab.onos.net.device.DeviceService;
26 import org.onlab.onos.net.flow.DefaultFlowRule; 27 import org.onlab.onos.net.flow.DefaultFlowRule;
27 import org.onlab.onos.net.flow.FlowRule; 28 import org.onlab.onos.net.flow.FlowRule;
29 +import org.onlab.onos.net.flow.FlowRule.FlowRuleState;
28 import org.onlab.onos.net.flow.FlowRuleEvent; 30 import org.onlab.onos.net.flow.FlowRuleEvent;
29 import org.onlab.onos.net.flow.FlowRuleListener; 31 import org.onlab.onos.net.flow.FlowRuleListener;
30 import org.onlab.onos.net.flow.FlowRuleProvider; 32 import org.onlab.onos.net.flow.FlowRuleProvider;
...@@ -37,10 +39,10 @@ import org.onlab.onos.net.flow.criteria.Criterion; ...@@ -37,10 +39,10 @@ import org.onlab.onos.net.flow.criteria.Criterion;
37 import org.onlab.onos.net.flow.instructions.Instruction; 39 import org.onlab.onos.net.flow.instructions.Instruction;
38 import org.onlab.onos.net.provider.AbstractProvider; 40 import org.onlab.onos.net.provider.AbstractProvider;
39 import org.onlab.onos.net.provider.ProviderId; 41 import org.onlab.onos.net.provider.ProviderId;
42 +import org.onlab.onos.net.trivial.impl.SimpleFlowRuleStore;
40 43
41 import com.google.common.collect.Lists; 44 import com.google.common.collect.Lists;
42 import com.google.common.collect.Sets; 45 import com.google.common.collect.Sets;
43 -import org.onlab.onos.net.trivial.impl.SimpleFlowRuleStore;
44 46
45 /** 47 /**
46 * Test codifying the flow rule service & flow rule provider service contracts. 48 * Test codifying the flow rule service & flow rule provider service contracts.
...@@ -56,7 +58,7 @@ public class FlowRuleManagerTest { ...@@ -56,7 +58,7 @@ public class FlowRuleManagerTest {
56 58
57 protected FlowRuleService service; 59 protected FlowRuleService service;
58 protected FlowRuleProviderRegistry registry; 60 protected FlowRuleProviderRegistry registry;
59 - protected FlowRuleProviderService providerSerivce; 61 + protected FlowRuleProviderService providerService;
60 protected TestProvider provider; 62 protected TestProvider provider;
61 protected TestListener listener = new TestListener(); 63 protected TestListener listener = new TestListener();
62 64
...@@ -72,7 +74,7 @@ public class FlowRuleManagerTest { ...@@ -72,7 +74,7 @@ public class FlowRuleManagerTest {
72 mgr.activate(); 74 mgr.activate();
73 mgr.addListener(listener); 75 mgr.addListener(listener);
74 provider = new TestProvider(PID); 76 provider = new TestProvider(PID);
75 - providerSerivce = registry.register(provider); 77 + providerService = registry.register(provider);
76 assertTrue("provider should be registered", 78 assertTrue("provider should be registered",
77 registry.getProviders().contains(provider.id())); 79 registry.getProviders().contains(provider.id()));
78 } 80 }
...@@ -94,10 +96,15 @@ public class FlowRuleManagerTest { ...@@ -94,10 +96,15 @@ public class FlowRuleManagerTest {
94 return new DefaultFlowRule(DID, ts, tr, 0); 96 return new DefaultFlowRule(DID, ts, tr, 0);
95 } 97 }
96 98
97 - private void addFlowRule(int hval) { 99 + private FlowRule flowRule(FlowRule rule, FlowRuleState state) {
100 + return new DefaultFlowRule(rule, state);
101 + }
102 +
103 + private FlowRule addFlowRule(int hval) {
98 FlowRule rule = flowRule(hval, hval); 104 FlowRule rule = flowRule(hval, hval);
99 - providerSerivce.flowAdded(rule); 105 + providerService.flowAdded(rule);
100 assertNotNull("rule should be found", service.getFlowEntries(DID)); 106 assertNotNull("rule should be found", service.getFlowEntries(DID));
107 + return rule;
101 } 108 }
102 109
103 private void validateEvents(FlowRuleEvent.Type ... events) { 110 private void validateEvents(FlowRuleEvent.Type ... events) {
...@@ -131,60 +138,91 @@ public class FlowRuleManagerTest { ...@@ -131,60 +138,91 @@ public class FlowRuleManagerTest {
131 138
132 addFlowRule(1); 139 addFlowRule(1);
133 assertEquals("should still be 2 rules", 2, flowCount()); 140 assertEquals("should still be 2 rules", 2, flowCount());
134 - validateEvents(); 141 + validateEvents(RULE_UPDATED);
142 + }
143 +
144 +
145 + //backing store is sensitive to the order of additions/removals
146 + private boolean validateState(FlowRuleState... state) {
147 + Iterable<FlowRule> rules = service.getFlowEntries(DID);
148 + int i = 0;
149 + for (FlowRule f : rules) {
150 + if (f.state() != state[i]) {
151 + return false;
152 + }
153 + i++;
154 + }
155 + return true;
135 } 156 }
136 157
137 @Test 158 @Test
138 public void applyFlowRules() { 159 public void applyFlowRules() {
139 - TestSelector ts = new TestSelector(1); 160 +
140 FlowRule r1 = flowRule(1, 1); 161 FlowRule r1 = flowRule(1, 1);
141 FlowRule r2 = flowRule(1, 2); 162 FlowRule r2 = flowRule(1, 2);
142 FlowRule r3 = flowRule(1, 3); 163 FlowRule r3 = flowRule(1, 3);
143 164
144 - //current FlowRules always return 0. FlowEntries inherit the value
145 - FlowRule e1 = new DefaultFlowRule(DID, ts, r1.treatment(), 0);
146 - FlowRule e2 = new DefaultFlowRule(DID, ts, r2.treatment(), 0);
147 - FlowRule e3 = new DefaultFlowRule(DID, ts, r3.treatment(), 0);
148 - List<FlowRule> fel = Lists.newArrayList(e1, e2, e3);
149 -
150 assertTrue("store should be empty", 165 assertTrue("store should be empty",
151 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty()); 166 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
152 - List<FlowRule> ret = mgr.applyFlowRules(r1, r2, r3); 167 + mgr.applyFlowRules(r1, r2, r3);
153 assertEquals("3 rules should exist", 3, flowCount()); 168 assertEquals("3 rules should exist", 3, flowCount());
154 - assertTrue("3 entries should result", fel.containsAll(ret)); 169 + assertTrue("Entries should be pending add.",
170 + validateState(FlowRuleState.PENDING_ADD, FlowRuleState.PENDING_ADD,
171 + FlowRuleState.PENDING_ADD));
155 } 172 }
156 173
157 @Test 174 @Test
158 public void removeFlowRules() { 175 public void removeFlowRules() {
159 - addFlowRule(1); 176 + FlowRule f1 = addFlowRule(1);
160 - addFlowRule(2); 177 + FlowRule f2 = addFlowRule(2);
161 addFlowRule(3); 178 addFlowRule(3);
162 assertEquals("3 rules should exist", 3, flowCount()); 179 assertEquals("3 rules should exist", 3, flowCount());
163 validateEvents(RULE_ADDED, RULE_ADDED, RULE_ADDED); 180 validateEvents(RULE_ADDED, RULE_ADDED, RULE_ADDED);
164 181
165 - FlowRule rem1 = flowRule(1, 1); 182 + FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED);
166 - FlowRule rem2 = flowRule(2, 2); 183 + FlowRule rem2 = flowRule(f2, FlowRuleState.REMOVED);
167 mgr.removeFlowRules(rem1, rem2); 184 mgr.removeFlowRules(rem1, rem2);
168 //removing from north, so no events generated 185 //removing from north, so no events generated
169 validateEvents(); 186 validateEvents();
170 - assertEquals("1 rule should exist", 1, flowCount()); 187 + assertEquals("3 rule should exist", 3, flowCount());
188 + assertTrue("Entries should be pending remove.",
189 + validateState(FlowRuleState.CREATED, FlowRuleState.PENDING_REMOVE,
190 + FlowRuleState.PENDING_REMOVE));
171 191
172 mgr.removeFlowRules(rem1); 192 mgr.removeFlowRules(rem1);
173 - assertEquals("1 rule should still exist", 1, flowCount()); 193 + assertEquals("3 rule should still exist", 3, flowCount());
174 } 194 }
175 195
176 @Test 196 @Test
177 public void flowRemoved() { 197 public void flowRemoved() {
178 - addFlowRule(1); 198 + FlowRule f1 = addFlowRule(1);
179 addFlowRule(2); 199 addFlowRule(2);
180 - FlowRule rem1 = flowRule(1, 1); 200 + FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED);
181 - providerSerivce.flowRemoved(rem1); 201 + providerService.flowRemoved(rem1);
182 validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED); 202 validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED);
183 203
184 - providerSerivce.flowRemoved(rem1); 204 + providerService.flowRemoved(rem1);
185 validateEvents(); 205 validateEvents();
186 } 206 }
187 207
208 + @Test
209 + public void flowMetrics() {
210 + FlowRule f1 = flowRule(1, 1);
211 + FlowRule f2 = flowRule(2, 2);
212 + FlowRule f3 = flowRule(3, 3);
213 +
214 + FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
215 + FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
216 + mgr.applyFlowRules(f1, f2, f3);
217 +
218 + providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2));
219 +
220 + assertTrue("Entries should be added.",
221 + validateState(FlowRuleState.PENDING_ADD, FlowRuleState.ADDED,
222 + FlowRuleState.ADDED));
223 + //TODO: add tests for flowmissing and extraneous flows
224 + }
225 +
188 private static class TestListener implements FlowRuleListener { 226 private static class TestListener implements FlowRuleListener {
189 final List<FlowRuleEvent> events = new ArrayList<>(); 227 final List<FlowRuleEvent> events = new ArrayList<>();
190 228
......
1 package org.onlab.onos.net.trivial.impl; 1 package org.onlab.onos.net.trivial.impl;
2 2
3 -import com.google.common.collect.HashMultimap; 3 +import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
4 -import com.google.common.collect.ImmutableSet; 4 +import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
5 -import com.google.common.collect.Multimap; 5 +import static org.slf4j.LoggerFactory.getLogger;
6 +
6 import org.apache.felix.scr.annotations.Activate; 7 import org.apache.felix.scr.annotations.Activate;
7 import org.apache.felix.scr.annotations.Component; 8 import org.apache.felix.scr.annotations.Component;
8 import org.apache.felix.scr.annotations.Deactivate; 9 import org.apache.felix.scr.annotations.Deactivate;
9 import org.apache.felix.scr.annotations.Service; 10 import org.apache.felix.scr.annotations.Service;
10 import org.onlab.onos.net.DeviceId; 11 import org.onlab.onos.net.DeviceId;
11 -import org.onlab.onos.net.flow.DefaultFlowRule;
12 import org.onlab.onos.net.flow.FlowRule; 12 import org.onlab.onos.net.flow.FlowRule;
13 import org.onlab.onos.net.flow.FlowRuleEvent; 13 import org.onlab.onos.net.flow.FlowRuleEvent;
14 +import org.onlab.onos.net.flow.FlowRuleEvent.Type;
14 import org.onlab.onos.net.flow.FlowRuleStore; 15 import org.onlab.onos.net.flow.FlowRuleStore;
15 import org.slf4j.Logger; 16 import org.slf4j.Logger;
16 17
17 -import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED; 18 +import com.google.common.collect.ArrayListMultimap;
18 -import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED; 19 +import com.google.common.collect.ImmutableSet;
19 -import static org.slf4j.LoggerFactory.getLogger; 20 +import com.google.common.collect.Multimap;
20 21
21 /** 22 /**
22 * Manages inventory of flow rules using trivial in-memory implementation. 23 * Manages inventory of flow rules using trivial in-memory implementation.
...@@ -28,7 +29,7 @@ public class SimpleFlowRuleStore implements FlowRuleStore { ...@@ -28,7 +29,7 @@ public class SimpleFlowRuleStore implements FlowRuleStore {
28 private final Logger log = getLogger(getClass()); 29 private final Logger log = getLogger(getClass());
29 30
30 // store entries as a pile of rules, no info about device tables 31 // store entries as a pile of rules, no info about device tables
31 - private final Multimap<DeviceId, FlowRule> flowEntries = HashMultimap.create(); 32 + private final Multimap<DeviceId, FlowRule> flowEntries = ArrayListMultimap.create();
32 33
33 @Activate 34 @Activate
34 public void activate() { 35 public void activate() {
...@@ -46,12 +47,27 @@ public class SimpleFlowRuleStore implements FlowRuleStore { ...@@ -46,12 +47,27 @@ public class SimpleFlowRuleStore implements FlowRuleStore {
46 } 47 }
47 48
48 @Override 49 @Override
49 - public FlowRule storeFlowRule(FlowRule rule) { 50 + public void storeFlowRule(FlowRule rule) {
51 + DeviceId did = rule.deviceId();
52 + flowEntries.put(did, rule);
53 + }
54 +
55 + @Override
56 + public void deleteFlowRule(FlowRule rule) {
50 DeviceId did = rule.deviceId(); 57 DeviceId did = rule.deviceId();
51 - FlowRule entry = new DefaultFlowRule(did, 58 +
52 - rule.selector(), rule.treatment(), rule.priority()); 59 + /*
53 - flowEntries.put(did, entry); 60 + * find the rule and mark it for deletion.
54 - return entry; 61 + * Ultimately a flow removed will come remove it.
62 + */
63 +
64 + if (flowEntries.containsEntry(did, rule)) {
65 + synchronized (flowEntries) {
66 +
67 + flowEntries.remove(did, rule);
68 + flowEntries.put(did, rule);
69 + }
70 + }
55 } 71 }
56 72
57 @Override 73 @Override
...@@ -59,12 +75,17 @@ public class SimpleFlowRuleStore implements FlowRuleStore { ...@@ -59,12 +75,17 @@ public class SimpleFlowRuleStore implements FlowRuleStore {
59 DeviceId did = rule.deviceId(); 75 DeviceId did = rule.deviceId();
60 76
61 // check if this new rule is an update to an existing entry 77 // check if this new rule is an update to an existing entry
62 - for (FlowRule fe : flowEntries.get(did)) { 78 + if (flowEntries.containsEntry(did, rule)) {
63 - if (rule.equals(fe)) { 79 + synchronized (flowEntries) {
64 - // TODO update the stats on this FlowRule? 80 + // Multimaps support duplicates so we have to remove our rule
65 - return null; 81 + // and replace it with the current version.
82 +
83 + flowEntries.remove(did, rule);
84 + flowEntries.put(did, rule);
66 } 85 }
86 + return new FlowRuleEvent(Type.RULE_UPDATED, rule);
67 } 87 }
88 +
68 flowEntries.put(did, rule); 89 flowEntries.put(did, rule);
69 return new FlowRuleEvent(RULE_ADDED, rule); 90 return new FlowRuleEvent(RULE_ADDED, rule);
70 } 91 }
...@@ -80,4 +101,6 @@ public class SimpleFlowRuleStore implements FlowRuleStore { ...@@ -80,4 +101,6 @@ public class SimpleFlowRuleStore implements FlowRuleStore {
80 } 101 }
81 } 102 }
82 103
104 +
105 +
83 } 106 }
......
...@@ -88,6 +88,24 @@ public class FlowModBuilder { ...@@ -88,6 +88,24 @@ public class FlowModBuilder {
88 88
89 } 89 }
90 90
91 + public OFFlowMod buildFlowDel() {
92 + Match match = buildMatch();
93 + List<OFAction> actions = buildActions();
94 +
95 + OFFlowMod fm = factory.buildFlowDelete()
96 + .setCookie(U64.of(cookie.value()))
97 + .setBufferId(OFBufferId.NO_BUFFER)
98 + .setActions(actions)
99 + .setMatch(match)
100 + .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
101 + .setIdleTimeout(10)
102 + .setHardTimeout(10)
103 + .setPriority(priority)
104 + .build();
105 +
106 + return fm;
107 + }
108 +
91 private List<OFAction> buildActions() { 109 private List<OFAction> buildActions() {
92 List<OFAction> acts = new LinkedList<>(); 110 List<OFAction> acts = new LinkedList<>();
93 for (Instruction i : treatment.instructions()) { 111 for (Instruction i : treatment.instructions()) {
...@@ -246,4 +264,6 @@ public class FlowModBuilder { ...@@ -246,4 +264,6 @@ public class FlowModBuilder {
246 return mBuilder.build(); 264 return mBuilder.build();
247 } 265 }
248 266
267 +
268 +
249 } 269 }
......
...@@ -10,6 +10,7 @@ import org.onlab.onos.net.flow.DefaultFlowRule; ...@@ -10,6 +10,7 @@ import org.onlab.onos.net.flow.DefaultFlowRule;
10 import org.onlab.onos.net.flow.DefaultTrafficSelector; 10 import org.onlab.onos.net.flow.DefaultTrafficSelector;
11 import org.onlab.onos.net.flow.DefaultTrafficTreatment; 11 import org.onlab.onos.net.flow.DefaultTrafficTreatment;
12 import org.onlab.onos.net.flow.FlowRule; 12 import org.onlab.onos.net.flow.FlowRule;
13 +import org.onlab.onos.net.flow.FlowRule.FlowRuleState;
13 import org.onlab.onos.net.flow.TrafficSelector; 14 import org.onlab.onos.net.flow.TrafficSelector;
14 import org.onlab.onos.net.flow.TrafficTreatment; 15 import org.onlab.onos.net.flow.TrafficTreatment;
15 import org.onlab.onos.net.flow.criteria.Criteria; 16 import org.onlab.onos.net.flow.criteria.Criteria;
...@@ -52,7 +53,7 @@ public class FlowRuleBuilder { ...@@ -52,7 +53,7 @@ public class FlowRuleBuilder {
52 this.match = entry.getMatch(); 53 this.match = entry.getMatch();
53 this.actions = entry.getActions(); 54 this.actions = entry.getActions();
54 this.dpid = dpid; 55 this.dpid = dpid;
55 - removed = null; 56 + this.removed = null;
56 } 57 }
57 58
58 public FlowRuleBuilder(Dpid dpid, OFFlowRemoved removed) { 59 public FlowRuleBuilder(Dpid dpid, OFFlowRemoved removed) {
...@@ -69,16 +70,16 @@ public class FlowRuleBuilder { ...@@ -69,16 +70,16 @@ public class FlowRuleBuilder {
69 if (stat != null) { 70 if (stat != null) {
70 return new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), 71 return new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
71 buildSelector(), buildTreatment(), stat.getPriority(), 72 buildSelector(), buildTreatment(), stat.getPriority(),
72 - stat.getDurationNsec() / 1000000, stat.getIdleTimeout(), 73 + FlowRuleState.ADDED, stat.getDurationNsec() / 1000000,
73 stat.getPacketCount().getValue(), stat.getByteCount().getValue(), 74 stat.getPacketCount().getValue(), stat.getByteCount().getValue(),
74 - (int) (stat.getCookie().getValue() & 0xFFFFFFFF)); 75 + stat.getCookie().getValue());
75 } else { 76 } else {
76 // TODO: revisit potentially. 77 // TODO: revisit potentially.
77 return new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)), 78 return new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
78 buildSelector(), null, removed.getPriority(), 79 buildSelector(), null, removed.getPriority(),
79 - removed.getDurationNsec() / 1000000, removed.getIdleTimeout(), 80 + FlowRuleState.REMOVED, removed.getDurationNsec() / 1000000,
80 removed.getPacketCount().getValue(), removed.getByteCount().getValue(), 81 removed.getPacketCount().getValue(), removed.getByteCount().getValue(),
81 - (int) (removed.getCookie().getValue() & 0xFFFFFFFF)); 82 + removed.getCookie().getValue());
82 } 83 }
83 } 84 }
84 85
......
...@@ -10,6 +10,7 @@ import org.apache.felix.scr.annotations.Component; ...@@ -10,6 +10,7 @@ import org.apache.felix.scr.annotations.Component;
10 import org.apache.felix.scr.annotations.Deactivate; 10 import org.apache.felix.scr.annotations.Deactivate;
11 import org.apache.felix.scr.annotations.Reference; 11 import org.apache.felix.scr.annotations.Reference;
12 import org.apache.felix.scr.annotations.ReferenceCardinality; 12 import org.apache.felix.scr.annotations.ReferenceCardinality;
13 +import org.onlab.onos.net.DeviceId;
13 import org.onlab.onos.net.flow.FlowRule; 14 import org.onlab.onos.net.flow.FlowRule;
14 import org.onlab.onos.net.flow.FlowRuleProvider; 15 import org.onlab.onos.net.flow.FlowRuleProvider;
15 import org.onlab.onos.net.flow.FlowRuleProviderRegistry; 16 import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
...@@ -94,8 +95,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -94,8 +95,16 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
94 95
95 @Override 96 @Override
96 public void removeFlowRule(FlowRule... flowRules) { 97 public void removeFlowRule(FlowRule... flowRules) {
97 - // TODO Auto-generated method stub 98 + for (int i = 0; i < flowRules.length; i++) {
99 + removeRule(flowRules[i]);
100 + }
101 +
102 + }
103 +
98 104
105 + private void removeRule(FlowRule flowRule) {
106 + OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
107 + sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowDel());
99 } 108 }
100 109
101 110
...@@ -108,7 +117,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -108,7 +117,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
108 117
109 @Override 118 @Override
110 public void switchAdded(Dpid dpid) { 119 public void switchAdded(Dpid dpid) {
111 - FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), 1); 120 + FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), 5);
112 fsc.start(); 121 fsc.start();
113 collectors.put(dpid, fsc); 122 collectors.put(dpid, fsc);
114 } 123 }
...@@ -154,7 +163,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -154,7 +163,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
154 entries.add(new FlowRuleBuilder(dpid, reply).build()); 163 entries.add(new FlowRuleBuilder(dpid, reply).build());
155 } 164 }
156 log.debug("sending flowstats to core {}", entries); 165 log.debug("sending flowstats to core {}", entries);
157 - providerService.pushFlowMetrics(entries); 166 + providerService.pushFlowMetrics(DeviceId.deviceId(Dpid.uri(dpid)), entries);
158 } 167 }
159 168
160 } 169 }
......
1 +package org.onlab.packet;
2 +
3 +import java.util.Arrays;
4 +
5 +/**
6 + * A class representing an IPv4 address.
7 + * <p/>
8 + * TODO this class is a clone of IpPrefix and still needs to be modified to
9 + * look more like an IpAddress.
10 + */
11 +public final class IpAddress {
12 +
13 + // TODO a comparator for netmasks? E.g. for sorting by prefix match order.
14 +
15 + //IP Versions
16 + public enum Version { INET, INET6 };
17 +
18 + //lengths of address, in bytes
19 + public static final int INET_LEN = 4;
20 + public static final int INET6_LEN = 16;
21 +
22 + //maximum CIDR value
23 + public static final int MAX_INET_MASK = 32;
24 + //no mask (no network), e.g. a simple address
25 + public static final int DEFAULT_MASK = 0;
26 +
27 + /**
28 + * Default value indicating an unspecified address.
29 + */
30 + static final byte[] ANY = new byte [] {0, 0, 0, 0};
31 +
32 + protected Version version;
33 +
34 + protected byte[] octets;
35 + protected int netmask;
36 +
37 + private IpAddress(Version ver, byte[] octets, int netmask) {
38 + this.version = ver;
39 + this.octets = Arrays.copyOf(octets, INET_LEN);
40 + this.netmask = netmask;
41 + }
42 +
43 + private IpAddress(Version ver, byte[] octets) {
44 + this.version = ver;
45 + this.octets = Arrays.copyOf(octets, INET_LEN);
46 + this.netmask = DEFAULT_MASK;
47 + }
48 +
49 + /**
50 + * Converts a byte array into an IP address.
51 + *
52 + * @param address a byte array
53 + * @return an IP address
54 + */
55 + public static IpAddress valueOf(byte [] address) {
56 + return new IpAddress(Version.INET, address);
57 + }
58 +
59 + /**
60 + * Converts a byte array into an IP address.
61 + *
62 + * @param address a byte array
63 + * @param netmask the CIDR value subnet mask
64 + * @return an IP address
65 + */
66 + public static IpAddress valueOf(byte [] address, int netmask) {
67 + return new IpAddress(Version.INET, address, netmask);
68 + }
69 +
70 + /**
71 + * Helper to convert an integer into a byte array.
72 + *
73 + * @param address the integer to convert
74 + * @return a byte array
75 + */
76 + private static byte [] bytes(int address) {
77 + byte [] bytes = new byte [INET_LEN];
78 + for (int i = 0; i < INET_LEN; i++) {
79 + bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff);
80 + }
81 +
82 + return bytes;
83 + }
84 +
85 + /**
86 + * Converts an integer into an IPv4 address.
87 + *
88 + * @param address an integer representing an IP value
89 + * @return an IP address
90 + */
91 + public static IpAddress valueOf(int address) {
92 + return new IpAddress(Version.INET, bytes(address));
93 + }
94 +
95 + /**
96 + * Converts an integer into an IPv4 address.
97 + *
98 + * @param address an integer representing an IP value
99 + * @param netmask the CIDR value subnet mask
100 + * @return an IP address
101 + */
102 + public static IpAddress valueOf(int address, int netmask) {
103 + return new IpAddress(Version.INET, bytes(address), netmask);
104 + }
105 +
106 + /**
107 + * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
108 + * string can also be in CIDR (slash) notation. If the netmask is omitted,
109 + * it will be set to DEFAULT_MASK (0).
110 + *
111 + * @param address a IP address in string form, e.g. "10.0.0.1", "10.0.0.1/24"
112 + * @return an IP address
113 + */
114 + public static IpAddress valueOf(String address) {
115 +
116 + final String [] parts = address.split("\\/");
117 + if (parts.length > 2) {
118 + throw new IllegalArgumentException("Malformed IP address string; "
119 + + "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
120 + }
121 +
122 + int mask = DEFAULT_MASK;
123 + if (parts.length == 2) {
124 + mask = Integer.valueOf(parts[1]);
125 + if (mask > MAX_INET_MASK) {
126 + throw new IllegalArgumentException(
127 + "Value of subnet mask cannot exceed "
128 + + MAX_INET_MASK);
129 + }
130 + }
131 +
132 + final String [] net = parts[0].split("\\.");
133 + if (net.length != INET_LEN) {
134 + throw new IllegalArgumentException("Malformed IP address string; "
135 + + "Address must have four decimal values separated by dots (.)");
136 + }
137 + final byte [] bytes = new byte[INET_LEN];
138 + for (int i = 0; i < INET_LEN; i++) {
139 + bytes[i] = (byte) Short.parseShort(net[i], 10);
140 + }
141 + return new IpAddress(Version.INET, bytes, mask);
142 + }
143 +
144 + /**
145 + * Returns the IP version of this address.
146 + *
147 + * @return the version
148 + */
149 + public Version version() {
150 + return this.version;
151 + }
152 +
153 + /**
154 + * Returns the IP address as a byte array.
155 + *
156 + * @return a byte array
157 + */
158 + public byte[] toOctets() {
159 + return Arrays.copyOf(this.octets, INET_LEN);
160 + }
161 +
162 + /**
163 + * Returns the IP address prefix length.
164 + *
165 + * @return prefix length
166 + */
167 + public int prefixLength() {
168 + return netmask;
169 + }
170 +
171 + /**
172 + * Returns the integral value of this IP address.
173 + *
174 + * @return the IP address's value as an integer
175 + */
176 + public int toInt() {
177 + int address = 0;
178 + for (int i = 0; i < INET_LEN; i++) {
179 + address |= octets[i] << ((INET_LEN - (i + 1)) * 8);
180 + }
181 + return address;
182 + }
183 +
184 + /**
185 + * Helper for computing the mask value from CIDR.
186 + *
187 + * @return an integer bitmask
188 + */
189 + private int mask() {
190 + int shift = MAX_INET_MASK - this.netmask;
191 + return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
192 + }
193 +
194 + /**
195 + * Returns the subnet mask in IpAddress form. The netmask value for
196 + * the returned IpAddress is 0, as the address itself is a mask.
197 + *
198 + * @return the subnet mask
199 + */
200 + public IpAddress netmask() {
201 + return new IpAddress(Version.INET, bytes(mask()));
202 + }
203 +
204 + /**
205 + * Returns the network portion of this address as an IpAddress.
206 + * The netmask of the returned IpAddress is the current mask. If this
207 + * address doesn't have a mask, this returns an all-0 IpAddress.
208 + *
209 + * @return the network address or null
210 + */
211 + public IpAddress network() {
212 + if (netmask == DEFAULT_MASK) {
213 + return new IpAddress(version, ANY, DEFAULT_MASK);
214 + }
215 +
216 + byte [] net = new byte [4];
217 + byte [] mask = bytes(mask());
218 + for (int i = 0; i < INET_LEN; i++) {
219 + net[i] = (byte) (octets[i] & mask[i]);
220 + }
221 + return new IpAddress(version, net, netmask);
222 + }
223 +
224 + /**
225 + * Returns the host portion of the IPAddress, as an IPAddress.
226 + * The netmask of the returned IpAddress is the current mask. If this
227 + * address doesn't have a mask, this returns a copy of the current
228 + * address.
229 + *
230 + * @return the host address
231 + */
232 + public IpAddress host() {
233 + if (netmask == DEFAULT_MASK) {
234 + new IpAddress(version, octets, netmask);
235 + }
236 +
237 + byte [] host = new byte [INET_LEN];
238 + byte [] mask = bytes(mask());
239 + for (int i = 0; i < INET_LEN; i++) {
240 + host[i] = (byte) (octets[i] & ~mask[i]);
241 + }
242 + return new IpAddress(version, host, netmask);
243 + }
244 +
245 + public boolean isMasked() {
246 + return mask() != 0;
247 + }
248 +
249 + /**
250 + * Determines whether a given address is contained within this IpAddress'
251 + * network.
252 + *
253 + * @param other another IP address that could be contained in this network
254 + * @return true if the other IP address is contained in this address'
255 + * network, otherwise false
256 + */
257 + public boolean contains(IpAddress other) {
258 + if (this.netmask <= other.netmask) {
259 + // Special case where they're both /32 addresses
260 + if (this.netmask == MAX_INET_MASK) {
261 + return Arrays.equals(octets, other.octets);
262 + }
263 +
264 + // Mask the other address with our network mask
265 + IpAddress otherMasked =
266 + IpAddress.valueOf(other.octets, netmask).network();
267 +
268 + return network().equals(otherMasked);
269 + }
270 + return false;
271 + }
272 +
273 + @Override
274 + public int hashCode() {
275 + final int prime = 31;
276 + int result = 1;
277 + result = prime * result + netmask;
278 + result = prime * result + Arrays.hashCode(octets);
279 + result = prime * result + ((version == null) ? 0 : version.hashCode());
280 + return result;
281 + }
282 +
283 + @Override
284 + public boolean equals(Object obj) {
285 + if (this == obj) {
286 + return true;
287 + }
288 + if (obj == null) {
289 + return false;
290 + }
291 + if (getClass() != obj.getClass()) {
292 + return false;
293 + }
294 + IpAddress other = (IpAddress) obj;
295 + if (netmask != other.netmask) {
296 + return false;
297 + }
298 + if (!Arrays.equals(octets, other.octets)) {
299 + return false;
300 + }
301 + if (version != other.version) {
302 + return false;
303 + }
304 + return true;
305 + }
306 +
307 + @Override
308 + /*
309 + * (non-Javadoc)
310 + * format is "x.x.x.x" for non-masked (netmask 0) addresses,
311 + * and "x.x.x.x/y" for masked addresses.
312 + *
313 + * @see java.lang.Object#toString()
314 + */
315 + public String toString() {
316 + final StringBuilder builder = new StringBuilder();
317 + for (final byte b : this.octets) {
318 + if (builder.length() > 0) {
319 + builder.append(".");
320 + }
321 + builder.append(String.format("%d", b & 0xff));
322 + }
323 + if (netmask != DEFAULT_MASK) {
324 + builder.append("/");
325 + builder.append(String.format("%d", netmask));
326 + }
327 + return builder.toString();
328 + }
329 +
330 +}
...@@ -3,7 +3,9 @@ package org.onlab.packet; ...@@ -3,7 +3,9 @@ package org.onlab.packet;
3 import java.util.Arrays; 3 import java.util.Arrays;
4 4
5 /** 5 /**
6 - * A class representing an IPv4 address. 6 + * A class representing an IPv4 prefix.
7 + * <p/>
8 + * A prefix consists of an IP address and a subnet mask.
7 */ 9 */
8 public final class IpPrefix { 10 public final class IpPrefix {
9 11
......