Skip to content

Python Switch implementation with a focus on STP and VLANs.

License

Notifications You must be signed in to change notification settings

andreirusanescu/Switch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

1 2 3

Task 1 - Tabela CAM

Nu am intampinat probleme pentru acest task, rezolvarea mea este foarte similara cu pseudocodul oferit.

ex1.jpg

Am dat ping la host 3 de pe host 0 si a functionat, desi sunt in VLAN-uri separate, dar logica de VLAN inca nu a fost implementata. Se poate vedea rafala de ICMP-uri datorita buclei create de SWITCH-uri.

Task 2 - VLAN

Pentru acest task a trebuit sa consider toate cele 4 cazuri posibile, respectiv A-A, A-T, T-T, T-A (T = Trunk, A = Access).

Dificultatea a fost in cum faceam diferenta intre un cadru cu tag si un cadru fara tag. Pentru A-A sau T-T, trebuia efectuat forwarding clasic, dar pentru A-T trebuia inclus acel tag de 802.1q custom, iar pentru T-A trebuia scos. Pentru a nu scrie cod duplicat sau greu de inteles, am decis sa-mi creez de la inceput ambele cadre, atat cel cu tag, cat si cel fara tag, pentru ca in functie de interfata, daca trebuia sa trimit atat catre un port Acces cat si catre un port Trunk, trebuia sa am nevoie de ambele.

M-am folosit de un dictionar pentru a tine mapari de tip interface -> <vlan_id> / "T". De asemenea, aici trebuie verificata logica pentru ca un cadru sa fie trimis doar pe vlan-ul corespunzator lui, iar pentru adresele MAC destinatie care se aflau in tabela CAM trebuia verificat si daca suma aceea a nibble-urilor este egala cu primii 4 biti (MSB) ai vlan_tci-ului.

ex2.jpg

In poza se poate vedea in fereastra de wireshark rafala instantanee de cadre, intrucat neavand STP implementat, cele 3 switch-uri formeaza o bucla si fac un broadcast storm. De asemenea, am dat ping intre statiile 3 si 5, deoarece acestea apartin aceluiasi VLAN, daca as fi dat intre 3 si 4 pachetul nu ajungea, concluzionandu-se cu "Host unreachable"

Task 3 - STP

Acesta a fost de departe cel mai greu task, deoarece nu intelesesem foarte bine cum functioneaza acest protocol.

HPDU

Pentru a trimite un cadru HPDU la fiecare secunda am folosit un thread separat, care ruleaza intr-o bucla si trimite cadrul apoi sta in sleep 1 secunda.

PPDU

Pentru a crea un cadru PPDU, pe langa adrese MAC, LLC Length si LLC Header, PPDU_HEADER, trebuie creat si PPDU_CONFIG, care nu foloseste doar valori date din cerinta. Aici m-am folosit de IEEE Std 802.1D-2004, mai exact pagina 165 din 281 (paginile pdf-ului, nu ale lucrarii), unde este un tabel cu HELLO_TIME, MAX_AGE, FORWARD_DELAY, PORT_PRIORITY, care contine atat valorile default cat si un range. Pentru a construi port id, m-am folosit de valoarea standard, 128, care trebuie shiftata la stanga cu 8 biti pentru a concatena cu port_number, respectiv interfata switch-ului, rezultand 16 biti pt port id, cum este specificat in enunt (pagina 72/281, sectiunea 9.2.7 - despre cati biti ar trebui sa aiba port number si port priority). De asemenea, pentru a trimite cadre PPDU, am folosit un thread separat, care la fiecare HELLO_TIME secunde trimite pe toate interfetele de tip Trunk si cu port DESIGNATED un cadru PPDU. Acest cadru contine informatii de stare globala a switch-ului in variabila stp_info: root bridge id si root path cost. Pentru ca le foloseste in header, trebuie sa folosesc un lock pentru a nu avea race condition, intrucat variabila stp_info este modificata si in thread-ul principal, in main.

In logica din main, cand primesc un cadru, mai intai verific sa vad daca e de tip HPDU pentru a ii da discard, apoi verific daca e PPDU, si in final tratez cazul cand este un cadru de date (ICMP de ex). Singura diferenta intre logica de forwarding de la task-ul 2 si task-ul 3 este ca acum se verifica si daca interfata pe care ar trebui sa trimit cadrul este blocata, daca este nemaitrimitandu-se acesta.

Logica de STP este tratata in cazul unui cadru PPDU. Daca datele pe care le avertizeaza switch-ul, respectiv root BID, BID-ul sau si costul catre bridge sunt mai mari decat datele primite de la un switch vecin, se modifica starea globala a switch-ului, respectiv stp_info. Apoi se verifica din nou pentru a seta starile si rolurile fiecarui port.

ex3.jpg

In poza, in fereastra de Wireshark se vad cadrele urmatoare: cel cu Ethernet II este de tip ICMP, cadrul PPDU corespunzator STP-ului si cateva cadre cu destinatia Broadcast corespunzatoare HPDU-urilor lansate la o secunda distanta.

Decizii de design - stari si roluri STP

Initial, inainte sa se ruleze STP-ul, toate interfetele switch-urilor sunt in Starea FORWARDING in DESIGNATED role, deoarece initial toate pot trimite. In urma rularii STP-ului, sunt 3 stari posibile:

  1. Root port: ROOT_PORT (Role) si FORWARDING (State)
  2. Designated port: DESIGNATED (Role) si FORWARDING (State)
  3. Non-Designated port: BLOCKING (Role) si BLOCKING (State)

Practic am 3 tranzitii posibile din orice stare. Orice port poate trece intr-una din starile astea indiferent de starea lui curenta. Conteaza aceste comparatii:

    my_adv = (stp_info.root_bid, my_cost, stp_info.my_bid, my_port)
    neigh = (root_bid, root_cost, bid, pid)

    if stp_info.root_port == interface:
        port_roles[interface] = PortRole.ROOT_PORT
        port_states[interface] = PortState.FORWARDING
    elif my_adv < neigh:
        port_roles[interface] = PortRole.DESIGNATED
        port_states[interface] = PortState.FORWARDING
    else:
        port_roles[interface] = PortRole.BLOCKING
        port_states[interface] = PortState.BLOCKING

Aceste if-uri se rezuma la: daca oferi calea cea mai buna, inseamna ca esti root port, altfel daca anunti calea cea mai buna, esti designated port, iar la final, daca nu oferi calea cea mai buna si nici nu o desemnezi, esti port blocat.

Auto-evaluare:

E posibil sa fi facut mici optimizari, cum ar fi sa nu folosesc un dictionar pentru a mapa interfetele la diferite obiecte (stari, roluri, vlan_id), ci sa folosesc o lista din python (adica un vector), intrucat lista ar face accesul mai rapid la date, dar trebuie alocata in prealabil, si ar putea fi indexata dupa interfata, intrucat acestea sunt de la 1 la num_interfaces. Am ales dict() pt ca mi se pare mai usor de folosit, si teoretic ofera aceeasi complexitate. In acelasi timp, daca as fi indexat dupa numele interfetei (ex: FastEthernet0/1), mi ar fi fost de folos dict, deci e mai flexibil.

De asemenea, este posibil sa nu fi verificat toate cazurile teoretice pentru input, dar asta pentru ca in enunt se specifica aspecte precum: "vom presupune că switch-urile nu se pot strica".

About

Python Switch implementation with a focus on STP and VLANs.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published