DQQLH n i v e r s i t à d e g l i S t u d i d i P a l e r m o F a c o l t à d i I n g e g n e r i...

97
U n i v e r s i t à d e g l i S t u d i d i P a l e r m o F a c o l t à d i I n g e g n e r i a Corso di Laurea in Ingegneria Informatica progetto: $FWLYH1HWZRUNV1HZ,QWHOOLJHQW([SORUDWLRQ di progetto realizzato da /XSDUHOOR$OHVVDQGUR presentato come tesina per l’esame di I n t e l l i g e n z a A r t i f i c i a l e (corso tenuto dal prof. S.Gaglio nell’aa. 1998-1999) maggio 1999 DQQLH $OV:ROI

Transcript of DQQLH n i v e r s i t à d e g l i S t u d i d i P a l e r m o F a c o l t à d i I n g e g n e r i...

U n i v e r s i t à d e g l i S t u d i d i P a l e r m oF a c o l t à d i I n g e g n e r i a

Corso di Laurea in Ingegneria Informatica

progetto:

$FWLYH�1HWZRUNV��1HZ�,QWHOOLJHQW�([SORUDWLRQdi

progetto realizzato da

/XSDUHOOR�$OHVVDQGUR

presentatocome tesina per l’esame di

I n t e l l i g e n z a A r t i f i c i a l e(corso tenuto dal prof. S.Gaglio nell’aa. 1998-1999)

maggio 1999

D�Q�Q�L�H�$OV��:ROI�

D�Q�Q�L�H

progetto di studio ed applicazione software effettuata nel campo delle reti attive, PLANet in particolare.La parte software è stata realizzata in linguaggio PLAN (Packet Language for Active Networks) v.3.1(scritto in OCaml), sperimentata e testata su una rete PLANet comprendente alcuni computers deilaboratori 1 e 2 del CERE (Centro Studi sulle Reti di Computers, del CNR) ed altre macchine dislocate inaltre parti del mondo (si rimanda all’appendice A per una descrizione più accurata).

$OV��:ROI

Luparello Alessandro( Palermo, 11 Febbraio 1976)

matricola n. 0319099U n i v e r s i t à d e g l i S t u d i d i P a l e r m oIngegneria Informatica

v.le Regione Siciliana S.E. n.726 90129 Palermotel: 091-596177

Indice sinteticoContents

Prefazione ………………………………………………… Preface …………………………. 5

I Reti attive …….…………………………..……. Active Networks ………………. 6

1. Reti attive …………………………………………………………………………………….. 72. PLANet ………………………………………………………………………………………… 133. Linguaggio PLAN ………………………………………………………………………….. 28

II Analisi del progetto software ………. Analysis ………………………….. 48

4. Analisi del problema ……………………………………………………………………… 495. Analisi dell’algoritmo di risoluzione ideato ………………………………………. 52

III Osservazioni conclusive ………………… Observations……………………. 70

6. Osservazioni conclusive ……………………………………………………………………71

Appendici A. Prova sperimentale………………………………………….. 82B. Codice ………………….…….………………………………… 87

Riferimenti bibliografici ……………………….. Reference ……….………………..

Indice …………………………………………………………………………….………………..

PrefazionePreface

In questa brevissima introduzione voglio limitarmi a presentare il progetto D Q Q L H, frutto di

attenta analisi e meticolosa dedizione, come esperienza di ricerca. Esperienza che non posso

che reputare indubbiamente molto positiva, costruttiva ed importante.

Per lo studio delle reti attive in generale, e di PLANet in particolare, ci si è basati sui risultati di

ricerche effettuate prevalentemente da istituti quali il MIT, Massachussetts Institute of

Technology (Software Devices and Systems Group – Laboratory for Computer Science e

Telemedia, Networks and Systems Group) e la University of Pennsylvania (Department of

Computer and Information Science: Switchware project).

Per quel che riguarda la realizzazione pratica del progetto adesso presentato, è doveroso

sottolineare la collaborazione con l’ICSI (International Computer Science Institute) di Berkeley,

che ha anche permesso di utilizzare proprie macchine per la costruzione della nostra rete.

Ringraziamentiacknoledgments

Un cenno particolare va fatto in relazione al gentile interessamento (ed ai suggerimenti dati) del

prof. Michael Hicks, della University of Pennsylvania1. Ringrazio, ovviamente, il dott.

Giuseppe Di Fatta (all’ICSI di Berkeley), per i consigli ed il materiale fornitomi. Ringrazio

infine tutti quelli2 che hanno reso possibile, comodo e confortevole il mio lavoro all’interno

delle strutture universitarie3 (CERE, Centro di Studi sulle Reti di Elaboratori del CNR).

5 Uno dei principali ideatori del progetto PLANet, come si evince dalla ricorrenza del suo nometra gli autori del materiale utilizzato per il nostro studio (riferirsi alla bibliografia). Riguardo allo specificosupporto cui si è fatto cenno, si prega di fare riferimento alle note 7 ed 8 (ed al testo ad esse relativo) dellasezione 6 (osservazioni conclusive).2 Mi dispiace non essere in grado di elencare i nomi di queste persone: si tratta, comunque, di tuttii professori, assistenti e ricercatori (che si sono mostrati –tutti- affabili e cortesi (se non amichevoli) purdovendo sopportare a lungo la mia presenza, spero di non troppo disturbo) e di tutto il personale presente(sempre gentile…).3 Cosa che, mi dispiace enormemente dirlo, non può pensarsi scontata, ovvia e normale (comeinvece credo debba essere, in un contesto di sviluppo vero, attivo, concreto ed aggiornato degli studenti,dei progetti, dell’Università tutta e –conseguentemente- della nostra amata città e dell’intera società).Almeno nell’Università di Palermo cui pure sono fiero d’appartenere (più per campanilismo siciliano cheper razionali motivazioni) ed al cui miglioramento (o risanamento ?) vorrei, in minima parte (per quelloche mi compete), contribuire. Quanto detto, a titolo (ovviamente…) strettamente personale, è da ritenersiprivo di gratuite intenzioni polemiche (sterili lamentazioni, pur sempre molto in voga, vorrei nonappartenessero alla mia esperienza ed al mio bagaglio culturale) ma come (anche se piccolo…) sprononella direzione di una reale rinascita dell’ateneo palermitano.

3DUWH�3ULPD

R E T I A T T I V E$FWLYH�1HWZRUNV

Sezione 1

Reti attiveActive Networks

Introduzione

Abstract

Le reti attive permettono alle applicazioni di iniettare programmi in nodi di una rete locale o,

cosa più importante, su una rete geografica (wide area networks). Implicano veloci innovazioni

dei servizi forniti, essendo particolarmente facile sviluppare nuovi servizi di rete. Verranno

esplorati i concetti, ed in qualche modo l’architettura, delle reti attive, effettuando talora anche

confronti con la diffusa rete Internet.

Perché intodurre le reti attive?

Il ritmo delle innovazioni nelle applicazioni di rete è inesorabile. Nuove applicazioni continuano

ad emergere rapidamente e spesso riescono a trarre maggior beneficio (in termini di

performances) da servizi di rete che risultino particolarmente flessibili (adattandosi alla diversa

tipologia delle applicazioni, alle diverse necessità). Si è cominciato con l’osservare che, mentre

è comunque possibile sviluppare nuove routines di servizio in sistemi terminali, la loro

implementazione in nodi interni alla rete o perfino nello stesso strato di rete (network layer)1

spesso riusciva ad offrire migliori funzionalità e consentiva sensibili vantaggi nelle prestazioni.

Sfortunatamente l’attuale processo di modifica dei protocolli di gestione di rete è lento e

particolarmente difficoltoso, a causa della necessità di una standardizzazione che deve risultare

(ovviamente) compatibile con l’intera situazione presente.

1 Per dettagli in merito, ci si può riferire a qualunque testo relativo alla gestione delle reti dicomputers (testo di telematica, in generale). Ad es. citiamo [11]: Andrew Tanenbaum, Reti di computers.

Parte I, Sezione 1 Reti attive8

Le reti attive puntano a risolvere il problema della lentezza nell’evoluzione dei servizi di rete

mediante l’introduzione di un certo grado di programmabilità all’interno delle stesse

infrastrutture di rete, permettendo quindi un semplice e rapido inserimento di nuovi servizi.

Si crede fermamente nel fatto che l’abilità a costruire servizi di rete su misura per le

applicazioni riuscirà, in ultima analisi, a giustificare l’overhead necessario alla protezione

delle reti stesse. Conformemente a queste idee la ricerca sulle active networks sembra

focalizzarsi su due punti essenziali:

1. In che modo i nuovi servizi di rete possono essere utilizzati per potenziare le prestazioni

delle applicazioni.

2. Come è possibile costruire infrastrutture di rete programmabili senza compromettere le

prestazioni locali e le proprietà di sicurezza dell’intera rete.

Tradizionalmente le reti effettuano un passivo smistamento di pacchetti tra nodi terminali

(end-to-end): i dati utente (user data) sono trasferiti in modo “nascosto”, la rete è “insensibile”

ai bits che la attraversano e si limita ad instradarli senza effettuare alcuna modifica.

Le reti attive intendono rompere con questa tradizione permettendo alle reti di eseguire

elaborazioni “personalizzate” sui dati. Tali reti si possono dire attive in due sensi:

1. I routers eseguono calcoli sui dati utente che fluiscono su di essi.

2. Individui possono iniettare programmi nella rete, cosicché i processi sui nodi possano

diventare applicazioni specifiche per l’utente.

Sono stati individuati vari approcci architetturali alle reti attive. Uno di questi, ritenuto di

particolare interesse, rimpiazza i pacchetti passivi, dell’architettura dei giorni nostri, con

capsule attive: piccoli programmi che sono eseguiti in ogni router che attraversano. Questo

cambiamento nella prospettiva di visione delle architetture di rete, da pacchetti passivi a

capsule attive, verifica simultaneamente entrambe le proprietà di attività or ora descritte.

Le capsule, che contengono incapsulati (embedded) i dati utente, possono invocare metodi

predefiniti o impiantarne di nuovi all’interno dei nodi della rete.

Parte I, Sezione 1 Reti attive9

Vantaggi nell’utilizzo di reti attive

Ci sono tre principali vantaggi nel basare l’architettura di rete nel passaggio da pacchetti

passivi a programmi attivi:

1. Lo scambio di codice fornisce una base per i protocolli adattivi, rendendo le possibili

interazioni molto più cospicue che mediante il semplice scambio di dati a formato fisso.

2. Le capsule creano un mezzo per implementare specifiche funzioni a grana fine

(specifiche) nei punti strategici della rete.

3. L’astrazione di programmazione fornisce una potente piattaforma per una

personalizzazione, guidata dall’utente stesso, dell’infrastruttura, permettendo così a nuovi

servizi di essere sviluppati con un ritmo più veloce.

Diversi approcci alle reti attive

Si distinguono essenzialmente due diversi approcci alle reti attive:

A. Routers programmabili: approccio discreto

La gestione dei messaggi può essere architetturalmente separata dalle operazioni di

iniezione dei programmi nei nodi, per mezzo di un separato meccanismo per ognuna delle

funzioni.

Quando un pacchetto arriva, la sua intestazione (header) viene esaminata ed un

programma viene dedicato ad esaminare il suo contenuto; il programma analizza

attivamente il pacchetto, possibilmente modificandone il contenuto. Un grado di

personalizzazione dell’operazione è possibile perché l’intestazione del messaggio può

identificare quale programma dovrà essere eseguito; è perciò possibile, consentendo

l’utilizzo di diversi programmi, l’esecuzione di applicazioni che necessitano trattamenti

anche molto differenti.

Parte I, Sezione 1 Reti attive10

B. Capsule: approccio integrato

Altra estrema visione delle reti attive: ogni messaggio è un programma. Tutti i messaggi

(o capsule) che passano tra nodi contengono un piccolo programma che può inglobare dei

dati. Quando una capsula arriva su un nodo attivo, il suo contenuto viene valutato.

Si ipotizza che il programma sia costituito da istruzioni primitive (di un ridotto linguaggio

di programmazione), che eseguono operazioni elementari sul contenuto delle capsule

stesse e possono, inoltre, invocare metodi esterni, che potrebbero permettere l’accesso a

risorse esterne.

Considerazioni architetturali

La convenzionale architettura di rete separa lo strato superiore (end-to-end) da quello inferiore

(hop-by-hop). Le active networks sfidano questa tradizionale impostazione in diversi punti:

1. Le operazioni eseguite con le reti possono essere dinamicamente modificate.

2. Le reti possono essere rese specifiche per determinate applicazioni o in relazione agli

utenti che vi operano.

Stato attuale della ricerca mondiale sulle active networks

Elenco dei progetti attivi, ordinati per organizzazione:

Organization Research Title

BBN Systems and Technologies Smart Packets

Bellcore Protocol Boostersfor Distribuited Computing Systems

The Fox Project:Advanced Languages for Systems Software

Carnagie Mellon University

Active Networking for Storage

Parte I, Sezione 1 Reti attive11

Organizzation Research Title

NESTOR: Technologies and Protocols for self-managed & self-organizing Networks

Columbia UniversityNetScript: A language-BasedActive Network Architecture

Georgia Institute of Technology CANEs: Composable Active Network Elements

Lawrence Berkeley National Lab. Virtual InterNetwork Testbed (VINT)

Critical Tecnologyfor Universal Information Access

SpectrumWare

Applying Theory to Development ofDistribuited/Real-time Systems

Security for Distribuited Computer System

From Internet to ActiveNet

Robust Multi-Scalable Networks

Massachusetts Institute ofTechnology (MIT)

Specifying and checking security propertiesin an sofware base networks

for Adaptive Multicast ApplicationsThe Open Group ResearchInstitute of the Open SoftwareFoundation, Inc.

CONVERSANT: an environmentfor Real-time, Secure Active Networks

Secure Active Network Prototypes

Enabing High Performance Active Networks viaSecure Exokernal Implementations

Trusted Information Systems, Inc.(TIS)

New Cryptographic Tecniques for Active Networks

University of Arizona Liquid Software

University of California,Berkeley Proactive Infrastructure

Parte I, Sezione 1 Reti attive12

Organizzation Research Title

Adaptive Web CachingUniversity of California,Los Angeles (UCLA)

Middleware Framework

University of California,Santa Barbara

Thunder and Lightning:A communication Network

University of California,Santa Cruz Routing and Multicasting Services

University of Delaware Scalable, High Speed, Internet TimeSynchronization

University of Illinois Building dynamic interoperable securityarchitecture of active networks

University of Pennsylvania Accelerating Network Evolution with aSoftware Switch for Active Networks

Active Network Applications

University of WashingtonDesign and Demonstration of a scalable high

performance active network node

TNT: Reservation protocol(RSVP/RSVP2) Task

TNT: Scalable Personal

Rational ATM Internet Suite

Virtual InterNetwork Testbed (VINT)

USC Information Sciences Institute

Active Reservation Protocol (ARP)

Washington University in St.Louis High Performance Component-BasedDistribuited Applications

Multicast, Multimedia Infrastructure for theInternet

Xerox Palo Alto Research Center

Virtual InterNetwork Testbed (VINT)

Sezione 2

PLANetPLANet: An Active Internetwork

Introduzione

PLANet è sicuramente una rete attiva: essa implementa lo strato di servizio di rete direttamente

sopra le tecnologie dello strato di link, senza relazione con l’esistente infrastruttura IP1. PLANet

è inoltre “puramente attiva”: tutti i pacchetti contengono programmi scritti in un linguaggio

particolare dedicato (special-purpose packet language) chiamato PLAN (“Packet Language for

Active Networks”) e le potenzialità dei nodi possono essere estese mediante il caricamento

dinamico di codice addizionale (per modificare talune funzionalità o introdurne di nuove).

Andiamo adesso ad analizzare i due aspetti che rendono “attiva” la rete PLANet:

1. PLANet usa pacchetti attivi (active packets) che contengono programmi PLAN, come

menzionato prima. Per semplicità e per migliorare le prestazioni, un pacchetto PLAN può

scegliere di appoggiarsi ad un trasporto “passivo” e quindi necessita (in questo caso) di non

essere valutato in ogni nodo intermedio. I programmi PLAN sono tipicamente piccoli e

servono come “collante” tra routines di servizio (service routines) residenti nei routers, che

provvedono alle funzionalità generali (general-purpose functionalities) non esprimibili con

il solo linguaggio (le routines di servizio possono provvedere a semplici informazioni, come

potrebbe essere l’indirizzo dell’host attualmente raggiunto, oppure a funzionalità più

sostanziali, come segmentazione e riassemblamento di pacchetti).

1 IP: Internet Protocol. Per maggiori informazioni confrontare ad es. J.Postel “Internet Protocol”,Tech.Rep., IETF RFC 791, September 1981.

Parte I, Sezione 2 PLANet14

2. I nodi PLANet possono essere programmati tramite caricamento dinamico di estensioni

attive (active extensions) scritte in OCaml5, un “dialetto” del linguaggio di

programmazione ML6. Queste estensioni aggiungono nuove funzionalità, o migliorano

quelle esistenti, e possono generare servizi accessibili dai programmi PLAN. Vengono

utilizzate per programmare servizi essenziali necessari per operare nella rete, come

risoluzione si indirizzi (address resolution), routing, etc…, mentre i programmi PLAN

sono usati con lo scopo di breve comunicazione tra i nodi.

Tale architettura del nodo è visualizzata nello schema qui di seguito:

schizzo dell’architettura di un nodo PLANet

Prima, un pacchetto arriva direttamente attraverso l’interfaccia dello strato di link. Se il

programma ha raggiunto il suo nodo di destinazione (evaluation destination) viene “passato”

all’interprete PLAN per la valutazione, altrimenti è semplicemente instradato (routed) oltre.

Durante la valutazione, i programmi PLAN possono effettuare chiamate a servizi (tramite

service calls), incluso quello che trasmette il programma stesso in un altro nodo per essere

valutato.

PLAN

Molto del design di PLANet è sostanzialmente basato sul linguaggio dei suoi pacchetti (come

probabilmente si è già avuto modo di osservare in precedenza), il Packet Language for Active

5 Riferirsi, ad es., a [9]: OCaml home page: ZZZ�SDXLOODF�LQULD�IU�FDPO�LQGH[�HQJ�KWPO�6 Riferirsi, ad es., a [8]: Robert Harper, “ Introduction to Standard ML”, Carnage MellonUniversity, January 1993

PLAN program(s)

PLAN interpreter

Routing Extension

IP Ethernet

Active Packets

Active Extensions

Link layer

Parte I, Sezione 2 PLANet15

Networks (o PLAN)7. Questo è un “piccolo” linguaggio che ha molti elementi in comune con

altri linguaggi in qualche modo simili, come Haskell, Scheme ed ML8. La differenziazione di

maggiore importanza da questi ultimi è relativa al fatto che PLAN include primitive per valutare

espressioni in nodi “remoti”.

Un’altra speciale caratteristica del PLAN è una semantica impostata su risorse limitate

(resource-limited semantics), che assicura che i programmi abbiano sempre un termine e che i

pacchetti (ed i loro “discendenti”9) visitino al più un numero fissato di nodi.

PLAN è nato con l’obiettivo di essere flessibile a sufficienza per scrivere utili

programmi, ma limitato abbastanza da non permettere che i suoi programmi pongano rischi di

sicurezza. Per contrasto, le routines di servizio -a disposizione dei programmi stessi- sono di

carattere generale (general-purpose) e potrebbero necessitare d’essere protette mediante

crittografia (criptography) o altri mezzi10.

PLANet

PLANet è l’implementazione della rete attiva che andiamo a considerare, basata sull’ambiente

PLAN. Nasce e si sviluppa attingendo, quando possibile, all’esperienza pratica maturata

nell’utilizzo di Internet (e dell’IP); questa indica come sia opportuno seguire alcuni elementi

essenziali (core elements) :

• uniformità di indirizzamento allo strato di rete (network-layer addressing) e del formato dei

pacchetti.

7 Una descrizione sommaria del linguaggio PLAN sarà data anche nel seguito di questa stessasezione; per una trattazione minimamente più organica e più approfondita si può consultare la sezioneseguente (dedicata interamente ed esclusivamente proprio al PLAN).8 Se si vuole, ci si può riferire (ad es.) a:- “Haskell: A purely functional language”,ZZZ�KDVNHOO�RUJ, per l’Haskell- “Scheme home page”, ZZZ�VZLVV�DL�PLW�HGX�VFKHPH�KRPH�KWPO, per lo Scheme� R.Milner, M.Tofte, R.Harper, “The definition of Standard ML”, the MIT Press, 1990, oltre al già citato[8] (“ Introduction to Standard ML”), ovviamente per l’ML9 con questa dizione, si vogliono intendere tutti i pacchetti “generati” (ed iniettati nella rete) daquello in esame.10 In questa sezione, né nelle altre di questo lavoro, sarà preso in considerazione l’aspetto dellasicurezza (certamente importante ma molto complesso e forse eccessivamente distante dagli obiettivi checi siamo preposti). Qualora si fosse interessati, ci si potrebbe riferire (ad es.) a:- D:Scott, W.Arbaugh, A.Kerom, J.Smith, “A secure active network environment architecture:

Realization in SwitchWare”, IEEE Network Magazine, vol 12, no.3, pp. 37-45, 1998, Special issueon Active and Controllable Networks.

� M.Hicks, “PLAN sistem security”, Technical Report MS-CIS-98-25, Dep.of Comp.and InformationScience, Un.of Pennsylvania, April 1998.

A disposione, su Internet, all’indirizzo ZZZ�FLV�XSHQQ�HGX�aVZLWFKZDUH�SDSHUV�SURJSODQ�SV

Parte I, Sezione 2 PLANet16

• risoluzione di indirizzi (addess resolution) dello strato di link ad indirizzi dello strato di

rete.

• instradamento (routing) tra reti fisiche.

• “referto” degli errori incontrati (error reporting).

Questi elementi formano l’anima (core part) del PLAN stesso: ad eccezione della risoluzione

degli indirizzi, ognuno è potenzialmente considerabile come un’astrazione nel linguaggio. Da

Internet è inoltre stata adottata l’idea che la valutazione “remota” è la tecnica migliore; la

“consegna sicura” (reliable delivery) può essere ottenuta con l’aggiunta di servizi appropriati.

Oltre questi elementi centrali, sono stati implementati altri servizi, che pure -come i

primi- hanno controparti su Internet. Tali servizi non richiedono standardizzazione e non fanno

parte dei programmi PLAN ma sono elementi di routines di servizio caricabili (loadable service

routines)11 messe a disposizione dei programmi PLAN stessi.

A. Formato dei pacchetti PLAN (Packet Formats)

Per permettere interoperazionalità tra diverse reti fisiche, un’internetwork deve definire un

insieme di formati standard di pacchetti. In PLANet tutti i pacchetti consistono in programmi

PLAN, così che questa standardizzazione si riduce alla definizione di un ordinato schema

(standard) per i programmi PLAN (notiamo che ciò comporta una enorme semplificazione:

consideriamo, ad es., chi deve occuparsi dell’implementazione di nuovi servizi di rete, esso

necessiterà solamente di sapere quale informazione (what) deve essere elaborata, o

semplicemente trasmessa, e non come (how) questa è codificata).

Dall’esperienza con Internet si è ricavato che la maggior parte dei pacchetti richiede

solamente un semplice trasporto, ci si aspetta conformemente che una situazione analoga si

possa verificare (cosa statisticamente attendibile) anche in relazione alle reti attive, PLANet nel

nostro caso. Da qui la conseguente assunzione che un’alta percentuale dei pacchetti PLAN -

presenti nella rete- necessiterà di instradamento e non di valutazione e quindi la scelta di

disporre le informazioni necessarie all’instradamento in una posizione standard per migliorare

proprio l’efficienza di instradamento.

11 Delle routines di servizio a disposizione dei programmi PLAN si parlerà più lungamente (malimitando l’analisi dettagliata –necessariamente- solo a quelle concretamente utilizzate nel progettosoftware) nella sezione seguente (quella dedicata al PLAN).

Parte I, Sezione 2 PLANet17

Il formato dei pacchetti PLAN è illustrato nella figura qui di sotto e descritto di seguito.

Formato dei pacchetti PLAN

Analizziamone adesso, più o meno dettagliatamente, i vari campi (suddivisi in settori):

• Indirizzamento (Addressing)

I primi due campi del pacchetto indicano il nodo di destinazione dove il

programma dovrà essere valutato (evaluation destination, brevemente

evalDest) ed il nodo sorgente (source), che identifica il “nome” del

nodo che ha -per primo- generato il pacchetto (informazione utilizzata,

ad es., nella trasmissione dell’analisi degli errori riscontrati (error reporting)). Come per ogni

altra rete, importante è indubbiamente la risoluzione degli indirizzi dello strato di rete nello

strato di link (per il trasporto fisico).

evalDest

source

rb

session

flowId

routFun

handler

execFn

bindings

code

Address on which to evaluate

Integer global resource bound

Integer session identifier

Integer flow identifier

String name of routing function

String name of exception handler

chrunk

String name of fn to evaluate

List of PLAN value bindings

PLAN code

Address od Source

Parte I, Sezione 2 PLANet18

PLANet adotta un protocollo molto semplice quale l’ARP12 (Address Resolution Protocol).

• Programmi come dati13

Gli ultimi tre campi del pacchetto comprendono il chunk (forma breve di “code hunk”,

letteralmente “pezzetti di codice”), che è essenzialmente il suo (del pacchetto) programma:

- code ……… codice vero e proprio

- execFn …... punto di ingresso alla funzione (forse più chiaro nell’espressione: function entry

point)

- bindings … lista degli argomenti iniziali14

Quando un pacchetto PLAN raggiunge la sua destinazione

(evalDest), il suo codice viene “spacchettato” (si consenta,

senza eccessivi rimproveri, l’uso di questo –non felice (ne

siamo coscienti) ma comodo- termine) e l’appropriata

funzione viene “chiamata”, avendo come parametri gli

argomenti dati.

Osserviamo che, per quanto detto (e soprattutto per quanto non detto), il “chunk” di un

pacchetto potrebbe trasportare altri chunks come fossero dati, realizzando in tal modo un

elegante meccanismo di incapsulamento. Inoltre, con appropriate routines di servizio, i chunks

possono essere frammentati, trasportati, riassemblati e poi, infine, valutati15.

12 Come ci si può immaginare, non è negli obiettivi del presente lavoro (né, pur volendo, potrebbeessere) l’addentrarsi in particolari tecnici (fondamentali, magari interessanti, ma particolarmente ostici peri “non addetti” e per chi ha finalità diverse, precise ed improcrastinabili) quale, ad es., proprio larisoluzione degli indirizzi. Per quanto riguarda questo argomento si potrebbe rimandare ad una futurapubblicazione dello stesso autore oppure (per non costringere ad una lunga, estenuante, snervante e –probabilmente- inutile attesa chi fosse interessato) ad una delle pubblicazioni seguenti:- D.C.Plummer, “An Ethernet address resolution protocol”, Tech.Rep., IETF RFC 826, 1982- C.Hendrick, “Routing information protocol”, Tech.Rep., RFC 1058, June 1988- [11] Tanembaum, “Reti di Computer”.13 Un’esposizione più puntuale e meno astratta si può trovare nella sezione seguente.14 Gli argomenti sono valori PLAN che hanno un loro formato, come descritto nella sezione, aquesta, successiva.15 Questo permette di superare con semplicità l’ostacolo del limite –invalicabile come le zonemilitari- dato dall’MTU (maximum transferable unit). Tale limite consiste, molto brevemente, in unadimensione massima imposta ad ogni pacchetto che si muove sulla rete fisica. Per maggiori informazioni,si rimanda alla consultazione di articoli o testi specifici.

Parte I, Sezione 2 PLANet19

• Campi rimanenti

(Maggiori dettagli su alcuni di questi campi saranno dati nella sezione successiva, allorquando verranno prese in

considerazione le funzioni delle routines di servizio che, in un modo o nell’altro, interagiscono proprio con i suddetti

campi. Per gli altri si preferisce non andare oltre la succinta descrizione seguente)

Il terzo campo del pacchetto è un limite di risorse (resource bound): consiste nel massimo

numero di nodi che al pacchetto stesso è consentito attraversare (essenzialmente per porre un

freno alla moltiplicazione dei pacchetti, ed evitarne una permanenza “infinita” nella rete). Il

campo session funge da identificatore per i programmi applicativi sull’host, mentre il campo

flowId identifica il flusso di pacchetti attraverso un router.

B. Instradamento dei pacchetti (Routing)

Per determinare la direzione che un pacchetto PLAN dovrà prendere (next hop; ovvero il

prossimo nodo da attraversare, tra gli adiacenti a quello considerato e nella direzione di quello

di destinazione), ogni nodo intermedio valuta –in ogni pacchetto- la specificata routFun, che

“chiama” una routine di servizio residente nel nodo stesso.

Viene scelto tale approccio come alternativa a due punti estremi:

1. Si potrebbe richiedere che tutte le possibili destinazioni di valutazione (evaluation

destinations) siano dislocate esclusivamente all’interno della stessa rete del mittente; per

raggiungere destinazioni distanti, i pacchetti sarebbero valutati in ogni nodo intermedio per

determinare la prossima via di instradamento (next hop): la funzione di routing varierebbe

Sorgente

Destinazione

Parte I, Sezione 2 PLANet20

in relazione del nodo e del pacchetto. Un tale approccio risulterebbe senz’altro godere della

massima flessibilità, di contro –però- non potrebbe non dirsi molto costoso, sia in termini di

prestazioni (performance) che di convenienza (e comodità) per il programmatore.

2. Altro estremo è quello di implementare un unico protocollo di routing per tutti i nodi della

rete (o per una porzione autonoma di questa) e forzare tutti i pacchetti ad essere instradati

secondo tale determinazione.

Il considerare una funzione di routing relativa al pacchetto (e non più, quindi, ai nodi della rete)

serve come alternativa che non vuole favorire (e realmente non favorisce) nessuna strategia di

routing a discapito delle altre, risultando persino una scelta “leggera”: individua la direzione di

instradamento senza richiedere che il pacchetto venga valutato. L’unico costo aggiuntivo è

solamente quello relativo all’esecuzione della funzione di routing stessa.

La maggior parte dei pacchetti specifica una funzione di routing defaultRoute (che,

ovviamente, rappresenta la funzione di routing di default). Questa è implementata come un

semplice vettore di distanze di instradamento basato essenzialmente sul RIP16.

C. Analisi e gestione degli errori (Diagnostics and Error Handling)

Gli errori che possono presentarsi nell’ambito di una rete sono suddivisibili essenzialmente in

due categorie: errori di pacchetto (packet-level errors) ed errori relativi allo stato di rete

(network-level errors).

Gli errori di pacchetto si presentano quando un particolare

pacchetto fallisce il corretto raggiungimento della propria

destinazione, probabilmente perché tale destinazione è

troppo distante (il suo raggiungimento richiede una

quantità di risorse17 superiore a quelle disponibili che –

quindi- si esauriscono).

16 Alla strategia RIP viene dedicato una piccola annotazione nella sezione seguente: LinguaggioPLAN (relativamente alla presentazione del package di servizio RIP), qualora tali informazioni fosseroritenute insufficienti potrebbero consultarsi (ed es.) i testi già elencati nella precedente nota 12 (dellastessa sezione).17 Ricordiamo di aver già accennato al concetto di risorse proprio nella pagina precedente inrelazione allo schema del formato del pacchetto PLAN.

Parte I, Sezione 2 PLANet21

Errori di pacchetto sono inoltre (generalmente) sintomatici di anomalie a livello di rete: un ciclo

presente nella tabella di instradamento non può che provocare la terminazione del pacchetto

senza che questo possa raggiungere la sua destinazione.

Possiamo osservare che in una rete ben progettata, le applicazioni dovrebbero sempre

cercare di “catturare” (handle) gli errori a livello di pacchetto, così come gli amministratori

della rete stessa dovrebbero “diagnosticare” (diagnose) gli errori a livello di rete.

I mezzi mediante i quali gli errori a livello di pacchetto possono essere “catturati” sono molto

ricchi in PLAN, che da un livello di astrazione sono stati calati a livello di programma. Gli

errori che si presentano durante la valutazione del programma possono essere catturati

direttamente dal programma stesso, mentre errori che vengono alla luce nella fase di

instradamento possono essere catturati e manipolati dal nodo sorgente, mediante la routine di

servizio nominata nel campo handler del pacchetto18.

D. Dettagli implementativi

(tutte le informazioni qui presenti sono relative all’implementazione della rete PLANet, effettuata dal Department of

Computer and Information Science, University of Pennsylvania)

PLANet è implementato in OCaml v.2.0019 nello spazio utente del Kernel Linux ver. 2.0.30. La

scelta proprio di uno spazio utente sembra essere stata largamente motivata dalla convenienza

mentre non pochi sono stati gli sforzi per integrare PLANet nel kernel di vari sistemi operativi.

Perché OCaml ?

L’implementazione con questo linguaggio permette una completa indipendenza dalla macchina

ed un caricamento/scaricamento di codice (che risulta essere qualità indispensabile per il

caricamento dinamico delle estensioni attive). Inoltre, il codice sorgente OCaml è liberamente

disponibile, fatto oltremodo conveniente per le necessarie modifiche dirette alla specificazione

delle caratteristiche della rete.

18 Si riveda, a tal proposito, lo schema del formato del pacchetto PLAN.19 Come si è già avuto modo di dire in precedenza (e probabilmente si ripeterà nella sezionesuccessiva), per entrare in merito a questo linguaggio di programmazione potrebbe consultarsi il sito(citato nella nota 2) [9]: OCaml home page: ZZZ�SDXLOODF�LQULD�IU�FDPO�LQGH[�HQJ�KWPO�

Parte I, Sezione 2 PLANet22

Costruzione effettiva dei nodi attivi

Si è più volte detto (con anche troppa enfasi nella prefazione) che questo lavoro si inserisce (pur

come piccolissimo tassello) in un contesto ampio ed articolato20 di ricerca e studio attuale (vi si

lavora da non più di due anni, ben pochi punti possono ritenersi –di conseguenza-

definitivamente raggiunti e stabili), è quindi intuibile come diverse cose possano essere ancora

da definire, da “sistemare”, possano sembrare magari solamente abbozzate o drasticamente

semplificate21. E’ questo il caso (anche se si possono fare, e si faranno, esempi più evidenti e più

adatti) della costruzione materiale della rete.

Come si costruisce una rete PLAN?

E’ necessario pianificare la rete da costruire, e nel senso più restrittivo del termine:

Bisogna indicare (in un abbozzo di schema, per memorizzazione personale) il nome di tutti i

nodi (ossia il “nome” della macchina sulla quale si vuole lanciare il nodo attivo), tutti i

collegamenti tra loro (mediante specificazione delle interfacce nodo-nodo), il fatto se il nodo

debba essere un router o un host (ossia con possibilità di iniettare pacchetti dall’esterno),…

Tutte queste informazioni (che nel seguito saranno analizzate con più metodo, più chiaramente e

sicuramente più dettagliatamente) dovranno poi essere utilizzate per la costruzione effettiva,

nodo per nodo, della rete attiva.

Cominciamo con l’analizzare il comando che permette di “attivare” un nodo nella rete PLAN:

pland

Sintassi:

pland [-router] [-ip port] [-l log] [-rf rout_tab_file] [-hf host_table_file][-keypub public_key_file] [-keypriv private_key_file] [-policy policy_file]ifc_spec_file

comando necessario per costruire un nodo della rete attiva PLAN, secondo determinati parametri(si fa osservare che sono da intendersi come opzionali i parametri posti tra parentesi quadre)

20 Si confronti, a tal proposito, lo schema riassuntivo già evidenziato nella sezione precedente(quella relativa alle reti attive nel loro complesso).21 Intendo riferirmi alla problematica relativa a talune scelte drastiche e semplificative, forse anche“rozze” nella loro implemementazione, quali possono essere –ad es.- quelle sul package resident (comepuò leggersi nella sezione successiva, dedicata, appunto, all’analisi del linguaggio PLAN), che rivelano inmaniera molto esplicita la condizione di “work in progress” nella progettazione tutta.

Parte I, Sezione 2 PLANet23

Descrizione:

Pland è un demone (daemon program) che implementa un router attivo PLAN per la versione

3.1 del PLAN stesso. Attualmente pland può lavorare esclusivamente su sistemi UNIX ma sono

allo studio quei cambiamenti necessari per permettere l’esecuzione anche in sistemi Windows.

Esiste inoltre una versione di PLAN (la 2.2) scritta in Java, per questa la funzione che crea il

router attivo è nominata ARMain22.

Pland ed ARMain non sono compatibili l’uno con l’altro: ARMain trasmette e riceve

pacchetti incapsulati mediante ANEP, mentre pland “abbandona” l’incapsulazione ANEP per

utilizzare un formato di pacchetto più ottimizzato23.

Pland comunica con le applicazioni locali (definite applicazioni host, host applications)

mediante UNIX domain socket (ci si riferisca alla descrizione dell’opzione –ip). A seconda del

valore di alcuni flags usati durante l’attivazione del nodo, questo può utilizzare una

combinazione di due strati di link (link layers): Ethernet ed UDP/IP (come questi strati di link

sono scelti è deciso nel contenuto del ifc_spec_file; dettagli sul cui formato sono specificati di

seguito). Tali due link layers possono essere usati singolarmente o in combinazione;

essenzialmente questo permette di separare (isolare) reti PLANet basate su Ethernet salvo poi

connetterle (magari), tramite opportuni “tunnel”, ad Internet. Inoltre l’uso di UDP/IP consente a

più router attivi di essere presenti nello stesso host (ovviamente considerando numeri di porte

differenti).

indirizzi : gli indirizzi PLAN (strato di rete, network layer) sono costituiti da due

componenti: un indirizzo, di 32 bit, ed un numero di porta, di 16 bit.

Quando si lavora utilizzando Ethernet, la scelta di questi due campi è del tutto

arbitraria; mentre, se è UDP/IP ad essere utilizzato, la porzione dell’indirizzo

(primi 32 bit) deve corrispondere all’indirizzo IP della macchina sottostante e la

porzione di porta (ultimi 16 bit) deve essere una porta UDP non già utilizzata.

22 Può essere utile sapere (probabilmente non più che a titolo di curiosità) che l’implementazionedel progetto che si sta cercando (in modo -si spera- chiaro e lineare) di presentare, era stata iniziatautilizzando proprio la versione 2.2 di PLAN, scritta in Java. Si è passati poi (a lavoro già avviato ma consolo pochissimi inconvenienti, lo si ammette sinceramente) alla versione più avanzata per i vantaggi chequest’ultima portava come dote personale (specie in confronto con la versione più antica, troppodipendente dal suo linguaggio di costruzione), vantaggi –comunque- più volte accennati in precedenza.23 Non si vuole entrare nel dettaglio delle tecniche di incapsulazione (come già fatto più volte, sipreferisce non divagare in argomenti ritenuti troppo specifici e non strettamente utili alla comprensionedel progetto presentato). Per maggiori informazioni ci si può riferire, ad es., a:- D.S.Alexander, B.Branden, … “Active Network Encapsulation Protocol (ANEP)”, RFC, ANEP doc.- formato del pacchetto PLANet, in questa stessa sezione.

Parte I, Sezione 2 PLANet24

Per abilitare un servizio di sicurezza, un nodo PLAN può essere associato ad una coppia di

chiavi (pubblica e privata). Inoltre, è possibile specificare un file di supervisione (policy file) per

indicare il servizio di “polizia” da attivare automaticamente “all’accenzione” (start-up) del

nodo. Pland può utilizzare tecniche di instradamento statico o dinamico; il primo è in relazione

ad una tabella di startup, il secondo (considerato come default) è realizzato mediante un

protocollo di instradamento del tipo RIP24.

Opzioni del comando in linea (Command-line options)

- router specifica il modo router (router mode); questa opzione elimina la

possibilità del nodo di ricevere traffico locale dalla porta di riferimento

(implicit port).25 Questo potrebbe implicare (e generalmente implica) un

vantaggio nelle prestazioni del nodo (essenzialmente in termini di

tempo).

- ip incoming port Specifica il numero della porta di riferimento del nodo (implicit port),

che coinciderà con la porta di iniezione (injection port) qualora si

dovesse utilizzare il nodo in oggetto per iniettare un pacchetto nella

rete. Si considera, come default, in numero 3324.

- l logfile Specifica il nome del file dove scrivere i messaggi di logging (una sorta

di “diario di bordo” della valutazione dei pacchetti nel nodo).

- rf routfile Specifica che deve essere usata la tecnica di instradamento statica, la

cui tabella può essere trovata proprio nel routfile. Questo file ha la

forma di una lista di coppie di hosts: il primo elemento della coppia

indica un nodo della rete, il secondo indica il prossimo passo (hop)

verso questo (ossia il nodo, adiacente a quello in questione, nella

direzione di raggiungimento del primo).

24 Come si sarà certamente osservato, questa parte è quasi solamente accennata. La motivazionerisiede nel fatto che si tratta adesso di dettagli molto sofisticati che, sebbene sarebbe indubbiamente utileconsiderare ed approfondire, si preferisce non trattare nello specifico (come del resto si avrà modo diribadire nel seguito) perché non strettamente necessari allo sviluppo del progetto D Q Q L H e relativamentecomplessi.25 Ci si può riferire alla parte introduttiva della sezione successiva (PLAN), per un modelloschematico esemplificativo.

Parte I, Sezione 2 PLANet25

Qualora il primo elemento della coppia sia la parola default, allora la

direzione è quella da prendere nel caso si cerchi di raggiungere un nodo

non presente nella tabella (instradamento di default).

- hf hostfile Specifica il file che deve essere utilizzato per risolvere i nomi di host

(risoluzione imposta, ad esempio, già dalle funzioni di routine

getHostByName e thisHost).

Il formato che deve avere questo file è del tipo seguente (che riportiamo

con significato esemplificativo, utilizzando però solo connessioni di

tipo IP, non Ethernet):

176.123.6.23 archimede.cere.pa.cnr.it archimede arc176.123.6.12 galileo.cere.pa.cnr.it galileo128.32.201.59 panella.icsi.berkeley.edu panella

Osserviamo che ogni linea consiste in almeno due campi, separati da

spazi bianchi. Il primo è l’indirizzo del nodo, nel formato utilizzato

nell’IP (4 numeri compresi tra 0 e 255 (rappresentabili in 8 bit) separati

da un punto), il secondo campo rappresenta il domain name della

macchina. Eventuali altre parole (nella stessa riga) indicano nomi

(abbreviativi) equivalenti (nell’esempio fatto, archimede oppure arc

sono utilizzabili al posto del nome esteso archimede.cere.pa.cnr.it).

Il file di default è considerato con il nome di EXP_IP_ADDRS e

cercato nella directory attuale (quella dove si trova pland).

- keypub pubfile Specifica il file contenente un codificatore (a 64 bit) per la chiave

pubblica del nodo. Se questa opzione non è specificata, si ricerca il file

(nella directory locale) con il nome public.key.portnum, dove portnum

è il numero della porta di riferimento (implicit port) del nodo. Se questo

file non dovesse essere presente si utilizza una chiave di default.

- keypriv privfile Analogamente al precedente, specifica però una chiave privata. Il file

cercato (se non presente tale opzione) sarà quindi private.key.portnum,

con lo stesso significato visto in precedenza.

- policy policyfile Specifica il file contenete un programma che descrive la politica di

mantenimento della “sicurezza” nel nodo (node’s security policy).

Parte I, Sezione 2 PLANet26

Descrizione del file di interfaccia:

(denominato, nella synopsis, ifc_spec_file)

Il file di interfaccia descrive la struttura base dello strato di link (link layer), così come pland

dovrebbe utilizzarlo. In termini generali, questo file consiste in una lista di interfacce (devices)

che possono essere (nel caso di Ethernet) o rappresentare (nel caso di IP) le interfacce di rete

(network interfaces) che sono utilizzate da pland. Viene specificata, per ogni interfaccia, il suo

nome (identificativo), il tipo (ethernet o ip), l’indirizzo di rete ed un’opzionale lista di nodi

adiacenti. Tale lista di nodi adiacenti (neighbors) è usata per simulare il broadcast (diffusione di

pacchetti a tutti i “vicini” del nodo trasmittente). Piuttosto che addentrarci nella descrizione

delle specifiche lessicali e della grammatica26, si è ritenuto essere più utile fare un esempio

concreto della costruzione del file di interfaccia:

3ip0 ip archimede:3328 archimede:3332, leibniz:3328ip1 ip archimede:3329 fermat:3330eth0 ethernet archimede:3330

Questo file specifica che il nodo pland ha tre interfacce (indicato nel numero posto nella prima

riga), queste hanno i nomi: ip0, ip1, eth027 (indicati nella prima parola di ogni riga, oltre la

prima); le prime due interfacce sono di tipo IP, la terza è di tipo Ethernet (indicato nella seconda

parola di ogni riga: ip / ethernet). La parola posta come terzo “campo” della singola riga,

specifica il nome dell’interfaccia del nodo in questione (nome identificativo della macchina –

che deve essere conosciuto nel file hostfile- seguito da un numero –valido- di porta; come già

descritto quando si è parlato degli indirizzi, in questa stessa sezione).

Segue (nella riga) una lista di nomi identificativi di nodi della rete raggiungibili direttamente (o

meno) dal nodo in esame (del quale stiamo descrivendo il file di interfacciamento). Per

maggiore chiarezza e per avere comunque una visione complessiva, sintetica ed immediata di

quanto ci siamo sforzati di spiegare, segue adesso uno schema grafico rappresentante

l’interfacciamento prima descritto:

26 Qualora si rendesse necessario si può consultare l’articolo [5]: “pland: The PLAN ActiveRouter”. Per inciso, non posso che consigliarne una anche breve lettura, sia pur superficiale, per avere unavisione generale più completa e chiara.27 Per quel che riguarda il nome delle interfacce Ethernet, è bene osservare che questo –a differenzadi quanto avviene per il nome delle interfacce di tipo IP- non può essere scelto casualmente ma deverispecchiare il nome di un’interfaccia Ethernet conosciuta dal sistema (può usarsi il comando ifconfig (inLinux), per determinare nomi validi delle interfacce). Altra osservazione che bisogna fare in relazione alleinterfacce di tipo Ethernet è che, per poter accedere a queste, pland deve essere “lanciato” comesuperuser. Faccio notare qui che, nel progetto che ora viene presentato (la mia D Q Q L H), non vengonoutilizzate interfacce Ethernet ma solamente di tipo IP.

Parte I, Sezione 2 PLANet27

rappresentazione grafica dell’interfacciamento descritto dal file precedemente visto

Si è accennato (nella nota 26) al fatto che il nome di ogni interfaccia di tipo IP può essere scelto

a piacere, senza particolari attenzioni. Bisogna sottolineare però la presenza di un’eccezione,

dovuta al nome lo che è riservato e –quindi- non utilizzabile (esso identifica la speudo-

interfaccia locale; una sorta di “auto-anello” virtuale nella rappresentazione grafica di prima).

Qualora non si specifichi nessun valore come numero di porta, viene considerato

automaticamente quello della porta di riferimento (indicato nell’opzione –ip).

archimede

archimede leibnizfermat

3328

3329

3330

33283332

3330

Sezione 3

PLANPacket Language for Active Networks

Introduzione

La versione 3.1 del PLAN (quella utilizzata in questo progetto) è implementata in Ocaml,

versione 1.07. Le motivazioni di questa scelta sono già state accennate nella sezione precedente,

in relazione al paragrafetto D (“Dettagli implementativi”) ma possiamo riassumerle qui di

seguito in due soli punti:

1. L’implementazione con questo linguaggio permette una completa indipendenza dalla

macchina ed un semplice caricamento/scaricamento di codice (che risulta essere qualità

indispensabile per il caricamento dinamico delle estensioni attive).

2. Il codice sorgente OCaml è liberamente disponibile.

La versione precedente (PLAN 2.2) era scritta in Java (ed una sua estensione, Pizza), a questa si

è già fatto cenno (come pure dei motivi che hanno concorso a scegliere poi OCaml come

linguaggio per la versione successiva)1.

PLAN è un semplice linguaggio di programmazione funzionale, basato sulla natura

stessa del concetto di lambda calcolo2, con l’aggiunta di primitive per esprimere la valutazione

remota.

1 Si potrebbe rileggere (o leggere, a seconda della pazienza e della volontà del lettore) la nota 21nella sezione precedente (la 2).2 Si rimanda, non volendo essere eccessivamente pedandi nella spiegazione di ogni termineincontrato, a testi di supporto quali possono essere tutti quelli relativi a linguaggi funzionali, ad es: LISPo ML, per i quali citiamo rispettivamente:- D.Touretzky: “Common Lisp”, Zanichelli, Bologna, 1991- [8] R.Harper: “Introduction to Standard ML”, School of Computer Science, Carnegie Mellon

University, Pittsburgh, 1993

Parte I, Sezione 3 PLAN29

I programmi PLAN possono invocare alcuni servizi3, che sono elencati in librerie di funzioni

residenti sul nodo attivo.

Risorse limitate

Una caratteristica molto importante del linguaggio, che forse potrebbe essere considerata come

una forte limitazione alle sue potenzialità, è che ad esso sono fornite risorse limitate.

E le risorse sono limitate a proposito di due aspetti:

1. A tutti i programmi PLAN è assicurata la terminazione, limitando le risorse consumabili

in ogni singolo nodo attivo.

2. Le applicazioni PLAN sono limitate da una scorta massima iniziale (fornita al momento

dell’iniezione nella rete) di risorse (resource bound; possiamo fare riferimento al formato

del pacchetto PLAN, già analizzato nella sezione precedente) che limita la possibilità di

“girare” all’interno della rete (evitando, ad esempio, che un pacchetto -entrando in un

ciclo- vi possa rimanere indefinitamente, mantenendo in tal modo sempre occupati taluni

percorsi, con una conseguente degradazione delle prestazioni dell’intera rete).

Pacchetti PLAN

Per essere valutato, un programma PLAN è incapsulato in un pacchetto, iniettato all’interno

della rete attiva, e poi valutato. Come risultato della valutazione, il pacchetto potrebbe creare

altri pacchetti (“figli”) che hanno la possibilità d’essere valutati in altri nodi della rete.

A. Un programma PLAN4 può pensarsi suddiviso in due parti:

• Codice Consiste in una serie di definizioni che legano nomi ed astrazioni;

queste astrazioni hanno la forma di funzioni, valori ed eccezioni.

3 Riguardo ai servizi si parlerà con maggiore sistematicità nel seguito della stessa sezione.Anticipiamo comunque che non verranno analizzati, con lo stesso grado di dettaglio, tutti i packages diservizio a disposizione del linguaggio: maggiore precisione sarà dedicata a quelli contenenti funzioniche sono state effettivamente utilizzate nel nostro progetto, solamente accenni agli altri.4 Ci si riferisce, in realtà, non a programmi ma a chunks (code-hunks, letteralmente “pezzetti dicodice”) come già accennato nella sezione precedente. Una trattazione maggiormente organica eprecisa, ma non -comunque- esaustiva sul concetto di chunk può trovarsi più avanti in questa stessasezione…

Parte I, Sezione 3 PLAN30

• Invocazione Consiste in chiamate a funzioni (function calls) e relativi argomenti

(bindings). Queste saranno valutate (potenzialmente anche in nodi

diversi da quello della chiamata, qualora se ne richiedesse una

valutazione remota) solamente dopo che gli argomenti siano stati tutti a

loro volta valutati (passaggio che avviene all’atto della chiamata della

funzione e non alla sua valutazione)

Il PLAN adotta infatti una semantica che permette esclusivamente

passaggi per valore dei parametri (call-by-value semantics).

Per rendere più chiaro il concetto espresso ci si avvale subito5 della definizione di chunk,

concetto essenziale nella logica della programmazione PLAN:

chunks

I chunks sono costrutti di programmazione PLAN comprendenti6 un segmento di codice

(code segment) ed una chiamata a funzione (suspended function call). Provvedono a

supportare l’incapsulazione ed altre tecniche di programmazione di pacchetti.

Come già menzionato (nella sezione precedente), i chunks hanno tre componenti:

1. codice effettivo (in linguaggio PLAN).

2. funzione di “ingresso” (entry-point function) al codice.

3. collegamenti (bindings) con i parametri di tale funzione.

Un chunk può essere –per semplicità- visto come una tradizionale chiamata a funzione,

nella quale però gli argomenti sono stati assemblati ed il codice è parte integrante della

chiamata stessa. Quando un pacchetto PLAN giunge al suo nodo di destinazione, si

accede al codice mediante la sua funzione di ingresso (entry-point function), chiamata con

i parametri forniti. L’aspetto che riveste di maggiore potenzialità i chunks, è che essi sono

facilmente gestibili nell’ambito della programmazione stessa: infatti la sintassi

| f | (expr-1, … , expr-n)

è un’espressione di tipo chunk che crea un nuovo chunk (si perdoni il gioco di parole).

Intuitivamente, la barretta verticale ( | , pipe) individua la parte dell’espressione la cui

5 E non in seguito, facendone una trattazione più organica e completa, come in realtà era statoinizialmente ipotizzato e previsto.6 Come si sarà già intuito!

Parte I, Sezione 3 PLAN31

valutazione deve essere posticipata (la chiamata a funzione stessa, ovviamente).

Specificatamente, il chunk creato consiste nello stesso codice attualmente in esecuzione,

nella funzione di accesso f e nei collegamenti7 ai valori (value) ottenuti a seguito della

valutazione delle espressioni poste come argomenti (expr-1,…,expr-n).

Il chunk può essere adesso manipolato, copiato, passato come argomento oppure –da

notare con particolare attenzione- può apparire come bindings in altri chunks (in realtà

tale incapsulazione di un chunk in altri chunks rappresenta un meccanismo chiave in tutta

la programmazione PLAN). Oltre ad essere trattati come dati, il principale aspetto di un

chunk è ovviamente quello dell’esecuzione: il servizio eval effettua tale valutazione

mediante il caricamento (loading) del segmento di codice e l’invocazione della funzione

d’accesso (entry-point function) con i suoi argomenti.

Solamente a titolo di completezza8 accenniamo al fatto che è possibile “tradurre” il

chunk in una rappresentazione concreta (del tipo stringa di bit) mediante file di tipo blob.

Un esempio dell’incapsulamento dei chunks potrebbe essere il seguente (per quanto

stupido possa sembrare).

Si considerino le due funzioni così definite:

Supponiamo adesso la chiamata

viewIsZero (3,eval ( |isZero| (3) ))

ed osserviamo lo schema seguente.

7 Sicuramente renderebbe molto più il termine inglese binding, che –come per altri terminispecifici in lingua anglosassone- non sempre possiamo evitare di inserire nel testo (se non altro asupporto dei termini italiani, per una più immediata comprensione).

8 E non mediante una trattazione specifica. Si tratta infatti di un aspetto non semplice, inrelazione al quale si preferisce non entrare troppo in dettaglio (anzi non entrarvici proprio), anche invirtù del fatto che il progetto D Q Q L H non sfrutta le funzionalità fornite (non utili ai fini delraggiungimento degli obbiettivi preposti).

fun viewIsZero (numero :int, thisIsZero :bool) :unit=

(print (“il numero “^toString(numero));

if thisIsZero then print (“è zero”) else print (“non è zero”) )

fun isZero (numero:int):bool= if numero=0 then (true) else (false)

Parte I, Sezione 3 PLAN32

B. Un pacchetto PLAN consiste in un programma PLAN che è eseguito su un router attivo.

Oltre al codice, il pacchetto contiene diversi campi aggiuntivi9.

C. Un’applicazione PLAN è composta da una serie di pacchetti PLAN che, insieme,

formano un task. Questa è differente da una comune applicazione host10, che è un

programma che viene eseguito in un nodo terminale della rete e può essere scritto in

linguaggi differenti dal PLAN (linguaggi ad alto livello, non orientati ai pacchetti; come

Java o C, ad es.). Nel caso più semplice, un’applicazione PLAN è definita nell’iniezione

di un pacchetto nella rete e nella conseguente “progenie”11; è però possibile che tale

applicazione collabori con applicazioni host per completare un task.

9 Di questo si è già approfonditamente parlato nella sezione precedente, proprio nella partededicata ai pacchetti PLAN. Allora si è presentato l’argomento corredando la descrizione e l’analisi conuno schema grafico che, per quanto semplicistico, riassume bene tutti i concetti rendendoliimmediatamente concreti e visibili.10 Per avere più chiaro il concetto di applicazione host, si rimanda al prossimo paragrafetto.11 Con questo termine si vuole indicare l’insieme dei pacchetti generati (ed iniettati all’internodella rete) da quello in oggetto.

code

entry pnt

bindings

viewIsZero

fun viewIsZero (……

numero = 3

thisIsZero = fun isZero (……code

entry pnt. isZero

bindings numero = 3

Parte I, Sezione 3 PLAN33

Modello di valutazione (evaluation model)

Per comprendere come viene valutato un programma PLAN, è assolutamente necessario

conoscere dove viene valutato (ossia conoscere il suo ambiente di valutazione: evaluation

environment): la rete PLAN (PLANet), descritta –grosso modo- nella figura seguente.

PLANet: ambiente di valutazione dei pacchetti PLAN (PLAN evaluation environment)

Una rete PLAN consiste in hosts, che rappresentano i nodi terminali dell’ambiente, e routers,

che formano la struttura stessa della rete (active cloud: letteralmente “nuvola attiva”). Ci si

riferisce a routers ed hosts, insieme, come ai nodi della rete.

Tutti i nodi devono essere in grado di valutare programmi PLAN (inseriti in pacchetti), gli

hosts si distinguono dai routers anche per il fatto che in essi è possibile eseguire applicazioni

host, magari come parte di applicazioni PLAN.

PLANinterpreter

+ R V W

host application

implicit port

PLANinterpreter

5 R X W H U

PLANinterpreter

5 R X W H UPLAN

interpreter

5 R X W H U

$ F W L Y H & O R X G

Parte I, Sezione 3 PLAN34

Vita di un pacchetto PLAN

• Un pacchetto PLAN inizia la sua “vita” in un host, specificatamente per mezzo di

un’applicazione host. L’applicazione –infatti- “costruisce” un pacchetto PLAN e lo inietta

nella rete attiva “consegnandolo” all’interprete PLAN residente nell’host stesso. Ciò è

fatto mediante la creazione di una porta12 PLAN (che funge da interfaccia) tra

l’applicazione e l’interprete. Tale porta, che prende il nome di porta di iniezione (injection

port) o porta di riferimento (implicit port), permette all’interprete di mandare l’output

verso l’applicazione ed all’applicazione di sottoporre nuovi pacchetti PLAN.

• L’interprete locale allora procede con l’instradare il pacchetto verso la sua destinazione

(evalDest), mediante l’utilizzo della funzione di routing (routFun), definita nel pacchetto

stesso, che fornisce il nodo, adiacente a quello in esame- verso il quale il pacchetto dovrà

essere indirizzato (rappresenta il next-hop del quale si è già più volte accennato). Lungo la

strada verso il nodo di destinazione, ad ogni passaggio (hop) da un nodo ad un suo

adiacente, le risorse (resource bound) del pacchetto vengono decrementate di una unità;

qualora si raggiungesse il limite di risorse nulle, il pacchetto verrebbe terminato.

• Quando un pacchetto PLAN raggiunge la sua destinazione, il suo programma viene

valutato:

1. In prima istanza, il codice è analizzato (parsed) secondo uno schema top-down per

registrare tutti i collegamenti dell’implemetazione di variabili e funzioni (top-level

bindings).

2. Si procede con la valutazione vera e propria, mediante la chiamata a funzione (system

call) f (a1,..,an) definita nell’invocazione.

3. Tutte le eccezioni che non si è provveduto a catturare (e gestire) nel programma

stesso, saranno gestite dall’handler designato nelle specifiche del pacchetto13.

12 Come forse si sarà già detto, per port si intende una connessione biunivoce (duplex) tra unprogramma PLAN ed un’applicazione host.13 Per questo campo, come per altri precedentemente citati (es. evalDest, routFun,…), èconsigliabile (e difatti lo si sta consigliando esplicitamente) riferirsi allo schema grafico rappresentante(non solo nelle intenzioni, spero) la struttura di un pacchetto PLAN, schema già incontrato nella sezioneprecedente.

Parte I, Sezione 3 PLAN35

Eccezioni (exceptions)14

Il PLAN consente due costrutti sintattici relativi al trattamento delle eccezioni:(per ognuno dei costrutti presentati, viene considerata una porzione di codice a titolo esemplificativo…)

• try etry handle H => ehandle

Esegue l’espressione etry.

a) H indica un’eccezione (è un’exception literal).

Se tale eccezione (H) viene riscontrata nell’esecuzione di etry, allora si procede con la

valutazione dell’espressione ehandle.

b) H non indica un’eccezione, viene vista come il nome di una variabile alla quale,

ogni eccezione sollevata durante l’esecuzione di etry, viene collegata per la seguente

valutazione di ehandle. In tal modo (evidentemente) ogni eccezione viene catturata.

es.fun divisione (dividendo:int, divisore:int): int= try ( dividendo/divisore ) handle DivByZero => ( … )

• raise H

Solleva l’eccezione H. Qualora tale espressione sia contenuta all’interno di un blocco

try…handle (specifico per l’eccezione H evocata, caso a precedente, o generico per ogni

eccezione, caso b) allora implicherà la valutazione dell’espressione ehandle.

E’ opportuno evidenziare la grande importanza che questo costrutto può avere, all’interno

di una programmazione che vuole essere semplice e lineare, per via della possibilità data

al programmatore di definire esso stesso alcune eccezioni (tramite la parola chiave

exception, usata in un contesto di definizione (let-in-end15) ).

es.

fun prova (…) : unit = let exception <H>

fun prova ( ) : unit = ( … if (…) then (…) else raise (<H>) … )

in ( …

try prova( ) handle … ) end

14 Per un elenco delle eccezioni presenti a livello di programma PLAN, così come per quellerelative alle routines di servizio (cui si accennerà successivamente nella sezione) si può fare riferimentoall’articolo:[3] Jonathan T. Moore, Michael W. Hicks, Pankaj Kakkar “PLAN Programmer’s Guide”15 Si veda nel paragrafo dedicato ai costrutti del linguaggio, più avanti nella sezione.

Parte I, Sezione 3 PLAN36

Gestione degli errori (error handling)

Ogni eccezione “alzata” da un programma PLAN può essere catturata da un costrutto

try…handle di livello superiore. Tuttavia, nel caso che l’eccezione si presenti al di fuori

dell’esecuzione del programma (come accade, ad es., se il pacchetto eccede le risorse a

disposizione prima di poter essere valutato), oppure nel caso che non venga catturata,

l’ handler (esplicitato come campo del pacchetto) viene utilizzato per la gestione. Questo è –in

realtà- il nome di una funzione che viene invocata per essere eseguita nel nodo sorgente (del

pacchetto).

Il linguaggio fornisce un handler di default: defHandler. Inoltre esiste un servizio PLAN,

abort, che produce gli stessi effetti di un handler invocato.

Costrutti e primitive del linguaggio

Passiamo adesso ad analizzare e descrivere le primitive ed i costrutti forniti dal linguaggio

PLAN. E’ questa la parte più importante (insieme a quella che segue successivamente,

relativa ai servizi forniti) per coloro che intendano comprendere il linguaggio, non solo come

impostazione generica ed astratta, ma dettagliatamente nei suoi aspetti concreti e realizzativi.

Dalla grammatica16 del PLAN è possibile estrarre informazioni sui costrutti presenti, sui tipi di

valore possibili e sulle operazioni. Analizziamo adesso i costrutti17:

16 Non si tratta di esagerazione (magari dovuta a quel vago senso di onnipotenza che sembrainvadere gli studenti prossimi agli esami); un’attenta analisi della grammatica del PLAN (cui ci si puòriferire facilmente, [1]) risulta essere davvero oltremodo utile nella comprensione del linguaggio stesso.A volte (come nel caso –pur semplice- dei costrutti) quello della grammatica è addirittura l’unico puntocui poter fare riferimento. Ammettiamo –comunque- che il suo utilizzo non risulta essere affattodifficoltoso17 Tralasciamo la descrizione (peraltro banale) degli operatori e dei tipi base messi a disposizionedal linguaggio (per questi ci si può riferire agli già citati [1] (grammatica) e [2] (guida alprogrammatore) ).Non ci si aspettino costrutti complessi; come si nota immediatamente (ad occhio) il numero (…) diquesti è molto basso e si è a livelli di semplicità estrema. E’ buona cosa, comunque, non perdere di vistadue fatti, in questo contesto, importanti:a) Il PLAN è un linguaggio funzionale, aspettarsi la potenza espressiva di un linguaggio imperativo ad

alto livello (ad es. Java, C o –perché no- Pascal) implica ovviamente orientarsi decisamente versouna delusione (per inciso faccio notare d’essere stato il primo a cadere in questo tranello, ed arimanervi invischiato).

b) Il PLAN è stato costruito secondo alcune considerazioni (già tante volte ripetute) che riassumiamoin una sola parola: semplicità (considerando il punto di vista del pacchetto, non certo quello delprogrammatore).

Parte I, Sezione 3 PLAN37

• Costrutti del linguaggio:(Per ognuno dei costrutti presentati, viene considerata una parte di codice a titolo esemplificativo.Non vengonopresi ulteriormente in considerazione i costrutti relativi al trattamento delle eccezioni, già analizzati in precedenza)

1. let <defs-list> in <expr> end

Utilizzato per la definizione di variabili o funzioni locali (valide esclusivamente

all’interno del blocco in…end).

es. fun main ( ): unit= let val dividendo : int = leggiDividendo( )

val divisore : int = leggiDivisore ( ) (* non nullo *)fun divisione (dividendo:int, divisore:int) : int = dividendo/divisore

in ( … ) end

2. if <expr> then <expr> else <expr>

E’ il tipico costrutto if-then-else, non è prevista la possibilità di omettere l’else.

es. if (divisore=0) then ( … ) else ( … )

• Primitive del linguaggio:

Le primitive fornite dal linguaggio PLAN sono molto poche e suddivisibili in due categorie,

che andiamo adesso ad esaminare:

1. primitive di rete:

Le primitive di rete (network primitives) rappresentano forse l’aspetto di maggior interesse del

PLAN, permettendo una computazione “mobile” mediante creazione e trasmissione di nuovi

pacchetti attivi.

(a) OnRemote

La primitiva base OnRemote è pressochè generale. La sua sintassi è la seguente:

OnRemote ( E, H, Rb, Routing )

di tipo chunk(già analizzato in questa stessa sezione)

ricordiamo che eventuali parametrisaranno valutati subito (all’atto dellachiamata remota)

Host di destinazione

intero. Risorse del pacchettoattuale destinate al “figlio”

servizio (non funzionePLAN) di routing

Parte I, Sezione 3 PLAN38

Il suo significato è, banalmente: valuta E in H. Viene utilizzato il servizio Routing per

determinare il persorso necessario al raggiungimento della destinazione H. Infine, il

pacchetto in oggetto (“padre”, quello che chiama la OnRemote), dona Rb delle sue risorse

al pacchetto “figlio”.

- In caso di successo, la chiamata di OnRemote implica la creazione di un pacchetto

PLAN che è trasmesso ad un host adiacente (nella direzione della destinazione H,

come da risultato della routine di instradamento (Routing) ), decrementando la riserva

di risorse del pacchetto “padre” in esame della quantità destinata al “figlio” (Rb).

- In caso di insuccesso, verrà evocata un’eccezione.

(b) RetransOnRemote

Questa seconda primitiva, RetransOnRemote, è molto simile alla prima; eccetto che per il

fatto che tenta di assicurare una consegna affidabile dei pacchetti PLAN. La sintassi è:

RetransOnRemote ( Cs, K, n, H, Rb, Routing )

Tutti i chunks elencati nella lista Cs18, data come parametro, saranno trasmessi verso la

destinazione H mediante la routine di instradamento specificata e con un ammontare di

18 La lista di chunks potrebbe anche essere l’insieme di tutti i frammenti di un unico chunk(troppo “grosso”). Della frammentazione si accennerà in seguito (in questa stessa sezione), quandoverrà affrontato l’argomento dei pachage di servizio.

Lista di chunk(è infatti possibile trasmetterne più d’uno)

ricordiamo che eventuali parametrisaranno valutati subito (all’atto dellachiamata remota)

Host di destinazione

intero. Risorse del pacchetto attualedestinate ad ogni “figlio”, per ogniritrasmissione.

routine di servizio (nonfunzione PLAN) dirouting

tipo Key. Chiave utilizzata per la singolasessione di trasmissione, necessaria perdistinguere i segnali di acknoledgment (ack)che giungono sul nodo

numero massimo diritrasmissioni che possonovenire effettuate (fino allaricezione dell’ack)

Parte I, Sezione 3 PLAN39

risorse pari ad Rb, per ogni chunk trasmesso. Il pacchetto viene ritrasmesso ogni secondo

fino a che si riceva un acknoledgment19 di ricezione, per un massimo di n volte.

(c) OnNeighbor

Simile alla OnRemote, con la restrizione che il pacchetto “figlio” generato debba essere

eseguito in un nodo adiacente a quello attuale. La sintassi è:

OnNeighbor ( E, H, Rb, dev )

2. iteratori di liste

Gli iteratori di liste (che ne permettono, in pratica, la scansione sequenziale) sono basati sul

costrutto fold, con possibilità di associazione a destra o a sinistra. PLAN, per adesso almeno,

non supporta polimorfismi parametrici a livello di linguaggio o funzioni di alto livello, tali

iteratori di lista sono forniti come primitive di linguaggio piuttosto che come specifiche

funzioni.

1. foldl : ( D x E → D ) x D x E list → D

Per semplicità scriviamo che il significato dell’espressione seguente è quella riportata

a fianco:

foldl ( f, a, [b1,..,bn] ) f ( f … f ( a, b1), b2) …, bn )

19 Per maggiori dettagli, ci si può riferire alla trattazione del package reliable, di seguito nellasezione. Come piccola osservazione personale, mi permetto di sottolineare –senza alcuna volontàpolemica ed esclusivamente sulla base di (non pochi) riscontri sperimentali- che ben difficilmente(leggasi pure: mai) qualche frazione di secondo risulta essere sufficiente affinché possa riceversi ilsegnale di acknoledgement e quindi interrompere la ritrasmissione dei pacchetti. Sottolineo anchel’enorme spaventoso!, e non esagero) spreco di risorse legato a tale vana ritrasmissione. Si rimanda alcapitolo delle osservazioni conclusive (sezione 6) per un’analisi specifica dei problemi riscontrati edelle soluzioni proposte (nel mio piccolo).

di tipo chunk(già analizzato in questa stessa sezione)

ricordiamo che eventuali parametrisaranno valutati subito (all’atto dellachiamata remota)

intero. Risorse del pacchettoattuale destinate al “figlio”

dev. Interfaccia versola quale si raggiunge HHost di destinazione

(adiacente a quelloattuale)

Parte I, Sezione 3 PLAN40

2. foldr : ( D x E → E ) x D list x E → E

Analogamente a prima si può scrivere:

foldl ( f, [a1,..,an], b ) f ( a1, f ( a2,…f ( an, b ) … ) )

Servizi

Una parte importante20 delle funzionalità del linguaggio PLAN proviene dalle routines di

servizio. Mentre la prima21 release del PLAN offriva solamente pochissimi servizi, quella

attuale fornisce una ricca libreria nella quale scegliere. I servizi possono essere suddivisi in

due categorie:

1. Servizi essenziali (core services), presenti su tutti i routers della rete PLAN.

2. Servizi aggiuntivi (package services). Ogni package consiste in una o più routine di

servizio a disposizione dei programmi PLAN.

Come tutte le altre funzioni chiamate in PLAN, le funzioni di servizio possono ricevere più

argomenti22 e ritornano sempre un valore23.

1. Servizi essenziali.

Non vuole essere un gioco di parole ma tali servizi sono essenziali per davvero. Non

verrà fatto qui un sistematico elenco di tutte le funzioni fornite24 ma si provvederà

comunque (altrimenti sarebbe inutile l’intera sezione presente) ad analizzare quelle

funzioni che sono sembrate25 particolarmente interessanti ed utili.

20 Per quanto finora visto (e soprattutto per quello non visto) ci si può attendere che tale parte“importante” lo sia per davvero (vista la particolare “leggerezza” del linguaggio in sé). In effetti non èpraticamente possibile scrivere il codice di un’applicazione non banale (è sufficiente che sia non banaleappena un pò) senza utilizzare routines di servizio. Questo, per adesso solo un’aspettativa (ed unasperanza) diverrà evidente nel corso del presente paragrafo e –forse ancor di più- nell’ambito delleosservazioni conclusive sul linguaggio (sezione 6, parte III).21 Non ci si riferisce alla versione appena precedente; la già citata ver. 2.2 (quella scritta in Java)ha infatti circa le stesse routines di servizio presenti nella ver. 3.1 (adottata per il progetto D Q Q L H ).22 Nel senso stretto del termine: si tratta davvero di diversi argomenti; non di un unico argomento(eventualmente una tupla nella quale si facevano convogliare più dati) come accade per l’ML.23 Un servizio, così come una qualsiasi altra funzione PLAN, ritornerà una unità (unit) nel caso incui l’uscita (comunque presente) non abbia significato per il programma.24 Sarebbe troppo lungo, monotono e ben lontano dagli scopi che sono propri del nostro lavoro.Qualora lo si desideri (o qualora risulti necessario) si faccia riferimento alle guide [3] e [4].25 A detta di chi scrive, ovviamente. Non è stato effettuato un sondaggio d’opinione in merito nési è tentato di estrapolare commenti dagli articoli dei ricercatori statunitensi (sarebbe stato come cercaredi far uscire acqua dalle pietre).

Parte I, Sezione 3 PLAN41

• getRB: ( ) int

Non necessita di argomenti e ritorna un intero (come si evince dalla sintassi).

Fornisce l’ammontare delle risorse attualmente a disposizione del pacchetto. E’ un

servizio utilizzato moltissimo nel progetto, per quel che riguarda la non facile

gestione della trasmissione dei pacchetti attivi.

• getSource: ( ) host

Ritorna il nome (come host) del nodo specificato nel campo source del pacchetto.

Rappresenta il nodo che ha dato origine al più “anziano” pacchetto antenato

dell’attuale (potrebbe essere il pacchetto stesso, se non discendente da altri

pacchetti). Routine utilizzata in D Q Q L H per tutte quelle funzioni che

necessitavano d’essere poste in relazione direttamente con il nodo iniziale

(quartier generale, nel progetto).

• getSrcDev: ( ) dev

Ritorna l’interfaccia dalla quale il pacchetto è arrivato sul nodo in esame. Viene

utilizzata nel programma che presentiamo per individuare il nodo dal quale la

capsula (giunta su un router qualsiasi) proviene.

• getNeighbors: ( ) (host x dev) list

Utilizzando la tabella di routing di default, questa funzione determina i nodi

adiacenti (neighbors)26 di quello analizzato. Tale routine è stata estremamente

utilizzata nella stesura del codice che presentiamo (basato proprio

sull’esplorazione della rete attiva mediante propagazione delle capsule spia ai

“vicini” di ogni nodo)27.

• abort: chunk unit

Funzione molto particolare: comporta l’interruzione immediata dell’esecuzione

del programma di un pacchetto e la trasmissione di una routine (per trattare tale

situazione) al nodo sorgente (definito nel campo source del pacchetto stesso). Ad

una chiamata di abort –dunque- l’esecuzione del pacchetto viene terminata, ed

uno speciale pacchetto viene creato e trasmesso al sorgente. Quando vi arriva,

26 Per nodo adiacente si intende, come probabilmente risulta intuitivo, quel nodo che risulta –nella rete fisica- connesso a quello in esame mediante un link diretto27 Per ulteriori ragguagli, si rimanda (ovviamente) alla seconda e terza parte della presentedocumentazione.

Parte I, Sezione 3 PLAN42

setta a zero il suo resource bound e valuta il dato chunk (passato come

parametro)28.

• eval: chunk D

Sottrae una unità dall’ammontare attuale delle risorse del pacchetto, e valuta il

dato chunk. L’ambiente viene prima riinizializzato allo stato base (di default) del

nodo stesso; il risultato della valutazione del chunk è ritornato dalla eval. E’

importante sottolineare29 come tale funzione potrebbe essere utilizzata per

simulare la ricorsione.

2. Servizi aggiuntivi (package services)

Vi sono dieci package di servizio messi a disposione con l’attuale versione del PLAN.

Sono estremamente diversi tra loro e forniscono un vasto ventaglio di tipologie di

funzionalità, di queste verranno citate e commentate solo quelle ritenute

maggiormente utili alla comprensione del codice allegato.

I dieci package sono i seguenti:

- install Permette l’installazione di nuove routines di servizio ( eventualmente

scritte dall’utente stesso, in OCaml) mediante caricamento dinamico.

Si è forse dimenticato di dire in precedenza –cosa che pure ha

importanza non certo trascurabile- che è data possibilità ad un

qualunque programmatore di scrivere alcune proprie routines di

servizio (in OCaml, ribadiamo) che potranno successivamente essere

“caricate” sul singolo router (uno per volta) proprio mediante l’unica

funzione del package install: la installServices. Questo, come sembra

evidente, rende estremamente interessante la prospettiva di

costruzione di programmi, siano pure complessi, in PLAN; cosa

niente affatto scontata al solo esame del linguaggio30.

28 Se si dovesse essere interessati alla programmazione in linguaggio PLAN, o anche persemplice curiosità, si consiglia di fare riferimento al già citato (più volte) [3] (programmer’s guide)dove possono trovarsi (come è lecito attendersi) maggiori, e più dettagliate, informazioni.29 Lo si farà ancor meglio in seguito, nelle osservazioni conclusive (sezione 6), quando verrannoanalizzate le potenzialità ed i limiti del linguaggio PLAN in toto. Particolare attenzione sarà riservataanche alla ricorsione…30 Anche adesso non possiamo non ribadire che tutti questi concetti sul linguaggio PLANpotranno essere meglio valutati se inseriti in un contesto d’analisi più ampio (ci si riferisce nuovamentealla sezione 6, parte III, osservazioni conclusive)

Parte I, Sezione 3 PLAN43

- port Questo package provvede a rendere disponibili i mezzi perché un

programma PLAN possa interagire con delle applicazioni host.

Tutte le routines presenti, si basano sul concetto di port che si ha nella

rete PLANet: una port è una connessione bidirezionale (duplex) tra un

programma PLAN ed un’applicazione host. L’interfaccia verso il

router attivo può ricevere i pacchetti dalla rete, mentre l’interfaccia

verso l’applicazione può ricevere output in formato numerico,

relativamente al servizio utilizzato.

schizzo schematico di una porta (tra programma PLAN ed applicazione)

- resident Dati residenti sono quelli che permangono sul router anche dopo che il

programma PLAN che li ha creati è terminato (oppure ha abbandonato

il nodo per proseguire la propagazione all’interno della rete). Questa

caratteristica è stata aggiunta al PLAN per permettere ai programmi

una agevole strategia di attraversamento ed esplorazione della rete,

ossia proprio per rendere possibile la realizzazione di progetti come

quello che si sta presentando.

I dati residenti sono memorizzati in una tabella sul router, indicizzata

mediante un nome identificativo del dato ed una chiave di sessione. La

chiave serve essenzialmente a differenziare dati memorizzati da

differenti istanze della medesima applicazione PLAN.

esempio di una tabella di dati residenti in un determinato nodo

activerouter

hostapplication

port

keyidentifier data

“marking” <key> Observed

(“marking”, <key>) “ links” <key> [ 1; 3; 1; 2; 2 ]

“marking” <key2> Not Observed

(“marking”,<Key2>)

rappresenta evidentemente undato relativo ad una diversasessione di esplorazione (se diquesto si tratta)

timeout

300

300

300

Parte I, Sezione 3 PLAN44

Un potenziale pericolo, insito nel fatto stesso di permettere la

memorizzazione di dati residenti, è quello che programmi PLAN

potrebbero (anche se solo inavvertitamente) lasciare grandi quantità di

dati su un router, continuando così a consumare memoria anche dopo

la loro stessa terminazione. Per ovviare a questo problema, ogni

singolo dato residente ha associato un tempo di permanenza sul nodo

(timeout). Questo tempo è settato dall’utente all’atto stesso della

memorizzazione del dato, ma non può comunque superare i 300

secondi (5 minuti)31.

Sembra opportuno almeno citare qualche funzione di questo package

(cui si è fatto massicciamente ricorso nell’ambito della stesura del

codice di D Q Q L H), a titolo di esempio:

• get: (string, key) D

Riporta il valore memorizzato sul nodo che può essere individuato

mediante mediante la stringa (identifier) e la chiave della sessione.

Qualora non esistesse un valore in corrispondenza di questa

indicizzazione, verrebbe presentata un’eccezione di NotFound32.

• put: (string, key, D, int) unit

Inserisce una nuova riga nella tabella dei dati residenti sul nodo in

esame (del tipo di quella schematizzata prima), associando al dato

D (terzo argomento) la coppia per la identificazione (string e key).

Il quarto argomento specifica il numero di secondi che al dato è

permesso di “vivere” (come residente sul nodo, allo scadere di

questo timeout, il dato verrà automaticamente cancellato).

31 Tale soluzione appare forse eccessivamente grossolana: qualora fosse necessario conservaredati per un tempo più lungo, deve essere infatti l’utente stesso a prevedere (nel suo programma) unasorta di refreshing dei dati memorizzati sui vari nodi (mediante una nuova memorizzazione).I datiresidenti pongono anche altri problemi, oltre questo del tempo massimo di memorizzazione, qualequello –ad esempio- della necessità di una forma di “autorizzazione alla scrittura”; una analisi piùprecisa sarà condotta nella sezione 6 (osservazioni conclusive).32 Una delle eccezioni più ricorrenti durante la stesura del programma, il testing ed il debugging.

Parte I, Sezione 3 PLAN45

- RIP Implementa un protocollo di routing distribuito, basato sul protocollo

standard RIP33. Mette a disposizione del programmatore funzioni per

l’interazione diretta con la tabelle RIP stesse.

- arp Questo package, non utilizzato affatto nella stesura della tesina,

fornisce servizi necessari all’implementazione di strategie di

risoluzione di indirizzi (address resolution). E’ basato sullo standard

Address Resolution Protocol (ARP).

- flow In qualche applicazione, potrebbe essere utile (o intelligente)

instradare i pacchetti secondo una strategia particolare, comunque

diversa da quella di default, basata sul numero minimo di nodi da

attraversare (come già visto nella nota 33). La metrica basata sul

numero degli hop tende ad approssimare la latenza dei pacchetti nel

loro percorso; applicazioni che richiedono un’ampia larghezza di

banda dovrebbero però essere instradate secondo una metrica che

tenga in considerazione anche questo concetto (ben venga una strada

“più lunga” che consenta però una larghezza di banda superiore).

Questo package fornisce routines di servizio atte alla “creazione” di

nuove metriche e nuove strategie di instradamento.

33 Come si era promesso nella sezione precedente, diamo adesso un brevissimo cenno allastrategia di instradamento basata sul protocollo RIP (tale nota non vuole –ovviamente- essereconsiderata una trattazione sistematica dell’argomento, e neanche una semplice introduzione, masolamente quello che realmente rappresenta: un piccolissimo inciso finalizzato a dare appena ladefinizione del concetto di RIP, per poter avere –almeno lontanamente- idea del suo significato):Quella del RIP è una delle possibili stategie di “visione” della rete, necessaria per effettuarel’instradamento dei pacchetti. Si basa sulla trasmissione (da un nodo ai suoi vicini) delle tabelle dirouting del nodo stesso (inizialmente tale tabella è formata solamente dall’elenco dei vicini “fisici”),durante questa propagazione le tabelle vengono continuamente aggiornate (un nodo che riceve la tabellada un suo vicino, aggiorna la sua con i nuovi dati). In questo modo ben presto tutte le tabelle saranno“stabilizzate” (non sarà necessaria alcuna modifica) e la loro propagazione, che viene effettuatasolamente al presentarsi di modifiche, finisce col cessare (si ripresenta –appunto- in presenza dimodifiche nella rete, che possono essere –ad esempio- il crash di un router o il collegamento di unnuovo nodo).L’instradamento viene effettuato adesso consultando queste tabelle (che presentano l’elenco di tutti inodi della rete (o di una delimitata regione di questa), la distanza (in numero minimo di nodi daattraversare) da quello ove la tabella risiede ed il nodo adiacente a questo, nella direzione diraggiungimento della destinazione (secondo il cammino con il numero minimo di passi)).

Parte I, Sezione 3 PLAN46

- dns Questo package contiene una sola funzione (getHostByName), che

implementa la risoluzione dei nomi (nome del nodo – nome “fisico”).

Il mapping viene effettuato su una tabella statica, generata a partire da

un file specificato al momento dello startup del nodo34.

- frag Fornisce un’insieme di servizi usati per frammentare i programmi

PLAN in piccoli pezzi (di dimensione scelta) per poi riassemblarli alla

destinazione remota della trasmissione. Questo servizio, inizialmente

non considerato per la codifica del progetto D Q Q L H, si è reso

necessario assolutamente necessario per il fatto che la rete presenta un

limite massimo nella dimensione dei pacchetti trasmettibili (si tratta

del Maximum Transferable Unit, MTU, già citato in “programmi

come dati”, nella sezione precedente).

Schematizzazione del concetto di MTU, soluzione mediante frammentazione

- reliable Questo package fornisce al programmatore una serie di funzioni

utilizzabili congiuntamente alla primitiva RetransOnRemote (già

analizzata in precedenza), per assicurare una trasmissione quanto più

“sicura” ed attendibile dei dati/programmi PLAN.

Tra le funzioni presenti, analizziamo quella che è stata utilizzata

all’interno del progetto D Q Q L H:

source destination

+

Parte I, Sezione 3 PLAN47

• sendAck: (chunk, key, int) chunk

Costruisce un pacchetto incapsulandovi il chunk e la chiave

ricevuti come parametri. Il chunk viene “racchiuso” in un altro

chunk che consente la trasmissione, al nodo di provenienza (sent

back), di un segnale di ack (= trasmissione effettuata con

successo, pacchetto ricevuto). Tale segnale di ack è quello

necessario all’interruzione della sequenza di spedizione dei

pacchetti (della RetransOnRemote, se ne è già fatto cenno in

questa stessa sezione).

- csum Riguarda la strategia di incapsulazione.

- authproto Riguarda i meccanismi di sicurezza (security)35.

- security Anche questo package contiene routines inerenti ai meccanismi di

salvaguardia della sicurezza35.

34 Si tratta del file hostfile, già mensionato come opzione dell’istruzione di “lancio” del nodoattivo (costruzione effettiva di una rete PLAN, nella sezione precedente).35 Dei quali si è scelto, come più d’una volta già detto, di non parlare. V.nota 10, della sezioneprecedente, per i riferimenti bibliografici essenziali.

3DUWH�6HFRQGD

A N A L I S I D E LP R O G E T T O S O F T W A R E

$QDO\VLV

Sezione 4

Analisi del problemaAnalysis

Descrizione

Descrivere il problema che si è voluto affrontare non è affatto cosa difficile:

Avendo a disposizione una rete attiva sconosciuta è necessario stabilire quanti sono i routers

presenti nella stessa; si tratta quindi, semplicemente, di contare i nodi non terminali di una rete.

Per rendere immediatamente visualizzabile il problema, viene presentata questa piccolissimarete (nella quale i routers presenti –da contare- sono cinque)

Vincoli

I vincoli presenti in questo problema sono essenzialmente riconducibili all’unico concetto

riassunto nell’aggettivo “sconosciuta”, or ora attribuito alla rete in esame: della rete non si

conosce assolutamente nulla (questo fatto, vedremo meglio nella sezione seguente, ha limitato

fortemente il grado di efficienza potenzialmente associabile al programma di esplorazione

Parte II, Sezione 4 Analisi del problema50

sviluppato). Un vincolo realizzativo imposto è invece quello di non lasciare alcun dato sui nodi

attraversati1 (se si dovesse –considerando un esempio che si vedrà essere ben poco lontano dalla

realtà- scegliere di marcare in qualche modo i nodi stessi, tali machi dovranno essere

necessariamente cancellati prima della terminazione del programma) al fine di non introdurre

“impurità” sui nodi della rete in oggetto.

Sembra essere evidente che il programma debba funzionare in maniera del tutto

trasparente nei confronti di eventuali altri utenti della rete, nessun dato deve rimanere ad

occupare memoria dei nodi, nessuna riduzione delle prestazioni deve essere avvertita (ciò

implica che l’esplorazione avvenga con il minore sfruttamento possibile di risorse, quali tempo

di CPU, memoria nelle singole macchine, tempo di trasmissione e larghezza di banda nelle

connessioni tra i nodi).

Per rendere possibile tutto questo, l’algoritmo ideato deve risultare efficiente,

leggero, lineare (quanto possibile) ed affatto “incline” all’utilizzo di soluzioni laboriose,

impegnative (in termini di sfruttamento di risorse) e grossolane.

Difficoltà

Non sarà sfuggita la scelta del termine “semplicemente” (che si è pensato bene di sottolineare)

utilizzata nella definizione del problema affrontato, in relazione al grado di compessità dello

stesso. In effetti, contare non appare proprio come la più difficile delle operazioni che possono

essere effettuate su computers, e non si può certo pensare di contestare una così cristallina e

condivisibile posizione. Neanche sarebbe però corretto, non mensionare alcuni piccoli “scogli”

presenti nel problema stesso.

Tralasciando di affrontare2 questioni, pure affatto secondarie, quale potrebbero essere –ad

esempio- quella di dover scrivere il codice in un linguaggio funzionale interpretato3, oppure di

dover barcamenarsi tra sistemi operativi cui mai si ha avuto contatto4 e documentazioni spesso

particolarmente ostiche ed inaccessibili5, si può puntare direttamente su un punto.

1 Che (si suppone almeno…) sono tutti i nodi della rete.2 Ma non di citare…3 Dimenticando quindi quei begli ambienti visuali per la programmazione ad alto livello basata sulinguaggi imperativi, ben conosciuti nel loro approccio metodico alle più svariate situazioni, ricchi difunzioni e procedure di libreria che permettono di effettuare diversissime tipologie di operazioni,…4 Alludo a sistemi UNIX. Il fatto che questi fossero inizialmente estranei è imputabile, da un lato,allo stesso autore della presente tesina e, dall’altro (me lo si consenta), ai programmi universitari chesembrano non tenere in considerazione aspetti fondamentali del panorama informatico mondiale (presentee futuro).5 E non solo per il fatto (comunque per nulla trascurabile, purtroppo per me) d’essere scritte (comedel resto sembra essere decisamente ovvio !) in lingua inglese.

Parte II, Sezione 4 Analisi del problema51

Questo punto, di convergenza della grande maggioranza delle difficoltà incontrate, è

relativo all’ambiente di lavoro: le reti attive.

Cosa siano le reti attive e come funzionino, si è già avuto modo di osservare (ed

analizzare; anche con –si spera- sufficiente dettaglio) precedentemente6, ma la comprensione ed

assimilazione di tutti i dettagli concernenti le potenzialità delle reti stesse e del linguaggio di

programmazione delle capsule7, ha richiesto parecchio impegno, forse maggiore di quello che

potrebbe trasparire dalla presentazione che stiamo portando avanti.

6 L’intera prima parte (che consta di tre sezioni) della presente documentazione è stata dedicataall’introduzione alle reti attive, alla rete attiva PLANet (considerata nel progetto) ed al linguaggio diprogrammazione PLAN.7 Processo che, si può immaginare, non è certamente terminato né mai, credo, possa dirsi tale.

Sezione 5

Analisi dell’algoritmo di risoluzione ideatoAlgorithm

Introduzione

Bisogna ammettere che la stesura dell’algoritmo ha presentato notevoli difficoltà e la

sua versione ultima (quella che si andrà adesso a descrivere con particolare attenzione)

differisce, pur in modo non sostanziale, da quelle precedenti.

I motivi principali, sia delle difficoltà incontrate, che della necessità di effettuare

modifiche all’algoritmo stesso, sono riconducibili essenzialmente a due punti distinti:

a) Da un lato, all’iniziale mancata comprensione (nella sua globalità) delle potenzialità e dei

limiti del linguaggio di programmazione utilizzato (cosicché alcune delle funzionalità

inizialmente previste non sono state poi concretizzate, proprio perché di difficile –qualora

non addirittura impossibile- realizzazione pratica, mentre –di contro- altre scelte si sono

potute introdurre (e realizzare), anche con estrema semplicità)1.

b) Dall’altro (lato) alla condizione di pura sperimentazione in cui tale progetto si inserisce.

