github.com/aristanetworks/goarista@v0.0.0-20240514173732-cca2755bbd44/dscp/dscp_unix.go (about) 1 // Copyright (c) 2019 Arista Networks, Inc. 2 // Use of this source code is governed by the Apache License 2.0 3 // that can be found in the COPYING file. 4 5 //go:build linux || darwin 6 // +build linux darwin 7 8 package dscp 9 10 import ( 11 "context" 12 "net" 13 "os" 14 "strings" 15 "syscall" 16 17 "github.com/aristanetworks/goarista/logger" 18 "golang.org/x/sys/unix" 19 ) 20 21 // ListenTCPWithTOS is similar to net.ListenTCP but with the socket configured 22 // to the use the given ToS (Type of Service), to specify DSCP / ECN / class 23 // of service flags to use for incoming connections. 24 func ListenTCPWithTOS(address *net.TCPAddr, tos byte) (*net.TCPListener, error) { 25 return ListenTCPWithTOSLogger(address, tos, logger.Std) 26 } 27 28 // ListenTCPWithTOSLogger is similar to net.ListenTCP but with the 29 // socket configured to the use the given ToS (Type of Service), to 30 // specify DSCP / ECN / class of service flags to use for incoming 31 // connections. Allows passing in a Logger. 32 func ListenTCPWithTOSLogger(address *net.TCPAddr, tos byte, l logger.Logger) (*net.TCPListener, 33 error) { 34 cfg := net.ListenConfig{ 35 Control: func(network, address string, c syscall.RawConn) error { 36 return SetTOSLogger(network, c, tos, l) 37 }, 38 } 39 40 lsnr, err := cfg.Listen(context.Background(), "tcp", address.String()) 41 if err != nil { 42 return nil, err 43 } 44 45 return lsnr.(*net.TCPListener), err 46 } 47 48 // SetTOS will set the TOS byte on a unix system. It's intended to be 49 // used in a net.Dialer's Control function. 50 func SetTOS(network string, c syscall.RawConn, tos byte) error { 51 return SetTOSLogger(network, c, tos, logger.Std) 52 } 53 54 // SetTOSLogger will set the TOS byte on a unix system. It's intended 55 // to be used in a net.Dialer's Control function. Allows passing in a 56 // Logger. 57 func SetTOSLogger(network string, c syscall.RawConn, tos byte, l logger.Logger) error { 58 return c.Control(func(fd uintptr) { 59 // Configure ipv4 TOS for both IPv4 and IPv6 networks because 60 // v4 connections can still come over v6 networks. 61 err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_TOS, int(tos)) 62 if err != nil { 63 l.Errorf("failed to configure IP_TOS: %v", os.NewSyscallError("setsockopt", err)) 64 } 65 if strings.HasSuffix(network, "4") { 66 // Skip configuring IPv6 when we know we are using an IPv4 67 // network to avoid error. 68 return 69 } 70 err6 := unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_TCLASS, int(tos)) 71 if err6 != nil { 72 l.Errorf( 73 "failed to configure IPV6_TCLASS, traffic may not use the configured DSCP: %v", 74 os.NewSyscallError("setsockopt", err6)) 75 } 76 77 }) 78 }