|
vs. |
|
w konkurencji
|
Collision Avoidance Protocol
|
Problem
Collision Avoidance Protocol jest stosowany w Ethernecie jako nakładka
na protokoły typu CSMA/CD, czyli opóźniające transmisję w razie
możliwości kolizji. Wymagania stawiane omawianemu protokołowi to:
- wykluczenie kolizji, a co za tym idzie:
- ustanowienie górnego ograniczenia opóźnienia
transmisji, pod warunkiem, że są one bezbłędne
- dostarczanie wysłanych pakietów do wskazanych adresatów tzn. bez pomyłek
Założenia dotyczące medium są następujące:
- medium rozgłasza pakiety do wszystkich podłączonych doń stacji
- medium jest zawodne
Rozwiązanie
Prostym rozwiązaniem jest wprowadzenie nadrzędnej stacji,
która po kolei (wedle strategii Round-Robin) odpytuje zwykłe stacje, czy chcą
nadawać. Pomiędzy kolejnymi zapytaniami czeka przez określony czas.
Model rozwiązania
Wszystkie stacje (zwykłe user i nadrzędna master)
oraz medium (medium) są reprezentowane przez oddzielne
procesy. Dodatkowo każda stacja zwykła ma swojego sekretarza
(slave) pośredniczącego w jej komunikacji z medium. Sekretarz
rozdysponowuje nadchodzące pakiety. Przede wszystkim sprawdza, czy są
one adresowane do jego stacji i tylko wtedy je rozpatruje.
Rozpatrywanie polega na ustaleniu, czy pakiet jest zapytaniem od
stacji nadrzędnej czy zwykłym pakietem z danymi od innej stacji. W
pierwszym przypadku prosi swojego zwierzchnika o dane, a w drugim mu
je przekazuje. Stacja może odrzucić propozycję nadania.
Wszelka komunikacja
jest synchroniczna i odbywa się po następujących kanałach:
- to_medium - sekretarze i stacja nadrzędna nadają do
medium
- from_medium - medium rozgłasza do sekretarzy i stacji
nadrzędnej
- prywatne in - staje zwykłe nadają do swoich sekretarzy
- prywatne out - sekretarze nadają do swoich stacji
Zawodność medium (założenie 2.) polega na
możliwości nierozgłoszenia niektórych kopii pakietu.
Realizacja modelu w Spinie
Kod źródłowy
Akapit ten można traktować jak zbiór krótkich przewodników pt. "Jak
zrobić ... w Spinie".
Komunikacja synchroniczna
Komunikacja synchroniczna została zrealizowana za pomocą kanałów o
zerowej pojemności.
/* format pakietu w sieci: nadawca, adresat, dane */
chan to_medium = [0] of {byte, byte, byte};
chan from_medium[N] = [0] of {byte, byte, byte}; /* rozgłaszanie */
/* sekretarz przekazuje otrzymane dane swojej stacji */
chan out[N] = [0] of {byte}; /* powinno być N-1, ale składnia nie pozwala */
/* sekretarz odbiera od swojej stacji adresata i dane do wysłania */
chan in[N] = [0] of {byte, byte}; /* j.w. */
Sprawdzanie, czy nie zaszła pomyłka
Nagłówek pakietu krążącego w sieci zawiera identyfikator nadawcy i
adresata. Treścią pakietu będącego zwykłą wiadomością a nie zapytaniem
jest powtórzony identyfikator adresata. Umożliwia to zwykłej stacji
sprawdzenie, czy jej sekretarz przekazuje jej właściwe pakiety.
Odrzucenie propozycji nadania
Treścią pakietu będącego zapytaniem od stacji nadrzędnej jest
specjalna wartość ENQ. Jako że komunikacja jest
synchroniczna, sekretarz odebrawszy taki pakiet od medium, nie
przekazuje go zwierzchnikowi, tylko odbiera od zwierzchnika
identyfikator adresata i treść wiadomości.
Przekształca to w pakiet poprzez dodanie identyfikatora na
nadawcy i wysyła do medium. Jeśli stacja zwykła nie jest
zainteresowana nadawaniem, to zamiast identyfikatora istniejącego
adresata umieszcza INVALID_ID. Pakiet taki nie zostanie nikomu
dostarczony. Aby nie zaśmiecać sieci, sekretarz mógłby to sprawdzić
przed wysyłaniem do medium.
proctype user(byte id; chan cin,cout)
{
byte data;
byte succ = id%(N-1)+1; /* następnik */
do
:: cout?data ->
if
:: data!=id -> goto accept_wrong_data
:: data==id -> skip
fi
:: cin!INVALID_ID,0 /* nie zainteresowany */
:: cin!succ,succ /* adresat = treść (dla weryfikacji) */
od;
accept_wrong_data:
do
:: (1) -> skip
od
}
Rozgłaszanie
Kanały komunikacyjne w języku PROMELA nie posiadają rozgłaszania,
zostało więc ono zaimplementowane jako nadawanie po kolei po każdym z
kanałów w tablicy from_medium.
Jako że język nie zezwala na określanie ciągu zawierającego operacje
blokujące mianem atomowego, to niepodzielność rozgłaszania modelujemy
jako wyłączenie nasłuchu na medium na czas trwania tej operacji. Rozgłaszanie może zatem
przepleść się z komunikacją między stacjami a ich sekretarzami, ale
nie zaburza to oczekiwanej semantyki tej operacji.
active proctype medium()
{
byte sender;
byte receiver;
byte data;
byte i;
do
:: to_medium?sender,receiver,data ->
i=0;
if
:: (1) -> do
:: i<=N-1 ->
if
:: i==sender -> skip
:: i!=sender -> from_medium[i]!sender,receiver,data
fi;
i=i+1
:: i>N-1 -> break
od
:: to_medium?sender,receiver,data -> goto accept_collision
fi
od;
accept_collision: do
:: (1) -> skip
od
}
Zawodność medium
Tak jak zaznaczono w modelu, zawodność medium
polega na niedostarczeniu niektórych kopii pakietu. Przy powyżej
realizacji rozgłaszania wymaga to zatem modelowania zawodności w
sekretarzach. Osiągnięto to łatwo - sekretarz odebrawszy pakiet od
medium, może go po prostu porzucić.
proctype slave(byte id)
{
byte sender;
byte receiver;
byte data;
byte ny_receiver;
byte ny_data;
do
:: from_medium[id]?sender,receiver,data ->
if
:: data!=ENQ ->
if
:: receiver==id -> out[id]!data
:: receiver!=id -> skip
fi
:: data==ENQ && receiver==id ->
in[id]?ny_receiver,ny_data;
to_medium!id,ny_receiver,ny_data
:: data==ENQ && receiver!=id -> skip
fi
:: from_medium[id]?sender,receiver,data /* gubienie pakietu */
od
}
Odczekiwanie pomiędzy zapytaniami
Wysławszy zapytanie stacja nadrzędna musi odczekać, aż na łączu
zapanuje cisza. Język PROMELA oferuje instrukcję timeout,
która blokuje dopóki wszystko w systemie stanie się niewykonywalne i
wtedy sama staje się wykonywalna. Stacja nadrzędna zawsze zawiesza się
na tej instrukcji przed wysłaniem następnego zapytania, bo cisza może
wynikać albo ze zgubienia pakietu albo stąd, że wszyscy odebrali.
active proctype master()
{
byte sender;
byte receiver;
byte data;
byte next;
next=1;
to_medium!0,next,ENQ;
do
:: from_medium[0]?sender,receiver,data
:: timeout -> next=next%(N-1)+1;to_medium!0,next,ENQ
od
}
Weryfikacja w Spinie
Własność pierwsza i trzecia
są łatwe
do zweryfikowania w Spinie w oparciu o wykluczenie cykli akceptacji z
przebiegów. Narzędzie to nie pozwala jednak na tak bezpośrednią
weryfikację własności drugiej, ponieważ nie operuje
pojęciem czasu.
Brak kolizji
Proces medium wykonuje skok do cyklu akceptacji
accept_collision, gdy dwa razy z rzędu odbierze komunikat po
kanale to_medium. Przez dwa razy z rzędu rozumiemy bez
operacji rozgłaszania pomiędzy.
Dostarczenie do właściwego adresata
Proces zwykłej stacji wykonuje skok do cyklu akceptacji
accept_wrog_data, gdy treścią wiadomości jest co innego niż
jego identyfikator.
Realizacja modelu w Uppaalu
Landrynkowy interfejs graficzny Uppaala nie daje się sobie oprzeć i
zachęca do eksperymentowania z różnymi modelami. Proponuję więc
samodzielne przeprowadzanie symulacji w trakcie prezentacji.
Rozgłaszanie
Emulacja rozgłaszania
W chwili powstania pracy, na
której jest oparta ta prezentacja, Uppaal nie oferował wbudowanego
mechanizmu rozgłaszania. Emulowano je za pomocą ciągu lokacji typu
commited, po między którymi przejścia etykietowane były
nadawaniem. Wybranie tego typu lokacji zapewniało niepodzielność
rozgłaszania.
Podejście to, podobnie jak w Spinie, wymaga modelowania
zawodności medium w sekretarzach. Sekretarz może zgubić pakiet, gdy
jest zajęty obsługą poprzedniego pakietu. Stąd lokacje
ignore1 i ignore2, w których sekretarz przebywa nie
dłużej niż do upłynięcia dwóch jednostek czasu od chwili odebrania
pakietu.
Wysyłający dowiaduje się o zakończonym rozgłaszaniu dzięki
synchronizacji z medium po dodatkowym kanale finished, tak
jak robi to stacja nadrzędna.
Warto zwrócić uwagę na czyhające tu niebezpieczeństwo blokady, którego
nie dostrzegli (albo które uznali za pozbawione znaczenia) autorzy systemu. Emulacja rozgłaszania za pomocą lokacji
typu commited pociąga za sobą konieczność nadania tego
atrybutu innym lokacjom pozornie niezwiązanym z rozgłaszaniem. Jeśli
stacja nadrzędna nie dokona zaraz po nadaniu do medium przejścia do
lokacji wait (tzn. nie ustawi czasomierza), to po zakończeniu
rozgłaszania dojdzie do blokady. Przyczyną jest konieczność
opuszczenia przez medium lokacji broadcast4, czego jednak
zrobić nie może, ponieważ nie ma z kim się zsynchronizować po kanale
finished. Analogiczny problem wystąpi, gdy sekretarz zabawi
za długo w lokacji dispatch, a obecny model narzuca mu
pozostanie tam ze względu na niepodzielność rozgłaszania. Wyjściem z
impasu jest przypisanie obu tym lokacjom atrybutu commited.
Podobnie jak to było w Spinie mimo że taka
modyfikacja lokacji dispatch rozbije atomowość rozgłaszania,
nie psuje to modelu. Innym źródłem blokad w Uppaalu jest nieumiejętne
zmuszanie procesu do opuszczenia danej lokacji po dokładnie danym czasie.
Wyłączne postawienie dozoru z równaniem zegarowym na tranzycji
spowoduje, że proces może "przegapić" ten właściwy moment i nie móc
się później wydostać. Omawiany system obfituje w takie przypadki. W
poprawionej wersji odpowiednie lokacje są
zaopatrzone w niezmienniki narzucające ograniczenia czasowe na
pozostawanie w lokacji.
Wbudowany mechanizm rozgłaszania
Nowsze wersje Uppaala oferują wbudowany mechanizm rozgłaszania
posiadający wiele zalet. Po pierwsze eliminuje on opisane powyżej
ryzyko blokady. Po drugie nie wymaga modelowania zawodności medium w
sekretarzach, ponieważ wysyłanie do kanału typu broadcast
jest nieblokujące. Synchronizują się z nim tylko procesy, które mogą
to w danej chwili zrobić. Proponuję zweryfikować własność
A[] not deadlock
dla systemu z poprzedniego akapitu oraz stworzonego przeze mnie systemu korzystającego z nowego mechanizmu.
Weryfikacja w Uppaalu
Zapytania
Brak kolizji
Proces medium osiąga lokację collision, gdy dwa razy z rzędu
odbierze komunikat po kanale to_medium analogicznie do
wejścia w cykl akceptacji w Spinie.
A[] not Medium.collision
Ta podstawowa własność bezpieczeństwa jest bezwarunkowo zachowana
tylko przez niezawodne medium, natomiast w bardziej realistycznych
modelach jak nasz zależy od limitu, jaki stacja nadrzędna wyznacza na
otrzymanie pakietu wysłanego przez zwykłą stację jako odpowiedź na
zapytanie. Stacja nadrzędna ustawia czasomierz, który informuje ją
komunikatem timeout o przekroczeniu tego limitu.
Jeśli limit zostanie przekroczony za prędko, to stacja nadrzędna
zinterpretuje to jako sytuację, w której zgubiono pakiet i wszystkie
stacje zwykłe czekają na dane. Oczywiście nie to musi być prawdziwą
przyczyną, może bowiem zdarzyć się, że sekretarz jest właśnie w
trakcie przekazywania zapytania swojemu zwierzchnikowi. Wtedy może
dojść do kolizji wiadomości od tej stacji z kolejnym zapytaniem
pochopnie wysłanym przez stację nadrzędną. Dzięki Uppaalowi ustalono,
że minimalny limit broniący przed kolizjami to 3. Zachęcam do
poeksperymentowania z wartością TO w Global
declarations.
Ograniczona żywotność
Własności ograniczonej żywotności nie mogą być bezpośrednio wyrażone w
języku weryfikacji Uppaala, dlatego celem ich weryfikacji wprowadza
się do systemu dodatkowe automaty obserwujące pozostałe komponenty.
Obserwacja odbywa się przez komunikację. Dodatkowe kanały sent i
received służą odpowiednio poinformowaniu obserwatora o
nadaniu i odbiorze komunikatu przez zwykłą stację.
Czas obiegu
Najpierw przekonamy się, że istnieje dolne ograniczenie czasu pełnego
obiegu. Każdy automat Round-trip w nowym systemie obserwuje jedną stację i mierzy czas między kolejnymi dokonanymi przez nią nadaniami.
Biorąc pod uwagę pierwszą stację widzimy, że istnieje obieg w 12-stu
jednostkach czasu, ponieważ poniższa własność jest spełniona:
E<> RT0.end and RT0.s == 12
Nie można jednak tego oszacowania polepszyć, gdyż następująca własność
już nie zachodzi:
E<> RT0.end and RT0.s < 11
Co ciekawe, analogiczne własności z wartościami odpowiednio 18 i 17
zachodzą dla systemu zawierającego błędy
opisane przy okazji rozgłaszania.
Czas transmisji
Autorzy twierdzą, iż przy założeniu niezawodności medium oraz
zainteresowania nadawaniem ze strony każdej zapytanej stacji udało im
się ustalić górne ograniczenie opóźnienia transmisji oraz odstępu
pomiędzy kolejnymi nadaniami. Automat obserwujący BL osiąga lokację
bad_trans, jeśli odbiór nastąpił później niż w T
jednostek po nadaniu i lokację bad_int, jeśli interwał
pomiędzy nadaniami przez kolejne stacje był dłuższy niż I.
Żądana własność to:
A[] not (BL.bad_int or BL.bad_trans)
Uogólnienie metody
Te dwa przykłady ilustrują wyrażenie ograniczonej żywotności w
terminach osiągalności stanów przez automaty obserwujące. Podobnie jak
Spin potrafi generować postulaty never-claim wprost z formuł
LTL, tak można automatyzować budowę automatów obserwujących na
podstawie własności wyrażonych niektórych logikach np. Safety and
Bounded Liveness Logic. Oto prosta logika Simple Time Logic wraz z
indukcyjną konstrukcją automatów dla formuł (litery przy formułach
odpowiadają literom pod automatami). Formuła jest spełniona wtedy i
tylko wtedy, gdy stan bad jest nieosiągalny.
- prawda
- fałsz
- można wykonać akcję a nie później niż po czasie
N
- każda a-tranzycja wykonana przed upływem czasu N
prowadzi do stanu, którym spełniona jest formuła reprezentowana przez
automat T
- koniunkcja formuł reprezentowanych prze automaty T1 i
T2
- każdy osiągalny stan automatu spełnia formułę reprezentowaną przez
automat T
Wniosek
Tytuły prezentacji jak ten bywają przewrotne, wymienione w nim narzędzia
okazały się bowiem wzajemnie komplementarne.
Justyna Sidorska, maj 2004