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 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 }
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 TestAddP2PPath(t *testing.T) { ctx := buildTopologyForTest() p := addHandler{} msg := &bh.MockMsg{ MsgData: nom.AddPath{}, } err := p.Rcv(msg, ctx) if err == nil { t.Error("no error on invalid path") } msg.MsgData = nom.AddPath{ Path: nom.Path{ Pathlets: []nom.Pathlet{ { Match: nom.Match{ Fields: []nom.Field{ nom.InPort("n1$$0"), }, }, Actions: []nom.Action{ nom.ActionForward{ Ports: []nom.UID{"n6$$3"}, }, }, }, }, Priority: 1, }, } if err := p.Rcv(msg, ctx); err != nil { t.Errorf("cannot install flows for path: %v", err) } if len(ctx.CtxMsgs) == 0 { t.Error("no flows installed") } iports := []nom.UID{"n1$$0", "n2$$1", "n4$$1", "n6$$1"} oports := []nom.UID{"n1$$1", "n2$$2", "n4$$2", "n6$$3"} for i, msg := range ctx.CtxMsgs { add := msg.Data().(nom.AddFlowEntry) if add.Flow.Priority != 1 { t.Errorf("invalid flow priority: actual=%v want=1", add.Flow.Priority) } iport, ok := add.Flow.Match.InPort() if !ok { t.Errorf("flow #%v has no in ports", i) } else if nom.UID(iport) != iports[i] { t.Errorf("invalid input port on flow #%v: actual=%v want=%v", i, iport, iports[i]) } oport := add.Flow.Actions[0].(nom.ActionForward).Ports[0] if oport != oports[i] { t.Errorf("invalid output port on flow #%v: actual=%v want=%v", i, oport, oports[i]) } } }
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 }
// 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 (r LoadBalancer) Rcv(msg bh.Msg, ctx bh.RcvContext) error { switch dm := msg.Data().(type) { case setup: return registerEndhosts2(ctx) case nom.LinkAdded: link := InterAreaLink(dm) ctx.Emit(link) return r.GraphBuilderCentralized.Rcv(msg, ctx) case nom.LinkDeleted: return r.GraphBuilderCentralized.Rcv(msg, ctx) default: in := msg.Data().(nom.PacketIn) src := in.Packet.SrcMAC() dst := in.Packet.DstMAC() d := ctx.Dict(mac2port) load_dict := ctx.Dict(load_on_nodes) if dst.IsLLDP() { return nil } // FIXME: Hardcoding the hardware address at the moment srck := src.Key() if dst.IsBroadcast() || dst.IsMulticast() { fmt.Printf("Load Balancer: Received Broadcast or Multicast from %v\n", src) return nil } sn := in.Node dstk := dst.Key() dst_port, dst_err := d.Get(dstk) if dst_err != nil { fmt.Printf("Load Balancer: Cant find dest node %v\n", dstk) res, query_err := ctx.Sync(context.TODO(), InterAreaQuery{Src: srck, Dst: dstk}) if query_err != nil { fmt.Printf("Load Balancer: received error when querying! %v\n", query_err) } fmt.Printf("Load Balancer: received response succesfully - %v\n", res) dst_port = res.(nom.UID) } dn, _ := nom.ParsePortUID(dst_port.(nom.UID)) p := dst_port.(nom.UID) if sn != nom.UID(dn) { paths, _ := discovery.ShortestPathCentralized(sn, nom.UID(dn), ctx) opt_path := paths[0] min_load := calculate_load(ctx, paths[0]) for _, path := range paths[1:] { load := calculate_load(ctx, path) if load < min_load { opt_path = path min_load = load } } fmt.Printf("Load Balancer: Routing flow from %v to %v - %v, %v\n", sn, nom.UID(dn), opt_path, len(opt_path)) p = opt_path[0].From } // Forward flow entry add_forward := nom.AddFlowEntry{ Flow: nom.FlowEntry{ Node: in.Node, Match: nom.Match{ Fields: []nom.Field{ nom.EthDst{ Addr: dst, Mask: nom.MaskNoneMAC, }, }, }, Actions: []nom.Action{ nom.ActionForward{ Ports: []nom.UID{p}, }, }, }, } ctx.Reply(msg, add_forward) // Reverse flow entry add_reverse := nom.AddFlowEntry{ Flow: nom.FlowEntry{ Node: in.Node, Match: nom.Match{ Fields: []nom.Field{ nom.EthDst{ Addr: src, Mask: nom.MaskNoneMAC, }, }, }, Actions: []nom.Action{ nom.ActionForward{ Ports: []nom.UID{in.InPort}, }, }, }, } ctx.Reply(msg, add_reverse) // Updating the load on this node // FIXME: This is a naive approach, ideally should update when flowentry // is added/removed, but flowentry deleted is not implemented yet if load, err := load_dict.Get(string(in.Node)); err == nil { load_dict.Put(string(in.Node), load.(int)+1) } else { load_dict.Put(string(in.Node), 1) } out := nom.PacketOut{ Node: in.Node, InPort: in.InPort, BufferID: in.BufferID, Packet: in.Packet, Actions: []nom.Action{ nom.ActionForward{ Ports: []nom.UID{p}, }, }, } ctx.Reply(msg, out) } return nil }
func (r RouterM) Rcv(msg bh.Msg, ctx bh.RcvContext) error { switch dm := msg.Data().(type) { case area_setup: fmt.Printf("Adding to ctx: %v\n", ctx) d := ctx.Dict(cDict) d.Put("master", "master") return master_setup(ctx) case InterAreaLink: link := nom.Link(dm) nf, _ := nom.ParsePortUID(link.From) k := string(nf) nt, _ := nom.ParsePortUID(link.To) k2 := string(nt) d := ctx.Dict(node2area) nf_area, err := d.Get(k) nt_area, err2 := d.Get(k2) if err != nil || err2 != nil { fmt.Printf("Node does not belong to any existing areas! %v, %v, %v\n", err, err2, ctx) return nil } if nf_area != nt_area { link.From = nom.UID(nf_area.(string) + "$$" + strings.Replace(string(link.From), "$$", tmpD, 1)) link.To = nom.UID(nt_area.(string) + "$$" + strings.Replace(string(link.To), "$$", tmpD, 1)) fmt.Printf("Received Links from different areas, building graphs for %v, %v\n", link.From, link.To) ctx.Emit(nom.LinkAdded(link)) } return nil case InterAreaQuery: query := msg.Data().(InterAreaQuery) srck := query.Src dstk := query.Dst d := ctx.Dict(mac2area) src_area, src_err := d.Get(srck) dst_area, dst_err := d.Get(dstk) if src_err != nil || dst_err != nil { fmt.Printf("Error retriving area info: %v, %v\n", src_err, dst_err) return nil } paths, shortest_len := discovery.ShortestPathCentralized(nom.UID(src_area.(string)), nom.UID(dst_area.(string)), ctx) if shortest_len <= 0 { fmt.Printf("No route exists between area %v and area %v\n", src_area, dst_area) return nil } fmt.Printf("Path between area %v and area %v returned %v\n", src_area, dst_area, paths) for _, path := range paths { if len(path) != shortest_len { continue } else { _, port := nom.ParsePortUID(path[0].From) port_conv := strings.Replace(string(port), tmpD, "$$", 1) fmt.Printf("Sending converted port: %v\n", port_conv) ctx.Reply(msg, nom.UID(port_conv)) break } } return nil case setupM: m := msg.Data().(setupM) return registerEndhostsAll(ctx, m.area) case nom.LinkAdded: // link := InterAreaLink(dm) cd := ctx.Dict(cDict) _, cerr := cd.Get("master") if cerr != nil { // ctx.Emit(link) return r.GraphBuilderCentralized.Rcv(msg, ctx) } else { link := nom.Link(dm) nf, _ := nom.ParsePortUID(link.From) k := string(nf) nt, _ := nom.ParsePortUID(link.To) k2 := string(nt) d := ctx.Dict(node2area) nf_area, err := d.Get(k) nt_area, err2 := d.Get(k2) if err != nil || err2 != nil { fmt.Printf("Node does not belong to any existing areas! %v, %v, %v\n", err, err2, ctx) return nil } if nf_area != nt_area { link.From = nom.UID(nf_area.(string) + "$$" + strings.Replace(string(link.From), "$$", tmpD, 1)) link.To = nom.UID(nt_area.(string) + "$$" + strings.Replace(string(link.To), "$$", tmpD, 1)) fmt.Printf("Received Links from different areas, building graphs for %v, %v\n", link.From, link.To) InterAreaLinkAdded(link, ctx) } } case nom.LinkDeleted: return r.GraphBuilderCentralized.Rcv(msg, ctx) default: in := msg.Data().(nom.PacketIn) src := in.Packet.SrcMAC() dst := in.Packet.DstMAC() d := ctx.Dict(mac2port) if dst.IsLLDP() { return nil } // FIXME: Hardcoding the hardware address at the moment srck := src.Key() _, src_err := d.Get(srck) if src_err != nil { fmt.Printf("Router: Error retrieving hosts %v\n", src) } if dst.IsBroadcast() || dst.IsMulticast() { fmt.Printf("Router: Received Broadcast or Multicast from %v\n", src) return nil } sn := in.Node dstk := dst.Key() dst_port, dst_err := d.Get(dstk) if dst_err != nil { fmt.Printf("Router: Cant find dest node %v\n", dstk) res, query_err := ctx.Sync(context.TODO(), InterAreaQuery{Src: srck, Dst: dstk}) if query_err != nil { fmt.Printf("Router: received error when querying! %v\n", query_err) } fmt.Printf("Router: received response succesfully - %v\n", res) dst_port = res.(nom.UID) } dn, _ := nom.ParsePortUID(dst_port.(nom.UID)) p := dst_port.(nom.UID) if sn != nom.UID(dn) { paths, shortest_len := discovery.ShortestPathCentralized(sn, nom.UID(dn), ctx) fmt.Printf("Router: Path between %v and %v returns %v, %v\n", sn, nom.UID(dn), paths, shortest_len) for _, path := range paths { if len(path) != shortest_len { continue } else { p = path[0].From break } } } // Forward flow entry add_forward := nom.AddFlowEntry{ Flow: nom.FlowEntry{ Node: in.Node, Match: nom.Match{ Fields: []nom.Field{ nom.EthDst{ Addr: dst, Mask: nom.MaskNoneMAC, }, }, }, Actions: []nom.Action{ nom.ActionForward{ Ports: []nom.UID{p}, }, }, }, } ctx.Reply(msg, add_forward) // Reverse flow entry add_reverse := nom.AddFlowEntry{ Flow: nom.FlowEntry{ Node: in.Node, Match: nom.Match{ Fields: []nom.Field{ nom.EthDst{ Addr: src, Mask: nom.MaskNoneMAC, }, }, }, Actions: []nom.Action{ nom.ActionForward{ Ports: []nom.UID{in.InPort}, }, }, }, } ctx.Reply(msg, add_reverse) out := nom.PacketOut{ Node: in.Node, InPort: in.InPort, BufferID: in.BufferID, Packet: in.Packet, Actions: []nom.Action{ nom.ActionForward{ Ports: []nom.UID{p}, }, }, } ctx.Reply(msg, out) } return nil }
func (m MasterController) Rcv(msg bh.Msg, ctx bh.RcvContext) error { switch dm := msg.Data().(type) { case area_setup: fmt.Printf("Adding to ctx: %v\n", ctx) return master_setup(ctx) case InterAreaLink: link := nom.Link(dm) nf, _ := nom.ParsePortUID(link.From) k := string(nf) nt, _ := nom.ParsePortUID(link.To) k2 := string(nt) d := ctx.Dict(node2area) nf_area, err := d.Get(k) nt_area, err2 := d.Get(k2) if err != nil || err2 != nil { fmt.Printf("Node does not belong to any existing areas! %v, %v, %v\n", err, err2, ctx) return nil } if nf_area != nt_area { link.From = nom.UID(nf_area.(string) + "$$" + strings.Replace(string(link.From), "$$", tmpDelimiter, 1)) link.To = nom.UID(nt_area.(string) + "$$" + strings.Replace(string(link.To), "$$", tmpDelimiter, 1)) fmt.Printf("Received Links from different areas, building graphs for %v, %v\n", link.From, link.To) ctx.Emit(nom.LinkAdded(link)) } return nil case nom.LinkAdded: return m.GraphBuilderCentralized.Rcv(msg, ctx) case InterAreaQuery: query := msg.Data().(InterAreaQuery) srck := query.Src dstk := query.Dst d := ctx.Dict(mac2area) src_area, src_err := d.Get(srck) dst_area, dst_err := d.Get(dstk) if src_err != nil || dst_err != nil { fmt.Printf("Error retriving area info: %v, %v\n", src_err, dst_err) return nil } paths, shortest_len := discovery.ShortestPathCentralized(nom.UID(src_area.(string)), nom.UID(dst_area.(string)), ctx) if shortest_len <= 0 { fmt.Printf("No route exists between area %v and area %v\n", src_area, dst_area) return nil } fmt.Printf("Path between area %v and area %v returned %v\n", src_area, dst_area, paths) for _, path := range paths { if len(path) != shortest_len { continue } else { _, port := nom.ParsePortUID(path[0].From) port_conv := strings.Replace(string(port), tmpDelimiter, "$$", 1) fmt.Printf("Sending converted port: %v\n", port_conv) ctx.Reply(msg, nom.UID(port_conv)) break } } return nil // case nom.LinkDeleted: // return r.GraphBuilderCentralized.Rcv(msg, ctx) // default: // in := msg.Data().(nom.PacketIn) // src := in.Packet.SrcMAC() // dst := in.Packet.DstMAC() // // d := ctx.Dict(mac2port) // // if dst.IsLLDP() { // return nil // } // // // FIXME: Hardcoding the hardware address at the moment // srck := src.Key() // _, src_err := d.Get(srck) // if src_err != nil { // fmt.Printf("Router: Error retrieving hosts %v\n", src) // } // // if dst.IsBroadcast() || dst.IsMulticast() { // fmt.Printf("Router: Received Broadcast or Multicast from %v\n", src) // return nil // } // // sn := in.Node // // dstk := dst.Key() // dst_port, dst_err := d.Get(dstk) // if dst_err != nil { // fmt.Printf("Router: Cant find dest node %v\n", dstk) // dst_port, _ = d.Get("default") // } // dn,_ := nom.ParsePortUID(dst_port.(nom.UID)) // p := dst_port.(nom.UID) // // if (sn != nom.UID(dn)){ // // paths, shortest_len := discovery.ShortestPathCentralized(sn, nom.UID(dn), ctx) // fmt.Printf("Router: Path between %v and %v returns %v, %v\n", sn, nom.UID(dn), paths, shortest_len) // // // if shortest_len == -1 { // // borderDict := ctx.Dict(border_node_dict) // // borderDict.ForEach(func(k string, v interface{}) bool{ // // node, _ := nom.ParsePortUID(v.(nom.UID)) // // paths, shortest_len = discovery.ShortestPathCentralized(sn, nom.UID(node), ctx) // // // // if shortest_len == 0{ // // p = v.(nom.UID) // // } // // // TODO: Find the shortest one // // return false // // }) // // } // fmt.Printf("Router: After adjustment length: %v\n", shortest_len) // for _, path := range paths { // if len(path) != shortest_len { // continue // } else { // // p = path[0].From // break // } // } // } // // if src_err == nil { // // // Forward flow entry // add_forward := nom.AddFlowEntry{ // Flow: nom.FlowEntry{ // Node: in.Node, // Match: nom.Match{ // Fields: []nom.Field{ // nom.EthDst{ // Addr: dst, // Mask: nom.MaskNoneMAC, // }, // }, // }, // Actions: []nom.Action{ // nom.ActionForward{ // Ports: []nom.UID{p}, // }, // }, // }, // } // ctx.Reply(msg, add_forward) // // } // // if dst_err == nil { // // // Reverse flow entry // add_reverse := nom.AddFlowEntry{ // Flow: nom.FlowEntry{ // Node: in.Node, // Match: nom.Match{ // Fields: []nom.Field{ // nom.EthDst{ // Addr: src, // Mask: nom.MaskNoneMAC, // }, // }, // }, // Actions: []nom.Action{ // nom.ActionForward{ // Ports: []nom.UID{in.InPort}, // }, // }, // }, // } // ctx.Reply(msg, add_reverse) // // } // // out := nom.PacketOut{ // Node: in.Node, // InPort: in.InPort, // BufferID: in.BufferID, // Packet: in.Packet, // Actions: []nom.Action{ // nom.ActionForward{ // Ports: []nom.UID{p}, // }, // }, // } // ctx.Reply(msg, out) } return nil }
func (d *of12Driver) ofMatch(m nom.Match) (of12.Match, error) { ofm := of12.NewOXMatch() for _, f := range m.Fields { switch f := f.(type) { case nom.InPort: p, ok := d.nomPorts[nom.UID(f)] if !ok { return of12.Match{}, fmt.Errorf("of12Driver: nom port not found %v", f) } off := of12.NewOxmInPort() off.SetInPort(p) ofm.AddFields(off.OxmField) case nom.EthDst: if f.Mask == nom.MaskNoneMAC { off := of12.NewOxmEthDst() off.SetMacAddr([6]byte(f.Addr)) ofm.AddFields(off.OxmField) } else { off := of12.NewOxmEthDstMasked() off.SetMacAddr([6]byte(f.Addr)) off.SetMask([6]byte(f.Mask)) ofm.AddFields(off.OxmField) } case nom.EthSrc: if f.Mask == nom.MaskNoneMAC { off := of12.NewOxmEthSrc() off.SetMacAddr([6]byte(f.Addr)) ofm.AddFields(off.OxmField) } else { off := of12.NewOxmEthSrcMasked() off.SetMacAddr([6]byte(f.Addr)) off.SetMask([6]byte(f.Mask)) ofm.AddFields(off.OxmField) } case nom.EthType: off := of12.NewOxmEthType() off.SetType(uint16(f)) ofm.AddFields(off.OxmField) case nom.IPProto: off := of12.NewOxmIpProto() off.SetProto(uint8(f)) ofm.AddFields(off.OxmField) case nom.IPv4Src: if f.Mask == nom.MaskNoneIPV4 { off := of12.NewOxmIpV4Src() off.SetAddr(f.Addr) ofm.AddFields(off.OxmField) } else { off := of12.NewOxmIpV4SrcMasked() off.SetAddr(f.Addr) off.SetMask(f.Mask) ofm.AddFields(off.OxmField) } case nom.IPv4Dst: if f.Mask == nom.MaskNoneIPV4 { off := of12.NewOxmIpV4Dst() off.SetAddr(f.Addr) ofm.AddFields(off.OxmField) } else { off := of12.NewOxmIpV4DstMasked() off.SetAddr(f.Addr) off.SetMask(f.Mask) ofm.AddFields(off.OxmField) } case nom.IPv6Src: if f.Mask == nom.MaskNoneIPV6 { off := of12.NewOxmIpV6Src() off.SetAddr(f.Addr) ofm.AddFields(off.OxmField) } else { off := of12.NewOxmIpV6SrcMasked() off.SetAddr(f.Addr) off.SetMask(f.Mask) ofm.AddFields(off.OxmField) } case nom.IPv6Dst: if f.Mask == nom.MaskNoneIPV6 { off := of12.NewOxmIpV6Dst() off.SetAddr(f.Addr) ofm.AddFields(off.OxmField) } else { off := of12.NewOxmIpV6DstMasked() off.SetAddr(f.Addr) off.SetMask(f.Mask) ofm.AddFields(off.OxmField) } case nom.TransportPortSrc: off := of12.NewOxmTcpSrc() off.SetPort(uint16(f)) ofm.AddFields(off.OxmField) case nom.TransportPortDst: off := of12.NewOxmTcpDst() off.SetPort(uint16(f)) ofm.AddFields(off.OxmField) default: return of12.Match{}, fmt.Errorf("of12Driver: %#v is not supported", f) } } return ofm.Match, nil }
func (d *of10Driver) ofMatch(m nom.Match) (of10.Match, error) { ofm := of10.NewMatch() w := of10.PFW_ALL for _, f := range m.Fields { switch f := f.(type) { case nom.InPort: p, ok := d.nomPorts[nom.UID(f)] if !ok { return of10.Match{}, fmt.Errorf("of10Driver: nom port not found %v", f) } ofm.SetInPort(p) w &= ^of10.PFW_IN_PORT case nom.EthDst: if f.Mask != nom.MaskNoneMAC { return of10.Match{}, fmt.Errorf("of10Driver: masked ethernet address is not supported") } ofm.SetDlDst([6]byte(f.Addr)) w &= ^of10.PFW_DL_DST case nom.EthSrc: if f.Mask != nom.MaskNoneMAC { return of10.Match{}, fmt.Errorf("of10Driver: masked ethernet address is not supported") } ofm.SetDlSrc([6]byte(f.Addr)) w &= ^of10.PFW_DL_SRC case nom.EthType: ofm.SetDlType(uint16(f)) w &= ^of10.PFW_DL_TYPE case nom.IPv4Src: w &= ^of10.PFW_NW_SRC_MASK ofm.SetNwSrc(f.Addr.Uint()) mask := f.Mask.PopCount() if mask == 32 { w |= of10.PFW_NW_SRC_MASK } else { w |= of10.FlowWildcards(mask << uint(of10.PFW_NW_SRC_SHIFT)) } case nom.IPv4Dst: w &= ^of10.PFW_NW_DST_MASK ofm.SetNwDst(f.Addr.Uint()) mask := f.Mask.PopCount() if mask == 32 { w |= of10.PFW_NW_DST_MASK } else { w |= of10.FlowWildcards(mask << uint(of10.PFW_NW_DST_SHIFT)) } case nom.TransportPortSrc: ofm.SetTpSrc(uint16(f)) w &= ^of10.PFW_TP_SRC case nom.TransportPortDst: ofm.SetTpDst(uint16(f)) w &= ^of10.PFW_TP_DST case nom.IPv6Src, nom.IPv6Dst: return of10.Match{}, fmt.Errorf("of10Driver: IPv6 not supported") } } ofm.SetWildcards(uint32(w)) return ofm, nil }
func (r Router) Rcv(msg bh.Msg, ctx bh.RcvContext) error { switch dm := msg.Data().(type) { case setup: return registerEndhosts(ctx) case nom.LinkAdded: link := InterAreaLink(dm) ctx.Emit(link) return r.GraphBuilderCentralized.Rcv(msg, ctx) case nom.LinkDeleted: return r.GraphBuilderCentralized.Rcv(msg, ctx) default: in := msg.Data().(nom.PacketIn) src := in.Packet.SrcMAC() dst := in.Packet.DstMAC() d := ctx.Dict(mac2port) if dst.IsLLDP() { return nil } // FIXME: Hardcoding the hardware address at the moment srck := src.Key() _, src_err := d.Get(srck) if src_err != nil { fmt.Printf("Router: Error retrieving hosts %v\n", src) } if dst.IsBroadcast() || dst.IsMulticast() { fmt.Printf("Router: Received Broadcast or Multicast from %v\n", src) return nil } sn := in.Node dstk := dst.Key() dst_port, dst_err := d.Get(dstk) if dst_err != nil { fmt.Printf("Router: Cant find dest node %v\n", dstk) res, query_err := ctx.Sync(context.TODO(), InterAreaQuery{Src: srck, Dst: dstk}) if query_err != nil { fmt.Printf("Router: received error when querying! %v\n", query_err) } fmt.Printf("Router: received response succesfully - %v\n", res) dst_port = res.(nom.UID) } dn, _ := nom.ParsePortUID(dst_port.(nom.UID)) p := dst_port.(nom.UID) if sn != nom.UID(dn) { paths, shortest_len := discovery.ShortestPathCentralized(sn, nom.UID(dn), ctx) fmt.Printf("Router: Path between %v and %v returns %v, %v\n", sn, nom.UID(dn), paths, shortest_len) for _, path := range paths { if len(path) != shortest_len { continue } else { p = path[0].From break } } } // Forward flow entry add_forward := nom.AddFlowEntry{ Flow: nom.FlowEntry{ Node: in.Node, Match: nom.Match{ Fields: []nom.Field{ nom.EthDst{ Addr: dst, Mask: nom.MaskNoneMAC, }, }, }, Actions: []nom.Action{ nom.ActionForward{ Ports: []nom.UID{p}, }, }, }, } ctx.Reply(msg, add_forward) // Reverse flow entry add_reverse := nom.AddFlowEntry{ Flow: nom.FlowEntry{ Node: in.Node, Match: nom.Match{ Fields: []nom.Field{ nom.EthDst{ Addr: src, Mask: nom.MaskNoneMAC, }, }, }, Actions: []nom.Action{ nom.ActionForward{ Ports: []nom.UID{in.InPort}, }, }, }, } ctx.Reply(msg, add_reverse) out := nom.PacketOut{ Node: in.Node, InPort: in.InPort, BufferID: in.BufferID, Packet: in.Packet, Actions: []nom.Action{ nom.ActionForward{ Ports: []nom.UID{p}, }, }, } ctx.Reply(msg, out) } return nil }
func genFlowsForPathlet(p nom.Pathlet, inport nom.UID, priority uint16, ctx bh.RcvContext) (flows []nom.FlowEntry, outports []nom.UID, err error) { fwdnps := forwardNodes(p.Actions) for _, ports := range fwdnps { outports = append(outports, ports...) } floodns := floodNodes(p.Actions) for n, p := range floodns { outports = append(outports, outPortsFromFloodNode(n, p, ctx)...) } port, matchHasPort := p.Match.InPort() if matchHasPort { if inport != nom.Nil && inport != nom.UID(port) { return nil, nil, fmt.Errorf("path: two different inports %v and %v", inport, port) } inport = nom.UID(port) } m := p.Match if inport != nom.Nil && !matchHasPort { m = p.Match.Clone() m.Fields = append(m.Fields, nom.InPort(inport)) } noinMatch := p.Match.Clone() for f := range m.Fields { if _, ok := m.Fields[f].(nom.InPort); ok { noinMatch.Fields = append(noinMatch.Fields[:f], m.Fields[f+1:]...) break } } nofwdActions := make([]nom.Action, 0, len(p.Actions)) for _, a := range p.Actions { switch a.(type) { case nom.ActionForward, nom.ActionFlood: continue default: nofwdActions = append(nofwdActions, a) } } var innodes []nom.UID if inport != nom.Nil { innodes = []nom.UID{nom.NodeFromPortUID(inport)} } else { innodes = discovery.NodesCentralized(ctx) } for _, inn := range innodes { for _, outp := range outports { outn := nom.NodeFromPortUID(outp) sps, l := discovery.ShortestPathCentralized(inn, outn, ctx) if l < 0 { // TODO(soheil): maybe just log this and continue installing other // flows. return nil, nil, fmt.Errorf("path: no path found from %v to %v", inport, outp) } if l == 0 { m := noinMatch.Clone() if inport != nom.Nil { m.Fields = append(m.Fields, nom.InPort(inport)) } flow := nom.FlowEntry{ Node: outn, Match: m, Actions: p.Actions, Priority: priority, } flows = append(flows, flow) continue } // TODO(soheil): maybe install multiple paths. lastInPort := inport for _, link := range sps[0] { m := noinMatch.Clone() if lastInPort != nom.Nil { m.Fields = append(m.Fields, nom.InPort(lastInPort)) } var a []nom.Action a = append(a, nofwdActions...) a = append(a, nom.ActionForward{Ports: []nom.UID{link.From}}) flow := nom.FlowEntry{ Node: nom.NodeFromPortUID(link.From), Match: m, Actions: a, Priority: priority, } flows = append(flows, flow) lastInPort = link.To } m := noinMatch.Clone() if lastInPort != nom.Nil { m.Fields = append(m.Fields, nom.InPort(lastInPort)) } flow := nom.FlowEntry{ Node: outn, Match: m, Actions: p.Actions, Priority: priority, } flows = append(flows, flow) } } return flows, outports, nil }