diff options
Diffstat (limited to 'core/connection.go')
-rw-r--r-- | core/connection.go | 166 |
1 files changed, 85 insertions, 81 deletions
diff --git a/core/connection.go b/core/connection.go index 08f08f5..14b0af4 100644 --- a/core/connection.go +++ b/core/connection.go @@ -40,6 +40,8 @@ var ( HealthCheckReplyTimeout = time.Millisecond * 100 // timeout for reply to a health check probe HealthCheckThreshold = 1 // number of failed health checks until the error is reported DefaultReplyTimeout = time.Second * 1 // default timeout for replies from VPP + ReconnectInterval = time.Second * 1 // default interval for reconnect attempts + MaxReconnectAttempts = 10 // maximum number of reconnect attempts ) // ConnectionState represents the current state of the connection to VPP. @@ -51,6 +53,9 @@ const ( // Disconnected represents state in which the connection has been dropped. Disconnected + + // Failed represents state in which the reconnecting failed after exceeding maximum number of attempts. + Failed ) // ConnectionEvent is a notification about change in the VPP connection state. @@ -213,88 +218,11 @@ func (c *Connection) releaseAPIChannel(ch *Channel) { c.channelsLock.Unlock() } -// GetMessageID returns message identifier of given API message. -func (c *Connection) GetMessageID(msg api.Message) (uint16, error) { - if c == nil { - return 0, errors.New("nil connection passed in") - } - - if msgID, ok := c.msgIDs[getMsgNameWithCrc(msg)]; ok { - return msgID, nil - } - - return 0, fmt.Errorf("unknown message: %s (%s)", msg.GetMessageName(), msg.GetCrcString()) -} - -// LookupByID looks up message name and crc by ID. -func (c *Connection) LookupByID(msgID uint16) (api.Message, error) { - if c == nil { - return nil, errors.New("nil connection passed in") - } - - if msg, ok := c.msgMap[msgID]; ok { - return msg, nil - } - - return nil, fmt.Errorf("unknown message ID: %d", msgID) -} - -// retrieveMessageIDs retrieves IDs for all registered messages and stores them in map -func (c *Connection) retrieveMessageIDs() (err error) { - t := time.Now() - - var addMsg = func(msgID uint16, msg api.Message) { - c.msgIDs[getMsgNameWithCrc(msg)] = msgID - c.msgMap[msgID] = msg - } - - msgs := api.GetRegisteredMessages() - - for name, msg := range msgs { - msgID, err := c.vppClient.GetMsgID(msg.GetMessageName(), msg.GetCrcString()) - if err != nil { - return err - } - - addMsg(msgID, msg) - - if msg.GetMessageName() == msgControlPing.GetMessageName() { - c.pingReqID = msgID - msgControlPing = reflect.New(reflect.TypeOf(msg).Elem()).Interface().(api.Message) - } else if msg.GetMessageName() == msgControlPingReply.GetMessageName() { - c.pingReplyID = msgID - msgControlPingReply = reflect.New(reflect.TypeOf(msg).Elem()).Interface().(api.Message) - } - - if debugMsgIDs { - log.Debugf("message %q (%s) has ID: %d", name, getMsgNameWithCrc(msg), msgID) - } - } - - log.Debugf("retrieving %d message IDs took %s", len(msgs), time.Since(t)) - - // fallback for control ping when vpe package is not imported - if c.pingReqID == 0 { - c.pingReqID, err = c.vppClient.GetMsgID(msgControlPing.GetMessageName(), msgControlPing.GetCrcString()) - if err != nil { - return err - } - addMsg(c.pingReqID, msgControlPing) - } - if c.pingReplyID == 0 { - c.pingReplyID, err = c.vppClient.GetMsgID(msgControlPingReply.GetMessageName(), msgControlPingReply.GetCrcString()) - if err != nil { - return err - } - addMsg(c.pingReplyID, msgControlPingReply) - } - - return nil -} - // connectLoop attempts to connect to VPP until it succeeds. // Then it continues with healthCheckLoop. func (c *Connection) connectLoop(connChan chan ConnectionEvent) { + reconnectAttempts := 0 + // loop until connected for { if err := c.vppClient.WaitReady(); err != nil { @@ -304,9 +232,13 @@ func (c *Connection) connectLoop(connChan chan ConnectionEvent) { // signal connected event connChan <- ConnectionEvent{Timestamp: time.Now(), State: Connected} break + } else if reconnectAttempts < MaxReconnectAttempts { + reconnectAttempts++ + log.Errorf("connecting failed (attempt %d/%d): %v", reconnectAttempts, MaxReconnectAttempts, err) + time.Sleep(ReconnectInterval) } else { - log.Errorf("connecting to VPP failed: %v", err) - time.Sleep(time.Second) + connChan <- ConnectionEvent{Timestamp: time.Now(), State: Failed, Error: err} + return } } @@ -405,3 +337,75 @@ func (c *Connection) healthCheckLoop(connChan chan ConnectionEvent) { func getMsgNameWithCrc(x api.Message) string { return x.GetMessageName() + "_" + x.GetCrcString() } + +func getMsgFactory(msg api.Message) func() api.Message { + return func() api.Message { + return reflect.New(reflect.TypeOf(msg).Elem()).Interface().(api.Message) + } +} + +// GetMessageID returns message identifier of given API message. +func (c *Connection) GetMessageID(msg api.Message) (uint16, error) { + if c == nil { + return 0, errors.New("nil connection passed in") + } + + if msgID, ok := c.msgIDs[getMsgNameWithCrc(msg)]; ok { + return msgID, nil + } + + msgID, err := c.vppClient.GetMsgID(msg.GetMessageName(), msg.GetCrcString()) + if err != nil { + return 0, err + } + + c.msgIDs[getMsgNameWithCrc(msg)] = msgID + c.msgMap[msgID] = msg + + return msgID, nil +} + +// LookupByID looks up message name and crc by ID. +func (c *Connection) LookupByID(msgID uint16) (api.Message, error) { + if c == nil { + return nil, errors.New("nil connection passed in") + } + + if msg, ok := c.msgMap[msgID]; ok { + return msg, nil + } + + return nil, fmt.Errorf("unknown message ID: %d", msgID) +} + +// retrieveMessageIDs retrieves IDs for all registered messages and stores them in map +func (c *Connection) retrieveMessageIDs() (err error) { + t := time.Now() + + msgs := api.GetRegisteredMessages() + + var n int + for name, msg := range msgs { + msgID, err := c.GetMessageID(msg) + if err != nil { + log.Debugf("retrieving msgID for %s failed: %v", name, err) + continue + } + n++ + + if c.pingReqID == 0 && msg.GetMessageName() == msgControlPing.GetMessageName() { + c.pingReqID = msgID + msgControlPing = reflect.New(reflect.TypeOf(msg).Elem()).Interface().(api.Message) + } else if c.pingReplyID == 0 && msg.GetMessageName() == msgControlPingReply.GetMessageName() { + c.pingReplyID = msgID + msgControlPingReply = reflect.New(reflect.TypeOf(msg).Elem()).Interface().(api.Message) + } + + if debugMsgIDs { + log.Debugf("message %q (%s) has ID: %d", name, getMsgNameWithCrc(msg), msgID) + } + } + log.Debugf("retrieved %d/%d msgIDs (took %s)", n, len(msgs), time.Since(t)) + + return nil +} |