Questo aspetto, cui si è già fatto cenno nella prefazione, implica una mancanza di

conoscenza pressocchè assoluta dei meccanismi di funzionamento della rete attiva

considerata.

1 Per non fare discorsi privi di riscontri effettivi (che ricadrebbero quindi in elucubrazioni prive difondamento scientifico, per fortuna necessario nel campo in cui questo progretto vuole inserirsi), sembraopportuno considerare almeno un esempio, a supporto di quanto affermato (adesso e nel puntosuccessivo). Questo verrà fatto, con puntigliosa attenzione, lungo il corso di questa stessa sezione.

Parte II, Sezione 5 Analisi dell’algoritmo53

Diverse considerazioni, teoricamente esatte, “pulite” e lineari, si sono scontrate con

problemi pratici del tutto imprevisti (e comunque imprevedibili) relativi proprio al

funzionamento “concreto” della rete.

L’algoritmo risulta comunque completo ed il raggiungimento degli obiettivi preposti (già

brevemente descritti nella sezione precedente) può sicuramente dirsi avvenuto con successo (le

modifiche cui si accennava, lo si ripete, non hanno carattere sostanziale).

Come si è pensato di risolvere il problema?

Innanzi tutto si è voluto costruire un algoritmo di vera e propria “esplorazione”. La

