/**
* Copyright (c) <2013> <Radware Ltd.> and others. All rights reserved.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License
* v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
* @author Gera Goft
* @version 0.1
*/
package org.opendaylight.defense4all.cli;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.codehaus.jackson.type.TypeReference;
import org.opendaylight.defense4all.core.AMSConnection;
import org.opendaylight.defense4all.core.NetNode;
import org.opendaylight.defense4all.core.NetNode.SDNNodeMode;
import org.opendaylight.defense4all.core.ProtectedLink;
import org.opendaylight.defense4all.core.TrafficPort;
import org.opendaylight.defense4all.core.TrafficPort.PortLocation;
import org.opendaylight.defense4all.framework.core.Utils;
public class CliNetNode {
public static final String netnodeExplanation = "Netnode is an abstraction of a network location on which traffic "
+ "counters can be placed, and from which traffic is diverted (and in case of local diversion, returned) "
+ "to mitigation devices. Depending on the level of network abstraction a netnode can be a single switch, "
+ "an entry point to a logical network, or the complete logical network (including all entry points).";
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
protected static void displayUsageGetNetnodes() {
StringBuilder sb = new StringBuilder();
sb.append("Usage: controlapps getnetnodes\n");
sb.append(" Description - returns the netnodes known to DF.\n");
System.out.println(sb.toString());
}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
protected static void displayUsageGetNetnodesCount() {
StringBuilder sb = new StringBuilder();
sb.append("Usage: controlapps getnetnodescount\n");
sb.append(" Description - returns the number of netnodes known to DF.\n");
System.out.println(sb.toString());
}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
protected static void displayUsageGetNetnode() {
StringBuilder sb = new StringBuilder();
sb.append("Usage: controlapps getnetnode netnode_label\n");
sb.append(" Description - returns the netnode corresponding to specified netnode_label.\n");
System.out.println(sb.toString());
}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
protected static void displayUsageAddNetnode() {
StringBuilder sb = new StringBuilder();
sb.append("Bugged, please use curl instead!!!");//TODO: decide and use lower-case or camel-case, and fix the amslabel issue and parsing.
sb.append("Usage: controlapps addnetnode param1 param2 ... \n");
sb.append(" Description - adds the netnode described through the params.\n");
sb.append(" A params is formed -- field_name=field_value.\n");
sb.append(" A composite field is formed -- composite_field::sub_composite_field=sub_composite_field_value.\n");
sb.append(" I field in composite list element -- list_name::list_element_label::composite_field::sub_composite_field=value.\n");
sb.append(" The params are\n");
sb.append(" label - [mandatory] user provided unique textual label (starts with a letter) to this netnode.\n");
sb.append(" id - For OpenFlow NetNodes this is the DPID. For other netnodes left empty.\n");
sb.append(" type - NetNode type, currently only \"OF\" (for openflow), which is also the default if none provided.\n");
sb.append(" mgmtaddr - management address of the netnode. Currently unused.\n");
sb.append(" mgmtport - management port of the netnode. Currently unused.\n");
sb.append(" sdnnodemode - can be sdnenablednative [default] or sdnenabledhybrid.\n");
sb.append(" props - other custom properties. Each in the form:\n");
sb.append(" props::prop_name or props::prop_name=prop_value.\n");
sb.append(" ams connections - netnode connections to amss. Can be zero or more. Each connection is described through its fields, as follows:\n");
sb.append(" amsconnection::amslabel=label_value - [mandatory] ams connection unique label.\n");
sb.append(" amsconnection::amslabel=amslabel_value - [mandatory] label of the connected ams.\n");
sb.append(" amsconnection::amslabel::netnodenorthport=port_value - [mandatory] number of the north (closer to client) port in the netnode connected to the ams.\n");
sb.append(" amsconnection::amslabel::netnodesouthport=port_value - [mandatory] number of the south (closer to server) port in the netnode connected to the ams.\n");
sb.append(" amsconnection::amslabel::amsnorthport=port_value - [mandatory] number of the north port in the ams connected to the north port in the netnode.\n");
sb.append(" amsconnection::amslabel::amssouthport=port_value - [mandatory] number of the south port in the ams connected to the south port in the netnode.\n");
sb.append(" traffic ports - ports through which traffic flows north-south and south-north. Can be zero or more north-south ports. Each traffic port is described through its fields, as follows:\n");
sb.append(" trafficport::label=label_value - [mandatory] label of this traffic port.\n");
sb.append(" trafficport::label::number=number_value - [mandatory] number of the traffic port.\n");
sb.append(" trafficport::label::vlan=vlan_value - [mandatory] vlan to consider in this port.\n");
sb.append(" trafficport::label::location=location_value - [mandatory] Can be \"north\" (closer to client) or \"south\" (closer to server).\n");
sb.append(" protected links - links that should be considered for traffic protection. Can be zero or more protected links. Each protected link is described through its fields, as follows:\n");
sb.append(" protectedlink::label=label_value - [mandatory] label of this protected link.\n");
sb.append(" protectedlink::label::northport=port_value - [mandatory] number of the north traffic port.\n");
sb.append(" protectedlink::label::southport=port_value - [mandatory] number of the south traffic port.\n");
sb.append("Example: controlapps addnetnode label=ovs id=00:00:00:50:56:a3:1b:80 type=OF \n");
sb.append(" mgmtaddr=10.10.10.10 mgmtport=0 sdnnodemode=sdnenablednative \n");
sb.append(" props::example_prop=example_prop_value amsconnection::amslabel=ams1 \n");
sb.append(" amsconnection::ams1::netnodenorthport=2 amsconnection::ams1::netnodesouthport=3 \n");
sb.append(" amsconnection::ams1::amsnorthport=5 amsconnection::ams1::amssouthport=6 \n");
sb.append(" trafficport::label=tp1 trafficport::tp1::number=1 trafficport::tp1::vlan=0 trafficport::tp1::location=north \n");
sb.append(" trafficport::label=tp4 trafficport::tp4::number=4 trafficport::tp4::vlan=0 trafficport::tp4::location=south \n");
sb.append(" protectedlink::label=pl1 \n");
sb.append(" protectedlink::pl1::northport=1 protectedlink::pl1::southport=4");
System.out.println(sb.toString());
}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
protected static void displayUsageRemoveNetnode() {
StringBuilder sb = new StringBuilder();
sb.append("Usage: controlapps removenetnode netnode_label\n");
sb.append(" Description - removes the netnode corresponding to the netnode_label.");
System.out.println(sb.toString());
}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
protected static void handleGetNetNodes() {
List<NetNode> netNodes;
try {
Defense4allConnector connector = new Defense4allConnector(Cli.user, Cli.password);
TypeReference<?> typeRef = new TypeReference<List<NetNode>>(){};
netNodes = connector.getFromControlApps("netnodes", typeRef);
} catch (Exception e) {
System.out.println("Could not get netnodes because " + e.getMessage());
return;
}
if(netNodes == null || netNodes.isEmpty()) {
System.out.println("DF has no netnodes configured.");
return;
}
System.out.println("netnodes:\n");
for(NetNode netnode : netNodes) {
System.out.println(netnode.toString());
System.out.println("=================================");
}
}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
protected static void handleGetNetNodesCount() {
Integer count = 0;
try {
Defense4allConnector connector = new Defense4allConnector(Cli.user, Cli.password);
TypeReference<?> typeRef = new TypeReference<Integer>(){};
count = connector.getFromControlApps("netnodes/count", typeRef);
} catch (Exception e) {
System.out.println("Could not get netnodes count because " + e.getMessage());
return;
}
System.out.println("There are " + count + " netNodes known to DF.\n");
}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
protected static void handleGetNetNode(ArrayList<String> params) {
if(params == null || params.isEmpty()) {
displayUsageGetNetnode();
return;
}
String netNodeLabel = params.get(0);
if(netNodeLabel == null || netNodeLabel.isEmpty()) {
displayUsageGetNetnode();
return;
}
NetNode netNode;
try {
Defense4allConnector connector = new Defense4allConnector(Cli.user, Cli.password);
TypeReference<?> typeRef = new TypeReference<NetNode>(){};
netNode = connector.getFromControlApps("netnodes/" + netNodeLabel, typeRef);
String printOut = (netNode == null) ? "No netNode " + netNodeLabel + " is known to DF.\n" : netNode.toString();
System.out.println(printOut);
} catch (Exception e) {
System.out.println("Could not get netnode " + netNodeLabel + " because " + e.getMessage());
return;
}
}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
protected static void handleAddNetNode(ArrayList<String> params) {
if(params == null) {
displayUsageRemoveNetnode();
return;
}
NetNode netNode = new NetNode();
netNode.props = new Properties();
try {
for(String param : params) {
if(param.startsWith("label"))
addLabel(netNode, param);
else if(param.startsWith("id"))
addId(netNode, param);
else if(param.startsWith("type"))
addType(netNode, param);
else if(param.startsWith("mgmtaddr"))
addMgmtAddr(netNode, param);
else if(param.startsWith("mgmtport"))
addMgmtPort(netNode, param);
else if(param.startsWith("sdnnodemode"))
addSDNNodeMode(netNode, param);
else if(param.startsWith("props"))
addProp(netNode, param);
else if(param.startsWith("amsconnection"))
addAmsConnectionField(netNode, param);
else if(param.startsWith("trafficport"))
addTrafficPortField(netNode, param);
else if(param.startsWith("protectedlink"))
addProtectedLinkField(netNode, param);
}
netNode.toJacksonFriendly(); // Jackson does not handle lists with complex items. Let it inflate strings
// of those serialized lists, and inflate lists in "set" methods.
netNode.validate();
} catch (Throwable e1) {
System.out.println(e1.getMessage());
displayUsageAddNetnode();
return;
}
try {
Defense4allConnector connector = new Defense4allConnector(Cli.user, Cli.password);
System.out.println("Adding netnode " + netNode.label);
connector.postToControlApps("netnodes", netNode);
} catch (Exception e) {
System.out.println("Could not add netnode because " + e.getMessage());
}
}
protected static void addLabel(NetNode netNode, String param) throws Exception {
String[] split = Cli.splitAndAssertSize(param, "=");
netNode.label = split[1]; // Split "label=l1"
}
protected static boolean addId(NetNode netNode, String param) throws Exception {
String[] split = Cli.splitAndAssertSize(param, "=");
netNode.id = split[1]; // Split "id=00:00:00:50:56:a3:1b:80"
return true;
}
protected static void addType(NetNode netNode, String param) throws Exception {
String[] split = Cli.splitAndAssertSize(param, "=");
netNode.type = split[1]; // Split "type=OF"
}
protected static void addMgmtAddr(NetNode netNode, String param) throws Exception {
String[] split = Cli.splitAndAssertSize(param, "=");
netNode.mgmtAddr = split[1]; // Split "mgmtaddr=10.10.10.10"
}
protected static void addMgmtPort(NetNode netNode, String param) throws Exception {
String[] split = Cli.splitAndAssertSize(param, "=");
netNode.mgmtPort = Integer.valueOf(split[1]); // Split "mgmtport=0"
}
protected static void addSDNNodeMode(NetNode netNode, String param) throws Exception {
String[] split = Cli.splitAndAssertSize(param, "=");
netNode.sdnNodeMode = SDNNodeMode.valueOf(split[1]); // Split "sdnnodemode=sdnenablednative"
}
protected static void addProp(NetNode netNode, String param) throws Exception {
String[] split = Cli.splitAndAssertSize(param, "::"); // Split "props::example_prop=example_prop_value"
split = split[1].split("="); // Can be [example_prop] or [example_prop, example_prop_value]
if(split[0].isEmpty())
throw new Exception("Invalid property format - " + param);
String value = (split.length < 2) ? "" : split[1];
netNode.props.setProperty(split[0], value);
}
protected static void addAmsConnectionField(NetNode netNode, String param) throws Exception {
String[] split = Cli.splitAndAssertSize(param, "::");
if(split[1].startsWith("label"))
addAmsConnectionLabel(netNode, split[1]);
// else if(split[1].startsWith("amslabel"))
// addAmsConnectionAmsLabel(netNode, split[1], split[2]);
else if(split.length < 3 || split[1] == null || split[1].isEmpty())
throw new Exception("Invalid param " + param); // Other fields: amsconnection::label::field_name=field_value
else if(split[2].startsWith("amslabel"))
addAmsConnectionAmsLabel(netNode, split[1], split[2]);
else if(split[2].startsWith("netnodenorthport"))
addAmsConnectionNetnodeNorthPort(netNode, split[1], split[2]);
else if(split[2].startsWith("netnodesouthport"))
addAmsConnectionNetnodeSouthPort(netNode, split[1], split[2]);
else if(split[2].startsWith("amsnorthport"))
addAmsConnectionAmsNorthPort(netNode, split[1], split[2]);
else if(split[2].startsWith("amssouthport"))
addAmsConnectionAmsSouthPort(netNode, split[1], split[2]);
}
private static void addAmsConnectionLabel(NetNode netNode, String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
getCreateAmsConnection(netNode, split[1]); // Create if non existent
}
private static AMSConnection getCreateAmsConnection(NetNode netNode, String label) throws Exception {
AMSConnection amsConnection = netNode.amsConnections.get(label);
if(amsConnection == null) { // First field in this amsConnection
amsConnection = new AMSConnection();
amsConnection.label = label;
netNode.amsConnections.put(label, amsConnection);
}
return amsConnection;
}
private static void addAmsConnectionAmsLabel(NetNode netNode,String label,String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
String amsLabel = split[1];
if(amsLabel == null || amsLabel.isEmpty()) throw new Exception("Invalid amsLabel for amsconnection " + label);
AMSConnection amsConnection = getCreateAmsConnection(netNode, label);
amsConnection.amsLabel = split[1];
}
private static void addAmsConnectionNetnodeNorthPort(NetNode netNode,String label,String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
int port = Integer.valueOf(split[1]);
if(port == 0) throw new Exception("Invalid netnodenorthport (zero) for amsconnection " + label);
AMSConnection amsConnection = getCreateAmsConnection(netNode, label);
amsConnection.netNodeNorthPort = split[1];
}
private static void addAmsConnectionNetnodeSouthPort(NetNode netNode,String label,String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
int port = Integer.valueOf(split[1]);
if(port == 0) throw new Exception("Invalid netnodesouthport (zero) for amsconnection " + label);
AMSConnection amsConnection = getCreateAmsConnection(netNode, label);
amsConnection.netNodeSouthPort = split[1];
}
private static void addAmsConnectionAmsNorthPort(NetNode netNode, String label, String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
int port = Integer.valueOf(split[1]);
if(port == 0) throw new Exception("Invalid amsnorthport (zero) for amsconnection " + label);
AMSConnection amsConnection = getCreateAmsConnection(netNode, label);
amsConnection.amsNorthPort = port;
}
private static void addAmsConnectionAmsSouthPort(NetNode netNode, String label, String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
int port = Integer.valueOf(split[1]);
if(port == 0)
throw new Exception("Invalid amssouthport (zero) for amsconnection " + label);
AMSConnection amsConnection = getCreateAmsConnection(netNode, label);
amsConnection.amsSouthPort = port;
}
protected static void addTrafficPortField(NetNode netNode, String param) throws Exception {
String[] split = Cli.splitAndAssertSize(param, "::");
if(split[1].startsWith("label"))
addTrafficPortLabel(netNode, split[1]);
else if(split.length < 3 || split[1] == null || split[1].isEmpty())
throw new Exception("Invalid param " + param); // Other fields: trafficport::label::field_name=field_value
else if(split[2].startsWith("number"))
addTrafficPortNumber(netNode, split[1], split[2]);
else if(split[2].startsWith("vlan"))
addTrafficPortVlan(netNode, split[1], split[2]);
else if(split[2].startsWith("location"))
addTrafficPortLocation(netNode, split[1], split[2]);
}
private static void addTrafficPortLabel(NetNode netNode, String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
getCreateTrafficPort(netNode, split[1]); // Create if non existent
}
private static TrafficPort getCreateTrafficPort(NetNode netNode, String label) throws Exception {
TrafficPort trafficPort = netNode.trafficPorts.get(label);
if(trafficPort == null) { // First field in this trafficPort
trafficPort = new TrafficPort();
trafficPort.label = label;
netNode.trafficPorts.put(label, trafficPort);
}
return trafficPort;
}
private static void addTrafficPortNumber(NetNode netNode, String label, String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
short number = Short.valueOf(split[1]);
if(number == 0) throw new Exception("Invalid number (zero) for trafficport" + label);
TrafficPort trafficPort = getCreateTrafficPort(netNode, label);
trafficPort.number = number;
}
private static void addTrafficPortVlan(NetNode netNode, String label, String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
short vlan = Short.valueOf(split[1]);
TrafficPort trafficPort = getCreateTrafficPort(netNode, label);
trafficPort.vlan = vlan;
}
private static void addTrafficPortLocation(NetNode netNode, String label, String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
PortLocation location = PortLocation.valueOf(split[1]);
TrafficPort trafficPort = getCreateTrafficPort(netNode, label);
trafficPort.location = location;
}
protected static void addProtectedLinkField(NetNode netNode, String param) throws Exception {
String[] split = Cli.splitAndAssertSize(param, "::");
if(split[1].startsWith("label"))
addProtectedLinkLabel(netNode, split[1]);
else if(split.length < 3 || split[1] == null || split[1].isEmpty())
throw new Exception("Invalid param " + param); // Other fields: protectedlink::label::field_name=field_value
else if(split[2].startsWith("northport"))
addProtectedLinkNorthPort(netNode, split[1], split[2]);
else if(split[2].startsWith("southport"))
addProtectedLinkSouthPort(netNode, split[1], split[2]);
}
private static void addProtectedLinkLabel(NetNode netNode, String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
getCreateProtectedLink(netNode, split[1]); // Create if non existent
}
private static ProtectedLink getCreateProtectedLink(NetNode netNode, String label) throws Exception {
ProtectedLink protectedLink = netNode.protectedLinks.get(label);
if(protectedLink == null) { // First field in this protectedLink
protectedLink = new ProtectedLink();
protectedLink.label = label;
netNode.protectedLinks.put(label, protectedLink);
}
return protectedLink;
}
private static void addProtectedLinkNorthPort(NetNode netNode, String label, String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
short port = Short.valueOf(split[1]);
if(port == 0) throw new Exception("Invalid northport (zero) for protectedlink" + label);
ProtectedLink protectedLink = getCreateProtectedLink(netNode, label);
protectedLink.northPort = port;
}
private static void addProtectedLinkSouthPort(NetNode netNode, String label, String nameValStr) throws Exception {
String[] split = Cli.splitAndAssertSize(nameValStr, "=");
short port = Short.valueOf(split[1]);
if(port == 0) throw new Exception("Invalid southport (zero) for protectedlink" + label);
ProtectedLink protectedLink = getCreateProtectedLink(netNode, label);
protectedLink.southPort = port;
}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
protected static void handleRemoveNetNode(ArrayList<String> params) {
if(params == null || params.isEmpty()) {
displayUsageRemoveNetnode();
return;
}
String netNodeLabel = params.get(0);
if(netNodeLabel == null || netNodeLabel.isEmpty()) {
displayUsageRemoveNetnode();
return;
}
String msg = "Are you sure you want to remove netnode " + netNodeLabel + "? Please confirm with [yes, Yes or Y].";
boolean confirmed = Utils.confirmYesByUser(msg);
if(!confirmed) return;
try {
Defense4allConnector connector = new Defense4allConnector(Cli.user, Cli.password);
connector.delFromControlApps("netnodes/" + netNodeLabel);
} catch (Exception e) {
System.out.println("Could not remove netnode " + netNodeLabel + " because " + e.getMessage());
}
System.out.println("Initiating removal of netnode " + netNodeLabel);
}
}