Skip to content

Commit f644e9a

Browse files
committed
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 <[email protected]>
1 parent dbe8434 commit f644e9a

File tree

9 files changed

+59
-0
lines changed

9 files changed

+59
-0
lines changed

libcontainer/configs/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ type Config struct {
216216
// Do not try to remount a bind mount again after the first attempt failed on source
217217
// filesystems that have nodev, noexec, nosuid, noatime, relatime, strictatime, nodiratime set
218218
NoMountFallback bool `json:"no_mount_fallback,omitempty"`
219+
220+
// TimeOffsets specifies the offset for supporting time namespaces.
221+
TimeOffsets map[string]specs.LinuxTimeOffset `json:"time_offsets,omitempty"`
219222
}
220223

221224
type (

libcontainer/configs/namespaces_linux.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const (
1414
NEWIPC NamespaceType = "NEWIPC"
1515
NEWUSER NamespaceType = "NEWUSER"
1616
NEWCGROUP NamespaceType = "NEWCGROUP"
17+
NEWTIME NamespaceType = "NEWTIME"
1718
)
1819

1920
var (
@@ -38,6 +39,8 @@ func NsName(ns NamespaceType) string {
3839
return "uts"
3940
case NEWCGROUP:
4041
return "cgroup"
42+
case NEWTIME:
43+
return "time"
4144
}
4245
return ""
4346
}
@@ -72,6 +75,7 @@ func NamespaceTypes() []NamespaceType {
7275
NEWPID,
7376
NEWNS,
7477
NEWCGROUP,
78+
NEWTIME,
7579
}
7680
}
7781

libcontainer/configs/namespaces_syscall.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var namespaceInfo = map[NamespaceType]int{
1717
NEWUTS: unix.CLONE_NEWUTS,
1818
NEWPID: unix.CLONE_NEWPID,
1919
NEWCGROUP: unix.CLONE_NEWCGROUP,
20+
NEWTIME: unix.CLONE_NEWTIME,
2021
}
2122

2223
// CloneFlags parses the container's Namespaces options to set the correct

libcontainer/configs/validate/validator.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ func namespaces(config *configs.Config) error {
106106
}
107107
}
108108

109+
if config.Namespaces.Contains(configs.NEWTIME) {
110+
if _, err := os.Stat("/proc/self/timens_offsets"); os.IsNotExist(err) {
111+
return errors.New("time namespaces aren't enabled in the kernel")
112+
}
113+
}
114+
109115
return nil
110116
}
111117

libcontainer/container_linux.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2321,6 +2321,16 @@ func (c *Container) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Namespa
23212321
})
23222322
}
23232323

2324+
// write boottime and monotonic time ns offsets.
2325+
if c.config.TimeOffsets != nil {
2326+
timeOffset := append([]byte("monotonic"), []byte(fmt.Sprintf(" %d %d\n", c.config.TimeOffsets["monotonic"].Secs, c.config.TimeOffsets["monotonic"].Nanosecs))...)
2327+
timeOffset = append(timeOffset, []byte("boottime")...)
2328+
r.AddData(&Bytemsg{
2329+
Type: TimeOffsetsAttr,
2330+
Value: append(timeOffset, []byte(fmt.Sprintf(" %d %d", c.config.TimeOffsets["boottime"].Secs, c.config.TimeOffsets["boottime"].Nanosecs))...),
2331+
})
2332+
}
2333+
23242334
return bytes.NewReader(r.Serialize()), nil
23252335
}
23262336

libcontainer/message_linux.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const (
2323
GidmapPathAttr uint16 = 27289
2424
MountSourcesAttr uint16 = 27290
2525
IdmapSourcesAttr uint16 = 27291
26+
TimeOffsetsAttr uint16 = 27292
2627
)
2728

