예제 #1
0
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
}
예제 #2
0
// 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
}
예제 #3
0
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
}
예제 #4
0
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
}
예제 #5
0
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])
		}
	}
}
예제 #6
0
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
}
예제 #7
0
// 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)
}
예제 #8
0
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

}
예제 #9
0
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

}
예제 #10
0
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

}
예제 #11
0
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
}
예제 #12
0
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
}
예제 #13
0
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

}
예제 #14
0
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
}