github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/shaper/shaper_linux.go (about)

     1  /*
     2   * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package shaper
    19  
    20  import (
    21  	"github.com/pkg/errors"
    22  	"github.com/rs/zerolog/log"
    23  
    24  	"github.com/mysteriumnetwork/go-wondershaper/wondershaper"
    25  	"github.com/mysteriumnetwork/node/config"
    26  )
    27  
    28  type linuxShaper struct {
    29  	ws          *wondershaper.Shaper
    30  	listener    eventListener
    31  	listenTopic string
    32  }
    33  
    34  type linuxShaperNoop struct{}
    35  
    36  func (s *linuxShaperNoop) Start(interfaceName string) error {
    37  	return nil
    38  }
    39  
    40  func (s *linuxShaperNoop) Clear(interfaceName string) {
    41  	return
    42  }
    43  
    44  func create(listener eventListener) Shaper {
    45  	// return a noop filter if userspace flag is set
    46  	if config.GetBool(config.FlagUserspace) {
    47  		return &linuxShaperNoop{}
    48  	}
    49  
    50  	ws := wondershaper.New()
    51  	ws.Stdout = log.Logger
    52  	ws.Stderr = log.Logger
    53  	return &linuxShaper{
    54  		ws:          ws,
    55  		listener:    listener,
    56  		listenTopic: config.AppTopicConfig(config.FlagShaperEnabled.Name),
    57  	}
    58  }
    59  
    60  // Start applies shaping configuration on the specified interface and then continuously ensures it.
    61  func (s *linuxShaper) Start(interfaceName string) error {
    62  	applyLimits := func() error {
    63  		s.ws.Clear(interfaceName)
    64  
    65  		if config.GetBool(config.FlagShaperEnabled) {
    66  			err := s.ws.LimitDownlink(interfaceName, int(config.GetUInt64(config.FlagShaperBandwidth))*8)
    67  			if err != nil {
    68  				log.Error().Err(err).Msg("Could not limit download speed")
    69  				return err
    70  			}
    71  			err = s.ws.LimitUplink(interfaceName, int(config.GetUInt64(config.FlagShaperBandwidth))*8)
    72  			if err != nil {
    73  				log.Error().Err(err).Msg("Could not limit upload speed")
    74  				return err
    75  			}
    76  		}
    77  		return nil
    78  	}
    79  
    80  	err := s.listener.SubscribeAsync(s.listenTopic, applyLimits)
    81  	if err != nil {
    82  		return errors.Wrap(err, "could not subscribe to topic: "+s.listenTopic)
    83  	}
    84  
    85  	return applyLimits()
    86  }
    87  
    88  // Clear clears shaping rules.
    89  func (s *linuxShaper) Clear(interfaceName string) {
    90  	s.ws.Clear(interfaceName)
    91  }