func (c *Controller) handleConnection(conn *net.TCPConn) { stream := NewMessageStream(conn) stream.Outbound <- ofp10.NewHello() for { select { //case stream.Outbound <- ofp10.NewHello(): // Send hello message with latest protocol version. case msg := <-stream.Inbound: switch m := msg.(type) { // A Hello message of the appropriate type // completes version negotiation. If version // types are incompatable, it is possible the // connection may be servered without error. case *ofp10.Header: if m.Version == ofp10.VERSION { // Version negotiation is // considered complete. Create // new Switch and notifiy listening // applications. stream.Version = m.Version stream.Outbound <- ofp10.NewFeaturesRequest() } else { // Connection should be severed if controller // doesn't support switch version. stream.Shutdown <- true } // After a vaild FeaturesReply has been received we // have all the information we need. Create a new // switch object and notify applications. case *ofp10.SwitchFeatures: NewSwitch(stream, *m) for _, newInstance := range Applications { if sw, ok := Switch(m.DPID); ok { i := newInstance() sw.AddInstance(i) } } return // An error message may indicate a version mismatch. We // disconnect if an error occurs this early. case *ofp10.ErrorMsg: log.Println(m) stream.Version = m.Header.Version stream.Shutdown <- true } case err := <-stream.Error: // The connection has been shutdown. log.Println(err) return case <-time.After(time.Second * 3): // This shouldn't happen. If it does, both the controller // and switch are no longer communicating. The TCPConn is // still established though. log.Println("Connection timed out.") return } } }
/* Builds and populates Switch struct then starts listening for OpenFlow messages on conn. */ func NewOpenFlowSwitch(conn *net.TCPConn) { if _, err := conn.ReadFrom(ofp10.NewHello()); err != nil { log.Println("ERROR::Switch.SendSync::ReadFrom:", err) conn.Close() } buf := make([]byte, 1500) n, _ := conn.Read(buf) res := ofp10.NewHello() res.Write(buf[:n]) if _, err := conn.ReadFrom(ofp10.NewFeaturesRequest()); err != nil { log.Println("ERROR::Switch.SendSync::ReadFrom:", err) conn.Close() } buf2 := make([]byte, 1500) fres := ofp10.NewFeaturesReply() n, _ = conn.Read(buf2) fres.Write(buf2[:n]) if sw, ok := Switches[fres.DPID.String()]; ok { log.Println("Recovered connection from:", sw.DPID) sw.conn = *conn go sw.SendSync() go sw.Receive() } else { log.Printf("Openflow 1.%d Connection: %s", res.Version-1, fres.DPID.String()) s := new(Switch) s.conn = *conn s.DPID = fres.DPID s.Ports = make(map[int]ofp10.OfpPhyPort) s.requests = make(map[uint32]chan ofp10.OfpMsg) for _, p := range fres.Ports { s.Ports[int(p.PortNo)] = p } go s.SendSync() go s.Receive() Switches[s.DPID.String()] = s } }