package config import "fmt" // TCDevice defines a traffic-shaped interface with bandwidth limits. type TCDevice struct { Interface string `yaml:"interface"` InBandwidth string `yaml:"in_bandwidth,omitempty"` // ingress rate limit OutBandwidth string `yaml:"out_bandwidth"` // egress max Options TCDeviceOptions `yaml:"options,omitempty"` Comment string `yaml:"comment,omitempty"` } type TCDeviceOptions struct { Classify bool `yaml:"classify,omitempty"` HTB bool `yaml:"htb,omitempty"` HFSC bool `yaml:"hfsc,omitempty"` Linklayer string `yaml:"linklayer,omitempty"` // ethernet, atm, adsl } // TCClass defines an HTB/HFSC traffic class with rate guarantees. type TCClass struct { Interface string `yaml:"interface"` // format: iface:class or iface:parent:class Mark int `yaml:"mark,omitempty"` // 1-255 fw mark Rate string `yaml:"rate"` // minimum guaranteed bandwidth Ceil string `yaml:"ceil,omitempty"` // max bandwidth Priority int `yaml:"priority,omitempty"` // scheduling order Options TCClassOptions `yaml:"options,omitempty"` Comment string `yaml:"comment,omitempty"` } type TCClassOptions struct { Default bool `yaml:"default,omitempty"` // default class for unclassified traffic TCPAck bool `yaml:"tcp_ack,omitempty"` Pfifo bool `yaml:"pfifo,omitempty"` } // TCFilter classifies packets into traffic classes. type TCFilter struct { Class string `yaml:"class"` // interface:class Source string `yaml:"source,omitempty"` Dest string `yaml:"dest,omitempty"` Proto string `yaml:"proto,omitempty"` DPort PortSpec `yaml:"dport,omitempty"` SPort PortSpec `yaml:"sport,omitempty"` TOS string `yaml:"tos,omitempty"` Length int `yaml:"length,omitempty"` Priority int `yaml:"priority,omitempty"` // filter eval order Comment string `yaml:"comment,omitempty"` } // TCInterface defines simple traffic shaping (3-band priority queueing). type TCInterface struct { Interface string `yaml:"interface"` Type string `yaml:"type,omitempty"` // external, internal InBandwidth string `yaml:"in_bandwidth,omitempty"` OutBandwidth string `yaml:"out_bandwidth,omitempty"` Comment string `yaml:"comment,omitempty"` } // TCPriority assigns packets to priority bands (1=high, 2=medium, 3=low). type TCPriority struct { Band int `yaml:"band"` // 1, 2, or 3 Proto string `yaml:"proto,omitempty"` DPort PortSpec `yaml:"dport,omitempty"` SPort PortSpec `yaml:"sport,omitempty"` Address string `yaml:"address,omitempty"` Interface string `yaml:"interface,omitempty"` Helper string `yaml:"helper,omitempty"` Comment string `yaml:"comment,omitempty"` } func (c *Config) validateTCDevices() error { for i, dev := range c.TCDevices { if dev.Interface == "" { return fmt.Errorf("tcdevices[%d]: interface required", i) } if dev.OutBandwidth == "" { return fmt.Errorf("tcdevices[%d]: out_bandwidth required", i) } } return nil } func (c *Config) validateTCClasses() error { for i, cls := range c.TCClasses { if cls.Interface == "" { return fmt.Errorf("tcclasses[%d]: interface required", i) } if cls.Rate == "" { return fmt.Errorf("tcclasses[%d]: rate required", i) } if cls.Mark != 0 && (cls.Mark < 1 || cls.Mark > 255) { return fmt.Errorf("tcclasses[%d]: mark must be 1-255", i) } } return nil } func (c *Config) validateTCFilters() error { for i, f := range c.TCFilters { if f.Class == "" { return fmt.Errorf("tcfilters[%d]: class required", i) } if f.Source == "" && f.Dest == "" { return fmt.Errorf("tcfilters[%d]: source or dest required", i) } } return nil } func (c *Config) validateTCInterfaces() error { for i, iface := range c.TCInterfaces { if iface.Interface == "" { return fmt.Errorf("tcinterfaces[%d]: interface required", i) } } return nil } func (c *Config) validateTCPriority() error { for i, p := range c.TCPriorities { if p.Band < 1 || p.Band > 3 { return fmt.Errorf("tcpriority[%d]: band must be 1, 2, or 3", i) } } return nil }