// Handle openflow messages from the switch func (self *OFSwitch) handleMessages(dpid net.HardwareAddr, msg util.Message) { log.Debugf("Received message: %+v, on switch: %s", msg, dpid.String()) switch t := msg.(type) { case *common.Header: switch t.Header().Type { case openflow13.Type_Hello: // Send Hello response h, err := common.NewHello(4) if err != nil { log.Errorf("Error creating hello message") } self.Send(h) case openflow13.Type_EchoRequest: // Send echo reply res := openflow13.NewEchoReply() self.Send(res) case openflow13.Type_EchoReply: // FIXME: This is too fragile. Create a periodic timer // Wait three seconds then send an echo_request message. go func() { <-time.After(time.Second * 3) // Send echo request res := openflow13.NewEchoRequest() self.Send(res) }() case openflow13.Type_FeaturesRequest: case openflow13.Type_GetConfigRequest: case openflow13.Type_BarrierRequest: case openflow13.Type_BarrierReply: } case *openflow13.ErrorMsg: log.Errorf("Received ofp1.3 error msg: %+v", *t) self.stream.Shutdown <- true case *openflow13.VendorHeader: case *openflow13.SwitchFeatures: case *openflow13.SwitchConfig: switch t.Header.Type { case openflow13.Type_GetConfigReply: case openflow13.Type_SetConfig: } case *openflow13.PacketIn: log.Infof("Received packet(ofctrl): %+v", t) // send packet rcvd callback self.app.PacketRcvd(self, (*PacketIn)(t)) case *openflow13.FlowRemoved: case *openflow13.PortStatus: // FIXME: This needs to propagated to the app. case *openflow13.PacketOut: case *openflow13.FlowMod: case *openflow13.PortMod: case *openflow13.MultipartRequest: case *openflow13.MultipartReply: // FIXME: find a way to get multipart resp to app } }
// Handle TCP connection from the switch func (c *Controller) handleConnection(conn net.Conn) { stream := util.NewMessageStream(conn, c) log.Println("New connection..") // Send ofp 1.3 Hello by default h, err := common.NewHello(4) if err != nil { return } stream.Outbound <- h for { select { // 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 *common.Hello: if m.Version == openflow13.VERSION { log.Infoln("Received Openflow 1.3 Hello message") // Version negotiation is // considered complete. Create // new Switch and notifiy listening // applications. stream.Version = m.Version stream.Outbound <- openflow13.NewFeaturesRequest() } else { // Connection should be severed if controller // doesn't support switch version. log.Println("Received unsupported ofp version", m.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 *openflow13.SwitchFeatures: log.Printf("Received ofp1.3 Switch feature response: %+v", *m) // Create a new switch and handover the stream NewSwitch(stream, m.DPID, c.app) // Let switch instance handle all future messages.. return // An error message may indicate a version mismatch. We // disconnect if an error occurs this early. case *openflow13.ErrorMsg: log.Warnf("Received ofp1.3 error msg: %+v", *m) 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.Warnln("Connection timed out.") return } } }