Experimento SDN4

1 tema del experimento

Supongamos que es un administrador de red que vivió y mantuvo ARPAnet en 1972. En el experimento anterior, aprendió a establecer la ruta más corta y emitió una ruta con el menor número de saltos desde SDC a MIT (la ruta verde en la figura). . Un día, su colega Bob recibió un nuevo requisito de que todo el tráfico entre UTAH e ILLINOIS debe pasar por el analizador de tráfico implementado en TINKER para realizar más investigaciones. El descuidado Bob rápidamente cayó sin verificar el estado actual de la red. Envíe una nueva ruta (ruta roja en la imagen). Inteligente e ingenioso, rápidamente te das cuenta de que la tabla de flujo emitida por Bob puede provocar un bucle de reenvío.

Ahora debe ejecutar la herramienta VeriFlow, verificar las dos rutas de reenvío anteriores y completar las dos partes siguientes del experimento:

  • Parte básica del experimento.
  1. Generar el número de EC afectados cada vez
  2. Imprimir información sobre la ruta del bucle.
  3. Imprima más información relevante de la CE correspondiente al bucle.
  4. Analice la diferencia entre el código original y el código del parche y piense por qué es necesario agregar un parche.
  • Ampliar la parte experimental.
  1. Si modifica waypoint_path.pyel campo de prioridad de la regla agregada en el código, el resultado de la detección de VeriFlow será incorrecto. Describa cuál es el error y explique el motivo del error.
  2. Entre los 14 dominios admitidos por VeriFlow, seleccione varios dominios (no menos de 5) para verificar, generar y analizar los resultados.
  • Descarga de datos del experimento
    https://www.aliyundrive.com/s/iA9A9BWijz7

2 Contenido experimental

2.1 preparación

2.1.1 Observar el problema del bucle de reenvío

  • Inicie el programa de control de ruta más corta
    ryu-manager ofctl_rest.py shortest_path.py --observe-links

  • iniciar topología

    sudo python Arpanet19723.py

  • En la topología, SDC hace ping al MIT para establecer una conexión

    SDC ping MIT

  • Emitir la ruta de UTAH a ILLINOIS vía TINKER

    sudo python waypoint_path.py

  • En la topología, SDC vuelve a hacer ping al MIT para establecer una conexión

    SDC ping MIT

  • Ver un determinado interruptor en la ruta, como la tabla de flujo de la USC

    sudo ovs-ofctl dump-flows s22

  • Abra Wirehark para observar el puerto.

2.1.2 Uso de VeriFlow

  • Descargue VeriFlow desde github y aplique el parche experimental

    git clone https://github.com/samueljero/BEADS.git 
    cd BEADS 
    git am 0001-for-xjtu-sdn-exp-2020.patch 
    
  • Compilar VeriFlow

    cd veriflow/VeriFlow 
    make clean all 
    
  • Abra el control remoto en el puerto personalizado y ejecute el programa más corto

    ryu-manager ofctl_rest.py shortest_path.py --ofp-tcp-listen-port 1998 --observe-links

  • Ejecute VeriFlow en modo proxy

    ./VeriFlow 6633 127.0.0.1 1998 Arpanet19723.txt log_file.txt

  • iniciar topología

    sudo python Arpanet19723.py

  • En la topología, SDC hace ping al MIT para establecer una conexión

    SDC ping MIT

  • Emita la ruta de UTAH a ILLINOIS a través de TINKER y observe la información del bucle detectada por VeriFlow en el archivo de registro.

    sudo python waypoint_path.py

2.2 Parte del experimento básico

