diff options
-rw-r--r-- | server/zclient.go | 19 | ||||
-rw-r--r-- | zebra/zapi.go | 93 |
2 files changed, 75 insertions, 37 deletions
diff --git a/server/zclient.go b/server/zclient.go index 4bba83ec..d432b96d 100644 --- a/server/zclient.go +++ b/server/zclient.go @@ -519,10 +519,23 @@ func newZebraClient(s *BgpServer, url string, protos []string, version uint8, nh } cli, err := zebra.NewClient(l[0], l[1], zebra.ROUTE_BGP, version) if err != nil { - return nil, err + // Retry with another Zebra message version + var retry_version uint8 = 2 + if version == 2 { + retry_version = 3 + } + log.WithFields(log.Fields{ + "Topic": "Zebra", + }).Warnf("cannot connect to Zebra with message version %d. retry with version %d", version, retry_version) + cli, err = zebra.NewClient(l[0], l[1], zebra.ROUTE_BGP, retry_version) + if err != nil { + return nil, err + } } - cli.SendHello() - cli.SendRouterIDAdd() + // Note: HELLO/ROUTER_ID_ADD messages are automatically sent to negotiate + // the Zebra message version in zebra.NewClient(). + // cli.SendHello() + // cli.SendRouterIDAdd() cli.SendInterfaceAdd() for _, typ := range protos { t, err := zebra.RouteTypeFromString(typ) diff --git a/zebra/zapi.go b/zebra/zapi.go index 74d17f28..f4b8615e 100644 --- a/zebra/zapi.go +++ b/zebra/zapi.go @@ -332,46 +332,71 @@ func NewClient(network, address string, typ ROUTE_TYPE, version uint8) (*Client, } }() - go func() { - for { - headerBuf, err := readAll(conn, int(HeaderSize(version))) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Zebra", - }).Errorf("failed to read header:%s", err) - return - } + // Send HELLO/ROUTER_ID_ADD messages to negotiate the Zebra message version. + c.SendHello() + c.SendRouterIDAdd() + + receiveSingleMsg := func() (*Message, error) { + headerBuf, err := readAll(conn, int(HeaderSize(version))) + if err != nil { + err = fmt.Errorf("failed to read header: %s", err) log.WithFields(log.Fields{ "Topic": "Zebra", - }).Debugf("read header from zebra: %v", headerBuf) - hd := &Header{} - err = hd.DecodeFromBytes(headerBuf) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Zebra", - }).Errorf("failed to decode header:%s", err) - return - } + }).Error(err) + return nil, err + } + log.WithFields(log.Fields{ + "Topic": "Zebra", + }).Debugf("read header from zebra: %v", headerBuf) + hd := &Header{} + err = hd.DecodeFromBytes(headerBuf) + if err != nil { + err = fmt.Errorf("failed to decode header: %s", err) + log.WithFields(log.Fields{ + "Topic": "Zebra", + }).Error(err) + return nil, err + } - bodyBuf, err := readAll(conn, int(hd.Len-HeaderSize(version))) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Zebra", - }).Errorf("failed to read body:%s", err) - return - } + bodyBuf, err := readAll(conn, int(hd.Len-HeaderSize(version))) + if err != nil { + err = fmt.Errorf("failed to read body: %s", err) log.WithFields(log.Fields{ "Topic": "Zebra", - }).Debugf("read body from zebra: %v", bodyBuf) - m, err := ParseMessage(hd, bodyBuf) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Zebra", - }).Warnf("failed to parse message:%s", err) - continue - } + }).Error(err) + return nil, err + } + log.WithFields(log.Fields{ + "Topic": "Zebra", + }).Debugf("read body from zebra: %v", bodyBuf) + m, err := ParseMessage(hd, bodyBuf) + if err != nil { + log.WithFields(log.Fields{ + "Topic": "Zebra", + }).Warnf("failed to parse message: %s", err) + return nil, nil + } - incoming <- m + return m, nil + } + + // Try to receive the first message from Zebra. + if m, err := receiveSingleMsg(); err != nil { + c.Close() + // Return error explicitly in order to retry connection. + return nil, err + } else if m != nil { + incoming <- m + } + + // Start receive loop only when the first message successfully received. + go func() { + for { + if m, err := receiveSingleMsg(); err != nil { + return + } else if m != nil { + incoming <- m + } } }() |