summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/zclient.go19
-rw-r--r--zebra/zapi.go93
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
+ }
}
}()