ONOS-5503 Added CLIs for administering OFAgent
Change-Id: I58256316e2054952da9dce04bf927901761807e5
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgent.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgent.java
index 0db4489..659d6db 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgent.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgent.java
@@ -71,6 +71,15 @@
*/
OFAgent build();
+
+ /**
+ * Returns OF agent builder with the supplied OF agent.
+ *
+ * @param ofAgent ofagent
+ * @return of agent builder
+ */
+ Builder from(OFAgent ofAgent);
+
/**
* Returns OF agent builder with the supplied network ID.
*
@@ -88,6 +97,22 @@
Builder controllers(Set<OFController> controllers);
/**
+ * Returns OF agent builder with the supplied additional controller.
+ *
+ * @param controller additional controller
+ * @return of agent builder
+ */
+ Builder addController(OFController controller);
+
+ /**
+ * Returns OF agent builder with the supplied controller removed.
+ *
+ * @param controller controller to delete
+ * @return of agent builder
+ */
+ Builder deleteController(OFController controller);
+
+ /**
* Returns OF agent builder with the supplied state.
*
* @param state state of the agent
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgentAdminService.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgentAdminService.java
index 0c6667a..859215d 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgentAdminService.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFAgentAdminService.java
@@ -40,8 +40,9 @@
* Removes the OpenFlow agent for the given virtual network.
*
* @param networkId virtual network identifier
+ * @return removed ofagent; null if it fails
*/
- void removeAgent(NetworkId networkId);
+ OFAgent removeAgent(NetworkId networkId);
/**
* Starts the agent for the given network.
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentAddControllerCommand.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentAddControllerCommand.java
new file mode 100644
index 0000000..354197b
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentAddControllerCommand.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.ofagent.api.OFAgent;
+import org.onosproject.ofagent.api.OFAgentAdminService;
+import org.onosproject.ofagent.api.OFAgentService;
+import org.onosproject.ofagent.impl.DefaultOFAgent;
+import org.onosproject.ofagent.impl.DefaultOFController;
+
+/**
+ * Adds a controller to the OFAgent.
+ */
+@Command(scope = "onos", name = "ofagent-controller-add",
+ description = "Add a controller to the ofagent")
+public class OFAgentAddControllerCommand extends AbstractShellCommand {
+
+ private static final String PATTERN_IP_PORT = "\\d{1,3}(?:\\.\\d{1,3}){3}(?::\\d{1,5})";
+
+ @Argument(index = 0, name = "network", description = "Virtual network ID",
+ required = true, multiValued = false)
+ private long networkId = NetworkId.NONE.id();
+
+ @Argument(index = 1, name = "controller",
+ description = "External controller with IP:PORT format",
+ required = true, multiValued = false)
+ private String strCtrl;
+
+ @Override
+ protected void execute() {
+ if (!isValidController(strCtrl)) {
+ error("Invalid controller string %s, must be IP:PORT", strCtrl);
+ return;
+ }
+
+ OFAgentService service = get(OFAgentService.class);
+ OFAgentAdminService adminService = get(OFAgentAdminService.class);
+
+ OFAgent existing = service.agent(NetworkId.networkId(networkId));
+ if (existing == null) {
+ error("OFAgent for network %s does not exist", networkId);
+ return;
+ }
+
+ String[] temp = strCtrl.split(":");
+ OFAgent updated = DefaultOFAgent.builder()
+ .from(existing)
+ .addController(DefaultOFController.of(
+ IpAddress.valueOf(temp[0]),
+ TpPort.tpPort(Integer.valueOf(temp[1]))))
+ .build();
+ adminService.updateAgent(updated);
+ }
+
+ private boolean isValidController(String ctrl) {
+ if (!ctrl.matches(PATTERN_IP_PORT)) {
+ return false;
+ }
+
+ String[] temp = ctrl.split(":");
+ try {
+ IpAddress.valueOf(temp[0]);
+ TpPort.tpPort(Integer.valueOf(temp[1]));
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentCreateCommand.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentCreateCommand.java
new file mode 100644
index 0000000..239c5ef
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentCreateCommand.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.cli;
+
+import com.google.common.collect.Sets;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.ofagent.api.OFAgent;
+import org.onosproject.ofagent.api.OFAgentAdminService;
+import org.onosproject.ofagent.api.OFController;
+import org.onosproject.ofagent.impl.DefaultOFAgent;
+import org.onosproject.ofagent.impl.DefaultOFController;
+
+import java.util.Set;
+
+/**
+ * Creates a new OFAagent.
+ */
+@Command(scope = "onos", name = "ofagent-create", description = "Add a new ofagent")
+public class OFAgentCreateCommand extends AbstractShellCommand {
+
+ private static final String PATTERN_IP_PORT = "\\d{1,3}(?:\\.\\d{1,3}){3}(?::\\d{1,5})";
+
+ @Argument(index = 0, name = "network", description = "Virtual network ID",
+ required = true, multiValued = false)
+ private long networkId = NetworkId.NONE.id();
+
+ @Argument(index = 1, name = "controllers",
+ description = "List of external controllers with IP:PORT format",
+ required = false, multiValued = true)
+ private String[] strCtrls = {};
+
+ @Override
+ protected void execute() {
+ Set<OFController> ctrls = Sets.newHashSet();
+ for (String strCtrl : strCtrls) {
+ if (!isValidController(strCtrl)) {
+ print("Invalid controller %s, ignores it.", strCtrl);
+ continue;
+ }
+ String[] temp = strCtrl.split(":");
+ ctrls.add(DefaultOFController.of(IpAddress.valueOf(temp[0]),
+ TpPort.tpPort(Integer.valueOf(temp[1]))));
+ }
+
+ OFAgentAdminService adminService = get(OFAgentAdminService.class);
+ OFAgent ofAgent = DefaultOFAgent.builder()
+ .networkId(NetworkId.networkId(networkId))
+ .controllers(ctrls)
+ .state(OFAgent.State.STOPPED)
+ .build();
+ adminService.createAgent(ofAgent);
+ print("Successfully created OFAgent for network %s", networkId);
+ }
+
+ private boolean isValidController(String ctrl) {
+ if (!ctrl.matches(PATTERN_IP_PORT)) {
+ return false;
+ }
+
+ String[] temp = ctrl.split(":");
+ try {
+ IpAddress.valueOf(temp[0]);
+ TpPort.tpPort(Integer.valueOf(temp[1]));
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentDeleteControllerCommand.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentDeleteControllerCommand.java
new file mode 100644
index 0000000..e401798
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentDeleteControllerCommand.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.ofagent.api.OFAgent;
+import org.onosproject.ofagent.api.OFAgentAdminService;
+import org.onosproject.ofagent.api.OFAgentService;
+import org.onosproject.ofagent.impl.DefaultOFAgent;
+import org.onosproject.ofagent.impl.DefaultOFController;
+
+/**
+ * Removes the controller from the OFAgent.
+ */
+@Command(scope = "onos", name = "ofagent-controller-delete",
+ description = "Deletes a controller from the ofagent")
+public class OFAgentDeleteControllerCommand extends AbstractShellCommand {
+
+ private static final String PATTERN_IP_PORT = "\\d{1,3}(?:\\.\\d{1,3}){3}(?::\\d{1,5})";
+
+ @Argument(index = 0, name = "network", description = "Virtual network ID",
+ required = true, multiValued = false)
+ private long networkId = NetworkId.NONE.id();
+
+ @Argument(index = 1, name = "controller",
+ description = "External controller with IP:PORT format",
+ required = true, multiValued = false)
+ private String strCtrl;
+
+ @Override
+ protected void execute() {
+ if (!isValidController(strCtrl)) {
+ error("Invalid controller string %s, must be IP:PORT", strCtrl);
+ return;
+ }
+
+ OFAgentService service = get(OFAgentService.class);
+ OFAgentAdminService adminService = get(OFAgentAdminService.class);
+
+ OFAgent existing = service.agent(NetworkId.networkId(networkId));
+ if (existing == null) {
+ error("OFAgent for network %s does not exist", networkId);
+ return;
+ }
+
+ String[] temp = strCtrl.split(":");
+ OFAgent updated = DefaultOFAgent.builder()
+ .from(existing)
+ .deleteController(DefaultOFController.of(
+ IpAddress.valueOf(temp[0]),
+ TpPort.tpPort(Integer.valueOf(temp[1]))))
+ .build();
+ adminService.updateAgent(updated);
+ }
+
+ private boolean isValidController(String ctrl) {
+ if (!ctrl.matches(PATTERN_IP_PORT)) {
+ return false;
+ }
+
+ String[] temp = ctrl.split(":");
+ try {
+ IpAddress.valueOf(temp[0]);
+ TpPort.tpPort(Integer.valueOf(temp[1]));
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentListCommand.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentListCommand.java
new file mode 100644
index 0000000..8cceadc
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentListCommand.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.ofagent.api.OFAgentService;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Lists the existing OFAgents.
+ */
+@Command(scope = "onos", name = "ofagents", description = "Lists all ofagents")
+public class OFAgentListCommand extends AbstractShellCommand {
+
+ private static final String FORMAT = "%-10s%-10s%-8s";
+ private static final String CTRL = "%s:%s";
+
+ @Override
+ protected void execute() {
+ OFAgentService service = get(OFAgentService.class);
+ print(FORMAT, "Network", "Status", "Controllers");
+
+ service.agents().forEach(agent -> {
+ Set<String> ctrls = agent.controllers().stream()
+ .map(ctrl -> String.format(CTRL, ctrl.ip(), ctrl.port()))
+ .collect(Collectors.toSet());
+ print(FORMAT, agent.networkId(), agent.state().name(), ctrls);
+ });
+ }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentRemoveCommand.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentRemoveCommand.java
new file mode 100644
index 0000000..5e588f8
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentRemoveCommand.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.ofagent.api.OFAgent;
+import org.onosproject.ofagent.api.OFAgentAdminService;
+
+/**
+ * Removes the existing OFAgent.
+ */
+@Command(scope = "onos", name = "ofagent-remove", description = "Removes the ofagent")
+public class OFAgentRemoveCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "network", description = "Virtual network ID",
+ required = true, multiValued = false)
+ private long networkId = NetworkId.NONE.id();
+
+ @Override
+ protected void execute() {
+ OFAgentAdminService adminService = get(OFAgentAdminService.class);
+ OFAgent removed = adminService.removeAgent(NetworkId.networkId(networkId));
+ if (removed != null) {
+ print("Successfully removed OFAgent for network %s", networkId);
+ } else {
+ print("Failed to remove OFAgent for network %s", networkId);
+ }
+ }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentStartCommand.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentStartCommand.java
new file mode 100644
index 0000000..ba9228d
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentStartCommand.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.ofagent.api.OFAgentAdminService;
+
+/**
+ * Starts the OFAgent.
+ */
+@Command(scope = "onos", name = "ofagent-start", description = "Starts the ofagent")
+public class OFAgentStartCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "network", description = "Virtual network ID",
+ required = true, multiValued = false)
+ private long networkId = NetworkId.NONE.id();
+
+ @Override
+ protected void execute() {
+ OFAgentAdminService adminService = get(OFAgentAdminService.class);
+ adminService.startAgent(NetworkId.networkId(networkId));
+ print("Successfully started OFAgent for network %s", networkId);
+ }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentStopCommand.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentStopCommand.java
new file mode 100644
index 0000000..d780bed
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFAgentStopCommand.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.ofagent.api.OFAgentAdminService;
+
+/**
+ * Stops the OFAgent.
+ */
+@Command(scope = "onos", name = "ofagent-stop", description = "Stops the ofagent")
+public class OFAgentStopCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "network", description = "Virtual network ID",
+ required = true, multiValued = false)
+ private long networkId = NetworkId.NONE.id();
+
+ @Override
+ protected void execute() {
+ OFAgentAdminService adminService = get(OFAgentAdminService.class);
+ adminService.stopAgent(NetworkId.networkId(networkId));
+ print("Successfully stopped OFAgent for network %s", networkId);
+ }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFSwitchListCommand.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFSwitchListCommand.java
new file mode 100644
index 0000000..c3e5714
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/OFSwitchListCommand.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.ofagent.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.ofagent.api.OFSwitch;
+import org.onosproject.ofagent.api.OFSwitchService;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Lists virtual OF switches.
+ */
+@Command(scope = "onos", name = "ofagent-switches", description = "Lists all OF switches")
+public class OFSwitchListCommand extends AbstractShellCommand {
+
+ private static final String FORMAT = "%-35s%-8s";
+
+ @Argument(index = 0, name = "network", description = "Virtual network ID",
+ required = false, multiValued = false)
+ private long networkId = NetworkId.NONE.id();
+
+ @Override
+ protected void execute() {
+ OFSwitchService service = get(OFSwitchService.class);
+
+ Set<OFSwitch> ofSwitches;
+ if (networkId != NetworkId.NONE.id()) {
+ ofSwitches = service.ofSwitches(NetworkId.networkId(networkId));
+ } else {
+ ofSwitches = service.ofSwitches();
+ }
+
+ print(FORMAT, "DPID", "Connected controllers");
+ ofSwitches.forEach(ofSwitch -> {
+ Set<String> channels = ofSwitch.controllerChannels().stream()
+ .map(channel -> channel.remoteAddress().toString())
+ .collect(Collectors.toSet());
+ print(FORMAT, ofSwitch.dpid(), channels);
+ });
+ }
+}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/package-info.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/package-info.java
new file mode 100644
index 0000000..b9761ce
--- /dev/null
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/cli/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * CLIs for administering OFAgents.
+ */
+package org.onosproject.ofagent.cli;
\ No newline at end of file
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFAgent.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFAgent.java
index cac1e03..586ce3a 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFAgent.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFAgent.java
@@ -17,6 +17,7 @@
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.ofagent.api.OFAgent;
import org.onosproject.ofagent.api.OFController;
@@ -96,23 +97,10 @@
return new Builder();
}
- /**
- * Returns new builder instance from the existing agent.
- *
- * @param ofAgent the existing agent
- * @return default ofagent builder
- */
- public static Builder builder(OFAgent ofAgent) {
- return new Builder()
- .networkId(ofAgent.networkId())
- .controllers(ofAgent.controllers())
- .state(ofAgent.state());
- }
-
public static final class Builder implements OFAgent.Builder {
private NetworkId networkId;
- private Set<OFController> controllers;
+ private Set<OFController> controllers = Sets.newHashSet();
private State state;
private Builder() {
@@ -128,6 +116,14 @@
}
@Override
+ public Builder from(OFAgent ofAgent) {
+ this.networkId = ofAgent.networkId();
+ this.controllers = Sets.newHashSet(ofAgent.controllers());
+ this.state = ofAgent.state();
+ return this;
+ }
+
+ @Override
public Builder networkId(NetworkId networkId) {
this.networkId = networkId;
return this;
@@ -140,6 +136,18 @@
}
@Override
+ public OFAgent.Builder addController(OFController controller) {
+ this.controllers.add(controller);
+ return this;
+ }
+
+ @Override
+ public OFAgent.Builder deleteController(OFController controller) {
+ this.controllers.remove(controller);
+ return this;
+ }
+
+ @Override
public Builder state(State state) {
this.state = state;
return this;
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentManager.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentManager.java
index ce7c30f..454f7d7 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentManager.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFAgentManager.java
@@ -67,6 +67,8 @@
private static final String MSG_CREATED = "created";
private static final String MSG_UPDATED = "updated";
private static final String MSG_REMOVED = "removed";
+ private static final String MSG_STARTED = "started";
+ private static final String MSG_STOPPED = "stopped";
private static final String MSG_IN_STARTED = "is already in active state, do nothing";
private static final String MSG_IN_STOPPED = "is already in inactive state, do nothing";
@@ -117,7 +119,9 @@
leadershipService.removeListener(leadershipListener);
virtualNetService.removeListener(virtualNetListener);
ofAgentStore.unsetDelegate(delegate);
- ofAgentStore.ofAgents().forEach(ofAgent -> stopAgent(ofAgent.networkId()));
+ ofAgentStore.ofAgents().stream()
+ .filter(ofAgent -> ofAgent.state() == STARTED)
+ .forEach(ofAgent -> stopAgent(ofAgent.networkId()));
eventExecutor.shutdown();
leadershipService.withdraw(appId.name());
@@ -132,6 +136,7 @@
log.warn(String.format(MSG_OFAGENT, ofAgent.networkId(), ERR_IN_USE));
return;
}
+ // TODO check if the virtual network exists
ofAgentStore.createOfAgent(ofAgent);
log.info(String.format(MSG_OFAGENT, ofAgent.networkId(), MSG_CREATED));
}
@@ -144,7 +149,7 @@
}
@Override
- public void removeAgent(NetworkId networkId) {
+ public OFAgent removeAgent(NetworkId networkId) {
checkNotNull(networkId, ERR_NULL_NETID);
synchronized (this) {
OFAgent existing = ofAgentStore.ofAgent(networkId);
@@ -156,8 +161,8 @@
final String error = String.format(MSG_OFAGENT, networkId, ERR_IN_USE);
throw new IllegalStateException(error);
}
- ofAgentStore.removeOfAgent(networkId);
log.info(String.format(MSG_OFAGENT, networkId, MSG_REMOVED));
+ return ofAgentStore.removeOfAgent(networkId);
}
}
@@ -171,11 +176,13 @@
throw new IllegalStateException(error);
}
if (existing.state() == STARTED) {
- log.warn(String.format(MSG_OFAGENT, networkId, MSG_IN_STARTED));
- return;
+ final String error = String.format(MSG_OFAGENT, networkId, MSG_IN_STARTED);
+ throw new IllegalStateException(error);
}
- OFAgent updated = DefaultOFAgent.builder(existing).state(STARTED).build();
+ OFAgent updated = DefaultOFAgent.builder()
+ .from(existing).state(STARTED).build();
ofAgentStore.updateOfAgent(updated);
+ log.info(String.format(MSG_OFAGENT, networkId, MSG_STARTED));
}
}
@@ -189,11 +196,13 @@
throw new IllegalStateException(error);
}
if (existing.state() == STOPPED) {
- log.warn(String.format(MSG_OFAGENT, networkId, MSG_IN_STOPPED));
- return;
+ final String error = String.format(MSG_OFAGENT, networkId, MSG_IN_STOPPED);
+ throw new IllegalStateException(error);
}
- OFAgent updated = DefaultOFAgent.builder(existing).state(STOPPED).build();
+ OFAgent updated = DefaultOFAgent.builder()
+ .from(existing).state(STOPPED).build();
ofAgentStore.updateOfAgent(updated);
+ log.info(String.format(MSG_OFAGENT, networkId, MSG_STOPPED));
}
}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFConnectionHandler.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFConnectionHandler.java
index ed897ff..5853c4a 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFConnectionHandler.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFConnectionHandler.java
@@ -19,6 +19,7 @@
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.onosproject.ofagent.api.OFController;
@@ -28,6 +29,7 @@
import java.net.InetSocketAddress;
import java.net.SocketAddress;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -94,6 +96,7 @@
MSG_CONNECTED,
controller.ip(),
controller.port()));
+ // FIXME add close future listener to handle connection lost
} else {
if (retryCount.getAndIncrement() > MAX_RETRY) {
log.warn(String.format(MSG_STATE,
@@ -102,7 +105,8 @@
controller.ip(),
controller.port()));
} else {
- this.connect();
+ final EventLoop loop = future.channel().eventLoop();
+ loop.schedule(this::connect, 1L, TimeUnit.SECONDS);
}
}
}
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java
index f522d68..9d58115 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java
@@ -24,13 +24,14 @@
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
-import org.onlab.util.Tools;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.LeadershipService;
import org.onosproject.cluster.NodeId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
@@ -66,6 +67,7 @@
import static com.google.common.base.Preconditions.checkArgument;
import static org.onlab.util.BoundedThreadPool.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.ofagent.api.OFAgent.State.STARTED;
import static org.onosproject.ofagent.api.OFAgentService.APPLICATION_NAME;
/**
@@ -77,7 +79,8 @@
private final Logger log = LoggerFactory.getLogger(getClass());
- private static final OFSwitchCapabilities DEFAULT_CAPABILITIES = DefaultOFSwitchCapabilities.builder()
+ private static final OFSwitchCapabilities DEFAULT_CAPABILITIES =
+ DefaultOFSwitchCapabilities.builder()
.flowStats()
.tableStats()
.portStats()
@@ -106,6 +109,7 @@
private final ExecutorService eventExecutor = newSingleThreadExecutor(
groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
private final OFAgentListener ofAgentListener = new InternalOFAgentListener();
+ private final VirtualNetworkListener vNetworkListener = new InternalVirtualNetworkListener();
private final DeviceListener deviceListener = new InternalDeviceListener();
private final FlowRuleListener flowRuleListener = new InternalFlowRuleListener();
private final PacketProcessor packetProcessor = new InternalPacketProcessor();
@@ -119,13 +123,17 @@
appId = coreService.registerApplication(APPLICATION_NAME);
localId = clusterService.getLocalNode().id();
ioWorker = new NioEventLoopGroup();
+
+ ofAgentService.agents().forEach(this::processOFAgentCreated);
ofAgentService.addListener(ofAgentListener);
+ virtualNetService.addListener(vNetworkListener);
log.info("Started");
}
@Deactivate
protected void deactivate() {
+ virtualNetService.removeListener(vNetworkListener);
ofAgentService.removeListener(ofAgentListener);
ofAgentService.agents().forEach(this::processOFAgentStopped);
@@ -149,21 +157,25 @@
return ImmutableSet.copyOf(ofSwitches);
}
- private void addOFSwitch(DeviceId deviceId) {
+ private void addOFSwitch(NetworkId networkId, DeviceId deviceId) {
OFSwitch ofSwitch = DefaultOFSwitch.of(
dpidWithDeviceId(deviceId),
DEFAULT_CAPABILITIES);
ofSwitchMap.put(deviceId, ofSwitch);
- log.debug("Added virtual OF switch for {}", deviceId);
- // TODO connect controllers if the agent is in started state
+ log.info("Added virtual OF switch for {}", deviceId);
+
+ OFAgent ofAgent = ofAgentService.agent(networkId);
+ if (ofAgent.state() == STARTED) {
+ connectController(ofSwitch, ofAgent.controllers());
+ }
}
private void deleteOFSwitch(DeviceId deviceId) {
- // TODO disconnect switch if it has active connection
- OFSwitch ofSwitch = ofSwitchMap.remove(deviceId);
- if (ofSwitch != null) {
- log.debug("Removed virtual OFSwitch for {}", deviceId);
- }
+ OFSwitch ofSwitch = ofSwitchMap.get(deviceId);
+ ofSwitch.controllerChannels().forEach(ChannelOutboundInvoker::disconnect);
+
+ ofSwitchMap.remove(deviceId);
+ log.info("Removed virtual OFSwitch for {}", deviceId);
}
private void connectController(OFSwitch ofSwitch, Set<OFController> controllers) {
@@ -174,25 +186,22 @@
ioWorker);
connectionHandler.connect();
});
- log.debug("Connection requested for {}, controller:{}", ofSwitch.dpid(), controllers);
}
private void disconnectController(OFSwitch ofSwitch, Set<OFController> controllers) {
Set<SocketAddress> controllerAddrs = controllers.stream()
- .map(ctrl -> new InetSocketAddress(ctrl.ip().toInetAddress(), ctrl.port().toInt()))
+ .map(ctrl -> new InetSocketAddress(
+ ctrl.ip().toInetAddress(), ctrl.port().toInt()))
.collect(Collectors.toSet());
ofSwitch.controllerChannels().stream()
.filter(channel -> controllerAddrs.contains(channel.remoteAddress()))
.forEach(ChannelOutboundInvoker::disconnect);
- log.debug("Disconnection requested for {}, controller:{}", ofSwitch.dpid(), controllers);
}
private Set<DeviceId> devices(NetworkId networkId) {
- DeviceService deviceService = virtualNetService.get(
- networkId,
- DeviceService.class);
- Set<DeviceId> deviceIds = Tools.stream(deviceService.getAvailableDevices())
+ Set<DeviceId> deviceIds = virtualNetService.getVirtualDevices(networkId)
+ .stream()
.map(Device::id)
.collect(Collectors.toSet());
return ImmutableSet.copyOf(deviceIds);
@@ -214,19 +223,13 @@
}
private void processOFAgentCreated(OFAgent ofAgent) {
- devices(ofAgent.networkId()).forEach(this::addOFSwitch);
- DeviceService deviceService = virtualNetService.get(
- ofAgent.networkId(),
- DeviceService.class);
- deviceService.addListener(deviceListener);
+ devices(ofAgent.networkId()).forEach(deviceId -> {
+ addOFSwitch(ofAgent.networkId(), deviceId);
+ });
}
private void processOFAgentRemoved(OFAgent ofAgent) {
devices(ofAgent.networkId()).forEach(this::deleteOFSwitch);
- DeviceService deviceService = virtualNetService.get(
- ofAgent.networkId(),
- DeviceService.class);
- deviceService.removeListener(deviceListener);
}
private void processOFAgentStarted(OFAgent ofAgent) {
@@ -237,6 +240,11 @@
}
});
+ DeviceService deviceService = virtualNetService.get(
+ ofAgent.networkId(),
+ DeviceService.class);
+ deviceService.addListener(deviceListener);
+
PacketService packetService = virtualNetService.get(
ofAgent.networkId(),
PacketService.class);
@@ -256,6 +264,11 @@
}
});
+ DeviceService deviceService = virtualNetService.get(
+ ofAgent.networkId(),
+ DeviceService.class);
+ deviceService.removeListener(deviceListener);
+
PacketService packetService = virtualNetService.get(
ofAgent.networkId(),
PacketService.class);
@@ -267,6 +280,43 @@
flowRuleService.removeListener(flowRuleListener);
}
+ private class InternalVirtualNetworkListener implements VirtualNetworkListener {
+
+ @Override
+ public void event(VirtualNetworkEvent event) {
+ switch (event.type()) {
+ case VIRTUAL_DEVICE_ADDED:
+ eventExecutor.execute(() -> {
+ log.debug("Virtual device {} added to network {}",
+ event.virtualDevice().id(),
+ event.subject());
+ addOFSwitch(event.subject(), event.virtualDevice().id());
+ });
+ break;
+ case VIRTUAL_DEVICE_UPDATED:
+ // TODO handle device availability updates
+ break;
+ case VIRTUAL_DEVICE_REMOVED:
+ eventExecutor.execute(() -> {
+ log.debug("Virtual device {} removed from network {}",
+ event.virtualDevice().id(),
+ event.subject());
+ deleteOFSwitch(event.virtualDevice().id());
+ });
+ break;
+ case NETWORK_UPDATED:
+ case NETWORK_REMOVED:
+ case NETWORK_ADDED:
+ case VIRTUAL_PORT_ADDED:
+ case VIRTUAL_PORT_UPDATED:
+ case VIRTUAL_PORT_REMOVED:
+ default:
+ // do nothing
+ break;
+ }
+ }
+ }
+
private class InternalOFAgentListener implements OFAgentListener {
@Override
@@ -323,24 +373,10 @@
@Override
public void event(DeviceEvent event) {
switch (event.type()) {
- case DEVICE_ADDED:
- eventExecutor.execute(() -> {
- Device device = event.subject();
- log.debug("Processing device added: {}", device);
- addOFSwitch(device.id());
- });
- break;
- case DEVICE_REMOVED:
- eventExecutor.execute(() -> {
- Device device = event.subject();
- log.debug("Processing device added: {}", device);
- deleteOFSwitch(device.id());
- });
- break;
case DEVICE_AVAILABILITY_CHANGED:
- // TODO handle event
- break;
+ case DEVICE_ADDED:
case DEVICE_UPDATED:
+ case DEVICE_REMOVED:
case DEVICE_SUSPENDED:
case PORT_ADDED:
// TODO handle event
diff --git a/apps/ofagent/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/ofagent/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 0000000..2b0fe65
--- /dev/null
+++ b/apps/ofagent/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,43 @@
+<!--
+~ Copyright 2017-present Open Networking Laboratory
+~
+~ Licensed under the Apache License, Version 2.0 (the "License");
+~ you may not use this file except in compliance with the License.
+~ You may obtain a copy of the License at
+~
+~ http://www.apache.org/licenses/LICENSE-2.0
+~
+~ Unless required by applicable law or agreed to in writing, software
+~ distributed under the License is distributed on an "AS IS" BASIS,
+~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~ See the License for the specific language governing permissions and
+~ limitations under the License.
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.ofagent.cli.OFAgentListCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.ofagent.cli.OFAgentCreateCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.ofagent.cli.OFAgentRemoveCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.ofagent.cli.OFAgentStartCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.ofagent.cli.OFAgentStopCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.ofagent.cli.OFAgentAddControllerCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.ofagent.cli.OFAgentDeleteControllerCommand"/>
+ </command>
+ <command>
+ <action class="org.onosproject.ofagent.cli.OFSwitchListCommand"/>
+ </command>
+ </command-bundle>
+</blueprint>