mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement RTM_NEWROUTE in netstack to create/replace a route.
PiperOrigin-RevId: 650814137
This commit is contained in:
@@ -742,6 +742,122 @@ func (s *Stack) RouteTable() []inet.Route {
|
||||
return routeTable
|
||||
}
|
||||
|
||||
// NewRoute implements inet.Stack.NewRoute.
|
||||
func (s *Stack) NewRoute(ctx context.Context, msg *nlmsg.Message) *syserr.Error {
|
||||
var routeMsg linux.RouteMessage
|
||||
attrs, ok := msg.GetData(&routeMsg)
|
||||
if !ok {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
|
||||
route := inet.Route{
|
||||
Family: routeMsg.Family,
|
||||
DstLen: routeMsg.DstLen,
|
||||
SrcLen: routeMsg.SrcLen,
|
||||
TOS: routeMsg.TOS,
|
||||
Table: routeMsg.Table,
|
||||
Protocol: routeMsg.Protocol,
|
||||
Scope: routeMsg.Scope,
|
||||
Type: routeMsg.Type,
|
||||
Flags: routeMsg.Flags,
|
||||
}
|
||||
|
||||
for !attrs.Empty() {
|
||||
ahdr, value, rest, ok := attrs.ParseFirst()
|
||||
if !ok {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
attrs = rest
|
||||
|
||||
switch ahdr.Type {
|
||||
case linux.RTA_DST:
|
||||
if len(value) < 1 {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
route.DstAddr = value
|
||||
case linux.RTA_SRC:
|
||||
if len(value) < 1 {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
route.SrcAddr = value
|
||||
case linux.RTA_OIF:
|
||||
oif := nlmsg.BytesView(value)
|
||||
outputInterface, ok := oif.Int32()
|
||||
if !ok {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
if _, exist := s.Interfaces()[outputInterface]; !exist {
|
||||
return syserr.ErrNoDevice
|
||||
}
|
||||
route.OutputInterface = outputInterface
|
||||
case linux.RTA_GATEWAY:
|
||||
if len(value) < 1 {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
route.GatewayAddr = value
|
||||
case linux.RTA_PRIORITY:
|
||||
default:
|
||||
ctx.Warningf("Unknown attribute: %v", ahdr.Type)
|
||||
return syserr.ErrNotSupported
|
||||
}
|
||||
}
|
||||
|
||||
var dest tcpip.Subnet
|
||||
// When no destination address is provided, the new route might be the default route.
|
||||
if route.DstAddr == nil {
|
||||
if route.GatewayAddr == nil {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
switch len(route.GatewayAddr) {
|
||||
case header.IPv4AddressSize:
|
||||
subnet, err := tcpip.NewSubnet(tcpip.AddrFromSlice(tcpip.IPv4Zero), tcpip.MaskFromBytes(tcpip.IPv4Zero))
|
||||
if err != nil {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
dest = subnet
|
||||
case header.IPv6AddressSize:
|
||||
subnet, err := tcpip.NewSubnet(tcpip.AddrFromSlice(tcpip.IPv6Zero), tcpip.MaskFromBytes(tcpip.IPv6Zero))
|
||||
if err != nil {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
dest = subnet
|
||||
default:
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
} else {
|
||||
dest = tcpip.AddressWithPrefix{
|
||||
Address: tcpip.AddrFromSlice(route.DstAddr),
|
||||
PrefixLen: int(route.DstLen)}.Subnet()
|
||||
}
|
||||
|
||||
localRoute := tcpip.Route{
|
||||
Destination: dest,
|
||||
Gateway: tcpip.AddrFromSlice(route.GatewayAddr),
|
||||
NIC: tcpip.NICID(route.OutputInterface),
|
||||
}
|
||||
if len(route.SrcAddr) != 0 {
|
||||
localRoute.SourceHint = tcpip.AddrFromSlice(route.SrcAddr)
|
||||
}
|
||||
found := false
|
||||
for _, rt := range s.Stack.GetRouteTable() {
|
||||
if localRoute.Equal(rt) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
flags := msg.Header().Flags
|
||||
switch {
|
||||
case !found && flags&linux.NLM_F_CREATE == linux.NLM_F_CREATE:
|
||||
s.Stack.AddRoute(localRoute)
|
||||
case found && flags&linux.NLM_F_REPLACE != linux.NLM_F_REPLACE:
|
||||
return syserr.ErrExists
|
||||
}
|
||||
if flags&linux.NLM_F_REPLACE == linux.NLM_F_REPLACE {
|
||||
s.Stack.ReplaceRoute(localRoute)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IPTables returns the stack's iptables.
|
||||
func (s *Stack) IPTables() (*stack.IPTables, error) {
|
||||
return s.Stack.IPTables(), nil
|
||||
|
||||
Reference in New Issue
Block a user