Redes de ordenadores
5º de Ingeniería de Telecomunicación.
Curso 2002/2003
Práctica 2 - Simulaciones de nivel de red
(1 punto)
En esta práctica se va a profundizar en el funcionamiento del protocolo de red IP, tanto en cuestiones de direccionamiento como en el reenvío de paquetes por parte de los routers.
Para esta práctica se han desarrollado los programas necesarios para simular el funcionamiento de sistemas simples típicos de redes IP como son los routers y los hosts, así como concentradores (la tecnología de nivel físico va a ser Ethernet en todos los enlaces).
1.- Descripción de los bloques del simulador
Los diferentes elementos de la simulación (routers, hosts, concentradores) van a ser procesos independientes. La comunicación entre los mismos para el intercambio de paquetes se realizará mediante una técnica de comunicación entre procesos. Los detalles de implementación quedan ocultos bien dentro de programas ya terminados o dentro de librerías.
Por qué no se crea un simulador que se ejecute como un solo proceso? Esta solución tiene la ventaja de poder simular con gran detalle los tiempos de generación y procesado de los paquetes usando instantes de tiempo virtuales. En comparación, los programas que se emplearán funcionan en tiempo real con lo que si ejecutáramos muchos al mismo tiempo o intentaran simular una red con mucho tráfico se perdería precisión en la simulación, a diferencia de un simulador en tiempo virtual que tardaría más tiempo en terminar la simulación pero mantendría la precisión de los resultados (los simuladores creados con la librería dsim en la asignatura Redes, Sistemas y Servicios emplean tiempo virtual). Sin embargo, muchos aspectos de los protocolos en redes de ordenadores resultan bastante complejos de implementar en un simulador de eventos (tiempo virtual). Uno de los objetivos de esta práctica es comprender el funcionamiento de un router a base de implementar sus decisiones de reenvío. Esta implementación va a ser mucho más sencilla en un programa relativamente independiente que integrándolo dentro de un simulador de eventos.
Se han creado los siguientes programas: hub, hostenvia, hostrecibe, sonda y router. Se encuentran disponibles en el directorio /opt3/ro/ficheros/ifacesim/bin/. En los siguientes apartados vemos con ejemplos la forma de crear simulaciones con estos elementos.
2.- Sistema con dos hosts conectados a un hub
Empezaremos creando un sistema muy simple formado por un hub o concentrador Ethernet al cual se conectarán dos máquinas (figura 1).
Figura 1.- Dos hosts conectados a un Hub
El programa que simula el funcionamiento de un hub tiene la siguiente sintaxis:
hub nombre numero_de_puertos
Donde el significado de los argumentos es el siguiente:
nombre es el nombre que le queremos dar a este hub en concreto. Todos los hubs que estén en funcionamiento a la vez han de tener un nombre y ser diferente para cada uno.
numero_de_puertos es el número de puertos que queremos que tenga este concentrador para poder conectarle máquinas. Los puertos se numeran de 0 a numero_de_puertos-1.
Este bloque va a simular el funcionamiento de un hub en el sentido de que lo que reciba por uno cualquiera de sus puertos lo reenviará por los demás, sin embargo, no implementa colisiones y el funcionamiento es de tipo store&forward.
Así pues, comenzaremos creando un hub por ejemplo de 4 puertos que llamaremos hub0 con el siguiente comando:
%> hub hub0 4
A continuación crearemos un host que se va a dedicar simplemente a esperar paquetes IP que se dirijan a su interfaz y notificarnos por pantalla su llegada. La sintaxis de este programa es la siguiente
hostrecibe hub puerto_en_el_hub direccion_IP mascara
Donde el significado de los argumentos es el siguiente:
hub es el nombre que le hemos dado al hub al cual queremos conectar este host
puerto_en_el_hub es el número del puerto del hub al cual queremos conectarlo
direccion_IP es la dirección IP (en formato A.B.C.D) que queremos que tenga el interfaz de red de este host
mascara es la máscara que queremos que tenga configurado el interfaz del host
Como se va a limitar a recibir paquetes no va a necesitar tener configurado un router por defecto así que esa es toda la información que precisa. Creamos un host receptor de paquetes y lo conectamos al hub anterior con el comando:
%> hostrecibe hub0 1 10.123.45.13 255.0.0.0
Finalmente creamos el host que va a enviar paquetes IP que conectaremos en el puerto 0 del hub (con lo que nos quedarán aún dos puertos libres). Para realizar esta función disponemos del siguiente programa
hostenvia hub puerto_en_el_hub direccion_IP mascara defaul_trouter IPdestino numpkts pausaentrepkts numbytesdatosIP
Con el siguiente significado de los argumentos:
hub como hasta ahora es el nombre que le hemos dado al hub al cual queremos conectar este host
puerto_en_el_hub es el número del puerto del hub al cual queremos conectarlo
direccion_IP es la dirección IP (en formato A.B.C.D) que queremos que tenga el interfaz de red de este host
mascara es la máscara que queremos que tenga configurado ese interfaz de ese host
default_router es la dirección IP (en formato A.B.C.D) del router por defecto que queremos tenga configurado este host
IPdestino es la IP del interfaz al que queremos que envíe paquetes IP
numpkts es el número de paquetes IP que deseamos que envíe
pausaentrepkts es el tiempo (en milisegundos) que queremos que espere entre cada envío de un paquete IP
numbytesdatosIP es la cantidad de bytes de datos que debe haber en cada paquete IP que se envíe
Creamos un host que envíe paquete que conectamos en el mismo hub y configuramos de forma que su dirección IP se encuentre en la misma red que la del host que creamos con anterioridad. Como solo vamos a enviar paquetes de uno al otro y no hay routers en nuestra red podemos especificar lo que queramos en el campo default_router que no se va a dar el caso de necesitar utilizarlo. Entonces, crearíamos el host emisor con un comando como el siguiente:
%> hostenvia hub0 0 10.10.1.23 255.0.0.0 0.0.0.0 10.123.45.13 5 1000 200
Donde podemos ver que estamos configurándolo para que envíe 5 paquetes con 200 Bytes de datos IP al host de direcció 10.10.1.23, esperando 1 segundo (1000 msegs) entre cada par de envíos.
Estos tres comandos para formar este primer sistema podemos ejecutarlos cada uno en un terminal diferente, con lo que podremos terminarlos usando Ctrl+C o podemos ejecutarlos en el mismo terminal añadiendo al final de cada comando el carácter & que tiene como efecto que el proceso no siga usando el terminal como entrada. Es decir, ejecutaríamos:
%> hub hub0 4 &
%> hostrecibe hub0 1 10.123.45.13 255.0.0.0 &
%> hostenvia hub0 0 10.10.1.23 255.0.0.0 0.0.0.0 10.123.45.13 5 1000 200 &
El problema con el que nos encontraremos es que lo que cada uno de los programes envíe como salida al terminal se mezclará en el mismo y será un poco más complicado de interpretar. Si lanzamos los programas de esta forma podemos terminar con ellos ejecutando el siguiente comando:
%> killall hub hostrecibe hostenvia
3.- Sistema con dos hosts conectados a un hub y una sonda
Ahora vamos a añadir un host más al sistema anterior (figura 2). Este host va a estar conectado al hub y se va a dedicar a ver todos los paquetes que reenvía el hub y mostrar su contenido por pantalla. Es decir, su funcionamiento es muy similar a un host con el interfaz de red en modo promíscuo ejecutando un programa como tcpdump.
Figura 2.- Dos hosts y una sonda conectados a un Hub
El programa que funciona como una sonda tiene la siguiente sintaxis:
sonda hub puerto_del_hub
Donde:
hub es el nombre que le hemos dado al hub al cual queremos conectar este host
puerto_del_hub es el puerto de ese hub al que queremos conectar esta sonda
Ahora ejecutamos los programas que simulan los equipos de forma similar a como hicimos en el apartado anterior. El orden no tiene mucha importancia pero es conveniente dejar el host emisor como último equipo a crear porque en cuanto lo creemos intentará enviar paquetes. Así pues, por ejemplo podríamos seguir los pasos:
%> hub hub0 4 &
%> hostrecibe hub0 1 10.123.45.13 255.0.0.0 &
%> sonda hub0 2 &
%> hostenvia hub0 0 10.10.1.23 255.0.0.0 0.0.0.0 10.123.45.13 5 1000
Estudie con cuidado los paquetes que la sonda ve que se transmiten. Además de los paquetes IP circulan paquetes ARP en los que el host emisor pregunta por la dirección MAC que alguien (se dirige a la MAC de broadcast) tiene en su interfaz con dirección IP 10.123.45.13. Vemos que antes de cada paquete IP se produce este intercambio de paquetes ARP. Implementa el host que envía los paquetes IP una cache de ARP?
Repita el experimento con ordenadores del laboratorio de Telemática. Para ver la cache de ARP de los ordenadores recuerde que dispone del comando /sbin/arp y para ver los paquetes utilice el programa /opt3/ro/ficheros/bin/tcpdump_ro o /opt3/ro/ficheros/bin/simpledump. Si no sabe cómo enviar paquetes IP de una máquina a otra consulte el manual del comando ping; este comando envía paquetes del protocolo ICMP que se transportan sobre IP con el campo de protocolo a 1 y el que los recibe envía una respuesta también del protocolo ICMP (este protocolo se explicará en las clases de teoría).
4.- Sistema de dos redes conectadas con un router
En este apartado vamos a simular una configuración como la de la figura 3. Como podemos ver se trata de dos redes interconectadas por un router. En cada red colocaremos una sonda para ver los paquetes que se están trasmitiendo. Pretendemos ver cómo se produce el intercambio de paquetes IP entre hosts de diferentes redes.
Figura 3.- Dos redes interconectadas por un router
La creación de los hubs podría ser por ejemplo de la siguiente forma:
%> hub hub0 4 &
%> hub hub1 4 &
Colocamos también las sondas:
%> sonda hub0 2 &
%> sonda hub1 1 &
A continuación (y el orden en realidad no es importante) creamos un proceso que haga de router entre las dos redes. El programa de router tiene la siguiente sintaxis:
router fichero_rutas fichero_conexiones
Donde los parámetros son:
fichero_rutas es el nombre del fichero donde hemos especificado la tabla de rutas que tiene configurada este router.
fichero_conexiones es el nombre del fichero donde indicamos a qué hub se conecta cada interfaz del router.
El fichero fichero_rutas está formado por una línea de texto para cada ruta donde cada línea tiene el siguiente formato:
DirecciónDeRed Máscara IPNextHop Metrica PuertoLocal
Donde:
DirecciónDeRed es la dirección de la red destino a la que hace referencia esta entrada.
Máscara es la máscara que se aplica a esa dirección de red.
IPNextHop es la dirección IP del interfaz del siguiente router al que hay que entregar los paquetes para que lleguen a ese destino. Si la red donde está el destino está directamente conectada al interfaz entonces esta dirección debe ser 0.0.0.0
Métrica es el valor de la métrica para esta ruta. Emplearemos como métrica número de saltos.
PuertoLocal es el número del puerto del router por el que deben salir los paquetes para ese destino.
El fichero fichero_conexiones contiene una línea de texto por cada interfaz del router, con el siguiente formato:
PuertoLocal IPLocal Máscara NombreDelOtroEquipo PuertoDelOtroEquipo
Con el siguiente significado:
PuertoLocal es el número de puerto del router cuya conexión estamos especificando (numerados desde el 0).
IPLocal es la dirección IP que queremos asignar a este interfaz.
Máscara es la máscara para este interfaz.
NombreDelOtroEquipo es el nombre que tiene el otro equipo (el hub) al que queremos conectar este puerto.
PuertoDelOtroEquipo es el puerto de ese otro equipo en el que queremos conectarlo.
Para el caso que nos ocupa decidimos por ejemplo que la red de la izquierda va a ser la red B 130.206.0.0 y la de la derecha la red A 10.0.0.0 y las IPs de los interfaces del router serán respectivamente 130.206.160.1 y 10.0.0.1 . Creamos un fichero que llamamos por ejemplo mifich_cnxs con el siguiente contenido:
0 130.206.160.1 255.255.0.0 hub0 3
1 10.0.0.1 255.0.0.0 hub1 0
Y otro con las rutas que llamamos mifich_rutas con el siguiente contenido:
130.206.0.0 255.255.0.0 0.0.0.0 1 0
10.0.0.0 255.0.0.0 0.0.0.0 1 1
Y a continuación lanzamos el programa del router con el siguiente comando:
%> router mifich_rutas mifich_cnxs &
Ya solo nos queda crear el receptor y el emisor de paquetes:
%> hostrecibe hub1 2 10.0.1.1 255.0.0.0 &
%> hostenvia hub0 0 130.206.4.25 255.255.0.0 130.206.160.1 10.0.1.1 5 1000 300
Justifique cada uno de los paquetes que detectan las sondas.
Recuerde que puede terminar con todos los procesos de la simulación con el comando:
%> killall hub router sonda hostrecibe hostenvia
Consulte la disposición de ordenadores y routers en el Laboratorio de Telemática (http://www.tlm.unavarra.es/asignaturas/ro/ro02/labo.html) y busque una configuración similar a la analizada (dos redes separadas por un router). A continuación repita el experimento monitorizando mediante tcpdump o programas similares los paquetes que circulan. Hay alguna diferencia importante entre los resultados de la simulación y la experiencia?.
5.- Interconexión de varias redes (puntuado con el 50% de la práctica)
En este apartado se propone la simulación de la red de la figura 3. En dicha figura las elipses sombreadas no representan ningún elemento que simular sino tan solo lo que engloba cada una de las redes para poder referirnos a ellas. Así por ejemplo la Red 4 está compuesta por un interfaz del Router 1, otro el Router 2 y el hub que se emplea para interconectarlos.
Figura 3.- Variadas redes interconectadas
Emplee la red 10/8 (es decir, la red 10.0.0.0 con máscara 255.0.0.0) para el direccionamiento de todas las redes de la figura. Subdivida el espacio de direcciones disponible como prefiera siempre que cumpla que:
- En cada una de las redes 1, 2 y 3 se puedan conectar al menos 300 hosts (no hace falta que coloque hubs tan grandes como para albergar tantos equipos, reduzca los hubs a un tamaño razonable para los equipos que vaya a simular; con el número mínimo de hosts nos referimos a que haya suficientes direcciones IP libres en la red).
- Los routers 1 y 4 puedan tener una sola entrada en su tabla de rutas para acceder a las redes 3 y 5 (es decir, se puedan juntar ambas en un solo prefijo).
- La mayor cantidad posible de direcciones no se encuentre dentro de ninguna de esas redes y por tanto queden disponibles para futuras ampliaciones.
Cree las configuraciones de los cuatro routers de forma que los caminos entre las redes empleen las rutas más cortas en número de saltos.
Una vez dispuestos los equipos de red (routers y hubs) compruebe que existe conectividad IP (los paquetes IP son capaces de llegar de un extremo al otro) entre las redes 1, 2 y 3.
Finalmente, compruebe si un host en cualquiera de las redes 1, 2 o 3 sería capaz de enviar paquetes IP destinados a interfaces concretos de los routers (por ejemplo, para cambiar la configuración de los mismos empleando un protocolo que funcione sobre IP) y si le llegarín las respuestas del router.
5.1.- Formato de entrega
Los resultados de este apartado de la práctica 2 deben encontrarse dentro del directorio practica2_1 dentro del $HOME del grupo de prácticas. En dicho directorio deben dejar los ficheros de configuración de los cuatro routers que deben llamarse fconf_routerX_cnx donde X=1,2,3 ó 4 para los ficheros con las conexiones de los routers y fconf_routerX_rutas para los ficheros con las tablas de rutas de los mismos.
Si considera que necesita explicar alguna de las decisiones que ha tomado hágalo en un fichero de texto ASCII de nombre README.TXT que deje en ese mismo directorio.
6.- Implementación del algoritmo de reenvío de un router (puntuado con el 50% de la práctica)
En este apartado vamos a crear el programa que simula el router. En realidad solo la parte que toma las decisiones de reenvío dado un paquete y la tabla de rutas.
El programa se llamará simrouter y será funcionalmente idéntico al programa router descrito con anterioridad. Por tanto las opciones serán las descritas para dicho programa.
Para simplificar la tarea se dispone de unas librerías que se encargan de la parte de comunicación entre los diferentes elementos del simulador así como otra librería muy simple para leer de fichero las tablas de rutas y las conexiones del router. A continuación (subsecciones 6.1 y 6.2) se describe cada una de las librerías. En la subsección 6.3 se detalla cómo debe ser el funcionamiento de este programa que simula un router muy básico y en la subsección 6.4 se especifica el formato de entrega para los resultados de la parte final de esta práctica.
6.1.- Librería para leer la tabla de rutas y ficheros de conexiones libleetab.a
La librería libleetab.a se ofrece para simplificar la lectura de los ficheros con tablas de rutas y de conexiones, sin embargo NO es obligatorio su uso. Si lo desean pueden escribir su propio código para leer estos ficheros, lo cual no es complicado.
La librería se encuentra en /opt3/ro/ficheros/ifacesim/lib/ y el header es /opt3/ro/ficheros/ifacesim/include/libleetab.h.
Las funciones ofrecidas por la librería son las siguientes:
- struct R_entry *lee_tabla_rutas(FILE *ffich, int *numeltos);
Esta función lee las líneas de un fichero de rutas y devuelve un array donde cada elemento es una estructura con la información contenida en una línea del fichero.
El primer argumento es el fichero (naturalmente debe estar abierto) con la tabla de rutas. El segundo argumento es la dirección de memoria donde guardar un entero con el número de elementos que tiene el array que se devuelve.
El valor de retorno es la dirección de memoria del array con las entradas de la tabla de rutas. Cada uno de los elementos del array son del siguiente tipo:
struct R_entry
{
unsigned int direccionRed; /* En orden de la red */
unsigned int mascara; /* En orden de la red */
unsigned int nexthop; /* Si vale 0 es que esta directamente conectado */
unsigned short metrica; /* El campo de metrica, de momento no utilizado */
unsigned char puerto;
};
Cuando se haya terminado de usar el array que devuelve la función se puede destruir usando la siguiente llamada:
- void destruye_tabla_rutas(struct R_entry *tabla, int numeltos);
Elimina una tabla de rutas que se ha creado leyendo de fichero con la función lee_tabla_rutas(). El primer argumento es la tabla a destruir y el segundo el número de elementos que hay en la misma.
- struct R_entry *lee_tabla_conexiones(FILE *ffich, int *numeltos);
Esta función lee las líneas del fichero de conexiones y devuelve un array donde cada elemento es una estructura con la información contenida en una línea del fichero.
El primer argumento es el fichero (naturalmente debe estar abierto) con la tabla de conexiones. El segundo argumento es la dirección de memoria donde guardar un entero con el número de elementos que tiene el array que se devuelve.
El valor de retorno es la dirección de memoria del array con las entradas del fichero de conexiones. Cada uno de los elementos del array son del siguiente tipo:
struct C_entry
{
unsigned char puertolocal;
unsigned int direccionIP; /* En prden de la red */
unsigned int mascara; /* En orden de la red */
char *nombre;
unsigned char puertoexterno;
};
Cuando se haya terminado de usar el array que devuelve la función se puede destruir usando la siguiente llamada:
- void destruye_tabla_conexiones(struct C_entry *tabla, int numeltos);
Elimina una tabla de conexiones que se ha creado leyendo de fichero con la función lee_tabla_conexiones(). El primer argumento es la tabla a destruir y el segundo el número de elementos que hay en la misma.
6.2.- Librería de integración con el resto de sistemas de simulación libifacesim.a
Los programas que se emplean en esta práctica para crear una simulación usan las funciones de esta librería en la cual se implementa la comunicación entre los diferentes programas (por ejemplo el paso de paquetes de un router a un hub).
La libreía se encuentra disponible en /opt3/ro/ficheros/ifacesim/lib/ y el header con las declaraciones es /opt3/ro/ficheros/ifacesim/include/libifacesim.h.
A continuación se describen las funciones ofrecidas por la librería y cómo deben emplearse:
- int configurar_puerto(unsigned char puertolocal, unsigned int dirIP, unsigned int mascara, char *name, int puertoremoto);
Esta función sirve para configurar un puerto que tenga la aplicación (por ejemplo cada uno de los puertos de un router o el interfaz de un host). Los argumentos son:
- unsigned char puertolocal: Número del puerto
- unsigned int dirIP: La dirección IP que se desea asignar al interfaz de ese puerto
- unsigned int mascara: La máscara de red para ese interfaz
- char *name: El nombre (como una cadena de texto de C) del dispositivo al que se desea conectar este puerto (por ejemplo el nombre de un hub que exista o se vaya a crear)
- int puertoremoto: El puerto del dispositivo al que se desea conectar (por ejemplo el número de puerto del hub al que se desea conectar)
Cada vez que ejecute un programa, los interfaces que se configuren con esta función obtendrán una dirección MAC única en la simulación pero probablemente sea diferente de la dirección MAC que tengan la siguiente vez que se ejecute.
La función devuelve 0 si se ejecuta con éxito y -1 si se produce un error.
- int iniciar_nucleo(void);
Una vez se tengan configurados los interfaces de red se debe llamar a esta función para que la librería sepa que puede empezar a hacerse cargo de los paquetes que reciba este programa. A partir de ese momento parte de la librería se encargará de almacenar los paquetes IP que se vayan recibiendo así como de responder a peticiones de ARP. La función devuelve el control rápidamente y se deberá emplear la función recibir_packIP() para ir viendo todos los paquetes IP que se han recibido.
La función devuelve 0 si se ejecuta con éxito y -1 si se produce un error.
- struct paquete recibir_packIP();
Esta función sirve para obtener uno de los paquetes IP que hayan llegado a alguno de los interfaces configurados. Si no se ha recibido ninguno entonces la función se bloquea hasta que llegue alguno. Tan solo filtra que el paquete sea IP, no comprueba las direcciones ni nada más, así que el paquete podría tener como IP destino la de este interfaz u otra distinta. El tipo de estructura que devuelve es el siguiente:
struct paquete
{
int interfaz; /* Interfaz por el que lo ha leido */
struct Pack_Proto_IP *cabIP; /* Puntero a la zona de memoria del paquete donde esta la pseudo-cabecera IP */
void *pack; /* Puntero a la zona de memoria donde se ha guardado el paquete entero */
};
Donde:
- int interfaz: Número de interfaz (o puerto) por el que se ha leído el paquete.
- struct Pack_Proto_IP *cabIP: Puntero a un tipo de estructura que contiene los campos más importantes de la cabecera IP de este paquete.
- void *pack: Puntero a la zona de memoria donde se encuentra el paquete. No se recomienda emplearlo, cabIP se ha incluido para no tener que decodificar los campos de la cabecera IP del paquete.
El campo cabIP es un puntero a una estructura del siguiente tipo:
struct Pack_Proto_IP
{
unsigned int IPsrc, IPdst; /* En el orden de la red */
unsigned char ttl, protocolo;
unsigned short numbytesdatos; /* En el orden de la red */
};
Donde:
- unsigned int IPsrc, IPdst: Respectivamente la dirección IP origen y la dirección IP destino del paquete (ambas en el orden de la red).
- unsigned char ttl, protocolo: Respectivamente el campo de TTL y el campo de protocolo del paquete IP.
- unsigned short numbytesdatos: Número de bytes DE DATOS que tiene el paquete IP (DE DATOS, no cuenta el tamaño de la cabecera IP, a diferencia del campo de longitud que se encuentra en una cabecera IP). Esta cantidad se encuentra almacenada en el orden de la red.
- struct paquete crear_paqueteIP();
Podemos recibir un paquete de un interfaz de red o podemos crear un nuevo paquete IP desde cero. Para esta segunda alternativa se dispone de esta función. Devuelve un nuevo paquete, a partir de ahí se pueden modificar los valores de la estructura apuntada por el campo cabIP para alterar los parámetros de este paquete IP.
- void destruir_packIP(struct paquete pack);
Si lo que queremos es eliminar un paquete que hemos recibido y ya hemos procesado o uno que hemos creado y ya no necesitamos más podemos emplear esta función.
- int enviar_paqueteIP(struct paquete pack, unsigned char *macdst, int puerto);
Una vez que tengamos un paquete IP preparado podemos enviarlo a través de un interfaz con esta función. Sus argumentos son los siguientes:
- struct paquete pack: Descripción del paquete que queremos enviar. Puede estar creado con crear_paqueteIP() o puede ser un paquete que se ha recibido con recibir_packIP() y al que se le han cambiado algunos valores en sus campos. A la hora de enviar no se consulta el campo interfaz de esta estructura dado que se va a enviar por el interfaz especificado en el tercer argumento (puerto).
- unsigned char *macdst: Puntero a una zona de memoria de al menos 6 bytes que contiene la dirección MAC del interfaz al que se va a enviar este paquete. Si se desea averiguar este valor mediante un intercambio de paquetes de ARP consulte la función arp_de_ip().
- int puerto es el puerto de esta máquina por el que se desea enviar el paquete.
La función devuelve 0 si se ejecuta con éxito y -1 si se produce un error.
- int arp_de_ip(int puerto, unsigned int laip, unsigned char *mac, int timeoutmsecs);
Esta función sirve para enviar un paquete de ARP preguntando por la drección MAC de la máquina de dirección IP el segundo argumento.
- int puerto: Puerto por el que se desea enviar la pregunta (el ARP request)
- unsigned int laip: Dirección IP del interfaz cuya MAC se desea calcular. Debe ir en el orden de la red.
- unsigned char *mac: Dirección de una zona de memoria donde se puedan almacenar los 6 bytes de la dirección MAC que se espera obtener como respuesta.
- int timeoutmsecs: Máximo tiempo que se va a estar esperando la respuesta (el ARP Reply). Si se excede este tiempo la función devuelve 0, si se ha recibido la respuesta devuelve 1 y si se produce un error devuelve -1. El timer no es exacto sino que, al igual que muchas implementaciones de la pila TCP/IP, emplea un timer que caduca a intervalos regulares, es decir, solo se comprueba si se ha excedido el tiempo máximo de espera cada cierto tiempo, por debajo de esa escala el timer no es preciso. Las unidades son milisegundos (si se emplea un -1 quiere decir que no se quiere usar el timer con lo que la función puede bloquear al programa indeficindamente si no recibe la respuesta). Se sugiere un timer en el orden de centenares de milisegundos.
Para comprender cómo se deben utilizar cada una de estas funciones se han dejado las fuentes del programa hostenvia que son el fichero /opt3/ro/ficheros/ifacesim/ejemplos/hostenvia.c.
A la hora de compilar programas que empleen la librería libifacesim.a hay que enlazar también con la librería libpthread.a, es decir, recuerde poner -lpthread en la línea de compilación de gcc (hay un fichero Makefile de ejemplo en /opt3/ro/ficheros/ifacesim/ejemplos/)
6.3.- Descripción del funcionamiento del programa simrouter
Se ofrece un fichero plantilla para comenzar el desarrollo de este programa. Este fichero es /opt3/ro/ficheros/ifacesim/ejemplos/simrouter.c. En él ya se ha escrito la parte para leer las tablas de rutas y la información de conexiones del router. Igualmente se han configurado los interfaces y el programa está listo para recibir y enviar paquetes emplenado las funciones de la librería libifacesim.a. Es decir, falta escribir el bucle infinito que lee y reenvía los paquetes.
El programa debe funcionar como un router que soporte CIDR. Es decir, las redes vendrán definidas por una dirección de red y una máscara y se aplicará a un paquete la ruta con el Longest Match, es decir, aquella que se ajuste y tenga el prefijo más largo.
El router no va a hacer de router multicast ni va a soportar reenvío de broadcasts de red ni de subred ni fragmentación.
El pseudocódigo que debe cumplir la decisión de reenvío para cada paquete y que es lo que se debe implementar es el siguiente:
Si la IP destino del paquete es la de uno de los interfaces locales del router: No hacer nada [fin]
si no (reenviar):
Decrementar el TTL
Si el TTL es 0: tirar el paquete [fin]
si no:
Buscar en la tabla de rutas la entrada que se ajuste a esta IP destino con el prefijo más largo posible
Si no se encuentra ninguna: tirar el paquete [fin]
si se encuentra:
Si el siguiente salto de la ruta es un gateway: enviar el paquete a la direccion MAC de ese gateway [fin]
si no, el router ya esta conectado al destino: enviar el paquete a la MAC del host destino [fin]
6.4.- Formato de entrega
Los resultados de este apartado de la práctica 2 deben encontrarse dentro del directorio practica2_2 dentro del $HOME del grupo de prácticas. En dicho directorio deben dejar los ficheros fuente y el makefile para obtener con solo hacer make el programa simrouter.
Estas páginas pueden sufrir modificaciones
frecuentes
|
Última actualización 9:46 6/05/2003
|