func main() { flag.Parse() args := flag.Args() getConn := func(spec string) io.ReadWriter { p := strings.SplitN(spec, ":", 2) if len(p) == 1 { panic(fmt.Sprintf("connection scheme failure %s", args[0])) } else if c, err := net.Dial(p[0], p[1]); err != nil { panic(err) } else if n, err := c.Write([]byte(hello)); n != 8 || err != nil { panic("hello send error") } else if res, err := gopenflow.ReadMessage(c); err != nil { panic(err) } else if res[0] != 4 { panic("openflow version error") } else if ofp4.Header(res).Type() != ofp4.OFPT_HELLO { panic("hello recv error") } else { return c } } switch args[1] { case "dump-flows": con := getConn(args[0]) flowStatsReq := make([]byte, 32) flowStatsReq[0] = ofp4.OFPTT_ALL binary.BigEndian.PutUint32(flowStatsReq[4:], ofp4.OFPP_ANY) binary.BigEndian.PutUint32(flowStatsReq[8:], ofp4.OFPG_ANY) mphdr := make([]byte, 16) mphdr[0] = 4 mphdr[1] = ofp4.OFPT_MULTIPART_REQUEST binary.BigEndian.PutUint16(mphdr[8:], ofp4.OFPMP_FLOW) msg := append(mphdr, append(flowStatsReq, ofp4.MakeMatch(nil)...)...) binary.BigEndian.PutUint16(msg[2:], uint16(len(msg))) con.Write(msg) for { var seq ofp4.FlowStats if msg, err := gopenflow.ReadMessage(con); err != nil { panic(err) } else if ofp4.Header(msg).Type() != ofp4.OFPT_MULTIPART_REPLY { panic("multipart error") } else if mp := ofp4.MultipartReply(msg); mp.Type() != ofp4.OFPMP_FLOW { panic("flow_stats reply error") } else { seq = ofp4.FlowStats(mp.Body()) } var lines []string for _, stat := range seq.Iter() { lines = append(lines, fmt.Sprintf("%v pkts=%d bytes=%d dur=%d", stat, stat.PacketCount(), stat.ByteCount(), stat.DurationSec())) } sort.Sort(sort.Reverse(sort.StringSlice(lines))) for _, line := range lines { fmt.Print(line, "\n") } if binary.BigEndian.Uint16(mphdr[10:])&ofp4.OFPMPF_REPLY_MORE == 0 { break } } case "add-flow": flow := ofp4.FlowMod(make([]byte, 56)) if err := flow.Parse(args[2]); err != nil { panic(err) } else { con := getConn(args[0]) con.Write([]byte(flow)) con.Write([]byte(barrier)) if res, err := gopenflow.ReadMessage(con); err != nil { panic(err) } else if ofp4.Header(res).Type() == ofp4.OFPT_ERROR { log.Print("error") } } case "del-flows": flow := ofp4.FlowMod(make([]byte, 56)) flow[25] = ofp4.OFPFC_DELETE if err := flow.Parse(args[2]); err != nil { panic(err) } else { con := getConn(args[0]) con.Write([]byte(flow)) con.Write([]byte(barrier)) for { if res, err := gopenflow.ReadMessage(con); err != nil { panic(err) } else if ofp4.Header(res).Type() == ofp4.OFPT_BARRIER_REPLY { break } else { log.Print(res) } } } default: panic(fmt.Sprintf("unknown subcommand %s", args[1])) } }
func (self *ofmFlowMod) Map() Reducable { msg := ofp4.FlowMod(self.req) bufferId := msg.BufferId() switch msg.Command() { case ofp4.OFPFC_ADD: if err := self.pipe.addFlowEntry(msg); err != nil { if e, ok := err.(ofp4.ErrorMsg); ok { self.putError(e) } else { log.Print(err) } } case ofp4.OFPFC_MODIFY, ofp4.OFPFC_MODIFY_STRICT: reqMatch := match{} if err := reqMatch.UnmarshalBinary(msg.Match().OxmFields()); err != nil { log.Print(err) } else if msg.TableId() > ofp4.OFPTT_MAX { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_FLOW_MOD_FAILED, ofp4.OFPFMFC_BAD_TABLE_ID)) } else { filter := flowFilter{ cookie: msg.Cookie(), cookieMask: msg.CookieMask(), tableId: msg.TableId(), outPort: ofp4.OFPP_ANY, outGroup: ofp4.OFPG_ANY, match: reqMatch, } if msg.Command() == ofp4.OFPFC_MODIFY_STRICT { filter.priority = msg.Priority() filter.opStrict = true } for _, stat := range self.pipe.filterFlows(filter) { flow := stat.flow if err := func() error { flow.lock.Lock() defer flow.lock.Unlock() if msg.Flags()&ofp4.OFPFF_RESET_COUNTS != 0 { flow.packetCount = 0 flow.byteCount = 0 } return flow.importInstructions(msg.Instructions()) }(); err != nil { if e, ok := err.(ofp4.ErrorMsg); ok { self.putError(e) } else { log.Print(err) } } } } case ofp4.OFPFC_DELETE, ofp4.OFPFC_DELETE_STRICT: reqMatch := match{} if err := reqMatch.UnmarshalBinary(msg.Match().OxmFields()); err != nil { log.Print(err) } else { filter := flowFilter{ opUnregister: true, cookie: msg.Cookie(), cookieMask: msg.CookieMask(), tableId: msg.TableId(), outPort: msg.OutPort(), outGroup: msg.OutGroup(), match: reqMatch, } if msg.Command() == ofp4.OFPFC_DELETE_STRICT { filter.priority = msg.Priority() filter.opStrict = true } for _, stat := range self.pipe.filterFlows(filter) { if hdr, err := stat.flow.fields.MarshalBinary(); err != nil { log.Print(err) } else if portNo, act := hookDot11Action(oxm.Oxm(hdr)); portNo != 0 && len(act) != 0 { if port := self.pipe.getPort(portNo); port != nil { if err := port.Vendor(gopenflow.MgmtFrameRemove(act)).(error); err != nil { log.Print(err) } } } if stat.flow.flags&ofp4.OFPFF_SEND_FLOW_REM != 0 { self.pipe.sendFlowRem(stat.tableId, stat.priority, stat.flow, ofp4.OFPRR_DELETE) } } } bufferId = ofp4.OFP_NO_BUFFER // nothing to do with buffer by specification. } if bufferId != ofp4.OFP_NO_BUFFER { original, ok := func() (outputToPort, bool) { self.pipe.lock.Lock() defer self.pipe.lock.Unlock() original, ok := self.pipe.buffer[bufferId] if ok { delete(self.pipe.buffer, bufferId) } return original, ok }() if ok { pipe := self.pipe pipe.datapath <- &flowTask{ Frame: original.Frame, pipe: self.pipe, tableId: 0, } } else { self.putError(ofp4.MakeErrorMsg(ofp4.OFPET_BAD_REQUEST, ofp4.OFPBRC_BUFFER_UNKNOWN)) } } return self }