2829
type Int32msg struct {

libcontainer/nsenter/namespace.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,8 @@
2828
#ifndef CLONE_NEWNET
2929
# define CLONE_NEWNET 0x40000000 /* New network namespace */
3030
#endif
31+
#ifndef CLONE_NEWTIME
32+
# define CLONE_NEWTIME 0x00000080 /* New time namespace */
33+
#endif
3134

3235
#endif /* NSENTER_NAMESPACE_H */

libcontainer/nsenter/nsexec.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ struct nlconfig_t {
104104
/* Idmap sources opened outside the container userns which will be id mapped. */
105105
char *idmapsources;
106106
size_t idmapsources_len;
107+
108+
/* Time NS offsets. */
109+
char *timensoffset;
110+
size_t timensoffset_len;
107111
};
108112

109113
/*
@@ -122,6 +126,8 @@ struct nlconfig_t {
122126
#define GIDMAPPATH_ATTR 27289
123127
#define MOUNT_SOURCES_ATTR 27290
124128
#define IDMAP_SOURCES_ATTR 27291
129+
#define TIMENSOFFSET_ATTR 27292
130+
125131

126132
/*
127133
* Use the raw syscall for versions of glibc which don't include a function for
@@ -351,6 +357,8 @@ static int nsflag(char *name)
351357
return CLONE_NEWUSER;
352358
else if (!strcmp(name, "uts"))
353359
return CLONE_NEWUTS;
360+
else if (!strcmp(name, "time"))
361+
return CLONE_NEWTIME;
354362

355363
/* If we don't recognise a name, fallback to 0. */
356364
return 0;
@@ -444,6 +452,9 @@ static void nl_parse(int fd, struct nlconfig_t *config)
444452
case IDMAP_SOURCES_ATTR:
445453
config->idmapsources = current;
446454
config->idmapsources_len = payload_len;
455+
case TIMENSOFFSET_ATTR:
456+
config->timensoffset = current;
457+
config->timensoffset_len = payload_len;
447458
break;
448459
default:
449460
bail("unknown netlink message type %d", nlattr->nla_type);
@@ -747,6 +758,17 @@ void receive_idmapsources(int sockfd)
747758
receive_fd_sources(sockfd, "_LIBCONTAINER_IDMAP_FDS");
748759
}
749760

761+
static void update_timens(char *map, size_t map_len)
762+
{
763+
if (map == NULL || map_len == 0)
764+
return;
765+
write_log(DEBUG, "update /proc/self/timens_offsets to '%s'", map);
766+
if (write_file(map, map_len, "/proc/self/timens_offsets") < 0) {
767+
if (errno != EPERM)
768+
bail("failed to update /proc/self/timens_offsets");
769+
}
770+
}
771+
750772
void nsexec(void)
751773
{
752774
int pipenum;
@@ -1185,6 +1207,11 @@ void nsexec(void)
11851207
bail("failed to sync with parent: SYNC_MOUNT_IDMAP_ACK: got %u", s);
11861208
}
11871209

1210+
/*
1211+
* set boottime and monotonic timens offsets.
1212+
*/
1213+
update_timens(config.timensoffset, config.timensoffset_len);
1214+
11881215
/*
11891216
* TODO: What about non-namespace clone flags that we're dropping here?
11901217
*

libcontainer/specconv/spec_linux.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func initMaps() {
4949
specs.IPCNamespace: configs.NEWIPC,
5050
specs.UTSNamespace: configs.NEWUTS,
5151
specs.CgroupNamespace: configs.NEWCGROUP,
52+
specs.TimeNamespace: configs.NEWTIME,
5253
}
5354

5455
mountPropagationMapping = map[string]int{
@@ -435,6 +436,9 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
435436
MemBwSchema: spec.Linux.IntelRdt.MemBwSchema,
436437
}
437438
}
439+
440+
// update timens offsets
441+
config.TimeOffsets = spec.Linux.TimeOffsets
438442
}
439443

440444
// Set the host UID that should own the container's cgroup.

0 commit comments

Comments
 (0)