/**
* 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.odl;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.mina.filter.firewall.Subnet;
import org.opendaylight.defense4all.core.AMSConnection;
import org.opendaylight.defense4all.core.DFAppRoot;
import org.opendaylight.defense4all.core.Mitigation;
import org.opendaylight.defense4all.core.DvsnRep;
import org.opendaylight.defense4all.core.NetNode;
import org.opendaylight.defense4all.core.PN;
import org.opendaylight.defense4all.core.PN.MitigationScope;
import org.opendaylight.defense4all.core.ProtectedLink;
import org.opendaylight.defense4all.core.ProtocolPort.DFProtocol;
import org.opendaylight.defense4all.core.Traffic.TrafficDirection;
import org.opendaylight.defense4all.core.TrafficFloor;
import org.opendaylight.defense4all.core.NetNode.SDNNodeMode;
import org.opendaylight.defense4all.core.DvsnInfo;
import org.opendaylight.defense4all.core.ProtocolPort;
import org.opendaylight.defense4all.core.TrafficPort;
import org.opendaylight.defense4all.core.TrafficPort.PortLocation;
import org.opendaylight.defense4all.core.interactionstructures.NetNodeUppedDownedAMSConns;
import org.opendaylight.defense4all.framework.core.ExceptionControlApp;
import org.opendaylight.defense4all.framework.core.FrameworkMain.ResetLevel;
import org.opendaylight.defense4all.framework.core.HealthTracker;
import org.opendaylight.defense4all.odl.pojos.FlowConfigNoProtocol.ActionType;
public class OdlDvsnRep extends DvsnRep {
Odl odl = null;
Logger log = LoggerFactory.getLogger(this.getClass());
/* Constructor for Spring */
public OdlDvsnRep() {
super();
}
/* Setters for Spring */
public void setOdl(Odl odl) {this.odl = odl;}
/** Post-constructor initialization */
@Override
public void init() throws ExceptionControlApp {
super.init();
odl.init();
}
/** Pre-shutdown cleanup */
@Override
public void finit() {
super.finit();
odl.finit();
}
/** Reset
* @throws ExceptionControlApp */
@Override
public void reset(ResetLevel resetLevel) throws ExceptionControlApp {
super.reset(resetLevel);
odl.reset(resetLevel);
}
@Override
protected void initConnectionToOFC(String ofcKey) throws ExceptionControlApp {
odl.initConnectionToOFC(ofcKey);
odl.retrieveTopology(ofcKey);
}
/**
* ####
* @param param_name param description
* @return return description
* @throws ExceptionControlApp
* @throws exception_type circumstances description
*/
@Override
public void addNetNode(String netNodeKey) throws ExceptionControlApp {
odl.addNetNode(netNodeKey);
}
/**
* ####
* @param param_name param description
* @return return description
* @throws ExceptionControlApp
* @throws exception_type circumstances description
*/
@Override
public void removeNetNode(String netNodeKey) throws ExceptionControlApp {
// TODO: add checks and returns similar to NEC
odl.removeNetNode(netNodeKey);
}
public void test(Properties props) {}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
@Override
public void removeOFC(String ofcKey) {
// Reuse/extend super class implementation
}
/**
* #### method description ####
* @param param_name param description
* @return return Properties object containing diversion properties. If the traffic to the passed in protected object can not be diverted
* to the passed in DPis (in terms of network capacity, addressing and other constraints) then null is returned.
* @throws exception_type circumstances description
*/
@Override
public Properties getDvsnProps(String pnKey, String netNodeLabel, String amsConnKey) {
// Can check diversion links capacity and current load with respect to the diverted traffic size,
// constraints with respect to other diverted traffics.
NetNode netNode;
try {
Hashtable<String,Object> netNodeRow = dfAppRoot.netNodesRepo.getRow(netNodeLabel);
if(netNodeRow == null || NetNode.isRemoved(netNodeLabel)) return null;
netNode = new NetNode(netNodeRow);
} catch (ExceptionControlApp e) {
log.error("Excepted trying to inflate netNode " + netNodeLabel, e);
fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, "Failed to get diversion properties for " + pnKey
+ " from NetNode " + netNodeLabel + " to AMS " + amsConnKey);
return null;
}
/* If the ams is directly connected to the netNode, then local diversion is possible. Otherwise not. */
if(netNode.amsConnections == null || !netNode.amsConnections.containsKey(amsConnKey))
return null;
return new Properties();
}
/**
* Set diversion in the OF network
* @param param_name param description
* @return return description
* @throws ExceptionControlApp
* @throws exception_type circumstances description
*/
@Override
public String divert(String mitigationKey, String dvsnInfoKey) throws ExceptionControlApp {
Mitigation mitigation; DvsnInfo dvsnInfo; NetNode netNode; PN pn; TrafficFloor tFloor;
boolean success; DFProtocol protoToDivert; AMSConnection amsConn; String amsConnLabel;
try {
Hashtable<String, Object> mitigationRow = dfAppRoot.mitigationsRepo.getRow(mitigationKey);
mitigation = new Mitigation(mitigationRow);
Hashtable<String,Object> dvsnInfoRow = dfAppRoot.dvsnInfosRepo.getRow(dvsnInfoKey);
dvsnInfo = new DvsnInfo(dvsnInfoRow);
Hashtable<String, Object> netNodeRow = dfAppRoot.netNodesRepo.getRow(dvsnInfo.netNodeLabel);
if(netNodeRow == null || NetNode.isRemoved(dvsnInfo.netNodeLabel)) {
log.warn("NetNode " + dvsnInfo.netNodeLabel + " specified for PN " + mitigation.pnKey + " is not known to Defense4All");
return null;
}
netNode = new NetNode(netNodeRow); // NetNode in which to install diversion flow entries
Hashtable<String, Object> pnRow = dfAppRoot.pNsRepo.getRow(mitigation.pnKey);
pn = new PN(pnRow);
tFloor = new TrafficFloor();
tFloor.pnKey = mitigation.pnKey;
tFloor.nodeLabel = netNode.label;
tFloor.nodeId = netNode.id;
amsConnLabel = dvsnInfo.amsDvsnInfos.get(0).label;
amsConn = netNode.amsConnections.get(amsConnLabel); // Connection to diversion AMS
if(amsConn == null) {
String msg = "Internal DF inconsistency - NetNode AMSConnection does not contain the AMSConnection " +
" specified in DvsnInfo. DF Reset is advised. " + dvsnInfoKey;
log.error(msg);
fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, "OdlDvsnRep failed to divert traffic for mitigation "
+ mitigationKey + " , and according to diversion information " + dvsnInfoKey);
fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE);
return null;
}
tFloor.floorBase = getAvailableDvsnFloor(tFloor.nodeLabel, tFloor.pnKey, mitigation.protocolPort.protocol);
tFloor.floorCurrentHeight = tFloor.floorBase;
String trafficFloorKey = tFloor.generateAndSetKey();
/* Check if we already added this diversion traffic floor. Can be if the application is restarted
* and attacked traffic diversion is re-requested. */
Hashtable<String,Object> trafficFloorRow = dfAppRoot.trafficFloorsRepo.getRow(trafficFloorKey);
if(trafficFloorRow != null) {
String msg = "Suitable diversion traffic floor exists for " + pn.label + ", mitigation " + mitigationKey
+ ", diversion information " + dvsnInfoKey + ". Most likely DF was restarted during an active attack.";
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY, msg);
return trafficFloorKey;
}
} catch (Throwable e) {
String msg = "Excepted retrieving/reconstructing relevant info from repos " + mitigationKey + " " + dvsnInfoKey;
log.error(msg, e);
fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, "OdlDvsnRep failed to divert traffic for mitigation "
+ mitigationKey + " , and according to diversion information " + dvsnInfoKey);
fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE);
throw new ExceptionControlApp(msg, e);
}
/* Prepare configInfo common template to be duplicated and adjusted in called methods.
* Per mitigation scope - divert either all traffic of attacked PN or only traffic of attacked protocol */
OdlFlowConfigInfo ciTemplate = new OdlFlowConfigInfo();
ciTemplate.nodeLabel = netNode.label; ciTemplate.etherType = 2048;
ciTemplate.actions = new ArrayList<String>();
ciTemplate.forTrafficLearning = false; // None of the flow entries in this floor is for traffic learning
/* Set protocol if only attacked protocol traffic should be diverted (rather than all PN traffic), and
* the protocol is not IP (rest of the traffic). */
if(pn.mitigationScope == MitigationScope.ATTACKED) {
protoToDivert = mitigation.protocolPort.protocol;
if(mitigation.protocolPort.protocol != DFProtocol.IP)
ciTemplate.protocol = mitigation.protocolPort.protocol.getProtocolNumber();
} else
protoToDivert = DFProtocol.INVALID;
try {
StringBuilder sb = new StringBuilder();
sb.append("Diverting traffic for pn="); sb.append(pn.label);
if(pn.mitigationScope == MitigationScope.ATTACKED) {
sb.append(", protocol="); sb.append(mitigation.protocolPort.protocol);
if(mitigation.protocolPort.port != 0) {
sb.append(", protocol="); sb.append(mitigation.protocolPort.protocol);
}
} else {
sb.append(" - all traffic");
}
sb.append(", according to mitigationKey="); sb.append(mitigationKey);
sb.append(", and diversionInfoKey="); sb.append(dvsnInfoKey);
sb.append(". diversionInfoKey="); sb.append(dvsnInfoKey);
sb.append(". Diverting from NetNode="); sb.append(netNode.label);
sb.append(" through AMSConnection="); sb.append(amsConnLabel);
sb.append(". The diversion is "); sb.append(pn.symmetricDvsn ? "symmetric" : "asymmetric");
sb.append(". Diversion traffic floor key="); sb.append(tFloor.key);
sb.append(", floor number="); sb.append(tFloor.floorBase);
sb.append(", floor current height="); sb.append(tFloor.floorCurrentHeight);
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY, sb.toString());
/* Set diversion flow entries for traffic to protected object to flow through mitigating DP */
success = addReturnPath(tFloor, netNode, amsConn, TrafficDirection.INBOUND, ciTemplate);
success &= addDvsnPath(pn, tFloor, netNode, amsConn, TrafficDirection.INBOUND, ciTemplate, protoToDivert);
/* In case of symmetric diversion divert also the returning traffic from protected object through same DP */
if(pn.symmetricDvsn) {
success &= addReturnPath(tFloor, netNode, amsConn, TrafficDirection.OUTBOUND,ciTemplate);
success &= addDvsnPath(pn,tFloor,netNode, amsConn, TrafficDirection.OUTBOUND,ciTemplate, protoToDivert);
}
if(! success) { // If any of the diversion parts failed cancel all other parts of this diversion
fMain.getFR().logRecord(DFAppRoot.FR_OFC_FAILURE, "Failed to divert traffic for mitigation="
+ mitigationKey + ". Removing any installed flow entries in this traffic floor.");
odl.removeTrafficFloor(tFloor);
return null;
}
/* record the complemented diversion information in diversions repo */
dfAppRoot.mitigationsRepo.setRow(mitigationKey, mitigation.toRow());
dfAppRoot.trafficFloorsRepo.setRow(tFloor.key, tFloor.toRow());
return tFloor.key;
} catch (Throwable e) {
try {
fMain.getFR().logRecord(DFAppRoot.FR_OFC_FAILURE, "Failed to divert traffic for mitigation="
+ mitigationKey + ". Removing any installed flow entries in this traffic floor.");
odl.removeTrafficFloor(tFloor);
} catch (ExceptionControlApp e1) {
String msg = "Excepted cleaning up traffic floor after failure to install " + tFloor.key;
log.error(msg);
fMain.getFR().logRecord(DFAppRoot.FR_OFC_FAILURE, msg);
}
String msg = "Failed to create diversion for " + tFloor.toString();
log.error(msg, e);
fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE);
throw new ExceptionControlApp(msg, e);
}
}
/* Add returning flow entries down. */
protected boolean addReturnPath(TrafficFloor tFloor, NetNode netNode, AMSConnection amsConn, TrafficDirection direction,
OdlFlowConfigInfo configInfoTemplate) {
OdlFlowConfigInfo configInfoTemplateClone = new OdlFlowConfigInfo(configInfoTemplate);
configInfoTemplateClone.forRates = false; // Don't monitor oubound traffic - only inbound (to servers)
configInfoTemplateClone.direction = direction;
boolean inBoundTraffic = (direction == TrafficDirection.INBOUND);
boolean success = false;
/* For inbound traffic set return path flow from southToAms port. For outbound traffic - from northToAms port */
String portStr = (inBoundTraffic ? amsConn.netNodeSouthPort : amsConn.netNodeNorthPort);
configInfoTemplateClone.ingressPort = Short.valueOf(portStr);
if(netNode.sdnNodeMode == SDNNodeMode.sdnenabledhybrid) { // hybrid switch - action is "send to normal"
StringBuilder sb = new StringBuilder();
sb.append("adding diversion return path for traffic floor key="); sb.append(tFloor.key);
sb.append(" in direction "); sb.append(direction);
sb.append(" from SDN hybrid NetNode="); sb.append(netNode.label);
sb.append(" through AMS "); sb.append(amsConn.toString());
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY, sb.toString());
OdlFlowConfigInfo configInfo = new OdlFlowConfigInfo(configInfoTemplateClone);
configInfo.actions.add(ActionType.HW_PATH.name()); // "Send to normal" (non-OF routing)
configInfo.floor = tFloor.floorCurrentHeight++;
configInfo.id = odl.getUniqueCookie();
success = odl.setFlowEntry(configInfo, tFloor);
if(!success)
fMain.getFR().logRecord(DFAppRoot.FR_OFC_FAILURE, "Failed " + sb.toString());
return success;
} else { // native switch - send to output traffic port with matching destination mac
Iterator<Map.Entry<String,ProtectedLink>> iter = netNode.protectedLinks.entrySet().iterator();
if(netNode.protectedLinks == null) {
log.error("Got null protectedLinks in netNode " + netNode);
fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
return false;
}
ProtectedLink protectedLink; OdlFlowConfigInfo configInfo; String action; short outPort = 0;
boolean anyMacs = false; Map.Entry<String,ProtectedLink> entry;
StringBuilder sb = new StringBuilder();
while(iter.hasNext()) {
entry = iter.next();
protectedLink = entry.getValue();
if(protectedLink == null) {
log.error("Got null protectedLink value for in netNode " + entry.getKey());
fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
return false;
}
configInfo = new OdlFlowConfigInfo(configInfoTemplateClone);
configInfo.id = odl.getUniqueCookie();
configInfo.generateAndSetKey();
/* Determine to which port to route the traffic returning from AMS. The output traffic port has to
* match the input traffic port (protectedLink) otherwise MAC learning will be screwed. Because the
* output traffic port is lost in packets returning from AMS device we must use another mechanism
* to determine the input port. We can only identify the input port by the MAC of the device
* connected to north port - which still appears in the packet. We assume a topology in which there
* is a single router connected to north port, and learn it. Then, for inbound traffic we match the
* source mac, and for outbound traffic we match the destination mac. */
if(inBoundTraffic) {
configInfo.dlSrc = protectedLink.macOfConnectedToNorthPort;
outPort = protectedLink.southPort;
} else {
configInfo.dlDst = protectedLink.macOfConnectedToNorthPort;
outPort = protectedLink.northPort;
}
if(protectedLink.macOfConnectedToNorthPort == null || protectedLink.macOfConnectedToNorthPort.isEmpty())
continue; // Will set a single flow entry if no MACs are set. Usable for single north port topology.
anyMacs = true;
sb.setLength(0);
sb.append("adding diversion return path for traffic floor key="); sb.append(tFloor.key);
sb.append(" in direction "); sb.append(direction);
sb.append(" from SDN native NetNode="); sb.append(netNode.label);
sb.append(" through AMS "); sb.append(amsConn.toString());
sb.append("Setting "); sb.append(inBoundTraffic ? "source" : "destination");
sb.append(" MAC filter of north connected Network element to ");
sb.append(protectedLink.macOfConnectedToNorthPort);
sb.append(". Outputting to port "); sb.append(outPort);
sb.append(". Generated cookie (id)="); sb.append(configInfo.id);
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY, sb.toString());
action = ActionType.OUTPUT.name() + "=" + outPort; // Send to matching out port
if(configInfo.actions == null)
configInfo.actions = new ArrayList<String>(); // Just in case it was not created
configInfo.actions.add(action);
configInfo.floor = tFloor.floorCurrentHeight++;
success |= odl.setFlowEntry(configInfo, tFloor);
if(!success)
fMain.getFR().logRecord(DFAppRoot.FR_OFC_FAILURE, "Failed " + sb.toString());
}
if(!anyMacs && outPort != 0) { // Support topology with single NB port with no MACs learned of connected devices
if(netNode.protectedLinks.size() > 1) return false; // Cannot return traffic to the wrong output port
configInfo = new OdlFlowConfigInfo(configInfoTemplateClone);
configInfo.id = odl.getUniqueCookie();
configInfo.generateAndSetKey();
action = ActionType.OUTPUT.name() + "=" + outPort; // Send to sole out port
if(configInfo.actions == null)
configInfo.actions = new ArrayList<String>(); // Just in case it was not created
configInfo.actions.add(action);
configInfo.floor = tFloor.floorCurrentHeight++;
sb.setLength(0);
sb.append("adding diversion return path for traffic floor key="); sb.append(tFloor.key);
sb.append(" in direction "); sb.append(direction);
sb.append(" from SDN native NetNode="); sb.append(netNode.label);
sb.append(" through AMS "); sb.append(amsConn.toString());
sb.append("Setting "); sb.append(inBoundTraffic ? "source" : "destination");
sb.append(". Outputting to port "); sb.append(outPort);
sb.append(". Generated cookie (id)="); sb.append(configInfo.id);
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY, sb.toString());
success |= odl.setFlowEntry(configInfo, tFloor);
if(!success)
fMain.getFR().logRecord(DFAppRoot.FR_OFC_FAILURE, "Failed " + sb.toString());
}
return success;
}
}
/* Add flow entries to divert traffic into mitigating DP. */
protected boolean addDvsnPath(PN pn, TrafficFloor tFloor, NetNode netNode, AMSConnection amsConn,
TrafficDirection direction, OdlFlowConfigInfo configInfoTemplate, DFProtocol protocolToDivert) {
boolean success = false;
OdlFlowConfigInfo configInfoTemplateClone = new OdlFlowConfigInfo(configInfoTemplate);
configInfoTemplateClone.firstToDelete = true; // Diversion flow entries should be deleted first to avoid packet loss
boolean inBoundTraffic = (direction == TrafficDirection.INBOUND);
configInfoTemplateClone.direction = direction;
configInfoTemplateClone.forRates = (inBoundTraffic == true);
StringBuilder sb = new StringBuilder();
/* Set the pnAddr filter - either as destination match or as source match - depending on traffic direction */
try {
String dstAddrStr = (String) dfAppRoot.pNsRepo.getCellValue(pn.label, PN.DST_ADDR);
int dstAddrLen = (Integer) dfAppRoot.pNsRepo.getCellValue(pn.label, PN.DST_ADDR_PREFIX_LEN);
Subnet pnAddrSubnet = new Subnet(InetAddress.getByName(dstAddrStr), dstAddrLen);
if(inBoundTraffic)
configInfoTemplateClone.nwDst = pnAddrSubnet.toString();
else
configInfoTemplateClone.nwSrc = pnAddrSubnet.toString();
} catch (Throwable e) {
log.error("Excepted trying to get PN destination address from repo for " + pn.label);
fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
return false;
}
String portStr = (inBoundTraffic ? amsConn.netNodeNorthPort : amsConn.netNodeSouthPort);
int portToAms = Short.valueOf(portStr);
String divertAction = ActionType.OUTPUT.name() + "=" + portToAms; // E.g., "OUTPUT=2"
PortLocation relevantPortLoc = inBoundTraffic ? PortLocation.north : PortLocation.south;
/* 1) "Rest of traffic" diversion - send {TCP,UDP,ICMP} traffic to matching output port. "Rest of traffic" - to AMS.
* 2) Any other protocol diversion - divert traffic of that to AMS.
* 3) All traffic diversion - divert all traffic to AMS. */
if(protocolToDivert == DFProtocol.IP) { // Case 1 above
sb.append("adding diversion path for traffic floor key="); sb.append(tFloor.key);
sb.append(" in direction "); sb.append(direction);
sb.append(" of \"other\" (non TCP, UDP or ICMP) traffic "); sb.append(protocolToDivert);
sb.append(" from NetNode="); sb.append(netNode.label);
sb.append(" through AMS "); sb.append(amsConn.toString());
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY, sb.toString());
if(netNode.protectedLinks == null) {
log.error("Got null protectedLinks in netNode " + netNode);
fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
return false;
}
Iterator<Map.Entry<String,ProtectedLink>> iter = netNode.protectedLinks.entrySet().iterator();
ProtectedLink protectedLink; String normalFlowAction; short ingressPort; short dvsnPort;
while(iter.hasNext()) {
protectedLink = iter.next().getValue();
if(inBoundTraffic) {
ingressPort = protectedLink.northPort;
dvsnPort = protectedLink.southPort; // E.g., "OUTPUT=3"
} else {
ingressPort = protectedLink.southPort;
dvsnPort = protectedLink.northPort; // E.g., "OUTPUT=1"
}
normalFlowAction = ActionType.OUTPUT.name() + "=" + dvsnPort;
sb.setLength(0);
sb.append("adding diversion path for ingress port="); sb.append(ingressPort);
sb.append(". TCP, UDP, ICMP traffic is send normally to "); sb.append(dvsnPort);
sb.append(", \"other\" traffic is diverted to AMS via port="); sb.append(portToAms);
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY, sb.toString());
/* Add OTHER flow entry - divert to AMS - This flow entry needs to have the lowest priority. As such
* it is added first, every set bumps up the priority */
success |= setFlowEntry(configInfoTemplateClone, tFloor, ingressPort, DFProtocol.IP.getProtocolNumber(),
divertAction);
/* Now add flows with no diversion - for all other protocols */
success |= setFlowEntry(configInfoTemplateClone, tFloor, ingressPort, DFProtocol.UDP.getProtocolNumber(),
normalFlowAction); // Add UDP flow entry - normal flow to output
success |= setFlowEntry(configInfoTemplateClone, tFloor, ingressPort, DFProtocol.ICMP.getProtocolNumber(),
normalFlowAction); // Add ICMP flow entry - normal flow to output
success |= setFlowEntry(configInfoTemplateClone, tFloor, ingressPort, DFProtocol.TCP.getProtocolNumber(),
normalFlowAction); // Add TCP flow entry - normal flow to output
if(!success)
fMain.getFR().logRecord(DFAppRoot.FR_OFC_FAILURE, "Failed " + sb.toString());
}
} else { // cases 2 and 3 above
if(netNode.trafficPorts == null) {
String msg = "Got null trafficPorts in netNode " + netNode;
log.error(msg);
fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
return false;
}
Iterator<Map.Entry<String,TrafficPort>> iter = netNode.trafficPorts.entrySet().iterator();
TrafficPort trafficPort; Map.Entry<String,TrafficPort> entry;
sb.append("adding diversion path for traffic floor key="); sb.append(tFloor.key);
sb.append(" in direction "); sb.append(direction);
sb.append(" of protocol="); sb.append(protocolToDivert);
sb.append(" from NetNode="); sb.append(netNode.label);
sb.append(" through AMS "); sb.append(amsConn.toString());
sb.append(", via port "); sb.append(portToAms);
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY, sb.toString());
while(iter.hasNext()) {
entry = iter.next();
trafficPort = entry.getValue();
if(trafficPort == null) {
log.error("Got null trafficPort value for in netNode " + entry.getKey());
fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
return false;
}
if(trafficPort.location != relevantPortLoc) continue;
sb.setLength(0);
sb.append("adding diversion path from traffic port="); sb.append(trafficPort.toString());
sb.append(" to AMS via port="); sb.append(portToAms);
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY, sb.toString());
success |= setFlowEntry(configInfoTemplateClone, tFloor, trafficPort.number,
protocolToDivert.getProtocolNumber(), divertAction);
if(!success)
fMain.getFR().logRecord(DFAppRoot.FR_OFC_FAILURE, "Failed " + sb.toString());
}
}
return success;
}
protected boolean setFlowEntry(OdlFlowConfigInfo clone, TrafficFloor tFloor, short ingressPort, short protocol,
String action) {
OdlFlowConfigInfo configInfo = new OdlFlowConfigInfo(clone);
configInfo.ingressPort = ingressPort;
configInfo.actions.add(action);
configInfo.id = odl.getUniqueCookie();
configInfo.generateAndSetKey();
configInfo.protocol = protocol;
configInfo.floor = (short) (tFloor.floorCurrentHeight++);
boolean success = odl.setFlowEntry(configInfo, tFloor);
return success;
}
/**
* #### method description ####
* @param param_name param description
* @return return description
* @throws exception_type circumstances description
*/
@Override
public void endDvsn(String mitigationKey, String tFloorKey) {
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY, "Ending diversion for dvsnKey=" + mitigationKey
+ ", trafficFloorKey=" + tFloorKey);
try {
Hashtable<String,Object> mitigationRow = dfAppRoot.mitigationsRepo.getRow(mitigationKey);
String pnKey = (String) mitigationRow.get(Mitigation.PNKEY);
ProtocolPort protocolPort = new ProtocolPort((String) mitigationRow.get(Mitigation.PROTOCOL_PORT));
log.info("defense4all is canceling traffic diversion for " + pnKey + " " + protocolPort.toString() + "!");
} catch (Throwable e1) {/* Ignore */}
try {
odl.removeTrafficFloor(tFloorKey);
} catch (Throwable e) {
log.error("Excepted trying to remove diversion traffic floor for " + tFloorKey, e);
fMain.getFR().logRecord(DFAppRoot.FR_DF_SECURITY,"Failed to properly end diversion for trafficFloorKey="+tFloorKey);
}
}
@Override
public DvsnInfo prepareForDvsn(String mitigationKey, String dvsnInfoKey) {return new DvsnInfo(dvsnInfoKey);}
@Override
public DvsnInfo unprepareForDvsn(String mitigationKey, String dvsnInfoKey) {return new DvsnInfo(dvsnInfoKey);}
@Override
public void notifyNetNodeAMSConnStatusChanged(NetNodeUppedDownedAMSConns netNodeUppedDownedAMSConn2) {}
@Override
protected void actionSwitcher(int actionCode, Object param) {}
}