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 (d *of10Driver) nomMatch(m of10.Match) (nom.Match, error) { nm := nom.Match{} wc := of10.FlowWildcards(m.Wildcards()) if wc&of10.PFW_IN_PORT == 0 { ofp := m.InPort() nomp, ok := d.ofPorts[ofp] if !ok { return nom.Match{}, fmt.Errorf("of10Driver: cannot find port %v", ofp) } nm.AddField(nom.InPort(nomp.UID())) } if wc&of10.PFW_DL_SRC == 0 { nm.AddField(nom.EthSrc{ Addr: m.DlSrc(), Mask: nom.MaskNoneMAC, }) } if wc&of10.PFW_DL_DST == 0 { nm.AddField(nom.EthDst{ Addr: m.DlDst(), Mask: nom.MaskNoneMAC, }) } if wc&of10.PFW_DL_TYPE == 0 { nm.AddField(nom.EthType(m.DlType())) } if wc&of10.PFW_NW_SRC_MASK != of10.PFW_NW_SRC_ALL && m.NwSrc() != 0 { mask := uint(wc&of10.PFW_NW_SRC_MASK) >> uint(of10.PFW_NW_SRC_SHIFT) nm.AddField(nom.IPv4Src(nom.CIDRToMaskedIPv4(m.NwSrc(), mask))) } if wc&of10.PFW_NW_DST_MASK != of10.PFW_NW_DST_ALL && m.NwDst() != 0 { mask := uint(wc&of10.PFW_NW_DST_MASK) >> uint(of10.PFW_NW_DST_SHIFT) nm.AddField(nom.IPv4Dst(nom.CIDRToMaskedIPv4(m.NwDst(), mask))) } if wc&of10.PFW_TP_SRC == 0 { nm.AddField(nom.TransportPortSrc(m.TpSrc())) } if wc&of10.PFW_TP_DST == 0 { nm.AddField(nom.TransportPortDst(m.TpDst())) } return nm, nil }
func (d *of12Driver) nomMatch(m of12.Match) (nom.Match, error) { nm := nom.Match{} if !of12.IsOXMatch(m) { return nm, fmt.Errorf("of12Driver: std math is not supported") } xm, err := of12.ToOXMatch(m) if err != nil { return nm, err } for _, f := range xm.Fields() { switch f.OxmField() { case uint8(of12.PXMT_IN_PORT): xf, err := of12.ToOxmInPort(f) if err != nil { return nom.Match{}, err } np, ok := d.ofPorts[xf.InPort()] if !ok { return nom.Match{}, fmt.Errorf("of12Driver: cannot find port %v", xf.InPort()) } nm.AddField(nom.InPort(np.UID())) case uint8(of12.PXMT_ETH_TYPE): xf, err := of12.ToOxmEthType(f) if err != nil { return nom.Match{}, err } nm.AddField(nom.EthType(xf.Type())) case uint8(of12.PXMT_ETH_SRC): xf, err := of12.ToOxmEthSrc(f) if err != nil { return nom.Match{}, err } nf := nom.EthSrc{} nf.Addr = xf.MacAddr() nf.Mask = nom.MaskNoneMAC nm.AddField(nf) case uint8(of12.PXMT_ETH_SRC_MASKED): xf, err := of12.ToOxmEthSrcMasked(f) if err != nil { return nom.Match{}, err } nf := nom.EthSrc{} nf.Addr = xf.MacAddr() nf.Mask = xf.Mask() nm.AddField(nf) case uint8(of12.PXMT_ETH_DST): xf, err := of12.ToOxmEthDst(f) if err != nil { return nom.Match{}, err } nf := nom.EthDst{} nf.Addr = xf.MacAddr() nf.Mask = nom.MaskNoneMAC nm.AddField(nf) case uint8(of12.PXMT_ETH_DST_MASKED): xf, err := of12.ToOxmEthDstMasked(f) if err != nil { return nom.Match{}, err } nf := nom.EthDst{} nf.Addr = xf.MacAddr() nf.Mask = xf.Mask() nm.AddField(nf) case uint8(of12.PXMT_IP_PROTO): xf, err := of12.ToOxmIpProto(f) if err != nil { return nom.Match{}, err } nm.AddField(nom.IPProto(xf.Proto())) case uint8(of12.PXMT_IPV4_SRC): xf, err := of12.ToOxmIpV4Src(f) if err != nil { return nom.Match{}, err } nf := nom.IPv4Src{} nf.Addr = nom.IPv4Addr(xf.Addr()) nf.Mask = nom.MaskNoneIPV4 nm.AddField(nf) case uint8(of12.PXMT_IPV4_SRC_MASKED): xf, err := of12.ToOxmIpV4SrcMasked(f) if err != nil { return nom.Match{}, err } nf := nom.IPv4Src{} nf.Addr = nom.IPv4Addr(xf.Addr()) nf.Mask = nom.IPv4Addr(xf.Mask()) nm.AddField(nf) case uint8(of12.PXMT_IPV4_DST): xf, err := of12.ToOxmIpV4Dst(f) if err != nil { return nom.Match{}, err } nf := nom.IPv4Dst{} nf.Addr = nom.IPv4Addr(xf.Addr()) nf.Mask = nom.MaskNoneIPV4 nm.AddField(nf) case uint8(of12.PXMT_IPV4_DST_MASKED): xf, err := of12.ToOxmIpV4DstMasked(f) if err != nil { return nom.Match{}, err } nf := nom.IPv4Dst{} nf.Addr = nom.IPv4Addr(xf.Addr()) nf.Mask = nom.IPv4Addr(xf.Mask()) nm.AddField(nf) case uint8(of12.PXMT_IPV6_SRC): xf, err := of12.ToOxmIpV6Src(f) if err != nil { return nom.Match{}, err } nf := nom.IPv6Src{} nf.Addr = nom.IPv6Addr(xf.Addr()) nf.Mask = nom.MaskNoneIPV6 nm.AddField(nf) case uint8(of12.PXMT_IPV6_SRC_MASKED): xf, err := of12.ToOxmIpV6SrcMasked(f) if err != nil { return nom.Match{}, err } nf := nom.IPv6Src{} nf.Addr = nom.IPv6Addr(xf.Addr()) nf.Mask = nom.IPv6Addr(xf.Mask()) nm.AddField(nf) case uint8(of12.PXMT_IPV6_DST): xf, err := of12.ToOxmIpV6Dst(f) if err != nil { return nom.Match{}, err } nf := nom.IPv6Dst{} nf.Addr = nom.IPv6Addr(xf.Addr()) nf.Mask = nom.MaskNoneIPV6 nm.AddField(nf) case uint8(of12.PXMT_IPV6_DST_MASKED): xf, err := of12.ToOxmIpV6DstMasked(f) if err != nil { return nom.Match{}, err } nf := nom.IPv6Dst{} nf.Addr = nom.IPv6Addr(xf.Addr()) nf.Mask = nom.IPv6Addr(xf.Mask()) nm.AddField(nf) case uint8(of12.PXMT_TCP_SRC): xf, err := of12.ToOxmTcpSrc(f) if err != nil { return nom.Match{}, err } nm.AddField(nom.TransportPortSrc(xf.Port())) case uint8(of12.PXMT_TCP_DST): xf, err := of12.ToOxmTcpDst(f) if err != nil { return nom.Match{}, err } nm.AddField(nom.TransportPortDst(xf.Port())) } } return nm, 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 }