finalità ultima (quella poi effettivamente realizzata e funzionante) permane pur sempre quella

del raggiungimento degli obiettivi posti nella definizione del problema1, ma la struttura

dell’algoritmo è tale da permettere, con modifiche mirate molto settoriali, una affatto complessa

(se non addirittura semplice) “riconversione” a scopi in qualche modo più completi2. In poche

parole si è effettuata una progettazione strutturalmente adatta a realizzare scopi esplorativi dalle

caratteristiche anche più ampie di un semplice conteggio.

Ci si è subito posti nell’ottica di dovere effettuare un’esplorazione il più possibile

flessibile ed esaustiva (quindi anche robusta). Perché questo potesse essere realizzato è stata

necessaria una fase di analisi del problema difficile e laboriosa, comprensiva di

approfondimenti, chiarimenti, modifiche (cui si è accennato) e continui adattamenti.

Sono state effettuate diverse scelte atte a privilegiare un aspetto (robustezza e

flessibilità) piuttosto che un altro:

• Una scelta fatta è stata quella di basarsi esclusivamente sui link che, da ogni nodo della rete,

si dipartono verso i suoi “vicini” (nodi ad esso adiacenti: “fisicamente” collegati in modo

diretto); questa scelta è stata motivata dall’intenzione di rendere l’esplorazione

