Skip to content

Commit

Permalink
use TCP MSS configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxime Peim authored and fujita committed Jul 25, 2023
1 parent f617588 commit e7534de
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 7 deletions.
2 changes: 2 additions & 0 deletions internal/pkg/config/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ func NewPeerFromConfigStruct(pconf *Neighbor) *api.Peer {
LocalAddress: localAddress,
PassiveMode: pconf.Transport.Config.PassiveMode,
BindInterface: pconf.Transport.Config.BindInterface,
TcpMss: uint32(pconf.Transport.Config.TcpMss),
},
AfiSafis: afiSafis,
}
Expand Down Expand Up @@ -640,6 +641,7 @@ func NewPeerGroupFromConfigStruct(pconf *PeerGroup) *api.PeerGroup {
RemotePort: uint32(pconf.Transport.Config.RemotePort),
LocalAddress: pconf.Transport.Config.LocalAddress,
PassiveMode: pconf.Transport.Config.PassiveMode,
TcpMss: uint32(pconf.Transport.Config.TcpMss),
},
AfiSafis: afiSafis,
}
Expand Down
25 changes: 22 additions & 3 deletions pkg/server/fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ func (h *fsmHandler) connectLoop(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
fsm := h.fsm

retry, addr, port, password, ttl, ttlMin, localAddress, localPort, bindInterface := func() (int, string, int, string, uint8, uint8, string, int, string) {
retry, addr, port, password, ttl, ttlMin, mss, localAddress, localPort, bindInterface := func() (int, string, int, string, uint8, uint8, uint16, string, int, string) {
fsm.lock.RLock()
defer fsm.lock.RUnlock()

Expand All @@ -521,7 +521,7 @@ func (h *fsmHandler) connectLoop(ctx context.Context, wg *sync.WaitGroup) {
ttl = fsm.pConf.EbgpMultihop.Config.MultihopTtl
}
}
return tick, addr, port, password, ttl, ttlMin, fsm.pConf.Transport.Config.LocalAddress, int(fsm.pConf.Transport.Config.LocalPort), fsm.pConf.Transport.Config.BindInterface
return tick, addr, port, password, ttl, ttlMin, fsm.pConf.Transport.Config.TcpMss, fsm.pConf.Transport.Config.LocalAddress, int(fsm.pConf.Transport.Config.LocalPort), fsm.pConf.Transport.Config.BindInterface
}()

tick := minConnectRetryInterval
Expand Down Expand Up @@ -556,7 +556,7 @@ func (h *fsmHandler) connectLoop(ctx context.Context, wg *sync.WaitGroup) {
LocalAddr: laddr,
Timeout: time.Duration(tick-1) * time.Second,
Control: func(network, address string, c syscall.RawConn) error {
return dialerControl(fsm.logger, network, address, c, ttl, ttlMin, password, bindInterface)
return dialerControl(fsm.logger, network, address, c, ttl, ttlMin, mss, password, bindInterface)
},
}

Expand Down Expand Up @@ -634,6 +634,14 @@ func (h *fsmHandler) active(ctx context.Context) (bgp.FSMState, *fsmStateReason)
"State": fsm.state.String(),
"Error": err})
}
if err := setPeerConnMSS(fsm); err != nil {
fsm.logger.Warn("cannot set MSS for peer",
log.Fields{
"Topic": "Peer",
"Key": fsm.pConf.Config.NeighborAddress,
"State": fsm.state.String(),
"Error": err})
}
fsm.lock.RUnlock()
// we don't implement delayed open timer so move to opensent right
// away.
Expand Down Expand Up @@ -705,6 +713,17 @@ func setPeerConnTTL(fsm *fsm) error {
return nil
}

func setPeerConnMSS(fsm *fsm) error {
mss := fsm.pConf.Transport.Config.TcpMss
if mss == 0 {
return nil
}
if err := setTCPMSSSockopt(fsm.conn.(*net.TCPConn), mss); err != nil {
return fmt.Errorf("failed to set MSS %d: %w", mss, err)
}
return nil
}

