func floodNodes(actions []nom.Action) (nodes map[nom.UID]nom.UID) { fn := make(map[nom.UID]nom.UID) for _, a := range actions { switch f := a.(type) { case nom.ActionFlood: nid := nom.NodeFromPortUID(f.InPort) fn[nid] = f.InPort } } return fn }
func inPortsFromOutPorts(outport []nom.UID, ctx bh.RcvContext) ( inports []nom.UID) { nextoutport: for _, p := range outport { n := nom.NodeFromPortUID(p) for _, l := range discovery.LinksCentralized(n, ctx) { if l.From == p { inports = append(inports, p) continue nextoutport } } glog.Errorf("cannot find peer port for %v", p) } return inports }
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 }