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 nil } 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 (p Poller) Rcv(msg bh.Msg, ctx bh.RcvContext) error { dict := ctx.Dict(driversDict) dict.ForEach(func(k string, v interface{}) { node := nom.UID(k) query := nom.FlowStatsQuery{ Node: node, } sendToMaster(query, node, ctx) nd := v.(nodeDrivers) for i := range nd.Drivers { // TODO(soheil): remove the hardcoded value. if nd.Drivers[i].OutPings > MaxPings { ctx.SendToBee(nom.NodeDisconnected{ Node: nom.Node{ID: nom.NodeID(node)}, Driver: nd.Drivers[i].Driver, }, ctx.ID()) continue } ctx.SendToBee(nom.Ping{}, nd.Drivers[i].BeeID) nd.Drivers[i].OutPings++ } if err := dict.Put(k, nd); err != nil { glog.Warningf("error in encoding drivers: %v", err) } }) return nil }
// NodesCentralized returns the nodes with outgoing links so far. // // Note that this methods should be used only when the GraphBuilderCentralized // is in use. func NodesCentralized(ctx bh.RcvContext) (nodes []nom.UID) { ctx.Dict(GraphDict).ForEach(func(k string, v interface{}) bool { nodes = append(nodes, nom.UID(k)) return true }) return nodes }
func (h portStatusHandler) Rcv(msg bh.Msg, ctx bh.RcvContext) error { // FIXME(soheil): This implementation is very naive and cannot tolerate // faults. We need to first check if the driver is the mater, and then apply // the change. Otherwise, we need to enque this message for that driver and // make sure we apply the log to the port status data := msg.Data().(nom.PortStatusChanged) dict := ctx.Dict(driversDict) k := string(data.Port.Node) v, err := dict.Get(k) if err != nil { return fmt.Errorf("NOMController: node %v not found", data.Port.Node) } n := v.(nodeDrivers) if !n.isMaster(data.Driver) { glog.Warningf("NOMController: %v ignored, %v is not master, master is %v", data.Port, data.Driver, n.master()) return nil } if p, ok := n.Ports.GetPort(data.Port.UID()); ok { if p == data.Port { return fmt.Errorf("NOMController: duplicate port status change for %v", data.Port) } n.Ports.DelPort(p) } n.Ports.AddPort(data.Port) ctx.Emit(nom.PortUpdated(data.Port)) return nil }
func confirmFlowEntryForPath(flow nom.FlowEntry, ctx bh.RcvContext) error { d := ctx.Dict(dictPath) v, err := d.Get(flow.ID) if err != nil { return fmt.Errorf("path: flow not found: %v", err) } pf := v.(pathAndFlows) for i := range pf.Flows { if pf.Flows[i].Flow.Equals(flow) { if pf.Flows[i].Installed { return fmt.Errorf("%v is already installed", flow) } pf.Flows[i].Installed = true pf.Installed++ break } } if pf.Installed == len(pf.Flows) { ctx.SendToCell(nom.PathAdded{Path: pf.Path}, pf.Subscriber.App, pf.Subscriber.Cell()) } return d.Put(flow.ID, pf) }
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 (h HealthChecker) Rcv(msg bh.Msg, ctx bh.RcvContext) error { db := msg.From() dict := ctx.Dict(driversDict) dict.ForEach(func(k string, v interface{}) { nd := v.(nodeDrivers) updated := false for i := range nd.Drivers { if nd.Drivers[i].BeeID == db { nd.Drivers[i].LastSeen = time.Now() // TODO(soheil): Maybe if outpings was more than MaxPings we // should emit a connected message. nd.Drivers[i].OutPings-- updated = true } } if !updated { return } if err := dict.Put(k, nd); err != nil { glog.Warningf("error in encoding drivers: %v", err) } }) return nil }
func (h *hostConnectedHandler) Rcv(msg bh.Msg, ctx bh.RcvContext) error { host := msg.Data().(nom.HostConnected) dict := ctx.Dict(hostDict) _, err := dict.Get(host.MACAddr.String()) if err == nil { return nil } v, err := dict.Get("hsts") hsts := []nom.Host{} if err == nil { hsts = v.([]nom.Host) } hsts = append(hsts, nom.Host(host)) err = dict.Put(host.MACAddr.String(), host) if err != nil { glog.Errorf("Put %v in %s: %v", host, host.MACAddr.String(), err) return err } err = dict.Put("hsts", hsts) if err != nil { glog.Errorf("Put %v in hsts: %v", hsts, err) return err } ctx.Emit(nom.HostJoined(host)) return nil }
// The bee hander func BeeHandler( beehiveMessage beehive.Msg, beeContext beehive.RcvContext) error { // beehiveMessage is an envelope around the Hello message. // You can retrieve the Hello, using msg.Data() and then // you need to assert that its a MessageToBee. message := beehiveMessage.Data().(MessageToBee) // Using ctx.Dict you can get (or create) a dictionary. dict := beeContext.Dict("beehive-app-dict") value, err := dict.Get(message.DestinationBee) logger.Trace.Printf("[BeeHandler] Message sent to bee with id (%s) \n", message.DestinationBee) count := 0 if err == nil { // No error mean there is already an item with given key count = value.(int) } count++ logger.Trace.Printf("[BeeHandler] Count = %d\n", count) logger.Trace.Printf("[BeeHandler] Calculate fib number %d\n", message.FibNumber) Fib(message.FibNumber) beeContext.Reply(beehiveMessage, count) return dict.Put(message.DestinationBee, count) }
func (h *httpHostListHandler) Rcv(msg bh.Msg, ctx bh.RcvContext) error { hrq := msg.Data().(http.HTTPRequest) if hrq.AppName == "host" && hrq.Verb == "list" { dict := ctx.Dict(hostDict) v, err := dict.Get("hsts") hsts := []nom.Host{} if err == nil { hsts = v.([]nom.Host) } data, err := json.Marshal(hsts) if err != nil { glog.Errorf("Host list JSON marshaling: %v", err) return err } fmt.Println(hsts) hrs := http.HTTPResponse{ AppName: "host", Data: data, } err = ctx.Reply(msg, hrs) if err != nil { glog.Errorf("Replay error: %v", err) return err } } return nil }
func (h AckHandler) Rcv(msg beehive.Msg, ctx beehive.RcvContext) error { ack := msg.Data().(Ack) acked := Acked{ ID: ack.ID, Queue: ack.Queue, TaskID: ack.TaskID, } key := ack.TaskID.String() ddict := ctx.Dict(dequed) if err := ddict.Del(key); err == nil { ctx.Reply(msg, acked) return nil } // The task might have been moved from dequed to out of order, because of a // timeout. So, we need to search the active dictionary as well. odict := ctx.Dict(ooo) if err := odict.Del(key); err == nil { ctx.Reply(msg, acked) return nil } return ErrNoSuchTask }
// Rcvf receives the message and the context. func Rcvf(msg beehive.Msg, ctx beehive.RcvContext) error { // msg is an envelope around the Hello message. // You can retrieve the Hello, using msg.Data() and then // you need to assert that its a Hello. hello := msg.Data().(Hello) // Using ctx.Dict you can get (or create) a dictionary. dict := ctx.Dict("hello_dict") // Using Get(), you can get the value associated with // a key in the dictionary. Keys are always string // and values are generic interface{}'s. v, err := dict.Get(hello.Name) // If there is an error, the entry is not in the // dictionary. Otherwise, we set cnt based on // the value we already have in the dictionary // for that name. cnt := 0 if err == nil { cnt = v.(int) } // Now we increment the count. cnt++ // And then we print the hello message. ctx.Printf("hello %s (%d)!\n", hello.Name, cnt) // Finally we update the count stored in the dictionary. return dict.Put(hello.Name, cnt) }
func (h EnQHandler) Rcv(msg beehive.Msg, ctx beehive.RcvContext) error { enq := msg.Data().(Enque) dict := ctx.Dict(active) next := TaskID(1) if v, err := dict.Get("_next_"); err == nil { next = v.(TaskID) } key := next.String() task := Task{ Queue: enq.Queue, ID: next, Body: enq.Body, } if err := dict.Put(key, task); err != nil { return err } if err := dict.Put("_next_", next+1); err != nil { return err } enqued := Enqued{ ID: enq.ID, Queue: enq.Queue, TaskID: next, } return ctx.Reply(msg, enqued) }
func (c *Collector) Rcv(m beehive.Msg, ctx beehive.RcvContext) error { res := m.Data().(StatResult) glog.V(2).Infof("Stat results: %+v", res) matrix := ctx.Dict(matrixDict) key := res.Switch.Key() v, err := matrix.Get(key) if err != nil { return fmt.Errorf("No such switch in matrix: %+v", res) } c.poller.query <- StatQuery{res.Switch} sw := v.(SwitchStats) stat, ok := sw[res.Flow] sw[res.Flow] = res.Bytes glog.V(2).Infof("Previous stats: %+v, Now: %+v", stat, res.Bytes) if !ok || res.Bytes-stat > c.delta { glog.Infof("Found an elephent flow: %+v, %+v, %+v", res, stat, ctx.Hive().ID()) ctx.Emit(MatrixUpdate(res)) } matrix.Put(key, sw) return nil }
func addFlowEntriesForPath(sub bh.AppCellKey, path nom.Path, flows []nom.FlowEntry, ctx bh.RcvContext) { fs := make([]flowAndStatus, 0, len(flows)) path.ID = strconv.FormatUint(reservePathID(ctx), 16) for i := range flows { flows[i].ID = path.ID fs = append(fs, flowAndStatus{Flow: flows[i]}) } pf := pathAndFlows{ Subscriber: sub, Path: path, Flows: fs, Timestamp: time.Now(), } d := ctx.Dict(dictPath) if err := d.Put(path.ID, pf); err != nil { glog.Fatalf("error in storing path entry: %v", err) } ack := centralizedAppCellKey(ctx.App()) for _, f := range flows { addf := nom.AddFlowEntry{ Flow: f, Subscriber: ack, } ctx.Emit(addf) } }
func (r Router) neighbors(node Node, ctx bh.RcvContext) Edges { dict := ctx.Dict(neighDict) var neighs Edges if v, err := dict.Get(node.Key()); err == nil { neighs = v.(Edges) } return neighs }
func (p Poller) Rcv(msg bh.Msg, ctx bh.RcvContext) error { ctx.Dict("Switches").ForEach(func(k string, v interface{}) { fmt.Printf("poller: polling switch %v\n", k) ctx.Emit(nom.FlowStatsQuery{ Node: nom.UID(k), }) }) return nil }
func (r Router) appendNieghbor(edge Edge, ctx bh.RcvContext) error { neighs := r.neighbors(edge.To, ctx) if neighs.Contains(edge) { return fmt.Errorf("%v is already a neighbor", edge) } neighs = append(neighs, edge) ctx.Dict(neighDict).Put(edge.To.Key(), neighs) return nil }
func (h *nodeLeftHandler) Rcv(msg bh.Msg, ctx bh.RcvContext) error { n := nom.Node(msg.Data().(nom.NodeLeft)) d := ctx.Dict(nodeDict) k := string(n.UID()) if _, err := d.Get(k); err != nil { return fmt.Errorf("%v is not joined", n) } d.Del(k) return nil }
func reservePathID(ctx bh.RcvContext) uint64 { d := ctx.Dict(dictID) var id uint64 if v, err := d.Get("path"); err == nil { id = v.(uint64) } id++ d.Put("path", id) return id - 1 }
func reserveFlowID(ctx bh.RcvContext, cnt int) uint64 { d := ctx.Dict(dictID) var id uint64 if v, err := d.Get("flow"); err == nil { id = v.(uint64) } id += uint64(cnt) d.Put("flow", id) return id - uint64(cnt) }
func (r Router) routingTable(from Node, ctx bh.RcvContext) RoutingTable { dict := ctx.Dict(routeDict) var tbl RoutingTable if v, err := dict.Get(from.Key()); err == nil { tbl = v.(RoutingTable) } else { tbl = make(RoutingTable) } return tbl }
func (h *timeoutHandler) Rcv(msg bh.Msg, ctx bh.RcvContext) error { d := ctx.Dict(nodeDict) d.ForEach(func(k string, v interface{}) { np := v.(nodePortsAndLinks) for _, p := range np.P { sendLLDPPacket(np.N, p, ctx) } }) return nil }
func (h addTriggerHandler) Rcv(msg bh.Msg, ctx bh.RcvContext) error { add := msg.Data().(nom.AddTrigger) dict := ctx.Dict(triggersDict) var nt nodeTriggers if v, err := dict.Get(string(add.Node)); err == nil { nt = v.(nodeTriggers) } nt.maybeAddTrigger(nom.Trigger(add)) return dict.Put(string(add.Node), nt) }
func (h delTriggerHandler) Rcv(msg bh.Msg, ctx bh.RcvContext) error { del := msg.Data().(nom.DelTrigger) var nt nodeTriggers dict := ctx.Dict(triggersDict) if v, err := dict.Get(string(del.Node)); err == nil { nt = v.(nodeTriggers) } nt.delTrigger(nom.Trigger(del)) return dict.Put(string(del.Node), nt) }
func (p *pinger) Rcv(msg bh.Msg, ctx bh.RcvContext) error { dict := ctx.Dict(PingPongDict) data := msg.Data() switch data := data.(type) { case ping: fmt.Printf("Rx Ping %d %v->%v\n", data.Seq, msg.From(), ctx.ID()) time.Sleep(300 * time.Millisecond) v, err := dict.Get("ping") var p ping if err == nil { p = v.(ping) } if data != p { return fmt.Errorf("Invalid ping: ping=%d, want=%d", data.Seq, p.Seq) } p.Seq += 1 dict.Put("ping", p) fmt.Printf("Ping stored to %v\n", p.Seq) if !msg.NoReply() { fmt.Printf("Tx Pong %d @ %v\n", data.pong().Seq, ctx.ID()) ctx.Emit(data.pong()) } case pong: fmt.Printf("Rx Pong %d %v->%v\n", data.Seq, msg.From(), ctx.ID()) time.Sleep(300 * time.Millisecond) dict := ctx.Dict(PingPongDict) v, err := dict.Get("pong") var p pong if err == nil { p = v.(pong) } if data != p { return fmt.Errorf("Invalid pong: pong=%d, want=%d", data.Seq, p.Seq) } p.Seq += 1 dict.Put("pong", p) fmt.Printf("Pong stored to %v\n", p.Seq) fmt.Printf("Tx Ping %d @ %v\n", data.ping().Seq, ctx.ID()) ctx.Emit(data.ping()) } return nil }
// doDequeTask adds a task to the dequed dictionary and replys to the message. func doDequeTask(msg beehive.Msg, ctx beehive.RcvContext, t Task) error { ctx.Reply(msg, Dequed{ ID: msg.Data().(Deque).ID, Task: t, }) ddict := ctx.Dict(dequed) return ddict.Put(t.ID.String(), dqTask{ Task: t, DequeTime: time.Now(), }) }
// 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 (h *timeoutHandler) Rcv(msg bh.Msg, ctx bh.RcvContext) error { fmt.Println("LLDP .. ?! Timeout") d := ctx.Dict(nodeDict) d.ForEach(func(k string, v interface{}) bool { np := v.(nodePortsAndLinks) fmt.Println(np) for _, p := range np.P { sendLLDPPacket(np.N, p, ctx) } return true }) return nil }
func rcvf(msg bh.Msg, ctx bh.RcvContext) error { name := msg.Data().(string) cnt := 0 if v, err := ctx.Dict(helloDict).Get(name); err == nil { cnt = v.(int) } cnt++ ctx.Printf("hello %s (%d)!\n", name, cnt) ctx.Dict(helloDict).Put(name, cnt) return nil }