assolutamente svincolata dalla natura, e dalle proprietà specifiche, della rete su cui si opera.

Inizialmente, in realtà, si era pensato di effettuare un’esplorazione di diversa concezione,

forse più “elegante” di quella attualmente presentata, ma che doveva basarsi su assunti

1 Si può fare riferimento alla sezione precedente.2 Di questo argomento, come –in genere- dell’intero ambito delle prospettive future di sviluppo, sidiscuterà con maggiore approfondimento nella sezione dedicata alle conclusioni finali sul progetto portatoavanti ed ora presentato.

Parte II, Sezione 5 Analisi dell’algoritmo54

molto specifici su strutturazioni gerarchiche ordinate presenti nella rete3. Una tale forma di

assunzione, è sembrata però eccessivamente restrittiva (e poco realistica, in considerazione

del meccanismo di “costruzione continua” cui le reti sono generalmente sottoposte;

prestandosi a qualunque genere di modifica, risulta impensabile mantenervi una sorta di

ordine gerarchico inviolabile)4 ed è stata abbandonata a favore dell’ottica di massima

flessibilità già descritta.

• Un’altra scelta effettuata, in conformità con quelle che abbiamo voluto fossero le linee

guida del progetto (presentate nella sezione precedente), è stata quella di minimizzare, per

quanto possibile, il numero delle capsule presenti nella rete. Questo al fine di rendere il più

possibile “trasparente” l’intera operazione di esplorazione, e di ridurre le probabilità di

errore relativi a disfunzionamenti eventualmente presentabili proprio a livello di rete.

La realizzazione, per seguire tale direttiva, si è indirizzata quindi verso la restrizione di un

solo attraversamento possibile per ogni singolo nodo: Ogni nodo della rete può essere

analizzato da una sola capsula e, una volta raggiunto, nessuna altra capsula può accedervi

(neanche come nodo intermedio per tentare di raggiungerne altri).

Scenario

L’ambiente a cui il progetto si apre consta di tre “attori” principali (ed unici), divisi in due

categorie in relazione alla loro tipologia:

a) Struttura fisica sulla quale si va ad operare:

In questo gruppo è presente il nodo della rete (o, meglio, le strutture ivi presenti).

b) Oggetti software:

- Capsula esploratrice (“spia”), che è quella sulla quale ricade l’intero compito

dell’esplorazione (e cui viene dedicata la quasi totalità del codice).

- “Quartier generale”, che effettua (come risulterà chiaro nell’analisi dell’algoritmo) una

sorta di supervisione dell’avanzamento dell’esplorazione stessa.

3 Si voleva cercare una suddivisione “fisica”, oltre che concettuale ed ideale, della retecompessiva, in piccole reti locali connesse via via verso livelli sempre più alti, fino a giungere ad unasorta di top-level.4 Per avere un’idea del livello di disordine potenzialmente presente su una rete (e dellaimpossibilità di garantire una strutturazione ordinata stabile) si consideri –a titolo esemplificativo-Internet.

Parte II, Sezione 5 Analisi dell’algoritmo55

Informazioni presenti

Si fornirà adesso, in una brevissima panoramica, una descrizione delle informazioni principali

(necessarie all’algoritmo, come descritto di seguito) che sono inserite negli “oggetti” che

compongono lo scenario in cui ci muove, della loro strutturazione astratta (e cenni sulla

realizzazione concreta) e del loro significato (e funzione) all’interno del progetto5.

1. Nodo della rete

