Beispiel #1
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
}
Beispiel #2
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
}
Beispiel #3
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
}
Beispiel #4
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])
		}
	}
}
Beispiel #5
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)
}
Beispiel #6
0
func (p Poller) Rcv(msg bh.Msg, ctx bh.RcvContext) error {
	dict := ctx.Dict(driversDict)

	var nds []nodeDrivers
	dict.ForEach(func(k string, v interface{}) bool {
		node := nom.UID(k)
		query := nom.FlowStatsQuery{
			Node: node,
		}
		sendToMaster(query, node, ctx)

		nd := v.(nodeDrivers)
		updated := false
		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++
			updated = true
		}

		if updated {
			nds = append(nds, nd)
		}

		return true
	})

	for _, nd := range nds {
		if err := dict.Put(string(nd.Node.ID), nd); err != nil {
			glog.Warningf("error in encoding drivers: %v", err)
		}
	}
	return nil
}
Beispiel #7
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
}
Beispiel #8
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
}
Beispiel #9
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
}