func (b GraphBuilderCentralized) Rcv(msg bh.Msg, ctx bh.RcvContext) error { dict := ctx.Dict(GraphDict) var link nom.Link switch dm := msg.Data().(type) { case nom.LinkAdded: link = nom.Link(dm) case nom.LinkDeleted: link = nom.Link(dm) default: return fmt.Errorf("GraphBuilderCentralized: unsupported message type %v", msg.Type()) } nf, _ := nom.ParsePortUID(link.From) nt, _ := nom.ParsePortUID(link.To) if nf == nt { return fmt.Errorf("%v is a loop", link) } k := string(nf) links := make(map[nom.UID][]nom.Link) if v, err := dict.Get(k); err == nil { links = v.(map[nom.UID][]nom.Link) } links[nt.UID()] = append(links[nt.UID()], link) return dict.Put(k, links) }
func decodeLLDP(b []byte) (nom.Node, nom.Port, error) { h := lldp.NewLinkDiscoveryProtocolWithBuf(b) size := h.Size() tlvb := b[size:] chTLV := lldp.NewChassisMacTLVWithBuf(tlvb) if chTLV.Size() == 0 { return nom.Node{}, nom.Port{}, errors.New("decodeLLDP: no chassis id") } n := nom.Node{ MACAddr: chTLV.MacAddr(), } size += chTLV.Size() tlvb = b[size:] pTLV := lldp.NewLinkDiscoveryTLVWithBuf(tlvb) if pTLV.Size() == 0 || pTLV.Type() != uint8(lldp.TLV_PORT_ID) { return nom.Node{}, nom.Port{}, errors.New("decodeLLDP: no port id") } v := pTLV.Value() if v[0] != uint8(lldp.PORT_TLV_IFACE_NAME) { return nom.Node{}, nom.Port{}, errors.New("decodeLLDP: no port iface name") } portUID := nom.UID(v[1:]) nID, pID := nom.ParsePortUID(portUID) n.ID = nID return n, nom.Port{ID: pID, Node: n.UID()}, nil }
func allPaths(from, to nom.UID, visited map[nom.UID]distAndLinks) ( [][]nom.Link, int) { if from == to { return nil, 0 } todl, ok := visited[to] if !ok { return nil, -1 } var paths [][]nom.Link for _, l := range todl.BackLinks { lfn, _ := nom.ParsePortUID(l.From) prevpaths, _ := allPaths(from, nom.UID(lfn), visited) if len(prevpaths) == 0 { paths = append(paths, []nom.Link{l}) continue } for _, p := range prevpaths { paths = append(paths, append(p, l)) } } return paths, todl.Dist }
// ShortestPathCentralized calculates the shortest path from node "from" to node // "to" according to the state stored in GraphDict by the // GraphBuilderCentralized. // // This method is not go-routine safe and must be called within a handler of the // application that uses the GraphBuilderCentralized as a handler. Otherwise, // the user needs to synchronize the two. func ShortestPathCentralized(from, to nom.UID, ctx bh.RcvContext) ( paths [][]nom.Link, length int) { if from == to { return nil, 0 } visited := make(map[nom.UID]distAndLinks) visited[from] = distAndLinks{Dist: 0} pq := nodeAndDistSlice{{Dist: 0, Node: from}} heap.Init(&pq) dict := ctx.Dict(GraphDict) for len(pq) != 0 { nd := heap.Pop(&pq).(nodeAndDist) if nd.Node == to { continue } nodeLinks := make(map[nom.UID][]nom.Link) if v, err := dict.Get(string(nd.Node)); err == nil { nodeLinks = v.(map[nom.UID][]nom.Link) } nd.Dist = visited[nd.Node].Dist for _, links := range nodeLinks { for _, l := range links { nid, _ := nom.ParsePortUID(l.To) ton := nom.UID(nid) if dl, ok := visited[ton]; ok { switch { case nd.Dist+1 < dl.Dist: glog.Fatalf("invalid distance in BFS") case nd.Dist+1 == dl.Dist: dl.BackLinks = append(dl.BackLinks, l) visited[ton] = dl } continue } visited[ton] = distAndLinks{ Dist: nd.Dist + 1, BackLinks: []nom.Link{l}, } ndto := nodeAndDist{ Dist: nd.Dist + 1, Node: ton, } heap.Push(&pq, ndto) } } } return allPaths(from, to, visited) }
func forwardNodes(actions []nom.Action) (nodeToPorts map[nom.UID][]nom.UID) { nodeToPorts = make(map[nom.UID][]nom.UID) for _, a := range actions { switch f := a.(type) { case nom.ActionForward: for _, p := range f.Ports { fnid, _ := nom.ParsePortUID(p) ports := nodeToPorts[fnid.UID()] ports = append(ports, p) nodeToPorts[fnid.UID()] = ports } } } return nodeToPorts }
func (b GraphBuilderCentralized) Map(msg bh.Msg, ctx bh.MapContext) bh.MappedCells { var from nom.UID switch dm := msg.Data().(type) { case nom.LinkAdded: from = dm.From case nom.LinkDeleted: from = dm.From default: return nil } // TODO(soheil): maybe store and update the matrix directly here. n, _ := nom.ParsePortUID(from) return bh.MappedCells{{GraphDict, string(n)}} }
func (h *newLinkHandler) Rcv(msg bh.Msg, ctx bh.RcvContext) error { l := nom.Link(msg.Data().(NewLink)) n, _ := nom.ParsePortUID(l.From) d := ctx.Dict(nodeDict) k := string(n) v, err := d.Get(k) if err != nil { return err } np := v.(nodePortsAndLinks) if oldl, ok := np.linkFrom(l.From); ok { if oldl.UID() == l.UID() { return nil } np.removeLink(oldl) ctx.Emit(nom.LinkDeleted(oldl)) } glog.V(2).Infof("Link detected %v", l) ctx.Emit(nom.LinkAdded(l)) np.L = append(np.L, l) return d.Put(k, np) }
func (h *newLinkHandler) Map(msg bh.Msg, ctx bh.MapContext) bh.MappedCells { n, _ := nom.ParsePortUID(msg.Data().(NewLink).From) return bh.MappedCells{{nodeDict, string(n)}} }