Alcune informazioni associate ad ogni nodo della rete risultano essere assolutamente

necessarie per il corretto funzionamento dell’esplorazione.

rappresentazione schematizzata di un nodo della retesi può osservare sia la zona protetta da mutua esclusione che le connessioni fisiche con nodi adiacenti

5 Anche se questo, come ovvio, può essere maggiormente chiarito solamente con uncontemporaneo confronto (passo-passo) con l’analisi dell’algoritmo.

semaforo

TTLresiduo

Counter

Status

status deilinks

router

area dei datiprotetti in mutua

esclusione

W

W

P

W

K

K

parent

89 14

Observed

free

Parte II, Sezione 5 Analisi dell’algoritmo56

Tali informazioni, schematizzate nella rappresentazione grafica precedente, vengono

adesso definite:

a) Semaforo

E’ una varibile intera (funge comunque da flag: 0/1) introdotta per gestire la mutua

esclusione nell’accesso ai dati condivisi.

Tutti i campi informativi introdotti nel nodo (visualizzati in figura all’interno della

zona verde) risultano essere, infatti, del tutto generali e “globali”: ogni capsula che,

in qualsiasi modo, debba interagire con nodo in esame, deve poter aver accesso ai

suoi dati residenti (fosse pure solo per sapere se il nodo è già stato osservato da

qualche altra capsula “spia” esploratrice o meno). Ovvia, quindi, la necessità di

introdurre meccanismi atti a garantire l’effettiva mutua esclusione nell’accesso ai

dati, quale salvaguardia della integrità e consistenza degli stessi6.

b) Status

Consiste in un campo intero (utilizzato come flag: 0/1) indicante lo stato del nodo

(non osservato / osservato).

La sua introduzione è motivata, quasi esclusivamente, dalla volontà di mantenere

una sorta di “pulizia logica” (e linearità) nell’algoritmo stesso. Il suo utilizzo pratico

è, infatti, molto circoscritto (e, comunque, non strettamente necessario) proprio per

via della condizione di non lasciare alcun dato residente sul nodo (lo stato <non

osservato> non è quindi mai presente come dato fisicamente residente sul nodo

stesso)7.

c) TTL residuo

Time To Live (tempo di vita): indica la quantità di risorse teoricamente ancora

disponibili per la capsula che dovrà dipartire dal nodo per “risalire” verso

l’avamposto. Tale quantità è, come si sarà potuto certamente intuire, strettamente

legata all’algoritmo di esplorazione della rete; la sua funzione (lo scopo per il quale

è stata considerata ed introdotta) è però risultata inapplicabile per limitazioni

strettamente legate alla gestione interna della rete attiva PLAN.

6 Altri cenni sulla mutua esclusione si dovranno presentare anche più avanti nella sezione (quandoverrà affrontato il problema delle caratteristiche “avanzate” del progetto sviluppato)7 Ovviamente, se la capsula giunge su un nodo in cui non è presente il dato status (così come tuttigli altri), potrà “dedurre” di trovarsi su un nodo non già raggiunto da altre capsule.

Parte II, Sezione 5 Analisi dell’algoritmo57

Un solo cenno sull’algoritmo, per chiarire il concetto:

La capsula spia che giunge su un nodo inesplorato (fase di esplorazione), dopo aver

effettuato talune operazioni (poi meglio specificate), si propaga a tutti gli adiacenti

(cui è consentito accedere)8 suddividendo equamente le risorse (o TTL) a

disposizione. Quando (fase di rientro) le capsule lanciate ritornano al nodo in

esame, vi “scaricano” le risorse ancora a disposizione (non utilizzate), oltre ad altre

informazioni.

Schematizzazione della gestione delle risorse nell’attraversamento di un router(a): fase di esplorazione: divisione equa delle risorse tra tutte le capsule “figlie”

(b): fase di rientro, nell’ipotesi che l’ultima capsula figlia a rientrare sia quella con risorse pari a 3(cosa del tutto plausibile: rientra con meno risorse = ha raggiunto maggiori profondità = torna ultima)

osserviamo (in corsivo) come ben più efficiente sia la gestione delle risorse qualora fosse possibilerealizzare un “riutilizzo” di quelle rimanenti.

L’idea di base, tuttora pienamente valida e potenzialmente applicabile, era quella di

poter riutilizzare queste risorse (altrimenti del tutto sprecate) assegnandole alla

capsula che, ritornata per ultima, avrebbe dovuto abbandonare il nodo facendo

“rotta” verso il predecessore. Purtroppo però, l’implementazione dell’architettura

della rete PLANet non consente, a tutt’oggi, di effettuare “passaggi” di risorse da

una capsula ad un’altra (né tantomeno –ma questo appare ben giustificabile-

aggiunte arbitrarie di risorse ad una specifica capsula).

8 Si potrà meglio osservare in seguito (nella parte strettamente dedicata all’algoritmo) a qualegenere di “consenso” si fa adesso riferimento. Non bisogna spedire una capsula spia al nodo (puradiacente) dal quale essa è appena giunta, ad esempio.

100

33

33

33

3

31

3

12

31+3+12=46

Parte II, Sezione 5 Analisi dell’algoritmo58

Il dato TTL residuo, quindi, non può servire a svolgere il compito che si era, in

prima istanza, immaginato. Si è comunque voluto scegliere di non eliminare del

tutto questa informazione, per poterla eventualmente sfruttare nel caso (si spera non

eccessivamente irrealistico) di una revisione, in tal senso, della disciplina di

gestione delle risorse intrapresa in PLANet.

d) Counter

E’ un campo contenente una variabile intera. Il nome del campo, data la finalità

ultima del progetto, lascia intuire la sua importanza: è il campo cui convogliano i

risultati parziali, via via raggiunti, sul numero di routers attualmente contati in

un’area che può essere vista come facente capo al nodo in esame.

e) Links

Implementato mediante una lista, vuole rappresentare il vettore degli stati di

avanzamento dell’esplorazione nelle direzioni dei vicini. Ogni elemento di tale

vettore9 contiene informazioni relative al link cui corrisponde (la corrispondenza

viene costruita, e mantenuta, sulla base della posizione all’interno del vettore: ad

es., lo stato dell’esplorazione nella direzione del terzo vicino10 sarà individuata dal

terzo elemento del vettore considerato).

Gli stati di avanzamento dell’esplorazione possibili sono i seguenti:

0. stato di esplorazione non ancora effettuata;

1. stato di attesa: una spia è stata lanciata nella corrispondente direzione e se ne

attende il rientro con le informazioni;

2. stato di terminazione dell’esplorazione: la capsula spia lanciata ha fatto ritorno,

oppure la direzione di esplorazione non deve essere intrapresa11 (in questo caso

il link si dirà “barricato”).

9 Lo si indicherà come tale anche se, come detto, la sua implementazione effettiva è realizzatamediante una lista di interi (il PLAN non ammette array, né consente la definizione di tipi). Si avrà ancoramodo di affrontare l’argomento, persino da due differenti punti di vista:- Uno, più pratico, della costruzione di funzioni (ad-hoc) finalizzate ad adattare la struttura

realmente a disposizione (lista) con quella ideale, e più logica nel nostro contesto, (array);- L’altro, più teorico, dell’analisi complessiva e conclusiva sui vari aspetti del linguaggio PLAN

(potenzialità e limitazioni).Ci si può riferire, rispettivamente, alla sezione seguente ed alla sezione relativa alle osservazioniconclusive.10 Terzo nella lista di vicini fornita dalla routine di servizio getNeighbors.11 Come già più volte accennato, molti concetti adesso espressi potranno trovare una chiaracollocazione (ed essere compresi in modo più sistematico ed organizzato) all’interno dell’analisidell’algoritmo.

Parte II, Sezione 5 Analisi dell’algoritmo59

3. indica il link verso il nodo “padre”, dal quale si è giunti nel nodo in esame, ed al

quale ritornare le informazioni raccolte, quando la fase esplorativa termina.

Osservazione:

Si vuole fare notare che, in linea con quanto chiarito precedentemente (al momento

della definizione del problema e durante l’introduzione alla presente sezione), tutte le

strutture informative sul nodo (siano esse dati strutturati o semplici flag) cui ci si avvale

nell’esplorazione, e che –proprio per questo motivo- non possono non essere mantenute

residenti sulla memoria dei singoli nodi, saranno poi completamente eliminate: sui nodi

della rete, al termine dell’esplorazione, non resterà nessuna traccia , nessuna “impurità”

relativa alla sessione esplorativa effettuatavi.

2. Capsula spia (esploratrice)

Che la capsula esploratrice abbia necessità di poter disporre di qualche dato, magari

aggiornabile, sembra essere abbastanza intuitivo (si prenda, come esempio, il contatore

dei routers: è un dato necessario che la capsula deve mantenere). I dati questa volta non

sono però residenti su supporto fisico, ma semplici variabili interne al pacchetto.

schema riassuntivo dei dati memorizzati sulla singola spia

Key

Counter

Outpost

direction

level prec

level MAX

numero routerscontati

dir. propagazione:Esplorazione-Rientroultimo livello di

profondità raggiunto

profondità massimaraggiungibile

avamposto diriferimento

chiave della sessionedi esplorazione

Parte II, Sezione 5 Analisi dell’algoritmo60

Tali informazioni, schematizzate nella rappresentazione grafica precedente, vengono

adesso definite:

a) Key

E’ la chiave della sessione di esplorazione, necessaria per poter aver accesso a tutti i

dati residenti sui nodi, riconoscendoli relativi appunto alla propria sessione di

lavoro.

b) Counter

E’, banalmente, il numero di routers contati, che fanno capo alla spia in oggetto.

Visualizzazione della strategie di propagazione all’indietro delleinformazioni ricavate (somma del numero dei routers contati)

Dall’analisi dell’algoritmo, si può evincere chiaramente come tale variabile (e

quindi l’effettivo conteggio dei routers) entri in gioco solamente nella fase di

“rientro” delle capsule (e non nella fase, precedente, di esplorazione).

c) Outpost

Variabile di tipo host, rappresenta il nome del nodo che ha la funzione di avamposto

(base intermedia di esplorazione). E’ a questo nodo che la spia deve fare

riferimento: tutti i dati (nella fase di rientro) dovranno essere definitivamente

depositati in quel nodo (su cui viene operata un’azione di coordinamento12 da parte

del quartier generale13).

12 Si rimanda, nuovamente, all’analisi dell’algoritmo.13 Rappresenta il nodo di iniezione della prima spia (ossia il punto da dove avviene la richiestadell’esplorazione), il punto dove far confluire i dati finali, nonché il nodo che coordina, come detto,l’avanzamento dell’intera sessione esplorativa.

7(5+0+2)

52

0

Parte II, Sezione 5 Analisi dell’algoritmo61

d) Direction

Individua la direzione di propagazione della capsula, distinguendo nettamente

quindi (distinzione necessaria per la strategia scelta) tra fase di esplorazione

(ricognizione) e fase di rientro (con raccolta dei dati).

e) Level prec.

Valore intero. Memorizza il livello (inteso come distanza14 dal quartier generale)

dell’ultimo router osservato (si ponga attenzione al fatto che si parla proprio di

routing osservato, escludendo quindi sia i nodi terminali che quei routers che, pur

acceduti dalla spia, non vengono da essa “osservati”15). Il motivo dell’introduzione

di tale dato è dettato dalla necessità di non permettere ad una capsula esploratrice di

esaminare nodi (nella sola fase di esplorazione, ovviamente) che si trovino ad un

livello inferiore di quello appena precedentemente raggiunto (tale strategia, si

comprenderà meglio nell’analisi dell’algoritmo, è indispensabile per garantire il

corretto funzionamento della gestione delle basi intermedie (avamposti)).

f) Level MAX

Anche questo è un valore intero. Indica il massimo grado di profondità al quale la

spia può spingersi durante la fase di esplorazione. Oltre questo livello sarà richiesta

(al quartier generale) la costruzione di un nuovo avamposto.

14 La distanza tra due nodi, come si sarà probabilmente già accennato in precedenza, è misuratacome il minimo numero di nodi da attraversare (quindi il minimo numero di hop da effettuare) perraggiungere un nodo dall’altro. Premettiamo adesso (si consiglia di fare adesso riferimento al codicestesso) che ottenere tale quantità non risulta affatto complesso: basta semplicemente scorrere la tabella dirouting del nodo in esame (si vuole ricordare, infatti, che PLANet adotta, di default, la strategia RIP, chebasa l’instadamento dei pacchetti appunto su tale minima distanza; si può confrontare la nota 33 dellasezione precedente per un cenno sulla politica di tale tecnica di routing).15 Perché, ad es., quel dato router era già stato oggetto dell’esplorazione di un’altra capsula spia.

Parte II, Sezione 5 Analisi dell’algoritmo62

3. Quartier generale

Il quartier generale indica, secondo la nominazione che si è voluta dare ad ogni

elemento del progetto, il nodo che sta alla base dell’intera fase esplorativa. La sua

funzione, già accennata poco prima, verrà ulteriormente descritta (con maggiore

dettaglio) durante l’analisi dell’algoritmo; si può comunque intuire, dato il compito di

coordinamento cui è chiamato, la necessità di avere a disposizione alcuni dati.

Questa entità è, tra quelle esaminate, l’unica a servirsi sia di dati residenti sul nodo

(appunto quello di iniezione), sia di dati non residenti. Ciò anche a sottolineare il

duplice aspetto cui il termine quartier generale fa riferimento: uno relativo

concretamente al nodo stesso (che, si ribadisce, è quello di iniezione) e l’altro associato

alla funzione che, sul nodo, resta attiva.

schematizzazione grafica del quartier generale.nella parte azzurra sono rappresentate le risorse residenti, accedibili in mutua esclusione,

mentre le frecce rosa indicano i legami tra i vari dati

Semaforo(message)

tipo dirichiesta

livellodell’avamposto

nome (host)dell’avamposto

informazionidall’avamposto(TTLr e Count)

Key

resource bound perogni livello diesplorazione

numero routersattualmente contati

TTL residuo attualmenteaccantonato

elenco degliavamposti aperti

step di livello(per area di

esplorazione)

numero avamposti aperti

Parte II, Sezione 5 Analisi dell’algoritmo63

Sulla base della rappresentazione schematica appena fornita, passiamo adesso ad

analizzare i singoli campi di informazione:

Dati non residenti sul nodo:

a) Key

E’ la chiave identificativa della sessione di esplorazione attualmente attiva. Viene

creata proprio sul quartier generale al momento dell’iniezione della prima capsula

spia ed è la stessa chiave che ogni capsula utilizza per memorizzare (ed averne poi

accesso) i dati temporanei sui vari routers esaminati.

b) lista outpost aperti

E’ una lista di host contenente l’elenco di tutti gli avamposti che, al momento,

risultano “aperti” (ne è stata richiesta la costruzione16 ma non ancora l’eliminazione,

l’esplorazione dell’area consentita non è, evidentemente, terminata).

c) numero outpost aperti

Indica, banalmente, il numero delle basi intermedie ancora in attività. Viene

incrementato ad ogni richiesta di costruzione di un nuovo avamposto e

decrementato al momento dell’eliminazione dell’avamposto stesso. Può essere visto

anche come dato ridondante (per garantire una maggiore sicurezza) dato che

coincide sempre con la lunghezza della lista degli avamposti aperti.

d) RB per livello

E’ un dato di tipo intero. Rappresenta la quantità di risorse (resource bound, o

anche TTL) da assegnare ad ogni nuovo avamposto (o, meglio, alla prima spia

lanciata verso l’avamposto, che poi si propagherà a partire proprio da quella base).

Tale valore dovrà essere sufficiente (sarà quindi necessariamente sovrastimato) a

garantire l’esplorazione dell’intera area lecitamente analizzabile dalla spia (in

relazione al livello di profondità, cui si è già accennato).

16 E’ proprio in questo istante che il nome del nodo (richiedente la costruzione dell’avamposto)viene inserito nella lista.

Parte II, Sezione 5 Analisi dell’algoritmo64

e) level step

Indica la profondità che dovrà avere l’area esplorativa facente capo ad ogni base

intermedia. Coincide quindi con il passo di incremento del limite estremo

raggiungibile, nel passaggio da un avamposto al successivo (ad es. se tale step fosse

pari a 10, la massima profondità raggiungibile sarebbe 10, per il primo avamposto,

10+10=20, per gli avamposti seguenti, e così via…).

f) act. Count

Indica il numero dei routers attualmente contati. Inizializzato a zero, viene

successivamente aggiornato sommandovi il contenuto dei contatori parziali,

trasmessi da ogni avamposto al termine della ricognizione ad esso associata (quindi

contestualmente alla richiesta di “eliminazione” dell’avamposto stesso). Quando la

sessione esplorativa è conclusa (non vi sono più basi intermedie aperte), conterrà il

numero definitivo dei routers presenti nella rete esaminata.

g) act. TTLr

Indica il numero delle risorse (cumulate) non utilizzate (e, per quanto già detto in

precedenza, non utilizzabili)17 che fanno riferimento ai vari avamposti. Questo dato

viene raccolto, trasmesso ed aggiornato con le stesse modalità descritte per il

counter.

Dati residenti sul nodo:

h) semaforo (message)

Come quello presente in ogni router della rete, è necessario per garantire la

consistenza dei dati residenti, cui più capsule possono accedere (in questo specifico

caso –quartier generale- solo in scrittura)18.

17 Si può rileggere (qualora non se ne ricordasse il contenuto) il tratto relativo alla descrizione delcampo TTL residuo sul router, in questa stessa sezione.18 Non si può fare a meno di rinviare ancora una volta, per un approccio forse più esauriente esicuramente più completo, alla descrizione ed analisi dell’algoritmo.

Parte II, Sezione 5 Analisi dell’algoritmo65

i) tipo richiesta (flag)

Si sarà già intuito (ma diverrà probabilmente più chiaro successivamente) che

possono giungere due tipi di richieste a questo particolare nodo:

1. richiesta di creazione di una nuova base intermedia;

2. richiesta di eliminazione di un avamposto (ad esplorazione terminata).

Il flag che stiamo descrivendo serve appunto a discriminare tra le due possibilità.

j) nome outpost

Questo campo, come i due successivamente descritti, entra in gioco solo all’arrivo,

sul quartier generale, di una qualche richiesta (tra le due esaminate nel punto

precedente). Qui, la spia richiedente, memorizzerà (temporaneamente) il nome

dell’host per cui effettua la segnalazione (indipendentemente dal tipo di questa).

k) level outpost

Similmente al precedente, vi si memorizza il livello di profondità della base in

esame. Viene utilizzato quasi esclusivamente nella fase di creazione

(dell’avamposto), per poter considerare l’overhead di risorse necessario alla

trasmissione della nuova capsula spia (in modo che, iniziando la sua fase

esplorativa, questa disponga interamente delle risorse assegnate per ogni livello

(come già descritto), senza che debba, da queste, prelevarsi quella quantità

necessaria al raggiungimento dell’avamposto stesso).

l) outpost information

Su questo campo (coppia di interi) si potrà scrivere solamente al momento della

richiesta di cancellazione di un avamposto attualmente attivo. Contestualmente a

tale richiesta, infatti, su questo campo verranno memorizzate le informazioni

(numero di routers contati e TTL residuo) raccolte durante la missione svolta (e

conclusa) nell’area di pertinanenza della base richiedente.

Parte II, Sezione 5 Analisi dell’algoritmo66

Algoritmo

Dell’algoritmo studiato si sono avute già parecchie anticipazioni nel corso di questa

stessa sezione (erano, a dire il vero, necessarie per rendere minimamente comprensibile quanto

descritto). Ciò non limita però l’importanza di questo paragrafo19 né, tantomeno, l’attenzione e

la meticolosa cura che si è posta nella sua stesura.

L’algoritmo di risoluzione del problema che ci si è posti, può pensarsi suddiviso in due

parti complementari: da un lato si ha quello che può essere definito (a ragione) il cuore

dell’intero progetto, ossia la strategia di ricognizione della spia; dall’altro c’è l’algoritmo

relativo alla gestione del quartier generale che, in qualche modo, coordina l’intera missione.

A. Strategia di esplorazione

Si tratta dell’algoritmo implementato nel codice della capsula spia. Si ricordi (dall’analisi

delle reti attive)20 che questo programma viene eseguito su ogni nodo raggiunto dalla

capsula.

Operazioni di inizializzazione:

- lettura dello status del nodo raggiunto (status)- calcolo del livello di profondità a cui il nodo si trova (level)- individuazione del nodo dal quale si proviene (parent)- tentativo di settare ad “occupato” il semaforo

if semaforo settato then

if nodo è router non marcato then

if in area di esplorabilità then

{ marking dello status del nodo: Observed; inizializza lo status dei links (inserisce il parent); inizializzazione del contatore e del TTL residuo (=0); lancio capsule a tutti i vicini consentiti }

else

19 Verso il quale si sono fatti moltissimi richiami da diverse parti dell’intera documentazionepresente.

la spia si trova su un router nonprecedentemente analizzato

il semaforo è stato settato correttamente, se nededuce che fosse libero

il cui link si trovanello stato free

Parte II, Sezione 5 Analisi dell’algoritmo67

if livello inferiore del precedente then

{ barrica link verso il nodo precedente; torna indietro senza effettuare altre operazioni }else

{ marking dello stato del nodo: Observed; torna indietro; effettua richiesta di costruzione di un nuovo avamposto }

else

if il router è il predecessore (parent) ed attende il rientro della spia then

{ aggiorna i campi TTL e Count con le informazioni raccolte; aggiorna lo status dei link, barricando quello dal quale si proviene; if tutti i links sono chiusi then abbandoniamo il nodo }

else

if si è su un nodo terminale o su un router marcato da altra spia then

{ if nodo marcato da altra spia thenbarrica il link verso il nodo dal quale si è giunti;

torna al nodo precedente }

else if tutti i links sono chiusi then abbandoniamo il nodo

else ritenta l’accesso al nodo

20 Esaminate nella prima parte (sezioni 1,2 e 3) del progetto.

il livello raggiunto è oltre illimite massimo consentito

la spia è giunta su un nodo terminaleoppure su un nodo già marcato

il link nella relativa direzione sitrova ancora nello stato di wait

la spia è sul nodo padre del precedente (sta risalendoverso l’avamposto), ma non è più attesa (il link

relativo è stato già barricato)

il semaforo è stato trovato alzato (accesso nonconsentito: altra spia presente al suo interno

Parte II, Sezione 5 Analisi dell’algoritmo68

Sembra opportuno adesso focalizzare l’attenzione su un paio di punti ritenuti

particolarmente importanti (o che, comunque, necessitano di un ulteriore livello di

dettaglio):

1. procedura di barricamento

consiste nel porre a “K”21 il link in questione (quello relativo al nodo dal quale la spia

proviene), per impedire che una qualche altra capsula esploratrice possa ripercorrere (in

senso inverso, quindi verso un nodo già esaminato) la connessione stessa.

2. procedura di abbandono del nodo

Questa operazione viene effettuata dalla spia che, tornando (fase di rientro) su un nodo,

barricando il link dal quale proviene, verifica che non vi sono altri link aperti (nessuna

capsula è ancora attesa dal router in questione).

{

if il nodo da abbandonare non è un avamposto then

propagazione della spia all’indietro (verso il nodo predecessore: parent)

else trasmissione della richiesta di cancellazione dell’avamposto al quartier generale(fornendo le informazioni raccolte: TTL res. e routers contati);

cancellazione di tutti i dati residenti sul nodo stesso

}

21 Si rimanda alla parte (in questa stessa sezione) che analizza i dati residenti su ogni singolorouter.

osserviamo come, in linea con quantodetto, nessuna informazione permane

sui nodi della rete al termine dellasessione di esplorazione

Parte II, Sezione 5 Analisi dell’algoritmo69

B. Gestione del quartier generale

Si tratta della strategia eseguita sul nodo di iniezione, che resta poi quello verso il quale

convoglieranno via via tutti i dati parziali, le richieste di creazione e cancellazione di

avamposti.Ne viene fornita, è sembrato più opportuno così, una schematizzazione mediante

diagramma a blocchi:

Semaforo(per le richieste)

libero occupato

tipo dirichiesta

creazionenuovo

avamposto

cancellazioneavamposto

(area esplorata)

nessuna

ancoraavamposti aperti ?

no

silettura nomeavamposto

lettura nomeavamposto

lancio spia verso ilnuovo avamposto(definita l’area di

esplorazione) lettura informazionifornite dall’avamposto

(TTLr e Count)

aggiornamento dati(cumulativi):TTLr e Count

aggiornamentodell’elenco (e del

numero) degli avampostiancora aperti

aggiornamento elenco (enumero) degli avamposti

ancora aperti

aggiornamentodell’elenco (e del

numero) degli avampostiancora aperti

missione terminata

3DUWH�7HU]D

O S S E R V A Z I O N IC O N C L U S I V E

