gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/network/internal/multicast/example_test.go (about)

     1  // Copyright 2022 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package multicast_test
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  	"testing"
    21  	"time"
    22  
    23  	"gvisor.dev/gvisor/pkg/buffer"
    24  	"gvisor.dev/gvisor/pkg/refs"
    25  	"gvisor.dev/gvisor/pkg/tcpip"
    26  	"gvisor.dev/gvisor/pkg/tcpip/faketime"
    27  	"gvisor.dev/gvisor/pkg/tcpip/network/internal/multicast"
    28  	"gvisor.dev/gvisor/pkg/tcpip/stack"
    29  	"gvisor.dev/gvisor/pkg/tcpip/testutil"
    30  )
    31  
    32  const (
    33  	defaultMinTTL             = 10
    34  	defaultMTU                = 1500
    35  	inputNICID    tcpip.NICID = 1
    36  	outgoingNICID tcpip.NICID = 2
    37  )
    38  
    39  // Example shows how to interact with a multicast RouteTable.
    40  func Example() {
    41  	address := testutil.MustParse4("192.168.1.1")
    42  	defaultOutgoingInterfaces := []stack.MulticastRouteOutgoingInterface{{ID: outgoingNICID, MinTTL: defaultMinTTL}}
    43  	routeKey := stack.UnicastSourceAndMulticastDestination{Source: address, Destination: address}
    44  	multicastRoute := stack.MulticastRoute{inputNICID, defaultOutgoingInterfaces}
    45  
    46  	pkt := newPacketBuffer("hello")
    47  	defer pkt.DecRef()
    48  
    49  	clock := faketime.NewManualClock()
    50  	clock.Advance(10 * time.Second)
    51  
    52  	// Create a route table from a specified config.
    53  	table := multicast.RouteTable{}
    54  	defer table.Close()
    55  	config := multicast.DefaultConfig(clock)
    56  
    57  	if err := table.Init(config); err != nil {
    58  		panic(err)
    59  	}
    60  
    61  	// Each entry in the table represents either an installed route or a pending
    62  	// route. To insert a pending route, call:
    63  	result, hasBufferSpace := table.GetRouteOrInsertPending(routeKey, pkt)
    64  
    65  	// Callers should handle a no buffer space error (e.g. only deliver the
    66  	// packet locally).
    67  	if !hasBufferSpace {
    68  		deliverPktLocally(pkt)
    69  	}
    70  
    71  	// Callers should handle the various pending route states.
    72  	switch result.GetRouteResultState {
    73  	case multicast.InstalledRouteFound:
    74  		// The packet can be forwarded using the installed route.
    75  		forwardPkt(pkt, result.InstalledRoute)
    76  	case multicast.NoRouteFoundAndPendingInserted:
    77  		// The route has just entered the pending state.
    78  		emitMissingRouteEvent(routeKey)
    79  		deliverPktLocally(pkt)
    80  	case multicast.PacketQueuedInPendingRoute:
    81  		// The route was already in the pending state.
    82  		deliverPktLocally(pkt)
    83  	}
    84  
    85  	// To transition a pending route to the installed state, call:
    86  	route := table.NewInstalledRoute(multicastRoute)
    87  	pendingPackets := table.AddInstalledRoute(routeKey, route)
    88  
    89  	// If there was a pending route, then the caller is responsible for
    90  	// flushing any pending packets.
    91  	for _, pkt := range pendingPackets {
    92  		forwardPkt(pkt, route)
    93  		pkt.DecRef()
    94  	}
    95  
    96  	// To obtain the last used time of the route, call:
    97  	timestamp, found := table.GetLastUsedTimestamp(routeKey)
    98  
    99  	if !found {
   100  		panic(fmt.Sprintf("table.GetLastUsedTimestamp(%#v) = (_, false)", routeKey))
   101  	}
   102  
   103  	fmt.Printf("Last used timestamp: %s", timestamp)
   104  
   105  	// Finally, to remove an installed route, call:
   106  	if removed := table.RemoveInstalledRoute(routeKey); !removed {
   107  		panic(fmt.Sprintf("table.RemoveInstalledRoute(%#v) = false", routeKey))
   108  	}
   109  
   110  	// Output:
   111  	// emitMissingRouteEvent
   112  	// deliverPktLocally
   113  	// forwardPkt
   114  	// Last used timestamp: 10000000000
   115  }
   116  
   117  func forwardPkt(*stack.PacketBuffer, *multicast.InstalledRoute) {
   118  	fmt.Println("forwardPkt")
   119  }
   120  
   121  func emitMissingRouteEvent(stack.UnicastSourceAndMulticastDestination) {
   122  	fmt.Println("emitMissingRouteEvent")
   123  }
   124  
   125  func deliverPktLocally(*stack.PacketBuffer) {
   126  	fmt.Println("deliverPktLocally")
   127  }
   128  
   129  func newPacketBuffer(body string) *stack.PacketBuffer {
   130  	return stack.NewPacketBuffer(stack.PacketBufferOptions{
   131  		Payload: buffer.MakeWithData([]byte(body)),
   132  	})
   133  }
   134  
   135  func TestMain(m *testing.M) {
   136  	refs.SetLeakMode(refs.LeaksPanic)
   137  	code := m.Run()
   138  	refs.DoLeakCheck()
   139  	os.Exit(code)
   140  }