/** * 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 * @author Konstantin Pozdeev * @version 0.1 */ package org.opendaylight.defense4all.core.impl; import java.util.*; import org.opendaylight.defense4all.core.AMS; import org.opendaylight.defense4all.core.AMSConnection; import org.opendaylight.defense4all.core.AMSRep; import org.opendaylight.defense4all.core.Attack; import org.opendaylight.defense4all.core.CounterStat; import org.opendaylight.defense4all.core.DFAppRoot; import org.opendaylight.defense4all.core.DFHolder; import org.opendaylight.defense4all.core.DFMgmtPoint; import org.opendaylight.defense4all.core.Detection; import org.opendaylight.defense4all.core.DetectorMgr; import org.opendaylight.defense4all.core.DetectorInfo; import org.opendaylight.defense4all.core.FlowConfigInfo; import org.opendaylight.defense4all.core.Mitigation; import org.opendaylight.defense4all.core.DvsnRep; import org.opendaylight.defense4all.core.MitigationDriver; import org.opendaylight.defense4all.core.MitigationMgr; import org.opendaylight.defense4all.core.NetNode; import org.opendaylight.defense4all.core.DvsnInfo; import org.opendaylight.defense4all.core.OFC; import org.opendaylight.defense4all.core.PN; import org.opendaylight.defense4all.core.PO; import org.opendaylight.defense4all.core.StatsCollectionRep; import org.opendaylight.defense4all.core.TrafficFloor; import org.opendaylight.defense4all.core.interactionstructures.NetNodeUppedDownedAMSConns; import org.opendaylight.defense4all.framework.core.ExceptionControlApp; import org.opendaylight.defense4all.framework.core.FrameworkMain; import org.opendaylight.defense4all.framework.core.HealthTracker; import org.opendaylight.defense4all.framework.core.Repo; import org.opendaylight.defense4all.framework.core.RepoFactory; import org.opendaylight.defense4all.framework.core.FrameworkMain.ResetLevel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DFAppRootFullImpl extends DFAppRoot { static Logger log = LoggerFactory.getLogger(DFAppRootFullImpl.class); protected AttackDecisionPointImpl attackDecisionPointImpl; protected StatsCollectorImpl statsCollectorImpl; protected MitigationMgrImpl mitigationMgrImpl; protected DFMgmtPointImpl mgmtPointImpl; protected DetectorMgrImpl detectorMgrImpl; protected StatsCollectionRep statsCollectionRep; protected DvsnRep dvsnRep; protected AMSRep amsRep; private Map<String, AMSRep> amsRepMap; /* Mitigation drivers will be invoked for mitigation - in the order they appear here - 0 first. */ protected MitigationDriver mitigationDriver0 = null; protected MitigationDriver mitigationDriver1 = null; protected MitigationDriver mitigationDriver2 = null; protected MitigationDriver mitigationDriver3 = null; protected MitigationDriver mitigationDriver4 = null; protected MitigationDriver mitigationDriver5 = null; protected ArrayList<MitigationDriver> mitigationDrivers = null; /** * defense4all core entity manager id */ public static final String DF_CORE_EM_ID = "df.core"; protected String stateClassPaths = null; /** * Constructor for Spring to set context and mFrameworkMain. Sets all column descriptions for all the global repos. * @param param_name param description * @throws exception_type circumstances description */ public DFAppRootFullImpl() throws ExceptionControlApp { super(); DFHolder.set(this); name = DF_APP; } /* Setters for Spring */ public void setFrameworkMain(FrameworkMain frameworkMain) {super.setFrameworkMain(frameworkMain);} public void setAttackDecisionPoint(AttackDecisionPointImpl impl) {this.attackDecisionPointImpl = impl;} public void setStatsCollectorImpl(StatsCollectorImpl impl) {this.statsCollectorImpl = impl;} public void setMitigationMgrImpl(MitigationMgrImpl impl) {this.mitigationMgrImpl = impl;} public void setDetectorMgrImpl(DetectorMgrImpl impl) {this.detectorMgrImpl = impl;} public void setMgmtPointImpl(DFMgmtPointImpl impl) {this.mgmtPointImpl = impl;} public void setStatsCollectionRep(StatsCollectionRep statsCollectionRep) {this.statsCollectionRep = statsCollectionRep;} public void setDvsnRep(DvsnRep dvsnRep) {this.dvsnRep = dvsnRep;} public void setAmsRep(AMSRep amsRep) {this.amsRep = amsRep;} public void setAmsRepMap(Map<String, AMSRep> amsRepMap) {this.amsRepMap = amsRepMap;} public void setClassPaths(String stateClassPaths) {this.stateClassPaths = stateClassPaths;} public void setAttackDecisionPointImpl(AttackDecisionPointImpl impl) {this.attackDecisionPointImpl = impl;} public void setMitigationDriver0(MitigationDriver driver0) {this.mitigationDriver0 = driver0;} public void setMitigationDriver1(MitigationDriver driver1) {this.mitigationDriver1 = driver1;} public void setMitigationDriver2(MitigationDriver driver2) {this.mitigationDriver2 = driver2;} public void setMitigationDriver3(MitigationDriver driver3) {this.mitigationDriver3 = driver3;} public void setMitigationDriver4(MitigationDriver driver4) {this.mitigationDriver4 = driver4;} public void setMitigationDriver5(MitigationDriver driver5) {this.mitigationDriver5 = driver5;} public void setControllerStatsCollectionIntervalInSecs(long interval) {this.controllerStatsCollectionIntervalInSecs = interval;} public void setBaselineRecordingIntervalInSecs(long interval) {this.baselineRecordingIntervalInSecs = interval;} @Override public StatsCollectionRep getStatsCollectionRep() {return statsCollectionRep;} @Override public DvsnRep getDvsnRep() {return dvsnRep;} @Override public AMSRep getAMSRep() {return amsRep;} @Override public DFMgmtPoint getMgmtPoint() {return mgmtPointImpl;} @Override public MitigationMgr getMitigationMgr() {return mitigationMgrImpl;} @Override public DetectorMgr getDetectorMgr() {return detectorMgrImpl;} @Override public StatsCollectorImpl getStatsCollector() {return statsCollectorImpl;} @Override public AttackDecisionPointImpl getAttackDecisionPoint() {return attackDecisionPointImpl;} @Override public ArrayList<MitigationDriver> getMitigationDrivers() {return mitigationDrivers;} /** * Initializes all modules after construction - bottom-up. * @param param_name param description * @return return description * @throws ExceptionControlApp * @throws exception_type circumstances description */ public void init(boolean bestEffort) throws ExceptionControlApp { try { fMain.getFR().logRecord(DFAppRoot.FR_DF_OPERATIONAL, name + " is (re)starting."); super.init(bestEffort); } catch (Throwable e) { if ( ! bestEffort ) throw new ExceptionControlApp(e); } /* This class initialization */ RepoFactory rf= null; try { rf = fMain.getRepoFactory(); dfEM = rf.getOrCreateEM(DF_CORE_EM_ID, stateClassPaths); } catch (Throwable e) { String msg = "Excepted trying to init RepoFactory "+ name; log.error(msg, e); if ( ! bestEffort ) throw new ExceptionControlApp(msg); } /* Set all non-null mitigation drivers into their array list */ try { mitigationDrivers = new ArrayList<MitigationDriver>(); if(mitigationDriver0 != null) { mitigationDriver0.init(); mitigationDrivers.add(mitigationDriver0); } if(mitigationDriver1 != null) { mitigationDriver1.init(); mitigationDrivers.add(mitigationDriver1); } if(mitigationDriver2 != null) { mitigationDriver2.init(); mitigationDrivers.add(mitigationDriver2); } if(mitigationDriver3 != null) { mitigationDriver3.init(); mitigationDrivers.add(mitigationDriver3); } if(mitigationDriver4 != null) { mitigationDriver4.init(); mitigationDrivers.add(mitigationDriver4); } if(mitigationDriver5 != null) { mitigationDriver5.init(); mitigationDrivers.add(mitigationDriver5); } } catch (Throwable e) { String msg = "Excepted trying to init Mitigation Drivers "+ name; log.error(msg, e); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, name + " failed to start."); if ( ! bestEffort ) throw new ExceptionControlApp(msg); } // All DF global repos String repoGlobal = RepoMajor.DF_GLOBAL.name(); try { oFCsRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.OFCS.name(), sSer, true, OFC.getOFCRCDs()); amsRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.AMS.name(), sSer, true, AMS.getAMSRCDs()); netNodesRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.NETNODES.name(), sSer, true, NetNode.getNetNodeRCDs()); pNsRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.PNS.name(), sSer, true, PN.getPNRCDs()); posRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.POS.name(), sSer, true, PO.getPORCDs()); attacksRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.ATTACKS.name(), sSer, true, Attack.getAttackRCDs()); detectorsRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.DETECTORS.name(), sSer, true, DetectorInfo.getDetectorRCDs()); detectionsRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.DETECTIONS.name(), sSer, true, Detection.getDetectionRCDs()); profilesRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.PROFILES.name(), sSer, true, null); policiesRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.POLICIES.name(), sSer, true, null); mitigationsRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.MITIGATIONS.name(), sSer, true, Mitigation.getMitigationRCDs()); dvsnInfosRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.DVSN_INFOS.name(), sSer, true, DvsnInfo.getRCDs()); flowConfigInfosRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.FLOW_CONFIG_INFOS.name(), sSer, true, FlowConfigInfo.getRCDs()); trafficFloorsRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.TRAFFIC_FLOORS.name(), sSer, true, TrafficFloor.getRCDs()); countersStatsRepo = (Repo<String>) rf.getOrCreateRepo(repoGlobal, RepoMinor.COUNTERS_STATS.name(), sSer, true, CounterStat.getCounterStatsRCDs()); } catch (Throwable e) { String msg = "Excepted trying to retrieve/construct all global repos"; log.error(msg, e); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, name + " failed to start."); if ( !bestEffort) throw new ExceptionControlApp(msg, e); } ; // Set DF and AMS based detectors in detectionSourcesRepo /* Other modules initialization */ try { statsCollectionRep.init(); } catch (Throwable e) { String msg = "Excepted trying to init statsCollectionRep"; log.error(msg, e); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, name + " failed to start."); if ( ! bestEffort) throw new ExceptionControlApp(msg); } try { dvsnRep.init(); } catch (Throwable e) { String msg = "Excepted trying to init dvsnRep"; log.error(msg, e); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, name + " failed to start."); if ( ! bestEffort) throw new ExceptionControlApp(msg); } try { //load ams from DB in case it exists, and decide if using DPRep or DefaultAmsRep AMS ams = retrieveActiveAms(); if (ams != null) { if (ams.getBrand().contains("DefensePro")) { setAmsRepByType("DP");//constant from spring map at defense4all_context } else { setAmsRepByType(ams.getBrand()); } } amsRep.init(); for (AMSRep amsRepItem : amsRepMap.values()) { amsRepItem.init(); } } catch (Throwable e) { String msg = "Excepted trying to init amsRep"; log.error(msg, e); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, name + " failed to start."); if ( ! bestEffort) throw new ExceptionControlApp(msg); } try { statsCollectorImpl.init(); } catch (Throwable e) { String msg = "Excepted trying to init statsCollectorImpl"; log.error(msg, e); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, name + " failed to start."); if ( ! bestEffort) throw new ExceptionControlApp(msg); } try { detectorMgrImpl.init(); } catch (Throwable e) { String msg = "Excepted trying to init detectorMgrImpl"; log.error(msg, e); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, name + " failed to start."); if ( ! bestEffort) throw new ExceptionControlApp(msg); } try { attackDecisionPointImpl.init(); } catch (Throwable e) { String msg = "Excepted trying to init attackDecisionPointImpl"; log.error(msg, e); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, name + " failed to start."); if ( ! bestEffort) throw new ExceptionControlApp(msg); } try { mitigationMgrImpl.init(); } catch (Throwable e) { String msg = "Excepted trying to init mitigationMgrImpl"; log.error(msg, e); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, name + " failed to start."); if ( ! bestEffort) throw new ExceptionControlApp(msg); } try { mgmtPointImpl.init(); } catch (Throwable e) { String msg = "Excepted trying to init mgmtPointImpl"; log.error(msg, e); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, name + " failed to start."); if ( ! bestEffort) throw new ExceptionControlApp(msg); } } private AMS retrieveActiveAms() throws ExceptionControlApp { AMS activeAms = null; boolean foundActiveAms = false; List<String> AmsKeys = amsRepo.getKeys(); for (String amsKey : AmsKeys) { AMS ams = new AMS(amsRepo.getRow(amsKey)); if (AMS.Status.ACTIVE.equals(ams.getStatus())) { if (foundActiveAms) { log.error("found more than one active AMS, supports 1 only!!! the other is " + ams); } else { foundActiveAms = true; log.debug("found active AMS in DB: " +ams); activeAms = ams; } } } return activeAms; } /** * Cleans up all modules before shutdown - top-down . * @param param_name param description * @return return description * @throws exception_type circumstances description */ public void finit() { fMain.getFR().logRecord(DFAppRoot.FR_DF_OPERATIONAL, name + " stopping."); // TODO: this class cleanup try { mgmtPointImpl.finit(); } catch (Exception e) {log.error("mgmtPointImpl failed to finit " + e.getMessage());} try { mitigationMgrImpl.finit(); } catch (Exception e) {log.error("mitigationMgrImpl failed to finit " + e.getMessage());} try { attackDecisionPointImpl.finit(); } catch (Exception e) {log.error("attackDecisionPointImpl failed to finit " + e.getMessage());} try { detectorMgrImpl.finit(); } catch (Exception e) {log.error("detectorMgrImpl failed to finit " + e.getMessage());} try { statsCollectorImpl.finit(); } catch (Exception e) {log.error("statsCollectorImpl failed to finit " + e.getMessage());} try { amsRep.finit(); for (AMSRep amsRepItem : amsRepMap.values()) { amsRepItem.finit(); } } catch (Exception e) {log.error("amsRep failed to finit " + e.getMessage());} try { statsCollectionRep.finit(); } catch (Exception e) {log.error("statsCollectionRep failed to finit " + e.getMessage());} try { dvsnRep.finit(); } catch (Exception e) {log.error("dvsnRep failed to finit " + e.getMessage());} try { super.finit(); } catch (Exception e) {log.error("dfAppRoot super failed to finit " + e.getMessage());} } /** * Performs factory reset on all modules. * @throws ExceptionControlApp * @throws exception_type circumstances description */ public void reset(ResetLevel resetLevel) throws ExceptionControlApp { Throwable eToLog = null; fMain.getFR().logRecord(DFAppRoot.FR_DF_OPERATIONAL, name + " resetting to " + resetLevel + " settings."); try { super.reset(resetLevel); } catch ( Throwable e ) { eToLog = e; } try { mgmtPointImpl.reset(resetLevel); } catch ( Throwable e ) { eToLog = e;} try { mitigationMgrImpl.reset(resetLevel); } catch ( Throwable e ) { eToLog = e; } try { attackDecisionPointImpl.reset(resetLevel); } catch ( Throwable e ) { eToLog = e; } try { detectorMgrImpl.reset(resetLevel); } catch ( Throwable e ) { eToLog = e; } try { statsCollectorImpl.reset(resetLevel); } catch ( Throwable e ) { eToLog = e; } try { amsRep.reset(resetLevel); for (AMSRep amsRepItem : amsRepMap.values()) { amsRepItem.reset(resetLevel); } } catch ( Throwable e ) { eToLog = e; } try { statsCollectionRep.reset(resetLevel); } catch ( Throwable e ) { eToLog = e; } try { dvsnRep.reset(resetLevel); } catch ( Throwable e ) { eToLog = e; } try { /* Clear repos */ flowConfigInfosRepo.truncate(); trafficFloorsRepo.truncate(); countersStatsRepo.truncate(); } catch ( Throwable e ) { eToLog = e; } if ( eToLog != null ) { log.error("Excepting trying to reset application", eToLog); throw new ExceptionControlApp ( eToLog ); } } @Override public void test(Properties props) { // annotationsTest1(); // repoTest1(); // mStatsCollectionRep.test(props); // mDiversionRep.test(props); // mMgmtPointImpl.test(); // attackDecisionPointImpl.test(); } @Override public synchronized void notifyAMSStatusChange(String amsLabel, HealthStatus healthStatus) { if(!fMain.isOpenForBusiness()) return; // Operate only after everything is initialized and is not terminating /* Update all relevant AMSConnections, and build the list of AMSConnection status changes in all netnodes. */ Hashtable<String,Hashtable<String,Object>> table = netNodesRepo.getTable(); if(table == null) { log.error("Received null netnodes table"); return; } Hashtable<String,Object> row; NetNode netNode; NetNodeUppedDownedAMSConns netNodeDownedAMSConns; Iterator<Map.Entry<String,Hashtable<String,Object>>> iter = table.entrySet().iterator(); List<NetNodeUppedDownedAMSConns> downedAmsConns = new ArrayList<NetNodeUppedDownedAMSConns>(); while(iter.hasNext()) { row = iter.next().getValue(); try { netNode = new NetNode(row); netNodeDownedAMSConns = updateNetNodeAMSConnsStatus(netNode, amsLabel, healthStatus); if(netNodeDownedAMSConns != null) downedAmsConns.add(netNodeDownedAMSConns); } catch (Throwable e1) { String msg = "Failed to netNodeUppedDownedAMSConns for netnode " + row.get(NetNode.LABEL); log.error(msg); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, "Failed to update AMS connection status"); fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE); } } /* Notify AMSConnections status change. Do it in a second pass because some netNodes can be logical, * depend on other netNodes, and their AMSConnections may be created dynamically. To avoid handling * complex cross-netNode dependencies we update all AMSConnections status in all netNodes in the * first pass, and then notify to handle upon those changes in the second pass - ensuring that in * any case all dependent upon netNodes have all their AMSConnection status updated already. */ for(NetNodeUppedDownedAMSConns netNodedownedAMSConns2 : downedAmsConns) { dvsnRep.notifyNetNodeAMSConnStatusChanged(netNodedownedAMSConns2); } /* Mitigations with no resources or failed AMSs may look for other AMSs to retry mitigation. */ mitigationMgrImpl.decoupledRetryMitigations(); } protected NetNodeUppedDownedAMSConns updateNetNodeAMSConnsStatus(NetNode netNode,String amsLabel,HealthStatus amsStatus) { NetNodeUppedDownedAMSConns netNodeDownedAMSConns = new NetNodeUppedDownedAMSConns(netNode.label); Iterator<Map.Entry<String,AMSConnection>> iter = netNode.amsConnections.entrySet().iterator(); AMSConnection amsConnection; AMSConnection clonedAMSConnection; boolean netNodeChanged = false; boolean amsConnStatusChanged; while(iter.hasNext()) { amsConnection = iter.next().getValue(); if(! amsConnection.amsLabel.equals(amsLabel)) continue; amsConnStatusChanged = amsConnection.setAmsStatus(amsStatus); if(!amsConnStatusChanged) continue; /* AMSConnection status changed, so record it in FR, add to upped/downed. mark netNode changed. */ clonedAMSConnection = new AMSConnection(amsConnection); fMain.getFR().logRecord(DFAppRoot.FR_OFC_OPERATIONAL,"AMS "+amsConnection.amsLabel+" ports "+amsConnection.amsNorthPort+" "+amsConnection.amsSouthPort+" now "+amsConnection.getHealthStatus()); if(amsConnection.getHealthStatus() == HealthStatus.DOWN) netNodeDownedAMSConns.downedAmsConns.add(clonedAMSConnection); netNodeChanged = true; } if(!netNodeChanged) return null; /* Persist in netnodes repo netnode changes. */ try { netNodesRepo.setRow(netNode.label, netNode.toRow()); } catch (Throwable e1) { log.error("Failed to persist changes to repo for netNode " + netNode.label, e1); fMain.getFR().logRecord(DFAppRoot.FR_DF_FAILURE, "Failed to update AMS connection to "+netNode.id+" NetNode status"); return null; } return netNodeDownedAMSConns; } @Override public void netNodeStatusChanged(String logicalNetNodeLabel, HealthStatus healthStatus) { mitigationMgrImpl.netNodeStatusChanged(logicalNetNodeLabel, healthStatus); } public void setAmsRepByType(String amsTypeOrBrand) { this.amsRep = amsRepMap.get(amsTypeOrBrand); if (this.amsRep==null) { log.warn("did not found AMS type {} in spring configuration -> using DefaultAms", amsTypeOrBrand ); this.amsRep = amsRepMap.get("DefaultAms");//default from the Spring xml } } }