&RQFOXVLRQV

Sezione 6

Osservazioni conclusiveConclusions

Questa sezione è interamente dedicata ad una dettagliata analisi di talune particolarità del

progetto, o del linguaggio adoperato, sulle quali si vuole poter indirizzare fortemente

l’attenzione.

Si è pensato fosse opportuno suddividere la presente in tre parti, sulla base all’argomento

principale cui le osservazioni stesse si riferiscono; ciò non esclude, però, una marcata ed

esplicita coesione tra i paragrafi (ben presente).

A. Osservazioni sulla rete attiva PLANet

La rete PLANet sembra essere davvero una soluzione efficace ed efficiente ai problemi di

realizzazione di una rete attiva. Non sono certamente in grado di esprimere giudizi di

carattere tecnico sull’architettura di rete considerata, molte parti della sua natura (e non

certamente di trascurabile importanza) mi sono attualmente del tutto oscure1 ma , per la

lunga fase di sperimentazione pratica cui la realizzazione del progetto D Q Q L H mi ha

costretto, la mia esperienza non può che definirsi soddisfacente.

Credo comunque di poter evidenziare due punti che ritengo essere, pur per opposti motivi,

degni di nota in questo contesto.

1 Solo per fare qualche esempio, si possono considerare i problemi della sicurezza, dellaaffidabilità, delle prestazioni,…

Parte III, Sezione 6 Osservazioni conclusive72

1. possibilità di scrivere (e caricare sui routers) routines di servizio

Credo che questa sia una delle più interessanti caratteristiche (tra quelle da me

conosciute) dell’implementazione dell’architettura PLANet, se non altro per i suoi

molteplici risvolti pratici. In realtà però tale possibilità non è stata sfruttata nel

progetto realizzato, da un lato perché il dover scrivere codice in OCaml ha

funzionato un po’ da deterrente, dall’altro –e principalmente- perché il contesto

ove ci si muoveva non sembrava affatto richiedere interventi simili.

Perché si è voluto citare, come esempio di caratteristica positiva della rete,

proprio questo?

Probabilmente per via della enorme flessibilità che una tale possibilità introduce

all’interno della rete stessa (si pensi a quante e quali funzionalità sarebbe possibile

far diventare bagaglio interno di uno o più nodi non terminali)3.

2. impossibilità di scambiare risorse tra due capsule

E’ quasi certamente il più grosso inconveniente che mi è possibile attribuire alla

politica di gestione della rete. E’ fin troppo ovvia la forzata impossibilità di

aggiungere, in modo del tutto arbitrario, risorse ad una capsula già iniettata

all’interno della rete (si violerebbe uno dei pilastri principali che, come

specificatamente spiegato4, vuole limitare la proliferazione incontrollata, ed

incontrollabile, di pacchetti); di contro non si riesce però ad immaginare (o non si

riesce a condividerle) motivazioni tali da impedire lo spostamento di risorse da

una capsula ad un’altra.

Ciò non risulterebbe neanche eccessivamente distante dall’attuale gestione

delle risorse: si ricorda, infatti, come sia tuttora possibile che una capsula, durante

la sua esecuzione, crei altre capsule (“figlie”), e trasmetta ad esse parte delle

proprie risorse.

Comunque sia, una simile possibilità non è stata implementata (per lo meno

allo stato attuale delle cose) e questo ha provocato molti problemi, contribuendo

3 Non riesco a non fare un esempio che (come si avrà comunque modo di riaffermare anche piùavanti nella stessa sezione) mi sta particolarmente a cuore: alcune funzioni di supporto alla gestionedelle liste; non esistenti né come routines di servizio né come funzioni del linguaggio. Quando, pocooltre, verranno elencate ed esaminate (con una ancora indomata dose di orgoglio) le funzioni PLAN cheè stato necessario scrivere, quale indispensabile aiuto alla realizzazione delle strategie che si è volutoscegliere, si immagini quanto sarebbe opportuno inserirle –come package- all’interno di ogni nodo (epoterle conseguentemente utilizzare da ogni differente capsula).4 Nella sezione dedicata alla rete attiva PLANet ma anche (secondariamente) in quella relativa allinguaggio PLAN.

Parte III, Sezione 6 Osservazioni conclusive73

in maniera pressoché determinate5 alla creazione di una mal controllata

“emorragia”6 di risorse nell’esecuzione del programma che stiamo presentando.

3. poco flessibile gestione della trasmissione “sicura” dei pacchetti

Come già descritto precedentemente (nella sezione dedicata al linguaggio di

programmazione PLAN), esiste una funzione di trasmissione remota, la

RetransOnRemote, che permette l’invio di un pacchetto con eventuale

ritrasmissione fino alla ricezione di un ack che ne confermi la ricezione. Ebbene,

la gestione di questo meccanismo funziona7 mediante l’utilizzo di una tabella di

ritrasmissione (retransmit table):

Ogni volta che la RetransOnRemote viene chiamata con una lista di chunks,

viene aggiunta una nuova riga (entry) nella tabella di ritrasmissione, indicizzata

tramite la chiave della sessione (utilizzata come sequenza numerica). Solo quando

viene ricevuto l’ack, questa riga viene cancellata.

La tabella è inizializzata per permettere la memorizzazione di 10 linee, è quindi

una tabella statica, a dimensione fissa. Sarebbe stato certamente molto più

flessibile, adattivo ed efficiente considerare una tabella che possa crescere

dinamicamente (growable), come ammesso dagli stessi progettisti7.

La limitazione della dimensione della tabella ha creato, durante la fase di

sperimentazione prima e di testing poi, alcune difficoltà al corretto funzionamento

del programma8: frequente (specie su routers con molti nodi adiacenti) era la

saturazione della tabella di ritrasmissione, espicitata dal messaggio d’errore (tra i

più gettonati) di Retransmit table is full.

5 Un’altra importante motivazione è questa volta imputabile a limitazioni nella flessibilità dellinguaggio adoperato.6 Mi si perdoni il termine, forse non proprio puramente scientifico (se non in campi dal nostroben distanti); dello speco (veramente eccessivo) di risorse si tornerà comunque a parlare presto. Solo unultimo cenno, per chetare eventuali eccessi di curiosità: come si è ovviato al problema? Nel modopeggiore possibile (ma l’unico da noi realizzabile, a meno di non iniziare a modificare il codice sorgentedelle funzioni PLAN) aumentando cioè il budget di risorse inizialmente fornito (al momento dellainiezione)7 Queste informazioni sono state fornite dal prof. Michael Hicks (ZZZ�FLV�XSHQQ�HGX�aPZK,PZK#GVO�FLV�XSHQQ�HGX), della University of Pennsylvania, a seguito di una nostra interrogazione inmerito. Ringrazio qui nuovamente (già fatto nella premessa all’intero lavoro) il professore per l’aiuto(indispensabile) fornito e per l’interesse mostrato verso il progetto D Q Q L H, questo mi riempepersonalmente di fiducia ed orgoglio.8 E’ stato proprio questo motivo (cui non si è riusciti a rimediare) a spingerci verso la richiesta diulteriori informazioni in merito, richiesta cui si è fatto riferimento già nella nota precedente.

Parte III, Sezione 6 Osservazioni conclusive74

Si è rimediato a questo problema (non avendo intenzione di riscrivere il codice

(ML) della gestione della ritrasmissione in un’ottica maggiormente dinamica)

solamente modificando il codice del file reliable/reliable.ml, nel punto dove

veniva stabilita la dimensione massima della tabella; che abbiamo pensato di

portare da 10 a 100 (let retransmit_store_size=10).

B. Osservazioni sul linguaggio di programmazione PLAN

Sul linguaggio PLAN si è già abbondantemente parlato nella sezione dedicata, e proprio in

quel contesto sono state non poche le parentesi di commento (che pure hanno finito col

rimandare a questa parte conclusiva). Il paragrafetto che vi si presenta viene quindi

organizzato come una sorta di schematizzazione (con un tentativo di analisi) dei vari punti

“dubbi” incontrati finora:

• dati residenti

Si è già accennato al fatto che è possibile scrivere dati su un nodo della rete e si è

anche sottolineato il fatto che a tali dati è associato un tempo di permanenza sulla

memoria del nodo (timeout), assegnato dall’utente ma limitato da un tetto superiore di

300 secondi (5 minuti). Và da sé che un tale sistema di gestione dei dati residenti non

può pensarsi definitivo (sicuramente appare grossolano ed inelegante) e difatti gli

stessi autori9 esplicitano la speranza di poter, in futuro, implementare un mezzo più

“piacevole” di mantenimento della “pulizia” dei nodi (magari mediante una sorta di

garbage collection, dei dati inutilizzati).

Un altro punto (forse neanche ancora accennato) non propriamente “inattaccabile”

nella gestione dei dati residenti è quello che riguarda la, forse eccessiva, libertà

consentita nell’accesso alle risorse sui nodi (si allude principalmente alla memoria).

Anche qui sembrano allo studio eventuali procedure di autentificazione che possano

abilitare o meno la scrittura sul nodo (magari effettuando un filtraggio, permettendo

quindi tale operazione a seconda del possesso di determinati privilegi che potrebbero

essere richiesti alle capsule).

9 In un commento al package resident, nella guida al programmatore (riferirsi a [3])

Parte III, Sezione 6 Osservazioni conclusive75

• dichiarazione di tipi complessi

Non è affatto possibile, in PLAN, effettuare dichiarazioni di tipi di dati. E’ però

consentito, come unica (comunque non poco importante) forma di

“personalizzazione”, costruire tuple (date dal prodotto cartesiano di uno o più tipi

base).

La volontà di parlare ora di questo argomento (non certo fondamentale se paragonato

agli altri) è dovuta principalmente al desiderio di esprimere le difficoltà incontrate nel

non poter usare un tipo vettore (ma anche all’ambizione di poter elencare adesso

talune delle funzioni appositamente realizzate). Si ricorderà10 come si sia imposta la

necessità di ideare funzioni ad-hoc, tali da consentire l’applicazione alle liste (unica

struttura dati, ad eccezione della già citata tupla, consentita) di tecniche caratterizzanti

le strutture statiche.

Verranno adesso (solamente) elencate alcune delle più importanti tra le funzioni cui si

è fatto (ormai fin troppo ampiamente) riferimento:

- reverse che effettua l’inversione dell’ordine degli elementi del vettore in

esame.

- seek che restituisce l'elemento alla posizione indicata dal parametro

(simulazione dell’accesso diretto in lettura); qualora non vi fossero elementi nella

posizione richiesta (minore di 1 o maggiore del numero di valori presenti nel

vettore) si fornisce un false come risultato (accanto ad un valore numerico privo

comunque di significato)

- modL che permette di modificare l'elemento di una data posizione nel vettore

(simulando l’accesso diretto in scrittura)

- trouve che individua la posizione della prima occorrenza di un elemento

passato come parametro. Restituisce 0 se l’elemento non dovesse essere presente.

10 E’ comunque permesso riprendere in considerazione la sezione dedicata all’analisidell’algoritmo (nel paragrafo che esaminava i dati residenti sul nodo, in particolare i links)

Parte III, Sezione 6 Osservazioni conclusive76

• costrutti di loop

La completa assenza di possibilità di effettuare cicli condizionati, che –invece-

risultano essere spesso indispensabili nel nostro progetto11, ci ha posti in una

situazione complessa: riuscire a sfruttare ogni mezzo disponibile per simularne, in

qualche modo12, l’effetto.

Proviamo ad analizzare le tecniche adoperate a tale scopo:

1. ciclo di scorrimento condizionato di una lista13

Si è reso necessario nella ricerca di un dato elemento all’interno della lista14.

Serviva, quindi, una scansione della stessa lista fino all’individuazione del

simbolo cercato.

soluzione implementata:

Si è utilizzata la fornita funzione di scansione (incondizionata) della lista stessa

(foldl), con l’aggiunta di una memorizzazione temporanea (come dato residente)

delle informazioni richieste (ad esempio la posizione dell’elemento cercato),

quando ottenute. Alla fine del ciclo (terminata la scansione dell’intera lista) si è

provveduto a riportare il dato memorizzato e quindi a cancellarlo.

11 E non poteva essere certo diversamente, stando alla celebre legge di Murphy (non ancoradimostrata con rigore matematico ma neppure una volta smentita da prove empiriche).12 Si lascia immaginare (ma tutto verrà chiarito poco oltre) come questo in qualche modoimplichi metodi non proprio da manuale. Ancora adesso non riusciamo a non rabbrividirne, data lapalese violazione di ogni minimo concetto di pulizia logica (sia essa d’analisi o di programmazione).

Premetto che non si va certamente fieri delle soluzioni trovate (che spesso brillano perineleganza) ma che queste stesse si sono rivelate provvidenziali per la prosecuzione realizzativadell’intero progetto (altrimenti costretto ad una “fine” prematura, particolarmente dolorosa). Con ciònon si vuole certo affermare, con il più alto grado di sicurezza, che non sia effettivamente possibileindividuare (con una straordinaria fantasia e mediante una celeste illuminazione) soluzioni menogrossolane e più efficienti (noi, comunque, non siamo riusciti ad andare oltre le scelte fatte; e non vedosinceramente quale ulteriore tempo avremmo potuto investirvi).13 Vettore, secondo la nostra concezione (esplicitamente dichiarata già in questa stessa sezione).14 Ad esempio, la direzione verso il parent del nodo in esame (individuato come quello aventesimboloP(=3) nello lo status del link corrispondente).

Parte III, Sezione 6 Osservazioni conclusive77

2. ciclo di attesa di un evento (repeat…until)

a) primo caso(Attesa dello “spegnimento” di un semaforo)

Quando una capsula tenta l’accesso ad un nodo e trova, in questo, il semaforo

acceso (è quindi presente un’altra capsula che –al momento- esegue istruzioni

interne al blocco critico), dovrebbe attenderne lo spegnimento (effettuato, da

buona norma, dalla stessa capsula interna al blocco).

soluzione implementata:

Si è scelto di rimandare indietro (al nodo dal quale proveniva, che –

comunque- è un nodo adiacente) la capsula che ha fallito il tentativo d’accesso

per farla poi subito rispedire nuovamente verso la destinazione (nuovo

tentativo)15.

b) secondo caso(Ciclo di “coordinamento” effettuato dal quartier generale)

Il quartier generale, come si può benissimo evidenziare dal diagramma a

blocchi16, necessita di attendere il verificarsi di un evento (che può essere,

ricordiamo: la richiesta di insediamento di una nuova base d’avamposto, la

richiesta di eliminazione di una base che ha terminato l’esplorazione dell’area

assegnata o il verificarsi della condizione di fine lavoro).

soluzione implementata:

Si è pensato (senza avere però troppi gradi di libertà) di servirci della

ricorsione. Al termine del test sul verificarsi di un evento (così come al

termine della trattazione di uno dei primi due eventi elencati) si procede col

richiamare la stessa funzione, ripetendo quindi nuovamente i test…

15 Si fa notare comunque notare che, sperimentalmente, si è osservata una bassa probabilità difallimento del tentativo d’accesso (inferiore al 10%) e, nella quasi totalità dei casi, non è statanecessaria una seconda rispedizione (non si è quindi giunti ad un terzo tentativo d’accesso, sufficiente ilsecondo).16 Ci si riferisca alla sezione precedente (analisi dell’algoritmo).

Parte III, Sezione 6 Osservazioni conclusive78

Sarebbe bastato il costrutto di un qualunque ciclo o, al limite richiamare la

stessa funzione senza dover necessariamente far uso della ricorsione, ma né

l’una né l’altra possibilità viene messa a disposizione del programmatore17.

C. Osservazioni sul progetto software realizzatoSviluppi futuri

Sarebbe bello, in questa ultima parte, fare solamente un lungo, ricco e coinvolgente elogio

delle notevoli potenzialità che il progetto sembra possedere (secondo il mio modesto,

asettico, obiettivo e disinteressato parere).

Pur volendo rimarcare la vastità dell’ambiente cui ci si è addentrati, l’aspetto di solidità,

flessibilità e robustezza che credo possa essere disinvoltamente accordato alla struttura

dell’algoritmo e il grado di competenza ed efficienza complessivamente (nello studio

teorico e nella realizzazione pratica) raggiunto non sembra corretto non citare (ed

esaminare) quelle che sono considerabili come imperfezioni, modificabili magari in

successive versioni ma attualmente presenti.

17 Che, in certi casi, raggiunge livelli di stess e confuzione tali da spingerlo (a rischio discomunica da parte di tutta la comunità civile) a rimpiangere i vecchio, “sporco”, disordinato,pericoloso, incondizionato, destabilizzante, impresentabile ed inutilizzabile go to.

Parte III, Sezione 6 Osservazioni conclusive79

• mutua esclusione

In un ambiente distribuito come quello considerato, il problema di garantire la mutua

esclusione nell’accesso a dati condivisi e quello –forse ancora più pressante- di

mantenere l’atomicità di alcune sequenze di operazioni (che non devono essere

interrotte), è di grande (fondamentale) importanza.

La difficoltà realizzativa e, soprattutto, la inadeguata soluzione trovata18, spinge però a

proporre un cospiquo sforzo nella direzione di limitare il più possibile (ma meglio

eliminare) la dimensione dei blocchi critici considerati.

• spreco di risorse

Si è più volte (e non solo in questa sezione) fatto riferimento al problema della

gestione, non proprio efficientissima, delle risorse. In realtà si tratta di una vera e

propria enorme voragine che implica uno spreco spesso inaccettabile (e, da un punto

di vista di linearità e “purezza”, assolutamente insopportabile) di resource bound in

una sessione esplorativa (tanto che, come già detto, si è costretti a sovradimensionarne

tantissimo la quantità inizialmente fornita).

A cosa sia dovuto questo spreco si sarà, probabilmente, compreso; riassumiamo

comunque (in una sintetica schematizzazione) tali motivazioni:

1. La necessità di garantire una trasmissione affidabile delle capsule ha spinto

all’utilizzo della RetransOnRemote che, ripetiamo, suddivide le risorse

equamente a tutte le possibili ritrasmissioni, anche quando queste non

risultino necessarie:

nella semplice trasmissione da un nodo al suo adiacente, considerando un limite massimo di treritrasmissioni, si ha una perdita di 667 (su 1000) unità di risorsa (contro l’unica (1) necessaria)

18 Si faccia riferimento alla trattazione del problema dell’inesistenza di cicli nel linguaggio PLAN

1000

x 3 ritr.

333

Parte III, Sezione 6 Osservazioni conclusive80

2. L’impossibilità di trasferire risorse da una capsula all’altra19 è stata ulteriore

vincolo ad una politica di recupero delle risorse stesse. Ricordiamo come si

sia progettato, e sia stato mantenuto tuttora presente, un meccanismo che –

potendo effettuare la citata operazione di trasferimento- riuscirebbe a ridurre

(sensibilmente) lo spreco cui ci si riferisce.

riportiamo la schematizzazione già considerata nella sezione 5 (nella parte dedicata ai dati residenti)riguardo la gestione delle risorse nell’attraversamento di un router

(a): fase di esplorazione: divisione equa delle risorse tra tutte le capsule “figlie”(b): fase di rientro, nell’ipotesi che l’ultima capsula figlia a rientrare sia quella con risorse pari a 3osserviamo (in verde) come ben più efficiente sia la gestione delle risorse qualora fosse possibile

realizzare un “riutilizzo” di quelle rimanenti.

19 Tale argomento è stato affrontato nella parte iniziale di questa stessa sezione.

100

33

33

33

3

31

3

12

31+3+12=46

(a) (b)

A P P E N D I C E

Appendice A

Prova sperimentale

In questa brevissima appendice viene sinteticamente descritta la rete che si è ideata come

scenario ove poter effettuare un (significativo) testing del programma realizzato.

Si vuole qui mettere in evidenza lo sforzo proteso al mantenimento del più alto grado di

genericità possibile nella costruzione della rete. Si è infatti cercato di non rimare invischiati in

nessun genere di “ordine”, né esplicitamente prestabilito, né involontariamente realizzato.

A tale scopo di genericità (che fornisce uno strumento ideale di testing), si vuole giungere

attraverso la realizzazione di alcune condizioni:

• non tutti i nodi della rete devono avere un eguale numero di adiacenti.

• devono (ovviamente) essere presenti sia routers che nodi terminali.

• non dovrebbe esistere alcun grado di gerarchizzazione esplicita tra i nodi della rete.

Nella costruzione della rete attiva si è voluto utilizzare un certo numero di macchine differenti

(cfr. tabella seguente), per fornire alla rete stessa le condizioni di aleatorietà implicate sia da

performances (computazionali) non più necessariamente coincidenti, che dalla presenza di

connessioni effettive (con il loro grado di efficienza e velocità) tra macchine diverse.

Appendice B Prova Sperimentale83

Viene adesso presentato il tracciamento schematico della rete attiva PLANet che è stata

costruita:

Schematizzazione della rete attiva utilizzata come rete di testing del programma presentato

12

3

4

5

13

15

16

14

6

789

11

1012

Appendice B Prova Sperimentale84

Viene presentata adesso una tabella riassuntiva dello schema prima tracciato; quasi una

legenda, necessaria a comprendere -nel suo insieme- l’effettiva dimensione della rete in esame

e la sua concreta dislocazione pratica nelle macchine disponibili.

id. nodonum.vicini

nome macchina(dove si trova il nodo)

elenco dei numeri diporta utilizzati

1 1 3348

2 1 3329

3 4 3330-31-32-33

4 4

archimedearchimede.cere.pa.cnr.it

3334-35-36-37

5 1 3328

6 3 3329-30-31

7 1 3332

8 2

galileogalileo.cere.pa.cnr.it

3333-3334

9 4 3328-29-30-31

10 1 3332

11 3 3333-34-35

12 1

fermatfermat.cere.pa.cnr.it

3336

13 4 leibnizleibniz.cere.pa.cnr.it

3328-29-30-31

14 1 panellapanella.icsi.berkeley.edu

3332

15 4 3339-40-41-42

16 1

archimedearchimede.cere.pa.cnr.it

3343

Tabella riassuntiva dei principali attributi dei nodi della retein relazione alla sua reale dislocazione

Appendice B Prova Sperimentale85

Si ponga attenzione alla scelta di inserire nella rete, per rendere ancor più concrete le

intenzioni inizialmente espresse, un nodo attivo posto su una macchina dislocata negli Stati

Uniti (precisamente a Berkeley, in California).

Il fatto che tale nodo (il 14) sia stato configurato come nodo terminale sembra abbastanza

intuitivo, specie nella considerazione che il suo effettivo posizionamento “fisico” lo potrebbe

far classificare come nodo (decisamente) remoto, rappresentante magari una porta d’accesso

ad un’altra rete attiva PLANet, in qualche modo locale:

scenario prospettato, in cui più reti attive locali sono connesse tra loro medianteopportuni (e robusti) canali di trasmissione

Si vuole prospettare questo scenario per indirizzare, verso simili situazioni (affatto lontane da

una realistica configurazione), un eventuale sviluppo futuro del progetto che si è appena

terminato di descrivere.

(* progetto: A N N I E

Active Network, New Intelligent Exploration *)

(* Alessandro Luparello

v.le Regione Siciliana S.E., 726

90129 Palermo *)