2.2.1 Impresión del número CE

  • VeriFlow::verifyRule()Es una función para ejecutar el algoritmo central de VeriFlow, incluida la división de clases de equivalencia, la construcción de gráficos de reenvío y la verificación de invariantes. La variable en la función ecCountes el número de EC.

  • Sólo es necesario ecCountimprimir en un archivo de registro.

  • VeriFlow::verifyRule()antes de arreglar:

    if(ecCount == 0)
    {
        fprintf(stderr, "[VeriFlow::verifyRule] Error in rule: %s\n", rule.toString().c_str());
        fprintf(stderr, "[VeriFlow::verifyRule] Error: (ecCount = vFinalPacketClasses.size() = 0). Terminating process.\n");
        exit(1);
    }
    else
    {
        // fprintf(stdout, "\n");
        // fprintf(stdout, "[VeriFlow::verifyRule] ecCount: %lu\n", ecCount);
    }
    
  • VeriFlow::verifyRule()Después de la modificación:

    fprintf(fp, "[VeriFlow::verifyRule] verifying this rule: %s\n", rule.toString().c_str());
    if(ecCount == 0)
    {
        fprintf(stderr, "[VeriFlow::verifyRule] Error in rule: %s\n", rule.toString().c_str());
        fprintf(stderr, "[VeriFlow::verifyRule] Error: (ecCount = vFinalPacketClasses.size() = 0). Terminating process.\n");
        exit(1);
    }
    else
    {
        fprintf(stdout, "\n");
        fprintf(stdout, "[VeriFlow::verifyRule] ecCount: %lu\n", ecCount);
        fprintf(fp, "[VeriFlow::verifyRule] ecCount: %lu\n", ecCount);//输出到日志文件
    }
    
  • Recompilar, captura de pantalla del archivo de registro

2.2.2 Impresión de la ruta del bucle

  • VeriFlow::traverseForwardingGraph()Para recorrer el gráfico de reenvío de un EC en particular, verifique si hay bucles o agujeros negros. Solo es necesario agregar una variable vector<string> loop_pathpara registrar la ruta del bucle.

  • VeriFlow::traverseForwardingGraph()Después de la modificación:

    bool VeriFlow::traverseForwardingGraph(const EquivalenceClass& packetClass, ForwardingGraph* graph, const string& currentLocation, const string& lastHop, unordered_set< string > visited, FILE* fp,vector<string> loop_path)
    {
    	...
    	if(visited.find(currentLocation) != visited.end())
    	{
    		// Found a loop.
    		fprintf(fp, "\n");
    		fprintf(fp, "[VeriFlow::traverseForwardingGraph] Found a LOOP for the following packet class at node %s.\n", currentLocation.c_str());
    		fprintf(fp, "[VeriFlow::traverseForwardingGraph] PacketClass: %s\n", packetClass.toString().c_str());
    		fprintf(fp, "[VeriFlow::traverseForwardingGraph] Loop path is:\n");
    		bool flag=false;
    		for(unsigned int i = 0; i < loop_path.size()-1; i++) {
    			if(loop_path[i]==currentLocation){
    				flag=true;
    			}
    			if(flag){
    				fprintf(fp, "%s --> ", loop_path[i].c_str());
    			}
    		}
    		fprintf(fp, "%s\n", currentLocation.c_str());
    		for(unsigned int i = 0; i < faults.size(); i++) {
    			if (packetClass.subsumes(faults[i])) {
    				faults.erase(faults.begin() + i);
    				i--;
    			}
    		}
    		faults.push_back(packetClass);
    
    		return false;
    	}
    	visited.insert(currentLocation);
    	loop_path.push_back(currentLocation);
        ...
        return this->traverseForwardingGraph(packetClass, graph, itr->rule.nextHop, currentLocation, visited, fp,loop_path);
    }
    
  • Recompilar, captura de pantalla del archivo de registro

