Virtlab:Řídící server/Mapping.php.inc

Z VirtlabWiki

Přejít na: navigace, hledání

Tato třída implementuje vlastní namapování fyzických prvků na prvky ve virtuální topologii, tak aby byly splněny všechny podmínky.

Zatím není plně dokončeno - pokud mapovaní nelze provézt je proveden jen vypis oznamení.

Popis funkcí

function __construct(virtlabParserEquipment $equip, virtlabParserTopology $topol) 
konstruktor třídy v PHP5. Jako parametry očekává objekty jednotlivých parseru - virtuální topologie a vybavení
public function Evaluate($device) 
vrátí hodnotu zadaného zařízení. Podle nastavení třídy virtlabValues.
public function DevicesValue() 
vrátí pole všech zařízení s vypočtenou hodnotou
public function Availability($device, $vertex) 
zjistí zda-li může být zadané fyzické zařízením zařízením ve virtuální topologii. Pokud ano, vrátí pole s určením, které rozhraní mohou být použity, na kterých linkách virtuální topologie. Pokud ne vrátí číslo chyby - definováno ve třídě virtlabValues.
private function Mapping($map2, &$vysledek) 
rekurzivní funkce, která se snaží mapovat. Ve dvojrozměrné poli $map2 je uloženo, který vertex může být realizován jakými device. Případný vysledek mapovaní je uložen do proměnné $vysledek. (viz příklady) Pozn.: tato funkce je psána obecně, takže je ve druhém kroku znovu použita na mapovaní LINKA-ROZHRANÍ. Podrobnější informace k algoritmu rekuzivní funkce jsou zde.
public function Map() 
funkce obstarávající celý algoritmus mapování.

Příklady

Výsledný výstup:

$mapper->Map();
r21:s0/0 r11:s0/0 
r21:s0/1 r10:s0/0 
r42:gi7 r21:fa3 
r41:gi7 r21:fa2 
r41:gi6 r11:gi1 
r42:gi6 r10:gi1 
r42:gi5 r11:gi0 
r41:gi5 r10:gi0 

Poznámka: podrobné výpisy z průběhu algoritmu, jsou zde.

Zdrojový kód

<?php

class virtlabMapping {
    private $equipment = NULL;
    private $topology  = NULL;

    function __construct(virtlabParserEquipment $equip, virtlabParserTopology $topol) {
        $this->equipment = $equip;
        $this->topology = $topol;
    }//konstruktor

    public function Evaluate($device) {
        $hodnota = 0;
        $eq = $this->equipment;	//pointer to equipment

        $temp = $eq->getDeviceFeatures($device);
        $hodnota += count($temp) * virtlabValues::DeviceFeature;

        $temp = $eq->getDeviceInterfacesFeatures($device);
        $hodnota += count($temp) * virtlabValues::InterfaceFeature;

        for($i = $eq->getDeviceInterfacesCount($device) - 1; $i >= 0; $i--) {
            $technology = $eq->getDeviceInterfaceTechnology($device, $i);

            if($technology == "ethernet") {
                $inf = virtlabValues::InterfaceTechnologyEthernet;
                $ether_type = $eq->getDeviceInterfaceEthertype($device, $i);
                if($ether_type == "legacy") 
                    $inf *= virtlabValues::EthertypeMultiplerLegacy;
                else if($ether_type == "fast")
                    $inf *= virtlabValues::EthertypeMultiplerFast;
                else if($ether_type == "gigabit")
                    $inf *= virtlabValues::EthertypeMultiplerGigabit;
                else $inf *= 0; //error

                $hodnota += $inf;
            }//if:ethernet
            else if($technology == "serial") {
                $inf = virtlabValues::InterfaceTechnologySerial;
                $bps = $eq->getDeviceInterfaceMaxbps($device, $i);

                if(is_null($bps)) $bps = virtlabValues::defaultMaxbps; //error

                if((int)$bps < virtlabValues::bpsDefault)
                    $inf = (int)((double)$inf * virtlabValues::bpsLower);
                else if((int)$bps > virtlabValues::bpsDefault)
                    $inf = (int)((double)$inf * virtlabValues::bpsBigger);

                $hodnota += $inf;
            }//else-if:serial
        }//for-interfaces
        return $hodnota;
    }//function-Evaluate


    public function DevicesValue() {
        $tmp = array();
        $devices = $this->equipment->getDevicesList();
        foreach($devices as $device) {
            $tmp[$device] = $this->Evaluate($device);
        }//foreach
        return $tmp;
    }//function-DevicesValue


