mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
netlink: allow to up/down interfaces via RTM_NEWLINK
It is required to run Docker in gVisor. Netstack interfaces are always up, so this is no-op. PiperOrigin-RevId: 576220175
This commit is contained in:
@@ -161,6 +161,72 @@ func (p *Protocol) getLink(ctx context.Context, msg *netlink.Message, ms *netlin
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Protocol) newLink(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
if stack == nil {
|
||||
// No network stack.
|
||||
return syserr.ErrProtocolNotSupported
|
||||
}
|
||||
|
||||
var ifinfomsg linux.InterfaceInfoMessage
|
||||
attrs, ok := msg.GetData(&ifinfomsg)
|
||||
if !ok {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
for !attrs.Empty() {
|
||||
// The index is unspecified, search by the interface name.
|
||||
ahdr, value, rest, ok := attrs.ParseFirst()
|
||||
if !ok {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
attrs = rest
|
||||
switch ahdr.Type {
|
||||
case linux.IFLA_IFNAME:
|
||||
if len(value) < 1 {
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
if ifinfomsg.Index != 0 {
|
||||
// Device name changing isn't supported yet.
|
||||
return syserr.ErrNotSupported
|
||||
}
|
||||
ifname := string(value[:len(value)-1])
|
||||
for idx, ifa := range stack.Interfaces() {
|
||||
if ifname == ifa.Name {
|
||||
ifinfomsg.Index = idx
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
ctx.Warningf("unexpected attribute: %x", ahdr.Type)
|
||||
return syserr.ErrNotSupported
|
||||
}
|
||||
}
|
||||
if ifinfomsg.Index == 0 {
|
||||
return syserr.ErrNoDevice
|
||||
}
|
||||
|
||||
flags := msg.Header().Flags
|
||||
if flags&linux.NLM_F_EXCL != 0 {
|
||||
return syserr.ErrExists
|
||||
}
|
||||
if flags&linux.NLM_F_REPLACE != 0 {
|
||||
return syserr.ErrExists
|
||||
}
|
||||
|
||||
if ifinfomsg.Flags != 0 || ifinfomsg.Change != 0 {
|
||||
if ifinfomsg.Change & ^uint32(linux.IFF_UP) != 0 {
|
||||
ctx.Warningf("Unsupported ifi_change flags: %x", ifinfomsg.Change)
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
if ifinfomsg.Flags & ^uint32(linux.IFF_UP) != 0 {
|
||||
ctx.Warningf("Unsupported ifi_flags: %x", ifinfomsg.Change)
|
||||
return syserr.ErrInvalidArgument
|
||||
}
|
||||
// Netstack interfaces are always up.
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// delLink handles RTM_DELLINK requests.
|
||||
func (p *Protocol) delLink(ctx context.Context, msg *netlink.Message, ms *netlink.MessageSet) *syserr.Error {
|
||||
stack := inet.StackFromContext(ctx)
|
||||
@@ -576,6 +642,8 @@ func (p *Protocol) ProcessMessage(ctx context.Context, msg *netlink.Message, ms
|
||||
}
|
||||
} else if hdr.Flags&linux.NLM_F_REQUEST == linux.NLM_F_REQUEST {
|
||||
switch hdr.Type {
|
||||
case linux.RTM_NEWLINK:
|
||||
return p.newLink(ctx, msg, ms)
|
||||
case linux.RTM_GETLINK:
|
||||
return p.getLink(ctx, msg, ms)
|
||||
case linux.RTM_DELLINK:
|
||||
|
||||
@@ -198,6 +198,32 @@ TEST(NetlinkRouteTest, GetLinkByIndex) {
|
||||
EXPECT_TRUE(found) << "Netlink response does not contain any links.";
|
||||
}
|
||||
|
||||
TEST(NetlinkRouteTest, LinkUp) {
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));
|
||||
SKIP_IF(IsRunningWithHostinet());
|
||||
|
||||
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
|
||||
|
||||
FileDescriptor fd =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
struct request {
|
||||
struct nlmsghdr hdr;
|
||||
struct ifinfomsg ifm;
|
||||
};
|
||||
|
||||
struct request req = {};
|
||||
req.hdr.nlmsg_len = sizeof(req);
|
||||
req.hdr.nlmsg_type = RTM_NEWLINK;
|
||||
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
req.hdr.nlmsg_seq = kSeq;
|
||||
req.ifm.ifi_family = AF_UNSPEC;
|
||||
req.ifm.ifi_index = loopback_link.index;
|
||||
req.ifm.ifi_change = IFF_UP;
|
||||
req.ifm.ifi_flags = IFF_UP;
|
||||
EXPECT_NO_ERRNO(NetlinkRequestAckOrError(fd, kSeq, &req, sizeof(req)));
|
||||
}
|
||||
|
||||
TEST(NetlinkRouteTest, GetLinkByName) {
|
||||
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user