Documentation
¶
Index ¶
- Constants
- Variables
- type ClassView
- func (cv *ClassView) Apply() error
- func (cv *ClassView) Index() int
- func (cv *ClassView) OnIfaceStateChanged(name string, ifIndex int, state ifacemonitor.State)
- func (cv *ClassView) QueueResync()
- func (cv *ClassView) QueueResyncIface(ifaceName string)
- func (cv *ClassView) ReadRoutesFromKernel(ifaceName string) ([]Target, error)
- func (cv *ClassView) RouteRemove(ifaceName string, cidr ip.CIDR)
- func (cv *ClassView) RouteUpdate(ifaceName string, target Target)
- func (cv *ClassView) SetRoutes(ifaceName string, targets []Target)
- type ConntrackCleanupManager
- func (c *ConntrackCleanupManager) CIDRNeedsEarlyCleanup(cidr ip.CIDR, oldIface int) bool
- func (c *ConntrackCleanupManager) OnDataplaneRouteDeleted(cidr ip.CIDR, ifindex int)
- func (c *ConntrackCleanupManager) RemoveCIDROwner(cidr ip.CIDR)
- func (c *ConntrackCleanupManager) StartConntrackCleanupAndReset()
- func (c *ConntrackCleanupManager) UpdateCIDROwner(cidr ip.CIDR, ifaceIdx int, routeClass RouteClass)
- func (c *ConntrackCleanupManager) WaitForPendingDeletion(cidr ip.CIDR)
- type DummyTable
- func (_ *DummyTable) Apply() error
- func (_ *DummyTable) Index() int
- func (_ *DummyTable) OnIfaceStateChanged(_ string, _ int, _ ifacemonitor.State)
- func (_ *DummyTable) QueueResync()
- func (_ *DummyTable) QueueResyncIface(string)
- func (_ *DummyTable) ReadRoutesFromKernel(ifaceName string) ([]Target, error)
- func (_ *DummyTable) RouteRemove(routeClass RouteClass, ifaceName string, cidr ip.CIDR)
- func (_ *DummyTable) RouteUpdate(routeClass RouteClass, ifaceName string, target Target)
- func (_ *DummyTable) SetRemoveExternalRoutes(b bool)
- func (_ *DummyTable) SetRoutes(routeClass RouteClass, ifaceName string, targets []Target)
- type Interface
- type NextHop
- type NoOpRouteTracker
- func (n NoOpRouteTracker) CIDRNeedsEarlyCleanup(cidr ip.CIDR, ifindex int) bool
- func (n NoOpRouteTracker) OnDataplaneRouteDeleted(cidr ip.CIDR, ifindex int)
- func (n NoOpRouteTracker) RemoveCIDROwner(addr ip.CIDR)
- func (n NoOpRouteTracker) StartConntrackCleanupAndReset()
- func (n NoOpRouteTracker) UpdateCIDROwner(addr ip.CIDR, ifaceIdx int, routeClass RouteClass)
- func (n NoOpRouteTracker) WaitForPendingDeletion(cidr ip.CIDR)
- type Opt
- func WithConntrackCleanup(enabled bool) Opt
- func WithConntrackShim(shim conntrackIface) Opt
- func WithLivenessCB(cb func()) Opt
- func WithNetlinkHandleShim(newNetlinkHandle func() (netlinkshim.Interface, error)) Opt
- func WithRouteCleanupGracePeriod(routeCleanupGracePeriod time.Duration) Opt
- func WithStaticARPEntries(b bool) Opt
- func WithTimeShim(shim timeshim.Interface) Opt
- type OwnershipPolicy
- type RouteClass
- type RouteOwnershipTracker
- type RouteTable
- func (r *RouteTable) Apply() (err error)
- func (r *RouteTable) Index() int
- func (r *RouteTable) OnIfaceStateChanged(ifaceName string, ifIndex int, state ifacemonitor.State)
- func (r *RouteTable) QueueResync()
- func (r *RouteTable) QueueResyncIface(ifaceName string)
- func (r *RouteTable) ReadRoutesFromKernel(ifaceName string) ([]Target, error)
- func (r *RouteTable) RouteRemove(routeClass RouteClass, ifaceName string, cidr ip.CIDR)
- func (r *RouteTable) RouteUpdate(routeClass RouteClass, ifaceName string, target Target)
- func (r *RouteTable) SetRemoveExternalRoutes(b bool)
- func (r *RouteTable) SetRoutes(routeClass RouteClass, ifaceName string, targets []Target)
- type SyncerInterface
- type Target
- type TargetType
Constants ¶
const (
// Use this for targets with no outbound interface.
InterfaceNone = "*NoOIF*"
)
Variables ¶
Functions ¶
This section is empty.
Types ¶
type ClassView ¶
type ClassView struct {
// contains filtered or unexported fields
}
ClassView wraps a RouteTable with a simplified API that removes the need to pass the RouteClass to each method.
func NewClassView ¶
func NewClassView(class RouteClass, routeTable Interface) *ClassView
func (*ClassView) OnIfaceStateChanged ¶
func (cv *ClassView) OnIfaceStateChanged(name string, ifIndex int, state ifacemonitor.State)
func (*ClassView) QueueResync ¶
func (cv *ClassView) QueueResync()
func (*ClassView) QueueResyncIface ¶
func (*ClassView) ReadRoutesFromKernel ¶
func (*ClassView) RouteUpdate ¶
type ConntrackCleanupManager ¶
type ConntrackCleanupManager struct {
// contains filtered or unexported fields
}
ConntrackCleanupManager handles cleaning up conntrack entries on behalf of a RouteTable when routes are moved or deleted . It:
Uses a DeltaTracker to track which interfaces the RouteTable has told us own which IP addresses. We assume that the RouteTable only allows one route per CIDR (even though it understands how to clean up routes for other ToS and priority values).
Expects a callback from the RouteTable when a route is deleted.
Uses the interface index and route class on that callback to decide if the route being deleted needs a conntrack cleanup.
Provides a lookup function to check if an updated route needs a cleanup.
Updates that don't change the interface index don't need cleanup.
Updates from remote to remote don't need cleanup. For example, a route moving from VXLAN to VXLAN-same-subnet.
Updates where there was no previous route don't need cleanup.
A complicating factor is that the kernel keys routes using CIDR, ToS and priority whereas conntrack entries are keyed on 5-tuple only. We sidestep that by assuming the RouteTable only allows one route per CIDR in its final state. [Shaun] I tried to handle multiple routes per CIDR, but the complexity spiralled, and it wasn't clear what should be done in a lot of the corner cases. I'm hoping that, should we add function that uses multiple ToSes or priorities, the right way to handle conflicts will be clear at that time!
func NewConntrackCleanupManager ¶
func NewConntrackCleanupManager(ipVersion uint8, conntrack conntrackIface) *ConntrackCleanupManager
func (*ConntrackCleanupManager) CIDRNeedsEarlyCleanup ¶
func (c *ConntrackCleanupManager) CIDRNeedsEarlyCleanup(cidr ip.CIDR, oldIface int) bool
CIDRNeedsEarlyCleanup is called by the RouteTable to check if a route should be deleted early, to allow for conntrack cleanup to be properly sequenced.
func (*ConntrackCleanupManager) OnDataplaneRouteDeleted ¶
func (c *ConntrackCleanupManager) OnDataplaneRouteDeleted(cidr ip.CIDR, ifindex int)
OnDataplaneRouteDeleted is called when the RouteTable tells us that a route has been removed from the dataplane on the given interface. In most cases, this will queue the CIDR for conntrack cleanup at the next call to StartConntrackCleanupAndReset.
No cleanup is triggered if there is a desired route for the given CIDR and that desired route is staying on this interface.
func (*ConntrackCleanupManager) RemoveCIDROwner ¶
func (c *ConntrackCleanupManager) RemoveCIDROwner(cidr ip.CIDR)
RemoveCIDROwner is called when there is no longer an owner for the given CIDR. Like UpdateCIDROwner, it updates the "desired" next state so a call to UpdateCIDROwner for the same CIDR before the cleanup is triggered will undo the removal.
func (*ConntrackCleanupManager) StartConntrackCleanupAndReset ¶
func (c *ConntrackCleanupManager) StartConntrackCleanupAndReset()
StartConntrackCleanupAndReset starts all pending conntrack cleanups and resets the tracker to prepare for the next round of updates.
func (*ConntrackCleanupManager) UpdateCIDROwner ¶
func (c *ConntrackCleanupManager) UpdateCIDROwner(cidr ip.CIDR, ifaceIdx int, routeClass RouteClass)
UpdateCIDROwner is called when the new owner of a CIDR is calculated. It updates the "desired" next state, so multiple calls for the same CIDR are effectively coalesced; only the most recent update is remembered. the actual cleanup is triggered later by calls to OnDataplaneRouteDeleted and StartConntrackCleanupAndReset.
func (*ConntrackCleanupManager) WaitForPendingDeletion ¶
func (c *ConntrackCleanupManager) WaitForPendingDeletion(cidr ip.CIDR)
WaitForPendingDeletion waits for any pending conntrack deletions (if any) for the given IP to complete. Returns immediately if there's no pending deletion.
type DummyTable ¶
type DummyTable struct { }
func (*DummyTable) Apply ¶
func (_ *DummyTable) Apply() error
func (*DummyTable) Index ¶
func (_ *DummyTable) Index() int
func (*DummyTable) OnIfaceStateChanged ¶
func (_ *DummyTable) OnIfaceStateChanged(_ string, _ int, _ ifacemonitor.State)
func (*DummyTable) QueueResync ¶
func (_ *DummyTable) QueueResync()
func (*DummyTable) QueueResyncIface ¶
func (_ *DummyTable) QueueResyncIface(string)
func (*DummyTable) ReadRoutesFromKernel ¶
func (_ *DummyTable) ReadRoutesFromKernel(ifaceName string) ([]Target, error)
func (*DummyTable) RouteRemove ¶
func (_ *DummyTable) RouteRemove(routeClass RouteClass, ifaceName string, cidr ip.CIDR)
func (*DummyTable) RouteUpdate ¶
func (_ *DummyTable) RouteUpdate(routeClass RouteClass, ifaceName string, target Target)
func (*DummyTable) SetRemoveExternalRoutes ¶
func (_ *DummyTable) SetRemoveExternalRoutes(b bool)
func (*DummyTable) SetRoutes ¶
func (_ *DummyTable) SetRoutes(routeClass RouteClass, ifaceName string, targets []Target)
type Interface ¶
type Interface interface { SyncerInterface SetRoutes(routeClass RouteClass, ifaceName string, targets []Target) RouteRemove(routeClass RouteClass, ifaceName string, cidr ip.CIDR) RouteUpdate(routeClass RouteClass, ifaceName string, target Target) Index() int QueueResyncIface(ifaceName string) ReadRoutesFromKernel(ifaceName string) ([]Target, error) }
Interface is the interface provided by the standard routetable module used to program the RIB.
type NoOpRouteTracker ¶
type NoOpRouteTracker struct { }
NoOpRouteTracker is a dummy implementation of RouteOwnershipTracker that does nothing.
func NewNoOpRouteTracker ¶
func NewNoOpRouteTracker() NoOpRouteTracker
func (NoOpRouteTracker) CIDRNeedsEarlyCleanup ¶
func (n NoOpRouteTracker) CIDRNeedsEarlyCleanup(cidr ip.CIDR, ifindex int) bool
func (NoOpRouteTracker) OnDataplaneRouteDeleted ¶
func (n NoOpRouteTracker) OnDataplaneRouteDeleted(cidr ip.CIDR, ifindex int)
func (NoOpRouteTracker) RemoveCIDROwner ¶
func (n NoOpRouteTracker) RemoveCIDROwner(addr ip.CIDR)
func (NoOpRouteTracker) StartConntrackCleanupAndReset ¶
func (n NoOpRouteTracker) StartConntrackCleanupAndReset()
func (NoOpRouteTracker) UpdateCIDROwner ¶
func (n NoOpRouteTracker) UpdateCIDROwner(addr ip.CIDR, ifaceIdx int, routeClass RouteClass)
func (NoOpRouteTracker) WaitForPendingDeletion ¶
func (n NoOpRouteTracker) WaitForPendingDeletion(cidr ip.CIDR)
type Opt ¶
type Opt func(table *RouteTable)
func WithConntrackCleanup ¶
func WithConntrackShim ¶
func WithConntrackShim(shim conntrackIface) Opt
func WithLivenessCB ¶
func WithLivenessCB(cb func()) Opt
func WithNetlinkHandleShim ¶
func WithNetlinkHandleShim(newNetlinkHandle func() (netlinkshim.Interface, error)) Opt
func WithStaticARPEntries ¶
func WithTimeShim ¶
type OwnershipPolicy ¶
type OwnershipPolicy interface { RouteIsOurs(ifaceName string, route *netlink.Route) bool IfaceIsOurs(ifaceName string) bool IfaceShouldHaveARPEntries(ifaceName string) bool IfaceShouldHaveGracePeriod(ifaceName string) bool }
OwnershipPolicy is used to determine whether a given interface or route belongs to Calico. Routes that are loaded from the kernel are checked against this policy to determine if they should be tracked. The RouteTable cleans up tracked routes that don't match the current datastore state.
The policy is also used to determine whether an interface should be tracked or not. If an interface is not tracked then the RouteTable will not be able to program routes for it, and it will not respond to interface state updates. This is mainly a performance optimisation for our non-main routing tables which tend to be used to manage routes for a single device.
type RouteClass ¶
type RouteClass int
RouteClass is a type used to identify the different groups of routes that we program. It is used as a tie-breaker when there are conflicting routes for the same CIDR (lowest numeric value wins).
const ( RouteClassLocalWorkload RouteClass = iota RouteClassBPFSpecial RouteClassWireguard RouteClassVXLANSameSubnet RouteClassVXLANTunnel RouteClassIPAMBlockDrop RouteClassMax )
func (RouteClass) IsRemote ¶
func (c RouteClass) IsRemote() bool
func (RouteClass) String ¶
func (i RouteClass) String() string
type RouteOwnershipTracker ¶
type RouteOwnershipTracker interface { UpdateCIDROwner(addr ip.CIDR, ifaceIdx int, routeClass RouteClass) RemoveCIDROwner(addr ip.CIDR) CIDRNeedsEarlyCleanup(cidr ip.CIDR, oldIface int) bool OnDataplaneRouteDeleted(cidr ip.CIDR, ifindex int) StartConntrackCleanupAndReset() WaitForPendingDeletion(cidr ip.CIDR) }
type RouteTable ¶
type RouteTable struct {
// contains filtered or unexported fields
}
RouteTable manages the Calico routes for a specific kernel routing table.
There are several complicating factors to managing the routes and all of these have caused real problems in the past:
There is more than one Felix subcomponent that needs to program routes, often into the same table. It is possible for different components to try to program conflicting routes for the same CIDR (for example, if a local and remote endpoint share the same IP address). To deal with this we assign a RouteClass to each potential source of routes and break ties on that value.
Most Calico components only deal with CIDRs and interfaces, but the kernel routing table is indexed by CIDR, metric and ToS field. To handle this difference in indexing, we use a DeltaTracker indexed in a way that matches the kernel's indexing. That allows us to correctly clean up any kernel routes that would alias if we only considered CIDR.
We need to translate interface name to interface index and that mapping can change over time. Interfaces can be renamed, keeping the same index. Interfaces can be recreated, keeping the same name but getting a new index. We handle this by indexing the routes we've been told to create on interface name and by listening for interface state changes. When an interface is updated, we re-calculate the routes that we want to program for it and re-do conflict resolution.
We can race with the interface monitor goroutine, being asked to program a route before we've heard about the interface, or spotting a new interface index when we do a read back of routes from the kernel.
The CNI plugin also programs the same routes that we do, so we can race with it as well. We may see an interface pop up with a route before we hear about the corresponding WorkloadEndpoint. To deal with that, we implement a grace period before deleting routes that belong to us but that we don't know about yet.
When IP addresses move from one interface to another (for example because a workload has been terminated and a new workload now has the IP) we need to clean up the conntrack entries from the old workload. We delegate this cleanup to the RouteOwnershipTracker; giving it callbacks when routes move. We do that cleanup in the background to avoid holding up other route programming.
func New ¶
func New( ownershipPolicy OwnershipPolicy, ipVersion uint8, netlinkTimeout time.Duration, deviceRouteSourceAddress net.IP, defaultRouteProtocol netlink.RouteProtocol, removeExternalRoutes bool, tableIndex int, opReporter logutils.OpRecorder, featureDetector environment.FeatureDetectorIface, opts ...Opt, ) *RouteTable
func (*RouteTable) Apply ¶
func (r *RouteTable) Apply() (err error)
func (*RouteTable) Index ¶
func (r *RouteTable) Index() int
func (*RouteTable) OnIfaceStateChanged ¶
func (r *RouteTable) OnIfaceStateChanged(ifaceName string, ifIndex int, state ifacemonitor.State)
func (*RouteTable) QueueResync ¶
func (r *RouteTable) QueueResync()
func (*RouteTable) QueueResyncIface ¶
func (r *RouteTable) QueueResyncIface(ifaceName string)
func (*RouteTable) ReadRoutesFromKernel ¶
func (r *RouteTable) ReadRoutesFromKernel(ifaceName string) ([]Target, error)
ReadRoutesFromKernel offers partial support for reading back routes from the kernel. In particular, it assumes that "onlink" routes are VXLAN routes, which is lossy. Currently, this is only used in Enterprise, where the routes it needs to read are VXLAN routes.
func (*RouteTable) RouteRemove ¶
func (r *RouteTable) RouteRemove(routeClass RouteClass, ifaceName string, cidr ip.CIDR)
RouteRemove removes the route with the specified CIDR. These deltas will be applied to any routes set using SetRoute.
func (*RouteTable) RouteUpdate ¶
func (r *RouteTable) RouteUpdate(routeClass RouteClass, ifaceName string, target Target)
RouteUpdate updates the route keyed off the target CIDR. These deltas will be applied to any routes set using SetRoute.
func (*RouteTable) SetRemoveExternalRoutes ¶
func (r *RouteTable) SetRemoveExternalRoutes(b bool)
func (*RouteTable) SetRoutes ¶
func (r *RouteTable) SetRoutes(routeClass RouteClass, ifaceName string, targets []Target)
SetRoutes replaces the full set of targets for the specified interface.
type SyncerInterface ¶
type SyncerInterface interface { OnIfaceStateChanged(name string, ifIndex int, state ifacemonitor.State) QueueResync() Apply() error }
SyncerInterface is the interface used to manage data-sync of route table managers. This includes notification of interface state changes, hooks to queue a full resync and apply routing updates.
type Target ¶
type Target struct { Type TargetType CIDR ip.CIDR GW ip.Addr Src ip.Addr DestMAC net.HardwareAddr Protocol netlink.RouteProtocol MultiPath []NextHop }
func (Target) Flags ¶
func (t Target) Flags() netlink.NextHopFlag
func (Target) RouteScope ¶
type TargetType ¶
type TargetType string
const ( TargetTypeLocal TargetType = "local" TargetTypeVXLAN TargetType = "vxlan" TargetTypeNoEncap TargetType = "noencap" TargetTypeOnLink TargetType = "onlink" TargetTypeGlobalUnicast TargetType = "global-unicast" TargetTypeLinkLocalUnicast TargetType = "local-unicast" TargetTypeBlackhole TargetType = "blackhole" TargetTypeProhibit TargetType = "prohibit" TargetTypeThrow TargetType = "throw" TargetTypeUnreachable TargetType = "unreachable" )