func capAddPathFromConfig(pConf *config.Neighbor) bgp.ParameterCapabilityInterface {
tuples := make([]*bgp.CapAddPathTuple, 0, len(pConf.AfiSafis))
for _, af := range pConf.AfiSafis {
Expand Down
2 changes: 2 additions & 0 deletions pkg/server/grpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@ func newNeighborFromAPIStruct(a *api.Peer) (*config.Neighbor, error) {
pconf.Transport.Config.RemotePort = uint16(a.Transport.RemotePort)
pconf.Transport.Config.LocalPort = uint16(a.Transport.LocalPort)
pconf.Transport.Config.BindInterface = a.Transport.BindInterface
pconf.Transport.Config.TcpMss = uint16(a.Transport.TcpMss)
}
if a.EbgpMultihop != nil {
pconf.EbgpMultihop.Config.Enabled = a.EbgpMultihop.Enabled
Expand Down Expand Up @@ -836,6 +837,7 @@ func newPeerGroupFromAPIStruct(a *api.PeerGroup) (*config.PeerGroup, error) {
pconf.Transport.Config.LocalAddress = a.Transport.LocalAddress
pconf.Transport.Config.PassiveMode = a.Transport.PassiveMode
pconf.Transport.Config.RemotePort = uint16(a.Transport.RemotePort)
pconf.Transport.Config.TcpMss = uint16(a.Transport.TcpMss)
}
if a.EbgpMultihop != nil {
pconf.EbgpMultihop.Config.Enabled = a.EbgpMultihop.Enabled
Expand Down
12 changes: 11 additions & 1 deletion pkg/server/sockopt.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ func setBindToDevSockopt(sc syscall.RawConn, device string) error {
return fmt.Errorf("binding connection to a device is not supported")
}

func dialerControl(logger log.Logger, network, address string, c syscall.RawConn, ttl, minTtl uint8, password string, bindInterface string) error {
func setTCPMSSSockopt(conn *net.TCPConn, mss uint16) error {
return setTcpMSSSockopt(conn, mss)
}

func dialerControl(logger log.Logger, network, address string, c syscall.RawConn, ttl, minTtl uint8, mss uint16, password string, bindInterface string) error {
if password != "" {
logger.Warn("setting md5 for active connection is not supported",
log.Fields{
Expand All @@ -60,5 +64,11 @@ func dialerControl(logger log.Logger, network, address string, c syscall.RawConn
"Topic": "Peer",
"Key": address})
}
if mss != 0 {
logger.Warn("setting MSS for active connection is not supported",
log.Fields{
"Topic": "Peer",
"Key": address})
}
return nil
}
9 changes: 9 additions & 0 deletions pkg/server/sockopt_bsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,12 @@ func setTcpMinTTLSockopt(conn *net.TCPConn, ttl int) error {
}
return setsockOptInt(sc, level, name, ttl)
}

func setTcpMSSSockopt(conn *net.TCPConn, mss uint16) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
if err != nil {
return err
}
return setsockoptTcpMss(sc, family, mss)
}
9 changes: 9 additions & 0 deletions pkg/server/sockopt_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,12 @@ func setTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
func setTcpMinTTLSockopt(conn *net.TCPConn, ttl int) error {
return fmt.Errorf("setting min ttl is not supported")
}

func setTcpMSSSockopt(conn *net.TCPConn, mss uint16) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
if err != nil {
return err
}
return setsockoptTcpMss(sc, family, mss)
}
25 changes: 24 additions & 1 deletion pkg/server/sockopt_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,16 @@ func setTCPMinTTLSockopt(conn *net.TCPConn, ttl int) error {
return setsockOptInt(sc, level, name, ttl)
}

func dialerControl(logger log.Logger, network, address string, c syscall.RawConn, ttl, minTtl uint8, password string, bindInterface string) error {
func setTCPMSSSockopt(conn *net.TCPConn, mss uint16) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
if err != nil {
return err
}
return setsockoptTcpMss(sc, family, mss)
}

func dialerControl(logger log.Logger, network, address string, c syscall.RawConn, ttl, minTtl uint8, mss uint16, password string, bindInterface string) error {
family := syscall.AF_INET
raddr, _ := net.ResolveTCPAddr("tcp", address)
if raddr.IP.To4() == nil {
Expand Down Expand Up @@ -146,6 +155,20 @@ func dialerControl(logger log.Logger, network, address string, c syscall.RawConn
return sockerr
}
}

if mss != 0 {
if err := c.Control(func(fd uintptr) {
level := syscall.IPPROTO_TCP
name := syscall.TCP_MAXSEG
sockerr = os.NewSyscallError("setsockopt", syscall.SetsockoptInt(int(fd), level, name, int(mss)))
}); err != nil {
return err
}
if sockerr != nil {
return sockerr
}
}

if bindInterface != "" {
if err := setBindToDevSockopt(c, bindInterface); err != nil {
return err
Expand Down
24 changes: 23 additions & 1 deletion pkg/server/sockopt_openbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,11 +384,20 @@ func setTCPMinTTLSockopt(conn *net.TCPConn, ttl int) error {
return setsockOptInt(sc, level, name, ttl)
}

func setTCPMSSSockopt(conn *net.TCPConn, mss uint16) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
if err != nil {
return err
}
return setsockoptTcpMss(sc, family, mss)
}

func setBindToDevSockopt(sc syscall.RawConn, device string) error {
return fmt.Errorf("binding connection to a device is not supported")
}

func dialerControl(logger log.Logger, network, address string, c syscall.RawConn, ttl, minTtl uint8, password string, bindInterface string) error {
func dialerControl(logger log.Logger, network, address string, c syscall.RawConn, ttl, minTtl uint8, mss uint16, password string, bindInterface string) error {
if password != "" {
logger.Warn("setting md5 for active connection is not supported",
log.Fields{
Expand All @@ -407,5 +416,18 @@ func dialerControl(logger log.Logger, network, address string, c syscall.RawConn
"Topic": "Peer",
"Key": address})
}
var sockerr error
if mss != 0 {
if err := c.Control(func(fd uintptr) {
level := syscall.IPPROTO_TCP
name := syscall.TCP_MAXSEG
sockerr = os.NewSyscallError("setsockopt", syscall.SetsockoptInt(int(fd), level, name, int(mss)))
}); err != nil {
return err
}
if sockerr != nil {
return sockerr
}
}
return nil
}
4 changes: 4 additions & 0 deletions pkg/server/sockopt_stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ func setTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
func setTcpMinTTLSockopt(conn *net.TCPConn, ttl int) error {
return fmt.Errorf("setting min ttl is not supported")
}

func setTcpMSSSockopt(conn *net.TCPConn, mss uint16) error {
return fmt.Errorf("setting min ttl is not supported")
}
21 changes: 20 additions & 1 deletion pkg/server/sockopt_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
tcpMD5SIG = 14 // TCP MD5 Signature (RFC2385)
ipv6MinHopCount = 73 // Generalized TTL Security Mechanism (RFC5082)
IP_MINTTL = 0x15 // pulled from https://golang.org/pkg/syscall/?GOOS=linux#IP_MINTTL
TCP_MAXSEG = 0x2 // pulled from https://pkg.go.dev/syscall?GOOS=linux#TCP_MAXSEG
)

func setTCPMD5SigSockopt(l *net.TCPListener, address string, key string) error {
Expand Down Expand Up @@ -63,7 +64,19 @@ func setTCPMinTTLSockopt(conn *net.TCPConn, ttl int) error {
return setsockOptInt(sc, level, name, ttl)
}

func dialerControl(logger log.Logger, network, address string, c syscall.RawConn, ttl, ttlMin uint8, password string, bindInterface string) error {
func setTCPMSSSockopt(conn *net.TCPConn, mss uint16) error {
// TCP_MAXSEG syscall option exists only from Windows 10
// https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getsockopt
sc, err := conn.SyscallConn()
if err != nil {
return err
}
level := syscall.IPPROTO_TCP
name := TCP_MAXSEG
return setsockOptInt(sc, level, name, int(mss))
}

func dialerControl(logger log.Logger, network, address string, c syscall.RawConn, ttl, ttlMin uint8, mss uint16, password string, bindInterface string) error {
if password != "" {
logger.Warn("setting md5 for active connection is not supported",
log.Fields{
Expand All @@ -82,5 +95,11 @@ func dialerControl(logger log.Logger, network, address string, c syscall.RawConn
"Topic": "Peer",
"Key": address})
}
if mss != 0 {
logger.Warn("setting MSS for active connection is not supported",
log.Fields{
"Topic": "Peer",
"Key": address})
}
return nil
}
6 changes: 6 additions & 0 deletions pkg/server/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,9 @@ func setsockoptIpTtl(sc syscall.RawConn, family int, value int) error {
}
return setsockOptInt(sc, level, name, value)
}

func setsockoptTcpMss(sc syscall.RawConn, family int, value uint16) error {
level := syscall.IPPROTO_TCP
name := syscall.TCP_MAXSEG
return setsockOptInt(sc, level, name, int(value))
}

0 comments on commit e7534de

Please sign in to comment.