Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Showing
61 changed files
with
1772 additions
and
401 deletions
... | @@ -15,18 +15,29 @@ | ... | @@ -15,18 +15,29 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.calendar; | 16 | package org.onlab.onos.calendar; |
17 | 17 | ||
18 | -import org.onlab.onos.net.ConnectPoint; | 18 | +import java.net.URI; |
19 | -import org.onlab.onos.net.DeviceId; | ||
20 | -import org.onlab.onos.net.intent.IntentService; | ||
21 | -import org.onlab.rest.BaseResource; | ||
22 | 19 | ||
23 | import javax.ws.rs.POST; | 20 | import javax.ws.rs.POST; |
24 | import javax.ws.rs.Path; | 21 | import javax.ws.rs.Path; |
25 | import javax.ws.rs.PathParam; | 22 | import javax.ws.rs.PathParam; |
26 | import javax.ws.rs.core.Response; | 23 | import javax.ws.rs.core.Response; |
27 | -import java.net.URI; | 24 | + |
25 | +import org.onlab.onos.core.ApplicationId; | ||
26 | +import org.onlab.onos.core.CoreService; | ||
27 | +import org.onlab.onos.net.ConnectPoint; | ||
28 | +import org.onlab.onos.net.DeviceId; | ||
29 | +import org.onlab.onos.net.flow.DefaultTrafficSelector; | ||
30 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
31 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
32 | +import org.onlab.onos.net.intent.Intent; | ||
33 | +import org.onlab.onos.net.intent.IntentService; | ||
34 | +import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint; | ||
35 | +import org.onlab.onos.net.resource.BandwidthResourceRequest; | ||
36 | +import org.onlab.packet.Ethernet; | ||
37 | +import org.onlab.rest.BaseResource; | ||
28 | 38 | ||
29 | import static org.onlab.onos.net.PortNumber.portNumber; | 39 | import static org.onlab.onos.net.PortNumber.portNumber; |
40 | +import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder; | ||
30 | 41 | ||
31 | /** | 42 | /** |
32 | * Web resource for triggering calendared intents. | 43 | * Web resource for triggering calendared intents. |
... | @@ -47,12 +58,33 @@ public class BandwidthCalendarResource extends BaseResource { | ... | @@ -47,12 +58,33 @@ public class BandwidthCalendarResource extends BaseResource { |
47 | ConnectPoint srcPoint = new ConnectPoint(deviceId(src), portNumber(srcPort)); | 58 | ConnectPoint srcPoint = new ConnectPoint(deviceId(src), portNumber(srcPort)); |
48 | ConnectPoint dstPoint = new ConnectPoint(deviceId(dst), portNumber(dstPort)); | 59 | ConnectPoint dstPoint = new ConnectPoint(deviceId(dst), portNumber(dstPort)); |
49 | 60 | ||
61 | + TrafficSelector selector = buildTrafficSelector(); | ||
62 | + TrafficTreatment treatment = builder().build(); | ||
63 | + | ||
64 | + Intent intent = new PointToPointIntentWithBandwidthConstraint( | ||
65 | + appId(), selector, treatment, | ||
66 | + srcPoint, dstPoint, new BandwidthResourceRequest(Double.parseDouble(bandwidth))); | ||
67 | + service.submit(intent); | ||
68 | + | ||
50 | return Response.ok("Yo! We got src=" + srcPoint + "; dst=" + dstPoint + | 69 | return Response.ok("Yo! We got src=" + srcPoint + "; dst=" + dstPoint + |
51 | "; bw=" + bandwidth + "; intent service " + service).build(); | 70 | "; bw=" + bandwidth + "; intent service " + service).build(); |
52 | } | 71 | } |
53 | 72 | ||
73 | + private TrafficSelector buildTrafficSelector() { | ||
74 | + TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); | ||
75 | + Short ethType = Ethernet.TYPE_IPV4; | ||
76 | + | ||
77 | + selectorBuilder.matchEthType(ethType); | ||
78 | + | ||
79 | + return selectorBuilder.build(); | ||
80 | + } | ||
81 | + | ||
54 | private DeviceId deviceId(String dpid) { | 82 | private DeviceId deviceId(String dpid) { |
55 | return DeviceId.deviceId(URI.create("of:" + dpid)); | 83 | return DeviceId.deviceId(URI.create("of:" + dpid)); |
56 | } | 84 | } |
57 | 85 | ||
86 | + protected ApplicationId appId() { | ||
87 | + return get(CoreService.class).registerApplication("org.onlab.onos.calendar"); | ||
88 | + } | ||
89 | + | ||
58 | } | 90 | } | ... | ... |
... | @@ -76,7 +76,7 @@ | ... | @@ -76,7 +76,7 @@ |
76 | "nodeName1": "ROUTER1", | 76 | "nodeName1": "ROUTER1", |
77 | "nodeName2": "ROADM1", | 77 | "nodeName2": "ROADM1", |
78 | "bandWidth": 100000, | 78 | "bandWidth": 100000, |
79 | - "port1": 1, | 79 | + "port1": 2, |
80 | "port2": 10 | 80 | "port2": 10 |
81 | }, | 81 | }, |
82 | "type": "pktOptLink" | 82 | "type": "pktOptLink" |
... | @@ -90,7 +90,7 @@ | ... | @@ -90,7 +90,7 @@ |
90 | "nodeName1": "ROUTER2", | 90 | "nodeName1": "ROUTER2", |
91 | "nodeName2": "ROADM2", | 91 | "nodeName2": "ROADM2", |
92 | "bandWidth": 100000, | 92 | "bandWidth": 100000, |
93 | - "port1": 1, | 93 | + "port1": 2, |
94 | "port2": 11 | 94 | "port2": 11 |
95 | }, | 95 | }, |
96 | "type": "pktOptLink" | 96 | "type": "pktOptLink" | ... | ... |
cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentWithBandwidthConstraintCommand.java
0 → 100644
1 | +/* | ||
2 | + * Licensed to the Apache Software Foundation (ASF) under one | ||
3 | + * or more contributor license agreements. See the NOTICE file | ||
4 | + * distributed with this work for additional information | ||
5 | + * regarding copyright ownership. The ASF licenses this file | ||
6 | + * to you under the Apache License, Version 2.0 (the | ||
7 | + * "License"); you may not use this file except in compliance | ||
8 | + * with the License. You may obtain a copy of the License at | ||
9 | + * | ||
10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + * | ||
12 | + * Unless required by applicable law or agreed to in writing, | ||
13 | + * software distributed under the License is distributed on an | ||
14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
15 | + * KIND, either express or implied. See the License for the | ||
16 | + * specific language governing permissions and limitations | ||
17 | + * under the License. | ||
18 | + */ | ||
19 | +package org.onlab.onos.cli.net; | ||
20 | + | ||
21 | +import org.apache.karaf.shell.commands.Argument; | ||
22 | +import org.apache.karaf.shell.commands.Command; | ||
23 | +import org.onlab.onos.net.ConnectPoint; | ||
24 | +import org.onlab.onos.net.DeviceId; | ||
25 | +import org.onlab.onos.net.PortNumber; | ||
26 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
27 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
28 | +import org.onlab.onos.net.intent.Intent; | ||
29 | +import org.onlab.onos.net.intent.IntentService; | ||
30 | +import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint; | ||
31 | +import org.onlab.onos.net.resource.BandwidthResourceRequest; | ||
32 | + | ||
33 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
34 | +import static org.onlab.onos.net.PortNumber.portNumber; | ||
35 | +import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder; | ||
36 | + | ||
37 | +/** | ||
38 | + * Installs point-to-point connectivity intents. | ||
39 | + */ | ||
40 | +@Command(scope = "onos", name = "add-point-intent-bw", | ||
41 | + description = "Installs point-to-point connectivity intent with bandwidth constraint") | ||
42 | +public class AddPointToPointIntentWithBandwidthConstraintCommand extends ConnectivityIntentCommand { | ||
43 | + | ||
44 | + @Argument(index = 0, name = "ingressDevice", | ||
45 | + description = "Ingress Device/Port Description", | ||
46 | + required = true, multiValued = false) | ||
47 | + String ingressDeviceString = null; | ||
48 | + | ||
49 | + @Argument(index = 1, name = "egressDevice", | ||
50 | + description = "Egress Device/Port Description", | ||
51 | + required = true, multiValued = false) | ||
52 | + String egressDeviceString = null; | ||
53 | + | ||
54 | + @Argument(index = 2, name = "bandwidth", | ||
55 | + description = "Bandwidth", | ||
56 | + required = true, multiValued = false) | ||
57 | + String bandwidthString = null; | ||
58 | + | ||
59 | + @Override | ||
60 | + protected void execute() { | ||
61 | + IntentService service = get(IntentService.class); | ||
62 | + | ||
63 | + DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString)); | ||
64 | + PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString)); | ||
65 | + ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber); | ||
66 | + | ||
67 | + DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString)); | ||
68 | + PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString)); | ||
69 | + ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber); | ||
70 | + | ||
71 | + long bandwidth = Long.parseLong(bandwidthString); | ||
72 | + | ||
73 | + TrafficSelector selector = buildTrafficSelector(); | ||
74 | + TrafficTreatment treatment = builder().build(); | ||
75 | + | ||
76 | + Intent intent = new PointToPointIntentWithBandwidthConstraint( | ||
77 | + appId(), selector, treatment, | ||
78 | + ingress, egress, new BandwidthResourceRequest(bandwidth)); | ||
79 | + service.submit(intent); | ||
80 | + } | ||
81 | + | ||
82 | + /** | ||
83 | + * Extracts the port number portion of the ConnectPoint. | ||
84 | + * | ||
85 | + * @param deviceString string representing the device/port | ||
86 | + * @return port number as a string, empty string if the port is not found | ||
87 | + */ | ||
88 | + private String getPortNumber(String deviceString) { | ||
89 | + int slash = deviceString.indexOf('/'); | ||
90 | + if (slash <= 0) { | ||
91 | + return ""; | ||
92 | + } | ||
93 | + return deviceString.substring(slash + 1, deviceString.length()); | ||
94 | + } | ||
95 | + | ||
96 | + /** | ||
97 | + * Extracts the device ID portion of the ConnectPoint. | ||
98 | + * | ||
99 | + * @param deviceString string representing the device/port | ||
100 | + * @return device ID string | ||
101 | + */ | ||
102 | + private String getDeviceId(String deviceString) { | ||
103 | + int slash = deviceString.indexOf('/'); | ||
104 | + if (slash <= 0) { | ||
105 | + return ""; | ||
106 | + } | ||
107 | + return deviceString.substring(0, slash); | ||
108 | + } | ||
109 | +} |
... | @@ -47,8 +47,8 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { | ... | @@ -47,8 +47,8 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { |
47 | */ | 47 | */ |
48 | protected TrafficSelector buildTrafficSelector() { | 48 | protected TrafficSelector buildTrafficSelector() { |
49 | TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); | 49 | TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); |
50 | - | ||
51 | Short ethType = Ethernet.TYPE_IPV4; | 50 | Short ethType = Ethernet.TYPE_IPV4; |
51 | + | ||
52 | if (!Strings.isNullOrEmpty(ethTypeString)) { | 52 | if (!Strings.isNullOrEmpty(ethTypeString)) { |
53 | EthType ethTypeParameter = EthType.valueOf(ethTypeString); | 53 | EthType ethTypeParameter = EthType.valueOf(ethTypeString); |
54 | ethType = ethTypeParameter.value(); | 54 | ethType = ethTypeParameter.value(); | ... | ... |
... | @@ -40,7 +40,7 @@ import static org.onlab.onos.net.DeviceId.deviceId; | ... | @@ -40,7 +40,7 @@ import static org.onlab.onos.net.DeviceId.deviceId; |
40 | description = "Lists all ports or all ports of a device") | 40 | description = "Lists all ports or all ports of a device") |
41 | public class DevicePortsListCommand extends DevicesListCommand { | 41 | public class DevicePortsListCommand extends DevicesListCommand { |
42 | 42 | ||
43 | - private static final String FMT = " port=%s, state=%s%s"; | 43 | + private static final String FMT = " port=%s, state=%s, type=%s, speed=%s%s"; |
44 | 44 | ||
45 | @Option(name = "-e", aliases = "--enabled", description = "Show only enabled ports", | 45 | @Option(name = "-e", aliases = "--enabled", description = "Show only enabled ports", |
46 | required = false, multiValued = false) | 46 | required = false, multiValued = false) |
... | @@ -110,10 +110,14 @@ public class DevicePortsListCommand extends DevicesListCommand { | ... | @@ -110,10 +110,14 @@ public class DevicePortsListCommand extends DevicesListCommand { |
110 | ports.add(mapper.createObjectNode() | 110 | ports.add(mapper.createObjectNode() |
111 | .put("port", port.number().toString()) | 111 | .put("port", port.number().toString()) |
112 | .put("isEnabled", port.isEnabled()) | 112 | .put("isEnabled", port.isEnabled()) |
113 | + .put("type", port.type().toString().toLowerCase()) | ||
114 | + .put("portSpeed", port.portSpeed()) | ||
113 | .set("annotations", annotations(mapper, port.annotations()))); | 115 | .set("annotations", annotations(mapper, port.annotations()))); |
114 | } | 116 | } |
115 | } | 117 | } |
116 | - return result.put("device", device.id().toString()).set("ports", ports); | 118 | + result.set("device", json(service, mapper, device)); |
119 | + result.set("ports", ports); | ||
120 | + return result; | ||
117 | } | 121 | } |
118 | 122 | ||
119 | // Determines if a port should be included in output. | 123 | // Determines if a port should be included in output. |
... | @@ -130,6 +134,7 @@ public class DevicePortsListCommand extends DevicesListCommand { | ... | @@ -130,6 +134,7 @@ public class DevicePortsListCommand extends DevicesListCommand { |
130 | for (Port port : ports) { | 134 | for (Port port : ports) { |
131 | if (isIncluded(port)) { | 135 | if (isIncluded(port)) { |
132 | print(FMT, port.number(), port.isEnabled() ? "enabled" : "disabled", | 136 | print(FMT, port.number(), port.isEnabled() ? "enabled" : "disabled", |
137 | + port.type().toString().toLowerCase(), port.portSpeed(), | ||
133 | annotations(port.annotations())); | 138 | annotations(port.annotations())); |
134 | } | 139 | } |
135 | } | 140 | } | ... | ... |
... | @@ -116,6 +116,17 @@ | ... | @@ -116,6 +116,17 @@ |
116 | </optional-completers> | 116 | </optional-completers> |
117 | </command> | 117 | </command> |
118 | <command> | 118 | <command> |
119 | + <action class="org.onlab.onos.cli.net.AddPointToPointIntentWithBandwidthConstraintCommand"/> | ||
120 | + <completers> | ||
121 | + <ref component-id="connectPointCompleter"/> | ||
122 | + <ref component-id="connectPointCompleter"/> | ||
123 | + <null/> | ||
124 | + </completers> | ||
125 | + <optional-completers> | ||
126 | + <entry key="-t" value-ref="ethTypeCompleter"/> | ||
127 | + </optional-completers> | ||
128 | + </command> | ||
129 | + <command> | ||
119 | <action class="org.onlab.onos.cli.net.AddOpticalIntentCommand"/> | 130 | <action class="org.onlab.onos.cli.net.AddOpticalIntentCommand"/> |
120 | <completers> | 131 | <completers> |
121 | <ref component-id="connectPointCompleter"/> | 132 | <ref component-id="connectPointCompleter"/> | ... | ... |
... | @@ -35,6 +35,11 @@ public class RoleInfo { | ... | @@ -35,6 +35,11 @@ public class RoleInfo { |
35 | this.backups = ImmutableList.copyOf(backups); | 35 | this.backups = ImmutableList.copyOf(backups); |
36 | } | 36 | } |
37 | 37 | ||
38 | + public RoleInfo() { | ||
39 | + this.master = null; | ||
40 | + this.backups = ImmutableList.of(); | ||
41 | + } | ||
42 | + | ||
38 | public NodeId master() { | 43 | public NodeId master() { |
39 | return master; | 44 | return master; |
40 | } | 45 | } |
... | @@ -63,7 +68,7 @@ public class RoleInfo { | ... | @@ -63,7 +68,7 @@ public class RoleInfo { |
63 | 68 | ||
64 | @Override | 69 | @Override |
65 | public int hashCode() { | 70 | public int hashCode() { |
66 | - return Objects.hash(master, backups.hashCode()); | 71 | + return Objects.hash(master, backups); |
67 | } | 72 | } |
68 | 73 | ||
69 | @Override | 74 | @Override | ... | ... |
... | @@ -24,9 +24,27 @@ import static com.google.common.base.MoreObjects.toStringHelper; | ... | @@ -24,9 +24,27 @@ import static com.google.common.base.MoreObjects.toStringHelper; |
24 | */ | 24 | */ |
25 | public class DefaultPort extends AbstractAnnotated implements Port { | 25 | public class DefaultPort extends AbstractAnnotated implements Port { |
26 | 26 | ||
27 | + /** Default port speed in Mbps. */ | ||
28 | + public static final long DEFAULT_SPEED = 1_000; | ||
29 | + | ||
27 | private final Element element; | 30 | private final Element element; |
28 | private final PortNumber number; | 31 | private final PortNumber number; |
29 | private final boolean isEnabled; | 32 | private final boolean isEnabled; |
33 | + private final Type type; | ||
34 | + private final long portSpeed; | ||
35 | + | ||
36 | + /** | ||
37 | + * Creates a network element attributed to the specified provider. | ||
38 | + * | ||
39 | + * @param element parent network element | ||
40 | + * @param number port number | ||
41 | + * @param isEnabled indicator whether the port is up and active | ||
42 | + * @param annotations optional key/value annotations | ||
43 | + */ | ||
44 | + public DefaultPort(Element element, PortNumber number, boolean isEnabled, | ||
45 | + Annotations... annotations) { | ||
46 | + this(element, number, isEnabled, Type.COPPER, DEFAULT_SPEED, annotations); | ||
47 | + } | ||
30 | 48 | ||
31 | /** | 49 | /** |
32 | * Creates a network element attributed to the specified provider. | 50 | * Creates a network element attributed to the specified provider. |
... | @@ -34,19 +52,49 @@ public class DefaultPort extends AbstractAnnotated implements Port { | ... | @@ -34,19 +52,49 @@ public class DefaultPort extends AbstractAnnotated implements Port { |
34 | * @param element parent network element | 52 | * @param element parent network element |
35 | * @param number port number | 53 | * @param number port number |
36 | * @param isEnabled indicator whether the port is up and active | 54 | * @param isEnabled indicator whether the port is up and active |
55 | + * @param type port type | ||
56 | + * @param portSpeed port speed in Mbs | ||
37 | * @param annotations optional key/value annotations | 57 | * @param annotations optional key/value annotations |
38 | */ | 58 | */ |
39 | - public DefaultPort(Element element, PortNumber number, | 59 | + public DefaultPort(Element element, PortNumber number, boolean isEnabled, |
40 | - boolean isEnabled, Annotations... annotations) { | 60 | + Type type, long portSpeed, Annotations... annotations) { |
41 | super(annotations); | 61 | super(annotations); |
42 | this.element = element; | 62 | this.element = element; |
43 | this.number = number; | 63 | this.number = number; |
44 | this.isEnabled = isEnabled; | 64 | this.isEnabled = isEnabled; |
65 | + this.type = type; | ||
66 | + this.portSpeed = portSpeed; | ||
67 | + | ||
68 | + } | ||
69 | + | ||
70 | + @Override | ||
71 | + public Element element() { | ||
72 | + return element; | ||
73 | + } | ||
74 | + | ||
75 | + @Override | ||
76 | + public PortNumber number() { | ||
77 | + return number; | ||
78 | + } | ||
79 | + | ||
80 | + @Override | ||
81 | + public boolean isEnabled() { | ||
82 | + return isEnabled; | ||
83 | + } | ||
84 | + | ||
85 | + @Override | ||
86 | + public Type type() { | ||
87 | + return type; | ||
88 | + } | ||
89 | + | ||
90 | + @Override | ||
91 | + public long portSpeed() { | ||
92 | + return portSpeed; | ||
45 | } | 93 | } |
46 | 94 | ||
47 | @Override | 95 | @Override |
48 | public int hashCode() { | 96 | public int hashCode() { |
49 | - return Objects.hash(number, isEnabled); | 97 | + return Objects.hash(number, isEnabled, type, portSpeed); |
50 | } | 98 | } |
51 | 99 | ||
52 | @Override | 100 | @Override |
... | @@ -58,7 +106,9 @@ public class DefaultPort extends AbstractAnnotated implements Port { | ... | @@ -58,7 +106,9 @@ public class DefaultPort extends AbstractAnnotated implements Port { |
58 | final DefaultPort other = (DefaultPort) obj; | 106 | final DefaultPort other = (DefaultPort) obj; |
59 | return Objects.equals(this.element.id(), other.element.id()) && | 107 | return Objects.equals(this.element.id(), other.element.id()) && |
60 | Objects.equals(this.number, other.number) && | 108 | Objects.equals(this.number, other.number) && |
61 | - Objects.equals(this.isEnabled, other.isEnabled); | 109 | + Objects.equals(this.isEnabled, other.isEnabled) && |
110 | + Objects.equals(this.type, other.type) && | ||
111 | + Objects.equals(this.portSpeed, other.portSpeed); | ||
62 | } | 112 | } |
63 | return false; | 113 | return false; |
64 | } | 114 | } |
... | @@ -69,22 +119,9 @@ public class DefaultPort extends AbstractAnnotated implements Port { | ... | @@ -69,22 +119,9 @@ public class DefaultPort extends AbstractAnnotated implements Port { |
69 | .add("element", element.id()) | 119 | .add("element", element.id()) |
70 | .add("number", number) | 120 | .add("number", number) |
71 | .add("isEnabled", isEnabled) | 121 | .add("isEnabled", isEnabled) |
122 | + .add("type", type) | ||
123 | + .add("portSpeed", portSpeed) | ||
72 | .toString(); | 124 | .toString(); |
73 | } | 125 | } |
74 | 126 | ||
75 | - @Override | ||
76 | - public PortNumber number() { | ||
77 | - return number; | ||
78 | - } | ||
79 | - | ||
80 | - @Override | ||
81 | - public boolean isEnabled() { | ||
82 | - return isEnabled; | ||
83 | - } | ||
84 | - | ||
85 | - @Override | ||
86 | - public Element element() { | ||
87 | - return element; | ||
88 | - } | ||
89 | - | ||
90 | } | 127 | } | ... | ... |
... | @@ -21,6 +21,26 @@ package org.onlab.onos.net; | ... | @@ -21,6 +21,26 @@ package org.onlab.onos.net; |
21 | */ | 21 | */ |
22 | public interface Port extends Annotated { | 22 | public interface Port extends Annotated { |
23 | 23 | ||
24 | + /** Represents coarse port type classification. */ | ||
25 | + public enum Type { | ||
26 | + /** | ||
27 | + * Signifies copper-based connectivity. | ||
28 | + */ | ||
29 | + COPPER, | ||
30 | + | ||
31 | + /** | ||
32 | + * Signifies optical fiber-based connectivity. | ||
33 | + */ | ||
34 | + FIBER | ||
35 | + } | ||
36 | + | ||
37 | + /** | ||
38 | + * Returns the parent network element to which this port belongs. | ||
39 | + * | ||
40 | + * @return parent network element | ||
41 | + */ | ||
42 | + Element element(); | ||
43 | + | ||
24 | /** | 44 | /** |
25 | * Returns the port number. | 45 | * Returns the port number. |
26 | * | 46 | * |
... | @@ -36,12 +56,18 @@ public interface Port extends Annotated { | ... | @@ -36,12 +56,18 @@ public interface Port extends Annotated { |
36 | boolean isEnabled(); | 56 | boolean isEnabled(); |
37 | 57 | ||
38 | /** | 58 | /** |
39 | - * Returns the parent network element to which this port belongs. | 59 | + * Returns the port type. |
40 | * | 60 | * |
41 | - * @return parent network element | 61 | + * @return port type |
42 | */ | 62 | */ |
43 | - Element element(); | 63 | + Type type(); |
44 | 64 | ||
45 | - // set of port attributes | 65 | + /** |
66 | + * Returns the current port speed in Mbps. | ||
67 | + * | ||
68 | + * @return current port speed | ||
69 | + */ | ||
70 | + long portSpeed(); | ||
46 | 71 | ||
72 | + // TODO: more attributes? | ||
47 | } | 73 | } | ... | ... |
... | @@ -15,11 +15,12 @@ | ... | @@ -15,11 +15,12 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.net.device; | 16 | package org.onlab.onos.net.device; |
17 | 17 | ||
18 | +import com.google.common.base.MoreObjects; | ||
18 | import org.onlab.onos.net.AbstractDescription; | 19 | import org.onlab.onos.net.AbstractDescription; |
19 | import org.onlab.onos.net.PortNumber; | 20 | import org.onlab.onos.net.PortNumber; |
20 | import org.onlab.onos.net.SparseAnnotations; | 21 | import org.onlab.onos.net.SparseAnnotations; |
21 | 22 | ||
22 | -import com.google.common.base.MoreObjects; | 23 | +import static org.onlab.onos.net.Port.Type; |
23 | 24 | ||
24 | /** | 25 | /** |
25 | * Default implementation of immutable port description. | 26 | * Default implementation of immutable port description. |
... | @@ -27,32 +28,62 @@ import com.google.common.base.MoreObjects; | ... | @@ -27,32 +28,62 @@ import com.google.common.base.MoreObjects; |
27 | public class DefaultPortDescription extends AbstractDescription | 28 | public class DefaultPortDescription extends AbstractDescription |
28 | implements PortDescription { | 29 | implements PortDescription { |
29 | 30 | ||
31 | + private static final long DEFAULT_SPEED = 1_000; | ||
32 | + | ||
30 | private final PortNumber number; | 33 | private final PortNumber number; |
31 | private final boolean isEnabled; | 34 | private final boolean isEnabled; |
35 | + private final Type type; | ||
36 | + private final long portSpeed; | ||
32 | 37 | ||
33 | /** | 38 | /** |
34 | * Creates a port description using the supplied information. | 39 | * Creates a port description using the supplied information. |
35 | * | 40 | * |
36 | - * @param number port number | 41 | + * @param number port number |
37 | - * @param isEnabled port enabled state | 42 | + * @param isEnabled port enabled state |
38 | - * @param annotations optional key/value annotations map | 43 | + * @param annotations optional key/value annotations map |
39 | */ | 44 | */ |
40 | public DefaultPortDescription(PortNumber number, boolean isEnabled, | 45 | public DefaultPortDescription(PortNumber number, boolean isEnabled, |
41 | - SparseAnnotations... annotations) { | 46 | + SparseAnnotations... annotations) { |
47 | + this(number, isEnabled, Type.COPPER, DEFAULT_SPEED, annotations); | ||
48 | + } | ||
49 | + | ||
50 | + /** | ||
51 | + * Creates a port description using the supplied information. | ||
52 | + * | ||
53 | + * @param number port number | ||
54 | + * @param isEnabled port enabled state | ||
55 | + * @param type port type | ||
56 | + * @param portSpeed port speed in Mbps | ||
57 | + * @param annotations optional key/value annotations map | ||
58 | + */ | ||
59 | + public DefaultPortDescription(PortNumber number, boolean isEnabled, | ||
60 | + Type type, long portSpeed, | ||
61 | + SparseAnnotations...annotations) { | ||
42 | super(annotations); | 62 | super(annotations); |
43 | this.number = number; | 63 | this.number = number; |
44 | this.isEnabled = isEnabled; | 64 | this.isEnabled = isEnabled; |
65 | + this.type = type; | ||
66 | + this.portSpeed = portSpeed; | ||
67 | + } | ||
68 | + | ||
69 | + // Default constructor for serialization | ||
70 | + private DefaultPortDescription() { | ||
71 | + this.number = null; | ||
72 | + this.isEnabled = false; | ||
73 | + this.portSpeed = DEFAULT_SPEED; | ||
74 | + this.type = Type.COPPER; | ||
45 | } | 75 | } |
46 | 76 | ||
47 | /** | 77 | /** |
48 | * Creates a port description using the supplied information. | 78 | * Creates a port description using the supplied information. |
49 | * | 79 | * |
50 | - * @param base PortDescription to get basic information from | 80 | + * @param base PortDescription to get basic information from |
51 | - * @param annotations optional key/value annotations map | 81 | + * @param annotations optional key/value annotations map |
52 | */ | 82 | */ |
53 | public DefaultPortDescription(PortDescription base, | 83 | public DefaultPortDescription(PortDescription base, |
54 | - SparseAnnotations annotations) { | 84 | + SparseAnnotations annotations) { |
55 | - this(base.portNumber(), base.isEnabled(), annotations); | 85 | + this(base.portNumber(), base.isEnabled(), base.type(), base.portSpeed(), |
86 | + annotations); | ||
56 | } | 87 | } |
57 | 88 | ||
58 | @Override | 89 | @Override |
... | @@ -66,17 +97,24 @@ public class DefaultPortDescription extends AbstractDescription | ... | @@ -66,17 +97,24 @@ public class DefaultPortDescription extends AbstractDescription |
66 | } | 97 | } |
67 | 98 | ||
68 | @Override | 99 | @Override |
100 | + public Type type() { | ||
101 | + return type; | ||
102 | + } | ||
103 | + | ||
104 | + @Override | ||
105 | + public long portSpeed() { | ||
106 | + return portSpeed; | ||
107 | + } | ||
108 | + | ||
109 | + @Override | ||
69 | public String toString() { | 110 | public String toString() { |
70 | return MoreObjects.toStringHelper(getClass()) | 111 | return MoreObjects.toStringHelper(getClass()) |
71 | .add("number", number) | 112 | .add("number", number) |
72 | .add("isEnabled", isEnabled) | 113 | .add("isEnabled", isEnabled) |
114 | + .add("type", type) | ||
115 | + .add("portSpeed", portSpeed) | ||
73 | .add("annotations", annotations()) | 116 | .add("annotations", annotations()) |
74 | .toString(); | 117 | .toString(); |
75 | } | 118 | } |
76 | 119 | ||
77 | - // default constructor for serialization | ||
78 | - private DefaultPortDescription() { | ||
79 | - this.number = null; | ||
80 | - this.isEnabled = false; | ||
81 | - } | ||
82 | } | 120 | } | ... | ... |
... | @@ -18,13 +18,13 @@ package org.onlab.onos.net.device; | ... | @@ -18,13 +18,13 @@ package org.onlab.onos.net.device; |
18 | import org.onlab.onos.net.Description; | 18 | import org.onlab.onos.net.Description; |
19 | import org.onlab.onos.net.PortNumber; | 19 | import org.onlab.onos.net.PortNumber; |
20 | 20 | ||
21 | +import static org.onlab.onos.net.Port.Type; | ||
22 | + | ||
21 | /** | 23 | /** |
22 | * Information about a port. | 24 | * Information about a port. |
23 | */ | 25 | */ |
24 | public interface PortDescription extends Description { | 26 | public interface PortDescription extends Description { |
25 | 27 | ||
26 | - // TODO: possibly relocate this to a common ground so that this can also used by host tracking if required | ||
27 | - | ||
28 | /** | 28 | /** |
29 | * Returns the port number. | 29 | * Returns the port number. |
30 | * | 30 | * |
... | @@ -39,4 +39,18 @@ public interface PortDescription extends Description { | ... | @@ -39,4 +39,18 @@ public interface PortDescription extends Description { |
39 | */ | 39 | */ |
40 | boolean isEnabled(); | 40 | boolean isEnabled(); |
41 | 41 | ||
42 | + /** | ||
43 | + * Returns the port type. | ||
44 | + * | ||
45 | + * @return port type | ||
46 | + */ | ||
47 | + Type type(); | ||
48 | + | ||
49 | + /** | ||
50 | + * Returns the current port speed in Mbps. | ||
51 | + * | ||
52 | + * @return current port speed | ||
53 | + */ | ||
54 | + long portSpeed(); | ||
55 | + | ||
42 | } | 56 | } | ... | ... |
... | @@ -20,6 +20,7 @@ import org.onlab.onos.core.ApplicationId; | ... | @@ -20,6 +20,7 @@ import org.onlab.onos.core.ApplicationId; |
20 | import org.onlab.onos.net.Path; | 20 | import org.onlab.onos.net.Path; |
21 | import org.onlab.onos.net.flow.TrafficSelector; | 21 | import org.onlab.onos.net.flow.TrafficSelector; |
22 | import org.onlab.onos.net.flow.TrafficTreatment; | 22 | import org.onlab.onos.net.flow.TrafficTreatment; |
23 | +import org.onlab.onos.net.resource.LinkResourceRequest; | ||
23 | 24 | ||
24 | /** | 25 | /** |
25 | * Abstraction of explicitly path specified connectivity intent. | 26 | * Abstraction of explicitly path specified connectivity intent. |
... | @@ -27,6 +28,7 @@ import org.onlab.onos.net.flow.TrafficTreatment; | ... | @@ -27,6 +28,7 @@ import org.onlab.onos.net.flow.TrafficTreatment; |
27 | public class PathIntent extends ConnectivityIntent { | 28 | public class PathIntent extends ConnectivityIntent { |
28 | 29 | ||
29 | private final Path path; | 30 | private final Path path; |
31 | + private final LinkResourceRequest[] resourceRequests; | ||
30 | 32 | ||
31 | /** | 33 | /** |
32 | * Creates a new point-to-point intent with the supplied ingress/egress | 34 | * Creates a new point-to-point intent with the supplied ingress/egress |
... | @@ -39,10 +41,11 @@ public class PathIntent extends ConnectivityIntent { | ... | @@ -39,10 +41,11 @@ public class PathIntent extends ConnectivityIntent { |
39 | * @throws NullPointerException {@code path} is null | 41 | * @throws NullPointerException {@code path} is null |
40 | */ | 42 | */ |
41 | public PathIntent(ApplicationId appId, TrafficSelector selector, | 43 | public PathIntent(ApplicationId appId, TrafficSelector selector, |
42 | - TrafficTreatment treatment, Path path) { | 44 | + TrafficTreatment treatment, Path path, LinkResourceRequest[] resourceRequests) { |
43 | super(id(PathIntent.class, selector, treatment, path), appId, | 45 | super(id(PathIntent.class, selector, treatment, path), appId, |
44 | resources(path.links()), selector, treatment); | 46 | resources(path.links()), selector, treatment); |
45 | this.path = path; | 47 | this.path = path; |
48 | + this.resourceRequests = resourceRequests; | ||
46 | } | 49 | } |
47 | 50 | ||
48 | /** | 51 | /** |
... | @@ -51,6 +54,7 @@ public class PathIntent extends ConnectivityIntent { | ... | @@ -51,6 +54,7 @@ public class PathIntent extends ConnectivityIntent { |
51 | protected PathIntent() { | 54 | protected PathIntent() { |
52 | super(); | 55 | super(); |
53 | this.path = null; | 56 | this.path = null; |
57 | + this.resourceRequests = new LinkResourceRequest[0]; | ||
54 | } | 58 | } |
55 | 59 | ||
56 | /** | 60 | /** |
... | @@ -67,6 +71,10 @@ public class PathIntent extends ConnectivityIntent { | ... | @@ -67,6 +71,10 @@ public class PathIntent extends ConnectivityIntent { |
67 | return true; | 71 | return true; |
68 | } | 72 | } |
69 | 73 | ||
74 | + public LinkResourceRequest[] resourceRequests() { | ||
75 | + return resourceRequests; | ||
76 | + } | ||
77 | + | ||
70 | @Override | 78 | @Override |
71 | public String toString() { | 79 | public String toString() { |
72 | return MoreObjects.toStringHelper(getClass()) | 80 | return MoreObjects.toStringHelper(getClass()) | ... | ... |
core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntentWithBandwidthConstraint.java
0 → 100644
1 | +/* | ||
2 | + * Licensed to the Apache Software Foundation (ASF) under one | ||
3 | + * or more contributor license agreements. See the NOTICE file | ||
4 | + * distributed with this work for additional information | ||
5 | + * regarding copyright ownership. The ASF licenses this file | ||
6 | + * to you under the Apache License, Version 2.0 (the | ||
7 | + * "License"); you may not use this file except in compliance | ||
8 | + * with the License. You may obtain a copy of the License at | ||
9 | + * | ||
10 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + * | ||
12 | + * Unless required by applicable law or agreed to in writing, | ||
13 | + * software distributed under the License is distributed on an | ||
14 | + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
15 | + * KIND, either express or implied. See the License for the | ||
16 | + * specific language governing permissions and limitations | ||
17 | + * under the License. | ||
18 | + */ | ||
19 | +package org.onlab.onos.net.intent; | ||
20 | + | ||
21 | +import org.onlab.onos.core.ApplicationId; | ||
22 | +import org.onlab.onos.net.ConnectPoint; | ||
23 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
24 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
25 | +import org.onlab.onos.net.resource.BandwidthResourceRequest; | ||
26 | + | ||
27 | +import com.google.common.base.MoreObjects; | ||
28 | + | ||
29 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
30 | + | ||
31 | +/** | ||
32 | + * Abstraction of point-to-point connectivity. | ||
33 | + */ | ||
34 | +public class PointToPointIntentWithBandwidthConstraint extends ConnectivityIntent { | ||
35 | + | ||
36 | + private final ConnectPoint ingressPoint; | ||
37 | + private final ConnectPoint egressPoint; | ||
38 | + private final BandwidthResourceRequest bandwidthResourceRequest; | ||
39 | + | ||
40 | + /** | ||
41 | + * Creates a new point-to-point intent with the supplied ingress/egress | ||
42 | + * ports. | ||
43 | + * | ||
44 | + * @param appId application identifier | ||
45 | + * @param selector traffic selector | ||
46 | + * @param treatment treatment | ||
47 | + * @param ingressPoint ingress port | ||
48 | + * @param egressPoint egress port | ||
49 | + * @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null. | ||
50 | + */ | ||
51 | + public PointToPointIntentWithBandwidthConstraint(ApplicationId appId, TrafficSelector selector, | ||
52 | + TrafficTreatment treatment, | ||
53 | + ConnectPoint ingressPoint, | ||
54 | + ConnectPoint egressPoint, | ||
55 | + BandwidthResourceRequest bandwidthResourceRequest) { | ||
56 | + super(id(PointToPointIntentWithBandwidthConstraint.class, selector, | ||
57 | + treatment, ingressPoint, egressPoint, bandwidthResourceRequest.bandwidth()), | ||
58 | + appId, null, selector, treatment); | ||
59 | + this.ingressPoint = checkNotNull(ingressPoint); | ||
60 | + this.egressPoint = checkNotNull(egressPoint); | ||
61 | + this.bandwidthResourceRequest = bandwidthResourceRequest; | ||
62 | + } | ||
63 | + | ||
64 | + /** | ||
65 | + * Constructor for serializer. | ||
66 | + */ | ||
67 | + protected PointToPointIntentWithBandwidthConstraint() { | ||
68 | + super(); | ||
69 | + this.ingressPoint = null; | ||
70 | + this.egressPoint = null; | ||
71 | + bandwidthResourceRequest = new BandwidthResourceRequest(0.0); | ||
72 | + } | ||
73 | + | ||
74 | + /** | ||
75 | + * Returns the port on which the ingress traffic should be connected to | ||
76 | + * the egress. | ||
77 | + * | ||
78 | + * @return ingress port | ||
79 | + */ | ||
80 | + public ConnectPoint ingressPoint() { | ||
81 | + return ingressPoint; | ||
82 | + } | ||
83 | + | ||
84 | + /** | ||
85 | + * Returns the port on which the traffic should egress. | ||
86 | + * | ||
87 | + * @return egress port | ||
88 | + */ | ||
89 | + public ConnectPoint egressPoint() { | ||
90 | + return egressPoint; | ||
91 | + } | ||
92 | + | ||
93 | + public BandwidthResourceRequest bandwidthRequest() { | ||
94 | + return this.bandwidthResourceRequest; | ||
95 | + } | ||
96 | + | ||
97 | + @Override | ||
98 | + public String toString() { | ||
99 | + return MoreObjects.toStringHelper(getClass()) | ||
100 | + .add("id", id()) | ||
101 | + .add("appId", appId()) | ||
102 | + .add("selector", selector()) | ||
103 | + .add("treatment", treatment()) | ||
104 | + .add("ingress", ingressPoint) | ||
105 | + .add("egress", egressPoint) | ||
106 | + .add("bandwidth", bandwidthResourceRequest.bandwidth().toString()) | ||
107 | + .toString(); | ||
108 | + } | ||
109 | + | ||
110 | +} |
1 | +/* | ||
2 | + * Copyright 2014 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onlab.onos.net.resource; | ||
17 | + | ||
18 | +import java.util.Set; | ||
19 | + | ||
20 | +import org.onlab.onos.net.Link; | ||
21 | +import org.onlab.onos.net.intent.IntentId; | ||
22 | + | ||
23 | + | ||
24 | +/** | ||
25 | + * Manages link resources. | ||
26 | + */ | ||
27 | +public interface LinkResourceStore { | ||
28 | + Set<ResourceAllocation> getFreeResources(Link link); | ||
29 | + | ||
30 | + void allocateResources(LinkResourceAllocations allocations); | ||
31 | + | ||
32 | + void releaseResources(LinkResourceAllocations allocations); | ||
33 | + | ||
34 | + LinkResourceAllocations getAllocations(IntentId intentId); | ||
35 | + | ||
36 | + Iterable<LinkResourceAllocations> getAllocations(Link link); | ||
37 | + | ||
38 | + Iterable<LinkResourceAllocations> getAllocations(); | ||
39 | +} |
... | @@ -23,6 +23,8 @@ import org.onlab.packet.ChassisId; | ... | @@ -23,6 +23,8 @@ import org.onlab.packet.ChassisId; |
23 | import static org.junit.Assert.assertEquals; | 23 | import static org.junit.Assert.assertEquals; |
24 | import static org.onlab.onos.net.Device.Type.SWITCH; | 24 | import static org.onlab.onos.net.Device.Type.SWITCH; |
25 | import static org.onlab.onos.net.DeviceId.deviceId; | 25 | import static org.onlab.onos.net.DeviceId.deviceId; |
26 | +import static org.onlab.onos.net.Port.Type.COPPER; | ||
27 | +import static org.onlab.onos.net.Port.Type.FIBER; | ||
26 | import static org.onlab.onos.net.PortNumber.portNumber; | 28 | import static org.onlab.onos.net.PortNumber.portNumber; |
27 | 29 | ||
28 | /** | 30 | /** |
... | @@ -35,15 +37,16 @@ public class DefaultPortTest { | ... | @@ -35,15 +37,16 @@ public class DefaultPortTest { |
35 | private static final DeviceId DID2 = deviceId("of:bar"); | 37 | private static final DeviceId DID2 = deviceId("of:bar"); |
36 | private static final PortNumber P1 = portNumber(1); | 38 | private static final PortNumber P1 = portNumber(1); |
37 | private static final PortNumber P2 = portNumber(2); | 39 | private static final PortNumber P2 = portNumber(2); |
40 | + private static final long SP1 = 1_000_000; | ||
38 | 41 | ||
39 | @Test | 42 | @Test |
40 | public void testEquality() { | 43 | public void testEquality() { |
41 | Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n", | 44 | Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n", |
42 | new ChassisId()); | 45 | new ChassisId()); |
43 | - Port p1 = new DefaultPort(device, portNumber(1), true); | 46 | + Port p1 = new DefaultPort(device, portNumber(1), true, COPPER, SP1); |
44 | - Port p2 = new DefaultPort(device, portNumber(1), true); | 47 | + Port p2 = new DefaultPort(device, portNumber(1), true, COPPER, SP1); |
45 | - Port p3 = new DefaultPort(device, portNumber(2), true); | 48 | + Port p3 = new DefaultPort(device, portNumber(2), true, FIBER, SP1); |
46 | - Port p4 = new DefaultPort(device, portNumber(2), true); | 49 | + Port p4 = new DefaultPort(device, portNumber(2), true, FIBER, SP1); |
47 | Port p5 = new DefaultPort(device, portNumber(1), false); | 50 | Port p5 = new DefaultPort(device, portNumber(1), false); |
48 | 51 | ||
49 | new EqualsTester().addEqualityGroup(p1, p2) | 52 | new EqualsTester().addEqualityGroup(p1, p2) |
... | @@ -56,10 +59,12 @@ public class DefaultPortTest { | ... | @@ -56,10 +59,12 @@ public class DefaultPortTest { |
56 | public void basics() { | 59 | public void basics() { |
57 | Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n", | 60 | Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n", |
58 | new ChassisId()); | 61 | new ChassisId()); |
59 | - Port port = new DefaultPort(device, portNumber(1), true); | 62 | + Port port = new DefaultPort(device, portNumber(1), true, FIBER, SP1); |
60 | assertEquals("incorrect element", device, port.element()); | 63 | assertEquals("incorrect element", device, port.element()); |
61 | assertEquals("incorrect number", portNumber(1), port.number()); | 64 | assertEquals("incorrect number", portNumber(1), port.number()); |
62 | assertEquals("incorrect state", true, port.isEnabled()); | 65 | assertEquals("incorrect state", true, port.isEnabled()); |
66 | + assertEquals("incorrect speed", SP1, port.portSpeed()); | ||
67 | + assertEquals("incorrect type", FIBER, port.type()); | ||
63 | } | 68 | } |
64 | 69 | ||
65 | } | 70 | } | ... | ... |
... | @@ -15,11 +15,12 @@ | ... | @@ -15,11 +15,12 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.net.intent; | 16 | package org.onlab.onos.net.intent; |
17 | 17 | ||
18 | -import static org.junit.Assert.assertEquals; | ||
19 | - | ||
20 | import org.junit.Test; | 18 | import org.junit.Test; |
21 | import org.onlab.onos.net.NetTestTools; | 19 | import org.onlab.onos.net.NetTestTools; |
22 | import org.onlab.onos.net.Path; | 20 | import org.onlab.onos.net.Path; |
21 | +import org.onlab.onos.net.resource.LinkResourceRequest; | ||
22 | + | ||
23 | +import static org.junit.Assert.assertEquals; | ||
23 | 24 | ||
24 | public class PathIntentTest extends ConnectivityIntentTest { | 25 | public class PathIntentTest extends ConnectivityIntentTest { |
25 | // 111:11 --> 222:22 | 26 | // 111:11 --> 222:22 |
... | @@ -39,11 +40,11 @@ public class PathIntentTest extends ConnectivityIntentTest { | ... | @@ -39,11 +40,11 @@ public class PathIntentTest extends ConnectivityIntentTest { |
39 | 40 | ||
40 | @Override | 41 | @Override |
41 | protected PathIntent createOne() { | 42 | protected PathIntent createOne() { |
42 | - return new PathIntent(APPID, MATCH, NOP, PATH1); | 43 | + return new PathIntent(APPID, MATCH, NOP, PATH1, new LinkResourceRequest[0]); |
43 | } | 44 | } |
44 | 45 | ||
45 | @Override | 46 | @Override |
46 | protected PathIntent createAnother() { | 47 | protected PathIntent createAnother() { |
47 | - return new PathIntent(APPID, MATCH, NOP, PATH2); | 48 | + return new PathIntent(APPID, MATCH, NOP, PATH2, new LinkResourceRequest[0]); |
48 | } | 49 | } |
49 | } | 50 | } | ... | ... |
... | @@ -67,8 +67,8 @@ import com.google.common.collect.HashMultimap; | ... | @@ -67,8 +67,8 @@ import com.google.common.collect.HashMultimap; |
67 | @Component(immediate = true) | 67 | @Component(immediate = true) |
68 | @Service | 68 | @Service |
69 | public class DeviceManager | 69 | public class DeviceManager |
70 | - extends AbstractProviderRegistry<DeviceProvider, DeviceProviderService> | 70 | + extends AbstractProviderRegistry<DeviceProvider, DeviceProviderService> |
71 | - implements DeviceService, DeviceAdminService, DeviceProviderRegistry { | 71 | + implements DeviceService, DeviceAdminService, DeviceProviderRegistry { |
72 | 72 | ||
73 | private static final String DEVICE_ID_NULL = "Device ID cannot be null"; | 73 | private static final String DEVICE_ID_NULL = "Device ID cannot be null"; |
74 | private static final String PORT_NUMBER_NULL = "Port number cannot be null"; | 74 | private static final String PORT_NUMBER_NULL = "Port number cannot be null"; |
... | @@ -227,8 +227,8 @@ public class DeviceManager | ... | @@ -227,8 +227,8 @@ public class DeviceManager |
227 | 227 | ||
228 | // Personalized device provider service issued to the supplied provider. | 228 | // Personalized device provider service issued to the supplied provider. |
229 | private class InternalDeviceProviderService | 229 | private class InternalDeviceProviderService |
230 | - extends AbstractProviderService<DeviceProvider> | 230 | + extends AbstractProviderService<DeviceProvider> |
231 | - implements DeviceProviderService { | 231 | + implements DeviceProviderService { |
232 | 232 | ||
233 | InternalDeviceProviderService(DeviceProvider provider) { | 233 | InternalDeviceProviderService(DeviceProvider provider) { |
234 | super(provider); | 234 | super(provider); |
... | @@ -236,7 +236,7 @@ public class DeviceManager | ... | @@ -236,7 +236,7 @@ public class DeviceManager |
236 | 236 | ||
237 | @Override | 237 | @Override |
238 | public void deviceConnected(DeviceId deviceId, | 238 | public void deviceConnected(DeviceId deviceId, |
239 | - DeviceDescription deviceDescription) { | 239 | + DeviceDescription deviceDescription) { |
240 | checkNotNull(deviceId, DEVICE_ID_NULL); | 240 | checkNotNull(deviceId, DEVICE_ID_NULL); |
241 | checkNotNull(deviceDescription, DEVICE_DESCRIPTION_NULL); | 241 | checkNotNull(deviceDescription, DEVICE_DESCRIPTION_NULL); |
242 | checkValidity(); | 242 | checkValidity(); |
... | @@ -267,7 +267,7 @@ public class DeviceManager | ... | @@ -267,7 +267,7 @@ public class DeviceManager |
267 | deviceClockProviderService.setMastershipTerm(deviceId, term); | 267 | deviceClockProviderService.setMastershipTerm(deviceId, term); |
268 | 268 | ||
269 | DeviceEvent event = store.createOrUpdateDevice(provider().id(), | 269 | DeviceEvent event = store.createOrUpdateDevice(provider().id(), |
270 | - deviceId, deviceDescription); | 270 | + deviceId, deviceDescription); |
271 | 271 | ||
272 | // If there was a change of any kind, tell the provider | 272 | // If there was a change of any kind, tell the provider |
273 | // that this instance is the master. | 273 | // that this instance is the master. |
... | @@ -337,14 +337,14 @@ public class DeviceManager | ... | @@ -337,14 +337,14 @@ public class DeviceManager |
337 | 337 | ||
338 | @Override | 338 | @Override |
339 | public void updatePorts(DeviceId deviceId, | 339 | public void updatePorts(DeviceId deviceId, |
340 | - List<PortDescription> portDescriptions) { | 340 | + List<PortDescription> portDescriptions) { |
341 | checkNotNull(deviceId, DEVICE_ID_NULL); | 341 | checkNotNull(deviceId, DEVICE_ID_NULL); |
342 | checkNotNull(portDescriptions, | 342 | checkNotNull(portDescriptions, |
343 | - "Port descriptions list cannot be null"); | 343 | + "Port descriptions list cannot be null"); |
344 | checkValidity(); | 344 | checkValidity(); |
345 | 345 | ||
346 | List<DeviceEvent> events = store.updatePorts(this.provider().id(), | 346 | List<DeviceEvent> events = store.updatePorts(this.provider().id(), |
347 | - deviceId, portDescriptions); | 347 | + deviceId, portDescriptions); |
348 | for (DeviceEvent event : events) { | 348 | for (DeviceEvent event : events) { |
349 | post(event); | 349 | post(event); |
350 | } | 350 | } |
... | @@ -352,13 +352,13 @@ public class DeviceManager | ... | @@ -352,13 +352,13 @@ public class DeviceManager |
352 | 352 | ||
353 | @Override | 353 | @Override |
354 | public void portStatusChanged(DeviceId deviceId, | 354 | public void portStatusChanged(DeviceId deviceId, |
355 | - PortDescription portDescription) { | 355 | + PortDescription portDescription) { |
356 | checkNotNull(deviceId, DEVICE_ID_NULL); | 356 | checkNotNull(deviceId, DEVICE_ID_NULL); |
357 | checkNotNull(portDescription, PORT_DESCRIPTION_NULL); | 357 | checkNotNull(portDescription, PORT_DESCRIPTION_NULL); |
358 | checkValidity(); | 358 | checkValidity(); |
359 | 359 | ||
360 | final DeviceEvent event = store.updatePortStatus(this.provider().id(), | 360 | final DeviceEvent event = store.updatePortStatus(this.provider().id(), |
361 | - deviceId, portDescription); | 361 | + deviceId, portDescription); |
362 | if (event != null) { | 362 | if (event != null) { |
363 | log.info("Device {} port {} status changed", deviceId, event | 363 | log.info("Device {} port {} status changed", deviceId, event |
364 | .port().number()); | 364 | .port().number()); |
... | @@ -370,7 +370,7 @@ public class DeviceManager | ... | @@ -370,7 +370,7 @@ public class DeviceManager |
370 | public void unableToAssertRole(DeviceId deviceId, MastershipRole role) { | 370 | public void unableToAssertRole(DeviceId deviceId, MastershipRole role) { |
371 | // FIXME: implement response to this notification | 371 | // FIXME: implement response to this notification |
372 | log.warn("Failed to assert role [{}] onto Device {}", role, | 372 | log.warn("Failed to assert role [{}] onto Device {}", role, |
373 | - deviceId); | 373 | + deviceId); |
374 | if (role == MastershipRole.MASTER) { | 374 | if (role == MastershipRole.MASTER) { |
375 | mastershipService.relinquishMastership(deviceId); | 375 | mastershipService.relinquishMastership(deviceId); |
376 | // TODO: Shouldn't we be triggering event? | 376 | // TODO: Shouldn't we be triggering event? |
... | @@ -393,7 +393,7 @@ public class DeviceManager | ... | @@ -393,7 +393,7 @@ public class DeviceManager |
393 | // random cache size | 393 | // random cache size |
394 | private final int cacheSize = 5; | 394 | private final int cacheSize = 5; |
395 | // temporarily stores term number + events to check for duplicates. A hack. | 395 | // temporarily stores term number + events to check for duplicates. A hack. |
396 | - private HashMultimap<Integer, RoleInfo> eventCache = | 396 | + private HashMultimap<Integer, RoleInfo> eventCache = |
397 | HashMultimap.create(); | 397 | HashMultimap.create(); |
398 | 398 | ||
399 | @Override | 399 | @Override |
... | @@ -407,14 +407,14 @@ public class DeviceManager | ... | @@ -407,14 +407,14 @@ public class DeviceManager |
407 | // TODO duplicate suppression should probably occur in the MastershipManager | 407 | // TODO duplicate suppression should probably occur in the MastershipManager |
408 | // itself, so listeners that can't deal with duplicates don't have to | 408 | // itself, so listeners that can't deal with duplicates don't have to |
409 | // so this check themselves. | 409 | // so this check themselves. |
410 | - if (checkDuplicate(event.roleInfo(), term.termNumber())) { | 410 | +// if (checkDuplicate(event.roleInfo(), term.termNumber())) { |
411 | - return; | 411 | +// return; |
412 | - } | 412 | +// } |
413 | 413 | ||
414 | if (!myNodeId.equals(term.master())) { | 414 | if (!myNodeId.equals(term.master())) { |
415 | // something went wrong in consistency, let go | 415 | // something went wrong in consistency, let go |
416 | log.warn("Mastership has changed after this event." | 416 | log.warn("Mastership has changed after this event." |
417 | - + "Term Service suggests {} for {}", term, did); | 417 | + + "Term Service suggests {} for {}", term, did); |
418 | // FIXME: Is it possible to let go of MASTER role | 418 | // FIXME: Is it possible to let go of MASTER role |
419 | // but remain on STANDBY list? | 419 | // but remain on STANDBY list? |
420 | mastershipService.relinquishMastership(did); | 420 | mastershipService.relinquishMastership(did); |
... | @@ -435,11 +435,12 @@ public class DeviceManager | ... | @@ -435,11 +435,12 @@ public class DeviceManager |
435 | return; | 435 | return; |
436 | } | 436 | } |
437 | //flag the device as online. Is there a better way to do this? | 437 | //flag the device as online. Is there a better way to do this? |
438 | - DeviceEvent devEvent = store.createOrUpdateDevice(device.providerId(), did, | 438 | + DeviceEvent devEvent = |
439 | - new DefaultDeviceDescription( | 439 | + store.createOrUpdateDevice(device.providerId(), did, |
440 | - did.uri(), device.type(), device.manufacturer(), | 440 | + new DefaultDeviceDescription( |
441 | - device.hwVersion(), device.swVersion(), | 441 | + did.uri(), device.type(), device.manufacturer(), |
442 | - device.serialNumber(), device.chassisId())); | 442 | + device.hwVersion(), device.swVersion(), |
443 | + device.serialNumber(), device.chassisId())); | ||
443 | post(devEvent); | 444 | post(devEvent); |
444 | } | 445 | } |
445 | applyRole(did, MastershipRole.MASTER); | 446 | applyRole(did, MastershipRole.MASTER); |
... | @@ -476,7 +477,7 @@ public class DeviceManager | ... | @@ -476,7 +477,7 @@ public class DeviceManager |
476 | 477 | ||
477 | // Store delegate to re-post events emitted from the store. | 478 | // Store delegate to re-post events emitted from the store. |
478 | private class InternalStoreDelegate | 479 | private class InternalStoreDelegate |
479 | - implements DeviceStoreDelegate { | 480 | + implements DeviceStoreDelegate { |
480 | @Override | 481 | @Override |
481 | public void notify(DeviceEvent event) { | 482 | public void notify(DeviceEvent event) { |
482 | post(event); | 483 | post(event); | ... | ... |
... | @@ -15,6 +15,10 @@ | ... | @@ -15,6 +15,10 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.net.intent.impl; | 16 | package org.onlab.onos.net.intent.impl; |
17 | 17 | ||
18 | +import java.util.Arrays; | ||
19 | +import java.util.List; | ||
20 | +import java.util.Set; | ||
21 | + | ||
18 | import org.apache.felix.scr.annotations.Activate; | 22 | import org.apache.felix.scr.annotations.Activate; |
19 | import org.apache.felix.scr.annotations.Component; | 23 | import org.apache.felix.scr.annotations.Component; |
20 | import org.apache.felix.scr.annotations.Deactivate; | 24 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -32,13 +36,10 @@ import org.onlab.onos.net.intent.IntentCompiler; | ... | @@ -32,13 +36,10 @@ import org.onlab.onos.net.intent.IntentCompiler; |
32 | import org.onlab.onos.net.intent.IntentExtensionService; | 36 | import org.onlab.onos.net.intent.IntentExtensionService; |
33 | import org.onlab.onos.net.intent.PathIntent; | 37 | import org.onlab.onos.net.intent.PathIntent; |
34 | import org.onlab.onos.net.topology.LinkWeight; | 38 | import org.onlab.onos.net.topology.LinkWeight; |
39 | +import org.onlab.onos.net.resource.LinkResourceRequest; | ||
35 | import org.onlab.onos.net.topology.PathService; | 40 | import org.onlab.onos.net.topology.PathService; |
36 | import org.onlab.onos.net.topology.TopologyEdge; | 41 | import org.onlab.onos.net.topology.TopologyEdge; |
37 | 42 | ||
38 | -import java.util.Arrays; | ||
39 | -import java.util.List; | ||
40 | -import java.util.Set; | ||
41 | - | ||
42 | import static org.onlab.onos.net.flow.DefaultTrafficSelector.builder; | 43 | import static org.onlab.onos.net.flow.DefaultTrafficSelector.builder; |
43 | 44 | ||
44 | /** | 45 | /** |
... | @@ -85,7 +86,7 @@ public class HostToHostIntentCompiler | ... | @@ -85,7 +86,7 @@ public class HostToHostIntentCompiler |
85 | TrafficSelector selector = builder(intent.selector()) | 86 | TrafficSelector selector = builder(intent.selector()) |
86 | .matchEthSrc(src.mac()).matchEthDst(dst.mac()).build(); | 87 | .matchEthSrc(src.mac()).matchEthDst(dst.mac()).build(); |
87 | return new PathIntent(intent.appId(), selector, intent.treatment(), | 88 | return new PathIntent(intent.appId(), selector, intent.treatment(), |
88 | - path); | 89 | + path, new LinkResourceRequest[0]); |
89 | } | 90 | } |
90 | 91 | ||
91 | private Path getPath(HostId one, HostId two) { | 92 | private Path getPath(HostId one, HostId two) { | ... | ... |
... | @@ -15,9 +15,6 @@ | ... | @@ -15,9 +15,6 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.net.intent.impl; | 16 | package org.onlab.onos.net.intent.impl; |
17 | 17 | ||
18 | -import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder; | ||
19 | -import static org.slf4j.LoggerFactory.getLogger; | ||
20 | - | ||
21 | import java.util.Iterator; | 18 | import java.util.Iterator; |
22 | import java.util.List; | 19 | import java.util.List; |
23 | 20 | ||
... | @@ -41,10 +38,15 @@ import org.onlab.onos.net.flow.TrafficTreatment; | ... | @@ -41,10 +38,15 @@ import org.onlab.onos.net.flow.TrafficTreatment; |
41 | import org.onlab.onos.net.intent.IntentExtensionService; | 38 | import org.onlab.onos.net.intent.IntentExtensionService; |
42 | import org.onlab.onos.net.intent.IntentInstaller; | 39 | import org.onlab.onos.net.intent.IntentInstaller; |
43 | import org.onlab.onos.net.intent.PathIntent; | 40 | import org.onlab.onos.net.intent.PathIntent; |
41 | +import org.onlab.onos.net.resource.LinkResourceAllocations; | ||
42 | +import org.onlab.onos.net.resource.LinkResourceService; | ||
44 | import org.slf4j.Logger; | 43 | import org.slf4j.Logger; |
45 | 44 | ||
46 | import com.google.common.collect.Lists; | 45 | import com.google.common.collect.Lists; |
47 | 46 | ||
47 | +import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder; | ||
48 | +import static org.slf4j.LoggerFactory.getLogger; | ||
49 | + | ||
48 | /** | 50 | /** |
49 | * Installer for {@link PathIntent packet path connectivity intents}. | 51 | * Installer for {@link PathIntent packet path connectivity intents}. |
50 | */ | 52 | */ |
... | @@ -59,6 +61,9 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { | ... | @@ -59,6 +61,9 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { |
59 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 61 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
60 | protected CoreService coreService; | 62 | protected CoreService coreService; |
61 | 63 | ||
64 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
65 | + protected LinkResourceService resourceService; | ||
66 | + | ||
62 | private ApplicationId appId; | 67 | private ApplicationId appId; |
63 | 68 | ||
64 | @Activate | 69 | @Activate |
... | @@ -74,6 +79,14 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { | ... | @@ -74,6 +79,14 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { |
74 | 79 | ||
75 | @Override | 80 | @Override |
76 | public List<FlowRuleBatchOperation> install(PathIntent intent) { | 81 | public List<FlowRuleBatchOperation> install(PathIntent intent) { |
82 | + if (intent.resourceRequests().length > 0) { | ||
83 | + LinkResourceAllocations allocations = allocateBandwidth(intent); | ||
84 | + if (allocations == null) { | ||
85 | + log.debug("Insufficient bandwidth available to install path intent {}", intent); | ||
86 | + return null; | ||
87 | + } | ||
88 | + } | ||
89 | + | ||
77 | TrafficSelector.Builder builder = | 90 | TrafficSelector.Builder builder = |
78 | DefaultTrafficSelector.builder(intent.selector()); | 91 | DefaultTrafficSelector.builder(intent.selector()); |
79 | Iterator<Link> links = intent.path().links().iterator(); | 92 | Iterator<Link> links = intent.path().links().iterator(); |
... | @@ -117,6 +130,10 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { | ... | @@ -117,6 +130,10 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> { |
117 | return Lists.newArrayList(new FlowRuleBatchOperation(rules)); | 130 | return Lists.newArrayList(new FlowRuleBatchOperation(rules)); |
118 | } | 131 | } |
119 | 132 | ||
133 | + private LinkResourceAllocations allocateBandwidth(PathIntent intent) { | ||
134 | + return resourceService.requestResources(intent.resourceRequests()[0]); | ||
135 | + } | ||
136 | + | ||
120 | // TODO refactor below this line... ---------------------------- | 137 | // TODO refactor below this line... ---------------------------- |
121 | 138 | ||
122 | /** | 139 | /** | ... | ... |
... | @@ -15,6 +15,10 @@ | ... | @@ -15,6 +15,10 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.net.intent.impl; | 16 | package org.onlab.onos.net.intent.impl; |
17 | 17 | ||
18 | +import java.util.ArrayList; | ||
19 | +import java.util.List; | ||
20 | +import java.util.Set; | ||
21 | + | ||
18 | import org.apache.felix.scr.annotations.Activate; | 22 | import org.apache.felix.scr.annotations.Activate; |
19 | import org.apache.felix.scr.annotations.Component; | 23 | import org.apache.felix.scr.annotations.Component; |
20 | import org.apache.felix.scr.annotations.Deactivate; | 24 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -31,15 +35,12 @@ import org.onlab.onos.net.intent.IntentExtensionService; | ... | @@ -31,15 +35,12 @@ import org.onlab.onos.net.intent.IntentExtensionService; |
31 | import org.onlab.onos.net.intent.PathIntent; | 35 | import org.onlab.onos.net.intent.PathIntent; |
32 | import org.onlab.onos.net.intent.PointToPointIntent; | 36 | import org.onlab.onos.net.intent.PointToPointIntent; |
33 | import org.onlab.onos.net.provider.ProviderId; | 37 | import org.onlab.onos.net.provider.ProviderId; |
38 | +import org.onlab.onos.net.resource.LinkResourceRequest; | ||
34 | import org.onlab.onos.net.topology.LinkWeight; | 39 | import org.onlab.onos.net.topology.LinkWeight; |
35 | import org.onlab.onos.net.topology.Topology; | 40 | import org.onlab.onos.net.topology.Topology; |
36 | import org.onlab.onos.net.topology.TopologyEdge; | 41 | import org.onlab.onos.net.topology.TopologyEdge; |
37 | import org.onlab.onos.net.topology.TopologyService; | 42 | import org.onlab.onos.net.topology.TopologyService; |
38 | 43 | ||
39 | -import java.util.ArrayList; | ||
40 | -import java.util.List; | ||
41 | -import java.util.Set; | ||
42 | - | ||
43 | import static java.util.Arrays.asList; | 44 | import static java.util.Arrays.asList; |
44 | 45 | ||
45 | /** | 46 | /** |
... | @@ -76,7 +77,7 @@ public class PointToPointIntentCompiler | ... | @@ -76,7 +77,7 @@ public class PointToPointIntentCompiler |
76 | links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false)); | 77 | links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false)); |
77 | 78 | ||
78 | return asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2, | 79 | return asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2, |
79 | - path.annotations()), intent)); | 80 | + path.annotations()), intent)); |
80 | } | 81 | } |
81 | 82 | ||
82 | /** | 83 | /** |
... | @@ -89,7 +90,8 @@ public class PointToPointIntentCompiler | ... | @@ -89,7 +90,8 @@ public class PointToPointIntentCompiler |
89 | private Intent createPathIntent(Path path, | 90 | private Intent createPathIntent(Path path, |
90 | PointToPointIntent intent) { | 91 | PointToPointIntent intent) { |
91 | return new PathIntent(intent.appId(), | 92 | return new PathIntent(intent.appId(), |
92 | - intent.selector(), intent.treatment(), path); | 93 | + intent.selector(), intent.treatment(), path, |
94 | + new LinkResourceRequest[0]); | ||
93 | } | 95 | } |
94 | 96 | ||
95 | /** | 97 | /** | ... | ... |
1 | +package org.onlab.onos.net.intent.impl; | ||
2 | + | ||
3 | +import java.util.ArrayList; | ||
4 | +import java.util.Arrays; | ||
5 | +import java.util.List; | ||
6 | +import java.util.Set; | ||
7 | + | ||
8 | +import org.apache.felix.scr.annotations.Activate; | ||
9 | +import org.apache.felix.scr.annotations.Component; | ||
10 | +import org.apache.felix.scr.annotations.Deactivate; | ||
11 | +import org.apache.felix.scr.annotations.Reference; | ||
12 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
13 | +import org.onlab.onos.net.ConnectPoint; | ||
14 | +import org.onlab.onos.net.DefaultEdgeLink; | ||
15 | +import org.onlab.onos.net.DefaultPath; | ||
16 | +import org.onlab.onos.net.Link; | ||
17 | +import org.onlab.onos.net.Path; | ||
18 | +import org.onlab.onos.net.intent.Intent; | ||
19 | +import org.onlab.onos.net.intent.IntentCompiler; | ||
20 | +import org.onlab.onos.net.intent.IntentExtensionService; | ||
21 | +import org.onlab.onos.net.intent.PathIntent; | ||
22 | +import org.onlab.onos.net.intent.PointToPointIntent; | ||
23 | +import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint; | ||
24 | +import org.onlab.onos.net.provider.ProviderId; | ||
25 | +import org.onlab.onos.net.resource.BandwidthResourceRequest; | ||
26 | +import org.onlab.onos.net.resource.DefaultLinkResourceRequest; | ||
27 | +import org.onlab.onos.net.resource.LinkResourceRequest; | ||
28 | +import org.onlab.onos.net.resource.LinkResourceService; | ||
29 | +import org.onlab.onos.net.resource.ResourceRequest; | ||
30 | +import org.onlab.onos.net.resource.ResourceType; | ||
31 | +import org.onlab.onos.net.topology.LinkWeight; | ||
32 | +import org.onlab.onos.net.topology.Topology; | ||
33 | +import org.onlab.onos.net.topology.TopologyEdge; | ||
34 | +import org.onlab.onos.net.topology.TopologyService; | ||
35 | + | ||
36 | +/** | ||
37 | + * A intent compiler for {@link org.onlab.onos.net.intent.HostToHostIntent}. | ||
38 | + */ | ||
39 | +@Component(immediate = true) | ||
40 | +public class PointToPointIntentWithBandwidthConstraintCompiler | ||
41 | + implements IntentCompiler<PointToPointIntentWithBandwidthConstraint> { | ||
42 | + | ||
43 | + private static final ProviderId PID = new ProviderId("core", "org.onlab.onos.core", true); | ||
44 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
45 | + protected IntentExtensionService intentManager; | ||
46 | + | ||
47 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
48 | + protected TopologyService topologyService; | ||
49 | + | ||
50 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
51 | + protected LinkResourceService resourceService; | ||
52 | + | ||
53 | + @Activate | ||
54 | + public void activate() { | ||
55 | + intentManager.registerCompiler(PointToPointIntentWithBandwidthConstraint.class, this); | ||
56 | + } | ||
57 | + | ||
58 | + @Deactivate | ||
59 | + public void deactivate() { | ||
60 | + intentManager.unregisterCompiler(PointToPointIntent.class); | ||
61 | + } | ||
62 | + | ||
63 | + @Override | ||
64 | + public List<Intent> compile(PointToPointIntentWithBandwidthConstraint intent) { | ||
65 | + Path path = getPath(intent.ingressPoint(), intent.egressPoint(), intent.bandwidthRequest()); | ||
66 | + | ||
67 | + List<Link> links = new ArrayList<>(); | ||
68 | + links.add(DefaultEdgeLink.createEdgeLink(intent.ingressPoint(), true)); | ||
69 | + links.addAll(path.links()); | ||
70 | + links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false)); | ||
71 | + | ||
72 | + return Arrays.asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2, | ||
73 | + path.annotations()), | ||
74 | + intent)); | ||
75 | + } | ||
76 | + | ||
77 | + /** | ||
78 | + * Creates a path intent from the specified path and original | ||
79 | + * connectivity intent. | ||
80 | + * | ||
81 | + * @param path path to create an intent for | ||
82 | + * @param intent original intent | ||
83 | + */ | ||
84 | + private Intent createPathIntent(Path path, | ||
85 | + PointToPointIntentWithBandwidthConstraint intent) { | ||
86 | + LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(), | ||
87 | + path.links()) | ||
88 | + // TODO - this seems awkward, maybe allow directly attaching a BandwidthRequest | ||
89 | + .addBandwidthRequest(intent.bandwidthRequest().bandwidth().toDouble()); | ||
90 | + LinkResourceRequest bandwidthRequest = request.build(); | ||
91 | + LinkResourceRequest[] bandwidthRequests = {bandwidthRequest}; | ||
92 | + return new PathIntent(intent.appId(), | ||
93 | + intent.selector(), intent.treatment(), path, | ||
94 | + bandwidthRequests); | ||
95 | + } | ||
96 | + | ||
97 | + /** | ||
98 | + * Computes a path between two ConnectPoints. | ||
99 | + * | ||
100 | + * @param one start of the path | ||
101 | + * @param two end of the path | ||
102 | + * @return Path between the two | ||
103 | + * @throws org.onlab.onos.net.intent.impl.PathNotFoundException if a path cannot be found | ||
104 | + */ | ||
105 | + private Path getPath(ConnectPoint one, ConnectPoint two, final BandwidthResourceRequest bandwidthRequest) { | ||
106 | + Topology topology = topologyService.currentTopology(); | ||
107 | + LinkWeight weight = new LinkWeight() { | ||
108 | + @Override | ||
109 | + public double weight(TopologyEdge edge) { | ||
110 | + if (bandwidthRequest != null) { | ||
111 | + double allocatedBandwidth = 0.0; | ||
112 | + Iterable<ResourceRequest> availableResources = resourceService.getAvailableResources(edge.link()); | ||
113 | + for (ResourceRequest availableResource : availableResources) { | ||
114 | + if (availableResource.type() == ResourceType.BANDWIDTH) { | ||
115 | + BandwidthResourceRequest bandwidthRequest = (BandwidthResourceRequest) availableResource; | ||
116 | + allocatedBandwidth += bandwidthRequest.bandwidth().toDouble(); | ||
117 | + } | ||
118 | + } | ||
119 | + | ||
120 | + // TODO this needs to be discovered from switch/ports somehow | ||
121 | + double maxBandwidth = 1000; | ||
122 | + | ||
123 | + double availableBandwidth = maxBandwidth - allocatedBandwidth; | ||
124 | + if (availableBandwidth >= bandwidthRequest.bandwidth().toDouble()) { | ||
125 | + return 1; | ||
126 | + } else { | ||
127 | + return -1; | ||
128 | + } | ||
129 | + } else { | ||
130 | + return 1; | ||
131 | + } | ||
132 | + } | ||
133 | + }; | ||
134 | + | ||
135 | + Set<Path> paths = topologyService.getPaths(topology, | ||
136 | + one.deviceId(), | ||
137 | + two.deviceId(), | ||
138 | + weight); | ||
139 | + | ||
140 | + if (paths.isEmpty()) { | ||
141 | + throw new PathNotFoundException("No packet path from " + one + " to " + two); | ||
142 | + } | ||
143 | + // TODO: let's be more intelligent about this eventually | ||
144 | + return paths.iterator().next(); | ||
145 | + } | ||
146 | +} |
... | @@ -15,9 +15,13 @@ | ... | @@ -15,9 +15,13 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.net.resource.impl; | 16 | package org.onlab.onos.net.resource.impl; |
17 | 17 | ||
18 | +import static com.google.common.base.Preconditions.checkArgument; | ||
19 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
18 | import static org.slf4j.LoggerFactory.getLogger; | 20 | import static org.slf4j.LoggerFactory.getLogger; |
19 | 21 | ||
22 | +import java.util.Collections; | ||
20 | import java.util.HashMap; | 23 | import java.util.HashMap; |
24 | +import java.util.HashSet; | ||
21 | import java.util.Iterator; | 25 | import java.util.Iterator; |
22 | import java.util.Map; | 26 | import java.util.Map; |
23 | import java.util.Set; | 27 | import java.util.Set; |
... | @@ -25,6 +29,8 @@ import java.util.Set; | ... | @@ -25,6 +29,8 @@ import java.util.Set; |
25 | import org.apache.felix.scr.annotations.Activate; | 29 | import org.apache.felix.scr.annotations.Activate; |
26 | import org.apache.felix.scr.annotations.Component; | 30 | import org.apache.felix.scr.annotations.Component; |
27 | import org.apache.felix.scr.annotations.Deactivate; | 31 | import org.apache.felix.scr.annotations.Deactivate; |
32 | +import org.apache.felix.scr.annotations.Reference; | ||
33 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
28 | import org.apache.felix.scr.annotations.Service; | 34 | import org.apache.felix.scr.annotations.Service; |
29 | import org.onlab.onos.net.Link; | 35 | import org.onlab.onos.net.Link; |
30 | import org.onlab.onos.net.intent.IntentId; | 36 | import org.onlab.onos.net.intent.IntentId; |
... | @@ -32,15 +38,16 @@ import org.onlab.onos.net.resource.BandwidthResourceAllocation; | ... | @@ -32,15 +38,16 @@ import org.onlab.onos.net.resource.BandwidthResourceAllocation; |
32 | import org.onlab.onos.net.resource.BandwidthResourceRequest; | 38 | import org.onlab.onos.net.resource.BandwidthResourceRequest; |
33 | import org.onlab.onos.net.resource.Lambda; | 39 | import org.onlab.onos.net.resource.Lambda; |
34 | import org.onlab.onos.net.resource.LambdaResourceAllocation; | 40 | import org.onlab.onos.net.resource.LambdaResourceAllocation; |
41 | +import org.onlab.onos.net.resource.LambdaResourceRequest; | ||
35 | import org.onlab.onos.net.resource.LinkResourceAllocations; | 42 | import org.onlab.onos.net.resource.LinkResourceAllocations; |
36 | import org.onlab.onos.net.resource.LinkResourceRequest; | 43 | import org.onlab.onos.net.resource.LinkResourceRequest; |
37 | import org.onlab.onos.net.resource.LinkResourceService; | 44 | import org.onlab.onos.net.resource.LinkResourceService; |
45 | +import org.onlab.onos.net.resource.LinkResourceStore; | ||
38 | import org.onlab.onos.net.resource.ResourceAllocation; | 46 | import org.onlab.onos.net.resource.ResourceAllocation; |
39 | import org.onlab.onos.net.resource.ResourceRequest; | 47 | import org.onlab.onos.net.resource.ResourceRequest; |
48 | +import org.onlab.onos.net.resource.ResourceType; | ||
40 | import org.slf4j.Logger; | 49 | import org.slf4j.Logger; |
41 | 50 | ||
42 | -import com.google.common.collect.Sets; | ||
43 | - | ||
44 | /** | 51 | /** |
45 | * Provides basic implementation of link resources allocation. | 52 | * Provides basic implementation of link resources allocation. |
46 | */ | 53 | */ |
... | @@ -50,6 +57,9 @@ public class LinkResourceManager implements LinkResourceService { | ... | @@ -50,6 +57,9 @@ public class LinkResourceManager implements LinkResourceService { |
50 | 57 | ||
51 | private final Logger log = getLogger(getClass()); | 58 | private final Logger log = getLogger(getClass()); |
52 | 59 | ||
60 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
61 | + private LinkResourceStore store; | ||
62 | + | ||
53 | @Activate | 63 | @Activate |
54 | public void activate() { | 64 | public void activate() { |
55 | log.info("Started"); | 65 | log.info("Started"); |
... | @@ -60,27 +70,65 @@ public class LinkResourceManager implements LinkResourceService { | ... | @@ -60,27 +70,65 @@ public class LinkResourceManager implements LinkResourceService { |
60 | log.info("Stopped"); | 70 | log.info("Stopped"); |
61 | } | 71 | } |
62 | 72 | ||
73 | + /** | ||
74 | + * Returns available lambdas on specified link. | ||
75 | + * | ||
76 | + * @param link the link | ||
77 | + * @return available lambdas on specified link | ||
78 | + */ | ||
79 | + private Set<Lambda> getAvailableLambdas(Link link) { | ||
80 | + checkNotNull(link); | ||
81 | + Set<ResourceAllocation> resAllocs = store.getFreeResources(link); | ||
82 | + if (resAllocs == null) { | ||
83 | + return Collections.emptySet(); | ||
84 | + } | ||
85 | + Set<Lambda> lambdas = new HashSet<>(); | ||
86 | + for (ResourceAllocation res : resAllocs) { | ||
87 | + if (res.type() == ResourceType.LAMBDA) { | ||
88 | + lambdas.add(((LambdaResourceAllocation) res).lambda()); | ||
89 | + } | ||
90 | + } | ||
91 | + return lambdas; | ||
92 | + } | ||
93 | + | ||
94 | + /** | ||
95 | + * Returns available lambdas on specified links. | ||
96 | + * | ||
97 | + * @param links the links | ||
98 | + * @return available lambdas on specified links | ||
99 | + */ | ||
63 | private Iterable<Lambda> getAvailableLambdas(Iterable<Link> links) { | 100 | private Iterable<Lambda> getAvailableLambdas(Iterable<Link> links) { |
64 | - return Sets.newHashSet(Lambda.valueOf(7)); | 101 | + checkNotNull(links); |
102 | + Iterator<Link> i = links.iterator(); | ||
103 | + checkArgument(i.hasNext()); | ||
104 | + Set<Lambda> lambdas = new HashSet<>(getAvailableLambdas(i.next())); | ||
105 | + while (i.hasNext()) { | ||
106 | + lambdas.retainAll(getAvailableLambdas(i.next())); | ||
107 | + } | ||
108 | + return lambdas; | ||
65 | } | 109 | } |
66 | 110 | ||
67 | @Override | 111 | @Override |
68 | public LinkResourceAllocations requestResources(LinkResourceRequest req) { | 112 | public LinkResourceAllocations requestResources(LinkResourceRequest req) { |
69 | - // TODO implement it using a resource data store. | 113 | + // TODO Concatenate multiple bandwidth requests. |
114 | + // TODO Support multiple lambda resource requests. | ||
115 | + // TODO Throw appropriate exception. | ||
70 | 116 | ||
71 | - ResourceAllocation alloc = null; | 117 | + Set<ResourceAllocation> allocs = new HashSet<>(); |
72 | for (ResourceRequest r : req.resources()) { | 118 | for (ResourceRequest r : req.resources()) { |
73 | switch (r.type()) { | 119 | switch (r.type()) { |
74 | case BANDWIDTH: | 120 | case BANDWIDTH: |
75 | - log.info("requestResources() always returns requested bandwidth"); | ||
76 | BandwidthResourceRequest br = (BandwidthResourceRequest) r; | 121 | BandwidthResourceRequest br = (BandwidthResourceRequest) r; |
77 | - alloc = new BandwidthResourceAllocation(br.bandwidth()); | 122 | + allocs.add(new BandwidthResourceAllocation(br.bandwidth())); |
78 | break; | 123 | break; |
79 | case LAMBDA: | 124 | case LAMBDA: |
80 | - log.info("requestResources() always returns lambda 7"); | 125 | + Iterator<Lambda> lambdaIterator = |
81 | - Iterator<Lambda> lambdaIterator = getAvailableLambdas(req.links()).iterator(); | 126 | + getAvailableLambdas(req.links()).iterator(); |
82 | if (lambdaIterator.hasNext()) { | 127 | if (lambdaIterator.hasNext()) { |
83 | - alloc = new LambdaResourceAllocation(lambdaIterator.next()); | 128 | + allocs.add(new LambdaResourceAllocation(lambdaIterator.next())); |
129 | + } else { | ||
130 | + log.info("Failed to allocate lambda resource."); | ||
131 | + return null; | ||
84 | } | 132 | } |
85 | break; | 133 | break; |
86 | default: | 134 | default: |
... | @@ -90,50 +138,66 @@ public class LinkResourceManager implements LinkResourceService { | ... | @@ -90,50 +138,66 @@ public class LinkResourceManager implements LinkResourceService { |
90 | 138 | ||
91 | Map<Link, Set<ResourceAllocation>> allocations = new HashMap<>(); | 139 | Map<Link, Set<ResourceAllocation>> allocations = new HashMap<>(); |
92 | for (Link link : req.links()) { | 140 | for (Link link : req.links()) { |
93 | - allocations.put(link, Sets.newHashSet(alloc)); | 141 | + allocations.put(link, allocs); |
94 | } | 142 | } |
95 | - return new DefaultLinkResourceAllocations(req, allocations); | 143 | + LinkResourceAllocations result = |
144 | + new DefaultLinkResourceAllocations(req, allocations); | ||
145 | + store.allocateResources(result); | ||
146 | + return result; | ||
147 | + | ||
96 | } | 148 | } |
97 | 149 | ||
98 | @Override | 150 | @Override |
99 | public void releaseResources(LinkResourceAllocations allocations) { | 151 | public void releaseResources(LinkResourceAllocations allocations) { |
100 | - // TODO Auto-generated method stub | 152 | + store.releaseResources(allocations); |
101 | - | ||
102 | } | 153 | } |
103 | 154 | ||
104 | @Override | 155 | @Override |
105 | public LinkResourceAllocations updateResources(LinkResourceRequest req, | 156 | public LinkResourceAllocations updateResources(LinkResourceRequest req, |
106 | - LinkResourceAllocations oldAllocations) { | 157 | + LinkResourceAllocations oldAllocations) { |
158 | + // TODO | ||
107 | return null; | 159 | return null; |
108 | } | 160 | } |
109 | 161 | ||
110 | @Override | 162 | @Override |
111 | public Iterable<LinkResourceAllocations> getAllocations() { | 163 | public Iterable<LinkResourceAllocations> getAllocations() { |
112 | - // TODO Auto-generated method stub | 164 | + return store.getAllocations(); |
113 | - return null; | ||
114 | } | 165 | } |
115 | 166 | ||
116 | @Override | 167 | @Override |
117 | public Iterable<LinkResourceAllocations> getAllocations(Link link) { | 168 | public Iterable<LinkResourceAllocations> getAllocations(Link link) { |
118 | - // TODO Auto-generated method stub | 169 | + return store.getAllocations(link); |
119 | - return null; | ||
120 | } | 170 | } |
121 | 171 | ||
122 | @Override | 172 | @Override |
123 | public LinkResourceAllocations getAllocations(IntentId intentId) { | 173 | public LinkResourceAllocations getAllocations(IntentId intentId) { |
124 | - // TODO Auto-generated method stub | 174 | + return store.getAllocations(intentId); |
125 | - return null; | ||
126 | } | 175 | } |
127 | 176 | ||
128 | @Override | 177 | @Override |
129 | public Iterable<ResourceRequest> getAvailableResources(Link link) { | 178 | public Iterable<ResourceRequest> getAvailableResources(Link link) { |
130 | - // TODO Auto-generated method stub | 179 | + Set<ResourceAllocation> freeRes = store.getFreeResources(link); |
131 | - return null; | 180 | + Set<ResourceRequest> result = new HashSet<>(); |
181 | + for (ResourceAllocation alloc : freeRes) { | ||
182 | + switch (alloc.type()) { | ||
183 | + case BANDWIDTH: | ||
184 | + result.add(new BandwidthResourceRequest( | ||
185 | + ((BandwidthResourceAllocation) alloc).bandwidth())); | ||
186 | + break; | ||
187 | + case LAMBDA: | ||
188 | + result.add(new LambdaResourceRequest()); | ||
189 | + break; | ||
190 | + default: | ||
191 | + break; | ||
192 | + } | ||
193 | + } | ||
194 | + return result; | ||
132 | } | 195 | } |
133 | 196 | ||
134 | @Override | 197 | @Override |
135 | public ResourceRequest getAvailableResources(Link link, | 198 | public ResourceRequest getAvailableResources(Link link, |
136 | - LinkResourceAllocations allocations) { | 199 | + LinkResourceAllocations allocations) { |
200 | + // TODO | ||
137 | return null; | 201 | return null; |
138 | } | 202 | } |
139 | 203 | ... | ... |
... | @@ -543,8 +543,9 @@ public class GossipDeviceStore | ... | @@ -543,8 +543,9 @@ public class GossipDeviceStore |
543 | Port newPort, | 543 | Port newPort, |
544 | Map<PortNumber, Port> ports) { | 544 | Map<PortNumber, Port> ports) { |
545 | if (oldPort.isEnabled() != newPort.isEnabled() || | 545 | if (oldPort.isEnabled() != newPort.isEnabled() || |
546 | - !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) { | 546 | + oldPort.type() != newPort.type() || |
547 | - | 547 | + oldPort.portSpeed() != newPort.portSpeed() || |
548 | + !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) { | ||
548 | ports.put(oldPort.number(), newPort); | 549 | ports.put(oldPort.number(), newPort); |
549 | return new DeviceEvent(PORT_UPDATED, device, newPort); | 550 | return new DeviceEvent(PORT_UPDATED, device, newPort); |
550 | } | 551 | } |
... | @@ -867,7 +868,10 @@ public class GossipDeviceStore | ... | @@ -867,7 +868,10 @@ public class GossipDeviceStore |
867 | } | 868 | } |
868 | } | 869 | } |
869 | 870 | ||
870 | - return new DefaultPort(device, number, isEnabled, annotations); | 871 | + return portDesc == null ? |
872 | + new DefaultPort(device, number, false, annotations) : | ||
873 | + new DefaultPort(device, number, isEnabled, portDesc.value().type(), | ||
874 | + portDesc.value().portSpeed(), annotations); | ||
871 | } | 875 | } |
872 | 876 | ||
873 | /** | 877 | /** | ... | ... |
... | @@ -16,7 +16,9 @@ | ... | @@ -16,7 +16,9 @@ |
16 | package org.onlab.onos.store.mastership.impl; | 16 | package org.onlab.onos.store.mastership.impl; |
17 | 17 | ||
18 | import static org.onlab.onos.mastership.MastershipEvent.Type.MASTER_CHANGED; | 18 | import static org.onlab.onos.mastership.MastershipEvent.Type.MASTER_CHANGED; |
19 | +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.putIfAbsent; | ||
19 | 20 | ||
21 | +import java.util.HashSet; | ||
20 | import java.util.Map; | 22 | import java.util.Map; |
21 | import java.util.Set; | 23 | import java.util.Set; |
22 | 24 | ||
... | @@ -41,7 +43,6 @@ import org.onlab.onos.store.serializers.KryoNamespaces; | ... | @@ -41,7 +43,6 @@ import org.onlab.onos.store.serializers.KryoNamespaces; |
41 | import org.onlab.onos.store.serializers.KryoSerializer; | 43 | import org.onlab.onos.store.serializers.KryoSerializer; |
42 | import org.onlab.util.KryoNamespace; | 44 | import org.onlab.util.KryoNamespace; |
43 | 45 | ||
44 | -import com.google.common.collect.ImmutableSet; | ||
45 | import com.hazelcast.core.EntryEvent; | 46 | import com.hazelcast.core.EntryEvent; |
46 | import com.hazelcast.core.EntryListener; | 47 | import com.hazelcast.core.EntryListener; |
47 | import com.hazelcast.core.IAtomicLong; | 48 | import com.hazelcast.core.IAtomicLong; |
... | @@ -105,46 +106,50 @@ implements MastershipStore { | ... | @@ -105,46 +106,50 @@ implements MastershipStore { |
105 | 106 | ||
106 | @Override | 107 | @Override |
107 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { | 108 | public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { |
108 | - final RoleValue roleInfo = getRoleValue(deviceId); | 109 | + final RoleValue roleInfo = roleMap.get(deviceId); |
109 | - if (roleInfo.contains(MASTER, nodeId)) { | 110 | + if (roleInfo != null) { |
110 | - return MASTER; | 111 | + return roleInfo.getRole(nodeId); |
111 | - } | ||
112 | - if (roleInfo.contains(STANDBY, nodeId)) { | ||
113 | - return STANDBY; | ||
114 | } | 112 | } |
115 | return NONE; | 113 | return NONE; |
116 | } | 114 | } |
117 | 115 | ||
118 | @Override | 116 | @Override |
119 | - public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) { | 117 | + public MastershipEvent setMaster(NodeId newMaster, DeviceId deviceId) { |
120 | 118 | ||
121 | - MastershipRole role = getRole(nodeId, deviceId); | ||
122 | roleMap.lock(deviceId); | 119 | roleMap.lock(deviceId); |
123 | try { | 120 | try { |
124 | - RoleValue rv = getRoleValue(deviceId); | 121 | + final RoleValue rv = getRoleValue(deviceId); |
125 | - switch (role) { | 122 | + final MastershipRole currentRole = rv.getRole(newMaster); |
123 | + switch (currentRole) { | ||
126 | case MASTER: | 124 | case MASTER: |
127 | //reinforce mastership | 125 | //reinforce mastership |
128 | - rv.reassign(nodeId, STANDBY, NONE); | 126 | + // RoleInfo integrity check |
129 | - roleMap.put(deviceId, rv); | 127 | + boolean modified = rv.reassign(newMaster, STANDBY, NONE); |
128 | + if (modified) { | ||
129 | + roleMap.put(deviceId, rv); | ||
130 | + // should never reach here. | ||
131 | + log.warn("{} was in both MASTER and STANDBY for {}", newMaster, deviceId); | ||
132 | + // trigger BACKUPS_CHANGED? | ||
133 | + } | ||
130 | return null; | 134 | return null; |
131 | case STANDBY: | 135 | case STANDBY: |
132 | case NONE: | 136 | case NONE: |
133 | - NodeId current = rv.get(MASTER); | 137 | + final NodeId currentMaster = rv.get(MASTER); |
134 | - if (current != null) { | 138 | + if (currentMaster != null) { |
135 | - //backup and replace current master | 139 | + // place current master in STANDBY |
136 | - rv.reassign(current, NONE, STANDBY); | 140 | + rv.reassign(currentMaster, NONE, STANDBY); |
137 | - rv.replace(current, nodeId, MASTER); | 141 | + rv.replace(currentMaster, newMaster, MASTER); |
138 | } else { | 142 | } else { |
139 | //no master before so just add. | 143 | //no master before so just add. |
140 | - rv.add(MASTER, nodeId); | 144 | + rv.add(MASTER, newMaster); |
141 | } | 145 | } |
142 | - rv.reassign(nodeId, STANDBY, NONE); | 146 | + // remove newMaster from STANDBY |
143 | - roleMap.put(deviceId, rv); | 147 | + rv.reassign(newMaster, STANDBY, NONE); |
144 | updateTerm(deviceId); | 148 | updateTerm(deviceId); |
149 | + roleMap.put(deviceId, rv); | ||
145 | return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); | 150 | return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); |
146 | default: | 151 | default: |
147 | - log.warn("unknown Mastership Role {}", role); | 152 | + log.warn("unknown Mastership Role {}", currentRole); |
148 | return null; | 153 | return null; |
149 | } | 154 | } |
150 | } finally { | 155 | } finally { |
... | @@ -160,66 +165,83 @@ implements MastershipStore { | ... | @@ -160,66 +165,83 @@ implements MastershipStore { |
160 | 165 | ||
161 | @Override | 166 | @Override |
162 | public RoleInfo getNodes(DeviceId deviceId) { | 167 | public RoleInfo getNodes(DeviceId deviceId) { |
163 | - roleMap.lock(deviceId); | 168 | + RoleValue rv = roleMap.get(deviceId); |
164 | - try { | 169 | + if (rv != null) { |
165 | - RoleValue rv = getRoleValue(deviceId); | ||
166 | return rv.roleInfo(); | 170 | return rv.roleInfo(); |
167 | - } finally { | 171 | + } else { |
168 | - roleMap.unlock(deviceId); | 172 | + return new RoleInfo(); |
169 | } | 173 | } |
170 | } | 174 | } |
171 | 175 | ||
172 | @Override | 176 | @Override |
173 | public Set<DeviceId> getDevices(NodeId nodeId) { | 177 | public Set<DeviceId> getDevices(NodeId nodeId) { |
174 | - ImmutableSet.Builder<DeviceId> builder = ImmutableSet.builder(); | 178 | + Set<DeviceId> devices = new HashSet<>(); |
175 | 179 | ||
176 | for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) { | 180 | for (Map.Entry<DeviceId, RoleValue> el : roleMap.entrySet()) { |
177 | if (nodeId.equals(el.getValue().get(MASTER))) { | 181 | if (nodeId.equals(el.getValue().get(MASTER))) { |
178 | - builder.add(el.getKey()); | 182 | + devices.add(el.getKey()); |
179 | } | 183 | } |
180 | } | 184 | } |
181 | 185 | ||
182 | - return builder.build(); | 186 | + return devices; |
183 | } | 187 | } |
184 | 188 | ||
185 | @Override | 189 | @Override |
186 | public MastershipRole requestRole(DeviceId deviceId) { | 190 | public MastershipRole requestRole(DeviceId deviceId) { |
187 | - NodeId local = clusterService.getLocalNode().id(); | ||
188 | 191 | ||
192 | + // if no master => become master | ||
193 | + // if there already exists a master: | ||
194 | + // if I was the master return MASTER | ||
195 | + // else put myself in STANDBY and return STANDBY | ||
196 | + | ||
197 | + final NodeId local = clusterService.getLocalNode().id(); | ||
198 | + boolean modified = false; | ||
189 | roleMap.lock(deviceId); | 199 | roleMap.lock(deviceId); |
190 | try { | 200 | try { |
191 | - RoleValue rv = getRoleValue(deviceId); | 201 | + final RoleValue rv = getRoleValue(deviceId); |
192 | - MastershipRole role = getRole(local, deviceId); | 202 | + if (rv.get(MASTER) == null) { |
193 | - switch (role) { | 203 | + // there's no master become one |
204 | + // move out from STANDBY | ||
205 | + rv.reassign(local, STANDBY, NONE); | ||
206 | + rv.add(MASTER, local); | ||
207 | + | ||
208 | + updateTerm(deviceId); | ||
209 | + roleMap.put(deviceId, rv); | ||
210 | + return MASTER; | ||
211 | + } | ||
212 | + final MastershipRole currentRole = rv.getRole(local); | ||
213 | + switch (currentRole) { | ||
194 | case MASTER: | 214 | case MASTER: |
195 | - rv.reassign(local, STANDBY, NONE); | 215 | + // RoleInfo integrity check |
196 | - terms.putIfAbsent(deviceId, INIT); | 216 | + modified = rv.reassign(local, STANDBY, NONE); |
197 | - roleMap.put(deviceId, rv); | 217 | + if (modified) { |
198 | - break; | 218 | + log.warn("{} was in both MASTER and STANDBY for {}", local, deviceId); |
219 | + // should never reach here, | ||
220 | + // but heal if we happened to be there | ||
221 | + roleMap.put(deviceId, rv); | ||
222 | + // trigger BACKUPS_CHANGED? | ||
223 | + } | ||
224 | + return currentRole; | ||
199 | case STANDBY: | 225 | case STANDBY: |
200 | - rv.reassign(local, NONE, STANDBY); | 226 | + // RoleInfo integrity check |
201 | - roleMap.put(deviceId, rv); | 227 | + modified = rv.reassign(local, NONE, STANDBY); |
202 | - terms.putIfAbsent(deviceId, INIT); | 228 | + if (modified) { |
203 | - break; | 229 | + log.warn("{} was in both NONE and STANDBY for {}", local, deviceId); |
204 | - case NONE: | 230 | + // should never reach here, |
205 | - //either we're the first standby, or first to device. | 231 | + // but heal if we happened to be there |
206 | - //for latter, claim mastership. | 232 | + roleMap.put(deviceId, rv); |
207 | - if (rv.get(MASTER) == null) { | 233 | + // trigger BACKUPS_CHANGED? |
208 | - rv.add(MASTER, local); | ||
209 | - rv.reassign(local, STANDBY, NONE); | ||
210 | - updateTerm(deviceId); | ||
211 | - role = MastershipRole.MASTER; | ||
212 | - } else { | ||
213 | - rv.add(STANDBY, local); | ||
214 | - rv.reassign(local, NONE, STANDBY); | ||
215 | - role = MastershipRole.STANDBY; | ||
216 | } | 234 | } |
235 | + return currentRole; | ||
236 | + case NONE: | ||
237 | + rv.reassign(local, NONE, STANDBY); | ||
217 | roleMap.put(deviceId, rv); | 238 | roleMap.put(deviceId, rv); |
218 | - break; | 239 | + // TODO: notifyDelegate BACKUPS_CHANGED |
240 | + return STANDBY; | ||
219 | default: | 241 | default: |
220 | - log.warn("unknown Mastership Role {}", role); | 242 | + log.warn("unknown Mastership Role {}", currentRole); |
221 | } | 243 | } |
222 | - return role; | 244 | + return currentRole; |
223 | } finally { | 245 | } finally { |
224 | roleMap.unlock(deviceId); | 246 | roleMap.unlock(deviceId); |
225 | } | 247 | } |
... | @@ -227,35 +249,58 @@ implements MastershipStore { | ... | @@ -227,35 +249,58 @@ implements MastershipStore { |
227 | 249 | ||
228 | @Override | 250 | @Override |
229 | public MastershipTerm getTermFor(DeviceId deviceId) { | 251 | public MastershipTerm getTermFor(DeviceId deviceId) { |
230 | - RoleValue rv = getRoleValue(deviceId); | 252 | + // term information and role must be read atomically |
231 | - if ((rv.get(MASTER) == null) || (terms.get(deviceId) == null)) { | 253 | + // acquiring write lock for the device |
232 | - return null; | 254 | + roleMap.lock(deviceId); |
255 | + try { | ||
256 | + RoleValue rv = getRoleValue(deviceId); | ||
257 | + final Integer term = terms.get(deviceId); | ||
258 | + final NodeId master = rv.get(MASTER); | ||
259 | + if ((master == null) || (term == null)) { | ||
260 | + return null; | ||
261 | + } | ||
262 | + return MastershipTerm.of(master, term); | ||
263 | + } finally { | ||
264 | + roleMap.unlock(deviceId); | ||
233 | } | 265 | } |
234 | - return MastershipTerm.of(rv.get(MASTER), terms.get(deviceId)); | ||
235 | } | 266 | } |
236 | 267 | ||
237 | @Override | 268 | @Override |
238 | public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) { | 269 | public MastershipEvent setStandby(NodeId nodeId, DeviceId deviceId) { |
239 | - MastershipEvent event = null; | 270 | + // if nodeId was MASTER, rotate STANDBY |
271 | + // if nodeId was STANDBY no-op | ||
272 | + // if nodeId was NONE, add to STANDBY | ||
240 | 273 | ||
241 | roleMap.lock(deviceId); | 274 | roleMap.lock(deviceId); |
242 | try { | 275 | try { |
243 | - RoleValue rv = getRoleValue(deviceId); | 276 | + final RoleValue rv = getRoleValue(deviceId); |
244 | - MastershipRole role = getRole(nodeId, deviceId); | 277 | + final MastershipRole currentRole = getRole(nodeId, deviceId); |
245 | - switch (role) { | 278 | + switch (currentRole) { |
246 | case MASTER: | 279 | case MASTER: |
247 | - event = reelect(nodeId, deviceId, rv); | 280 | + NodeId newMaster = reelect(nodeId, deviceId, rv); |
248 | - //fall through to reinforce role | 281 | + rv.reassign(nodeId, NONE, STANDBY); |
282 | + if (newMaster != null) { | ||
283 | + updateTerm(deviceId); | ||
284 | + roleMap.put(deviceId, rv); | ||
285 | + return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); | ||
286 | + } else { | ||
287 | + // no master candidate | ||
288 | + roleMap.put(deviceId, rv); | ||
289 | + // FIXME: Should there be new event type? | ||
290 | + // or should we issue null Master event? | ||
291 | + return null; | ||
292 | + } | ||
249 | case STANDBY: | 293 | case STANDBY: |
250 | - //fall through to reinforce role | 294 | + return null; |
251 | case NONE: | 295 | case NONE: |
252 | rv.reassign(nodeId, NONE, STANDBY); | 296 | rv.reassign(nodeId, NONE, STANDBY); |
253 | roleMap.put(deviceId, rv); | 297 | roleMap.put(deviceId, rv); |
254 | - break; | 298 | + // TODO: BACKUPS_CHANGED? |
299 | + return null; | ||
255 | default: | 300 | default: |
256 | - log.warn("unknown Mastership Role {}", role); | 301 | + log.warn("unknown Mastership Role {}", currentRole); |
257 | } | 302 | } |
258 | - return event; | 303 | + return null; |
259 | } finally { | 304 | } finally { |
260 | roleMap.unlock(deviceId); | 305 | roleMap.unlock(deviceId); |
261 | } | 306 | } |
... | @@ -263,57 +308,71 @@ implements MastershipStore { | ... | @@ -263,57 +308,71 @@ implements MastershipStore { |
263 | 308 | ||
264 | @Override | 309 | @Override |
265 | public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) { | 310 | public MastershipEvent relinquishRole(NodeId nodeId, DeviceId deviceId) { |
266 | - MastershipEvent event = null; | 311 | + // relinquishRole is basically set to None |
312 | + | ||
313 | + // If nodeId was master reelect next and remove nodeId | ||
314 | + // else remove from STANDBY | ||
267 | 315 | ||
268 | roleMap.lock(deviceId); | 316 | roleMap.lock(deviceId); |
269 | try { | 317 | try { |
270 | - RoleValue rv = getRoleValue(deviceId); | 318 | + final RoleValue rv = getRoleValue(deviceId); |
271 | - MastershipRole role = getRole(nodeId, deviceId); | 319 | + final MastershipRole currentRole = rv.getRole(nodeId); |
272 | - switch (role) { | 320 | + switch (currentRole) { |
273 | case MASTER: | 321 | case MASTER: |
274 | - event = reelect(nodeId, deviceId, rv); | 322 | + NodeId newMaster = reelect(nodeId, deviceId, rv); |
275 | - if (event != null) { | 323 | + if (newMaster != null) { |
276 | - Integer term = terms.get(deviceId); | 324 | + updateTerm(deviceId); |
277 | - terms.put(deviceId, ++term); | 325 | + roleMap.put(deviceId, rv); |
326 | + return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); | ||
327 | + } else { | ||
328 | + // no master candidate | ||
329 | + roleMap.put(deviceId, rv); | ||
330 | + // Should there be new event type? | ||
331 | + return null; | ||
278 | } | 332 | } |
279 | - //fall through to reinforce relinquishment | ||
280 | case STANDBY: | 333 | case STANDBY: |
281 | //fall through to reinforce relinquishment | 334 | //fall through to reinforce relinquishment |
282 | case NONE: | 335 | case NONE: |
283 | - rv.reassign(nodeId, STANDBY, NONE); | 336 | + boolean modified = rv.reassign(nodeId, STANDBY, NONE); |
284 | - roleMap.put(deviceId, rv); | 337 | + if (modified) { |
285 | - break; | 338 | + roleMap.put(deviceId, rv); |
339 | + // TODO: BACKUPS_CHANGED? | ||
340 | + return null; | ||
341 | + } | ||
342 | + return null; | ||
286 | default: | 343 | default: |
287 | - log.warn("unknown Mastership Role {}", role); | 344 | + log.warn("unknown Mastership Role {}", currentRole); |
288 | } | 345 | } |
289 | - return event; | 346 | + return null; |
290 | } finally { | 347 | } finally { |
291 | roleMap.unlock(deviceId); | 348 | roleMap.unlock(deviceId); |
292 | } | 349 | } |
293 | } | 350 | } |
294 | 351 | ||
352 | + // TODO: Consider moving this to RoleValue method | ||
295 | //helper to fetch a new master candidate for a given device. | 353 | //helper to fetch a new master candidate for a given device. |
296 | - private MastershipEvent reelect( | 354 | + private NodeId reelect( |
297 | NodeId current, DeviceId deviceId, RoleValue rv) { | 355 | NodeId current, DeviceId deviceId, RoleValue rv) { |
298 | 356 | ||
299 | //if this is an queue it'd be neater. | 357 | //if this is an queue it'd be neater. |
300 | - NodeId backup = null; | 358 | + NodeId candidate = null; |
301 | for (NodeId n : rv.nodesOfRole(STANDBY)) { | 359 | for (NodeId n : rv.nodesOfRole(STANDBY)) { |
302 | if (!current.equals(n)) { | 360 | if (!current.equals(n)) { |
303 | - backup = n; | 361 | + candidate = n; |
304 | break; | 362 | break; |
305 | } | 363 | } |
306 | } | 364 | } |
307 | 365 | ||
308 | - if (backup == null) { | 366 | + if (candidate == null) { |
309 | log.info("{} giving up and going to NONE for {}", current, deviceId); | 367 | log.info("{} giving up and going to NONE for {}", current, deviceId); |
310 | rv.remove(MASTER, current); | 368 | rv.remove(MASTER, current); |
369 | + // master did change, but there is no master candidate. | ||
311 | return null; | 370 | return null; |
312 | } else { | 371 | } else { |
313 | - log.info("{} trying to pass mastership for {} to {}", current, deviceId, backup); | 372 | + log.info("{} trying to pass mastership for {} to {}", current, deviceId, candidate); |
314 | - rv.replace(current, backup, MASTER); | 373 | + rv.replace(current, candidate, MASTER); |
315 | - rv.reassign(backup, STANDBY, NONE); | 374 | + rv.reassign(candidate, STANDBY, NONE); |
316 | - return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); | 375 | + return candidate; |
317 | } | 376 | } |
318 | } | 377 | } |
319 | 378 | ||
... | @@ -340,17 +399,30 @@ implements MastershipStore { | ... | @@ -340,17 +399,30 @@ implements MastershipStore { |
340 | } | 399 | } |
341 | 400 | ||
342 | //adds or updates term information. | 401 | //adds or updates term information. |
402 | + // must be guarded by roleMap.lock(deviceId) | ||
343 | private void updateTerm(DeviceId deviceId) { | 403 | private void updateTerm(DeviceId deviceId) { |
344 | - terms.lock(deviceId); | 404 | + Integer term = terms.get(deviceId); |
345 | - try { | 405 | + if (term == null) { |
346 | - Integer term = terms.get(deviceId); | 406 | + term = terms.putIfAbsent(deviceId, INIT); |
347 | if (term == null) { | 407 | if (term == null) { |
348 | - terms.put(deviceId, INIT); | 408 | + // initial term set successfully |
349 | - } else { | 409 | + return; |
350 | - terms.put(deviceId, ++term); | ||
351 | } | 410 | } |
352 | - } finally { | 411 | + // concurrent initialization detected, |
353 | - terms.unlock(deviceId); | 412 | + // fall through to try incrementing |
413 | + } | ||
414 | + Integer nextTerm = term + 1; | ||
415 | + boolean success = terms.replace(deviceId, term, nextTerm); | ||
416 | + while (!success) { | ||
417 | + term = terms.get(deviceId); | ||
418 | + if (term == null) { | ||
419 | + // something is very wrong, but write something to avoid | ||
420 | + // infinite loop. | ||
421 | + log.warn("Term info for {} disappeared.", deviceId); | ||
422 | + term = putIfAbsent(terms, deviceId, nextTerm); | ||
423 | + } | ||
424 | + nextTerm = term + 1; | ||
425 | + success = terms.replace(deviceId, term, nextTerm); | ||
354 | } | 426 | } |
355 | } | 427 | } |
356 | 428 | ... | ... |
... | @@ -15,6 +15,10 @@ | ... | @@ -15,6 +15,10 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.store.mastership.impl; | 16 | package org.onlab.onos.store.mastership.impl; |
17 | 17 | ||
18 | +import static org.onlab.onos.net.MastershipRole.MASTER; | ||
19 | +import static org.onlab.onos.net.MastershipRole.NONE; | ||
20 | +import static org.onlab.onos.net.MastershipRole.STANDBY; | ||
21 | + | ||
18 | import java.util.Collections; | 22 | import java.util.Collections; |
19 | import java.util.EnumMap; | 23 | import java.util.EnumMap; |
20 | import java.util.LinkedList; | 24 | import java.util.LinkedList; |
... | @@ -59,18 +63,30 @@ final class RoleValue { | ... | @@ -59,18 +63,30 @@ final class RoleValue { |
59 | return value.get(type).contains(nodeId); | 63 | return value.get(type).contains(nodeId); |
60 | } | 64 | } |
61 | 65 | ||
66 | + public MastershipRole getRole(NodeId nodeId) { | ||
67 | + if (contains(MASTER, nodeId)) { | ||
68 | + return MASTER; | ||
69 | + } | ||
70 | + if (contains(STANDBY, nodeId)) { | ||
71 | + return STANDBY; | ||
72 | + } | ||
73 | + return NONE; | ||
74 | + } | ||
75 | + | ||
62 | /** | 76 | /** |
63 | * Associates a node to a certain role. | 77 | * Associates a node to a certain role. |
64 | * | 78 | * |
65 | * @param type the role | 79 | * @param type the role |
66 | * @param nodeId the node ID of the node to associate | 80 | * @param nodeId the node ID of the node to associate |
81 | + * @return true if modified | ||
67 | */ | 82 | */ |
68 | - public void add(MastershipRole type, NodeId nodeId) { | 83 | + public boolean add(MastershipRole type, NodeId nodeId) { |
69 | List<NodeId> nodes = value.get(type); | 84 | List<NodeId> nodes = value.get(type); |
70 | 85 | ||
71 | if (!nodes.contains(nodeId)) { | 86 | if (!nodes.contains(nodeId)) { |
72 | - nodes.add(nodeId); | 87 | + return nodes.add(nodeId); |
73 | } | 88 | } |
89 | + return false; | ||
74 | } | 90 | } |
75 | 91 | ||
76 | /** | 92 | /** |
... | @@ -78,7 +94,7 @@ final class RoleValue { | ... | @@ -78,7 +94,7 @@ final class RoleValue { |
78 | * | 94 | * |
79 | * @param type the role | 95 | * @param type the role |
80 | * @param nodeId the ID of the node to remove | 96 | * @param nodeId the ID of the node to remove |
81 | - * @return | 97 | + * @return true if modified |
82 | */ | 98 | */ |
83 | public boolean remove(MastershipRole type, NodeId nodeId) { | 99 | public boolean remove(MastershipRole type, NodeId nodeId) { |
84 | List<NodeId> nodes = value.get(type); | 100 | List<NodeId> nodes = value.get(type); |
... | @@ -96,10 +112,12 @@ final class RoleValue { | ... | @@ -96,10 +112,12 @@ final class RoleValue { |
96 | * @param nodeId the Node ID of node changing roles | 112 | * @param nodeId the Node ID of node changing roles |
97 | * @param from the old role | 113 | * @param from the old role |
98 | * @param to the new role | 114 | * @param to the new role |
115 | + * @return true if modified | ||
99 | */ | 116 | */ |
100 | - public void reassign(NodeId nodeId, MastershipRole from, MastershipRole to) { | 117 | + public boolean reassign(NodeId nodeId, MastershipRole from, MastershipRole to) { |
101 | - remove(from, nodeId); | 118 | + boolean modified = remove(from, nodeId); |
102 | - add(to, nodeId); | 119 | + modified |= add(to, nodeId); |
120 | + return modified; | ||
103 | } | 121 | } |
104 | 122 | ||
105 | /** | 123 | /** |
... | @@ -109,10 +127,12 @@ final class RoleValue { | ... | @@ -109,10 +127,12 @@ final class RoleValue { |
109 | * @param from the old NodeId to replace | 127 | * @param from the old NodeId to replace |
110 | * @param to the new NodeId | 128 | * @param to the new NodeId |
111 | * @param type the role associated with the old NodeId | 129 | * @param type the role associated with the old NodeId |
130 | + * @return true if modified | ||
112 | */ | 131 | */ |
113 | - public void replace(NodeId from, NodeId to, MastershipRole type) { | 132 | + public boolean replace(NodeId from, NodeId to, MastershipRole type) { |
114 | - remove(type, from); | 133 | + boolean modified = remove(type, from); |
115 | - add(type, to); | 134 | + modified |= add(type, to); |
135 | + return modified; | ||
116 | } | 136 | } |
117 | 137 | ||
118 | /** | 138 | /** | ... | ... |
... | @@ -142,7 +142,7 @@ public class DistributedMastershipStoreTest { | ... | @@ -142,7 +142,7 @@ public class DistributedMastershipStoreTest { |
142 | testStore.setCurrent(CN1); | 142 | testStore.setCurrent(CN1); |
143 | 143 | ||
144 | //if already MASTER, nothing should happen | 144 | //if already MASTER, nothing should happen |
145 | - testStore.put(DID2, N1, true, false, false); | 145 | + testStore.put(DID2, N1, true, false, true); |
146 | assertEquals("wrong role for MASTER:", MASTER, dms.requestRole(DID2)); | 146 | assertEquals("wrong role for MASTER:", MASTER, dms.requestRole(DID2)); |
147 | 147 | ||
148 | //populate maps with DID1, N1 thru NONE case | 148 | //populate maps with DID1, N1 thru NONE case | ... | ... |
... | @@ -22,11 +22,11 @@ import java.util.HashMap; | ... | @@ -22,11 +22,11 @@ import java.util.HashMap; |
22 | import java.util.HashSet; | 22 | import java.util.HashSet; |
23 | import java.util.LinkedList; | 23 | import java.util.LinkedList; |
24 | 24 | ||
25 | -import org.onlab.onos.core.DefaultApplicationId; | ||
26 | import org.onlab.onos.cluster.ControllerNode; | 25 | import org.onlab.onos.cluster.ControllerNode; |
27 | import org.onlab.onos.cluster.DefaultControllerNode; | 26 | import org.onlab.onos.cluster.DefaultControllerNode; |
28 | import org.onlab.onos.cluster.NodeId; | 27 | import org.onlab.onos.cluster.NodeId; |
29 | import org.onlab.onos.cluster.RoleInfo; | 28 | import org.onlab.onos.cluster.RoleInfo; |
29 | +import org.onlab.onos.core.DefaultApplicationId; | ||
30 | import org.onlab.onos.mastership.MastershipTerm; | 30 | import org.onlab.onos.mastership.MastershipTerm; |
31 | import org.onlab.onos.net.ConnectPoint; | 31 | import org.onlab.onos.net.ConnectPoint; |
32 | import org.onlab.onos.net.DefaultAnnotations; | 32 | import org.onlab.onos.net.DefaultAnnotations; |
... | @@ -59,6 +59,9 @@ import org.onlab.onos.net.flow.StoredFlowEntry; | ... | @@ -59,6 +59,9 @@ import org.onlab.onos.net.flow.StoredFlowEntry; |
59 | import org.onlab.onos.net.flow.criteria.Criteria; | 59 | import org.onlab.onos.net.flow.criteria.Criteria; |
60 | import org.onlab.onos.net.flow.criteria.Criterion; | 60 | import org.onlab.onos.net.flow.criteria.Criterion; |
61 | import org.onlab.onos.net.flow.instructions.Instructions; | 61 | import org.onlab.onos.net.flow.instructions.Instructions; |
62 | +import org.onlab.onos.net.flow.instructions.L0ModificationInstruction; | ||
63 | +import org.onlab.onos.net.flow.instructions.L2ModificationInstruction; | ||
64 | +import org.onlab.onos.net.flow.instructions.L3ModificationInstruction; | ||
62 | import org.onlab.onos.net.host.DefaultHostDescription; | 65 | import org.onlab.onos.net.host.DefaultHostDescription; |
63 | import org.onlab.onos.net.host.HostDescription; | 66 | import org.onlab.onos.net.host.HostDescription; |
64 | import org.onlab.onos.net.intent.ConnectivityIntent; | 67 | import org.onlab.onos.net.intent.ConnectivityIntent; |
... | @@ -66,6 +69,7 @@ import org.onlab.onos.net.intent.HostToHostIntent; | ... | @@ -66,6 +69,7 @@ import org.onlab.onos.net.intent.HostToHostIntent; |
66 | import org.onlab.onos.net.intent.Intent; | 69 | import org.onlab.onos.net.intent.Intent; |
67 | import org.onlab.onos.net.intent.IntentId; | 70 | import org.onlab.onos.net.intent.IntentId; |
68 | import org.onlab.onos.net.intent.IntentState; | 71 | import org.onlab.onos.net.intent.IntentState; |
72 | +import org.onlab.onos.net.intent.LinkCollectionIntent; | ||
69 | import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; | 73 | import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; |
70 | import org.onlab.onos.net.intent.PathIntent; | 74 | import org.onlab.onos.net.intent.PathIntent; |
71 | import org.onlab.onos.net.intent.PointToPointIntent; | 75 | import org.onlab.onos.net.intent.PointToPointIntent; |
... | @@ -115,6 +119,7 @@ public final class KryoNamespaces { | ... | @@ -115,6 +119,7 @@ public final class KryoNamespaces { |
115 | // | 119 | // |
116 | ControllerNode.State.class, | 120 | ControllerNode.State.class, |
117 | Device.Type.class, | 121 | Device.Type.class, |
122 | + Port.Type.class, | ||
118 | ChassisId.class, | 123 | ChassisId.class, |
119 | DefaultAnnotations.class, | 124 | DefaultAnnotations.class, |
120 | DefaultControllerNode.class, | 125 | DefaultControllerNode.class, |
... | @@ -149,6 +154,17 @@ public final class KryoNamespaces { | ... | @@ -149,6 +154,17 @@ public final class KryoNamespaces { |
149 | DefaultTrafficTreatment.class, | 154 | DefaultTrafficTreatment.class, |
150 | Instructions.DropInstruction.class, | 155 | Instructions.DropInstruction.class, |
151 | Instructions.OutputInstruction.class, | 156 | Instructions.OutputInstruction.class, |
157 | + L0ModificationInstruction.class, | ||
158 | + L0ModificationInstruction.L0SubType.class, | ||
159 | + L0ModificationInstruction.ModLambdaInstruction.class, | ||
160 | + L2ModificationInstruction.class, | ||
161 | + L2ModificationInstruction.L2SubType.class, | ||
162 | + L2ModificationInstruction.ModEtherInstruction.class, | ||
163 | + L2ModificationInstruction.ModVlanIdInstruction.class, | ||
164 | + L2ModificationInstruction.ModVlanPcpInstruction.class, | ||
165 | + L3ModificationInstruction.class, | ||
166 | + L3ModificationInstruction.L3SubType.class, | ||
167 | + L3ModificationInstruction.ModIPInstruction.class, | ||
152 | RoleInfo.class, | 168 | RoleInfo.class, |
153 | FlowRuleBatchOperation.class, | 169 | FlowRuleBatchOperation.class, |
154 | CompletedBatchOperation.class, | 170 | CompletedBatchOperation.class, |
... | @@ -163,7 +179,8 @@ public final class KryoNamespaces { | ... | @@ -163,7 +179,8 @@ public final class KryoNamespaces { |
163 | DefaultEdgeLink.class, | 179 | DefaultEdgeLink.class, |
164 | HostToHostIntent.class, | 180 | HostToHostIntent.class, |
165 | PointToPointIntent.class, | 181 | PointToPointIntent.class, |
166 | - MultiPointToSinglePointIntent.class | 182 | + MultiPointToSinglePointIntent.class, |
183 | + LinkCollectionIntent.class | ||
167 | ) | 184 | ) |
168 | .register(DefaultApplicationId.class, new DefaultApplicationIdSerializer()) | 185 | .register(DefaultApplicationId.class, new DefaultApplicationIdSerializer()) |
169 | .register(URI.class, new URISerializer()) | 186 | .register(URI.class, new URISerializer()) | ... | ... |
... | @@ -15,13 +15,10 @@ | ... | @@ -15,13 +15,10 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.store.serializers; | 16 | package org.onlab.onos.store.serializers; |
17 | 17 | ||
18 | -import static org.junit.Assert.assertEquals; | 18 | +import com.google.common.collect.ImmutableList; |
19 | -import static org.onlab.onos.net.DeviceId.deviceId; | 19 | +import com.google.common.collect.ImmutableMap; |
20 | -import static org.onlab.onos.net.PortNumber.portNumber; | 20 | +import com.google.common.collect.ImmutableSet; |
21 | -import static java.util.Arrays.asList; | 21 | +import com.google.common.testing.EqualsTester; |
22 | - | ||
23 | -import java.nio.ByteBuffer; | ||
24 | - | ||
25 | import org.junit.After; | 22 | import org.junit.After; |
26 | import org.junit.Before; | 23 | import org.junit.Before; |
27 | import org.junit.BeforeClass; | 24 | import org.junit.BeforeClass; |
... | @@ -50,10 +47,12 @@ import org.onlab.packet.IpPrefix; | ... | @@ -50,10 +47,12 @@ import org.onlab.packet.IpPrefix; |
50 | import org.onlab.packet.MacAddress; | 47 | import org.onlab.packet.MacAddress; |
51 | import org.onlab.util.KryoNamespace; | 48 | import org.onlab.util.KryoNamespace; |
52 | 49 | ||
53 | -import com.google.common.collect.ImmutableList; | 50 | +import java.nio.ByteBuffer; |
54 | -import com.google.common.collect.ImmutableMap; | 51 | + |
55 | -import com.google.common.collect.ImmutableSet; | 52 | +import static java.util.Arrays.asList; |
56 | -import com.google.common.testing.EqualsTester; | 53 | +import static org.junit.Assert.assertEquals; |
54 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
55 | +import static org.onlab.onos.net.PortNumber.portNumber; | ||
57 | 56 | ||
58 | public class KryoSerializerTest { | 57 | public class KryoSerializerTest { |
59 | 58 | ... | ... |
... | @@ -291,8 +291,9 @@ public class SimpleDeviceStore | ... | @@ -291,8 +291,9 @@ public class SimpleDeviceStore |
291 | Port newPort, | 291 | Port newPort, |
292 | Map<PortNumber, Port> ports) { | 292 | Map<PortNumber, Port> ports) { |
293 | if (oldPort.isEnabled() != newPort.isEnabled() || | 293 | if (oldPort.isEnabled() != newPort.isEnabled() || |
294 | + oldPort.type() != newPort.type() || | ||
295 | + oldPort.portSpeed() != newPort.portSpeed() || | ||
294 | !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) { | 296 | !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) { |
295 | - | ||
296 | ports.put(oldPort.number(), newPort); | 297 | ports.put(oldPort.number(), newPort); |
297 | return new DeviceEvent(PORT_UPDATED, device, newPort); | 298 | return new DeviceEvent(PORT_UPDATED, device, newPort); |
298 | } | 299 | } |
... | @@ -510,7 +511,10 @@ public class SimpleDeviceStore | ... | @@ -510,7 +511,10 @@ public class SimpleDeviceStore |
510 | } | 511 | } |
511 | } | 512 | } |
512 | 513 | ||
513 | - return new DefaultPort(device, number, isEnabled, annotations); | 514 | + return portDesc == null ? |
515 | + new DefaultPort(device, number, false, annotations) : | ||
516 | + new DefaultPort(device, number, isEnabled, portDesc.type(), | ||
517 | + portDesc.portSpeed(), annotations); | ||
514 | } | 518 | } |
515 | 519 | ||
516 | /** | 520 | /** | ... | ... |
core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleLinkResourceStore.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2014 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onlab.onos.store.trivial.impl; | ||
17 | + | ||
18 | +import static com.google.common.base.Preconditions.*; | ||
19 | +import static org.slf4j.LoggerFactory.getLogger; | ||
20 | + | ||
21 | +import java.util.Collections; | ||
22 | +import java.util.HashMap; | ||
23 | +import java.util.HashSet; | ||
24 | +import java.util.Map; | ||
25 | +import java.util.Set; | ||
26 | + | ||
27 | +import org.apache.felix.scr.annotations.Activate; | ||
28 | +import org.apache.felix.scr.annotations.Component; | ||
29 | +import org.apache.felix.scr.annotations.Deactivate; | ||
30 | +import org.apache.felix.scr.annotations.Service; | ||
31 | +import org.onlab.onos.net.Link; | ||
32 | +import org.onlab.onos.net.intent.IntentId; | ||
33 | +import org.onlab.onos.net.resource.Bandwidth; | ||
34 | +import org.onlab.onos.net.resource.BandwidthResourceAllocation; | ||
35 | +import org.onlab.onos.net.resource.Lambda; | ||
36 | +import org.onlab.onos.net.resource.LambdaResourceAllocation; | ||
37 | +import org.onlab.onos.net.resource.LinkResourceAllocations; | ||
38 | +import org.onlab.onos.net.resource.LinkResourceStore; | ||
39 | +import org.onlab.onos.net.resource.ResourceAllocation; | ||
40 | +import org.onlab.onos.net.resource.ResourceType; | ||
41 | +import org.slf4j.Logger; | ||
42 | + | ||
43 | +/** | ||
44 | + * Manages link resources using trivial in-memory structures implementation. | ||
45 | + */ | ||
46 | +@Component(immediate = true) | ||
47 | +@Service | ||
48 | +public class SimpleLinkResourceStore implements LinkResourceStore { | ||
49 | + private final Logger log = getLogger(getClass()); | ||
50 | + private Map<IntentId, LinkResourceAllocations> linkResourceAllocationsMap; | ||
51 | + private Map<Link, Set<LinkResourceAllocations>> allocatedResources; | ||
52 | + private Map<Link, Set<ResourceAllocation>> freeResources; | ||
53 | + | ||
54 | + @Activate | ||
55 | + public void activate() { | ||
56 | + linkResourceAllocationsMap = new HashMap<>(); | ||
57 | + allocatedResources = new HashMap<>(); | ||
58 | + freeResources = new HashMap<>(); | ||
59 | + | ||
60 | + log.info("Started"); | ||
61 | + } | ||
62 | + | ||
63 | + @Deactivate | ||
64 | + public void deactivate() { | ||
65 | + log.info("Stopped"); | ||
66 | + } | ||
67 | + | ||
68 | + private Set<ResourceAllocation> readOriginalFreeResources(Link link) { | ||
69 | + // TODO read capacity and lambda resources from topology | ||
70 | + Set<ResourceAllocation> allocations = new HashSet<>(); | ||
71 | + for (int i = 1; i <= 100; i++) { | ||
72 | + allocations.add(new LambdaResourceAllocation(Lambda.valueOf(i))); | ||
73 | + } | ||
74 | + allocations.add(new BandwidthResourceAllocation(Bandwidth.valueOf(1000000))); | ||
75 | + return allocations; | ||
76 | + } | ||
77 | + | ||
78 | + private BandwidthResourceAllocation getBandwidth(Set<ResourceAllocation> freeRes) { | ||
79 | + for (ResourceAllocation res : freeRes) { | ||
80 | + if (res.type() == ResourceType.BANDWIDTH) { | ||
81 | + return (BandwidthResourceAllocation) res; | ||
82 | + } | ||
83 | + } | ||
84 | + return new BandwidthResourceAllocation(Bandwidth.valueOf(0)); | ||
85 | + } | ||
86 | + | ||
87 | + private void subtractFreeResources(Link link, LinkResourceAllocations allocations) { | ||
88 | + // TODO Use lock or version for updating freeResources. | ||
89 | + checkNotNull(link); | ||
90 | + Set<ResourceAllocation> freeRes = freeResources.get(link); | ||
91 | + checkNotNull(freeRes); | ||
92 | + freeRes = new HashSet<>(freeRes); | ||
93 | + Set<ResourceAllocation> subRes = allocations.getResourceAllocation(link); | ||
94 | + for (ResourceAllocation res : subRes) { | ||
95 | + switch (res.type()) { | ||
96 | + case BANDWIDTH: | ||
97 | + BandwidthResourceAllocation ba = getBandwidth(freeRes); | ||
98 | + double requestedBandwidth = | ||
99 | + ((BandwidthResourceAllocation) res).bandwidth().toDouble(); | ||
100 | + double newBandwidth = ba.bandwidth().toDouble() - requestedBandwidth; | ||
101 | + checkState(newBandwidth >= 0.0); | ||
102 | + freeRes.remove(ba); | ||
103 | + freeRes.add(new BandwidthResourceAllocation( | ||
104 | + Bandwidth.valueOf(newBandwidth))); | ||
105 | + break; | ||
106 | + case LAMBDA: | ||
107 | + checkState(freeRes.remove(res)); | ||
108 | + break; | ||
109 | + default: | ||
110 | + break; | ||
111 | + } | ||
112 | + } | ||
113 | + freeResources.put(link, freeRes); | ||
114 | + | ||
115 | + } | ||
116 | + | ||
117 | + private void addFreeResources(Link link, LinkResourceAllocations allocations) { | ||
118 | + // TODO Use lock or version for updating freeResources. | ||
119 | + Set<ResourceAllocation> freeRes = freeResources.get(link); | ||
120 | + checkNotNull(freeRes); | ||
121 | + freeRes = new HashSet<>(freeRes); | ||
122 | + Set<ResourceAllocation> addRes = allocations.getResourceAllocation(link); | ||
123 | + for (ResourceAllocation res : addRes) { | ||
124 | + switch (res.type()) { | ||
125 | + case BANDWIDTH: | ||
126 | + BandwidthResourceAllocation ba = getBandwidth(freeRes); | ||
127 | + double requestedBandwidth = | ||
128 | + ((BandwidthResourceAllocation) res).bandwidth().toDouble(); | ||
129 | + double newBandwidth = ba.bandwidth().toDouble() + requestedBandwidth; | ||
130 | + freeRes.remove(ba); | ||
131 | + freeRes.add(new BandwidthResourceAllocation( | ||
132 | + Bandwidth.valueOf(newBandwidth))); | ||
133 | + break; | ||
134 | + case LAMBDA: | ||
135 | + checkState(freeRes.add(res)); | ||
136 | + break; | ||
137 | + default: | ||
138 | + break; | ||
139 | + } | ||
140 | + } | ||
141 | + freeResources.put(link, freeRes); | ||
142 | + } | ||
143 | + | ||
144 | + @Override | ||
145 | + public Set<ResourceAllocation> getFreeResources(Link link) { | ||
146 | + checkNotNull(link); | ||
147 | + Set<ResourceAllocation> freeRes = freeResources.get(link); | ||
148 | + if (freeRes == null) { | ||
149 | + freeRes = readOriginalFreeResources(link); | ||
150 | + } | ||
151 | + | ||
152 | + return freeRes; | ||
153 | + } | ||
154 | + | ||
155 | + @Override | ||
156 | + public void allocateResources(LinkResourceAllocations allocations) { | ||
157 | + checkNotNull(allocations); | ||
158 | + linkResourceAllocationsMap.put(allocations.intendId(), allocations); | ||
159 | + for (Link link : allocations.links()) { | ||
160 | + subtractFreeResources(link, allocations); | ||
161 | + Set<LinkResourceAllocations> linkAllocs = allocatedResources.get(link); | ||
162 | + if (linkAllocs == null) { | ||
163 | + linkAllocs = new HashSet<>(); | ||
164 | + } | ||
165 | + linkAllocs.add(allocations); | ||
166 | + allocatedResources.put(link, linkAllocs); | ||
167 | + } | ||
168 | + } | ||
169 | + | ||
170 | + @Override | ||
171 | + public void releaseResources(LinkResourceAllocations allocations) { | ||
172 | + checkNotNull(allocations); | ||
173 | + linkResourceAllocationsMap.remove(allocations); | ||
174 | + for (Link link : allocations.links()) { | ||
175 | + addFreeResources(link, allocations); | ||
176 | + Set<LinkResourceAllocations> linkAllocs = allocatedResources.get(link); | ||
177 | + if (linkAllocs == null) { | ||
178 | + log.error("Missing resource allocation."); | ||
179 | + } else { | ||
180 | + linkAllocs.remove(allocations); | ||
181 | + } | ||
182 | + allocatedResources.put(link, linkAllocs); | ||
183 | + } | ||
184 | + } | ||
185 | + | ||
186 | + @Override | ||
187 | + public LinkResourceAllocations getAllocations(IntentId intentId) { | ||
188 | + checkNotNull(intentId); | ||
189 | + return linkResourceAllocationsMap.get(intentId); | ||
190 | + } | ||
191 | + | ||
192 | + @Override | ||
193 | + public Iterable<LinkResourceAllocations> getAllocations(Link link) { | ||
194 | + checkNotNull(link); | ||
195 | + Set<LinkResourceAllocations> result = allocatedResources.get(link); | ||
196 | + if (result == null) { | ||
197 | + result = Collections.emptySet(); | ||
198 | + } | ||
199 | + return Collections.unmodifiableSet(result); | ||
200 | + } | ||
201 | + | ||
202 | + @Override | ||
203 | + public Iterable<LinkResourceAllocations> getAllocations() { | ||
204 | + return Collections.unmodifiableCollection(linkResourceAllocationsMap.values()); | ||
205 | + } | ||
206 | + | ||
207 | +} |
... | @@ -15,6 +15,22 @@ | ... | @@ -15,6 +15,22 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.provider.lldp.impl; | 16 | package org.onlab.onos.provider.lldp.impl; |
17 | 17 | ||
18 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
19 | +import static java.util.concurrent.TimeUnit.MILLISECONDS; | ||
20 | +import static org.onlab.onos.net.MastershipRole.MASTER; | ||
21 | +import static org.onlab.onos.net.PortNumber.portNumber; | ||
22 | +import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder; | ||
23 | +import static org.slf4j.LoggerFactory.getLogger; | ||
24 | + | ||
25 | +import java.nio.ByteBuffer; | ||
26 | +import java.util.Collections; | ||
27 | +import java.util.HashMap; | ||
28 | +import java.util.HashSet; | ||
29 | +import java.util.Iterator; | ||
30 | +import java.util.Map; | ||
31 | +import java.util.Set; | ||
32 | +import java.util.concurrent.atomic.AtomicInteger; | ||
33 | + | ||
18 | import org.jboss.netty.util.Timeout; | 34 | import org.jboss.netty.util.Timeout; |
19 | import org.jboss.netty.util.TimerTask; | 35 | import org.jboss.netty.util.TimerTask; |
20 | import org.onlab.onos.mastership.MastershipService; | 36 | import org.onlab.onos.mastership.MastershipService; |
... | @@ -36,22 +52,6 @@ import org.onlab.packet.ONOSLLDP; | ... | @@ -36,22 +52,6 @@ import org.onlab.packet.ONOSLLDP; |
36 | import org.onlab.util.Timer; | 52 | import org.onlab.util.Timer; |
37 | import org.slf4j.Logger; | 53 | import org.slf4j.Logger; |
38 | 54 | ||
39 | -import java.nio.ByteBuffer; | ||
40 | -import java.util.Collections; | ||
41 | -import java.util.HashMap; | ||
42 | -import java.util.HashSet; | ||
43 | -import java.util.Iterator; | ||
44 | -import java.util.Map; | ||
45 | -import java.util.Set; | ||
46 | -import java.util.concurrent.atomic.AtomicInteger; | ||
47 | - | ||
48 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
49 | -import static java.util.concurrent.TimeUnit.MILLISECONDS; | ||
50 | -import static org.onlab.onos.net.MastershipRole.MASTER; | ||
51 | -import static org.onlab.onos.net.PortNumber.portNumber; | ||
52 | -import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder; | ||
53 | -import static org.slf4j.LoggerFactory.getLogger; | ||
54 | - | ||
55 | /** | 55 | /** |
56 | * Run discovery process from a physical switch. Ports are initially labeled as | 56 | * Run discovery process from a physical switch. Ports are initially labeled as |
57 | * slow ports. When an LLDP is successfully received, label the remote port as | 57 | * slow ports. When an LLDP is successfully received, label the remote port as |
... | @@ -336,7 +336,7 @@ public class LinkDiscovery implements TimerTask { | ... | @@ -336,7 +336,7 @@ public class LinkDiscovery implements TimerTask { |
336 | private void sendProbes(Long portNumber) { | 336 | private void sendProbes(Long portNumber) { |
337 | // TODO: should have suppression port configuration, not by type | 337 | // TODO: should have suppression port configuration, not by type |
338 | if (device.type() != Device.Type.ROADM) { | 338 | if (device.type() != Device.Type.ROADM) { |
339 | - log.debug("Sending probes out to {}@{}", portNumber, device.id()); | 339 | + log.trace("Sending probes out to {}@{}", portNumber, device.id()); |
340 | OutboundPacket pkt = this.createOutBoundLLDP(portNumber); | 340 | OutboundPacket pkt = this.createOutBoundLLDP(portNumber); |
341 | pktService.emit(pkt); | 341 | pktService.emit(pkt); |
342 | if (useBDDP) { | 342 | if (useBDDP) { | ... | ... |
... | @@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; | ... | @@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; |
23 | import org.onlab.onos.net.Device; | 23 | import org.onlab.onos.net.Device; |
24 | import org.onlab.onos.net.DeviceId; | 24 | import org.onlab.onos.net.DeviceId; |
25 | import org.onlab.onos.net.MastershipRole; | 25 | import org.onlab.onos.net.MastershipRole; |
26 | +import org.onlab.onos.net.Port; | ||
26 | import org.onlab.onos.net.PortNumber; | 27 | import org.onlab.onos.net.PortNumber; |
27 | import org.onlab.onos.net.device.DefaultDeviceDescription; | 28 | import org.onlab.onos.net.device.DefaultDeviceDescription; |
28 | import org.onlab.onos.net.device.DefaultPortDescription; | 29 | import org.onlab.onos.net.device.DefaultPortDescription; |
... | @@ -43,14 +44,19 @@ import org.onlab.packet.ChassisId; | ... | @@ -43,14 +44,19 @@ import org.onlab.packet.ChassisId; |
43 | import org.projectfloodlight.openflow.protocol.OFFactory; | 44 | import org.projectfloodlight.openflow.protocol.OFFactory; |
44 | import org.projectfloodlight.openflow.protocol.OFPortConfig; | 45 | import org.projectfloodlight.openflow.protocol.OFPortConfig; |
45 | import org.projectfloodlight.openflow.protocol.OFPortDesc; | 46 | import org.projectfloodlight.openflow.protocol.OFPortDesc; |
47 | +import org.projectfloodlight.openflow.protocol.OFPortFeatures; | ||
46 | import org.projectfloodlight.openflow.protocol.OFPortState; | 48 | import org.projectfloodlight.openflow.protocol.OFPortState; |
47 | import org.projectfloodlight.openflow.protocol.OFPortStatus; | 49 | import org.projectfloodlight.openflow.protocol.OFPortStatus; |
50 | +import org.projectfloodlight.openflow.protocol.OFVersion; | ||
51 | +import org.projectfloodlight.openflow.types.PortSpeed; | ||
48 | import org.slf4j.Logger; | 52 | import org.slf4j.Logger; |
49 | 53 | ||
50 | import java.util.ArrayList; | 54 | import java.util.ArrayList; |
51 | import java.util.List; | 55 | import java.util.List; |
52 | 56 | ||
53 | import static org.onlab.onos.net.DeviceId.deviceId; | 57 | import static org.onlab.onos.net.DeviceId.deviceId; |
58 | +import static org.onlab.onos.net.Port.Type.COPPER; | ||
59 | +import static org.onlab.onos.net.Port.Type.FIBER; | ||
54 | import static org.onlab.onos.openflow.controller.Dpid.dpid; | 60 | import static org.onlab.onos.openflow.controller.Dpid.dpid; |
55 | import static org.onlab.onos.openflow.controller.Dpid.uri; | 61 | import static org.onlab.onos.openflow.controller.Dpid.uri; |
56 | import static org.slf4j.LoggerFactory.getLogger; | 62 | import static org.slf4j.LoggerFactory.getLogger; |
... | @@ -63,6 +69,7 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -63,6 +69,7 @@ import static org.slf4j.LoggerFactory.getLogger; |
63 | public class OpenFlowDeviceProvider extends AbstractProvider implements DeviceProvider { | 69 | public class OpenFlowDeviceProvider extends AbstractProvider implements DeviceProvider { |
64 | 70 | ||
65 | private static final Logger LOG = getLogger(OpenFlowDeviceProvider.class); | 71 | private static final Logger LOG = getLogger(OpenFlowDeviceProvider.class); |
72 | + private static final long MBPS = 1_000 * 1_000; | ||
66 | 73 | ||
67 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 74 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
68 | protected DeviceProviderRegistry providerRegistry; | 75 | protected DeviceProviderRegistry providerRegistry; |
... | @@ -122,9 +129,9 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr | ... | @@ -122,9 +129,9 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr |
122 | 129 | ||
123 | OpenFlowSwitch sw = controller.getSwitch(dpid(device.id().uri())); | 130 | OpenFlowSwitch sw = controller.getSwitch(dpid(device.id().uri())); |
124 | //if (!checkChannel(device, sw)) { | 131 | //if (!checkChannel(device, sw)) { |
125 | - // LOG.error("Failed to probe device {} on sw={}", device, sw); | 132 | + // LOG.error("Failed to probe device {} on sw={}", device, sw); |
126 | // providerService.deviceDisconnected(device.id()); | 133 | // providerService.deviceDisconnected(device.id()); |
127 | - //return; | 134 | + //return; |
128 | //} | 135 | //} |
129 | 136 | ||
130 | // Prompt an update of port information. We can use any XID for this. | 137 | // Prompt an update of port information. We can use any XID for this. |
... | @@ -143,13 +150,13 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr | ... | @@ -143,13 +150,13 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr |
143 | 150 | ||
144 | // Checks if the OF channel is connected. | 151 | // Checks if the OF channel is connected. |
145 | //private boolean checkChannel(Device device, OpenFlowSwitch sw) { | 152 | //private boolean checkChannel(Device device, OpenFlowSwitch sw) { |
146 | - // FIXME if possible, we might want this to be part of | 153 | + // FIXME if possible, we might want this to be part of |
147 | - // OpenFlowSwitch interface so the driver interface isn't misused. | 154 | + // OpenFlowSwitch interface so the driver interface isn't misused. |
148 | // if (sw == null || !((OpenFlowSwitchDriver) sw).isConnected()) { | 155 | // if (sw == null || !((OpenFlowSwitchDriver) sw).isConnected()) { |
149 | - // return false; | 156 | + // return false; |
150 | - // } | 157 | + // } |
151 | // return true; | 158 | // return true; |
152 | - // } | 159 | + // } |
153 | 160 | ||
154 | @Override | 161 | @Override |
155 | public void roleChanged(Device device, MastershipRole newRole) { | 162 | public void roleChanged(Device device, MastershipRole newRole) { |
... | @@ -188,7 +195,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr | ... | @@ -188,7 +195,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr |
188 | sw.hardwareDescription(), | 195 | sw.hardwareDescription(), |
189 | sw.softwareDescription(), | 196 | sw.softwareDescription(), |
190 | sw.serialNumber(), | 197 | sw.serialNumber(), |
191 | - cId); | 198 | + cId); |
192 | providerService.deviceConnected(did, description); | 199 | providerService.deviceConnected(did, description); |
193 | providerService.updatePorts(did, buildPortDescriptions(sw.getPorts())); | 200 | providerService.updatePorts(did, buildPortDescriptions(sw.getPorts())); |
194 | } | 201 | } |
... | @@ -244,8 +251,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr | ... | @@ -244,8 +251,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr |
244 | * @param ports the list of ports | 251 | * @param ports the list of ports |
245 | * @return list of portdescriptions | 252 | * @return list of portdescriptions |
246 | */ | 253 | */ |
247 | - private List<PortDescription> buildPortDescriptions( | 254 | + private List<PortDescription> buildPortDescriptions(List<OFPortDesc> ports) { |
248 | - List<OFPortDesc> ports) { | ||
249 | final List<PortDescription> portDescs = new ArrayList<>(ports.size()); | 255 | final List<PortDescription> portDescs = new ArrayList<>(ports.size()); |
250 | for (OFPortDesc port : ports) { | 256 | for (OFPortDesc port : ports) { |
251 | portDescs.add(buildPortDescription(port)); | 257 | portDescs.add(buildPortDescription(port)); |
... | @@ -260,12 +266,25 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr | ... | @@ -260,12 +266,25 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr |
260 | * @return portDescription for the port. | 266 | * @return portDescription for the port. |
261 | */ | 267 | */ |
262 | private PortDescription buildPortDescription(OFPortDesc port) { | 268 | private PortDescription buildPortDescription(OFPortDesc port) { |
263 | - final PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber()); | 269 | + PortNumber portNo = PortNumber.portNumber(port.getPortNo().getPortNumber()); |
264 | - final boolean enabled = !port.getState().contains(OFPortState.LINK_DOWN) && | 270 | + boolean enabled = |
265 | - !port.getConfig().contains(OFPortConfig.PORT_DOWN); | 271 | + !port.getState().contains(OFPortState.LINK_DOWN) && |
266 | - return new DefaultPortDescription(portNo, enabled); | 272 | + !port.getConfig().contains(OFPortConfig.PORT_DOWN); |
273 | + Port.Type type = port.getCurr().contains(OFPortFeatures.PF_FIBER) ? FIBER : COPPER; | ||
274 | + return new DefaultPortDescription(portNo, enabled, type, portSpeed(port)); | ||
267 | } | 275 | } |
268 | 276 | ||
277 | + private long portSpeed(OFPortDesc port) { | ||
278 | + if (port.getVersion() == OFVersion.OF_13) { | ||
279 | + return port.getCurrSpeed() / MBPS; | ||
280 | + } | ||
281 | + | ||
282 | + PortSpeed portSpeed = PortSpeed.SPEED_NONE; | ||
283 | + for (OFPortFeatures feat : port.getCurr()) { | ||
284 | + portSpeed = PortSpeed.max(portSpeed, feat.getPortSpeed()); | ||
285 | + } | ||
286 | + return portSpeed.getSpeedBps() / MBPS; | ||
287 | + } | ||
269 | } | 288 | } |
270 | 289 | ||
271 | } | 290 | } | ... | ... |
... | @@ -6,4 +6,4 @@ | ... | @@ -6,4 +6,4 @@ |
6 | [ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1 | 6 | [ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1 |
7 | . $ONOS_ROOT/tools/build/envDefaults | 7 | . $ONOS_ROOT/tools/build/envDefaults |
8 | 8 | ||
9 | -cd $ONOS_ROOT && mvn clean install && cd docs && mvn javadoc:aggregate | 9 | +cd $ONOS_ROOT && mvn clean install "$@" && cd docs && mvn javadoc:aggregate | ... | ... |
... | @@ -34,6 +34,7 @@ alias mci='mvn clean install' | ... | @@ -34,6 +34,7 @@ alias mci='mvn clean install' |
34 | 34 | ||
35 | # Short-hand for ONOS build, package and test. | 35 | # Short-hand for ONOS build, package and test. |
36 | alias ob='onos-build' | 36 | alias ob='onos-build' |
37 | +alias obi='onos-build -Dmaven.test.failure.ignore=true' | ||
37 | alias obs='onos-build-selective' | 38 | alias obs='onos-build-selective' |
38 | alias op='onos-package' | 39 | alias op='onos-package' |
39 | alias ot='onos-test' | 40 | alias ot='onos-test' | ... | ... |
1 | # Local VirtualBox-based single ONOS instance & ONOS mininet box | 1 | # Local VirtualBox-based single ONOS instance & ONOS mininet box |
2 | 2 | ||
3 | -export ONOS_CELL="cbench" | ||
4 | - | ||
5 | export ONOS_NIC=192.168.56.* | 3 | export ONOS_NIC=192.168.56.* |
6 | export OC1="192.168.56.103" | 4 | export OC1="192.168.56.103" |
7 | export OCN="192.168.56.103" | 5 | export OCN="192.168.56.103" | ... | ... |
1 | # Local VirtualBox-based ONOS instances 1,2 & ONOS mininet box | 1 | # Local VirtualBox-based ONOS instances 1,2 & ONOS mininet box |
2 | 2 | ||
3 | -export ONOS_CELL="local" | ||
4 | - | ||
5 | export ONOS_NIC=192.168.56.* | 3 | export ONOS_NIC=192.168.56.* |
6 | export OC1="192.168.56.101" | 4 | export OC1="192.168.56.101" |
7 | export OC2="192.168.56.102" | 5 | export OC2="192.168.56.102" | ... | ... |
1 | # ProxMox-based cell of ONOS instance; no mininet-box | 1 | # ProxMox-based cell of ONOS instance; no mininet-box |
2 | 2 | ||
3 | -export ONOS_CELL="office" | ||
4 | - | ||
5 | export ONOS_NIC="10.1.10.*" | 3 | export ONOS_NIC="10.1.10.*" |
6 | export OC1="10.1.10.223" | 4 | export OC1="10.1.10.223" |
7 | export OCI="${OC1}" | 5 | export OCI="${OC1}" | ... | ... |
1 | # ProxMox-based cell of ONOS instances 1,2 & ONOS mininet box | 1 | # ProxMox-based cell of ONOS instances 1,2 & ONOS mininet box |
2 | 2 | ||
3 | -export ONOS_CELL="prox" | ||
4 | - | ||
5 | export ONOS_NIC="10.1.9.*" | 3 | export ONOS_NIC="10.1.9.*" |
6 | export OC1="10.1.9.94" | 4 | export OC1="10.1.9.94" |
7 | export OC2="10.1.9.82" | 5 | export OC2="10.1.9.82" | ... | ... |
1 | # Local VirtualBox-based single ONOS instance & ONOS mininet box | 1 | # Local VirtualBox-based single ONOS instance & ONOS mininet box |
2 | 2 | ||
3 | -export ONOS_CELL="single" | ||
4 | - | ||
5 | export ONOS_NIC=192.168.56.* | 3 | export ONOS_NIC=192.168.56.* |
6 | export OC1="192.168.56.101" | 4 | export OC1="192.168.56.101" |
7 | export OCN="192.168.56.103" | 5 | export OCN="192.168.56.103" | ... | ... |
1 | # Local VirtualBox-based ONOS instances 1,2,3 & ONOS mininet box | 1 | # Local VirtualBox-based ONOS instances 1,2,3 & ONOS mininet box |
2 | 2 | ||
3 | -export ONOS_CELL="triple" | ||
4 | - | ||
5 | export ONOS_NIC=192.168.56.* | 3 | export ONOS_NIC=192.168.56.* |
6 | export OC1="192.168.56.101" | 4 | export OC1="192.168.56.101" |
7 | export OC2="192.168.56.102" | 5 | export OC2="192.168.56.102" | ... | ... |
... | @@ -3,28 +3,33 @@ | ... | @@ -3,28 +3,33 @@ |
3 | { | 3 | { |
4 | "uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM", | 4 | "uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM", |
5 | "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM1", | 5 | "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM1", |
6 | - "annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 } | 6 | + "annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 }, |
7 | + "ports": [ { "port": 10, "speed": 100000, "type": "FIBER" }, { "port": 20, "speed": 0, "type": "FIBER" } ] | ||
7 | }, | 8 | }, |
8 | { | 9 | { |
9 | "uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM", | 10 | "uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM", |
10 | "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM2", | 11 | "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM2", |
11 | - "annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 } | 12 | + "annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 }, |
13 | + "ports": [ { "port": 11, "speed": 100000, "type": "FIBER" }, { "port": 21, "speed": 0, "type": "FIBER" } ] | ||
12 | }, | 14 | }, |
13 | { | 15 | { |
14 | "uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM", | 16 | "uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM", |
15 | "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM3", | 17 | "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM3", |
16 | - "annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 2 } | 18 | + "annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 2 }, |
19 | + "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ] | ||
17 | }, | 20 | }, |
18 | 21 | ||
19 | { | 22 | { |
20 | - "uri": "of:0000ffffffff0001", "mac": "ffffffffff0003", "type": "SWITCH", | 23 | + "uri": "of:0000ffffffff0001", "mac": "ffffffffff0001", "type": "SWITCH", |
21 | "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ROUTER1", | 24 | "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ROUTER1", |
22 | - "annotations": { "latitude": 37.6, "longitude": 122.3 } | 25 | + "annotations": { "latitude": 37.6, "longitude": 122.3 }, |
26 | + "ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ] | ||
23 | }, | 27 | }, |
24 | { | 28 | { |
25 | "uri": "of:0000ffffffff0002", "mac": "ffffffffff0002", "type": "SWITCH", | 29 | "uri": "of:0000ffffffff0002", "mac": "ffffffffff0002", "type": "SWITCH", |
26 | "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ROUTER2", | 30 | "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ROUTER2", |
27 | - "annotations": { "latitude": 37.3, "longitude": 121.9 } | 31 | + "annotations": { "latitude": 37.3, "longitude": 121.9 }, |
32 | + "ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ] | ||
28 | } | 33 | } |
29 | ], | 34 | ], |
30 | 35 | ||
... | @@ -36,10 +41,8 @@ | ... | @@ -36,10 +41,8 @@ |
36 | { "src": "of:0000ffffffff0002/2", "dst": "of:0000ffffffffff02/11", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } } | 41 | { "src": "of:0000ffffffff0002/2", "dst": "of:0000ffffffffff02/11", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } } |
37 | ], | 42 | ], |
38 | 43 | ||
39 | - "Xhosts" : [ | 44 | + "hosts" : [ |
40 | - { "mac": "a0:00:00:00:00:11", "vlan": -1, "location": "of:0000ffffffff0001/11", "ip": "1.2.3.4" }, | 45 | + { "mac": "00:00:00:00:00:01", "vlan": -1, "location": "of:0000ffffffff0001/1", "ip": "10.0.0.1" }, |
41 | - { "mac": "a0:00:00:00:00:12", "vlan": -1, "location": "of:0000ffffffff0001/12", "ip": "1.2.3.5" }, | 46 | + { "mac": "00:00:00:00:00:02", "vlan": -1, "location": "of:0000ffffffff0002/1", "ip": "10.0.0.2" } |
42 | - { "mac": "a0:00:00:00:00:21", "vlan": -1, "location": "of:0000ffffffff0002/11", "ip": "2.2.3.4" }, | ||
43 | - { "mac": "a0:00:00:00:00:22", "vlan": -1, "location": "of:0000ffffffff0002/12", "ip": "2.2.3.5" } | ||
44 | ] | 47 | ] |
45 | } | 48 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
tools/test/topos/oe-nonlinear-10.json
0 → 100644
1 | +{ | ||
2 | + "devices" : [ | ||
3 | + { | ||
4 | + "uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM", | ||
5 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "SFO-W10", | ||
6 | + "annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 }, | ||
7 | + "ports": [ { "port": 10, "speed": 100000, "type": "FIBER" }, { "port": 20, "speed": 0, "type": "FIBER" } ] | ||
8 | + }, | ||
9 | + { | ||
10 | + "uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM", | ||
11 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "SJC-W10", | ||
12 | + "annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 }, | ||
13 | + "ports": [ { "port": 11, "speed": 100000, "type": "FIBER" }, { "port": 21, "speed": 0, "type": "FIBER" } ] | ||
14 | + }, | ||
15 | + { | ||
16 | + "uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM", | ||
17 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "LAX-W10", | ||
18 | + "annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 0 }, | ||
19 | + "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ] | ||
20 | + }, | ||
21 | + { | ||
22 | + "uri": "of:0000ffffffffff04", "mac": "ffffffffffff04", "type": "ROADM", | ||
23 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "SDG-W10", | ||
24 | + "annotations": { "latitude": 32.8, "longitude": 117.1, "optical.regens": 3 }, | ||
25 | + "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ] | ||
26 | + }, | ||
27 | + { | ||
28 | + "uri": "of:0000ffffffffff05", "mac": "ffffffffffff05", "type": "ROADM", | ||
29 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "MSP-M10", | ||
30 | + "annotations": { "latitude": 44.8, "longitude": 93.1, "optical.regens": 3 }, | ||
31 | + "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ] | ||
32 | + }, | ||
33 | + { | ||
34 | + "uri": "of:0000ffffffffff06", "mac": "ffffffffffff06", "type": "ROADM", | ||
35 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "DFW-M10", | ||
36 | + "annotations": { "latitude": 32.8, "longitude": 97.1, "optical.regens": 3 }, | ||
37 | + "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ] | ||
38 | + }, | ||
39 | + { | ||
40 | + "uri": "of:0000ffffffffff07", "mac": "ffffffffffff07", "type": "ROADM", | ||
41 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "CHG-N10", | ||
42 | + "annotations": { "latitude": 41.8, "longitude": 120.1, "optical.regens": 3 }, | ||
43 | + "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ] | ||
44 | + }, | ||
45 | + { | ||
46 | + "uri": "of:0000ffffffffff08", "mac": "ffffffffffff08", "type": "ROADM", | ||
47 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "IAD-M10", | ||
48 | + "annotations": { "latitude": 38.8, "longitude": 77.1, "optical.regens": 3 }, | ||
49 | + "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ] | ||
50 | + }, | ||
51 | + { | ||
52 | + "uri": "of:0000ffffffffff09", "mac": "ffffffffffff09", "type": "ROADM", | ||
53 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "JFK-M10", | ||
54 | + "annotations": { "latitude": 40.8, "longitude": 73.1, "optical.regens": 0 }, | ||
55 | + "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ] | ||
56 | + }, | ||
57 | + { | ||
58 | + "uri": "of:0000ffffffffff0A", "mac": "ffffffffffff0A", "type": "ROADM", | ||
59 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ATL-S10", | ||
60 | + "annotations": { "latitude": 33.8, "longitude": 84.1, "optical.regens": 0 }, | ||
61 | + "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ] | ||
62 | + }, | ||
63 | + { | ||
64 | + "uri": "of:0000ffffffffff06", "mac": "ffffffffffff06", "type": "ROADM", | ||
65 | + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "DFW-M10", | ||
66 | + "annotations": { "latitude": 32.8, "longitude": 97.1, "optical.regens": 3 }, | ||
67 | + "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ] | ||
68 | + }, | ||
69 | + | ||
70 | + | ||
71 | + { | ||
72 | + "uri": "of:0000ffffffff0001", "mac": "ffffffffff0001", "type": "SWITCH", | ||
73 | + "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "SFO-R10", | ||
74 | + "annotations": { "latitude": 37.6, "longitude": 122.3 }, | ||
75 | + "ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ] | ||
76 | + }, | ||
77 | + { | ||
78 | + "uri": "of:0000ffffffff0003", "mac": "ffffffffff0003", "type": "SWITCH", | ||
79 | + "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "LAX-R10", | ||
80 | + "annotations": { "latitude": 33.9, "longitude": 118.4 }, | ||
81 | + "ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ] | ||
82 | + }, | ||
83 | + { | ||
84 | + "uri": "of:0000ffffffff0004", "mac": "ffffffffff0004", "type": "SWITCH", | ||
85 | + "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "SDG-R10", | ||
86 | + "annotations": { "latitude": 32.8, "longitude": 117.1 }, | ||
87 | + "ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ] | ||
88 | + }, | ||
89 | + { | ||
90 | + "uri": "of:0000ffffffff0007", "mac": "ffffffffff0007", "type": "SWITCH", | ||
91 | + "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "CHG-R10", | ||
92 | + "annotations": { "latitude": 41.8, "longitude": 120.1 }, | ||
93 | + "ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ] | ||
94 | + }, | ||
95 | + { | ||
96 | + "uri": "of:0000ffffffff0009", "mac": "ffffffffff0009", "type": "SWITCH", | ||
97 | + "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "JFK-R10", | ||
98 | + "annotations": { "latitude": 40.8, "longitude": 73.1 }, | ||
99 | + "ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ] | ||
100 | + }, | ||
101 | + { | ||
102 | + "uri": "of:0000ffffffff000A", "mac": "ffffffffff000A", "type": "SWITCH", | ||
103 | + "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ATL-R10", | ||
104 | + "annotations": { "latitude": 33.8, "longitude": 84.1 }, | ||
105 | + "ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ] | ||
106 | + } | ||
107 | + | ||
108 | + ], | ||
109 | + | ||
110 | + "links" : [ | ||
111 | + { "src": "of:0000ffffffffff01/10", "dst": "of:0000ffffffffff02/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
112 | + { "src": "of:0000ffffffffff02/10", "dst": "of:0000ffffffffff03/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
113 | + { "src": "of:0000ffffffffff03/30", "dst": "of:0000ffffffffff04/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
114 | + { "src": "of:0000ffffffffff02/20", "dst": "of:0000ffffffffff05/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
115 | + { "src": "of:0000ffffffffff03/20", "dst": "of:0000ffffffffff06/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
116 | + { "src": "of:0000ffffffffff05/30", "dst": "of:0000ffffffffff06/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
117 | + { "src": "of:0000ffffffffff05/20", "dst": "of:0000ffffffffff07/21", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
118 | + { "src": "of:0000ffffffffff06/30", "dst": "of:0000ffffffffff08/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
119 | + { "src": "of:0000ffffffffff07/30", "dst": "of:0000ffffffffff08/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
120 | + { "src": "of:0000ffffffffff07/20", "dst": "of:0000ffffffffff09/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
121 | + { "src": "of:0000ffffffffff08/30", "dst": "of:0000ffffffffff0A/10", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
122 | + { "src": "of:0000ffffffffff09/20", "dst": "of:0000ffffffffff0A/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1000 } }, | ||
123 | + | ||
124 | + { "src": "of:0000ffffffff0001/2", "dst": "of:0000ffffffffff01/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } }, | ||
125 | + { "src": "of:0000ffffffff0003/2", "dst": "of:0000ffffffffff03/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } }, | ||
126 | + { "src": "of:0000ffffffff0004/2", "dst": "of:0000ffffffffff04/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } }, | ||
127 | + { "src": "of:0000ffffffff0007/2", "dst": "of:0000ffffffffff07/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } }, | ||
128 | + { "src": "of:0000ffffffff0009/2", "dst": "of:0000ffffffffff09/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } }, | ||
129 | + { "src": "of:0000ffffffff000A/2", "dst": "of:0000ffffffffff0A/1", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } } | ||
130 | + ], | ||
131 | + | ||
132 | + "hosts" : [ | ||
133 | + { "mac": "00:00:00:00:00:01", "vlan": -1, "location": "of:0000ffffffff0001/1", "ip": "10.0.0.1" }, | ||
134 | + { "mac": "00:00:00:00:00:03", "vlan": -1, "location": "of:0000ffffffff0003/1", "ip": "10.0.0.3" }, | ||
135 | + { "mac": "00:00:00:00:00:04", "vlan": -1, "location": "of:0000ffffffff0004/1", "ip": "10.0.0.4" }, | ||
136 | + { "mac": "00:00:00:00:00:07", "vlan": -1, "location": "of:0000ffffffff0007/1", "ip": "10.0.0.7" }, | ||
137 | + { "mac": "00:00:00:00:00:09", "vlan": -1, "location": "of:0000ffffffff0009/1", "ip": "10.0.0.9" }, | ||
138 | + { "mac": "00:00:00:00:00:0A", "vlan": -1, "location": "of:0000ffffffff000A/1", "ip": "10.0.0.10" } | ||
139 | + ] | ||
140 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -101,20 +101,6 @@ public final class Ip4Prefix { | ... | @@ -101,20 +101,6 @@ public final class Ip4Prefix { |
101 | return this.address.toString() + "/" + this.prefixLen; | 101 | return this.address.toString() + "/" + this.prefixLen; |
102 | } | 102 | } |
103 | 103 | ||
104 | - /** | ||
105 | - * Compares the value of two Ip4Prefix objects. | ||
106 | - * <p/> | ||
107 | - * Note the value of the IPv4 address is compared directly between the | ||
108 | - * objects, and must match exactly for the objects to be considered equal. | ||
109 | - * This may result in objects which represent the same IP prefix being | ||
110 | - * classified as unequal, because the unsignificant bits of the address | ||
111 | - * field don't match (the bits to the right of the prefix length). | ||
112 | - * <p/> | ||
113 | - * TODO Change this behavior so that objects that represent the same prefix | ||
114 | - * are classified as equal according to this equals method. | ||
115 | - * | ||
116 | - * @see Object#equals(Object) | ||
117 | - */ | ||
118 | @Override | 104 | @Override |
119 | public boolean equals(Object other) { | 105 | public boolean equals(Object other) { |
120 | if (other == this) { | 106 | if (other == this) { | ... | ... |
... | @@ -101,20 +101,6 @@ public final class Ip6Prefix { | ... | @@ -101,20 +101,6 @@ public final class Ip6Prefix { |
101 | return this.address.toString() + "/" + this.prefixLen; | 101 | return this.address.toString() + "/" + this.prefixLen; |
102 | } | 102 | } |
103 | 103 | ||
104 | - /** | ||
105 | - * Compares the value of two Ip6Prefix objects. | ||
106 | - * <p/> | ||
107 | - * Note the value of the IPv6 address is compared directly between the | ||
108 | - * objects, and must match exactly for the objects to be considered equal. | ||
109 | - * This may result in objects which represent the same IP prefix being | ||
110 | - * classified as unequal, because the unsignificant bits of the address | ||
111 | - * field don't match (the bits to the right of the prefix length). | ||
112 | - * <p/> | ||
113 | - * TODO Change this behavior so that objects that represent the same prefix | ||
114 | - * are classified as equal according to this equals method. | ||
115 | - * | ||
116 | - * @see Object#equals(Object) | ||
117 | - */ | ||
118 | @Override | 104 | @Override |
119 | public boolean equals(Object other) { | 105 | public boolean equals(Object other) { |
120 | if (other == this) { | 106 | if (other == this) { | ... | ... |
... | @@ -17,6 +17,8 @@ package org.onlab.packet; | ... | @@ -17,6 +17,8 @@ package org.onlab.packet; |
17 | 17 | ||
18 | import java.nio.ByteBuffer; | 18 | import java.nio.ByteBuffer; |
19 | import java.util.Arrays; | 19 | import java.util.Arrays; |
20 | +import java.util.Objects; | ||
21 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
20 | 22 | ||
21 | /** | 23 | /** |
22 | * A class representing an IPv4 address. | 24 | * A class representing an IPv4 address. |
... | @@ -37,35 +39,68 @@ public final class IpAddress implements Comparable<IpAddress> { | ... | @@ -37,35 +39,68 @@ public final class IpAddress implements Comparable<IpAddress> { |
37 | /** | 39 | /** |
38 | * Constructor for given IP address version and address octets. | 40 | * Constructor for given IP address version and address octets. |
39 | * | 41 | * |
40 | - * @param ver the IP address version | 42 | + * @param value the IP address value stored in network byte order |
41 | - * @param octets the IP address octets | 43 | + * (i.e., the most significant byte first) |
44 | + * @param value the IP address value | ||
42 | */ | 45 | */ |
43 | - private IpAddress(Version ver, byte[] octets) { | 46 | + private IpAddress(Version version, byte[] value) { |
44 | - this.version = ver; | 47 | + checkNotNull(value); |
45 | - this.octets = Arrays.copyOf(octets, INET_BYTE_LENGTH); | 48 | + |
49 | + this.version = version; | ||
50 | + this.octets = Arrays.copyOf(value, INET_BYTE_LENGTH); | ||
51 | + } | ||
52 | + | ||
53 | + /** | ||
54 | + * Converts an integer into an IPv4 address. | ||
55 | + * | ||
56 | + * @param value an integer representing an IPv4 value | ||
57 | + * @return an IP address | ||
58 | + */ | ||
59 | + public static IpAddress valueOf(int value) { | ||
60 | + byte[] bytes = | ||
61 | + ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(value).array(); | ||
62 | + return new IpAddress(Version.INET, bytes); | ||
46 | } | 63 | } |
47 | 64 | ||
48 | /** | 65 | /** |
49 | * Converts a byte array into an IP address. | 66 | * Converts a byte array into an IP address. |
50 | * | 67 | * |
51 | - * @param address the IP address value stored in network byte order | 68 | + * @param value the IP address value stored in network byte order |
52 | * (i.e., the most significant byte first) | 69 | * (i.e., the most significant byte first) |
53 | * @return an IP address | 70 | * @return an IP address |
54 | */ | 71 | */ |
55 | - public static IpAddress valueOf(byte[] address) { | 72 | + public static IpAddress valueOf(byte[] value) { |
56 | - return new IpAddress(Version.INET, address); | 73 | + return new IpAddress(Version.INET, value); |
57 | } | 74 | } |
58 | 75 | ||
59 | /** | 76 | /** |
60 | - * Converts an integer into an IPv4 address. | 77 | + * Converts a byte array and a given offset from the beginning of the |
78 | + * array into an IP address. | ||
79 | + * <p/> | ||
80 | + * The IP address is stored in network byte order (i.e., the most | ||
81 | + * significant byte first). | ||
61 | * | 82 | * |
62 | - * @param address an integer representing an IPv4 value | 83 | + * @param value the value to use |
84 | + * @param offset the offset in bytes from the beginning of the byte array | ||
63 | * @return an IP address | 85 | * @return an IP address |
64 | */ | 86 | */ |
65 | - public static IpAddress valueOf(int address) { | 87 | + public static IpAddress valueOf(byte[] value, int offset) { |
66 | - byte[] bytes = | 88 | + // Verify the arguments |
67 | - ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(address).array(); | 89 | + if ((offset < 0) || (offset + INET_BYTE_LENGTH > value.length)) { |
68 | - return new IpAddress(Version.INET, bytes); | 90 | + String msg; |
91 | + if (value.length < INET_BYTE_LENGTH) { | ||
92 | + msg = "Invalid IPv4 address array: array length: " + | ||
93 | + value.length + ". Must be at least " + INET_BYTE_LENGTH; | ||
94 | + } else { | ||
95 | + msg = "Invalid IPv4 address array: array offset: " + | ||
96 | + offset + ". Must be in the interval [0, " + | ||
97 | + (value.length - INET_BYTE_LENGTH) + "]"; | ||
98 | + } | ||
99 | + throw new IllegalArgumentException(msg); | ||
100 | + } | ||
101 | + | ||
102 | + byte[] bc = Arrays.copyOfRange(value, offset, value.length); | ||
103 | + return IpAddress.valueOf(bc); | ||
69 | } | 104 | } |
70 | 105 | ||
71 | /** | 106 | /** |
... | @@ -77,8 +112,9 @@ public final class IpAddress implements Comparable<IpAddress> { | ... | @@ -77,8 +112,9 @@ public final class IpAddress implements Comparable<IpAddress> { |
77 | public static IpAddress valueOf(String address) { | 112 | public static IpAddress valueOf(String address) { |
78 | final String[] net = address.split("\\."); | 113 | final String[] net = address.split("\\."); |
79 | if (net.length != INET_BYTE_LENGTH) { | 114 | if (net.length != INET_BYTE_LENGTH) { |
80 | - throw new IllegalArgumentException("Malformed IP address string; " | 115 | + String msg = "Malformed IPv4 address string; " + |
81 | - + "Address must have four decimal values separated by dots (.)"); | 116 | + "Address must have four decimal values separated by dots (.)"; |
117 | + throw new IllegalArgumentException(msg); | ||
82 | } | 118 | } |
83 | final byte[] bytes = new byte[INET_BYTE_LENGTH]; | 119 | final byte[] bytes = new byte[INET_BYTE_LENGTH]; |
84 | for (int i = 0; i < INET_BYTE_LENGTH; i++) { | 120 | for (int i = 0; i < INET_BYTE_LENGTH; i++) { |
... | @@ -115,6 +151,48 @@ public final class IpAddress implements Comparable<IpAddress> { | ... | @@ -115,6 +151,48 @@ public final class IpAddress implements Comparable<IpAddress> { |
115 | return bb.getInt(); | 151 | return bb.getInt(); |
116 | } | 152 | } |
117 | 153 | ||
154 | + /** | ||
155 | + * Creates an IP network mask prefix. | ||
156 | + * | ||
157 | + * @param prefixLen the length of the mask prefix. Must be in the interval | ||
158 | + * [0, 32] for IPv4 | ||
159 | + * @return a new IP address that contains a mask prefix of the | ||
160 | + * specified length | ||
161 | + */ | ||
162 | + public static IpAddress makeMaskPrefix(int prefixLen) { | ||
163 | + // Verify the prefix length | ||
164 | + if ((prefixLen < 0) || (prefixLen > INET_BIT_LENGTH)) { | ||
165 | + final String msg = "Invalid IPv4 prefix length: " + prefixLen + | ||
166 | + ". Must be in the interval [0, 32]."; | ||
167 | + throw new IllegalArgumentException(msg); | ||
168 | + } | ||
169 | + | ||
170 | + long v = (0xffffffffL << (INET_BIT_LENGTH - prefixLen)) & 0xffffffffL; | ||
171 | + return IpAddress.valueOf((int) v); | ||
172 | + } | ||
173 | + | ||
174 | + /** | ||
175 | + * Creates an IP address by masking it with a network mask of given | ||
176 | + * mask length. | ||
177 | + * | ||
178 | + * @param addr the address to mask | ||
179 | + * @param prefixLen the length of the mask prefix. Must be in the interval | ||
180 | + * [0, 32] for IPv4 | ||
181 | + * @return a new IP address that is masked with a mask prefix of the | ||
182 | + * specified length | ||
183 | + */ | ||
184 | + public static IpAddress makeMaskedAddress(final IpAddress addr, | ||
185 | + int prefixLen) { | ||
186 | + IpAddress mask = IpAddress.makeMaskPrefix(prefixLen); | ||
187 | + byte[] net = new byte[INET_BYTE_LENGTH]; | ||
188 | + | ||
189 | + // Mask each byte | ||
190 | + for (int i = 0; i < INET_BYTE_LENGTH; i++) { | ||
191 | + net[i] = (byte) (addr.octets[i] & mask.octets[i]); | ||
192 | + } | ||
193 | + return IpAddress.valueOf(net); | ||
194 | + } | ||
195 | + | ||
118 | @Override | 196 | @Override |
119 | public int compareTo(IpAddress o) { | 197 | public int compareTo(IpAddress o) { |
120 | Long lv = ((long) this.toInt()) & 0xffffffffL; | 198 | Long lv = ((long) this.toInt()) & 0xffffffffL; |
... | @@ -124,32 +202,20 @@ public final class IpAddress implements Comparable<IpAddress> { | ... | @@ -124,32 +202,20 @@ public final class IpAddress implements Comparable<IpAddress> { |
124 | 202 | ||
125 | @Override | 203 | @Override |
126 | public int hashCode() { | 204 | public int hashCode() { |
127 | - final int prime = 31; | 205 | + return Objects.hash(version, Arrays.hashCode(octets)); |
128 | - int result = 1; | ||
129 | - result = prime * result + Arrays.hashCode(octets); | ||
130 | - result = prime * result + ((version == null) ? 0 : version.hashCode()); | ||
131 | - return result; | ||
132 | } | 206 | } |
133 | 207 | ||
134 | @Override | 208 | @Override |
135 | public boolean equals(Object obj) { | 209 | public boolean equals(Object obj) { |
136 | - if (this == obj) { | 210 | + if (obj == this) { |
137 | return true; | 211 | return true; |
138 | } | 212 | } |
139 | - if (obj == null) { | 213 | + if ((obj == null) || (getClass() != obj.getClass())) { |
140 | - return false; | ||
141 | - } | ||
142 | - if (getClass() != obj.getClass()) { | ||
143 | return false; | 214 | return false; |
144 | } | 215 | } |
145 | IpAddress other = (IpAddress) obj; | 216 | IpAddress other = (IpAddress) obj; |
146 | - if (!Arrays.equals(octets, other.octets)) { | 217 | + return (version == other.version) && |
147 | - return false; | 218 | + Arrays.equals(octets, other.octets); |
148 | - } | ||
149 | - if (version != other.version) { | ||
150 | - return false; | ||
151 | - } | ||
152 | - return true; | ||
153 | } | 219 | } |
154 | 220 | ||
155 | @Override | 221 | @Override | ... | ... |
... | @@ -19,17 +19,21 @@ import com.fasterxml.jackson.databind.JsonNode; | ... | @@ -19,17 +19,21 @@ import com.fasterxml.jackson.databind.JsonNode; |
19 | import org.onlab.onos.net.ConnectPoint; | 19 | import org.onlab.onos.net.ConnectPoint; |
20 | import org.onlab.onos.net.DefaultAnnotations; | 20 | import org.onlab.onos.net.DefaultAnnotations; |
21 | import org.onlab.onos.net.Device; | 21 | import org.onlab.onos.net.Device; |
22 | +import org.onlab.onos.net.DeviceId; | ||
22 | import org.onlab.onos.net.Host; | 23 | import org.onlab.onos.net.Host; |
23 | import org.onlab.onos.net.HostId; | 24 | import org.onlab.onos.net.HostId; |
24 | import org.onlab.onos.net.HostLocation; | 25 | import org.onlab.onos.net.HostLocation; |
25 | import org.onlab.onos.net.Link; | 26 | import org.onlab.onos.net.Link; |
26 | import org.onlab.onos.net.MastershipRole; | 27 | import org.onlab.onos.net.MastershipRole; |
28 | +import org.onlab.onos.net.Port; | ||
27 | import org.onlab.onos.net.SparseAnnotations; | 29 | import org.onlab.onos.net.SparseAnnotations; |
28 | import org.onlab.onos.net.device.DefaultDeviceDescription; | 30 | import org.onlab.onos.net.device.DefaultDeviceDescription; |
31 | +import org.onlab.onos.net.device.DefaultPortDescription; | ||
29 | import org.onlab.onos.net.device.DeviceDescription; | 32 | import org.onlab.onos.net.device.DeviceDescription; |
30 | import org.onlab.onos.net.device.DeviceProvider; | 33 | import org.onlab.onos.net.device.DeviceProvider; |
31 | import org.onlab.onos.net.device.DeviceProviderRegistry; | 34 | import org.onlab.onos.net.device.DeviceProviderRegistry; |
32 | import org.onlab.onos.net.device.DeviceProviderService; | 35 | import org.onlab.onos.net.device.DeviceProviderService; |
36 | +import org.onlab.onos.net.device.PortDescription; | ||
33 | import org.onlab.onos.net.host.DefaultHostDescription; | 37 | import org.onlab.onos.net.host.DefaultHostDescription; |
34 | import org.onlab.onos.net.host.HostProvider; | 38 | import org.onlab.onos.net.host.HostProvider; |
35 | import org.onlab.onos.net.host.HostProviderRegistry; | 39 | import org.onlab.onos.net.host.HostProviderRegistry; |
... | @@ -45,7 +49,9 @@ import org.onlab.packet.MacAddress; | ... | @@ -45,7 +49,9 @@ import org.onlab.packet.MacAddress; |
45 | import org.onlab.packet.VlanId; | 49 | import org.onlab.packet.VlanId; |
46 | 50 | ||
47 | import java.net.URI; | 51 | import java.net.URI; |
52 | +import java.util.ArrayList; | ||
48 | import java.util.Iterator; | 53 | import java.util.Iterator; |
54 | +import java.util.List; | ||
49 | 55 | ||
50 | import static com.google.common.base.Preconditions.checkNotNull; | 56 | import static com.google.common.base.Preconditions.checkNotNull; |
51 | import static org.onlab.onos.net.DeviceId.deviceId; | 57 | import static org.onlab.onos.net.DeviceId.deviceId; |
... | @@ -120,7 +126,30 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { | ... | @@ -120,7 +126,30 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { |
120 | DeviceDescription desc = | 126 | DeviceDescription desc = |
121 | new DefaultDeviceDescription(uri, type, mfr, hw, sw, serial, | 127 | new DefaultDeviceDescription(uri, type, mfr, hw, sw, serial, |
122 | cid, annotations); | 128 | cid, annotations); |
123 | - dps.deviceConnected(deviceId(uri), desc); | 129 | + DeviceId deviceId = deviceId(uri); |
130 | + dps.deviceConnected(deviceId, desc); | ||
131 | + | ||
132 | + JsonNode ports = node.get("ports"); | ||
133 | + if (ports != null) { | ||
134 | + parsePorts(dps, deviceId, ports); | ||
135 | + } | ||
136 | + } | ||
137 | + | ||
138 | + // Parses the given node with list of device ports. | ||
139 | + private void parsePorts(DeviceProviderService dps, DeviceId deviceId, JsonNode nodes) { | ||
140 | + List<PortDescription> ports = new ArrayList<>(); | ||
141 | + for (JsonNode node : nodes) { | ||
142 | + ports.add(parsePort(node)); | ||
143 | + } | ||
144 | + dps.updatePorts(deviceId, ports); | ||
145 | + } | ||
146 | + | ||
147 | + // Parses the given node with port information. | ||
148 | + private PortDescription parsePort(JsonNode node) { | ||
149 | + Port.Type type = Port.Type.valueOf(node.path("type").asText("COPPER")); | ||
150 | + return new DefaultPortDescription(portNumber(node.path("port").asLong(0)), | ||
151 | + node.path("enabled").asBoolean(true), | ||
152 | + type, node.path("speed").asLong(1_000)); | ||
124 | } | 153 | } |
125 | 154 | ||
126 | // Parses the given JSON and provides links as configured. | 155 | // Parses the given JSON and provides links as configured. | ... | ... |
... | @@ -18,9 +18,12 @@ package org.onlab.onos.gui; | ... | @@ -18,9 +18,12 @@ package org.onlab.onos.gui; |
18 | import com.fasterxml.jackson.databind.ObjectMapper; | 18 | import com.fasterxml.jackson.databind.ObjectMapper; |
19 | import com.fasterxml.jackson.databind.node.ArrayNode; | 19 | import com.fasterxml.jackson.databind.node.ArrayNode; |
20 | import com.fasterxml.jackson.databind.node.ObjectNode; | 20 | import com.fasterxml.jackson.databind.node.ObjectNode; |
21 | +import org.onlab.onos.net.Annotations; | ||
21 | import org.onlab.onos.net.ConnectPoint; | 22 | import org.onlab.onos.net.ConnectPoint; |
22 | import org.onlab.onos.net.Device; | 23 | import org.onlab.onos.net.Device; |
24 | +import org.onlab.onos.net.DeviceId; | ||
23 | import org.onlab.onos.net.Host; | 25 | import org.onlab.onos.net.Host; |
26 | +import org.onlab.onos.net.HostId; | ||
24 | import org.onlab.onos.net.HostLocation; | 27 | import org.onlab.onos.net.HostLocation; |
25 | import org.onlab.onos.net.Link; | 28 | import org.onlab.onos.net.Link; |
26 | import org.onlab.onos.net.device.DeviceService; | 29 | import org.onlab.onos.net.device.DeviceService; |
... | @@ -35,6 +38,7 @@ import org.onlab.packet.MacAddress; | ... | @@ -35,6 +38,7 @@ import org.onlab.packet.MacAddress; |
35 | import org.onlab.rest.BaseResource; | 38 | import org.onlab.rest.BaseResource; |
36 | 39 | ||
37 | import javax.ws.rs.GET; | 40 | import javax.ws.rs.GET; |
41 | +import javax.ws.rs.PathParam; | ||
38 | import javax.ws.rs.Produces; | 42 | import javax.ws.rs.Produces; |
39 | import javax.ws.rs.core.Response; | 43 | import javax.ws.rs.core.Response; |
40 | import java.util.HashMap; | 44 | import java.util.HashMap; |
... | @@ -43,12 +47,17 @@ import java.util.Iterator; | ... | @@ -43,12 +47,17 @@ import java.util.Iterator; |
43 | import java.util.Map; | 47 | import java.util.Map; |
44 | import java.util.Set; | 48 | import java.util.Set; |
45 | 49 | ||
50 | +import static org.onlab.onos.net.DeviceId.deviceId; | ||
51 | +import static org.onlab.onos.net.HostId.hostId; | ||
52 | + | ||
46 | /** | 53 | /** |
47 | * Topology viewer resource. | 54 | * Topology viewer resource. |
48 | */ | 55 | */ |
49 | @javax.ws.rs.Path("topology") | 56 | @javax.ws.rs.Path("topology") |
50 | public class TopologyResource extends BaseResource { | 57 | public class TopologyResource extends BaseResource { |
51 | 58 | ||
59 | + private static final String HOST_SEP = "/"; | ||
60 | + | ||
52 | @javax.ws.rs.Path("/graph") | 61 | @javax.ws.rs.Path("/graph") |
53 | @GET | 62 | @GET |
54 | @Produces("application/json") | 63 | @Produces("application/json") |
... | @@ -70,6 +79,66 @@ public class TopologyResource extends BaseResource { | ... | @@ -70,6 +79,66 @@ public class TopologyResource extends BaseResource { |
70 | return Response.ok(rootNode.toString()).build(); | 79 | return Response.ok(rootNode.toString()).build(); |
71 | } | 80 | } |
72 | 81 | ||
82 | + @javax.ws.rs.Path("/graph/{id}") | ||
83 | + @GET | ||
84 | + @Produces("application/json") | ||
85 | + public Response details(@PathParam("id") String id) { | ||
86 | + if (id.contains(HOST_SEP)) { | ||
87 | + return hostDetails(hostId(id)); | ||
88 | + } | ||
89 | + return deviceDetails(deviceId(id)); | ||
90 | + } | ||
91 | + | ||
92 | + // Returns device details response. | ||
93 | + private Response deviceDetails(DeviceId deviceId) { | ||
94 | + DeviceService deviceService = get(DeviceService.class); | ||
95 | + Device device = deviceService.getDevice(deviceId); | ||
96 | + Annotations annot = device.annotations(); | ||
97 | + int portCount = deviceService.getPorts(deviceId).size(); | ||
98 | + ObjectNode r = json(deviceId.toString(), | ||
99 | + device.type().toString().toLowerCase(), | ||
100 | + new Prop("Name", annot.value("name")), | ||
101 | + new Prop("Vendor", device.manufacturer()), | ||
102 | + new Prop("H/W Version", device.hwVersion()), | ||
103 | + new Prop("S/W Version", device.swVersion()), | ||
104 | + new Prop("S/W Version", device.serialNumber()), | ||
105 | + new Separator(), | ||
106 | + new Prop("Latitude", annot.value("latitude")), | ||
107 | + new Prop("Longitude", annot.value("longitude")), | ||
108 | + new Prop("Ports", Integer.toString(portCount))); | ||
109 | + return Response.ok(r.toString()).build(); | ||
110 | + } | ||
111 | + | ||
112 | + // Returns host details response. | ||
113 | + private Response hostDetails(HostId hostId) { | ||
114 | + HostService hostService = get(HostService.class); | ||
115 | + Host host = hostService.getHost(hostId); | ||
116 | + Annotations annot = host.annotations(); | ||
117 | + ObjectNode r = json(hostId.toString(), "host", | ||
118 | + new Prop("MAC", host.mac().toString()), | ||
119 | + new Prop("IP", host.ipAddresses().toString()), | ||
120 | + new Separator(), | ||
121 | + new Prop("Latitude", annot.value("latitude")), | ||
122 | + new Prop("Longitude", annot.value("longitude"))); | ||
123 | + return Response.ok(r.toString()).build(); | ||
124 | + } | ||
125 | + | ||
126 | + // Produces JSON property details. | ||
127 | + private ObjectNode json(String id, String type, Prop... props) { | ||
128 | + ObjectMapper mapper = new ObjectMapper(); | ||
129 | + ObjectNode result = mapper.createObjectNode() | ||
130 | + .put("id", id).put("type", type); | ||
131 | + ObjectNode pnode = mapper.createObjectNode(); | ||
132 | + ArrayNode porder = mapper.createArrayNode(); | ||
133 | + for (Prop p : props) { | ||
134 | + porder.add(p.key); | ||
135 | + pnode.put(p.key, p.value); | ||
136 | + } | ||
137 | + result.set("propOrder", porder); | ||
138 | + result.set("props", pnode); | ||
139 | + return result; | ||
140 | + } | ||
141 | + | ||
73 | // Encodes all infrastructure devices. | 142 | // Encodes all infrastructure devices. |
74 | private ArrayNode getDevices(ObjectMapper mapper, DeviceService deviceService, | 143 | private ArrayNode getDevices(ObjectMapper mapper, DeviceService deviceService, |
75 | TopologyGraph graph) { | 144 | TopologyGraph graph) { |
... | @@ -209,4 +278,20 @@ public class TopologyResource extends BaseResource { | ... | @@ -209,4 +278,20 @@ public class TopologyResource extends BaseResource { |
209 | return cp.elementId().toString(); | 278 | return cp.elementId().toString(); |
210 | } | 279 | } |
211 | 280 | ||
281 | + // Auxiliary key/value carrier. | ||
282 | + private class Prop { | ||
283 | + private final String key; | ||
284 | + private final String value; | ||
285 | + | ||
286 | + protected Prop(String key, String value) { | ||
287 | + this.key = key; | ||
288 | + this.value = value; | ||
289 | + } | ||
290 | + } | ||
291 | + | ||
292 | + private class Separator extends Prop { | ||
293 | + protected Separator() { | ||
294 | + super("-", ""); | ||
295 | + } | ||
296 | + } | ||
212 | } | 297 | } | ... | ... |
web/gui/src/main/webapp/img/roadm.png
0 → 100644
8.83 KB
web/gui/src/main/webapp/img/switch.png
0 → 100644
9.27 KB
... | @@ -39,7 +39,7 @@ | ... | @@ -39,7 +39,7 @@ |
39 | <body> | 39 | <body> |
40 | <div id="frame"> | 40 | <div id="frame"> |
41 | <div id="mast"> | 41 | <div id="mast"> |
42 | - <img id="logo" src="img/onos-logo.png" width="60" height="38"> | 42 | + <img id="logo" src="img/onos-logo.png"> |
43 | <span class="title">Open Network Operating System</span> | 43 | <span class="title">Open Network Operating System</span> |
44 | <span id="displayModes" class="right"> | 44 | <span id="displayModes" class="right"> |
45 | <span id="showAll" class="radio active">All Layers</span> | 45 | <span id="showAll" class="radio active">All Layers</span> | ... | ... |
... | @@ -59,54 +59,72 @@ | ... | @@ -59,54 +59,72 @@ |
59 | "src": "of:0000000000000001", | 59 | "src": "of:0000000000000001", |
60 | "dst": "of:0000000000000002", | 60 | "dst": "of:0000000000000002", |
61 | "type": "optical", | 61 | "type": "optical", |
62 | + "srcPort": 1, | ||
63 | + "dstPort": 2, | ||
62 | "linkWidth": 1.5 | 64 | "linkWidth": 1.5 |
63 | }, | 65 | }, |
64 | { | 66 | { |
65 | "src": "of:0000000000000001", | 67 | "src": "of:0000000000000001", |
66 | "dst": "of:0000000000000003", | 68 | "dst": "of:0000000000000003", |
67 | "type": "optical", | 69 | "type": "optical", |
70 | + "srcPort": 2, | ||
71 | + "dstPort": 5, | ||
68 | "linkWidth": 1.5 | 72 | "linkWidth": 1.5 |
69 | }, | 73 | }, |
70 | { | 74 | { |
71 | "src": "of:0000000000000001", | 75 | "src": "of:0000000000000001", |
72 | "dst": "of:0000000000000004", | 76 | "dst": "of:0000000000000004", |
73 | "type": "optical", | 77 | "type": "optical", |
78 | + "srcPort": 3, | ||
79 | + "dstPort": 2, | ||
74 | "linkWidth": 1.5 | 80 | "linkWidth": 1.5 |
75 | }, | 81 | }, |
76 | { | 82 | { |
77 | "src": "of:0000000000000002", | 83 | "src": "of:0000000000000002", |
78 | "dst": "of:0000000000000003", | 84 | "dst": "of:0000000000000003", |
79 | "type": "optical", | 85 | "type": "optical", |
86 | + "srcPort": 3, | ||
87 | + "dstPort": 4, | ||
80 | "linkWidth": 1.5 | 88 | "linkWidth": 1.5 |
81 | }, | 89 | }, |
82 | { | 90 | { |
83 | "src": "of:0000000000000002", | 91 | "src": "of:0000000000000002", |
84 | "dst": "of:0000000000000004", | 92 | "dst": "of:0000000000000004", |
85 | "type": "optical", | 93 | "type": "optical", |
94 | + "srcPort": 4, | ||
95 | + "dstPort": 1, | ||
86 | "linkWidth": 1.5 | 96 | "linkWidth": 1.5 |
87 | }, | 97 | }, |
88 | { | 98 | { |
89 | "src": "of:0000000000000003", | 99 | "src": "of:0000000000000003", |
90 | "dst": "of:0000000000000004", | 100 | "dst": "of:0000000000000004", |
91 | "type": "optical", | 101 | "type": "optical", |
102 | + "srcPort": 3, | ||
103 | + "dstPort": 3, | ||
92 | "linkWidth": 1.5 | 104 | "linkWidth": 1.5 |
93 | }, | 105 | }, |
94 | { | 106 | { |
95 | "src": "of:0000000000000013", | 107 | "src": "of:0000000000000013", |
96 | "dst": "of:0000000000000003", | 108 | "dst": "of:0000000000000003", |
97 | "type": "direct", | 109 | "type": "direct", |
110 | + "srcPort": 1, | ||
111 | + "dstPort": 7, | ||
98 | "linkWidth": 1.0 | 112 | "linkWidth": 1.0 |
99 | }, | 113 | }, |
100 | { | 114 | { |
101 | "src": "of:0000000000000012", | 115 | "src": "of:0000000000000012", |
102 | "dst": "of:0000000000000002", | 116 | "dst": "of:0000000000000002", |
103 | "type": "direct", | 117 | "type": "direct", |
118 | + "srcPort": 1, | ||
119 | + "dstPort": 9, | ||
104 | "linkWidth": 1.0 | 120 | "linkWidth": 1.0 |
105 | }, | 121 | }, |
106 | { | 122 | { |
107 | "src": "of:0000000000000011", | 123 | "src": "of:0000000000000011", |
108 | "dst": "of:0000000000000001", | 124 | "dst": "of:0000000000000001", |
109 | "type": "direct", | 125 | "type": "direct", |
126 | + "srcPort": 1, | ||
127 | + "dstPort": 6, | ||
110 | "linkWidth": 1.0 | 128 | "linkWidth": 1.0 |
111 | } | 129 | } |
112 | ], | 130 | ], | ... | ... |
1 | { | 1 | { |
2 | "comment": "sample device properties", | 2 | "comment": "sample device properties", |
3 | "id": "of:0000000000000001", | 3 | "id": "of:0000000000000001", |
4 | - "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ], | 4 | + "type": "roadm", |
5 | + "propOrder": [ "name", "type", "-", "dpid", "latitude", "longitude", "allowed" ], | ||
5 | "props": { | 6 | "props": { |
6 | "allowed": true, | 7 | "allowed": true, |
7 | "latitude": 37.6, | 8 | "latitude": 37.6, |
8 | "longitude": 122.3, | 9 | "longitude": 122.3, |
9 | "name": "SFO-W10", | 10 | "name": "SFO-W10", |
10 | - "dpid": "00:00:00:00:00:00:00:01", | 11 | + "dpid": "00:00:00:00:00:00:00:01" |
11 | - "type": "Roadm" | ||
12 | } | 12 | } |
13 | } | 13 | } | ... | ... |
1 | { | 1 | { |
2 | "comment": "sample device properties", | 2 | "comment": "sample device properties", |
3 | "id": "of:0000000000000002", | 3 | "id": "of:0000000000000002", |
4 | + "type": "switch", | ||
4 | "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ], | 5 | "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ], |
5 | "props": { | 6 | "props": { |
6 | "allowed": true, | 7 | "allowed": true, | ... | ... |
1 | { | 1 | { |
2 | "comment": "sample device properties", | 2 | "comment": "sample device properties", |
3 | "id": "of:0000000000000003", | 3 | "id": "of:0000000000000003", |
4 | + "type": "switch", | ||
4 | "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ], | 5 | "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ], |
5 | "props": { | 6 | "props": { |
6 | "allowed": true, | 7 | "allowed": true, | ... | ... |
1 | { | 1 | { |
2 | "comment": "sample device properties", | 2 | "comment": "sample device properties", |
3 | "id": "of:0000000000000004", | 3 | "id": "of:0000000000000004", |
4 | + "type": "switch", | ||
4 | "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ], | 5 | "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ], |
5 | "props": { | 6 | "props": { |
6 | "allowed": true, | 7 | "allowed": true, | ... | ... |
1 | { | 1 | { |
2 | "comment": "sample device properties", | 2 | "comment": "sample device properties", |
3 | "id": "of:0000000000000011", | 3 | "id": "of:0000000000000011", |
4 | + "type": "switch", | ||
4 | "propOrder": [ "name", "type", "dpid", "optLink" ], | 5 | "propOrder": [ "name", "type", "dpid", "optLink" ], |
5 | "props": { | 6 | "props": { |
6 | "name": "SFO-pkt", | 7 | "name": "SFO-pkt", | ... | ... |
1 | { | 1 | { |
2 | "comment": "sample device properties", | 2 | "comment": "sample device properties", |
3 | "id": "of:0000000000000012", | 3 | "id": "of:0000000000000012", |
4 | + "type": "switch", | ||
4 | "propOrder": [ "name", "type", "dpid", "optLink" ], | 5 | "propOrder": [ "name", "type", "dpid", "optLink" ], |
5 | "props": { | 6 | "props": { |
6 | "name": "SJC-pkt", | 7 | "name": "SJC-pkt", | ... | ... |
1 | { | 1 | { |
2 | "comment": "sample device properties", | 2 | "comment": "sample device properties", |
3 | "id": "of:0000000000000013", | 3 | "id": "of:0000000000000013", |
4 | + "type": "switch", | ||
4 | "propOrder": [ "name", "type", "dpid", "optLink" ], | 5 | "propOrder": [ "name", "type", "dpid", "optLink" ], |
5 | "props": { | 6 | "props": { |
6 | "name": "LAX-pkt", | 7 | "name": "LAX-pkt", | ... | ... |
... | @@ -37,9 +37,10 @@ | ... | @@ -37,9 +37,10 @@ |
37 | layering: true, | 37 | layering: true, |
38 | collisionPrevention: true | 38 | collisionPrevention: true |
39 | }, | 39 | }, |
40 | - XjsonUrl: 'rs/topology/graph', | 40 | + jsonUrl: 'rs/topology/graph', |
41 | - jsonUrl: 'json/network.json', | 41 | + jsonPrefix: '', |
42 | - jsonPrefix: 'json/', | 42 | + XjsonUrl: 'json/network.json', |
43 | + XjsonPrefix: 'json/', | ||
43 | iconUrl: { | 44 | iconUrl: { |
44 | device: 'img/device.png', | 45 | device: 'img/device.png', |
45 | host: 'img/host.png', | 46 | host: 'img/host.png', |
... | @@ -238,6 +239,9 @@ | ... | @@ -238,6 +239,9 @@ |
238 | function processKeyEvent() { | 239 | function processKeyEvent() { |
239 | var code = d3.event.keyCode; | 240 | var code = d3.event.keyCode; |
240 | switch (code) { | 241 | switch (code) { |
242 | + case 71: // G | ||
243 | + cycleLayout(); | ||
244 | + break; | ||
241 | case 76: // L | 245 | case 76: // L |
242 | cycleLabels(); | 246 | cycleLabels(); |
243 | break; | 247 | break; |
... | @@ -251,6 +255,11 @@ | ... | @@ -251,6 +255,11 @@ |
251 | 255 | ||
252 | } | 256 | } |
253 | 257 | ||
258 | + function cycleLayout() { | ||
259 | + config.options.layering = !config.options.layering; | ||
260 | + network.force.resume(); | ||
261 | + } | ||
262 | + | ||
254 | function cycleLabels() { | 263 | function cycleLabels() { |
255 | console.log('Cycle Labels - context = ' + contextLabel()); | 264 | console.log('Cycle Labels - context = ' + contextLabel()); |
256 | } | 265 | } |
... | @@ -688,7 +697,8 @@ | ... | @@ -688,7 +697,8 @@ |
688 | } | 697 | } |
689 | 698 | ||
690 | function iconUrl(d) { | 699 | function iconUrl(d) { |
691 | - return config.iconUrl[d.icon]; | 700 | + return 'img/' + d.type + '.png'; |
701 | +// return config.iconUrl[d.icon]; | ||
692 | } | 702 | } |
693 | 703 | ||
694 | function translate(x, y) { | 704 | function translate(x, y) { |
... | @@ -889,8 +899,11 @@ | ... | @@ -889,8 +899,11 @@ |
889 | } | 899 | } |
890 | 900 | ||
891 | function detailUrl(id) { | 901 | function detailUrl(id) { |
892 | - var safeId = id.replace(/[^a-z0-9]/gi, '_'); | 902 | + if (config.jsonPrefix) { |
893 | - return config.jsonPrefix + safeId + '.json'; | 903 | + var safeId = id.replace(/[^a-z0-9]/gi, '_'); |
904 | + return config.jsonPrefix + safeId + '.json'; | ||
905 | + } | ||
906 | + return config.jsonUrl + '/' + encodeURIComponent(id); | ||
894 | } | 907 | } |
895 | 908 | ||
896 | function flyinPane(obj) { | 909 | function flyinPane(obj) { |
... | @@ -924,17 +937,29 @@ | ... | @@ -924,17 +937,29 @@ |
924 | function displayDetails(data, pane) { | 937 | function displayDetails(data, pane) { |
925 | $('#flyout').empty(); | 938 | $('#flyout').empty(); |
926 | 939 | ||
927 | - pane.append('h2').text(data.id); | 940 | + var title = pane.append("h2"), |
928 | - | 941 | + table = pane.append("table"), |
929 | - var table = pane.append("table"), | ||
930 | tbody = table.append("tbody"); | 942 | tbody = table.append("tbody"); |
931 | 943 | ||
944 | + $('<img src="img/' + data.type + '.png">').appendTo(title); | ||
945 | + $('<span>').attr('class', 'icon').text(data.id).appendTo(title); | ||
946 | + | ||
947 | + | ||
932 | // TODO: consider using d3 data bind to TR/TD | 948 | // TODO: consider using d3 data bind to TR/TD |
933 | 949 | ||
934 | data.propOrder.forEach(function(p) { | 950 | data.propOrder.forEach(function(p) { |
935 | - addProp(tbody, p, data.props[p]); | 951 | + if (p === '-') { |
952 | + addSep(tbody); | ||
953 | + } else { | ||
954 | + addProp(tbody, p, data.props[p]); | ||
955 | + } | ||
936 | }); | 956 | }); |
937 | 957 | ||
958 | + function addSep(tbody) { | ||
959 | + var tr = tbody.append('tr'); | ||
960 | + $('<hr>').appendTo(tr.append('td').attr('colspan', 2)); | ||
961 | + } | ||
962 | + | ||
938 | function addProp(tbody, label, value) { | 963 | function addProp(tbody, label, value) { |
939 | var tr = tbody.append('tr'); | 964 | var tr = tbody.append('tr'); |
940 | 965 | ... | ... |
... | @@ -28,11 +28,17 @@ body, html { | ... | @@ -28,11 +28,17 @@ body, html { |
28 | * Classes | 28 | * Classes |
29 | */ | 29 | */ |
30 | 30 | ||
31 | +img#logo { | ||
32 | + height: 38px; | ||
33 | + padding-left: 8px; | ||
34 | + padding-right: 8px; | ||
35 | +} | ||
36 | + | ||
31 | span.title { | 37 | span.title { |
32 | - color: #37b; | 38 | + color: #369; |
33 | font-size: 14pt; | 39 | font-size: 14pt; |
34 | font-style: italic; | 40 | font-style: italic; |
35 | - vertical-align: 10px; | 41 | + vertical-align: 12px; |
36 | } | 42 | } |
37 | 43 | ||
38 | span.radio { | 44 | span.radio { |
... | @@ -41,6 +47,8 @@ span.radio { | ... | @@ -41,6 +47,8 @@ span.radio { |
41 | } | 47 | } |
42 | 48 | ||
43 | span.right { | 49 | span.right { |
50 | + padding-top: 8px; | ||
51 | + padding-right: 16px; | ||
44 | float: right; | 52 | float: right; |
45 | } | 53 | } |
46 | 54 | ||
... | @@ -89,14 +97,13 @@ svg .link { | ... | @@ -89,14 +97,13 @@ svg .link { |
89 | } | 97 | } |
90 | 98 | ||
91 | svg .link.host { | 99 | svg .link.host { |
92 | - stroke: #6a6; | 100 | + stroke: #666; |
93 | - stroke-dasharray: 3,3; | 101 | + stroke-width: 1px; |
102 | + Xstroke-dasharray: 3,3; | ||
94 | } | 103 | } |
95 | 104 | ||
96 | svg .node.device rect { | 105 | svg .node.device rect { |
97 | - stroke-width: 3.0px; | 106 | + stroke-width: 1.5px; |
98 | - stroke: white; | ||
99 | - stroke-dasharray: 2,2; | ||
100 | 107 | ||
101 | transition: opacity 250ms; | 108 | transition: opacity 250ms; |
102 | -webkit-transition: opacity 250ms; | 109 | -webkit-transition: opacity 250ms; |
... | @@ -104,19 +111,21 @@ svg .node.device rect { | ... | @@ -104,19 +111,21 @@ svg .node.device rect { |
104 | } | 111 | } |
105 | 112 | ||
106 | svg .node.device.fixed rect { | 113 | svg .node.device.fixed rect { |
107 | - stroke-width: 0; | 114 | + stroke-width: 1.5; |
115 | + stroke: #ccc; | ||
116 | + Xstroke-dasharray: 4,2; | ||
108 | } | 117 | } |
109 | 118 | ||
110 | svg .node.device.roadm rect { | 119 | svg .node.device.roadm rect { |
111 | - fill: #229; | 120 | + fill: #03c; |
112 | } | 121 | } |
113 | 122 | ||
114 | svg .node.device.switch rect { | 123 | svg .node.device.switch rect { |
115 | - fill: #55f; | 124 | + fill: #06f; |
116 | } | 125 | } |
117 | 126 | ||
118 | svg .node.host circle { | 127 | svg .node.host circle { |
119 | - fill: #898; | 128 | + fill: #c96; |
120 | stroke: #000; | 129 | stroke: #000; |
121 | } | 130 | } |
122 | 131 | ||
... | @@ -148,7 +157,7 @@ svg .node.inactive rect, | ... | @@ -148,7 +157,7 @@ svg .node.inactive rect, |
148 | svg .node.inactive circle, | 157 | svg .node.inactive circle, |
149 | svg .node.inactive text, | 158 | svg .node.inactive text, |
150 | svg .node.inactive image { | 159 | svg .node.inactive image { |
151 | - opacity: .05; | 160 | + opacity: .1; |
152 | } | 161 | } |
153 | 162 | ||
154 | svg .node.inactive.selected rect, | 163 | svg .node.inactive.selected rect, |
... | @@ -199,8 +208,9 @@ body { | ... | @@ -199,8 +208,9 @@ body { |
199 | #mast { | 208 | #mast { |
200 | height: 36px; | 209 | height: 36px; |
201 | padding: 4px; | 210 | padding: 4px; |
202 | - background-color: #ccc; | 211 | + background-color: #bbb; |
203 | vertical-align: baseline; | 212 | vertical-align: baseline; |
213 | + box-shadow: 0px 2px 8px #777; | ||
204 | } | 214 | } |
205 | 215 | ||
206 | #frame { | 216 | #frame { |
... | @@ -214,19 +224,27 @@ body { | ... | @@ -214,19 +224,27 @@ body { |
214 | z-index: 100; | 224 | z-index: 100; |
215 | display: block; | 225 | display: block; |
216 | top: 10%; | 226 | top: 10%; |
217 | - width: 300px; | 227 | + width: 280px; |
218 | - height: 80%; | 228 | + right: -300px; |
219 | - right: -320px; | ||
220 | opacity: 0; | 229 | opacity: 0; |
221 | - background-color: rgba(0,0,0,0.5); | 230 | + background-color: rgba(255,255,255,0.5); |
231 | + | ||
222 | padding: 10px; | 232 | padding: 10px; |
223 | - color: white; | 233 | + color: black; |
224 | font-size: 10pt; | 234 | font-size: 10pt; |
235 | + box-shadow: 2px 2px 16px #777; | ||
225 | } | 236 | } |
226 | 237 | ||
227 | #flyout h2 { | 238 | #flyout h2 { |
228 | margin: 8px 4px; | 239 | margin: 8px 4px; |
229 | - color: yellow; | 240 | + color: black; |
241 | + vertical-align: middle; | ||
242 | +} | ||
243 | + | ||
244 | +#flyout h2 img { | ||
245 | + height: 32px; | ||
246 | + padding-right: 8px; | ||
247 | + vertical-align: middle; | ||
230 | } | 248 | } |
231 | 249 | ||
232 | #flyout p, table { | 250 | #flyout p, table { |
... | @@ -235,7 +253,7 @@ body { | ... | @@ -235,7 +253,7 @@ body { |
235 | 253 | ||
236 | #flyout td.label { | 254 | #flyout td.label { |
237 | font-style: italic; | 255 | font-style: italic; |
238 | - color: #ccf; | 256 | + color: #777; |
239 | padding-right: 12px; | 257 | padding-right: 12px; |
240 | } | 258 | } |
241 | 259 | ||
... | @@ -243,3 +261,10 @@ body { | ... | @@ -243,3 +261,10 @@ body { |
243 | 261 | ||
244 | } | 262 | } |
245 | 263 | ||
264 | +#flyout hr { | ||
265 | + height: 1px; | ||
266 | + color: #ccc; | ||
267 | + background-color: #ccc; | ||
268 | + border: 0; | ||
269 | +} | ||
270 | + | ... | ... |
-
Please register or login to post a comment