func (self *ofmReply) putError(msg ofp4.ErrorMsg) { hdr := ofp4.Header(msg) if len(msg) == 12 { hdr = hdr.AppendData(self.req) } self.resps = append(self.resps, hdr.SetXid(self.req.Xid())) }
func Parse(data []byte) (encoding.BinaryMarshaler, error) { switch data[0] { default: return nil, &Error{1, 0} case 4: // Openflow 1.3 length := int(binary.BigEndian.Uint16(data[2:4])) return ofp4.Header(data[0:length]), nil } }
func readMsg(con io.Reader) ofp4.Header { buf := make([]byte, 8) if n, err := con.Read(buf); err != nil || n != 8 { panic("ofp header read error") } hdr := ofp4.Header(buf) if hdr.Version() != 4 { panic("ofp4 version error") } length := hdr.Length() if length != 8 { ext := make([]byte, length) copy(ext, buf) con.Read(ext[8:]) buf = ext } return ofp4.Header(buf) }
func (self *Pipeline) AddChannel(conn io.ReadWriteCloser) error { self.lock.Lock() defer self.lock.Unlock() ch := &channel{ Conn: conn, } // process hello ch.Notify(ofp4.MakeHello(ofp4.MakeHelloElemVersionbitmap([]uint32{uint32(1 << 4)}))) head := make([]byte, 4) if msg, err := readOfpMessage(conn, head); err != nil { return err } else if ofp4.Header(msg).Type() != ofp4.OFPT_HELLO { return fmt.Errorf("The first message must be HELLO") } else { satisfied := false for _, element := range ofp4.Hello(msg).Elements().Iter() { switch element.Type() { case ofp4.OFPHET_VERSIONBITMAP: bitmaps := ofp4.HelloElemVersionbitmap(element).Bitmaps() if len(bitmaps) > 0 && (bitmaps[0]&(1<<4) != 0) { satisfied = true } // ensure there be no bits higher than ofp4 for i, b := range bitmaps { if i == 0 && (b&0xFFFFFFE0) != 0 { satisfied = false } if i > 0 && b != 0 { satisfied = false } } } } if !satisfied && ofp4.Header(msg).Version() == 4 { satisfied = true } if !satisfied { err := ofp4.MakeErrorMsg( ofp4.OFPET_HELLO_FAILED, ofp4.OFPHFC_INCOMPATIBLE, ) ch.Response(ofp4.Header(err).SetXid(ofp4.Header(msg).Xid())) return err } } self.channels = append(self.channels, ch) worker := make(chan MapReducable) go MapReduce(worker, 4) go func() { defer close(worker) defer conn.Close() multipartCollect := make(map[uint32][][]byte) for { msg, err := readOfpMessage(conn, head) if err != nil { log.Print(err) break } reply := ofmReply{pipe: self, channel: ch, req: msg} switch ofp4.Header(msg).Type() { case ofp4.OFPT_ERROR: log.Print("got unexpected OFPT_ERROR") case ofp4.OFPT_ECHO_REQUEST: worker <- &ofmEcho{reply} case ofp4.OFPT_ECHO_REPLY: log.Print("got unexpected OFPT_ECHO_REPLY") case ofp4.OFPT_EXPERIMENTER: worker <- &ofmExperimenter{reply} case ofp4.OFPT_FEATURES_REQUEST: worker <- &ofmFeaturesRequest{reply} case ofp4.OFPT_GET_CONFIG_REQUEST: worker <- &ofmGetConfigRequest{reply} case ofp4.OFPT_SET_CONFIG: worker <- &ofmSetConfig{reply} case ofp4.OFPT_PACKET_OUT: worker <- &ofmPacketOut{ofmOutput{reply, nil}} case ofp4.OFPT_FLOW_MOD: worker <- &ofmFlowMod{ofmOutput{reply, nil}} case ofp4.OFPT_GROUP_MOD: worker <- &ofmGroupMod{reply} case ofp4.OFPT_PORT_MOD: worker <- &ofmPortMod{reply} case ofp4.OFPT_TABLE_MOD: worker <- &ofmTableMod{reply} case ofp4.OFPT_MULTIPART_REQUEST: xid := ofp4.Header(msg).Xid() req := ofp4.MultipartRequest(msg) multipartCollect[xid] = append(multipartCollect[xid], req.Body()) if req.Flags()&ofp4.OFPMPF_REQ_MORE == 0 { reqs := multipartCollect[xid] delete(multipartCollect, xid) mreply := ofmMulti{ ofmReply: reply, reqs: reqs, chunks: nil, } // capture switch req.Type() { case ofp4.OFPMP_DESC: worker <- &ofmMpDesc{mreply} case ofp4.OFPMP_TABLE: worker <- &ofmMpTable{mreply} case ofp4.OFPMP_GROUP_DESC: worker <- &ofmMpGroupDesc{mreply} case ofp4.OFPMP_GROUP_FEATURES: worker <- &ofmMpGroupFeatures{mreply} case ofp4.OFPMP_METER_FEATURES: worker <- &ofmMpMeterFeatures{mreply} case ofp4.OFPMP_PORT_DESC: worker <- &ofmMpPortDesc{mreply} case ofp4.OFPMP_FLOW: worker <- &ofmMpFlow{mreply} case ofp4.OFPMP_AGGREGATE: worker <- &ofmMpAggregate{mreply} case ofp4.OFPMP_PORT_STATS: worker <- &ofmMpPortStats{mreply} case ofp4.OFPMP_QUEUE: worker <- &ofmMpQueue{mreply} case ofp4.OFPMP_GROUP: worker <- &ofmMpGroup{mreply} case ofp4.OFPMP_METER: worker <- &ofmMpMeter{mreply} case ofp4.OFPMP_METER_CONFIG: worker <- &ofmMpMeterConfig{mreply} case ofp4.OFPMP_TABLE_FEATURES: worker <- &ofmMpTableFeatures{mreply} case ofp4.OFPMP_EXPERIMENTER: worker <- &ofmMpExperimenter{mreply} default: panic("unknown ofp_multipart_request.type") } } case ofp4.OFPT_BARRIER_REQUEST: for xid, _ := range multipartCollect { buf := ofp4.Header(make([]byte, 8)) buf.SetXid(xid) rep := ofmReply{pipe: self, channel: ch, req: buf} rep.createError(ofp4.OFPET_BAD_REQUEST, ofp4.OFPBRC_BAD_MULTIPART) worker <- &rep delete(multipartCollect, xid) } worker <- &ofmBarrierRequest{reply} case ofp4.OFPT_QUEUE_GET_CONFIG_REQUEST: worker <- &ofmQueueGetConfigRequest{reply} case ofp4.OFPT_ROLE_REQUEST: worker <- &ofmRoleRequest{reply} case ofp4.OFPT_GET_ASYNC_REQUEST: worker <- &ofmGetAsyncRequest{reply} case ofp4.OFPT_SET_ASYNC: worker <- &ofmSetAsync{reply} case ofp4.OFPT_METER_MOD: worker <- &ofmMeterMod{reply} default: fmt.Printf("unknown ofp_header.type %v\n", msg) return } } }() return nil }
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 *ofmReply) createError(ofpet uint16, code uint16) { self.resps = append(self.resps, ofp4.Header(ofp4.MakeErrorMsg(ofpet, code)).AppendData(self.req).SetXid(self.req.Xid())) }