2.2.3 Impresión de información del paquete de datos relacionados

  • La información básica de EC se muestra en el formato de intervalo de 14 dominios. Para facilitar la solución de problemas de Bob, la representación de la información de EC se simplifica y solo se extrae el quíntuple TCP/IP de los 14 dominios como visualización de información principal.

  • Información básica Imprimir código de EC existente

    VeriFlow::traverseForwardingGraph():

    fprintf(fp, "[VeriFlow::traverseForwardingGraph] PacketClass: %s\n", packetClass.toString().c_str());

  • Imita EquivalenceClass::toString()una función, EquivalenceClassagrégale TcpIptoString()una función

    string EquivalenceClass::TcpIptoString() const
    {
    	char buffer[1024];
    	sprintf(buffer, "[ nw_src(%s-%s), nw_dst(%s-%s)",
    			::getIpValueAsString(this->lowerBound[NW_SRC].c_str),
    			::getIpValueAsString(this->upperBound[NW_SRC].c_str),
    			::getIpValueAsString(this->lowerBound[NW_DST].c_str),
    			::getIpValueAsString(this->upperBound[NW_DST].c_str);
    
    	string retVal = buffer;
    	retVal += ", ";
    	sprintf(buffer,"nw_proto(%lu-%lu)",this->lowBound[NW_PROTO],this->upperBound[NW_PROTO]);
    	retVal+=buffer;
    	retVal+=",";
    	sprintf(buffer,"tp_src(%lu-%lu)",this->lowBound[TP_SRC],this->upperBound[TP_SRC]);
    	retVal+=buffer;
    	retVal+=",";
    	sprintf(buffer,"tp_dst(%lu-%lu)",this->lowBound[TP_DST],this->upperBound[TP_DST]);
    	retVal+=buffer;
    	return retVal;
    }
    
  • Recompilar, captura de pantalla del archivo de registro

2.2.4 Analizar la diferencia entre el código original y el código del parche, y pensar por qué es necesario agregar un parche

  • cambiar archivo

    • veriflow/VeriFlow/Network.cpp | 1 +

    • veriflow/VeriFlow/OpenFlowProtocolMessage.cpp | 17 +++±–

    • veriflow/VeriFlow/Rule.cpp | 8 ++±

    • veriflow/VeriFlow/Rule.h | 1 +

    • veriflow/VeriFlow/VeriFlow.cpp | 45 +++++++++++++++±–

    • veriflow/VeriFlow/VeriFlow.h | 2 ±

  • Ver contenido y análisis de modificación de parches

    • usar comando

      git diff HEAD origin/HEAD

    • Se agregaron in_portatributos a Rule, se agregó in_portalmacenamiento y procesamiento de pares.

    • Store lastHop, capacidad mejorada para encontrar BlackHole

    • Mejorar la situación a la hora de juzgar los agujeros negros.

      En el código fuente abierto en github, se dan dos situaciones para juzgar los agujeros negros:

      • El conmutador o host actual no está en la red actual
      • El conmutador o host actual está en la red, pero no hay ningún vínculo con otros conmutadores o hosts.

      En el parche se ha añadido un caso para juzgar los agujeros negros:

      • El conmutador o host actual también tiene un enlace conectado en la topología de la red, pero debido a cambios en la estructura de la red, el salto anterior no se puede encontrar desde la ubicación del conmutador o host actual y el puerto correspondiente (in_port). .cambiar o host.

    • Mejorar el juicio del bucle.

      Seleccionar el siguiente salto evita lo mismo que el salto anterior

2.3 Ampliar la parte experimental.

2.3.1 Si modifica waypoint_path.pyel campo de prioridad de la regla agregada en el código, el resultado de la detección de VeriFlow será incorrecto. Intente describir cuál es el error y explique el motivo del error.

  • Modifique waypoint_path.pyel campo de prioridad de la regla agregada en el código a 1 y descubra que no hay ningún bucle en el archivo de registro y no se puede SDC ping MITbloquear.

  • ver tabla de flujo

    • Antes de modificar el campo de prioridad

      • tabla de flujo s22

      • tabla de flujo s25

    • Después de modificar el campo de prioridad

      • tabla de flujo s22

      • tabla de flujo s25

    • Cuando los campos coincidentes son los mismos, la nueva entrada de flujo cubre la entrada de flujo anterior. De hecho, hay un bucle, pero VeriFlow no detecta el bucle.

  • No se puede encontrar la causa del bucle

    • Al juzgar el bucle para seleccionar el siguiente salto, veriflow usa el campo de prioridad para ordenar. Cuando hay reglas con la misma prioridad, ocurrirán problemas.

      graph->links[currentLocation].sort(compareForwardingLink);

    • Cuando una regla coincide completamente y necesita sobrescribir la regla original, VeriFlow no elimina la regla original y agrega una nueva regla, sino que conserva la regla original y descarta la regla recién agregada.

2.3.2 Entre los 14 dominios admitidos por VeriFlow, seleccione varios dominios (no menos de 5) para verificar, generar y analizar los resultados.

  • Dominios que se pueden verificar

    enum FieldIndex
    {
    	IN_PORT, // 0
    	DL_SRC,
    	DL_DST,
    	DL_TYPE,
    	DL_VLAN,
    	DL_VLAN_PCP,
    	MPLS_LABEL,
    	MPLS_TC,
    	NW_SRC,
    	NW_DST,
    	NW_PROTO,
    	NW_TOS,
    	TP_SRC,
    	TP_DST,
    	ALL_FIELD_INDEX_END_MARKER, // 14
    	METADATA, // 15, not used in this version.
    	WILDCARDS // 16
    };
    
  • Seleccione dominio verificado

    • DL_SRC
    • DL_DST
    • DL_TYPE
    • NO_SRC
    • NO_DST
    • EN_PUERTO
  • código de verificación

    import requests
    import json
    
    def add_flow(dpid, src_ip, dst_ip, in_port, out_port, src_mac,dst_mac,priority=10):
        flow = {
          
          
            "dpid": dpid,
            "idle_timeout": 0,
            "hard_timeout": 0,
            "priority": priority,
            "match":{
          
          
                "dl_type": 2048,
                "in_port": in_port,
                "nw_src": src_ip,
                "nw_dst": dst_ip,
                "dl_src":src_mac,
                "dl_dst":dst_mac
            },
            "actions":[
                {
          
          
                    "type":"OUTPUT",
                    "port": out_port
                }
            ]
        }
    
        url = 'http://localhost:8080/stats/flowentry/add'
        ret = requests.post(
            url, headers={
          
          'Accept': 'application/json'}, data=json.dumps(flow))
        print(ret)
    
    def show_path(src, dst, port_path):
        print('install mywaypoint path: {} -> {}'.format(src, dst))
        path = str(src) + ' -> '
        for node in port_path:
            path += '{}:s{}:{}'.format(*node) + ' -> '
        path += str(dst)
        path += '\n'
        print(path)
    
    def install_path():
        '23 -> 4:s22:2 -> 2:s9:3 -> 3:s16:2 -> 3:s7:2 -> 3:25:2 -> 1'
        src_sw, dst_sw = 23, 1
        waypoint_sw = 9  # Tinker 10.0.0.21, s9
    
        path = [(4, 22, 2), (2, 9, 3), (3, 16, 2), (3, 7, 2), (3, 25, 2)]
        # path = [(3, 7 , 2)]
        MIT_mac="00:00:00:00:00:01"
        SDC_mac="00:00:00:00:00:02"
        # send flow mod
        for node in path:
            in_port, dpid, out_port = node
            add_flow(dpid, '10.0.0.0/8', '10.0.0.0/8', in_port, out_port,SDC_mac,MIT_mac)
            add_flow(dpid, '10.0.0.0/8', '10.0.0.0/8', out_port, in_port,MIT_mac,SDC_mac)
        show_path(src_sw, dst_sw, path)
    
    if __name__ == '__main__':
        install_path()
    
  • resultado

  • analizar

    • Reglas de coincidencia:

      Regla 1 Regla 2
      src_ip 10.0.0.0/8 10.0.0.0/8
      dst_ip 10.0.0.0/8 10.0.0.0/8
      src_mac 00:00:00:00:00:01 00:00:00:00:00:02
      dst_mac 00:00:00:00:00:02 00:00:00:00:00:01
      en_puerto El puerto de entrada en la ruta de entrega. El puerto de entrada en la ruta de entrega.
      tipo_dl 2048 2048
    • El número de EC es 3, que es el mismo que el número de la pieza base, como se esperaba

    • Habrá un bucle de reenvío 20.0.0.5–>20.0.0.7–>20.0.0.16–>20.0.09–>20.0.0.22–>20.0.0.23–>20.0.0.25, como se esperaba

3 clasificación de problemas

  • La parte básica del experimento es solo un problema de configuración del entorno, como el problema de la falla del parche. La modificación del código fuente debe modificarse en el código parcheado.

  • Al realizar una coincidencia de dominio, src_mac puede coincidir correctamente, pero dst_mac no coincide

    src_mac es la dirección mac del host de origen; dst_mac es la dirección mac del host de destino

    Motivo del error: escritura incorrecta del nombre dl_dstde dominio

Supongo que te gusta

Origin blog.csdn.net/qq_49588762/article/details/117699068
Recomendado
Clasificación