github.com/jspc/eggos@v0.5.1-0.20221028160421-556c75c878a5/inet/stack.go (about)

     1  package inet
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"time"
     7  
     8  	"github.com/jspc/eggos/inet/dhcp"
     9  	"github.com/jspc/eggos/log"
    10  
    11  	"gvisor.dev/gvisor/pkg/tcpip"
    12  	"gvisor.dev/gvisor/pkg/tcpip/header"
    13  	"gvisor.dev/gvisor/pkg/tcpip/link/loopback"
    14  	"gvisor.dev/gvisor/pkg/tcpip/network/arp"
    15  	"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
    16  	"gvisor.dev/gvisor/pkg/tcpip/stack"
    17  	"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
    18  	"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
    19  )
    20  
    21  const (
    22  	defaultNIC  = 1
    23  	loopbackNIC = 2
    24  )
    25  
    26  var (
    27  	nstack *stack.Stack
    28  )
    29  
    30  func e(err tcpip.Error) error {
    31  	if err == nil {
    32  		return nil
    33  	}
    34  	return errors.New(err.String())
    35  }
    36  
    37  func Init() {
    38  	nstack = stack.New(stack.Options{
    39  		NetworkProtocols:   []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol},
    40  		TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol},
    41  		HandleLocal:        true,
    42  	})
    43  
    44  	// add net card interface
    45  	endpoint := New(&Options{})
    46  	err := nstack.CreateNIC(defaultNIC, endpoint)
    47  	if err != nil {
    48  		panic(err)
    49  	}
    50  	err1 := dodhcp(endpoint.LinkAddress())
    51  	if err1 != nil {
    52  		panic(err)
    53  	}
    54  
    55  	// add loopback interface
    56  	err = nstack.CreateNIC(loopbackNIC, loopback.New())
    57  	if err != nil {
    58  		panic(err)
    59  	}
    60  	addInterfaceAddr(nstack, loopbackNIC, tcpip.Address([]byte{127, 0, 0, 1}))
    61  	return
    62  }
    63  
    64  func addInterfaceAddr(s *stack.Stack, nic tcpip.NICID, addr tcpip.Address) {
    65  	s.AddAddress(nic, ipv4.ProtocolNumber, addr)
    66  	// Add route for local network if it doesn't exist already.
    67  	localRoute := tcpip.Route{
    68  		Destination: addr.WithPrefix().Subnet(),
    69  		Gateway:     "", // No gateway for local network.
    70  		NIC:         nic,
    71  	}
    72  
    73  	for _, rt := range s.GetRouteTable() {
    74  		if rt.Equal(localRoute) {
    75  			return
    76  		}
    77  	}
    78  
    79  	// Local route does not exist yet. Add it.
    80  	s.AddRoute(localRoute)
    81  }
    82  
    83  func dodhcp(linkaddr tcpip.LinkAddress) error {
    84  	dhcpclient := dhcp.NewClient(nstack, defaultNIC, linkaddr)
    85  	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    86  	log.Infof("[inet] begin dhcp")
    87  	err1 := dhcpclient.Request(ctx, "")
    88  	cancel()
    89  	if err1 != nil {
    90  		return err1
    91  	}
    92  	log.Infof("[inet] dhcp done")
    93  	cfg := dhcpclient.Config()
    94  	log.Infof("[inet] addr:%v", dhcpclient.Address())
    95  	log.Infof("[inet] gateway:%v", cfg.Gateway)
    96  	log.Infof("[inet] mask:%v", cfg.SubnetMask)
    97  	log.Infof("[inet] dns:%v", cfg.DomainNameServer)
    98  
    99  	addInterfaceAddr(nstack, defaultNIC, dhcpclient.Address())
   100  	nstack.AddRoute(tcpip.Route{
   101  		Destination: header.IPv4EmptySubnet,
   102  		Gateway:     cfg.Gateway,
   103  		NIC:         defaultNIC,
   104  	})
   105  	return nil
   106  }