Documentation ¶
Index ¶
- Constants
- Variables
- func Actions() generictables.ActionFactory
- func CalculateRuleHashes(chainName string, rules []generictables.Rule, features *environment.Features) []string
- func GrabIptablesLocks(lockFilePath, socketName string, timeout, probeInterval time.Duration) (io.Closer, error)
- func Match() generictables.MatchCriteria
- func PortRangesToMultiport(ports []*proto.PortRange) string
- func PortsToMultiport(ports []uint16) string
- type AcceptAction
- type ClearMarkAction
- type DNATAction
- type DropAction
- type GotoAction
- type IptablesRenderer
- type JumpAction
- type Locker
- type LogAction
- type MasqAction
- type NoTrackAction
- type Referrer
- type RejectAction
- type RestoreConnMarkAction
- type RestoreInputBuilder
- func (b *RestoreInputBuilder) Empty() bool
- func (b *RestoreInputBuilder) EndTransaction()
- func (b *RestoreInputBuilder) GetBytesAndReset() []byte
- func (b *RestoreInputBuilder) Reset()
- func (b *RestoreInputBuilder) StartTransaction(tableName string)
- func (b *RestoreInputBuilder) WriteForwardReference(chainName string)
- func (b *RestoreInputBuilder) WriteLine(line string)
- type ReturnAction
- type SNATAction
- type SaveConnMarkAction
- type SetConnMarkAction
- type SetMarkAction
- type SetMaskedMarkAction
- type SharedLock
- type Table
- func (t *Table) AppendRules(chainName string, rules []generictables.Rule)
- func (t *Table) Apply() (rescheduleAfter time.Duration)
- func (t *Table) CheckRulesPresent(chain string, rules []generictables.Rule) []generictables.Rule
- func (t *Table) IPVersion() uint8
- func (t *Table) InsertOrAppendRules(chainName string, rules []generictables.Rule)
- func (t *Table) InsertRulesNow(chain string, rules []generictables.Rule) error
- func (t *Table) InvalidateDataplaneCache(reason string)
- func (t *Table) Name() string
- func (t *Table) RemoveChainByName(name string)
- func (t *Table) RemoveChains(chains []*generictables.Chain)
- func (t *Table) UnexpectedInsertsSeen() int
- func (t *Table) UpdateChain(chain *generictables.Chain)
- func (t *Table) UpdateChains(chains []*generictables.Chain)
- type TableOptions
Constants ¶
const (
MaxChainNameLength = 28
)
Variables ¶
var ( Err14LockTimeout = errors.New("Timed out waiting for iptables 1.4 lock") Err16LockTimeout = errors.New("Timed out waiting for iptables 1.6 lock") )
var Wildcard string = "+"
Functions ¶
func Actions ¶
func Actions() generictables.ActionFactory
func CalculateRuleHashes ¶
func CalculateRuleHashes(chainName string, rules []generictables.Rule, features *environment.Features) []string
func GrabIptablesLocks ¶
func Match ¶
func Match() generictables.MatchCriteria
func PortRangesToMultiport ¶
func PortsToMultiport ¶
Types ¶
type AcceptAction ¶
type AcceptAction struct {
TypeAccept struct{}
}
func (AcceptAction) String ¶
func (g AcceptAction) String() string
func (AcceptAction) ToFragment ¶
func (g AcceptAction) ToFragment(features *environment.Features) string
type ClearMarkAction ¶
type ClearMarkAction struct { Mark uint32 TypeClearMark struct{} }
func (ClearMarkAction) String ¶
func (c ClearMarkAction) String() string
func (ClearMarkAction) ToFragment ¶
func (c ClearMarkAction) ToFragment(features *environment.Features) string
type DNATAction ¶
func (DNATAction) String ¶
func (g DNATAction) String() string
func (DNATAction) ToFragment ¶
func (g DNATAction) ToFragment(features *environment.Features) string
type DropAction ¶
type DropAction struct {
TypeDrop struct{}
}
func (DropAction) String ¶
func (g DropAction) String() string
func (DropAction) ToFragment ¶
func (g DropAction) ToFragment(features *environment.Features) string
type GotoAction ¶
type GotoAction struct { Target string TypeGoto struct{} }
func (GotoAction) ReferencedChain ¶
func (g GotoAction) ReferencedChain() string
func (GotoAction) String ¶
func (g GotoAction) String() string
func (GotoAction) ToFragment ¶
func (g GotoAction) ToFragment(features *environment.Features) string
type IptablesRenderer ¶
type IptablesRenderer interface { generictables.RuleHasher RenderAppend(rule *generictables.Rule, chainName, hash string, features *environment.Features) string RenderInsert(rule *generictables.Rule, chainName, hash string, features *environment.Features) string RenderInsertAtRuleNumber(rule *generictables.Rule, chainName string, ruleNum int, hash string, features *environment.Features) string RenderReplace(rule *generictables.Rule, chainName string, ruleNum int, hash string, features *environment.Features) string }
func NewIptablesRenderer ¶
func NewIptablesRenderer(hashCommentPrefix string) IptablesRenderer
type JumpAction ¶
type JumpAction struct { Target string TypeJump struct{} }
func (JumpAction) ReferencedChain ¶
func (g JumpAction) ReferencedChain() string
func (JumpAction) String ¶
func (g JumpAction) String() string
func (JumpAction) ToFragment ¶
func (g JumpAction) ToFragment(features *environment.Features) string
type LogAction ¶
type LogAction struct { Prefix string TypeLog struct{} }
func (LogAction) ToFragment ¶
func (g LogAction) ToFragment(features *environment.Features) string
type MasqAction ¶
type MasqAction struct { ToPorts string TypeMasq struct{} }
func (MasqAction) String ¶
func (g MasqAction) String() string
func (MasqAction) ToFragment ¶
func (g MasqAction) ToFragment(features *environment.Features) string
type NoTrackAction ¶
type NoTrackAction struct {
TypeNoTrack struct{}
}
func (NoTrackAction) String ¶
func (g NoTrackAction) String() string
func (NoTrackAction) ToFragment ¶
func (g NoTrackAction) ToFragment(features *environment.Features) string
type RejectAction ¶
type RejectAction struct { TypeReject struct{} With generictables.RejectWith }
func (RejectAction) String ¶
func (g RejectAction) String() string
func (RejectAction) ToFragment ¶
func (g RejectAction) ToFragment(features *environment.Features) string
type RestoreConnMarkAction ¶
type RestoreConnMarkAction struct { RestoreMask uint32 TypeConnMark struct{} }
func (RestoreConnMarkAction) String ¶
func (c RestoreConnMarkAction) String() string
func (RestoreConnMarkAction) ToFragment ¶
func (c RestoreConnMarkAction) ToFragment(features *environment.Features) string
type RestoreInputBuilder ¶
type RestoreInputBuilder struct { NumLinesWritten counter // contains filtered or unexported fields }
RestoreInputBuilder builds a byte slice for use as input to iptables-restore.
Operations must be done inside a per-table transaction.
Example:
buf.Reset() // Reset the buffer, if needed. buf.StartTransaction("filter") buf.WriteForwardReference("cali-chain-name") buf.WriteLine("-A cali-chain-name ...") buf.EndTransaction() bytes = buf.GetBytesAndReset() <write bytes to iptables-restore stdin>
Transactions are ignored completely if there are no writes between the StartTransaction() and EndTransaction() calls.
func (*RestoreInputBuilder) Empty ¶
func (b *RestoreInputBuilder) Empty() bool
Empty returns true if there is nothing in the buffer (i.e. all the transactions stored in the buffer were no-ops).
func (*RestoreInputBuilder) EndTransaction ¶
func (b *RestoreInputBuilder) EndTransaction()
EndTransaction ends the open transaction, if the transaction was non-empty, writes a COMMIT. Resets the transaction tracking state. Panics if there was no open transaction.
func (*RestoreInputBuilder) GetBytesAndReset ¶
func (b *RestoreInputBuilder) GetBytesAndReset() []byte
GetBytesAndReset returns the contents of the buffer and, as a side effect, resets the buffer. For performance, this is a direct reference to the data rather than a copy. The returned slice is only valid until the next write operation on the builder. Should be called after EndTransaction; panics if there is a still-open transaction.
func (*RestoreInputBuilder) Reset ¶
func (b *RestoreInputBuilder) Reset()
Reset the builder completely, any pending transaction is discarded.
func (*RestoreInputBuilder) StartTransaction ¶
func (b *RestoreInputBuilder) StartTransaction(tableName string)
StartTransaction opens a new transaction context for the named table. Panics if there is already a transaction in progress.
func (*RestoreInputBuilder) WriteForwardReference ¶
func (b *RestoreInputBuilder) WriteForwardReference(chainName string)
WriteForwardReference writes a "forward reference" for the given chain name. A forward reference is an instruction that tells iptables to ensure that the given chain exists and that it is empty. Panics if there is no open transaction.
func (*RestoreInputBuilder) WriteLine ¶
func (b *RestoreInputBuilder) WriteLine(line string)
WriteLine writes a line of iptables instructions to the buffer. Intended for writing the actual rules. Panics if there is no open transaction.
type ReturnAction ¶
type ReturnAction struct {
TypeReturn struct{}
}
func (ReturnAction) IsReturnAction ¶
func (r ReturnAction) IsReturnAction()
func (ReturnAction) String ¶
func (r ReturnAction) String() string
func (ReturnAction) ToFragment ¶
func (r ReturnAction) ToFragment(features *environment.Features) string
type SNATAction ¶
type SNATAction struct { ToAddr string TypeSNAT struct{} }
func (SNATAction) String ¶
func (g SNATAction) String() string
func (SNATAction) ToFragment ¶
func (g SNATAction) ToFragment(features *environment.Features) string
type SaveConnMarkAction ¶
type SaveConnMarkAction struct { SaveMask uint32 TypeConnMark struct{} }
func (SaveConnMarkAction) String ¶
func (c SaveConnMarkAction) String() string
func (SaveConnMarkAction) ToFragment ¶
func (c SaveConnMarkAction) ToFragment(features *environment.Features) string
type SetConnMarkAction ¶
func (SetConnMarkAction) String ¶
func (c SetConnMarkAction) String() string
func (SetConnMarkAction) ToFragment ¶
func (c SetConnMarkAction) ToFragment(features *environment.Features) string
type SetMarkAction ¶
type SetMarkAction struct { Mark uint32 TypeSetMark struct{} }
func (SetMarkAction) String ¶
func (c SetMarkAction) String() string
func (SetMarkAction) ToFragment ¶
func (c SetMarkAction) ToFragment(features *environment.Features) string
type SetMaskedMarkAction ¶
func (SetMaskedMarkAction) String ¶
func (c SetMaskedMarkAction) String() string
func (SetMaskedMarkAction) ToFragment ¶
func (c SetMaskedMarkAction) ToFragment(features *environment.Features) string
type SharedLock ¶
type SharedLock struct { // contains filtered or unexported fields }
SharedLock allows for multiple goroutines to share the iptables lock without blocking on each other. That is safe because each of our goroutines is accessing a different iptables table, so they do not conflict.
func NewSharedLock ¶
func NewSharedLock(lockFilePath string, lockTimeout, lockProbeInterval time.Duration) *SharedLock
func (*SharedLock) Lock ¶
func (l *SharedLock) Lock()
func (*SharedLock) Unlock ¶
func (l *SharedLock) Unlock()
type Table ¶
type Table struct {
// contains filtered or unexported fields
}
Table represents a single one of the iptables tables i.e. "raw", "nat", "filter", etc. It caches the desired state of that table, then attempts to bring it into sync when Apply() is called.
API Model ¶
Table supports two classes of operation: "rule insertions" and "full chain updates".
As the name suggests, rule insertions allow for inserting one or more rules into a preexisting chain. Rule insertions are intended to be used to hook kernel chains (such as "FORWARD") in order to direct them to a Felix-owned chain. It is important to minimise the use of rule insertions because the top-level chains are shared resources, which can be modified by other applications. In addition, rule insertions are harder to clean up after an upgrade to a new version of Felix (because we need a way to recognise our rules in a crowded chain).
Full chain updates replace the entire contents of a Felix-owned chain with a new set of rules. Limiting the operation to "replace whole chain" in this way significantly simplifies the API. Although the API operates on full chains, the dataplane write logic tries to avoid rewriting a whole chain if only part of it has changed (this was not the case in Felix 1.4). This prevents iptables counters from being reset unnecessarily.
In either case, the actual dataplane updates are deferred until the next call to Apply() so chain updates and insertions may occur in any order as long as they are consistent (i.e. there are no references to nonexistent chains) by the time Apply() is called.
Design ¶
We had several goals in designing the iptables machinery in 2.0.0:
(1) High performance. Felix needs to handle high churn of endpoints and rules.
(2) Ability to restore rules, even if other applications accidentally break them: we found that other applications sometimes misuse iptables-save and iptables-restore to do a read, modify, write cycle. That behaviour is not safe under concurrent modification.
(3) Avoid rewriting rules that haven't changed so that we don't reset iptables counters.
(4) Avoid parsing iptables commands (for example, the output from iptables/iptables-save). This is very hard to do robustly because iptables rules do not necessarily round-trip through the kernel in the same form. In addition, the format could easily change due to changes or fixes in the iptables/iptables-save command.
(5) Support for graceful restart. I.e. deferring potentially incorrect updates until we're in-sync with the datastore. For example, if we have 100 endpoints on a host, after a restart we don't want to write a "dispatch" chain when we learn about the first endpoint (possibly replacing an existing one that had all 100 endpoints in place and causing traffic to glitch); instead, we want to defer until we've seen all 100 and then do the write.
(6) Improved handling of rule inserts vs Felix 1.4.x. Previous versions of Felix sometimes inserted special-case rules that were not marked as Calico rules in any sensible way making cleanup of those rules after an upgrade difficult.
Implementation ¶
For high performance (goal 1), we use iptables-restore to do bulk updates to iptables. This is much faster than individual iptables calls.
To allow us to restore rules after they are clobbered by another process (goal 2), we cache them at this layer. This means that we don't need a mechanism to ask the other layers of Felix to do a resync. Note: Table doesn't start a thread of its own so it relies on the main event loop to trigger any dataplane resync polls.
There is tension between goals 3 and 4. In order to avoid full rewrites (goal 3), we need to know what rules are in place, but we also don't want to parse them to find out (goal 4)! As a compromise, we deterministically calculate an ID for each rule and store it in an iptables comment. Then, when we want to know what rules are in place, we _do_ parse the output from iptables-save, but only to read back the rule IDs. That limits the amount of parsing we need to do and keeps it manageable/robust.
To support graceful restart (goal 5), we defer updates to the dataplane until Apply() is called, then we do an atomic update using iptables-restore. As long as the first Apply() call is after we're in sync, the dataplane won't be touched until the right time. Felix 1.4.x had a more complex mechanism to support partial updates during the graceful restart period but Felix 2.0.0 resyncs so quickly that the added complexity is not justified.
To make it easier to manage rule insertions (goal 6), we add rule IDs to those too. With rule IDs in place, we can easily distinguish Calico rules from non-Calico rules without needing to know exactly which rules to expect. To deal with cleanup after upgrade from older versions that did not write rule IDs, we support special-case regexes to detect our old rules.
Thread safety ¶
Table doesn't do any internal synchronization, its methods should only be called from one thread. To avoid conflicts in the dataplane itself, there should only be one instance of Table for each iptable table in an application.
func NewTable ¶
func NewTable( name string, ipVersion uint8, hashPrefix string, iptablesWriteLock sync.Locker, featureDetector environment.FeatureDetectorIface, options TableOptions, ) *Table
func (*Table) AppendRules ¶
func (t *Table) AppendRules(chainName string, rules []generictables.Rule)
AppendRules sets the rules to be appended to a given non-Calico chain. These rules are always appended, even if chain insert mode is "insert". If chain insert mode is "append", these rules are appended after any rules added with InsertOrAppendRules.
func (*Table) CheckRulesPresent ¶
func (t *Table) CheckRulesPresent(chain string, rules []generictables.Rule) []generictables.Rule
CheckRulesPresent returns list of rules with the hashes that are already programmed. Return value of nil means that none of the rules are present.
func (*Table) InsertOrAppendRules ¶
func (t *Table) InsertOrAppendRules(chainName string, rules []generictables.Rule)
InsertOrAppendRules sets the rules that should be inserted into or appended to the given non-Calico chain (depending on the chain insert mode). See also AppendRules, which can be used to record additional rules that are always appended.
func (*Table) InsertRulesNow ¶
func (t *Table) InsertRulesNow(chain string, rules []generictables.Rule) error
InsertRulesNow insets the given rules immediately without removing or syncing other rules. This is primarily useful when bootstrapping and we cannot wait until we have the full state.
func (*Table) InvalidateDataplaneCache ¶
func (*Table) RemoveChainByName ¶
func (*Table) RemoveChains ¶
func (t *Table) RemoveChains(chains []*generictables.Chain)
func (*Table) UnexpectedInsertsSeen ¶
func (*Table) UpdateChain ¶
func (t *Table) UpdateChain(chain *generictables.Chain)
func (*Table) UpdateChains ¶
func (t *Table) UpdateChains(chains []*generictables.Chain)
type TableOptions ¶
type TableOptions struct { HistoricChainPrefixes []string ExtraCleanupRegexPattern string BackendMode string InsertMode string RefreshInterval time.Duration PostWriteInterval time.Duration // LockTimeout is the timeout to use for iptables-restore's native xtables lock. LockTimeout time.Duration // LockProbeInterval is the probe interval to use for iptables-restore's native xtables lock. LockProbeInterval time.Duration // NewCmdOverride for tests, if non-nil, factory to use instead of the real exec.Command() NewCmdOverride cmdshim.CmdFactory // SleepOverride for tests, if non-nil, replacement for time.Sleep() SleepOverride func(d time.Duration) // NowOverride for tests, if non-nil, replacement for time.Now() NowOverride func() time.Time // LookPathOverride for tests, if non-nil, replacement for exec.LookPath() LookPathOverride func(file string) (string, error) // Thunk to call periodically when doing a long-running operation. OnStillAlive func() // OpRecorder to tell when we do resyncs etc. OpRecorder logutils.OpRecorder }