package es.tid.pce.computingEngine;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import es.tid.pce.computingEngine.algorithms.ComputingAlgorithm;
import es.tid.pce.computingEngine.algorithms.ComputingAlgorithmManager;
import es.tid.pce.computingEngine.algorithms.ComputingAlgorithmManagerSSON;
import es.tid.pce.computingEngine.algorithms.DefaultSVECPathComputing;
import es.tid.pce.computingEngine.algorithms.DefaultSinglePathComputing;
import es.tid.pce.computingEngine.algorithms.multiLayer.OperationsCounter;
import es.tid.pce.parentPCE.ChildPCERequestManager;
import es.tid.pce.parentPCE.MD_LSP;
import es.tid.pce.parentPCE.ParentPCESession;
import es.tid.pce.parentPCE.MDLSPDB.MultiDomainLSPDB;
import es.tid.pce.parentPCE.MDLSPDB.SaveLSPinRedis;
import es.tid.pce.pcep.PCEPProtocolViolationException;
import es.tid.pce.pcep.constructs.EndPoint;
import es.tid.pce.pcep.constructs.ErrorConstruct;
import es.tid.pce.pcep.constructs.MetricPCE;
import es.tid.pce.pcep.constructs.Notify;
import es.tid.pce.pcep.constructs.P2PEndpoints;
import es.tid.pce.pcep.constructs.PCEPIntiatedLSP;
import es.tid.pce.pcep.constructs.Path;
import es.tid.pce.pcep.constructs.Request;
import es.tid.pce.pcep.constructs.Response;
import es.tid.pce.pcep.constructs.StateReport;
import es.tid.pce.pcep.messages.PCEPError;
import es.tid.pce.pcep.messages.PCEPInitiate;
import es.tid.pce.pcep.messages.PCEPMessageTypes;
import es.tid.pce.pcep.messages.PCEPNotification;
import es.tid.pce.pcep.messages.PCEPReport;
import es.tid.pce.pcep.messages.PCEPRequest;
import es.tid.pce.pcep.messages.PCEPResponse;
import es.tid.pce.pcep.objects.Bandwidth;
import es.tid.pce.pcep.objects.EndPoints;
import es.tid.pce.pcep.objects.EndPointsIPv4;
import es.tid.pce.pcep.objects.EndPointsUnnumberedIntf;
import es.tid.pce.pcep.objects.ExplicitRouteObject;
import es.tid.pce.pcep.objects.GeneralizedEndPoints;
import es.tid.pce.pcep.objects.LSP;
import es.tid.pce.pcep.objects.NoPath;
import es.tid.pce.pcep.objects.Notification;
import es.tid.pce.pcep.objects.ObjectParameters;
import es.tid.pce.pcep.objects.ObjectiveFunction;
import es.tid.pce.pcep.objects.PCEPErrorObject;
import es.tid.pce.pcep.objects.PceIdIPv4;
import es.tid.pce.pcep.objects.ProcTime;
import es.tid.pce.pcep.objects.RequestParameters;
import es.tid.pce.pcep.objects.SRP;
import es.tid.pce.pcep.objects.tlvs.EndPointDataPathTLV;
import es.tid.pce.pcep.objects.tlvs.EndPointIPv4TLV;
import es.tid.pce.pcep.objects.tlvs.NoPathTLV;
import es.tid.pce.pcep.objects.tlvs.PathReservationTLV;
import es.tid.pce.pcep.objects.tlvs.SymbolicPathNameTLV;
import es.tid.pce.pcep.objects.tlvs.UnnumberedEndpointTLV;
import es.tid.pce.pcep.objects.tlvs.subtlvs.SymbolicPathNameSubTLV;
import es.tid.pce.server.ParentPCERequestManager;
import es.tid.pce.server.communicationpce.CollaborationPCESessionManager;
import es.tid.pce.server.wson.ReservationManager;
import es.tid.rsvp.objects.subobjects.EROSubobject;
import es.tid.rsvp.objects.subobjects.IPv4prefixEROSubobject;
import es.tid.rsvp.objects.subobjects.UnnumberIfIDEROSubobject;
import es.tid.tedb.DomainTEDB;
import es.tid.tedb.ReachabilityManager;
import es.tid.tedb.TEDB;
//import tid.pce.pcep.objects.tlvs.NotificationTLV;
//import tid.pce.pcep.objects.tlvs.subtlvs.NotificationSubTLV;
import es.tid.util.Analysis;
import es.tid.util.UtilsFunctions;
/**
* IniProcessorThread is devoted to LSP Inititation from the PCE
* @author ogondio
*
*/
public class IniProcessorThread extends Thread{
private static int lspIdSeq=1;
//private Hashtable <Integer,MD_LSP> multiDomain_LSP_list;
private MultiDomainLSPDB multiDomainLSPDB;
/** The queue to read the initation requests
*/
private LinkedBlockingQueue<InitiationRequest> lspInitiationRequestQueue;
private ChildPCERequestManager childPCERequestManager;
private ReachabilityManager reachabilityManager;
public LinkedBlockingQueue<InitiationRequest> getLspInitiationRequestQueue() {
return lspInitiationRequestQueue;
}
public void setLspInitiationRequestQueue(
LinkedBlockingQueue<InitiationRequest> lspInitiationRequestQueue) {
this.lspInitiationRequestQueue = lspInitiationRequestQueue;
}
/**
* Indicates whether the thread is running
*/
private boolean running;
SaveLSPinRedis savelsp;
/**
* Logger
*/
private Logger log;
public IniProcessorThread( LinkedBlockingQueue<InitiationRequest> lspInitiationRequestQueue, ReachabilityManager reachabilityManager,ChildPCERequestManager childPCERequestManager,MultiDomainLSPDB multiDomainLSPDB ){
log=LoggerFactory.getLogger("PCEServer");
this.lspInitiationRequestQueue=lspInitiationRequestQueue;
this.reachabilityManager=reachabilityManager;
this.childPCERequestManager=childPCERequestManager;
this.multiDomainLSPDB=multiDomainLSPDB;
//FIXME
savelsp=new SaveLSPinRedis();
savelsp.configure(multiDomainLSPDB, "127.0.0.1",6379);
running=true;
}
/**
* The "core" of the Initiation Request
*/
public void run(){
InitiationRequest iniReq;
ExplicitRouteObject fullEro=null;
while (running) {
log.info("Waiting for a new Initiation Request");
try {
iniReq=lspInitiationRequestQueue.take();
PCEPIntiatedLSP pini=iniReq.getLspIniRequest();
long sRP_ID_number = pini.getRsp().getSRP_ID_number();
//Check if delete
if (pini.getRsp().isrFlag()){
delete(pini.getLsp().getLspId());
}
else {
//Check if need to take path computation
boolean needComputation=false;
if (pini.getEro()!=null){
needComputation=false;
log.info("Provision Multidomain LSP with ERO");
}else {
needComputation=true;
log.info("Provision Multidomain LSP that needs computation");
}
if (needComputation){
fullEro=null;
}else {
fullEro=pini.getEro();
}
LinkedList<PCEPInitiate> iniList= new LinkedList<PCEPInitiate>();
log.debug("Creating the bandwidth");
Bandwidth bw=null;
//Get the Bandwidth
if (pini.getBandwidth()!=null){
bw= pini.getBandwidth().duplicate();
}
log.info("Creating the Domain list");
//Create the domain list
Iterator<EROSubobject> eroi= fullEro.getEROSubobjectList().iterator();
Inet4Address lastDomain=null;
Hashtable<Inet4Address,ExplicitRouteObject> eroSplit = new Hashtable<Inet4Address,ExplicitRouteObject>();
ExplicitRouteObject lastEro=null;
Inet4Address domain=null;
while (eroi.hasNext()){
EROSubobject eroso=eroi.next();
if (eroso instanceof IPv4prefixEROSubobject) {
domain=this.reachabilityManager.getDomain(((IPv4prefixEROSubobject) eroso).getIpv4address());
}else if (eroso instanceof UnnumberIfIDEROSubobject) {
domain=this.reachabilityManager.getDomain(((UnnumberIfIDEROSubobject) eroso).getRouterID());
log.info("A3: "+domain);
}
if (domain!=null){
if (lastDomain==null){
ExplicitRouteObject eeero=new ExplicitRouteObject();
lastEro=eeero;
eeero.addEROSubobject(eroso);
eroSplit.put(domain,eeero );
lastDomain=domain;
}else if (domain.equals(lastDomain)){
lastEro.addEROSubobject(eroso);
}else {
log.info("New domaiiin");
ExplicitRouteObject eeero=new ExplicitRouteObject();
lastEro=eeero;
eeero.addEROSubobject(eroso);
eroSplit.put(domain,eeero );
lastDomain=domain;
}
}else {
lastEro.addEROSubobject(eroso);
}
}
Enumeration<Inet4Address> domains=eroSplit.keys();
LinkedList<Object> domainList=new LinkedList<Object>();
while(domains.hasMoreElements()){
domain = domains.nextElement();
log.info("Starting with domain "+domain);
PCEPInitiate ini = new PCEPInitiate();
PCEPIntiatedLSP inilsp = new PCEPIntiatedLSP();
ini.getPcepIntiatedLSPList().add(inilsp);
SRP srp= new SRP();
srp.setSRP_ID_number(ParentPCESession.getNewReqIDCounter());
inilsp.setRsp(srp);
log.info("Getting endpoints of Domain "+domain);
inilsp.setEndPoint(getEndPoints(eroSplit.get(domain)));
inilsp.setEro(eroSplit.get(domain));
inilsp.setBandwidth(bw);
LSP lsp =new LSP();
lsp.setLspId(0);
SymbolicPathNameTLV symbolicPathNameTLV_tlv = new SymbolicPathNameTLV();
String name ="IDEALIST "+ParentPCESession.getNewReqIDCounter();
byte [] symbolicPathNameID= name.getBytes();
symbolicPathNameTLV_tlv.setSymbolicPathNameID(symbolicPathNameID);
lsp.setSymbolicPathNameTLV_tlv(symbolicPathNameTLV_tlv);
inilsp.setLsp(lsp);
iniList.add(ini);
domainList.add(domain);
}
try {
if (childPCERequestManager==null){
log.error("o ooooooooo");
}
LinkedList<ComputingResponse> reps=childPCERequestManager.executeInitiates(iniList, domainList);
log.info("Hay "+reps.size()+" reps");
MD_LSP mdlsp=new MD_LSP();
mdlsp.setFullERO(fullEro);
for (int i=0;i<reps.size();++i){
ComputingResponse cr=reps.get(i);
LinkedList<StateReport> lsr=cr.ReportList;
StateReport sr=lsr.get(0);
int id=sr.getLSP().getLspId();
mdlsp.getDomainLSPIDMap().put((Inet4Address)domainList.get(i), new Integer(id));
mdlsp.getDomainLSRMpa().put((Inet4Address)domainList.get(i), sr);
}
int lspId = IniProcessorThread.getID();
multiDomainLSPDB.getMultiDomain_LSP_list().put(lspId, mdlsp);
StateReport srmd = new StateReport();
SRP srp = new SRP();
srp.setSRP_ID_number(sRP_ID_number);
srmd.setSRP(srp);
LSP lsp = new LSP();
lsp.setLspId(lspId);
srmd.setLSP(lsp);
Path p=new Path();
p.setEro(fullEro);
srmd.setPath(p);
PCEPReport rep = new PCEPReport();
rep.getStateReportList().add(srmd);
rep.encode();
log.info("Mando: "+ rep.toString());
iniReq.getOut().write(rep.getBytes());
iniReq.getOut().flush();
}catch (Exception e){
e.printStackTrace();
log.error("PROBLEM SENDING THE INITIATES");
}
}
try{
this.savelsp.run();
}catch (Exception e){
log.warn("Save LSP in Redis fail");
e.printStackTrace();
break;
}
} catch (InterruptedException e) {
log.warn("There is no ini to make");
e.printStackTrace();
break;
}
}
}
public EndPoints getEndPoints(ExplicitRouteObject ero){
Iterator<EROSubobject> eroi= ero.getEROSubobjectList().iterator();
EROSubobject eroso;
GeneralizedEndPoints gep = new GeneralizedEndPoints();
P2PEndpoints p2pEndpoints = new P2PEndpoints();
EndPoint sourceEndPoint=null;
EndPoint destinationEndPoint=null;
gep.setP2PEndpoints(p2pEndpoints);
while (eroi.hasNext()){
eroso=eroi.next();
if (eroso instanceof IPv4prefixEROSubobject) {
if(sourceEndPoint==null){
sourceEndPoint=new EndPoint();
EndPointIPv4TLV epipv4=new EndPointIPv4TLV();
epipv4.setIPv4address(((IPv4prefixEROSubobject)eroso).getIpv4address());
sourceEndPoint.setEndPointIPv4TLV(epipv4);
}
else if (!eroi.hasNext()){
destinationEndPoint=new EndPoint();
EndPointIPv4TLV epipv4=new EndPointIPv4TLV();
epipv4.setIPv4address(((IPv4prefixEROSubobject)eroso).getIpv4address());
destinationEndPoint.setEndPointIPv4TLV(epipv4);
}
}else if (eroso instanceof UnnumberIfIDEROSubobject) {
if(sourceEndPoint==null){
sourceEndPoint=new EndPoint();
UnnumberedEndpointTLV epipv4=new UnnumberedEndpointTLV();
epipv4.setIPv4address(((UnnumberIfIDEROSubobject)eroso).getRouterID());
epipv4.setIfID(((UnnumberIfIDEROSubobject)eroso).getInterfaceID());
sourceEndPoint.setUnnumberedEndpoint(epipv4);
destinationEndPoint=new EndPoint();
UnnumberedEndpointTLV epipv42=new UnnumberedEndpointTLV();
epipv42.setIPv4address(((UnnumberIfIDEROSubobject)eroso).getRouterID());
epipv42.setIfID(((UnnumberIfIDEROSubobject)eroso).getInterfaceID());
destinationEndPoint.setUnnumberedEndpoint(epipv42);
}
else {
destinationEndPoint=new EndPoint();
UnnumberedEndpointTLV epipv4=new UnnumberedEndpointTLV();
epipv4.setIPv4address(((UnnumberIfIDEROSubobject)eroso).getRouterID());
epipv4.setIfID(((UnnumberIfIDEROSubobject)eroso).getInterfaceID());
destinationEndPoint.setUnnumberedEndpoint(epipv4);
}
}
}
p2pEndpoints.setSourceEndpoint(sourceEndPoint);
p2pEndpoints.setDestinationEndPoints(destinationEndPoint);
return gep;
}
public void delete (int lspID){
log.info("GOING TO DELTE "+lspID);
MD_LSP mdlsp= this.multiDomainLSPDB.getMultiDomain_LSP_list().get(lspID);
if (mdlsp==null) {
log.error("LSP is NULL!!");
}
LinkedList<PCEPInitiate> iniList= new LinkedList<PCEPInitiate>();
LinkedList<Object> domainList=new LinkedList<Object>();
if (mdlsp!=null){
log.info("LSP OK in DB!!!");
Enumeration<Inet4Address> domains=mdlsp.getDomainLSPIDMap().keys();
while(domains.hasMoreElements()){
Inet4Address domain = domains.nextElement();
PCEPInitiate ini = new PCEPInitiate();
PCEPIntiatedLSP inilsp = new PCEPIntiatedLSP();
ini.getPcepIntiatedLSPList().add(inilsp);
SRP srp= new SRP();
srp.setSRP_ID_number(ParentPCESession.getNewReqIDCounter());
inilsp.setRsp(srp);
srp.setRFlag(true);
LSP lsp =new LSP();
SymbolicPathNameTLV symbolicPathNameTLV_tlv = new SymbolicPathNameTLV();
StateReport SR =mdlsp.getDomainLSRMpa().get(domain);
if (SR.getLSP().getSymbolicPathNameTLV_tlv()!=null){
symbolicPathNameTLV_tlv.setSymbolicPathNameID(SR.getLSP().getSymbolicPathNameTLV_tlv().getSymbolicPathNameID() );
lsp.setSymbolicPathNameTLV_tlv(symbolicPathNameTLV_tlv);
}else {
log.warn("NO SYMBOLIC PATH NAME TLV!!!" );
}
//FIXME: CREATE ENDPOINTS
lsp.setLspId(mdlsp.getDomainLSPIDMap().get(domain));
inilsp.setLsp(lsp);
iniList.add(ini);
domainList.add(domain);
}
try {
log.info("GOING TO send the deletes of "+lspID);
childPCERequestManager.executeInitiates(iniList, domainList);
log.info("Removing MD LSP "+lspID);
this.multiDomainLSPDB.getMultiDomain_LSP_list().remove(lspID);
}catch (Exception e){
log.error("PROBLEM SENDING THE DELETES");
}
}
}
public static synchronized int getID(){
IniProcessorThread.lspIdSeq+=1;
return IniProcessorThread.lspIdSeq;
}
}