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.
- Generar el número de EC afectados cada vez
- Imprimir información sobre la ruta del bucle.
- Imprima más información relevante de la CE correspondiente al bucle.
- 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.
- Si modifica
waypoint_path.py
el 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. - 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ónecCount
es el número de EC. -
Sólo es necesario
ecCount
imprimir 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 variablevector<string> loop_path
para 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,EquivalenceClass
agrégaleTcpIptoString()
una funciónstring 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_port
atributos a Rule, se agregóin_port
almacenamiento 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.py
el 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.py
el 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 puedeSDC ping MIT
bloquear. -
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_dst
de dominio