    public function Availability($device, $vertex) {
        $device_idx = NULL;
        $eq = $this->equipment; //pointer to equipment
        $to = $this->topology;  //pointer to topology

        $eq->getDeviceByName($device, &$device_idx);


        //type
        $tmp_e = $eq->getDeviceType($device_idx);
        $tmp_t = $to->getVertexType($vertex);
        if($tmp_e != $tmp_t) return virtlabValues::badType;
        //print("Same type\n");


        //platform
        $tmp_e = $eq->getDevicePlatform($device_idx);
        $tmp_t = $to->getVertexPlatforms($vertex, 1);
        $tmp_platf = 0;
        if(!is_null($tmp_t)) {
            foreach($tmp_t as $hodnota) {
                $pattern = "/" . $hodnota . "/";
                if(preg_match($pattern, $tmp_e)) {
                    $tmp_platf = 1;
                    break;
                }//if-preg_match
            }//foreach
            if(!$tmp_platf) return virtlabValues::badPlatform;
        }//if-compare
        unset($tmp_platf);
        //print("Good platform\n");


        //OS
        $tmp_e = $eq->getDeviceOS($device, 1);
        $tmp_t = $to->getVertexOS($vertex, 1);     
        $pattern = "/" . $tmp_t . "/";
        if(!preg_match($pattern, $tmp_e)) return virtlabValues::badOS;
        unset($pattern);
        //print("Good OS\n");


        //device features
        $tmp_e = $eq->getDeviceFeatures($device);
        $tmp_t = $to->getVertexFeatures($vertex);
        if(count(array_diff((array)$tmp_t,(array)$tmp_e)) > 0) return virtlabValues::noDeviceFeature;
        //print("Device features-OK\n");


        //enough interfaces
        $tmp_t_if = array();
        $tmp_e_if = array();
        $tmp_t = $to->getEdgesByVertex($vertex);
        foreach($tmp_t as $edge_idx => $edge) {
            $tmp_tech = $to->getEdgeTechnology($edge_idx);
            array_push($tmp_t_if, $tmp_tech);
        }//foreach
        for($i = $eq->getDeviceInterfacesCount($device) - 1; $i>=0; $i--) {
            $tmp_tech = $eq->getDeviceInterfaceTechnology($device, $i);
            array_push($tmp_e_if, $tmp_tech);
        }//for
        $tmp_res = array_porovnej($tmp_t_if, $tmp_e_if);	//intersect of multisets
        if(count($tmp_res) != 0) return virtlabValues::notEnoughInterfaces;
        unset($tmp_t_if, $tmp_e_if, $tmp_res);


        //interfaces
        $tmp_t = $to->getEdgesByVertex($vertex);
        $result = array();
        foreach($tmp_t as $idx => $edge) {
            $result[$edge] = array();

            for($i = $eq->getDeviceInterfacesCount($device) - 1; $i >= 0; $i--) {

                $tmp_e_fea = $eq->getDeviceInterfaceFeatures($device, $i);
                if(is_null($tmp_e_fea)) $tmp_e_fea = array();
                $tmp_t_fea = $to->getEdgeFeatures($idx);
                if(is_null($tmp_t_fea)) $tmp_t_fea = array();
                if(array_diff($tmp_t_fea, $tmp_e_fea)) continue;  //uncompatible interface features -> next interface

                if($eq->getDeviceInterfaceTechnology($device, $i) == $to->getEdgeTechnology($idx)) {
                    if($to->getEdgeTechnology($idx) == "serial") {
                        if(is_null($to->getEdgeMinbps($idx))) {
                            $result[$edge][$i] = $eq->getDeviceInterfaceName($device, $i);
                            continue; 
                        }//if-minbps=NULL
                
                        if(is_null($eq->getDeviceInterfaceMaxbps($device, $i)))
                            $tmp_maxbps = virtlabValues::defaultMaxbps;	//error avoidance
                        else $tmp_maxbps = $eq->getDeviceInterfaceMaxbps($device, $i);
                        if($to->getEdgeMinbps($idx) > $tmp_maxbps) continue;	//slow serial interface -> next inteface
                        
                        $result[$edge][$i] = $eq->getDeviceInterfaceName($device, $i);

                    }//if-technology=serial
                    else if($to->getEdgeTechnology($idx) == "ethernet") {
                       if(is_null($to->getEdgeEthertype($idx))) {
                           $result[$edge][$i] = $eq->getDeviceInterfaceName($device, $i);
                           continue;
                       }//if-ethertype-topology=NULL

                       if(is_null($eq->getDeviceInterfaceEthertype($device, $i)))
                           $tmp_e_ethertype = virtlabValues::defaultEthertype;	//error avoidance
                       else $tmp_e_ethertype = $eq->getDeviceInterfaceEthertype($device, $i);

                       $tmp_t_ethertype = $to->getEdgeEthertype($idx);

                       //if slower ethernet -> next interface
                       if($tmp_t_ethertype == "fast" && $tmp_e_ethertype == "legacy") continue;
                       else if($tmp_t_ethertype == "gigabit" && $tmp_e_ethertype == "legacy") continue;
                       else if($tmp_t_ethertype == "gigabit" && $tmp_e_ethertype == "fast") continue;

                        $result[$edge][$i] = $eq->getDeviceInterfaceName($device, $i);
                    }//if-technology=ethernet
                }//if-same technology
            }//for - interfaces
        }//foreach

        foreach($result as $hodnota) {
            if(!$hodnota) return virtlabValues::VertexDeviceMismatch;	//some edge has no compatible interface
        }//foreach

        return $result;
    }//function

