2017-11-09 00:30:41 +00:00
|
|
|
|
Le *namespace* `network` {#net-ns}
|
2021-10-31 19:51:17 +00:00
|
|
|
|
------------------------
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
Voyons maintenant plus en détail les différents espaces de nom, leurs
|
|
|
|
|
caractéristiques et leurs usages ; en commençant par le *namespace* `network`.
|
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
### Introduction
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
L'espace de noms `network`, comme son nom l'indique permet de virtualiser tout
|
2022-02-24 19:43:43 +00:00
|
|
|
|
ce qui est en lien avec le réseau : les interfaces, les ports, les routes, les
|
2016-10-19 03:24:05 +00:00
|
|
|
|
règles de filtrage, etc.
|
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
En entrant dans un nouvel espace de noms `network`, on se retrouve dans un
|
2022-02-24 19:43:43 +00:00
|
|
|
|
environnement qui n'a plus qu'une interface de *loopback* :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```
|
2022-11-11 09:14:16 +00:00
|
|
|
|
42sh# unshare --net ip a
|
2018-11-16 01:38:41 +00:00
|
|
|
|
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
|
|
|
|
|
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
::::: {.warning}
|
|
|
|
|
|
2017-11-09 00:30:41 +00:00
|
|
|
|
Bien que portant le même nom que l'interface de *loopback* de notre
|
|
|
|
|
environnement principal, il s'agit bien de deux interfaces isolées l'une de
|
|
|
|
|
l'autre.
|
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
:::::
|
|
|
|
|
|
|
|
|
|
Afin d'amener du réseau à notre nouvel espace de nom, il va falloir lui
|
|
|
|
|
attribuer des interface. En fait, nous allons pouvoir déplacer nos interfaces
|
|
|
|
|
réseaux, dans le *namespace* vers lequel elle doit être accessible. Une
|
|
|
|
|
interface donnée ne peut se trouver que dans un seul *namespace* à la fois.
|
|
|
|
|
|
2017-11-09 00:30:41 +00:00
|
|
|
|
Qui dit nouvelle pile réseau, dit également que les ports qui sont assignés
|
2022-02-24 19:43:43 +00:00
|
|
|
|
dans l'espace principal, ne le sont plus dans le conteneur : il est donc
|
2017-11-09 00:30:41 +00:00
|
|
|
|
possible de lancer un serveur web sans qu'il n'entre en conflit avec celui d'un
|
2016-10-19 03:24:05 +00:00
|
|
|
|
autre espace de noms.
|
|
|
|
|
|
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
### Premiers pas avec `ip netns`
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
La suite d'outils `iproute2` propose une interface simplifiée pour utiliser le
|
2022-02-24 19:43:43 +00:00
|
|
|
|
*namespace* `network` : `ip netns`.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Nous pouvons tout d'abord créer un nouvel espace de noms :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2022-11-11 09:14:16 +00:00
|
|
|
|
```
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh# ip netns add virli
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
::::: {.code}
|
|
|
|
|
|
2016-10-19 03:24:05 +00:00
|
|
|
|
La technique utilisée ici pour avoir des *namespaces* nommés est la même que
|
2017-11-09 00:30:41 +00:00
|
|
|
|
celle que nous avons vue dans
|
2022-02-24 19:43:43 +00:00
|
|
|
|
[la première partie sur les *namespaces*](#ns-lifetime) : via un `mount --bind`
|
2017-11-09 00:30:41 +00:00
|
|
|
|
dans le dossier `/var/run/netns/`. Cela permet de faire persister le namespace
|
|
|
|
|
malgré le fait que plus aucun processus ne s'y exécute.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
Nous pouvons créer artificiellement des entrées pour `ip netns` avec les
|
|
|
|
|
quelques commandes suivantes :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```
|
|
|
|
|
# On affiche la liste des netns déjà créés
|
|
|
|
|
42sh# ip netns
|
|
|
|
|
virli
|
|
|
|
|
|
|
|
|
|
# On crée un fichier pour servir de réceptacle au bind mount
|
|
|
|
|
42sh# touch /var/run/netns/foo
|
|
|
|
|
|
|
|
|
|
# On crée un nouveau namespace net, puis on bind tout de suite le
|
|
|
|
|
# fichier de namespace vers le fichier que l'on vient de créer
|
|
|
|
|
42sh# unshare --net \
|
|
|
|
|
mount --bind /proc/self/ns/net /var/run/netns/foo
|
|
|
|
|
|
|
|
|
|
# Testons si cela a bien marché
|
|
|
|
|
42sh# ip netns
|
|
|
|
|
foo virli
|
|
|
|
|
42sh# ip netns exec foo ip link
|
|
|
|
|
1: lo: <LOOPBACK> mut 65536 qdisc noop state DOWN mode DEFAULT group default
|
|
|
|
|
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
Les fichiers utilisés par `ip netns` ne sont donc rien de plus que des
|
|
|
|
|
*bind-mount*. Ce qui explique qu'ils soient persistant même sans processus
|
|
|
|
|
s'exécutant à l'intérieur.
|
|
|
|
|
|
|
|
|
|
:::::
|
|
|
|
|
|
2017-11-09 00:30:41 +00:00
|
|
|
|
Maintenant que notre *namespace* est créé, nous pouvons regarder s'il contient
|
2022-02-24 19:43:43 +00:00
|
|
|
|
des interfaces :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```
|
|
|
|
|
42sh# ip netns exec virli ip link
|
2022-02-24 19:43:43 +00:00
|
|
|
|
1: lo: <LOOPBACK> mut 65536 qdisc noop state DOWN mode DEFAULT group default
|
2018-11-16 01:38:41 +00:00
|
|
|
|
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-11-09 00:30:41 +00:00
|
|
|
|
Cette commande ne nous montre que l'interface de *loopback*, car nous n'avons
|
|
|
|
|
pour l'instant pas encore attaché la moindre interface.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-05-12 00:46:31 +00:00
|
|
|
|
D'ailleurs, cette interface est rapportée comme étant désactivée, activons-la
|
2022-02-24 19:43:43 +00:00
|
|
|
|
via la commande :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2022-11-11 09:14:16 +00:00
|
|
|
|
```
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh# ip netns exec virli ip link set dev lo up
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-05-12 00:46:31 +00:00
|
|
|
|
À ce stade, nous pouvons déjà commencer à lancer un `ping` sur cette interface :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```
|
|
|
|
|
42sh# ip netns exec virli ping 127.0.0.1
|
|
|
|
|
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
|
|
|
|
|
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.038 ms
|
|
|
|
|
...
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
### *Virtual Ethernet*
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
Étant donné qu'une interface réseau ne peut être présente que dans un seul
|
|
|
|
|
espace de noms à la fois, il n'est pas bien pratique d'imposer d'avoir une
|
|
|
|
|
interface physique par conteneur, d'autant plus si l'on a plusieurs
|
|
|
|
|
centaines de conteneurs à gérer.
|
|
|
|
|
|
|
|
|
|
Une technique couramment employée consiste à créer une interface virtuelle de
|
2022-02-24 19:43:43 +00:00
|
|
|
|
type `veth` :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh# ip link add veth0 type veth peer name veth1
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Une interface `veth` se comporte comme un tube bidirectionnel : tout ce qui
|
2016-10-19 03:24:05 +00:00
|
|
|
|
entre d'un côté sort de l'autre et inversement. La commande précédente a donc
|
2022-02-24 19:43:43 +00:00
|
|
|
|
créé deux interfaces `veth0` et `veth1` : les paquets envoyés sur `veth0` sont
|
2017-11-09 00:30:41 +00:00
|
|
|
|
donc reçus par `veth1` et les paquets envoyés à `veth1` sont reçus par `veth0`.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
::::: {.code}
|
|
|
|
|
|
|
|
|
|
Pour réaliser ces étapes dans un langage de programmation, nous allons passer
|
|
|
|
|
par Netlink. Il s'agit d'une interface de communication entre le noyau et
|
|
|
|
|
l'espace utilisateur. Il faut commencer par créer une `socket` pour avoir accès
|
|
|
|
|
à l'API Netlink, nous pourrons ensuite envoyer des requêtes, comme celle nous
|
|
|
|
|
permettant de créer notre interface `veth`.
|
|
|
|
|
|
|
|
|
|
Un message Netlink a une structure, alignée sur 4 octets, contenant un en-tête
|
|
|
|
|
et des données. Le format de l'en-tête est décrit dans le RFC
|
|
|
|
|
3549[^RFC3549] :
|
|
|
|
|
|
|
|
|
|
[^RFC3549]: <https://tools.ietf.org/html/rfc3549>
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```c
|
|
|
|
|
struct nlmsghdr {
|
|
|
|
|
uint32_t nlmsg_len; // Length of message including header
|
|
|
|
|
uint16_t nlmsg_type; // Type of message content
|
|
|
|
|
uint16_t nlmsg_flags; // Additional flags
|
|
|
|
|
uint32_t nlmsg_seq; // Sequence number
|
|
|
|
|
uint32_t nlmsg_pid; // Sender port ID
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
Parmi les fonctionnalités de Netlink, nous allons utiliser le module NIS
|
2022-11-14 12:52:40 +00:00
|
|
|
|
(Network Interface Service)[^RFC3549NIS]. Il spécifie le format par lequel
|
2022-11-11 09:14:16 +00:00
|
|
|
|
doivent commencer les données liées à l'administration d'interfaces réseau.
|
|
|
|
|
|
|
|
|
|
[^RFC3549NIS]: Network Interface Service Module <https://tools.ietf.org/html/rfc3549#section-2.3.3.1>
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```c
|
|
|
|
|
struct ifinfomsg {
|
|
|
|
|
uint8_t ifi_family; // AF_UNSPEC
|
|
|
|
|
// uint8_t Reserved
|
|
|
|
|
uint16_t ifi_type; // Device type
|
|
|
|
|
int32_t ifi_index; // Interface index
|
|
|
|
|
uint32_t ifi_flags; // Device flags
|
|
|
|
|
uint32_t ifi_change; // change mask
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
Le module NIS a besoin que les données soient transmises sous forme d'*attributs
|
|
|
|
|
Netlink*. Ces attributs fournissent un moyen de segmenter la charge utile en
|
|
|
|
|
sous-sections. Un attribut a une taille et un type, en plus de sa charge utile.
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```c
|
|
|
|
|
struct rtattr {
|
|
|
|
|
uint16_t rta_len; // Length of option
|
|
|
|
|
uint16_t rta_type; // Type of option
|
|
|
|
|
// Data follows
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
Le *payload* du message Netlink sera donc transmis comme une liste d'attributs (où
|
|
|
|
|
chaque attribut peut à son tour avoir des attributs imbriqués).
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```c
|
|
|
|
|
struct rtattr {
|
|
|
|
|
unsigned short rta_len;
|
|
|
|
|
unsigned short rta_type;
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
En se basant sur du code d'`ip link`[^IPLINK], on peut reconstituer la
|
|
|
|
|
communication suivante :
|
|
|
|
|
|
|
|
|
|
[^IPLINK]: <https://github.com/shemminger/iproute2/blob/main/ip/link_veth.c>
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```c
|
|
|
|
|
#define MAX_PAYLOAD 1024
|
|
|
|
|
|
|
|
|
|
struct nlreq {
|
|
|
|
|
struct nlmsghdr hdr; // Netlink message header
|
|
|
|
|
struct ifinfomsg msg; // First data filled with NIS module info
|
|
|
|
|
char buf[MAX_PAYLOAD]; // Remaining payload
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
create_veth(char *ifname, char *peername)
|
|
|
|
|
{
|
|
|
|
|
// Create the netlink socket
|
|
|
|
|
int sock_fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
|
|
|
|
if (sock_fd < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
uint16_t flags =
|
|
|
|
|
NLM_F_REQUEST // We build a request message
|
|
|
|
|
| NLM_F_CREATE // Create a device if it doesn't exist
|
|
|
|
|
| NLM_F_EXCL // Do nothing if it already exists
|
|
|
|
|
| NLM_F_ACK; // Except an ack as reply or an error
|
|
|
|
|
|
|
|
|
|
// Initialise request message
|
|
|
|
|
struct nl_req req = {
|
|
|
|
|
.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
|
|
|
|
.hdr.nlmsg_flags = flags,
|
|
|
|
|
.hdr.nlmsg_type = RTM_NEWLINK,
|
|
|
|
|
.msg.ifi_family = PF_NETLINK,
|
|
|
|
|
};
|
|
|
|
|
struct nlmsghdr *hdr = &req.hdr;
|
|
|
|
|
int maxlen = sizeof(req);
|
|
|
|
|
|
|
|
|
|
// Attribute r0 with veth info
|
|
|
|
|
addattr_l(hdr, maxlen, IFLA_IFNAME, ifname, strlen(ifname) + 1);
|
|
|
|
|
|
|
|
|
|
// Attribute r1 nested within r1, containing iface info
|
|
|
|
|
struct rtattr *linfo =
|
|
|
|
|
addattr_nest(n, maxlen, IFLA_LINKINFO);
|
|
|
|
|
// Specify the device type is veth
|
|
|
|
|
addattr_l(hdr, maxlen, IFLA_INFO_KIND, "veth", 5);
|
|
|
|
|
|
|
|
|
|
// r2: another nested attribute
|
|
|
|
|
struct rtattr *linfodata =
|
|
|
|
|
addattr_nest(hdr, maxlen, IFLA_INFO_DATA);
|
|
|
|
|
|
|
|
|
|
// r3: nested attribute, contains the peer name
|
|
|
|
|
struct rtattr *peerinfo =
|
|
|
|
|
addattr_nest(n, maxlen, VETH_INFO_PEER);
|
|
|
|
|
n->nlmsg_len += sizeof(struct ifinfomsg);
|
|
|
|
|
addattr_l(n, maxlen, IFLA_IFNAME, peername, strlen(peername) + 1);
|
|
|
|
|
addattr_nest_end(hdr, peerinfo);
|
|
|
|
|
|
|
|
|
|
addattr_nest_end(hdr, linfodata);
|
|
|
|
|
addattr_nest_end(hdr, linfo);
|
|
|
|
|
|
|
|
|
|
// Send the message
|
|
|
|
|
sendmsg(sock_fd, &req, 0);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
Maintenant que l'on a notre interface virtuelle, nous pouvons envoyer un second
|
|
|
|
|
message pour la déplacer dans un nouveau *namespace*[^IPSETNS] :
|
|
|
|
|
|
|
|
|
|
[^IPSETNS]: <https://github.com/shemminger/iproute2/blob/main/ip/iplink.c#L677>
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```c
|
|
|
|
|
// Initialise request message
|
|
|
|
|
struct nl_req req = {
|
|
|
|
|
.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
|
|
|
|
.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
|
|
|
|
|
.hdr.nlmsg_type = RTM_NEWLINK,
|
|
|
|
|
.msg.ifi_family = PF_NETLINK,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
addattr_l(&req.hdr, sizeof(req), IFLA_NET_NS_FD, &netns, 4);
|
|
|
|
|
addattr_l(&req.hdr, sizeof(req), IFLA_IFNAME,
|
|
|
|
|
ifname, strlen(ifname) + 1);
|
|
|
|
|
|
|
|
|
|
sendmsg(sock_fd, &req, 0);
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:::::
|
|
|
|
|
|
2016-10-19 03:24:05 +00:00
|
|
|
|
Dans cette configuration, ces deux interfaces ne sont pas très utiles, mais si
|
2021-10-31 19:51:17 +00:00
|
|
|
|
l'on place l'une des deux extrémités dans un autre *namespace* `network`, il
|
2017-11-09 00:30:41 +00:00
|
|
|
|
devient alors possible de réaliser un échange de paquets entre les deux.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Pour déplacer `veth1` dans notre *namespace* `virli` :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2022-11-11 09:14:16 +00:00
|
|
|
|
```
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh# ip link set veth1 netns virli
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2022-11-11 09:14:16 +00:00
|
|
|
|
```
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh# ip netns exec virli ip a add 10.10.10.42/24 dev veth1
|
|
|
|
|
42sh# ip a add 10.10.10.41/24 dev veth0
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité :
|
2017-11-09 00:30:41 +00:00
|
|
|
|
|
|
|
|
|
[^linkdown]: Il peut être nécessaire d'activer chaque lien, via `ip link set
|
|
|
|
|
vethX up`.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```
|
|
|
|
|
42sh# ping 10.10.10.42
|
|
|
|
|
- et -
|
|
|
|
|
42sh# ip netns exec virli ping 10.10.10.41
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
Il ne reste donc pas grand chose à faire pour fournir Internet à notre
|
2022-02-24 19:43:43 +00:00
|
|
|
|
conteneur : via un peu de NAT ou grâce à un pont Ethernet.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
### Les autres types d'interfaces
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
Le bridge ou le NAT obligera tous les paquets à passer à travers de nombreuses
|
2017-11-09 00:30:41 +00:00
|
|
|
|
couches du noyau. Utiliser les interfaces *veth* est plutôt simple et disponible
|
2016-10-19 03:24:05 +00:00
|
|
|
|
partout, mais c'est loin d'être la technique la plus rapide ou la moins
|
|
|
|
|
gourmande.
|
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
Voyons ensemble les autres possibilités à notre disposition.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
#### VLAN \
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2018-11-06 13:44:59 +00:00
|
|
|
|
Il est possible d'attribuer juste une interface de VLAN, si l'on a un switch
|
2019-11-03 17:54:22 +00:00
|
|
|
|
supportant la technologie [802.1q](https://fr.wikipedia.org/wiki/IEEE_802.1Q)
|
|
|
|
|
derrière notre machine.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh# ip link add link eth0 name eth0.100 type vlan id 100
|
|
|
|
|
42sh# ip link set dev eth0.100 up
|
|
|
|
|
42sh# ip link set eth0.100 netns virli
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
On attribuera alors à chaque conteneur une interface de VLAN différente. Cela
|
|
|
|
|
peut donner lieu à une configuration de switch(s) assez complexe.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
|
|
|
|
|
#### MACVLAN \
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-11-09 00:30:41 +00:00
|
|
|
|
<!-- https://hicu.be/bridge-vs-macvlan -->
|
|
|
|
|
|
|
|
|
|
Lorsque l'on n'a pas assez de carte ethernet et que le switch ne supporte pas
|
2022-02-24 19:43:43 +00:00
|
|
|
|
les VLAN, le noyau met à disposition un routage basé sur les adresses MAC : le
|
2016-10-19 03:24:05 +00:00
|
|
|
|
MACVLAN. S'il est activé dans votre noyau, vous allez avoir le choix entre l'un
|
2022-02-24 19:43:43 +00:00
|
|
|
|
des quatre modes : *private*, VEPA, *bridge* ou *passthru*.
|
2017-11-09 00:30:41 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
Quel que soit le mode choisi, les paquets en provenance d'autres machines et à
|
2022-11-11 09:14:16 +00:00
|
|
|
|
destination d'une MAC seront délivrés à l'interface possédant ladite MAC. Les
|
2017-11-09 00:30:41 +00:00
|
|
|
|
différences entre les modes se trouvent au niveau de la communication entre les
|
|
|
|
|
interfaces.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
##### VEPA \
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-11-09 00:30:41 +00:00
|
|
|
|
Dans ce mode, tous les paquets sortants sont directement envoyés sur
|
|
|
|
|
l'interface Ethernet de sortie, sans qu'aucun routage préalable n'ait été
|
|
|
|
|
effectué. Ainsi, si un paquet est à destination d'un des autres conteneurs de
|
|
|
|
|
la machine, c'est à l'équipement réseau derrière la machine de rerouter le
|
|
|
|
|
paquet vers la machine émettrice (par exemple un switch
|
|
|
|
|
[802.1Qbg](http://www.ieee802.org/1/pages/802.1bg.html)).
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Pour construire une nouvelle interface de ce type :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh# ip link add link eth0 mac0 type macvlan mode vepa
|
2017-11-09 00:30:41 +00:00
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
##### *Private* \
|
2017-11-09 00:30:41 +00:00
|
|
|
|
|
|
|
|
|
À la différence du mode *VEPA*, si un paquet émis par un conteneur à
|
|
|
|
|
destination d'un autre conteneur est réfléchi par un switch, le paquet ne sera
|
|
|
|
|
pas délivré.
|
|
|
|
|
|
2019-11-03 17:54:22 +00:00
|
|
|
|
Dans ce mode, on est donc assuré qu'aucun conteneur ne pourra parler à un autre
|
2017-11-09 00:30:41 +00:00
|
|
|
|
conteneur de la même machine.
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh# ip link add link eth0 mac1 type macvlan mode private
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
##### *Bridge* \
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
En mode *Bridge*, les paquets sont routés selon leur adresse MAC : si jamais
|
|
|
|
|
une adresse MAC est connue, le paquet est délivré à l'interface MACVLAN
|
|
|
|
|
correspondante ; dans le cas contraire, le paquet est envoyé sur l'interface de
|
|
|
|
|
sortie.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Pour construire une nouvelle interface de ce type :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh# ip link add link eth0 mac2 type macvlan mode bridge
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
|
2022-11-11 09:14:16 +00:00
|
|
|
|
##### *passthru* \
|
|
|
|
|
|
|
|
|
|
Enfin, le mode *passthru* permet de récupérer le contrôle sur tout ce qu'il
|
|
|
|
|
reste du périphérique initial (notamment pour lui changer sa MAC propre, ou
|
|
|
|
|
pour activer le mode de promiscuité).
|
|
|
|
|
|
|
|
|
|
L'intérêt est surtout de pouvoir donner cette interface à un conteneur ou une
|
|
|
|
|
machine virtuelle, sans lui donner un accès complet à l'interface physique (et
|
|
|
|
|
notamment aux autres MACVLAN).
|
|
|
|
|
|
|
|
|
|
On construit l'interface en mode *passthru* de cette façon :
|
|
|
|
|
|
|
|
|
|
<div lang="en-US">
|
|
|
|
|
```
|
|
|
|
|
42sh# ip link add link eth0 mac3 type macvlan mode passthru
|
|
|
|
|
```
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
Une seule interface MACVLAN peut être en mode *passthru* par interface
|
|
|
|
|
physique.
|
|
|
|
|
|
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
### Aller plus loin {-}
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
Pour approfondir les différentes techniques de routage, je vous
|
2022-02-24 19:43:43 +00:00
|
|
|
|
recommande cet article :
|
2022-04-08 20:39:14 +00:00
|
|
|
|
[Linux Containers and Networking](https://blog.flameeyes.eu/2010/09/linux-containers-and-networking)[^netnsmore1].
|
2021-09-11 12:41:43 +00:00
|
|
|
|
|
2022-02-24 19:43:43 +00:00
|
|
|
|
Appliqué à Docker, vous apprécierez cet article : [Understanding Docker
|
2021-09-11 12:41:43 +00:00
|
|
|
|
Networking Drivers and their use
|
2022-04-08 20:39:14 +00:00
|
|
|
|
cases](https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/)[^netnsmore2].
|
|
|
|
|
|
|
|
|
|
[^netnsmore1]: <https://blog.flameeyes.eu/2010/09/linux-containers-and-networking>
|
|
|
|
|
[^netnsmore2]: <https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/>
|