mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
Support time namespace
"time" namespace was introduced in Linux v5.6
support new time namespace to set boottime and monotonic time offset
Example runtime spec
"timeOffsets": {
"monotonic": {
"secs": 172800,
"nanosecs": 0
},
"boottime": {
"secs": 604800,
"nanosecs": 0
}
}
Signed-off-by: Chethan Suresh <chethan.suresh@sony.com>
This commit is contained in:
@@ -216,6 +216,9 @@ type Config struct {
|
|||||||
// Do not try to remount a bind mount again after the first attempt failed on source
|
// Do not try to remount a bind mount again after the first attempt failed on source
|
||||||
// filesystems that have nodev, noexec, nosuid, noatime, relatime, strictatime, nodiratime set
|
// filesystems that have nodev, noexec, nosuid, noatime, relatime, strictatime, nodiratime set
|
||||||
NoMountFallback bool `json:"no_mount_fallback,omitempty"`
|
NoMountFallback bool `json:"no_mount_fallback,omitempty"`
|
||||||
|
|
||||||
|
// TimeOffsets specifies the offset for supporting time namespaces.
|
||||||
|
TimeOffsets map[string]specs.LinuxTimeOffset `json:"time_offsets,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const (
|
|||||||
NEWIPC NamespaceType = "NEWIPC"
|
NEWIPC NamespaceType = "NEWIPC"
|
||||||
NEWUSER NamespaceType = "NEWUSER"
|
NEWUSER NamespaceType = "NEWUSER"
|
||||||
NEWCGROUP NamespaceType = "NEWCGROUP"
|
NEWCGROUP NamespaceType = "NEWCGROUP"
|
||||||
|
NEWTIME NamespaceType = "NEWTIME"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -38,6 +39,8 @@ func NsName(ns NamespaceType) string {
|
|||||||
return "uts"
|
return "uts"
|
||||||
case NEWCGROUP:
|
case NEWCGROUP:
|
||||||
return "cgroup"
|
return "cgroup"
|
||||||
|
case NEWTIME:
|
||||||
|
return "time"
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -72,6 +75,7 @@ func NamespaceTypes() []NamespaceType {
|
|||||||
NEWPID,
|
NEWPID,
|
||||||
NEWNS,
|
NEWNS,
|
||||||
NEWCGROUP,
|
NEWCGROUP,
|
||||||
|
NEWTIME,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ var namespaceInfo = map[NamespaceType]int{
|
|||||||
NEWUTS: unix.CLONE_NEWUTS,
|
NEWUTS: unix.CLONE_NEWUTS,
|
||||||
NEWPID: unix.CLONE_NEWPID,
|
NEWPID: unix.CLONE_NEWPID,
|
||||||
NEWCGROUP: unix.CLONE_NEWCGROUP,
|
NEWCGROUP: unix.CLONE_NEWCGROUP,
|
||||||
|
NEWTIME: unix.CLONE_NEWTIME,
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloneFlags parses the container's Namespaces options to set the correct
|
// CloneFlags parses the container's Namespaces options to set the correct
|
||||||
|
|||||||
@@ -106,6 +106,12 @@ func namespaces(config *configs.Config) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.Namespaces.Contains(configs.NEWTIME) {
|
||||||
|
if _, err := os.Stat("/proc/self/timens_offsets"); os.IsNotExist(err) {
|
||||||
|
return errors.New("time namespaces aren't enabled in the kernel")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2321,6 +2321,18 @@ func (c *Container) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Namespa
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write boottime and monotonic time ns offsets.
|
||||||
|
if c.config.Namespaces.Contains(configs.NEWTIME) && c.config.TimeOffsets != nil {
|
||||||
|
var offsetSpec bytes.Buffer
|
||||||
|
for clock, offset := range c.config.TimeOffsets {
|
||||||
|
fmt.Fprintf(&offsetSpec, "%s %d %d\n", clock, offset.Secs, offset.Nanosecs)
|
||||||
|
}
|
||||||
|
r.AddData(&Bytemsg{
|
||||||
|
Type: TimeOffsetsAttr,
|
||||||
|
Value: offsetSpec.Bytes(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return bytes.NewReader(r.Serialize()), nil
|
return bytes.NewReader(r.Serialize()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ const (
|
|||||||
GidmapPathAttr uint16 = 27289
|
GidmapPathAttr uint16 = 27289
|
||||||
MountSourcesAttr uint16 = 27290
|
MountSourcesAttr uint16 = 27290
|
||||||
IdmapSourcesAttr uint16 = 27291
|
IdmapSourcesAttr uint16 = 27291
|
||||||
|
TimeOffsetsAttr uint16 = 27292
|
||||||
)
|
)
|
||||||
|
|
||||||
type Int32msg struct {
|
type Int32msg struct {
|
||||||
|
|||||||
@@ -28,5 +28,8 @@
|
|||||||
#ifndef CLONE_NEWNET
|
#ifndef CLONE_NEWNET
|
||||||
# define CLONE_NEWNET 0x40000000 /* New network namespace */
|
# define CLONE_NEWNET 0x40000000 /* New network namespace */
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef CLONE_NEWTIME
|
||||||
|
# define CLONE_NEWTIME 0x00000080 /* New time namespace */
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* NSENTER_NAMESPACE_H */
|
#endif /* NSENTER_NAMESPACE_H */
|
||||||
|
|||||||
@@ -104,6 +104,10 @@ struct nlconfig_t {
|
|||||||
/* Idmap sources opened outside the container userns which will be id mapped. */
|
/* Idmap sources opened outside the container userns which will be id mapped. */
|
||||||
char *idmapsources;
|
char *idmapsources;
|
||||||
size_t idmapsources_len;
|
size_t idmapsources_len;
|
||||||
|
|
||||||
|
/* Time NS offsets. */
|
||||||
|
char *timensoffset;
|
||||||
|
size_t timensoffset_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -122,6 +126,7 @@ struct nlconfig_t {
|
|||||||
#define GIDMAPPATH_ATTR 27289
|
#define GIDMAPPATH_ATTR 27289
|
||||||
#define MOUNT_SOURCES_ATTR 27290
|
#define MOUNT_SOURCES_ATTR 27290
|
||||||
#define IDMAP_SOURCES_ATTR 27291
|
#define IDMAP_SOURCES_ATTR 27291
|
||||||
|
#define TIMENSOFFSET_ATTR 27292
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use the raw syscall for versions of glibc which don't include a function for
|
* Use the raw syscall for versions of glibc which don't include a function for
|
||||||
@@ -351,6 +356,8 @@ static int nsflag(char *name)
|
|||||||
return CLONE_NEWUSER;
|
return CLONE_NEWUSER;
|
||||||
else if (!strcmp(name, "uts"))
|
else if (!strcmp(name, "uts"))
|
||||||
return CLONE_NEWUTS;
|
return CLONE_NEWUTS;
|
||||||
|
else if (!strcmp(name, "time"))
|
||||||
|
return CLONE_NEWTIME;
|
||||||
|
|
||||||
/* If we don't recognise a name, fallback to 0. */
|
/* If we don't recognise a name, fallback to 0. */
|
||||||
return 0;
|
return 0;
|
||||||
@@ -445,6 +452,10 @@ static void nl_parse(int fd, struct nlconfig_t *config)
|
|||||||
config->idmapsources = current;
|
config->idmapsources = current;
|
||||||
config->idmapsources_len = payload_len;
|
config->idmapsources_len = payload_len;
|
||||||
break;
|
break;
|
||||||
|
case TIMENSOFFSET_ATTR:
|
||||||
|
config->timensoffset = current;
|
||||||
|
config->timensoffset_len = payload_len;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
bail("unknown netlink message type %d", nlattr->nla_type);
|
bail("unknown netlink message type %d", nlattr->nla_type);
|
||||||
}
|
}
|
||||||
@@ -747,6 +758,17 @@ void receive_idmapsources(int sockfd)
|
|||||||
receive_fd_sources(sockfd, "_LIBCONTAINER_IDMAP_FDS");
|
receive_fd_sources(sockfd, "_LIBCONTAINER_IDMAP_FDS");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void update_timens(char *map, size_t map_len)
|
||||||
|
{
|
||||||
|
if (map == NULL || map_len == 0)
|
||||||
|
return;
|
||||||
|
write_log(DEBUG, "update /proc/self/timens_offsets to '%s'", map);
|
||||||
|
if (write_file(map, map_len, "/proc/self/timens_offsets") < 0) {
|
||||||
|
if (errno != EPERM)
|
||||||
|
bail("failed to update /proc/self/timens_offsets");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void nsexec(void)
|
void nsexec(void)
|
||||||
{
|
{
|
||||||
int pipenum;
|
int pipenum;
|
||||||
@@ -1185,6 +1207,11 @@ void nsexec(void)
|
|||||||
bail("failed to sync with parent: SYNC_MOUNT_IDMAP_ACK: got %u", s);
|
bail("failed to sync with parent: SYNC_MOUNT_IDMAP_ACK: got %u", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set boottime and monotonic timens offsets.
|
||||||
|
*/
|
||||||
|
update_timens(config.timensoffset, config.timensoffset_len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: What about non-namespace clone flags that we're dropping here?
|
* TODO: What about non-namespace clone flags that we're dropping here?
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ func initMaps() {
|
|||||||
specs.IPCNamespace: configs.NEWIPC,
|
specs.IPCNamespace: configs.NEWIPC,
|
||||||
specs.UTSNamespace: configs.NEWUTS,
|
specs.UTSNamespace: configs.NEWUTS,
|
||||||
specs.CgroupNamespace: configs.NEWCGROUP,
|
specs.CgroupNamespace: configs.NEWCGROUP,
|
||||||
|
specs.TimeNamespace: configs.NEWTIME,
|
||||||
}
|
}
|
||||||
|
|
||||||
mountPropagationMapping = map[string]int{
|
mountPropagationMapping = map[string]int{
|
||||||
@@ -435,6 +436,9 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
|
|||||||
MemBwSchema: spec.Linux.IntelRdt.MemBwSchema,
|
MemBwSchema: spec.Linux.IntelRdt.MemBwSchema,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update timens offsets
|
||||||
|
config.TimeOffsets = spec.Linux.TimeOffsets
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the host UID that should own the container's cgroup.
|
// Set the host UID that should own the container's cgroup.
|
||||||
|
|||||||
Reference in New Issue
Block a user