blob: c2f013152a69a481dcba2b573646eb1fa1915dde [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package netstack
import (
"context"
"errors"
"fmt"
"syscall/zx"
"syscall/zx/fidl"
"go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/fidlconv"
"go.fuchsia.dev/fuchsia/src/lib/component"
syslog "go.fuchsia.dev/fuchsia/src/lib/syslog/go"
"fidl/fuchsia/net"
"fidl/fuchsia/net/multicast/admin"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
func addMulticastIpv4RoutingTableControllerService(componentCtx *component.Context, stack *stack.Stack) {
componentCtx.OutgoingService.AddService(
admin.Ipv4RoutingTableControllerName,
func(ctx context.Context, c zx.Channel) error {
eventDispatcher := multicastEventDispatcher{}
alreadyEnabled, err := stack.EnableMulticastForwardingForProtocol(ipv4.ProtocolNumber, &eventDispatcher)
if err != nil {
return WrapTcpIpError(err)
}
eventSender := admin.Ipv4RoutingTableControllerEventProxy(fidl.ChannelProxy{Channel: c})
if alreadyEnabled {
eventSender.OnClose(admin.TableControllerCloseReasonAlreadyInUse)
return errors.New("Ipv4RoutingTableController already in use")
}
multicastIPv4Stub := admin.Ipv4RoutingTableControllerWithCtxStub{
Impl: &multicastIpv4RoutingTableControllerImpl{
stack: stack,
eventSender: eventSender,
disp: &eventDispatcher,
},
}
go func() {
component.Serve(ctx, &multicastIPv4Stub, c, component.ServeOptions{
Concurrent: true,
OnError: func(err error) {
_ = syslog.WarnTf(admin.Ipv4RoutingTableControllerName, "%s", err)
},
})
if err := stack.DisableMulticastForwardingForProtocol(ipv4.ProtocolNumber); err != nil {
// Should never happen as this would imply that the IPv4
// protocol implementation was removed.
panic(fmt.Sprintf("stack.DisableMulticastForwardingForProtocol(ipv4.ProtocolNumber): %s", err))
}
}()
return nil
},
)
}
var _ admin.Ipv4RoutingTableControllerWithCtx = (*multicastIpv4RoutingTableControllerImpl)(nil)
type multicastIpv4RoutingTableControllerImpl struct {
stack *stack.Stack
eventSender admin.Ipv4RoutingTableControllerEventProxy
disp *multicastEventDispatcher
}
func toTCPIPAddressFromIPv4(addr net.Ipv4Address) tcpip.Address {
return fidlconv.ToTCPIPAddress(net.IpAddressWithIpv4(addr))
}
func toStackUnicastSourceAndMulticastDestination(addresses admin.Ipv4UnicastSourceAndMulticastDestination) stack.UnicastSourceAndMulticastDestination {
return stack.UnicastSourceAndMulticastDestination{
Source: toTCPIPAddressFromIPv4(addresses.UnicastSource),
Destination: toTCPIPAddressFromIPv4(addresses.MulticastDestination),
}
}
func (m *multicastIpv4RoutingTableControllerImpl) AddRoute(_ fidl.Context, addresses admin.Ipv4UnicastSourceAndMulticastDestination, route admin.Route) (admin.Ipv4RoutingTableControllerAddRouteResult, error) {
multicastRoute, success := fidlconv.ToStackMulticastRoute(route)
if !success {
return admin.Ipv4RoutingTableControllerAddRouteResultWithErr(admin.Ipv4RoutingTableControllerAddRouteErrorRequiredRouteFieldsMissing), nil
}
stackAddresses := toStackUnicastSourceAndMulticastDestination(addresses)
switch err := m.stack.AddMulticastRoute(ipv4.ProtocolNumber, stackAddresses, multicastRoute); err.(type) {
case nil:
return admin.Ipv4RoutingTableControllerAddRouteResultWithResponse(admin.Ipv4RoutingTableControllerAddRouteResponse{}), nil
case *tcpip.ErrBadAddress:
return admin.Ipv4RoutingTableControllerAddRouteResultWithErr(admin.Ipv4RoutingTableControllerAddRouteErrorInvalidAddress), nil
case *tcpip.ErrMissingRequiredFields:
return admin.Ipv4RoutingTableControllerAddRouteResultWithErr(admin.Ipv4RoutingTableControllerAddRouteErrorRequiredRouteFieldsMissing), nil
case *tcpip.ErrMulticastInputCannotBeOutput:
return admin.Ipv4RoutingTableControllerAddRouteResultWithErr(admin.Ipv4RoutingTableControllerAddRouteErrorInputCannotBeOutput), nil
case *tcpip.ErrUnknownNICID:
return admin.Ipv4RoutingTableControllerAddRouteResultWithErr(admin.Ipv4RoutingTableControllerAddRouteErrorInterfaceNotFound), nil
default:
panic(fmt.Sprintf("m.stack.AddRoute(ipv4.ProtocolNumber, %#v, %#v): %s", stackAddresses, multicastRoute, err))
}
}
func (m *multicastIpv4RoutingTableControllerImpl) DelRoute(fidl.Context, admin.Ipv4UnicastSourceAndMulticastDestination) (admin.Ipv4RoutingTableControllerDelRouteResult, error) {
// TODO(https://fxbug.dev/102563): Implement DelRoute.
return admin.Ipv4RoutingTableControllerDelRouteResult{}, errors.New("Ipv4RoutingTableController.DelRoute unimplemented. See fxbug.dev/102563.")
}
func (m *multicastIpv4RoutingTableControllerImpl) GetRouteStats(fidl.Context, admin.Ipv4UnicastSourceAndMulticastDestination) (admin.Ipv4RoutingTableControllerGetRouteStatsResult, error) {
// TODO(https://fxbug.dev/102565): Implement GetRouteStats.
return admin.Ipv4RoutingTableControllerGetRouteStatsResult{}, errors.New("Ipv4RoutingTableController.GetRouteStats unimplemented. See fxbug.dev/102565.")
}
func (m *multicastIpv4RoutingTableControllerImpl) WatchRoutingEvents(fidl.Context) (uint64, admin.Ipv4UnicastSourceAndMulticastDestination, uint64, admin.RoutingEvent, error) {
// TODO(https://fxbug.dev/102559): Implement WatchRoutingEvents.
return 0, admin.Ipv4UnicastSourceAndMulticastDestination{}, 0, admin.RoutingEvent{}, errors.New("Ipv4RoutingTableController.WatchRoutingEvents unimplemented. See fxbug.dev/102559.")
}