mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Cleanup the multicast routing table.
This change does the following: - Uses shared types for the route key and multicast route. - Returns a bool instead of error from GetRouteOrInsertPending since only one error type is possible. - Improves the naming of PendingRouteState using the suggestions in cl/445157188. Updates #7338. PiperOrigin-RevId: 449812803
This commit is contained in:
@@ -32,6 +32,7 @@ import (
|
||||
|
||||
const (
|
||||
defaultMinTTL = 10
|
||||
defaultMTU = 1500
|
||||
inputNICID tcpip.NICID = 1
|
||||
outgoingNICID tcpip.NICID = 2
|
||||
)
|
||||
@@ -39,8 +40,9 @@ const (
|
||||
// Example shows how to interact with a multicast RouteTable.
|
||||
func Example() {
|
||||
address := testutil.MustParse4("192.168.1.1")
|
||||
defaultOutgoingInterfaces := []multicast.OutgoingInterface{{ID: outgoingNICID, MinTTL: defaultMinTTL}}
|
||||
routeKey := multicast.RouteKey{UnicastSource: address, MulticastDestination: address}
|
||||
defaultOutgoingInterfaces := []stack.MulticastRouteOutgoingInterface{{ID: outgoingNICID, MinTTL: defaultMinTTL}}
|
||||
routeKey := stack.UnicastSourceAndMulticastDestination{Source: address, Destination: address}
|
||||
multicastRoute := stack.MulticastRoute{inputNICID, defaultOutgoingInterfaces}
|
||||
|
||||
pkt := newPacketBuffer("hello")
|
||||
defer pkt.DecRef()
|
||||
@@ -59,34 +61,30 @@ func Example() {
|
||||
|
||||
// Each entry in the table represents either an installed route or a pending
|
||||
// route. To insert a pending route, call:
|
||||
result, err := table.GetRouteOrInsertPending(routeKey, pkt)
|
||||
result, hasBufferSpace := table.GetRouteOrInsertPending(routeKey, pkt)
|
||||
|
||||
// Callers should handle a no buffer space error (e.g. only deliver the
|
||||
// packet locally).
|
||||
if err == multicast.ErrNoBufferSpace {
|
||||
if !hasBufferSpace {
|
||||
deliverPktLocally(pkt)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Callers should handle the various pending route states.
|
||||
switch result.PendingRouteState {
|
||||
case multicast.PendingRouteStateNone:
|
||||
switch result.GetRouteResultState {
|
||||
case multicast.InstalledRouteFound:
|
||||
// The packet can be forwarded using the installed route.
|
||||
forwardPkt(pkt, result.InstalledRoute)
|
||||
case multicast.PendingRouteStateInstalled:
|
||||
case multicast.NoRouteFoundAndPendingInserted:
|
||||
// The route has just entered the pending state.
|
||||
emitMissingRouteEvent(routeKey)
|
||||
deliverPktLocally(pkt)
|
||||
case multicast.PendingRouteStateAppended:
|
||||
case multicast.PacketQueuedInPendingRoute:
|
||||
// The route was already in the pending state.
|
||||
deliverPktLocally(pkt)
|
||||
}
|
||||
|
||||
// To transition a pending route to the installed state, call:
|
||||
route := table.NewInstalledRoute(inputNICID, defaultOutgoingInterfaces)
|
||||
route := table.NewInstalledRoute(multicastRoute)
|
||||
pendingPackets := table.AddInstalledRoute(routeKey, route)
|
||||
|
||||
// If there was a pending route, then the caller is responsible for
|
||||
@@ -121,7 +119,7 @@ func forwardPkt(*stack.PacketBuffer, *multicast.InstalledRoute) {
|
||||
fmt.Println("forwardPkt")
|
||||
}
|
||||
|
||||
func emitMissingRouteEvent(multicast.RouteKey) {
|
||||
func emitMissingRouteEvent(stack.UnicastSourceAndMulticastDestination) {
|
||||
fmt.Println("emitMissingRouteEvent")
|
||||
}
|
||||
|
||||
|
||||
@@ -47,11 +47,11 @@ type RouteTable struct {
|
||||
// Maintaining pointers ensures that the installed routes are exclusively
|
||||
// locked only when a route is being installed.
|
||||
// +checklocks:installedMu
|
||||
installedRoutes map[RouteKey]*InstalledRoute
|
||||
installedRoutes map[stack.UnicastSourceAndMulticastDestination]*InstalledRoute
|
||||
|
||||
pendingMu sync.RWMutex
|
||||
// +checklocks:pendingMu
|
||||
pendingRoutes map[RouteKey]PendingRoute
|
||||
pendingRoutes map[stack.UnicastSourceAndMulticastDestination]PendingRoute
|
||||
// cleanupPendingRoutesTimer is a timer that triggers a routine to remove
|
||||
// pending routes that are expired.
|
||||
// +checklocks:pendingMu
|
||||
@@ -75,35 +75,18 @@ var (
|
||||
ErrAlreadyInitialized = errors.New("table is already initialized")
|
||||
)
|
||||
|
||||
// RouteKey represents an entry key in the RouteTable.
|
||||
type RouteKey struct {
|
||||
UnicastSource tcpip.Address
|
||||
MulticastDestination tcpip.Address
|
||||
}
|
||||
|
||||
// InstalledRoute represents a route that is in the installed state.
|
||||
//
|
||||
// If a route is in the installed state, then it may be used to forward
|
||||
// multicast packets.
|
||||
type InstalledRoute struct {
|
||||
expectedInputInterface tcpip.NICID
|
||||
outgoingInterfaces []OutgoingInterface
|
||||
stack.MulticastRoute
|
||||
|
||||
lastUsedTimestampMu sync.RWMutex
|
||||
// +checklocks:lastUsedTimestampMu
|
||||
lastUsedTimestamp tcpip.MonotonicTime
|
||||
}
|
||||
|
||||
// ExpectedInputInterface returns the expected input interface for the route.
|
||||
func (r *InstalledRoute) ExpectedInputInterface() tcpip.NICID {
|
||||
return r.expectedInputInterface
|
||||
}
|
||||
|
||||
// OutgoingInterfaces returns the outgoing interfaces for the route.
|
||||
func (r *InstalledRoute) OutgoingInterfaces() []OutgoingInterface {
|
||||
return r.outgoingInterfaces
|
||||
}
|
||||
|
||||
// LastUsedTimestamp returns a monotonic timestamp that corresponds to the last
|
||||
// time the route was used or updated.
|
||||
func (r *InstalledRoute) LastUsedTimestamp() tcpip.MonotonicTime {
|
||||
@@ -127,17 +110,6 @@ func (r *InstalledRoute) SetLastUsedTimestamp(monotonicTime tcpip.MonotonicTime)
|
||||
}
|
||||
}
|
||||
|
||||
// OutgoingInterface represents an interface that packets should be forwarded
|
||||
// out of.
|
||||
type OutgoingInterface struct {
|
||||
// ID corresponds to the outgoing NIC.
|
||||
ID tcpip.NICID
|
||||
|
||||
// MinTTL represents the minumum TTL/HopLimit a multicast packet must have to
|
||||
// be sent through the outgoing interface.
|
||||
MinTTL uint8
|
||||
}
|
||||
|
||||
// PendingRoute represents a route that is in the "pending" state.
|
||||
//
|
||||
// A route is in the pending state if an installed route does not yet exist
|
||||
@@ -230,8 +202,8 @@ func (r *RouteTable) Init(config Config) error {
|
||||
}
|
||||
|
||||
r.config = config
|
||||
r.installedRoutes = make(map[RouteKey]*InstalledRoute)
|
||||
r.pendingRoutes = make(map[RouteKey]PendingRoute)
|
||||
r.installedRoutes = make(map[stack.UnicastSourceAndMulticastDestination]*InstalledRoute)
|
||||
r.pendingRoutes = make(map[stack.UnicastSourceAndMulticastDestination]PendingRoute)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -299,53 +271,47 @@ func (r *RouteTable) newPendingRoute() PendingRoute {
|
||||
}
|
||||
|
||||
// NewInstalledRoute instantiates an installed route for the table.
|
||||
func (r *RouteTable) NewInstalledRoute(inputInterface tcpip.NICID, outgoingInterfaces []OutgoingInterface) *InstalledRoute {
|
||||
func (r *RouteTable) NewInstalledRoute(route stack.MulticastRoute) *InstalledRoute {
|
||||
return &InstalledRoute{
|
||||
expectedInputInterface: inputInterface,
|
||||
outgoingInterfaces: outgoingInterfaces,
|
||||
lastUsedTimestamp: r.config.Clock.NowMonotonic(),
|
||||
MulticastRoute: route,
|
||||
lastUsedTimestamp: r.config.Clock.NowMonotonic(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetRouteResult represents the result of calling
|
||||
// RouteTable.GetRouteOrInsertPending.
|
||||
// GetRouteResult represents the result of calling GetRouteOrInsertPending.
|
||||
type GetRouteResult struct {
|
||||
// PendingRouteState represents the observed state of any applicable
|
||||
// PendingRoute.
|
||||
PendingRouteState
|
||||
// GetRouteResultState signals the result of calling GetRouteOrInsertPending.
|
||||
GetRouteResultState GetRouteResultState
|
||||
|
||||
// InstalledRoute represents the existing installed route. This field will
|
||||
// only be populated if the PendingRouteState is PendingRouteStateNone.
|
||||
*InstalledRoute
|
||||
// only be populated if the GetRouteResultState is InstalledRouteFound.
|
||||
InstalledRoute *InstalledRoute
|
||||
}
|
||||
|
||||
// PendingRouteState represents the state of a PendingRoute as observed by the
|
||||
// RouteTable.GetRouteOrInsertPending method.
|
||||
type PendingRouteState uint8
|
||||
// GetRouteResultState signals the result of calling GetRouteOrInsertPending.
|
||||
type GetRouteResultState uint8
|
||||
|
||||
const (
|
||||
// PendingRouteStateNone indicates that no pending route exists. In such a
|
||||
// case, the GetRouteResult will contain an InstalledRoute.
|
||||
PendingRouteStateNone PendingRouteState = iota
|
||||
// InstalledRouteFound indicates that an InstalledRoute was found.
|
||||
InstalledRouteFound GetRouteResultState = iota
|
||||
|
||||
// PendingRouteStateAppended indicates that the packet was queued in an
|
||||
// PacketQueuedInPendingRoute indicates that the packet was queued in an
|
||||
// existing pending route.
|
||||
PendingRouteStateAppended
|
||||
PacketQueuedInPendingRoute
|
||||
|
||||
// PendingRouteStateInstalled indicates that a pending route was newly
|
||||
// inserted into the RouteTable. In such a case, callers should typically
|
||||
// emit a missing route event.
|
||||
PendingRouteStateInstalled
|
||||
// NoRouteFoundAndPendingInserted indicates that no route was found and that
|
||||
// a pending route was newly inserted into the RouteTable.
|
||||
NoRouteFoundAndPendingInserted
|
||||
)
|
||||
|
||||
func (e PendingRouteState) String() string {
|
||||
func (e GetRouteResultState) String() string {
|
||||
switch e {
|
||||
case PendingRouteStateNone:
|
||||
return "PendingRouteStateNone"
|
||||
case PendingRouteStateAppended:
|
||||
return "PendingRouteStateAppended"
|
||||
case PendingRouteStateInstalled:
|
||||
return "PendingRouteStateInstalled"
|
||||
case InstalledRouteFound:
|
||||
return "InstalledRouteFound"
|
||||
case PacketQueuedInPendingRoute:
|
||||
return "PacketQueuedInPendingRoute"
|
||||
case NoRouteFoundAndPendingInserted:
|
||||
return "NoRouteFoundAndPendingInserted"
|
||||
default:
|
||||
return fmt.Sprintf("%d", uint8(e))
|
||||
}
|
||||
@@ -355,29 +321,28 @@ func (e PendingRouteState) String() string {
|
||||
// the provided key.
|
||||
//
|
||||
// If no matching installed route is found, then the pkt is cloned and queued
|
||||
// in a pending route. The GetRouteResult.PendingRouteState will indicate
|
||||
// in a pending route. The GetRouteResult.GetRouteResultState will indicate
|
||||
// whether the pkt was queued in a new pending route or an existing one.
|
||||
//
|
||||
// If the relevant pending route queue is at max capacity, then
|
||||
// ErrNoBufferSpace is returned. In such a case, callers are typically expected
|
||||
// to only deliver the pkt locally (if relevant).
|
||||
func (r *RouteTable) GetRouteOrInsertPending(key RouteKey, pkt *stack.PacketBuffer) (GetRouteResult, error) {
|
||||
// If the relevant pending route queue is at max capacity, then returns false.
|
||||
// Otherwise, returns true.
|
||||
func (r *RouteTable) GetRouteOrInsertPending(key stack.UnicastSourceAndMulticastDestination, pkt *stack.PacketBuffer) (GetRouteResult, bool) {
|
||||
r.installedMu.RLock()
|
||||
defer r.installedMu.RUnlock()
|
||||
|
||||
if route, ok := r.installedRoutes[key]; ok {
|
||||
return GetRouteResult{PendingRouteState: PendingRouteStateNone, InstalledRoute: route}, nil
|
||||
return GetRouteResult{GetRouteResultState: InstalledRouteFound, InstalledRoute: route}, true
|
||||
}
|
||||
|
||||
r.pendingMu.Lock()
|
||||
defer r.pendingMu.Unlock()
|
||||
|
||||
pendingRoute, pendingRouteState := r.getOrCreatePendingRouteRLocked(key)
|
||||
pendingRoute, getRouteResultState := r.getOrCreatePendingRouteRLocked(key)
|
||||
if len(pendingRoute.packets) >= int(r.config.MaxPendingQueueSize) {
|
||||
// The incoming packet is rejected if the pending queue is already at max
|
||||
// capacity. This behavior matches the Linux implementation:
|
||||
// https://github.com/torvalds/linux/blob/ae085d7f936/net/ipv4/ipmr.c#L1147
|
||||
return GetRouteResult{}, ErrNoBufferSpace
|
||||
return GetRouteResult{}, false
|
||||
}
|
||||
pendingRoute.packets = append(pendingRoute.packets, pkt.Clone())
|
||||
r.pendingRoutes[key] = pendingRoute
|
||||
@@ -392,15 +357,15 @@ func (r *RouteTable) GetRouteOrInsertPending(key RouteKey, pkt *stack.PacketBuff
|
||||
r.isCleanupRoutineRunning = true
|
||||
}
|
||||
|
||||
return GetRouteResult{PendingRouteState: pendingRouteState, InstalledRoute: nil}, nil
|
||||
return GetRouteResult{GetRouteResultState: getRouteResultState, InstalledRoute: nil}, true
|
||||
}
|
||||
|
||||
// +checklocks:r.pendingMu
|
||||
func (r *RouteTable) getOrCreatePendingRouteRLocked(key RouteKey) (PendingRoute, PendingRouteState) {
|
||||
func (r *RouteTable) getOrCreatePendingRouteRLocked(key stack.UnicastSourceAndMulticastDestination) (PendingRoute, GetRouteResultState) {
|
||||
if pendingRoute, ok := r.pendingRoutes[key]; ok {
|
||||
return pendingRoute, PendingRouteStateAppended
|
||||
return pendingRoute, PacketQueuedInPendingRoute
|
||||
}
|
||||
return r.newPendingRoute(), PendingRouteStateInstalled
|
||||
return r.newPendingRoute(), NoRouteFoundAndPendingInserted
|
||||
}
|
||||
|
||||
// AddInstalledRoute adds the provided route to the table.
|
||||
@@ -409,7 +374,7 @@ func (r *RouteTable) getOrCreatePendingRouteRLocked(key RouteKey) (PendingRoute,
|
||||
// returned. The caller assumes ownership of these packets and is responsible
|
||||
// for forwarding and releasing them. If an installed route already exists for
|
||||
// the provided key, then it is overwritten.
|
||||
func (r *RouteTable) AddInstalledRoute(key RouteKey, route *InstalledRoute) []*stack.PacketBuffer {
|
||||
func (r *RouteTable) AddInstalledRoute(key stack.UnicastSourceAndMulticastDestination, route *InstalledRoute) []*stack.PacketBuffer {
|
||||
r.installedMu.Lock()
|
||||
defer r.installedMu.Unlock()
|
||||
r.installedRoutes[key] = route
|
||||
@@ -436,7 +401,7 @@ func (r *RouteTable) AddInstalledRoute(key RouteKey, route *InstalledRoute) []*s
|
||||
// key.
|
||||
//
|
||||
// Returns true if a route was removed. Otherwise returns false.
|
||||
func (r *RouteTable) RemoveInstalledRoute(key RouteKey) bool {
|
||||
func (r *RouteTable) RemoveInstalledRoute(key stack.UnicastSourceAndMulticastDestination) bool {
|
||||
r.installedMu.Lock()
|
||||
defer r.installedMu.Unlock()
|
||||
|
||||
@@ -452,7 +417,7 @@ func (r *RouteTable) RemoveInstalledRoute(key RouteKey) bool {
|
||||
// time the route that matches the provided key was used or updated.
|
||||
//
|
||||
// Returns true if a matching route was found. Otherwise returns false.
|
||||
func (r *RouteTable) GetLastUsedTimestamp(key RouteKey) (tcpip.MonotonicTime, bool) {
|
||||
func (r *RouteTable) GetLastUsedTimestamp(key stack.UnicastSourceAndMulticastDestination) (tcpip.MonotonicTime, bool) {
|
||||
r.installedMu.RLock()
|
||||
defer r.installedMu.RUnlock()
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
|
||||
const (
|
||||
defaultMinTTL = 10
|
||||
defaultMTU = 1500
|
||||
inputNICID tcpip.NICID = 1
|
||||
outgoingNICID tcpip.NICID = 2
|
||||
defaultNICID tcpip.NICID = 3
|
||||
@@ -39,8 +40,9 @@ const (
|
||||
|
||||
var (
|
||||
defaultAddress = testutil.MustParse4("192.168.1.1")
|
||||
defaultRouteKey = RouteKey{UnicastSource: defaultAddress, MulticastDestination: defaultAddress}
|
||||
defaultOutgoingInterfaces = []OutgoingInterface{{ID: outgoingNICID, MinTTL: defaultMinTTL}}
|
||||
defaultRouteKey = stack.UnicastSourceAndMulticastDestination{Source: defaultAddress, Destination: defaultAddress}
|
||||
defaultOutgoingInterfaces = []stack.MulticastRouteOutgoingInterface{{ID: outgoingNICID, MinTTL: defaultMinTTL}}
|
||||
defaultRoute = stack.MulticastRoute{inputNICID, defaultOutgoingInterfaces}
|
||||
)
|
||||
|
||||
func newPacketBuffer(body string) *stack.PacketBuffer {
|
||||
@@ -77,11 +79,11 @@ func defaultConfig(opts ...configOption) Config {
|
||||
}
|
||||
|
||||
func installedRouteComparer(a *InstalledRoute, b *InstalledRoute) bool {
|
||||
if !cmp.Equal(a.OutgoingInterfaces(), b.OutgoingInterfaces()) {
|
||||
if !cmp.Equal(a.OutgoingInterfaces, b.OutgoingInterfaces) {
|
||||
return false
|
||||
}
|
||||
|
||||
if a.ExpectedInputInterface() != b.ExpectedInputInterface() {
|
||||
if a.ExpectedInputInterface != b.ExpectedInputInterface {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -143,15 +145,19 @@ func TestNewInstalledRoute(t *testing.T) {
|
||||
t.Fatalf("table.Init(%#v): %s", config, err)
|
||||
}
|
||||
|
||||
route := table.NewInstalledRoute(inputNICID, defaultOutgoingInterfaces)
|
||||
expectedRoute := &InstalledRoute{expectedInputInterface: inputNICID, outgoingInterfaces: defaultOutgoingInterfaces, lastUsedTimestamp: clock.NowMonotonic()}
|
||||
route := table.NewInstalledRoute(defaultRoute)
|
||||
|
||||
expectedRoute := &InstalledRoute{
|
||||
MulticastRoute: defaultRoute,
|
||||
lastUsedTimestamp: clock.NowMonotonic(),
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(expectedRoute, route, cmp.Comparer(installedRouteComparer)); diff != "" {
|
||||
t.Errorf("Installed route mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPendingRouteStates(t *testing.T) {
|
||||
func TestGetRouteResultStates(t *testing.T) {
|
||||
table := RouteTable{}
|
||||
defer table.Close()
|
||||
config := defaultConfig(withMaxPendingQueueSize(2))
|
||||
@@ -161,16 +167,17 @@ func TestPendingRouteStates(t *testing.T) {
|
||||
|
||||
pkt := newPacketBuffer("hello")
|
||||
defer pkt.DecRef()
|
||||
// Queue two pending packets for the same route. The PendingRouteState should
|
||||
// transition from PendingRouteStateInstalled to PendingRouteStateAppended.
|
||||
for _, wantPendingRouteState := range []PendingRouteState{PendingRouteStateInstalled, PendingRouteStateAppended} {
|
||||
routeResult, err := table.GetRouteOrInsertPending(defaultRouteKey, pkt)
|
||||
// Queue two pending packets for the same route. The GetRouteResultState
|
||||
// should transition from NoRouteFoundAndPendingInserted to
|
||||
// PacketQueuedInPendingRoute.
|
||||
for _, wantPendingRouteState := range []GetRouteResultState{NoRouteFoundAndPendingInserted, PacketQueuedInPendingRoute} {
|
||||
routeResult, hasBufferSpace := table.GetRouteOrInsertPending(defaultRouteKey, pkt)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("table.GetRouteOrInsertPending(%#v, %#v) = (_, %v), want = (_, nil)", defaultRouteKey, pkt, err)
|
||||
if !hasBufferSpace {
|
||||
t.Errorf("table.GetRouteOrInsertPending(%#v, %#v) = (_, false), want = (_, true)", defaultRouteKey, pkt)
|
||||
}
|
||||
|
||||
expectedResult := GetRouteResult{PendingRouteState: wantPendingRouteState}
|
||||
expectedResult := GetRouteResult{GetRouteResultState: wantPendingRouteState}
|
||||
if diff := cmp.Diff(expectedResult, routeResult); diff != "" {
|
||||
t.Errorf("table.GetRouteOrInsertPending(%#v, %#v) GetRouteResult mismatch (-want +got):\n%s", defaultRouteKey, pkt, diff)
|
||||
}
|
||||
@@ -178,8 +185,8 @@ func TestPendingRouteStates(t *testing.T) {
|
||||
|
||||
// Queuing a third packet should yield an error since the pending queue is
|
||||
// already at max capacity.
|
||||
if _, err := table.GetRouteOrInsertPending(defaultRouteKey, pkt); err != ErrNoBufferSpace {
|
||||
t.Errorf("table.GetRouteOrInsertPending(%#v, %#v) = (_, %v), want = (_, ErrNoBufferSpace)", defaultRouteKey, pkt, err)
|
||||
if _, hasBufferSpace := table.GetRouteOrInsertPending(defaultRouteKey, pkt); hasBufferSpace {
|
||||
t.Errorf("table.GetRouteOrInsertPending(%#v, %#v) = (_, true), want = (_, false)", defaultRouteKey, pkt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,8 +232,8 @@ func TestPendingRouteExpiration(t *testing.T) {
|
||||
|
||||
clock.Advance(test.advanceBeforeInsert)
|
||||
|
||||
if _, err := table.GetRouteOrInsertPending(defaultRouteKey, pkt); err != nil {
|
||||
t.Fatalf("table.GetRouteOrInsertPending(%#v, %#v): %v", defaultRouteKey, pkt, err)
|
||||
if _, hasBufferSpace := table.GetRouteOrInsertPending(defaultRouteKey, pkt); !hasBufferSpace {
|
||||
t.Fatalf("table.GetRouteOrInsertPending(%#v, %#v): false", defaultRouteKey, pkt)
|
||||
}
|
||||
|
||||
clock.Advance(test.advanceAfterInsert)
|
||||
@@ -288,8 +295,8 @@ func TestAddInstalledRouteWithPending(t *testing.T) {
|
||||
t.Fatalf("table.Init(%#v): %s", config, err)
|
||||
}
|
||||
|
||||
if _, err := table.GetRouteOrInsertPending(defaultRouteKey, pkt); err != nil {
|
||||
t.Fatalf("table.GetRouteOrInsertPending(%#v, %#v): %v", defaultRouteKey, pkt, err)
|
||||
if _, hasBufferSpace := table.GetRouteOrInsertPending(defaultRouteKey, pkt); !hasBufferSpace {
|
||||
t.Fatalf("table.GetRouteOrInsertPending(%#v, %#v): false", defaultRouteKey, pkt)
|
||||
}
|
||||
|
||||
// Disable the cleanup routine.
|
||||
@@ -297,7 +304,7 @@ func TestAddInstalledRouteWithPending(t *testing.T) {
|
||||
|
||||
clock.Advance(test.advance)
|
||||
|
||||
route := table.NewInstalledRoute(inputNICID, defaultOutgoingInterfaces)
|
||||
route := table.NewInstalledRoute(defaultRoute)
|
||||
pendingPackets := table.AddInstalledRoute(defaultRouteKey, route)
|
||||
|
||||
if diff := cmp.Diff(test.want, pendingPackets, cmpOpts...); diff != "" {
|
||||
@@ -326,27 +333,29 @@ func TestAddInstalledRouteWithNoPending(t *testing.T) {
|
||||
t.Fatalf("table.Init(%#v): %s", config, err)
|
||||
}
|
||||
|
||||
firstRoute := table.NewInstalledRoute(inputNICID, defaultOutgoingInterfaces)
|
||||
secondRoute := table.NewInstalledRoute(defaultNICID, defaultOutgoingInterfaces)
|
||||
firstRoute := table.NewInstalledRoute(defaultRoute)
|
||||
|
||||
secondMulticastRoute := stack.MulticastRoute{defaultNICID, defaultOutgoingInterfaces}
|
||||
secondRoute := table.NewInstalledRoute(secondMulticastRoute)
|
||||
|
||||
pkt := newPacketBuffer("hello")
|
||||
defer pkt.DecRef()
|
||||
for _, route := range [...]*InstalledRoute{firstRoute, secondRoute} {
|
||||
if pendingPackets := table.AddInstalledRoute(defaultRouteKey, route); pendingPackets != nil {
|
||||
t.Errorf("got table.AddInstalledRoute(%#v, %#v) = %#v, want = false", defaultRouteKey, route, pendingPackets)
|
||||
t.Errorf("table.AddInstalledRoute(%#v, %#v) = %#v, want = false", defaultRouteKey, route, pendingPackets)
|
||||
}
|
||||
|
||||
// AddInstalledRoute is invoked for the same routeKey two times. Verify
|
||||
// that the fetched InstalledRoute reflects the most recent invocation of
|
||||
// AddInstalledRoute.
|
||||
routeResult, err := table.GetRouteOrInsertPending(defaultRouteKey, pkt)
|
||||
routeResult, hasBufferSpace := table.GetRouteOrInsertPending(defaultRouteKey, pkt)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("table.GetRouteOrInsertPending(%#v, %#v): %v", defaultRouteKey, pkt, err)
|
||||
if !hasBufferSpace {
|
||||
t.Fatalf("table.GetRouteOrInsertPending(%#v, %#v): false", defaultRouteKey, pkt)
|
||||
}
|
||||
|
||||
if routeResult.PendingRouteState != PendingRouteStateNone {
|
||||
t.Errorf("routeResult.PendingRouteState = %s, want = PendingRouteStateNone", routeResult.PendingRouteState)
|
||||
if routeResult.GetRouteResultState != InstalledRouteFound {
|
||||
t.Errorf("routeResult.GetRouteResultState = %s, want = InstalledRouteFound", routeResult.GetRouteResultState)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(route, routeResult.InstalledRoute, cmp.Comparer(installedRouteComparer)); diff != "" {
|
||||
@@ -363,7 +372,7 @@ func TestRemoveInstalledRoute(t *testing.T) {
|
||||
t.Fatalf("table.Init(%#v): %s", config, err)
|
||||
}
|
||||
|
||||
route := table.NewInstalledRoute(inputNICID, defaultOutgoingInterfaces)
|
||||
route := table.NewInstalledRoute(defaultRoute)
|
||||
|
||||
table.AddInstalledRoute(defaultRouteKey, route)
|
||||
|
||||
@@ -374,10 +383,10 @@ func TestRemoveInstalledRoute(t *testing.T) {
|
||||
pkt := newPacketBuffer("hello")
|
||||
defer pkt.DecRef()
|
||||
|
||||
result, err := table.GetRouteOrInsertPending(defaultRouteKey, pkt)
|
||||
result, hasBufferSpace := table.GetRouteOrInsertPending(defaultRouteKey, pkt)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("table.GetRouteOrInsertPending(%#v, %#v): %v", defaultRouteKey, pkt, err)
|
||||
if !hasBufferSpace {
|
||||
t.Fatalf("table.GetRouteOrInsertPending(%#v, %#v): false", defaultRouteKey, pkt)
|
||||
}
|
||||
|
||||
if result.InstalledRoute != nil {
|
||||
@@ -444,7 +453,7 @@ func TestSetLastUsedTimestamp(t *testing.T) {
|
||||
t.Fatalf("table.Init(%#v): %s", config, err)
|
||||
}
|
||||
|
||||
route := table.NewInstalledRoute(inputNICID, defaultOutgoingInterfaces)
|
||||
route := table.NewInstalledRoute(defaultRoute)
|
||||
|
||||
table.AddInstalledRoute(defaultRouteKey, route)
|
||||
|
||||
|
||||
@@ -757,6 +757,41 @@ type NetworkProtocol interface {
|
||||
Parse(pkt *PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool)
|
||||
}
|
||||
|
||||
// UnicastSourceAndMulticastDestination is a tuple that represents a unicast
|
||||
// source address and a multicast destination address.
|
||||
type UnicastSourceAndMulticastDestination struct {
|
||||
// Source represents a unicast source address.
|
||||
Source tcpip.Address
|
||||
// Destination represents a multicast destination address.
|
||||
Destination tcpip.Address
|
||||
}
|
||||
|
||||
// MulticastRouteOutgoingInterface represents an outgoing interface in a
|
||||
// multicast route.
|
||||
type MulticastRouteOutgoingInterface struct {
|
||||
// ID corresponds to the outgoing NIC.
|
||||
ID tcpip.NICID
|
||||
|
||||
// MinTTL represents the minumum TTL/HopLimit a multicast packet must have to
|
||||
// be sent through the outgoing interface.
|
||||
//
|
||||
// Note: a value of 0 allows all packets to be forwarded.
|
||||
MinTTL uint8
|
||||
}
|
||||
|
||||
// MulticastRoute is a multicast route.
|
||||
type MulticastRoute struct {
|
||||
// ExpectedInputInterface is the interface on which packets using this route
|
||||
// are expected to ingress.
|
||||
ExpectedInputInterface tcpip.NICID
|
||||
|
||||
// OutgoingInterfaces is the set of interfaces that a multicast packet should
|
||||
// be forwarded out of.
|
||||
//
|
||||
// This field should not be empty.
|
||||
OutgoingInterfaces []MulticastRouteOutgoingInterface
|
||||
}
|
||||
|
||||
// NetworkDispatcher contains the methods used by the network stack to deliver
|
||||
// inbound/outbound packets to the appropriate network/packet(if any) endpoints.
|
||||
type NetworkDispatcher interface {
|
||||
|
||||
Reference in New Issue
Block a user