module routing sig IP {} -- sig Link {from, to: State ->! Router} sig Link {from: State ->! Router, to: State ->! Router} sig State {nexts: Router -> Router} sig Router {ip: IP, table: State -> IP ->? Link} fact { all r: Router, s: State { // router table refers only to router's links (r.table[s][IP].from)[s] = r // nexts are routers reachable in one step -- s.nexts[r] = {r': Router | some x: Link | x.from[s] = r && x.to[s] = r'} s.nexts[r] = (r.table[s][IP].to)[s] // router doesn't forward to itself no r.table[s][r.ip] } no disj r1, r2: Router | r1.ip = r2.ip } fun Consistent (s: State) { // table forwards on plausible link all r: Router, i: IP | (r.table[s][i].to)[s] in i.~ip.*~(s.nexts) } fun Propagate (s, s': State) { -- router may pass to its predecessor some of its table entries -- assume some OOB communication all r: Router | r.table[s'] in r.table[s] + r.~(s.nexts).table[s] } assert PropagationOK { all s, s': State | Consistent (s) && Propagate (s,s') => Consistent (s') } fun NoTopologyChange (s,s': State) { all x: Link { x.from[s] = x.from[s'] x.to[s] = x.to[s'] } } -- not true because routers can drop entries and not forward packets assert PropagationOK' { all s, s': State | Consistent (s) && Propagate (s,s') && NoTopologyChange (s,s') => Consistent (s') } check PropagationOK for 2 check PropagationOK' for 4 but 2 State run Propagate for 3 run Consistent assert Monotonic { all s, s': State | Consistent(s) && NoTopologyChange (s,s') && (all r: Router | r.table[s'] in r.table[s]) => Consistent (s') } check Monotonic for 4 but 2 State