(* Universita' degli Studi di Palermo

Facolta' di Ingegneria Informatica *)

(* Il progetto effettua l'esplorazione di una qualsiasi rete attiva PLANet, col fine di restituire il numero di routers ivi pre senti

Per una migliore comprensione dell'algoritmo e, di conseguenza, del codice, si consiglia di esaminare anche la documentazion e

allegata *)(* Linguaggio PLAN 3.1 *)

(* Il codice nel seguito e' quello contenuto in ogni singola capsula che si muove nella rete *)(* Puo' essere pensato come suddiviso in sezioni tematiche:

1. parte generale sulla gestione delle strutture dati (liste come fossero array)

Comprende funzioni di carattere generale (facilmente trasportabili e riutilizzabili in altri programmi PLAN)

per simulare l'utilizzo di un array dinamico, avando a disposizione solamente il tipo lista.Sono presenti quindi funzioni come:

- reverse che effettua l'inversione dell'ordine degli elementi

- seek che restituisce l'elemento alla posizione indicata (accesso diretto!)

- modL che permette di modificare l'elemento di una data posizione (accesso diretto!)- trouve che individua la posizione della prima occorrenza di un elemento

Tali funzioni (come altre) sono presenti spesso in due versioni: una relativa a liste di interi (necessaria per la

gestione dell'array degli status dei links (verso i vicini) di ogni router), l'altra relativa a liste di host*dev

(risultante dalla funzione PLAN di lettura dell'elenco dei vicini di un nodo: necessaria appunto per la gestione

della lista degli adiacenti di un nodo.

2. parte relativa alle funzioni di test

Comprende le funzioni:

- isOutpost che restituisce un boolean in conformita' al fatto che la capsula si trovi o meno in un avamposto- isFather che restituisce true se il nodo in esame e' quello di provenienza della capsula (a seconda della

direzione di esplorazione: forward (->false), rewind (->true)

- isTerminal che indica se il nodo in esame e' un terminale (->true) o un router

- isClosed che riferisce se tutti i links della capsula sono stati "chiusi" (tutte le strade esplorabili sonostate esplorate)

3. parte relativa alle funzioni di lettura di dati sul nodo (non necessariamente dati resident)

Comprende le funzioni:

- previousNode che fornisce il nome del nodo (tipo host) dal quale la capsula proviene (l'ultimo analizzatoprima di quello in esame). Necessario per settare lo status del relativo link a "P".

- controlloStatus che ritorna lo status del nodo in oggetto (osservato/non osservato)

- controlloLevel che ritorna il livello di profondita' attualmente raggiunto (come distanza minima del nodo

in esame con il quartier generale)- FoundPrecNode che ritorna il nome (fornito come tipo host) del nodo precedente (secondo il cammino della

particolare strada di esplorazione effettuata). Individuato come quello marcato con "P"

nell'array dello status dei links del nodo

4. parte relativa alle funzioni di scrittura sul nodoComprende le funzioni:

- markNode che effettua il marking dello status del nodo in esame: non osservato -> osservato

- markLinks che effettua il marking iniziale e l'aggiornamento dell'array degli status dei links agli adiacenti

- mark TTLr che effettua il marking iniziale e l'aggiornamento (solamente mediante somma) dell'indicatore dellaquantita' di TTL (risorse vitali) residuo (relativo a tutte le capsule spia facenti capo al nodo)

- markCount che effettua la modifica principale (dato lo scopo del programma): quella relativa all'inizializzazione

ed aggiornamento del contatore di tutti i routers contati dalle spie facenti capo al nodo in esame

5. parte relativa alle funzioni di trasmissione delle capsule:Comprende le funzioni:

- ReliableDeliver che consente di effettuare una trasmissione "sicura".

Permette: - la frammentazione/riassemblamento del pacchetto (la sua dimensione supera

l'MTU dei links)- la ripetizione della trasmissione, nel caso di perdita del pacchetto nella

rete (e' presente infatti un segnale di ack)

- launchCaps che effettua la trasmissione delle capsule spia a tutti i vicini del nodo in esame, purche'

cio' sia consentito (ad esempio non si ritrasmette una spia al vicino dal quale si proviene)- goPrec che consente alla capsula spia di tornare indietro senza compiere alcuna operazione

(necessario, ad esempio, quando si raggiunge un nodo terminale)

- leaveNode che permette di "abbandonare" il nodo, una volta raccolte tutte le informazioni (sono

ritornate tutte le spie mandate in missione ai nodi vicini). Effettua la cancellazione

dei dati residenti ----> Nessun dato (o mark) resta residente sul nodo quando questo viene abbandonato, in fase di risalita delle informazioni raccolte.

6. parte relativa alla gestione degli avamposti:

Per quanto riguarda la creazione di un nuovo avamposto si hanno le funzioni:- messageNewO che effettua la richiesta "formale" al quartier generale

- newOutpostHQ che effettua la trasmissione della richiesta di formazione di un nuovo avamposto

Per quanto riguarda la cancellazione di un avamposto (missione terminata->zona esplorata interamente) si ha la funzione:

- messageDelO che effettua la richiesta "formale" al quartier generale (passando come parametri anche i

dati raccolti (uno fra tutti: numero di router contati))

7. parte relativa alle funzioni prinpali:

a) spy e' la funzione "scheletro" dell'algoritmo considerato alla base del processo di esplorazione(una sorta di main function, richiamata dalla capsula che raggiunge un nodo)

b) loop e' la funzione stabilmente eseguita sul quartier generale, gestisce le richieste di creazione e

cancellazione di avamposti, in attesa della terminazione del processo di esplorazione

c) go e' la funzione di iniezione (quella che viene lanciata dal terminale), gestisce il lancio

della prima spia e l'insediamento del loop sul quartier generale)*)

(* Parte contenente tutte le funzioni relative all'utilizzo delle liste *)

(* In particolare sono presenti funzioni di supporto che consentono di utilizzare la lista come fosse un array *)

(* Possiamo osservare come talune di queste funzioni siano del tutto generiche ed esportabili ad altri programmi (come e' stato fatto) *)

(* restituisce la lista (di interi) in ingresso ivertendo l'ordine degli elementi*)

fun reverse (Lista:int list):int list=

let val NewLista:int list=[]

fun appR (l:int list, i: int):int list=i::l (* appende un elemento intero in testa ad una lista di interi *) in foldl (appR,NewLista,Lista) end

(* restituisce la lista (di hosts) in ingresso ivertendo l'ordine degli elementi*)

fun reverseH (ListaH:host list):host list=

let val NewListaH:host list=[] fun appRH (l:host list, i: host):host list=i::l (* appende un elemento di tipo host in testa ad una lista di hosts *)

in

foldl (appRH,NewListaH,ListaH)

end

(* appende in coda di una lista di host *)

fun appendH (ListaH:host list, CodaH: host):host list = reverseH (CodaH::reverseH(ListaH))

(* restituisce l'elemento presente nella posizione i-ma (true) oppure false se la lista [di interi] non ha posizione i-ma *)fun seek (i:int, Lista:int list):bool*int=

let val K:key=generateKey() (* chiave interna alla funzione *)

fun Eseek (K:key, i:int, Lista:int list):int= (* Effective-SEEK *)

let val cont:int=1 (* contatore della posizione attualmente analizzata*)

fun contr_seek (other: (key*int*int), elemLista:int):key*int*int=

(* controllo se siamo giunti alla posizione i-ma e riporto elemento *)

if snd other=#3 other then (* giunti all'i-mo elemento *)

( put ("pippo",fst other,elemLista,300);

(fst other,snd other+1,#3 other)

)

else (* non i-mo elemento *)(fst other,snd other+1,#3 other)

in

(

foldl (contr_seek,(K,cont,i),Lista); (* scansione lista degli elementi *) get ("pippo",K) (* riporto valore trovato *)

)

end

val present:bool=(i>0)and(i<=length(Lista)) (* la posizione i-ma e' presente nella lista ? *)

val elem:int=if present then Eseek (K,i,Lista) else 0 (* elemento posto nell'i-ma posizione *) in

(

delete ("pippo",K); (* cancellazione dei dati temporaneamente scritti sul nodo *)

(present,elem) (* valori di ritorno *) )

end

(* restituisce l'host presente nella posizione i-ma (true) oppure false se la lista [di host*dev (neighbors)] non ha posizione i-ma *)

fun seekHNb (i:int, Lista:(host*dev) list):bool*host= let val K:key=generateKey() (* chiave interna alla funzione *)

fun Eseek (K:key, i:int, Lista:(host*dev) list):host= (* Effective-SEEK *)

let val cont:int=1 (* contatore della posizione attualmente analizzata

*) fun contr_seek (other: (key*int*int), elemLista:host*dev):key*int*int= (* controllo se siamo giunti alla posizione i-ma,riporto elemento *)

if snd other=#3 other then (* giunti all'i-mo elemento *)

(

put ("pippo",fst other,fst elemLista,300);

(fst other,snd other+1,#3 other) )

else (fst other,snd other+1,#3 other) (* non i-mo elemento *)

in

( foldl (contr_seek,(K,cont,i),Lista); (* scansione lista degli elementi *)

get ("pippo",K) (* riporto valore trovato *)

)

end val present:bool=(i>0)and(i<=length(Lista)) (* la posizione i-ma e' presente nella lista ? *)

val elem:host=if present then Eseek (K,i,Lista) else hd thisHost() (* in else un valore (host) che comunque non verra' mai gua rdato *)

in

(

delete ("pippo",K); (* cancellazione dei dati temporaneamente scritti sul nodo *) (present,elem) (* valori di ritorno *)

)

end

(* copia gli elementi della lista (di interi) dalla pos. 'a' alla 'z' nella nuova *)

fun duplicaL (Lista:int list, NewLista: int list, a:int, z:int):int list=

let val pos:int=1 (* indice scorrimento lista *)

fun copy (other: (int list)*int*int*int,elemLista:int ) : int list*int*int*int= (* copia elemento *)

if ((#4 other>=snd other) and (#4 other<=#3 other)) then (elemLista::fst other,snd other,#3 other,#4 other+1) else (fst other,snd other,#3 other,#4 other+1)

in

reverse (fst foldl (copy,(NewLista,a,z,pos),Lista))

end

(* restituisce la lista con il settaggio previsto (NEW al posto dell'i-mo elemento) *)

fun modLista (Lista :int list, (* lista *)

i :int, (* posizione cui cambiare l'elemento *)

NEW :int (* nuovo elemento *) ) :int list= let val NewLista: int list = [] (* lista di supporto *)

in

(

(* copia i primi i-1 elementi nella nuova lista appende il nuovo elemento

copia i restanti elementi della lista *)

duplicaL (Lista,NEW::reverse (duplicaL (Lista,NewLista,1,i-1)),i+1,length(Lista))

)

end

fun trouveEff (elem:int,Lista:int list,iterazione:int):int=

(

if member (elem,Lista) then (* se l'elemento cercato fa parte della lista... *)

if hd Lista=elem then iterazione else eval (|trouveEff|(elem,tl Lista,iterazione+1)) (* ritorna valore o continua la scansione *)

else 0

)

(* restituisce la posizione del valore elem nella lista [di interi] (prima occorrenza), 0 se non presente *)

fun trouve (elem:int,Lista:int list):int=trouveEff (elem,Lista,1)

fun trouveEffH (Host :host ,neigh:(host*dev) list, iterazione:int):int= let val NewLista:host list=[] (* lista vuota, di supporto *)

fun hostOnly (neigh:(host*dev)list) : host list= (* ricopia la lista dei neighbors in una lista di soli hosts *)

let fun copyH (NewLista:host list, elemLista:host*dev): host list = (fst elemLista)::NewLista

in reverseH (foldl (copyH,NewLista,neigh))

end

val hostneigh:host list= hostOnly (neigh) (* lista di tutti gli host vicini (senza devices) *)

in

( if member (Host,hostneigh) then (* se l'elemento cercato fa parte della lista... *)

if fst hd neigh=Host then iterazione

else eval (|trouveEffH|(Host,tl neigh,iterazione+1)) (* ritorna valora o continua la scansione *)

else 0 )

end

(* restituisce la posizione del valore elem nella lista [di host*dev(neighbors)] (prima occorrenza), 0 se non presente *)

fun trouveH (Host :host ,neigh:(host*dev) list): int= trouveEffH (Host,neigh,1)

(* ---------------------------------------------------------------------------------------------------------------------------- ------------------- *)

(* Terminata la parte relativa alle funzioni generali di gestione delle liste, segue quella relativa al progetto in se: *)(* procedure di supporto all'esplorazione *)

(* funzione utilizzata come chunk della abort -> nessuna operazione da fare *)

(* presa in considerazione quando si tenta di effettuare operazioni non consentite, secondo l'algoritmo *)

fun null():unit=()

(* ----------------- funzioni di test: *)

(* La capsula e' su un avamposto ? *)

(* ritorna true se l'host thisH appartiene ad uno degli host dell'unica macchina outpost *)

fun isOutpost (outpost:host):bool=thisHostIs(outpost)

(* ritorna true se il nodo in cui ci si trova e' "padre" di quello precedente *)

fun isFather (direction:int) : bool= (direction=1)

(* ritorna true se il nodo in cui ci si trova e' un terminale *)fun isTerminal (neighbors: (host*dev)list ) : bool=

if length (neighbors)=1 then true (* il nodo ha un solo adiacente -> terminale *)

else false

(* ritorna vero se tutti i links sono chiusi (-> tutte le strade sono gia' state esplorate) *)fun isClosed (Key:key):bool=

let fun allLinksClosed (Key:key):bool=

let val links:int list=try get ("links",Key) handle NotFound => abort (|null|()) (* lettura della lista degli status dei

links *)fun isKP (Key:key,link:int):key= (* test sul singolo link *)

if (link=2)or(link=3) then (Key) (* se il link e' marcato K (oppure P), continua la scansione *)

else (put ("closed",Key,false,300);Key) (* altrimenti (link in Wait) viene modificato il valore del flag *)

in (put ("closed",Key,true,300);

foldl (isKP,Key,links);

get ("closed",Key)

)

end val allLinksAreClosed:bool=allLinksClosed(Key) (* variabile da riportare in uscita *)

in

(

delete ("closed",Key); (* cancella il dato temporaneamente memorizzato sul nodo *) allLinksAreClosed (* ritorna il valore risultante del test effettuato *)

)

end

(* ----------------- funzioni di lettura dati: *)

(* ritorna il nome(host) del nodo (adiacente) dal quale la capsula proviene *)

(* ritornando l'host che, tra i neighbors, ha un device uguale al parametro *)

fun previousNode (Key:key, Neigh:(host*dev)list, deviceIN:dev):host= let

fun returnH (Key:key) : host=

let val retH : host = get("prov",Key)

in

( delete ("prov",Key); (* cancella dato momentaneamente residente *)

retH (* ritorna dato *)

)

end fun controlladev (unvicino: host*dev, other:key*dev) : key*dev=

if (snd unvicino=#2 other) then ( put ("prov",fst other,fst unvicino,300); (other) )

else ( (other) )

in

(

(* scandisce la lista dei vicini sino a trovare quello con la cui interfaccia coincida con quella *) (* che si ha come parametro (che coincide con quella che indica l'ingresso della caspula nel nodo stesso) *)

foldr (controlladev, Neigh, (Key,deviceIN) );

returnH (Key) (* ritorna il valore cancellando i dati temporanei *)

) end

(* ritorna l'host contrassegnato dal mark-link:P *)

fun FoundPrecNode (K:key, neigh: (host*dev)list) : host= try snd seekHNb(trouve(3,get("links",K)),neigh) handle NotFound => abort (|null|())

(* ritorna lo status del nodo sul quale ci si trova *)

fun controlloStatus (Key:key): int =

( try

get("status",Key)

handle NotFound => (0)

)

(* ritorna il livello del nodo sul quale ci troviamo *)

(* non vi sono funzioni che lo permettono --> sfruttiamo la tabella di RIP *)

fun controlloLevel (Key: key , HQ: host) : int = let val RIPtable: (host*host*dev*int)list = RIPGetRoutes() (* tabella di RIP del nodo *)

(* controlla se il record della RIP table e' quello dell'head-quartier e memorizza la distanza *)

fun distanza (lineaRIP: host*host*dev*int , other: key*host) : key*host =

if (fst lineaRIP=snd other) then ( put("distanza",fst other,#4 lineaRIP,300); other )else ( other )

in

(

foldr (distanza,RIPtable,(Key,HQ)); (* individua distanza (salva il dato temporaneamente sul nodo) *)

let val dist:int=get ("distanza",Key) (* legge il risultato della ricerca *) in ( delete ("distanza",Key); (* cancella il dato temporaneo *)

dist ) (* ritorna in uscita il risultato richiesto *)

end

) end

(* ----------------- funzioni di scrittura dati (marking): *)

(* marca il nodo attuale *)

fun markNode (Key:key,mark:int):unit = put ("status",Key,mark,300)

(* inizializza la lista dei links *)

fun initLinks (n:(host*dev) list):int list= let fun incoda (n:host*dev,l:int list):int list=0::l (* 0 indica link libero (da esplorare) *)

val lista:int list=foldr (incoda,n,[])

in

lista end

(* setta e marca i links *)

(* se direzione e' di avanzamento in esplorazione (forward) marca a P il link dal quale la capsula proviene *)

(* altrimenti lo marca a K *)fun markLinks (Key:key, dir:int, Host:host, neigh:(host*dev)list, ThisIsOutpost:bool) : unit=

let val links:int list=( (* ritorna la situazione dei links salvata. Se non ancora presente, la inizializza *)

try

get("links",Key) handle NotFound=> ( initLinks (neigh) )

)

val markIs:int= if (dir=0 and not ThisIsOutpost) then 3 else 2 (* valore del marchio al link: 3->P, 2->K *)

val pos :int= trouveH (Host,neigh) (* trova posizione del link nella lista (=posizione dell'host in questione nella list a dei vicini) *)

in put ("links",Key,modLista (links,pos,markIs),300) (* aggiorna la lista dello stato dei links *)

end

(* aggiorna il contenuto informativo del nodo attuale: TTL residuo *)fun markTTLr (Key:key, dir:int, TTLr:int):unit=

(

if (dir=0) then put ("TTLr",Key,0,300)

else let val TTLr_prec:int=get("TTLr",Key)

in

put ("TTLr",Key,TTLr_prec + TTLr,300)

end

)

(* aggiorna il contenuto del contatore sul nodo in esame *)

fun markCount (Key:key, dir:int, count:int):unit=

( if (dir=0) then put ("Count",Key,0,300) (* direzione di esplorazione -> inizializzazione del valore a 0 *)

else (* direzione di rientro ... *)

let val count_prec:int=get("Count",Key)

in

put ("Count",Key,count + count_prec,300) (* somma nuovo valore al precedente *) end

)

(* ----------------- funzioni relative alla trasmissione delle capsule: *)

(* Permette la trasmissione "sicura" dei pacchetti da un nodo all'altro *)

fun ReliableDeliver (dest:host, totalRB:int, type:int, c:chunk):unit= let val trasmissionKey : key = generateKey() (* chiave della sessione di trasmissione *)

val Nrip : int = 2 (* massimo 2 ritrasmissoni / si suppone siano sufficienti *)

val RB_Ack : int = 10 (* risorse da assegnare al messaggio di ACK *)

val RB : int = totalRB/Nrip-RB_Ack-1 (* risorse per ogni tentativo di trasmissione *) val codeData : chunk = sendAck (c,trasmissionKey,RB_Ack) (* capsula con "ricevuta di ritorno" (acknoledgment) *)

val codeDataFrag : chunk list = fragment (codeData,getMTU(snd defaultRoute(dest))-fragment_overhead) (* capsula framme ntata *)

val RBperFrag : int = (RB/length(codeDataFrag)) (* risorse per ogni ogni frammento *)

in

RetransOnRemote (codeDataFrag, trasmissionKey, Nrip, dest, RBperFrag, defaultRoute)

end

(* lancia le capsule a tutti i vicini con link liberi (marcati con F) *)

fun launchCaps (Key:key, thisH:host, neigh:(host*dev)list, outpost:host,dir:int,newlevel: int,levelMAX:int,level_step:int):unit =

let

(* effettua il lancio della capsula spia al vicino in esame (se cio' e' consentito) *)

fun launchSPY (other: key*int list*host*int*int *host*int*int*int*int, vicino:host*dev): key*int list*host*int*int*host*int *int*int*int=

let val Key : key = fst other (* chiave della sessione di esplorazione *) val links : int list = snd other (* lista dello status dei links *)

val parent : host = #3 other (* l'host attuale (#3 other e' thisHost) diviene "padre" *)

val pos : int = #4 other (* posizione del link da esaminare *)

val RB : int = #5 other (* risorse a disposizione per la capsula *)

val outpost : host = #6 other (* nome dell'avamposto: resta immutato *) val direct : int = #7 other (* direzione di avanzamento della spia: resta immutato *)

val level_prec : int = #8 other (* il livello attualmente raggiunto diviene livello precedente per la nuova capsula *)

val levelMAX : int = #9 other (* livello massimo di esplorabilita' per la spia: resta immutato *)

val level_step : int = #10 other (* passo di modifica del livello massimo di avanzamento: resta immutato *) in

(

if (snd seek(pos,links)=0) then (* link F (da visionare) *)

( print ("--spia lanciata a "^toString(fst vicino));

ReliableDeliver (fst vicino,RB,0,|spy|(Key,0,outpost,direct,level_prec,levelMAX,level_step)); (Key, modLista (links,pos,1 (*W*)) ,parent ,pos+1, RB, outpost, direct, level_prec, levelMAX, level_step)

)

else (* link P,K,W (da non visionare) *)

(Key, links ,parent, pos+1, RB, outpost, direct, level_prec, levelMAX, level_step) )

end

val i:int=0 (* posizione (nell'elenco dei neighbors) della destinazione della nuova spia *)

val links:int list=get ("links",Key) (* status dei links *) fun getNumFreeLinks (links:int list):int= (* ritorna il numero dei link ancora aperti (da esplorare) *)

let val num:int=0

fun inc (link:int,count:int):int= if link=0 (*-F-*) then (count+1) else (count)

in foldr (inc,links,num)

end

val numFreeLinks :int = getNumFreeLinks (links) (* numero links da esplorare *)

val RBperSPY :int = getRB()/numFreeLinks-1 (* risorse da assegnare ad ogni spia *) in

(* aggiornamento dello status dei links *)

put ("links",Key,snd foldl (launchSPY,(Key,links,thisH,i+1,RBperSPY, outpost,dir,newlevel,levelMAX,level_step),neigh),300)

end

(* la capsula torna al nodo precedente senza compiere alcuna operazione *)

(* necessario, ad esempio, quando si e' raggiunto un nodo terminale *)

fun goPrec (Key:key, parent:host, thisH:host, outpost:host, levelP:int,levelMAX:int,levelStep:int,counter:int, daOutpost:bool) : unit = let val RB:int=if not daOutpost then getRB() (* se non proveniamo da un avamposto -> tutte le risorse *)

else getRB()/2-1 (* altrimenti meta' risorse: *)

(* l'altra meta' viene utilizzata per le procedure di costruzione dell'avamposto stesso *)

in

ReliableDeliver (parent,RB,0,|spy|(Key,counter,outpost,1,levelP,levelMAX,levelStep)) (* trasmissione della capsula *) end

(* abbandona il nodo, verso il suo precedente *)fun leaveNode ( Key:key, thisH:host, neigh: (host*dev) list,

outpost: host, ThisIsOutpost: bool,

level_prec:int, levelMAX:int, level_step:int ):unit =

let

val Count : int = get ("Count",Key)+1 (* conteggio memorizzato +1 (router attuale) *) val TTLr : int = get ("TTLr",Key) (* TTL residuo memorizzto *)

val Nneigh : int = length (neigh) (* numero di vicini: destinatari dei barricatori *)

val RBforB : int = 100 (* risorsa attribuita ad ogni barricatore (eccediamo per un'eventuale ritrasmissione) = 100 *)

val RBforBs: int = RBforB *Nneigh (* risorse accantonate per lanciare poi tutti i barricatori *)

(* manda un massaggio al quartie generale: cancella avamposto *)

fun delOutpostHQ (Key:key,thisH:host,level:int):unit=

let val OCount: int= get ("Count",Key)+1 (* Routers contati dalla spia: +1 e' relativo all'avamposto stesso *) val OTTLr : int= get ("TTLr",Key)

in (

print ("messaggio all'HQ con i dati seguenti:\n avamposto da chiudere: "^toString(thisH)^"\n routers contati: "^to String(OCount));

ReliableDeliver (getSource(),getRB(),1,|messageDelO| (Key,thisH,level,OCount,OTTLr)) (* trasmissione messaggio *)

) end

in

( if not ThisIsOutpost then (* Non siamo su un avamposto --> torniamo al P *) let val P : host = FoundPrecNode(Key,neigh)

in

(

print ("Abbandono il nodo --> spia al P: "^toString(P));

ReliableDeliver (P,getRB(),0,|spy|(Key,Count,outpost,1,level_prec,levelMAX,level_step)); (* trasmissione della spia al n odo prec.*)print("Routers contati dalla spia: "^toString(Count));

(* cancellazioni informazioni poste sul nodo (compito svolto prec. dai DESTROYERs *)

try delete("status",Key) handle NotFound =>(); try delete("links",Key) handle NotFound =>();

try delete("Count",Key) handle NotFound =>();

try delete("TTLr",Key) handle NotFound =>();

print ("tutti i dati residenti sono stati cancellati (nodo liberato!)");

delete ("marking",Key) )

end

else (* Siamo su un avamposto --> trasmettiamo dati al quartie generale *)

( print ("lascio outpost");

delOutpostHQ (Key,thisH,level_prec)

)

)

end

(* Rilancia la capsula spia nel caso in cui il nodo di destinazione era momentaneamente occupato (semaforo in ALT) *)

fun RilanciaSpy (D : host, (* nodo ove rilanciare la capsula spia *)

Key : key, (* chiave della sessione di esplorazione *)

counter : int, (* numero di router contati finora (in fase di ritorno) dalla capsula *) outpost : host, (* identificatore dell'avamposto al quale si fa riferimento *)

direction : int, (* indicatore della direzione di avanzamento: 0=forward, 1=rewind *)

level_prec : int, (* livello di profondita' finora raggiunto *)

levelMAX : int, (* massimo livello di profondita' che la spia puo' raggiungere (fino al prossimo avamposto) *) level_step : int (* passo di incremento del limite di profondita' alla creazione di un avamposto *)

): unit=

(

print ("<<** "^toString(D)^" occupato ("^toString(getRB())^")");

print ("Riprovo..."); ReliableDeliver (D,getRB(),0,|spy|(Key,counter,outpost,direction,level_prec,levelMAX,level_step)) )

(* ----------------- funzioni relative alla gestione degli avamposti: *)

(* creazione avamposto ... *)

(* riprova a lanciare la richiesta di creazione di un nuovo avamposto *)fun RiprovaMessaggeNO (Key:key, thisH:host, level:int):unit=

(

print("ritento lancio richiesta new outpost");

ReliableDeliver (getSource(),level+1,1,|messageNewO| (Key,thisH,level)) )

(* messaggio al quartier generale -> creazione nuovo avamposto *)

fun messageNewO (Key:key, thisH:host, level:int):unit=

let val CANwrite : bool = try setGT ("message",Key,1,300) handle NotFound => ( put("message",Key,1,300); true) in

(

if CANwrite then

( put ("outpostName",Key,thisH,300);

put ("outpostLevel",Key,level,300);

put ("flag",Key,1,300);

setLT ("message",Key,0,300) (* abbasso il flag sui messaggi (semaforo) *) )

else ReliableDeliver (thisH,getRB(),1,|RiprovaMessageNO|(Key,thisH,level))

)

end

(* manda un messaggio al quartier generale, crea avamposto *)

fun newOutpostHQ (Key:key,thisH:host,level:int,dir:int) :unit =

ReliableDeliver (getSources(),level+1,1,|messageNewO| (Key,thisH,level)) (* manda messaggio all'HQ: nuovo avamposto *)

(* cancellazione avamposto ... *)

(* ritrasmissione messaggio di richiesta cancellazione dell'avamposto *)fun RiprovaMessageDO (Key:key, thisH:host, level:int, OCount:int, OTTLr:int):unit=

(

print("ritento lancio: cancellazione");

ReliableDeliver (getSource(),getRB(),1,|messageDelO| (Key,thisH,level,OCount,OTTLr)) )

(* messaggio di richiesta di cancellazione di un avamposto *)

fun messageDelO (Key:key, thisH:host, level:int, OCount:int, OTTLr:int):unit=

let val CANwrite : bool = try setGT ("message",Key,1,300) handle NotFound => ( put("message",Key,1,300); true) in

(

if CANwrite then

( put ("outpostName",Key,thisH,300);

put ("outpostInfo",Key,(OCount,OTTLr),300);

put ("outpostLevel",Key,level,300);

put ("flag",Key,2,300);setLT ("message",Key,0,300) (* abbasso il flag sui messaggi *)

)

else ReliableDeliver (thisH,getRB(),1,|RiprovaMessageDO|(Key,thisH,level,OCount,OTTLr))

)

end

(* ---------------------------------------------------------------------------------------------------------------------------- ---*)

(* Opzione di VERBOSE *)

(* Visualizzazione dati all'arrivo della capsula spia nel nodo (modalita' -VERBOSE) *)fun printDATA (Key:key,parent:host, outpost:host, direction:int, status:int, level:int, thisH:host, thisD:dev, endHost:bool,cou nter:int):unit =

let val dir :string= if direction=0 then "FORWARD" else "BACK" (* direzione di esplorazione *)

val stat:string= if status=1 then "OBSERVED" else "NOT OBSERVED" (* stato del nodo *)

val term:string= if endHost then "TERMINAL" else "ROUTER" (* tipologia del nodo: terminale/router *) in

(

print ("\n\n*****************************************\n"^toString(Key));

if isOutpost(outpost) then print ("\nNodo: "^toString(thisH)^" [ AVAMPOSTO ]")

else print ("\nNodo: "^toString(thisH)^" ("^term^") "); print ("raggiunto dal: "^toString(parent)^" by interfaccia: "^toString(thisD));

print ("RB: "^toString(getRB())^"\nOutpost e': "^toString(outpost)^"\nquartier generale: "^toString(getSource()));

print ("Status: "^stat^", profondita': "^toString(level));

print ("direzione: "^dir^""); if direction=0 then print ("finora ho contato: "^toString(counter)^" routers\n") else () )

end

(* ---------------------------------------------------------------------------------------------------------------------------- ---*)(* Funzione principale di gestione della capsula spia *)

(* funzione riportante l'algoritmo di utilizzo della spia *)

fun spy (Key : key, (* chiave della sessione di esplorazione *) counter : int, (* numero di router contati finora (in fase di ritorno) dalla capsula *)

outpost : host, (* identificatore dell'avamposto al quale si fa riferimento *)

direction : int, (* indicatore della direzione di avanzamento: 0=forward, 1=rewind *)

level_prec : int, (* livello di profondita' finora raggiunto *) levelMAX : int, (* massimo livello di profondita' che la spia puo' raggiungere (fino al prossimo avamposto) *)

level_step : int (* passo di incremento del limite di profondita' alla creazione di un avamposto *)

): unit=

let val status : int = controlloStatus(Key) (* status del nodo in esame *)

val level : int = controlloLevel (Key,getSource()) (* livello del nodo in esame *) val neighbors : (host*dev)list= getNeighbors() (* nodi adiacenti a quello in esame (links) *)

val thisD : dev = getSrcDev() (* interfaccia del nodo in esame (quella dalla quale vi siamo arrivati) *)

val thisH : host = thisHost(thisD) (* Host in esame *)

val endHost : bool = isTerminal(neighbors) (* siamo su un nodo terminale ? *) val parent : host = previousNode (Key,neighbors,thisD) (* nodo dal quale proveniamo *)

val ThisIsOutpost : bool = isOutpost(outpost) (* siamo arrivati all'outpost ? *)

val MUTEX : bool = try setGT ("marking",Key,1,300) handle NotFound => (put("marking",Key,1,300); true) (* chiudo il

semaforo se aperto *)

in (

if MUTEX then (* la mutua esclusione e' salvaguardata, il semaforo (libero) e' stato posizionato ad ALT *)

(

printDATA (Key,parent,outpost,direction,status,level,thisH,thisD,endHost,counter); (* visualizzazione dati significativi ( -VERBOSE) *) print ("SEM alzo il flag"); (* indicatore di semaforo occupato *)

if ( ((status=0) and not endHost) or (ThisIsOutpost and direction=0)) then (* router non marcato *)

(

if ((level>=level_prec) and (level<levelMAX)) then (* libero/ entro l'area di esplorabilita' *) (

markNode (Key,1); (* status nodo: Observed *)

print ("Mark: OBSERVED");

markLinks (Key,direction,parent,neighbors,ThisIsOutpost); (* inizializzazione dei links *)print ("Mark links "^toString(get("links",Key))^"\nvicini: "^toString(neighbors));

launchCaps (Key,thisH,neighbors,outpost,direction,level,levelMAX,level_step); (* lancio delle capsule spia ai vicini *)

print ("Lancio capsule effettuato...");

markTTLr (Key,0,0); (* inizializzazione del TTL residuo *)print ("set TTL: 0");

markCount (Key,0,0); (* inizializzazione del COUNTER *)

print ("set count: 0")

)

else (* libero/ fuori area di esplorabilita' *) (

if (level<level_prec) then (* libero/ fuori area/ livello inferiore *)

(

print ("livello inferiore, barrico (->"^toString(parent)^") e torno indietro (RB: ^toString(getRB())^")");markLinks (Key,1,parent,neighbors,ThisIsOutpost);

goPrec (Key,parent,thisH,outpost,level,levelMAX,level_step,counter,false)

)

else (* libero/ fuori area/ oltre limite MAX *)

(print ("Nuovo avamposto");

markNode(Key,1); (* Observed *)

goPrec(Key,parent,thisH,outpost,level,levelMAX,level_step,counter,true); (* la capsula ritorna indietro *)

newOutpostHQ (Key,thisH,level,direction) (* richiesta nuovo avamposto *))

)

)

else (* router gia' marcato o terminale *) let val prec_Wait : bool = if (not endHost) then (snd seek (trouveH(parent,neighbors),get("links",Key))=1 ) (* spia ancora attesa *)

else false

(* spia non piu attesa *)

in (

if (isFather(direction) and prec_Wait) then (* terminale o marcato/ padre in attesa *)

(* nodo di provenienza e link dal quale proveniamo a W (non a K: risultato inutile) *)

(print ("\nNodo di provenienza...(di "^toString(parent)^")");

markTTLr (Key,1,getRB()); (* aggiornamento del TTL residuo *)

print ("TTL (+ "^toString(getRB())^")");

markCount (Key,1,counter); (* aggiornamento del COUNTER *)

print ("Count (+ "^toString(counter)^")");markLinks (Key,direction,parent,neighbors,ThisIsOutpost); (* aggiornamento dello status dei links *)

print ("Mark -K- link verso "^toString(parent)^"\nora: "^toString(get("links",Key)));

if isClosed(Key) then (* tutti i links sono stati esplorati *)

( print ("* Tutti i links sono stati esplorati");

leaveNode(Key,thisH,neighbors,outpost,ThisIsOutpost,level_prec,levelMAX,level_step); (* la capsula abban dona il nodo *)

print ("Nodo lasciato")

)

else () )

else (* terminale o marcato/ non padre in attesa *)

(

if (not isFather(direction)) then (* terminale o marcato/ terminale o marcato da altri *)(

if (not endHost) then (* terminale o mercato/ marcato da altri *)

(

markLinks (Key,1,parent,neighbors,ThisIsOutpost); (* barrichiamo il link verso il nodo di prov.*)

print ("barrico verso "^toString(parent));print ("I links sono adesso... "^toString (get("links",Key)))

)

else ();

print ("(nodo gia' raggiunto o terminale) torno indietro (RB: "^toString(getRB())^")"); goPrec(Key,parent,thisH,outpost,level,levelMAX,level_step,counter,false) (* la spia torna indietro *)

)

else (* terminale o marcato/ padre non in attesa *)

(

print ("il link e' gia' stato barricato, le mie informazioni non sono utili!");

if isClosed(Key) then (* controllo sullo stato dei links: tutti chiusi ? *) (

print ("* Tutti i links sono stati esplorati");

leaveNode(Key,thisH,neighbors,outpost,ThisIsOutpost,level_prec,levelMAX,level_step); (* la capsula ab bandona il nodo *)

print ("Nodo lasciato") )

else ()

)

)

)

end;

print ("SEM abbasso il flag"); (* indichiamo d'aver "liberato" la risorsa *) try setLT ("marking",Key,0,300) handle NotFound => put ("marking",Key,0,300) (* abbassamento del flag semaforo (-> libero) *)

)

else (* nodo momentaneamente inaccessibile (un'altra spia sta modificando i dati) *)

( print ("**>> ["^toString(parent)^"] tentato accesso ("^toString(getRB())^")");

ReliableDeliver (parent,getRB(),0,|RilanciaSpy|(thisH,Key,counter,outpost,direction,level_prec,levelMAX,level_step))

)

)

end

(* ---------------------------------------------------------------------------------------------------------------------------- ---*)

(* Ciclo di attesa sul quartier generale... *)

(* Ciclo di attesa sul quartier-generale, gestisce interazione con avamposti (creazione, cancellazione, trasporto dati) *)(* Termina con la fine dell'esplorazione *)

fun Loop (Key:key,OOList:host list,OONum:int, layerRB:int, levelStep:int, actCOUNT:int,actTTLr:int): int*int =

let val CANreadMess : bool= try setGT ("message",Key,1,300) handle NotFound=> (put("message",Key,1,300); true) (* alziamo i l semaforo *)

val flag : int = try get("flag",Key) handle NotFound=> 0 (* stato del flag /se non presente(300s. dall'ultima modifica) e'0 *) in

(

if CANreadMess then (* nessuno sta,al momento, scrivendo messaggi *)

( if flag=1 then (* 1 = richiesta creazione di un nuovo outpost *)

let val newOutpostName : host =get ("outpostName",Key) (* nome del nuovo avamposto da creare *)

val newOutpostLevel : int =get ("outpostLevel",Key) (* profondita' a cui si trova *)

val newLayerRB : int =layerRB+newOutpostLevel (* risorse da fornire: devono essere uguali per tutti gli stra ti, *)

(* quindi indipendenti dalla profondita' *) val OpenOutposts : host list =appendH(OOList,newOutpostName) (* nuovo outpost "aperto" si aggiunge alla lista *)

in

(

print ("\nArriva richiesta nuovo avamposto da "^toString(newOutpostName)^"\n");

(* lanciamo una spia verso il nuovo avamposto *)

ReliableDeliver (newOutpostName,newLayerRB,0,|spy| (Key,0,newOutpostName,0,newOutpostLevel,newOutpostLevel+levelStep, levelStep));

print ("spia lanciata...\n");

(* resettiamo il flag a 0 (nessuna novita')/ cancelliamo gli altri campi *)

put ("flag",Key,0,300);

delete ("outpostName",Key);

delete ("outpostLevel",Key); print ("cancellati dati...\n");

(* modifica: aggiungiamo il nuovo avamposto nell'elenco degli avamposti ancora attivi/ incrementiamo il loro numero *)

setLT("message",Key,0,300);

(* ripetiamo il ciclo *)

eval (|Loop| (Key,OpenOutposts,OONum+1,layerRB,levelStep,actCOUNT,actTTLr))

)

end else

if flag=2 then (* 2 = in un avamposto si e' terminata la missione esplorativa *)

let val OutpostName : host = get ("outpostName",Key) (* nome dell'avamposto da "smontare" *)

val OutpostLevel : int = get ("outpostLevel",Key) (* profondita' a cui si trova *) val OutpostInfo : int*int = get ("outpostInfo",Key) (* informazioni raccolte nell'avamposto: count+TTLr

*)

val OpenOutposts : host list = remove(OutpostName,OOList) (* outpost "chiuso" si toglie dalla lista *)

in

( print ("\n-> Close outpost: "^toString(OutpostName)^" Dati: "^toString(fst OutpostInfo)^", "^toString(snd OutpostInfo));

(* resettiamo il flag a 0 (nessuna novita')/ cancelliamo gli altri campi *)

put ("flag",Key,0,300); delete ("outpostName",Key);

delete ("outpostLevel",Key);

delete ("outpostInfo",Key);

(* modifica: cancelliamo l'avamposto dalla lista di quelli ancora "attivi"/ decrementiamo il loro numero *) setLT("message",Key,0,300);

eval (|Loop| (Key,OpenOutposts,OONum-1,layerRB,levelStep,actCOUNT+fst OutpostInfo,actTTLr+snd OutpostInfo) )

)

end else (* 0 = nessuna nuova richiesta dal campo *)

if OONum=0 then (actCOUNT,actTTLr) (* chiusi tutti gli avamposti--> missione terminata *)

else (* non chiusi tutti gli avamposti *)

(

setLT("message",Key,0,300); (* abbassiamo il semaforo *) eval (|Loop| (Key,OOList,OONum,layerRB,levelStep,actCOUNT,actTTLr)) (* ripetiamo il ciclo *)

)

)

else (* qualche spia sta' mandando un messaggio... attendere prima di leggere *) (

print ("\noccupato...");

eval (|Loop| (Key,OOList,OONum,layerRB,levelStep,actCOUNT,actTTLr)) (* ripetiamo il ciclo *)

)

)

end

(* ---------------------------------------------------------------------------------------------------------------------------- ---*)

(* Funzione relativa all'inizio dell'esplorazione (funzione di iniezione) *)

(* funzione di lancio del programma *)

fun go ():unit= let val Key : key = generateKey() (* secret Key !!!!! *)

val OONum : int = 1 (* numero degli outpost di cui si attende la "chiusura" *)

val layerRB : int = 999999999 (* resource bound da assegnare ad ogni avamposto (per esaminare il suo strato) *)

val levelStep : int = 10 (* profondita' stabilita per ogni strato *)

val actualCOUNT : int = 0 (* inizializzazione: routers attualmente contati *) val actualTTLr : int = 0 (* inizializzazione: TTL attualmente residuo *)

in

(

if (length(getNeighbors())=1) then (* siamo su un nodo terminale *) let val firstOutpost : host = fst hd getNeighbors() (* primo outpost *)

val OOList : host list = [firstOutpost] (* elenco degli outpost ancora "aperti" ........... consideriamo anche il primo *)

in

(

print ("Siamo su un terminale, lancio il primo avamposto nel router prossimo\nPARTITO...."); ReliableDeliver (fst hd getNeighbors(),layerRB,0,|spy| (Key,actualCOUNT,firstOutpost,0,0,levelStep,levelStep));

print ("LOOP:....");

print ("\nI routers nella rete sono : "^ toString (fst Loop (Key,OOList,OONum,layerRB,levelStep,actualCOUNT,actualTTLr)))

) end

else (* siamo su un nodo non terminale *)

let val firstOutpost : host = hd thisHost() (* primo outpost: questo stesso di iniezione *)

val OOList : host list = [firstOutpost] (* elenco degli outpost ancora "aperti" ........... consideriamo anche il primo *) in

(

print ("Siamo su un router, questo e' il primo avamposto\nPARTITO....");

spy (Key,actualCOUNT,firstOutpost,0,0,levelStep,levelStep);

print ("\nI routers nella rete sono : "^ toString (fst Loop (Key,OOList,OONum,layerRB,levelStep,actualCOUNT,actualTTLr))) )

end

)

end

Riferimenti bibliograficireferences

[1] Jonathan T. Moore, Pankaj KakkarPLAN Grammar (for PLAN ver.3.1) November, 1998ZZZ�FLV�XSHQQ�HGX�aVZLWFKZDUH�3/$1�GRHVaRFDPO�JUDPPDU�JUDPPDU�KWPOwork supported by DARPA under Contract N66001-96-C-852

[2] Pankaj Hakkar, Michael W. HicksPLAN Tutorial (for PLAN ver.3.1) November, 1998ZZZ�FLV�XSHQQ�HGX�aVZLWFKZDUH�3/$1�GRHVaRFDPO�WXWRULDO�WXWRULDO�KWPOwork supported by DARPA under Contract N66001-96-C-852

[3] Jonathan T. Moore, Michael W. Hicks, Pankaj KakkarPLAN Programmer’s Guide (for PLAN ver.3.1) November, 1998ZZZ�FLV�XSHQQ�HGX�aVZLWFKZDUH�3/$1�GRHVaRFDPO�JXLGH�JXLGH�KWPOwork supported by DARPA under Contract N66001-96-C-852

[4] Michael W. HicksPLAN Service Programmer’s Guide (for PLAN ver.3.1) November, 1998ZZZ�FLV�XSHQQ�HGX�aVZLWFKZDUH�3/$1�GRHVaRFDPO�VHUYBJXLGHO�VHUYBJXLGH�KWPOwork supported by DARPA under Contract N66001-96-C-852

[5] Michael W. Hickspland: The PLAN Active Router (for PLAN ver.3.1) November, 1998ZZZ�FLV�XSHQQ�HGX�aVZLWFKZDUH�3/$1�GRHVaRFDPO�SDSHUV�SODQHW�SVwork supported by DARPA under Contract N66001-96-C-852

[6] Michael W.Hicks, Jonathan T.Moore, D.Scott Alexander, Carl A.Gunter, Scott M.NettlesDepartment of Computer and Information Science. University of Pennsylvania

PLANet: An Active Internetwork March, 1999ZZZ�FLV�XSHQQ�HGX�aMRQP�SDSHUV�LQIRFRP���DEV�KWPOsubmitted to 1999 IEEE Conference on Computer Communication (INFOCOM’99)work supported by DARPA under Contract N66001-96-C-852

[7] Jonathan T.Moore, Michael W. Hicks, Scott M.NettlesDepartment of Computer and Information Science. University of PennsylvaniaChunks in PLAN: Language Support for programs as Packets March, 1999^MRQP�PZK�QHWWOV`#GVO�FLV�XSHQQ�HGXsubmitted to 1999 IEEE Conference on Computer Communication (INFOCOM’99)

[8] Robert HarperSchool of Computer Science. Carnage Mellon University. Pittsburgh, PA 15213-3891

(with exercices by Kevin Mitchell, Edinburgh University, Edinburgh, UK)

Introduction to Standard ML January, 1993

[9] OCaml home page: ZZZ�SDXLOODF�LQULD�IU� FDPO�LQGH[�HQJ�KWPO

[10] Stuart J. Russel, Peter Norvig edizione italiana a cura di Luigia Carlucci AielloIntelligenza Artificiale (Artificial Intelligence. A modern approach) Febbraio, 1998Prentice Hall International, UTET

[11] Andrew S. TanenbaumReti di computer (Computer Network) Novembre, 1991Prentice Hall International, Jackson libri

[12] David L.Tennenhouse, David J.Wetherall Telemedia, Networks and System Group, MITTowards an Active Network Architecture^GOW�GMZ`# OFV�PLW�HGX ZZZ�WQV�OFV�PLW�HGX��An earlier version of this paper was delivered during the keynote session of Multimedia Computing andNetworking, San Jose, CA January, 1996

[13] David Wetherall, Ulana Legedza, John GuttagSoftware Devices and Systems Group, Laboratory for Computer Science, MITIntroducing New Internet Services: Why and How July, 1998^GMZ�XODQD�JXWWDJ`# OFV�PLW�HGX ZZZ�VGV�OFV�PLW�HGX��To appear in IEEE NETWORK Magazine Special Issue on Active and Programmable Networks

[14] J.M.Smith, D.J.Farabert, C.A.Gunter, S.M. Nettles, Mark E.Segal, W.D.Sincoskie,D.C.Feldmeier, D.Scott AlexanderCIS Department, University of Pennsylvannia; Bellcore; MUSIC Semiconductors, Inc.SwitchWare: Towards an Active Network ArchitectureResearch supported by DARPA under Contract DABT 63-95-C-0079 and N66001-96-C-852.Additional support by Intel, Hewlett-Packard and AT&T.

IndiceIndex

Prefazione …………………………………………………………………………………………….. 5

I Reti attive ……..…………………………………………………………………………… 6

1. Reti attive ………………………………………..…………………………………………… 7

- Introduzione 7

- Perché introdurre le reti attive? 7

- Vantaggi nell’utilizzo delle reti attive 9

- Diversi approcci alle reti attive: 9

A. Routers programmabili (approccio discreto) 9

B. Capsule (approccio integrato) 10

- Considerazioni architetturali 10

- Stato attuale della ricerca: Progetti 10

2. PLANet ……………………………………………………………………………………… 13

- Introduzione 13

- PLAN 14

- PLANet 15

A. Formato pacchetti PLAN 16

- indirizzamento 17

- programmi come dati 18

- campi rimanenti 19

B. Instradamento dei pacchetti 19

C. Analisi e gestione degli errori 20

D. Dettagli implementativi 21

- perché Ocaml 21

- Costruzione effettiva dei nodi attivi 22

3. Linguaggio PLAN …………………..……………………………………………………. 28

- Introduzione 28

- Risorse limitate 29

- Pacchetti: a) programma PLAN 29

chunks 30

b) pacchetto PLAN 32

c) applicazione PLAN 32

- Modello di valutazione 33

- Vita di un pacchetto 34

- Eccezioni 35

- Gestione degli errori 36

- Costrutti e primitive del linguaggio: 36

a) costrutti 37

b) primitive: 37

b.1) primitive di rete 37

b.2) iteratori di liste 39

- Servizi 40

1. servizi essenziali (core services) 40

2. servizi aggiuntivi (package services) 42

II Analisi del progetto software ………………………………………………….. 48

4. Analisi del problema …………………………………………………………………… 49

- descrizione 49

- vincoli imposti 49

- difficoltà intrinseche 50

5. Analisi dell’algoritmo di risoluzione ideato …………………………………… 52

- introduzione 52

- come si è pensato di risolvere il problema 53

- scenario su cui ci si muove 54

- informazioni presenti 55

1. nel singolo nodo della rete 55

2. nella capsula spia (esploratrice) 59

3. nel quartier generale 62

- Algoritmo 66

A. strategie di esplorazione 66

B. gestione del quartier generale 69

III Osservazioni conclusive ……………………………………….………………….. 70

6. Osservazioni conclusive ………………………………………………………………… 71

A. Osservazioni sulla rete attiva PLANet 71

1. possibilità di scrivere routines di servizio 72

2. impossibilità di scambiare risorse tra capsule 72

3. poco flessibile gestione della trasmissione sicura dei pacchetti73

B. Osservazioni sul linguaggio di programmazione PLAN 74

- dati residenti 74

- dichiarazione di tipi complessi 75

- costrutti di loop 76

1. scorrimento condizionato di una lista 77

2. ciclo di attesa di un evento 77

C. Osservazioni sul progetto software realizzato – Sviluppi futuri 78

- mutua esclusione 79

- spreco di risorse 79

Appendici A. Prova sperimentale ………………………………………….. 82

B. Codice ………………..………………………..………………… 87

Riferimenti bibliografici ……………………………..………………………………………………