예제 #1
0
파일: control.go 프로젝트: hkwi/gopenflow
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()))
}
예제 #2
0
파일: obj.go 프로젝트: hkwi/gopenflow
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
	}
}
예제 #3
0
파일: main.go 프로젝트: hkwi/gopenflow
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)
}
예제 #4
0
파일: pipeline.go 프로젝트: hkwi/gopenflow
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
}
예제 #5
0
파일: main.go 프로젝트: hkwi/gopenflow
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]))
	}
}
예제 #6
0
파일: control.go 프로젝트: hkwi/gopenflow
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()))
}