    private function Mapping($map2, &$vysledek) {//recursive
        foreach($map2 as $vertex => $devices) {
            if(count($devices) == 0) return 0; //some vertex cannot be mapped
        }//foreach

        if(count($map2) == 1) {
            foreach($map2 as $vertex => $devices) {
                if(count($devices) == 0) return 0; //cannot be mapped       
                foreach($devices as $device => $cena) {
                    $tmp["vertex"] = $vertex;
                    $tmp["device"] = $device;
                    array_push($vysledek, $tmp);
                    return 1;
                }//foreach
            }//foreach
        }//if - count=1
        else {
            foreach($map2 as $vertex => $devices) { //exist vertex with one possibly device
                if(count($devices) == 1) {
                    foreach($devices as $device => $cena) {
                        MatrixClear($map2, $vertex, $device);
                        if($this->Mapping($map2, $vysledek)) { //if mapping $vertex to $device is good
                            $tmp["vertex"] = $vertex;
                            $tmp["device"] = $device;
                            array_push($vysledek, $tmp);
                            return 1;
                        }//if
                        else return 0; //bad choice
                    }//foreach
                }//if
            }//foreach-vertex with one poss device
            
            foreach($map2 as $vertex => $devices) { 
                foreach($devices as $device => $cena) {
                    MatrixClear($map2,$vertex,$device);
                    if($this->Mapping($map2, $vysledek)) {
                        $tmp["vertex"] = $vertex;
                        $tmp["device"] = $device;
                        array_push($vysledek, $tmp);
                        return 1;
                    }//if
                }//foreach
                return 0; //no mapping is possible
            }//general
        }//else
    }//function


    public function Map() {
        $devices = $this->equipment->getDevicesList();
        $vertexes = $this->topology->getVertexesList();
        
        $map = array();
        foreach($vertexes as $vertex) {
            foreach($devices as $device) {
                $vysledek = $this->Availability($device,$vertex);
        
                if(is_array($vysledek)) $map[$vertex][$device] = $vysledek;
                else $map[$vertex][$device] = 0;
            }//foreach
        }//foreach

        //print("<pre> "); print_r($map); print(" </pre>");

        $map2 = array();
        foreach($map as $vertex => $devices) {
            foreach($devices as $device => $infs) {
                if(is_array($infs))
                    $map2[$vertex][$device] = $this->Evaluate($device);
            }//foreach
        }//foreach

        foreach($map2 as $idx => $devices) {
            asort($devices,SORT_NUMERIC);
            reset($devices);
            $map2[$idx] = $devices;
        }//foreach - sort

        //print("<pre> "); print_r($map2); print(" </pre>");


        $ahoj = array();
        if($this->Mapping($map2,$ahoj)) {
            //print("<pre> "); print_r($ahoj); print(" </pre>");
        }
        else print("Smula");


        $hotovo = array();
        foreach($ahoj as $spojeni) {
            $ahoj2 = array();
            if($this->Mapping($map[$spojeni["vertex"]][$spojeni["device"]],$ahoj2)) {//map interfaces
                $hotovo[$spojeni["vertex"]]["device"] = $spojeni["device"];
                foreach($ahoj2 as $linka) {
                    $hotovo[$spojeni["vertex"]]["links"][$linka["vertex"]] = $this->equipment->getDeviceInterfaceName($spojeni["device"], $linka["device"]);
                }//foreach
            }//if
            else print("Smula");
        }//foreach
        
        //print("<pre> "); print_r($hotovo); print(" </pre>");


        print("<pre>");
        $tmp = $this->topology->getEdgesList();
        foreach($tmp as $edge_idx => $edge) {
            $vertexes = $this->topology->getEdgeVertexes($edge_idx);
            foreach($vertexes as $vertex) {
                print($hotovo[$vertex]["device"] . ":" . $hotovo[$vertex]["links"][$edge] . " ");
            }
            print("\n");
        }
        print("</pre>");
    }//function
}//class
?>

Osobní nástroje