Loading include/containerd/api.h +8 −2 Changes for include/containerd/api.h: 8 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -91,6 +91,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * or "dhcp": containerd asks the bridge's DHCP server, keeps * the lease renewed, takes router and name servers from it * gateway its default route (not with dhcp) * address6 an IPv6 address/len of eth0, e.g. 2001:db8::50/64 (network * = bridge); without one eth0 takes an address by SLAAC when a * router on the bridge advertises a prefix * gateway6 its IPv6 default route, global or link-local (fe80::1); * without one router advertisements give it * ipv6 no: eth0 without IPv6 (default yes) * vlan 1-4094 (network = bridge; 0: none): the veth is an access * port of that VLAN -- containerd turns on VLAN filtering of * the bridge (its other ports stay untagged in VLAN 1), gives Loading @@ -100,7 +106,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * tagged * mac eth0's MAC address; default: 02:.. made from the name, * the same at every start (for DHCP reservations) * dns repeated: name servers (default: the host's) * dns repeated: name servers, IPv4 or IPv6 (default: the host's) * bind repeated host[:container][:ro] -- a host directory or file * tmpfs repeated: a directory that gets an empty tmpfs * device repeated /dev/...[:/dev/... in the container]: a device Loading @@ -116,7 +122,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ListContainers -> per container: container (name), image, state * (stopped|starting|running|stopping|exited|failed), pid (host PID of * its PID 1), started, exit_code, restarts, error?, network, * address?, vlan?, veth? (the host's end of its veth pair, in the * address?, address6?, ipv6? (no if off), vlan?, veth? (the host's end of its veth pair, in the * bridge), lease? (the address DHCP gave it), autostart, restart, * memory (current bytes), tasks * GetContainer {name} -> container (name), state & co. as in the list, Loading src/containerctl.cpp +2 −0 Changes for src/containerctl.cpp: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * containerctl list containerctl status web * containerctl create web image=nginx network=bridge bridge=br0 \ * address=192.168.1.50/24 gateway=192.168.1.1 autostart=yes * containerctl edit web address6=2001:db8::50/64 gateway6=fe80::1 * containerctl edit web env=TZ=Europe/Berlin bind=/srv/www:/usr/share/nginx/html:ro * containerctl start|stop|restart|rm web containerctl kill web [HUP] * containerctl recreate web its changes go: fresh from the image Loading Loading @@ -284,6 +285,7 @@ int main(int argc, char **argv) { std::string pid = get(c, "pid") == "-1" ? "-" : get(c, "pid"); std::string addr = get(c, "network") != "bridge" ? get(c, "network") : get(c, "address") == "dhcp" ? "dhcp:" + get(c, "lease") : get(c, "address"); if (!get(c, "address6").empty()) addr += (addr.empty() ? "" : ",") + get(c, "address6"); printf("%-20s %-10s %-8s %-18s %s\n", get(c, "container").c_str(), state.c_str(), pid.c_str(), addr.c_str(), get(c, "image").c_str()); } Loading src/containers.cpp +6 −3 Changes for src/containers.cpp: 6 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -224,6 +224,7 @@ std::vector<std::string> nameservers(const Settings &s) { servers.push_back(n); } if (servers.empty() && !s.gateway.empty()) servers.push_back(s.gateway); if (servers.empty() && !s.gateway6.empty()) servers.push_back(s.gateway6); return servers; } Loading @@ -233,10 +234,10 @@ std::string prepare(const Settings &s) { if (!mkdirs(dir + "/" + d, 0755)) return sysErr(dir + "/" + d, errno); std::string host = s.hostname.empty() ? s.name : s.hostname; // with DHCP the supervisor writes the leased address in later std::string ip = s.network == "bridge" && !s.address.empty() && !isDhcp(s) ? s.address.substr(0, s.address.find('/')) : "127.0.1.1"; std::string ip = staticIp(s).empty() ? "127.0.1.1" : staticIp(s), ip6 = staticIp6(s); std::vector<std::string> servers = nameservers(s); if (!writeFile(dir + "/hosts", hostsText(host, ip)) || !writeFile(dir + "/hostname", host + "\n") || !writeFile(dir + "/resolv.conf", resolvConfText(servers)) || !writeFile(dir + "/host.yaml", hostYaml(host, ip)) || if (!writeFile(dir + "/hosts", hostsText(host, ip, ip6)) || !writeFile(dir + "/hostname", host + "\n") || !writeFile(dir + "/resolv.conf", resolvConfText(servers)) || !writeFile(dir + "/host.yaml", hostYaml(host, ip, ip6)) || !writeFile(dir + "/resolv.yaml", resolvYaml(servers))) return sysErr(dir, errno); return ""; Loading Loading @@ -409,6 +410,8 @@ void addRecord(Result &out, const std::string &name, const Settings &s) { out.add("network", s.network); if (s.network == "bridge") { out.add("address", s.address); if (!s.address6.empty()) out.add("address6", s.address6); if (!s.ipv6) out.add("ipv6", false); if (s.vlan) out.add("vlan", (long long)s.vlan); out.add("veth", hostVeth(name)); // its end on the host, while it runs } Loading src/netlink.cpp +22 −13 Changes for src/netlink.cpp: 22 added lines, 13 removed lines. Original line number Diff line number Diff line Loading @@ -245,20 +245,25 @@ std::string address(const std::string &ifname, const std::string &cidr, bool add int i = index(ifname); if (!i) return noSuch(ifname); size_t slash = cidr.find('/'); in_addr a{}; if (slash == std::string::npos || inet_pton(AF_INET, cidr.substr(0, slash).c_str(), &a) != 1) return "invalid address " + cidr; bool v6 = cidr.find(':') != std::string::npos; unsigned char a[16] = {0}; if (slash == std::string::npos || inet_pton(v6 ? AF_INET6 : AF_INET, cidr.substr(0, slash).c_str(), a) != 1) return "invalid address " + cidr; int len = std::atoi(cidr.substr(slash + 1).c_str()); size_t alen = v6 ? 16 : 4; Msg m(add ? RTM_NEWADDR : RTM_DELADDR, add ? NLM_F_CREATE | NLM_F_REPLACE : 0); auto *ifa = m.fixed<ifaddrmsg>(); ifa->ifa_family = AF_INET; ifa->ifa_family = v6 ? AF_INET6 : AF_INET; ifa->ifa_prefixlen = (unsigned char)len; ifa->ifa_index = (unsigned)i; m.attr(IFA_LOCAL, &a, 4); m.attr(IFA_ADDRESS, &a, 4); if (len < 31) { in_addr bc = a; if (v6) ifa->ifa_flags = IFA_F_NODAD; m.attr(IFA_LOCAL, a, alen); m.attr(IFA_ADDRESS, a, alen); if (!v6 && len < 31) { in_addr bc; memcpy(&bc, a, 4); uint32_t mask = len ? htonl(~0u << (32 - len)) : 0; bc.s_addr = (a.s_addr & mask) | ~mask; bc.s_addr = (bc.s_addr & mask) | ~mask; m.attr(IFA_BROADCAST, &bc, 4); } std::string err = talk(m); Loading @@ -270,17 +275,21 @@ std::string address(const std::string &ifname, const std::string &cidr, bool add std::string addAddress(const std::string &ifname, const std::string &cidr) { return address(ifname, cidr, true); } std::string delAddress(const std::string &ifname, const std::string &cidr) { return address(ifname, cidr, false); } std::string addDefaultRoute(const std::string &gateway) { in_addr gw{}; if (inet_pton(AF_INET, gateway.c_str(), &gw) != 1) return "invalid gateway " + gateway; std::string addDefaultRoute(const std::string &gateway, const std::string &ifname) { bool v6 = gateway.find(':') != std::string::npos; unsigned char gw[16] = {0}; if (inet_pton(v6 ? AF_INET6 : AF_INET, gateway.c_str(), gw) != 1) return "invalid gateway " + gateway; int oif = 0; if (!ifname.empty() && !(oif = index(ifname))) return noSuch(ifname); Msg m(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE); auto *rt = m.fixed<rtmsg>(); rt->rtm_family = AF_INET; rt->rtm_family = v6 ? AF_INET6 : AF_INET; rt->rtm_table = RT_TABLE_MAIN; rt->rtm_protocol = RTPROT_STATIC; rt->rtm_scope = RT_SCOPE_UNIVERSE; rt->rtm_type = RTN_UNICAST; m.attr(RTA_GATEWAY, &gw, 4); m.attr(RTA_GATEWAY, gw, v6 ? 16 : 4); if (oif) m.u32(RTA_OIF, (uint32_t)oif); std::string err = talk(m); return err.empty() ? "" : "route via " + gateway + ": " + err; } Loading src/netlink.h +5 −1 Changes for src/netlink.h: 5 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -47,9 +47,13 @@ std::string setMaster(const std::string &ifname, const std::string &bridge); std::string setUp(const std::string &ifname); std::string moveToNetns(const std::string &ifname, pid_t pid); std::string rename(const std::string &ifname, const std::string &to); // cidr: a.b.c.d/len or an IPv6 address/len (no duplicate address // detection: usable at once) std::string addAddress(const std::string &ifname, const std::string &cidr); std::string delAddress(const std::string &ifname, const std::string &cidr); std::string addDefaultRoute(const std::string &gateway); // gateway: IPv4 or IPv6; ifname: the route's interface ("" : any, an IPv6 // link-local gateway needs it) std::string addDefaultRoute(const std::string &gateway, const std::string &ifname = ""); std::string deleteLink(const std::string &ifname); // Bridge VLAN filtering (802.1Q-aware bridge): turned on for bridge (all Loading Loading
include/containerd/api.h +8 −2 Changes for include/containerd/api.h: 8 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -91,6 +91,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * or "dhcp": containerd asks the bridge's DHCP server, keeps * the lease renewed, takes router and name servers from it * gateway its default route (not with dhcp) * address6 an IPv6 address/len of eth0, e.g. 2001:db8::50/64 (network * = bridge); without one eth0 takes an address by SLAAC when a * router on the bridge advertises a prefix * gateway6 its IPv6 default route, global or link-local (fe80::1); * without one router advertisements give it * ipv6 no: eth0 without IPv6 (default yes) * vlan 1-4094 (network = bridge; 0: none): the veth is an access * port of that VLAN -- containerd turns on VLAN filtering of * the bridge (its other ports stay untagged in VLAN 1), gives Loading @@ -100,7 +106,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * tagged * mac eth0's MAC address; default: 02:.. made from the name, * the same at every start (for DHCP reservations) * dns repeated: name servers (default: the host's) * dns repeated: name servers, IPv4 or IPv6 (default: the host's) * bind repeated host[:container][:ro] -- a host directory or file * tmpfs repeated: a directory that gets an empty tmpfs * device repeated /dev/...[:/dev/... in the container]: a device Loading @@ -116,7 +122,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ListContainers -> per container: container (name), image, state * (stopped|starting|running|stopping|exited|failed), pid (host PID of * its PID 1), started, exit_code, restarts, error?, network, * address?, vlan?, veth? (the host's end of its veth pair, in the * address?, address6?, ipv6? (no if off), vlan?, veth? (the host's end of its veth pair, in the * bridge), lease? (the address DHCP gave it), autostart, restart, * memory (current bytes), tasks * GetContainer {name} -> container (name), state & co. as in the list, Loading
src/containerctl.cpp +2 −0 Changes for src/containerctl.cpp: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * containerctl list containerctl status web * containerctl create web image=nginx network=bridge bridge=br0 \ * address=192.168.1.50/24 gateway=192.168.1.1 autostart=yes * containerctl edit web address6=2001:db8::50/64 gateway6=fe80::1 * containerctl edit web env=TZ=Europe/Berlin bind=/srv/www:/usr/share/nginx/html:ro * containerctl start|stop|restart|rm web containerctl kill web [HUP] * containerctl recreate web its changes go: fresh from the image Loading Loading @@ -284,6 +285,7 @@ int main(int argc, char **argv) { std::string pid = get(c, "pid") == "-1" ? "-" : get(c, "pid"); std::string addr = get(c, "network") != "bridge" ? get(c, "network") : get(c, "address") == "dhcp" ? "dhcp:" + get(c, "lease") : get(c, "address"); if (!get(c, "address6").empty()) addr += (addr.empty() ? "" : ",") + get(c, "address6"); printf("%-20s %-10s %-8s %-18s %s\n", get(c, "container").c_str(), state.c_str(), pid.c_str(), addr.c_str(), get(c, "image").c_str()); } Loading
src/containers.cpp +6 −3 Changes for src/containers.cpp: 6 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -224,6 +224,7 @@ std::vector<std::string> nameservers(const Settings &s) { servers.push_back(n); } if (servers.empty() && !s.gateway.empty()) servers.push_back(s.gateway); if (servers.empty() && !s.gateway6.empty()) servers.push_back(s.gateway6); return servers; } Loading @@ -233,10 +234,10 @@ std::string prepare(const Settings &s) { if (!mkdirs(dir + "/" + d, 0755)) return sysErr(dir + "/" + d, errno); std::string host = s.hostname.empty() ? s.name : s.hostname; // with DHCP the supervisor writes the leased address in later std::string ip = s.network == "bridge" && !s.address.empty() && !isDhcp(s) ? s.address.substr(0, s.address.find('/')) : "127.0.1.1"; std::string ip = staticIp(s).empty() ? "127.0.1.1" : staticIp(s), ip6 = staticIp6(s); std::vector<std::string> servers = nameservers(s); if (!writeFile(dir + "/hosts", hostsText(host, ip)) || !writeFile(dir + "/hostname", host + "\n") || !writeFile(dir + "/resolv.conf", resolvConfText(servers)) || !writeFile(dir + "/host.yaml", hostYaml(host, ip)) || if (!writeFile(dir + "/hosts", hostsText(host, ip, ip6)) || !writeFile(dir + "/hostname", host + "\n") || !writeFile(dir + "/resolv.conf", resolvConfText(servers)) || !writeFile(dir + "/host.yaml", hostYaml(host, ip, ip6)) || !writeFile(dir + "/resolv.yaml", resolvYaml(servers))) return sysErr(dir, errno); return ""; Loading Loading @@ -409,6 +410,8 @@ void addRecord(Result &out, const std::string &name, const Settings &s) { out.add("network", s.network); if (s.network == "bridge") { out.add("address", s.address); if (!s.address6.empty()) out.add("address6", s.address6); if (!s.ipv6) out.add("ipv6", false); if (s.vlan) out.add("vlan", (long long)s.vlan); out.add("veth", hostVeth(name)); // its end on the host, while it runs } Loading
src/netlink.cpp +22 −13 Changes for src/netlink.cpp: 22 added lines, 13 removed lines. Original line number Diff line number Diff line Loading @@ -245,20 +245,25 @@ std::string address(const std::string &ifname, const std::string &cidr, bool add int i = index(ifname); if (!i) return noSuch(ifname); size_t slash = cidr.find('/'); in_addr a{}; if (slash == std::string::npos || inet_pton(AF_INET, cidr.substr(0, slash).c_str(), &a) != 1) return "invalid address " + cidr; bool v6 = cidr.find(':') != std::string::npos; unsigned char a[16] = {0}; if (slash == std::string::npos || inet_pton(v6 ? AF_INET6 : AF_INET, cidr.substr(0, slash).c_str(), a) != 1) return "invalid address " + cidr; int len = std::atoi(cidr.substr(slash + 1).c_str()); size_t alen = v6 ? 16 : 4; Msg m(add ? RTM_NEWADDR : RTM_DELADDR, add ? NLM_F_CREATE | NLM_F_REPLACE : 0); auto *ifa = m.fixed<ifaddrmsg>(); ifa->ifa_family = AF_INET; ifa->ifa_family = v6 ? AF_INET6 : AF_INET; ifa->ifa_prefixlen = (unsigned char)len; ifa->ifa_index = (unsigned)i; m.attr(IFA_LOCAL, &a, 4); m.attr(IFA_ADDRESS, &a, 4); if (len < 31) { in_addr bc = a; if (v6) ifa->ifa_flags = IFA_F_NODAD; m.attr(IFA_LOCAL, a, alen); m.attr(IFA_ADDRESS, a, alen); if (!v6 && len < 31) { in_addr bc; memcpy(&bc, a, 4); uint32_t mask = len ? htonl(~0u << (32 - len)) : 0; bc.s_addr = (a.s_addr & mask) | ~mask; bc.s_addr = (bc.s_addr & mask) | ~mask; m.attr(IFA_BROADCAST, &bc, 4); } std::string err = talk(m); Loading @@ -270,17 +275,21 @@ std::string address(const std::string &ifname, const std::string &cidr, bool add std::string addAddress(const std::string &ifname, const std::string &cidr) { return address(ifname, cidr, true); } std::string delAddress(const std::string &ifname, const std::string &cidr) { return address(ifname, cidr, false); } std::string addDefaultRoute(const std::string &gateway) { in_addr gw{}; if (inet_pton(AF_INET, gateway.c_str(), &gw) != 1) return "invalid gateway " + gateway; std::string addDefaultRoute(const std::string &gateway, const std::string &ifname) { bool v6 = gateway.find(':') != std::string::npos; unsigned char gw[16] = {0}; if (inet_pton(v6 ? AF_INET6 : AF_INET, gateway.c_str(), gw) != 1) return "invalid gateway " + gateway; int oif = 0; if (!ifname.empty() && !(oif = index(ifname))) return noSuch(ifname); Msg m(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE); auto *rt = m.fixed<rtmsg>(); rt->rtm_family = AF_INET; rt->rtm_family = v6 ? AF_INET6 : AF_INET; rt->rtm_table = RT_TABLE_MAIN; rt->rtm_protocol = RTPROT_STATIC; rt->rtm_scope = RT_SCOPE_UNIVERSE; rt->rtm_type = RTN_UNICAST; m.attr(RTA_GATEWAY, &gw, 4); m.attr(RTA_GATEWAY, gw, v6 ? 16 : 4); if (oif) m.u32(RTA_OIF, (uint32_t)oif); std::string err = talk(m); return err.empty() ? "" : "route via " + gateway + ": " + err; } Loading
src/netlink.h +5 −1 Changes for src/netlink.h: 5 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -47,9 +47,13 @@ std::string setMaster(const std::string &ifname, const std::string &bridge); std::string setUp(const std::string &ifname); std::string moveToNetns(const std::string &ifname, pid_t pid); std::string rename(const std::string &ifname, const std::string &to); // cidr: a.b.c.d/len or an IPv6 address/len (no duplicate address // detection: usable at once) std::string addAddress(const std::string &ifname, const std::string &cidr); std::string delAddress(const std::string &ifname, const std::string &cidr); std::string addDefaultRoute(const std::string &gateway); // gateway: IPv4 or IPv6; ifname: the route's interface ("" : any, an IPv6 // link-local gateway needs it) std::string addDefaultRoute(const std::string &gateway, const std::string &ifname = ""); std::string deleteLink(const std::string &ifname); // Bridge VLAN filtering (802.1Q-aware bridge): turned on for bridge (all Loading