From 34ae479b3e7f67ee80fc58880e7192f5c6f8e4ce Mon Sep 17 00:00:00 2001 From: Lars Ekman Date: Fri, 9 Nov 2018 10:41:23 +0100 Subject: [PATCH] Generate a router-id from a hash on the hostname as fallback This may be necessary in a true ipv6-only cluster. --- internal/bgp/bgp.go | 26 ++++++++++++++++---------- speaker/bgp_controller.go | 6 +++--- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/internal/bgp/bgp.go b/internal/bgp/bgp.go index 5f75cbf5705..965f46efe98 100644 --- a/internal/bgp/bgp.go +++ b/internal/bgp/bgp.go @@ -1,10 +1,12 @@ package bgp // import "go.universe.tf/metallb/internal/bgp" import ( + "bytes" "context" "encoding/binary" "errors" "fmt" + "hash/crc32" "io" "io/ioutil" "net" @@ -25,6 +27,7 @@ var errClosed = errors.New("session closed") type Session struct { asn uint32 routerID net.IP // May be nil, meaning "derive from context" + myNode string addr string peerASN uint32 holdTime time.Duration @@ -184,11 +187,7 @@ func (s *Session) connect() error { routerID := s.routerID if routerID == nil { - routerID = getRouterID(s.defaultNextHop) - if routerID == nil { - conn.Close() - return fmt.Errorf("cannot automatically derive router ID for IPv6 connection to %q", s.addr) - } + routerID = getRouterID(s.defaultNextHop, s.myNode) } if err = sendOpen(conn, s.asn, routerID, s.holdTime); err != nil { @@ -235,16 +234,22 @@ func (s *Session) connect() error { return nil } +func hashRouterId(hostname string) net.IP { + buf := new(bytes.Buffer) + binary.Write(buf, binary.LittleEndian, crc32.ChecksumIEEE([]byte(hostname))) + return net.IP(buf.Bytes()) +} + // Ipv4; Use the address as-is. // Ipv6; Pick the first ipv4 address on the same interface as the address -func getRouterID(addr net.IP) net.IP { +func getRouterID(addr net.IP, myNode string) net.IP { if addr.To4() != nil { return addr } ifaces, err := net.Interfaces() if err != nil { - return nil + return hashRouterId(myNode) } for _, i := range ifaces { addrs, err := i.Addrs() @@ -274,12 +279,12 @@ func getRouterID(addr net.IP) net.IP { if ip.To4() != nil { return ip } - return nil } + return hashRouterId(myNode) } } } - return nil + return hashRouterId(myNode) } // sendKeepalives sends BGP KEEPALIVE packets at the negotiated rate @@ -339,11 +344,12 @@ func (s *Session) sendKeepalive() error { // // The session will immediately try to connect and synchronize its // local state with the peer. -func New(l log.Logger, addr string, asn uint32, routerID net.IP, peerASN uint32, holdTime time.Duration, password string) (*Session, error) { +func New(l log.Logger, addr string, asn uint32, routerID net.IP, peerASN uint32, holdTime time.Duration, password string, myNode string) (*Session, error) { ret := &Session{ addr: addr, asn: asn, routerID: routerID.To4(), + myNode: myNode, peerASN: peerASN, holdTime: holdTime, logger: log.With(l, "peer", addr, "localASN", asn, "peerASN", peerASN), diff --git a/speaker/bgp_controller.go b/speaker/bgp_controller.go index 306a0e3fac1..ddd86c42f23 100644 --- a/speaker/bgp_controller.go +++ b/speaker/bgp_controller.go @@ -184,7 +184,7 @@ func (c *bgpController) syncPeers(l log.Logger) error { if p.cfg.RouterID != nil { routerID = p.cfg.RouterID } - s, err := newBGP(c.logger, net.JoinHostPort(p.cfg.Addr.String(), strconv.Itoa(int(p.cfg.Port))), p.cfg.MyASN, routerID, p.cfg.ASN, p.cfg.HoldTime, p.cfg.Password) + s, err := newBGP(c.logger, net.JoinHostPort(p.cfg.Addr.String(), strconv.Itoa(int(p.cfg.Port))), p.cfg.MyASN, routerID, p.cfg.ASN, p.cfg.HoldTime, p.cfg.Password, c.myNode) if err != nil { l.Log("op", "syncPeers", "error", err, "peer", p.cfg.Addr, "msg", "failed to create BGP session") errs++ @@ -286,6 +286,6 @@ func (c *bgpController) SetNode(l log.Logger, node *v1.Node) error { return c.syncPeers(l) } -var newBGP = func(logger log.Logger, addr string, myASN uint32, routerID net.IP, asn uint32, hold time.Duration, password string) (session, error) { - return bgp.New(logger, addr, myASN, routerID, asn, hold, password) +var newBGP = func(logger log.Logger, addr string, myASN uint32, routerID net.IP, asn uint32, hold time.Duration, password string, myNode string) (session, error) { + return bgp.New(logger, addr, myASN, routerID, asn, hold, password, myNode) }