|
| 1 | ++++ |
| 2 | +date = 2025-02-17T02:17:31-03:00 |
| 3 | +lastmod = 2025-02-18T18:40:04-03:00 |
| 4 | +draft = false |
| 5 | +title = "Virtualização de Redes" |
| 6 | +description = "Laboratório de virtualização de redes usando qemu/kvm, network namespaces e openvSwitch" |
| 7 | +tags = ['Virtualização', 'Redes', 'qemu', 'openvswitch'] |
| 8 | +categories = [] |
| 9 | +featured = true |
| 10 | ++++ |
| 11 | + |
| 12 | +## O que é virtualização |
| 13 | +A virtualização é a tecnologia que permite rodar múltiplos sistemas operacionais ou aplicações em um único hardware, criando versões virtuais de servidores, redes ou armazenamento. Isso otimiza recursos, reduz custos e é a base da computação em nuvem. |
| 14 | +## Linha do tempo de tecnologias de virtualização |
| 15 | +- **2002** - Surgimento do VMware Workstation, solução proprietária que popularizou a virtualização de sistemas, inspirando futuros projetos open source. |
| 16 | +- **2005** - Lançamento do Virtuozzo (posteriormente OpenVZ), pioneiro em virtualização via containers Linux, introduzindo isolamento de recursos em nível de sistema operacional. |
| 17 | +- **2006–2007** - Integração do KVM (Kernel-based Virtual Machine) ao kernel Linux, estabelecendo-se como hypervisor tipo 1 open source para criação de máquinas virtuais de alto desempenho. |
| 18 | +- **2008** - Lançamento do Microsoft Hyper-V, solução proprietária que impulsionou a competição e o aprimoramento de alternativas open source como KVM e Xen. |
| 19 | +- **2010** - Criação do OpenStack, incluindo o componente Neutron para virtualização de redes em nuvens, integrando redes virtuais, armazenamento e computação. |
| 20 | +- **2011** - Surgimento do oVirt, plataforma open source derivada do Red Hat Enterprise Virtualization, focada em orquestração de VMs baseadas em KVM. |
| 21 | +- **2013** - Revolução com o Docker, que popularizou containers leves, impactando a arquitetura de redes distribuídas através de microserviços isolados. |
| 22 | +- **2014** - Lançamento do Kubernetes pelo Google, padrão para orquestração de containers, com projetos posteriores como KubeVirt (2016) unindo VMs e containers. |
| 23 | +- **2015** - Padronização da NFV (Virtualização de Funções de Rede) pela ETSI, impulsionando projetos como OpenStack e OPNFV para substituir hardware dedicado por VMs. |
| 24 | +- **2016–2020** - Expansão de ecossistemas como KubeVirt (integração de VMs ao Kubernetes) e Cilium (redes baseadas em eBPF), aprimorando redes em ambientes cloud-native. |
| 25 | +- **2023** - Consolidação de tecnologias como KVM e OpenStack após a aquisição da VMware pela Broadcom, com foco em SDN, automação via IaC e edge computing. |
| 26 | + |
| 27 | +## Maquinas virtuais e containeres |
| 28 | +| Característica | **Máquinas Virtuais (VMs)** | **Contêineres** | |
| 29 | +| -------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------- | |
| 30 | +| **Isolamento** | Cada VM tem seu próprio sistema operacional completo | Compartilham o mesmo kernel do host, isolando apenas processos e bibliotecas | |
| 31 | +| **Uso de Recursos** | Mais pesado, pois cada VM precisa de um SO próprio | Mais leve, pois compartilha recursos do SO do host | |
| 32 | +| **Tempo de Inicialização** | Lento, pois precisa iniciar um SO completo | Rápido, pois roda como um processo do host | |
| 33 | +| **Escalabilidade** | Requer mais recursos para escalar | Altamente escalável e eficiente para microsserviços | |
| 34 | +| **Casos de Uso** | Aplicações legadas, múltiplos SOs no mesmo hardware | Desenvolvimento ágil, cloud computing e microsserviços | |
| 35 | + |
| 36 | + |
| 37 | +## Interface de rede físicas |
| 38 | +Uma **interface física de rede** é um hardware, como uma placa de rede (NIC), porta Ethernet ou adaptador Wi-Fi, que conecta um dispositivo a uma rede. Seu papel é transmitir e receber dados entre computadores, servidores e outros dispositivos, garantindo a comunicação na rede local ou na internet. |
| 39 | + |
| 40 | + |
| 41 | + |
| 42 | + |
| 43 | +## Interfaces de rede virtuais |
| 44 | +Uma **interface virtual de rede** é uma interface criada por software que simula uma conexão de rede sem a necessidade de hardware físico. Ela é usada para comunicação entre máquinas virtuais, contêineres ou diferentes processos dentro de um sistema. |
| 45 | +Exemplos incluem **veth (Virtual Ethernet)** para comunicação entre namespaces no Linux, **bridge interfaces** para conectar VMs a redes físicas, e **tun/tap interfaces**, que criam conexões de rede tuneladas. |
| 46 | + |
| 47 | +## [Virtual Interfaces](# Virtual Networking Devices - TUN, TAP and VETH Pairs Explained) |
| 48 | +### Tap/Tun |
| 49 | +[What is the TAP](https://vtun.sourceforge.net/tun/faq.html#1.2) |
| 50 | +``` |
| 51 | + The TAP is a Virtual Ethernet network device. |
| 52 | + TAP driver was designed as low level kernel support for |
| 53 | + Ethernet tunneling. It provides to userland application |
| 54 | + two interfaces: |
| 55 | + - /dev/tapX - character device; |
| 56 | + - tapX - virtual Ethernet interface. |
| 57 | + |
| 58 | + Userland application can write Ethernet frame to /dev/tapX |
| 59 | + and kernel will receive this frame from tapX interface. |
| 60 | + In the same time every frame that kernel writes to tapX |
| 61 | + interface can be read by userland application from /dev/tapX |
| 62 | + device. |
| 63 | +``` |
| 64 | + |
| 65 | +O driver TUN/TAP fornece recepção e transmissão de pacotes para programas em espaço de usuário. Ele pode ser visto como um dispositivo simples de Ponto-a-Ponto ou Ethernet que, em vez de receber pacotes de uma mídia física, os recebe de um programa em espaço de usuário, e em vez de enviar pacotes por uma mídia física, os escreve para o programa em espaço de usuário.[^1] |
| 66 | + |
| 67 | +Em outras palavras, o driver TUN/TAP cria uma interface de rede virtual no seu host Linux. Essa interface funciona como qualquer outra, ou seja, você pode atribuir um IP a ela, analisar o tráfego, rotear tráfego para ela, etc. Quando o tráfego é enviado para a interface, ele é entregue ao programa em espaço de usuário em vez de ser encaminhado para a rede real.[^1] |
| 68 | +### veth |
| 69 | +Dispositivos Veth são criados em pares de interfaces Ethernet virtuais conectadas e podem ser vistos como um cabo de rede virtual. O que entra em uma extremidade sai pela outra. |
| 70 | +Isso torna os pares veth ideais para conectar diferentes componentes de rede virtual, como bridges do Linux, bridges OVS e contêineres LXC.[^1] |
| 71 | + |
| 72 | + |
| 73 | + |
| 74 | + |
| 75 | + |
| 76 | +## Setup da VM com qemu |
| 77 | +Vamos realizar o download de uma Ubuntu Cloud Image. Essa img é otimizada para uso em cloud (utilizando hypervisors) e não vem com senha por padrão. Será necessário fornecer o arquivo para prover configuração de usuários e rede em uma próxima etapa. |
| 78 | +### Criar qcow2 overlay com qemu-img |
| 79 | +Queremos criar duas máquinas virtuais com base na imagem que fizemos download, porém não queremos alterar a imagem base, dessa maneira criamos uma imagem overlay qcow2 com base na imagem original utilizando *qemu-img*: `qemu-img create -f qcow2 -b ubuntu-24.04-server-cloudimg-amd64.img -F qcow2 vm.qcow2` |
| 80 | +### cloud-init |
| 81 | +Em ambientes Cloud, geralmente existe um componente dedicado a fornecer esse arquivo para as VMs, ocorrendo como um servidor web que fornece os metadados ou o próprio hypervisor adiciona um driver semelhante ao que será feito de maneira local no lab. |
| 82 | +O conteúdo do cloud init está em [[network-virtualization#Apêndice#Cloud Init]], os arquivos de rede devem estar separados do user-data. |
| 83 | +O pacote [cloud-utils](https://github.com/canonical/cloud-utils) deve ser instalado para gerar localmente a imagem. |
| 84 | +`cloud-localds --network-config=./config-data/network-config my-seed.img ./config-data/user-data.yaml` |
| 85 | +Adicionalmente, o pacote cloud-init tem um validator para conferir se o schema desses dois arquivos são válidos: |
| 86 | +`cloud-init schema --config-file user-data.yaml` |
| 87 | +`cloud-init schema -c network-config-dns --schema-type network-config` |
| 88 | +### Execução da VM com qemu: |
| 89 | +A primeira VM será criada executando o seguinte comando: |
| 90 | +``` |
| 91 | +# Create machine using e1000 driver |
| 92 | +qemu-system-x86_64 \ |
| 93 | +-name "Legacy-Net-Driver" \ |
| 94 | +-cpu host \ |
| 95 | +-enable-kvm \ |
| 96 | +-drive if=virtio,format=qcow2,file=e1000.qcow2 \ |
| 97 | +-drive if=virtio,format=raw,file=my-seed.img \ |
| 98 | +-m 2048 -smp 2 \ |
| 99 | +-netdev tap,id=mynet0,ifname=tap0,script=no,downscript=no \ |
| 100 | +-device e1000,netdev=mynet0,mac=52:54:00:12:34:56 \ |
| 101 | +-nographic -serial mon:stdio |
| 102 | +``` |
| 103 | +Explicação dos argumentos mais relevantes: |
| 104 | +- -enable-kvm -> habilita o KVM (utiliza instruções do processador de virtualização para melhor desempenho) |
| 105 | +- -drive if=virtio,format=qcow2,file=e1000.qcow2 -> carrega o driver com a imagem que foi criada a partir da cloudimg original, virtio é especificado como driver para melhor desempenho. |
| 106 | +- -drive if=virtio,format=raw,file=my-seed.img -> carrega a imagem de cloud-init que foi criada |
| 107 | +- -m 2048 -> 2gb de memória ram |
| 108 | +- -smp 2 -> 2 cores virtuais |
| 109 | +- -netdev tap,id=mynet0,ifname=tap0,script=no,downscript=no |
| 110 | + - netdev especifica que uma interface tap será utilizada para conectar a vm a rede |
| 111 | + - id é um identificador para essa interface |
| 112 | + - ifname será o nome do tap que foi criado manualmente |
| 113 | +- -device e1000,netdev=mynet0,mac=52:54:00:12:34:56 |
| 114 | + - adiciona um dispositivo de rede virtual usando o driver e1000 |
| 115 | + - netdev conecta a interface ao backend no comando anterior |
| 116 | + - mac define um endereço mac para a interface |
| 117 | +A diferença entre as duas VMs criadas é que invés de usar o driver e1000, virtio será utilizado como driver de rede, permitindo maior largura de banda. |
| 118 | +## Linux Bridges |
| 119 | +Uma bridge Linux se comporta como um switch de rede. Ela encaminha pacotes entre interfaces conectadas a ela. Normalmente é utilizada para encaminhar pacotes em roteadores, em gateways ou entre máquinas virtuais e namespaces de rede em um host.[^2] |
| 120 | +### Por que Open vSwitch no lugar de Linux Bridges? |
| 121 | +Open vSwitch está direcionado para implantações de virtualização multi-servidor, um cenário para o qual a stack anterior não era bem adequada. Estes ambientes são frequentemente caracterizados por pontos finais altamente dinâmicos, a manutenção de abstrações lógicas, e (às vezes) integração com ou offloading para hardware de switching especializado.[^3] |
| 122 | +## Linux Network Namespaces |
| 123 | +Namespaces de rede são uma característica do kernel Linux que permite criar ambientes de rede isolados dentro de um único sistema. Cada namespace de rede tem sua própria pilha de rede e conjunto de recursos de networking, como interfaces de rede virtuais, tabelas de roteamento, regras de firewall e mais. Isso possibilita criar múltiplos contextos de networking independentes em um único sistema, cada um com seu próprio conjunto de configurações de networking. |
| 124 | + |
| 125 | +Namespaces de rede são frequentemente utilizados em conjunto com outros tipos de namespaces, como PID namespaces, para criar ambientes isolados para execução de processos. Este é um aspecto fundamental da containerização e virtualização, pois permite criar ambientes leves, portáteis e seguros para execução de aplicações.[^4] |
| 126 | + |
| 127 | +## Laboratório |
| 128 | + |
| 129 | +Será construído uma topologia de rede semelhante ao exemplo de bridge nesse artigo sobre [interfaces virtuais da Red Hat](https://developers.redhat.com/blog/2018/10/22/introduction-to-linux-interfaces-for-virtual-networking#). Duas VMs serão criadas (para usar diferentes drivers de rede virtuais) e um namespace Linux. |
| 130 | + |
| 131 | + |
| 132 | + |
| 133 | +``` |
| 134 | +# ------------ core componentes installation ------------- |
| 135 | +# Download KVM |
| 136 | +# - Arch: pacman -S qemu |
| 137 | +# - Debian: apt install qemu-system |
| 138 | +
|
| 139 | +# Download Open vSwitch |
| 140 | +# - Arch: pacman -S openvswitch |
| 141 | +# - Debian: apt install openvswitch-switch openvswitch-common |
| 142 | +
|
| 143 | +# Start ovs server |
| 144 | +# - sudo /usr/share/openvswitch/scripts/ovs-ctl start |
| 145 | +
|
| 146 | +
|
| 147 | +# ------------ vm and ovs setup ------------- |
| 148 | +# Download ubuntu cloudimg |
| 149 | +wget https://cloud-images.ubuntu.com/releases/noble/release/ubuntu-24.04-server-cloudimg-amd64.img |
| 150 | +
|
| 151 | +# Create two overlays of the base image |
| 152 | +qemu-img create -f qcow2 -b ubuntu-24.04-server-cloudimg-amd64.img -F |
| 153 | +qcow2 e1000.qcow2 |
| 154 | +qemu-img create -f qcow2 -b ubuntu-24.04-server-cloudimg-amd64.img -F |
| 155 | +qcow2 virtio.qcow2 |
| 156 | +
|
| 157 | +# Create TAP devices |
| 158 | +sudo ip tuntap add mode tap user $USER name tap0 |
| 159 | +sudo ip tuntap add mode tap user $USER name tap1 |
| 160 | +sudo ip link set tap0 up |
| 161 | +sudo ip link set tap1 up |
| 162 | +
|
| 163 | +# Create OVS bridge and add ports |
| 164 | +sudo ovs-vsctl add-br ovs-br |
| 165 | +sudo ovs-vsctl add-port ovs-br tap0 |
| 166 | +sudo ovs-vsctl add-port ovs-br tap1 |
| 167 | +
|
| 168 | +# Assign IP to bridge for host communication |
| 169 | +sudo ip addr add 192.168.100.1/24 dev ovs-br |
| 170 | +sudo ip link set ovs-br up |
| 171 | +
|
| 172 | +# Enable ip forwarding |
| 173 | +sudo sysctl -w net.ipv4.ip_forward=1 |
| 174 | +
|
| 175 | +# Use nat to provide vms virtual connection, wlp2s0 should |
| 176 | +# be your internet connected interface and ovs-br should be your bridge |
| 177 | +sudo iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o wlp2s0 -j MASQUERADE |
| 178 | +sudo iptables -A FORWARD -i ovs-br -o wlp2s0 -j ACCEPT |
| 179 | +sudo iptables -A FORWARD -i wlp2s0 -o ovs-br -m state --state RELATED,ESTABLISHED -j ACCEPT |
| 180 | +
|
| 181 | +# Set up a DHCP server to provide IPs to VMs |
| 182 | +# install dnsmasq |
| 183 | +sudo apt install dnsmasq |
| 184 | +
|
| 185 | +# Edit the /etc/dnsmasq.conf file |
| 186 | +sudo vim /etc/dnsmasq.conf |
| 187 | +
|
| 188 | +# Enable the service |
| 189 | +sudo systemctl start dnsmasq.service |
| 190 | +
|
| 191 | +# Allow dhcp traffic [may not be necessary] |
| 192 | +# sudo iptables -A INPUT -p udp --dport 67 -j ACCEPT |
| 193 | +# sudo iptables -A INPUT -p udp --dport 68 -j ACCEPT |
| 194 | +
|
| 195 | +# Create cloud-init.yaml using cloud-init yaml |
| 196 | +# Install cloud-image-utils on arch or cloud-utils on apt-based |
| 197 | +sudo apt install cloud-utils |
| 198 | +cloud-localds --network-config=./config-data/network-config-dns my-seed2.img ./config-data/user-data.yaml |
| 199 | +
|
| 200 | +# Generate cloud-init img |
| 201 | +cloud-localds --network-config=./config-data/network-config my-seed.img ./c |
| 202 | +onfig-data/user-data.yaml |
| 203 | +
|
| 204 | +# Start VMs |
| 205 | +# Create machine using e1000 driver |
| 206 | +qemu-system-x86_64 \ |
| 207 | +-name "Legacy-Net-Driver" \ |
| 208 | +-cpu host \ |
| 209 | +-enable-kvm \ |
| 210 | +-drive if=virtio,format=qcow2,file=e1000.qcow2 \ |
| 211 | +-drive if=virtio,format=raw,file=my-seed.img \ |
| 212 | +-m 2048 -smp 2 \ |
| 213 | +-netdev tap,id=mynet0,ifname=tap0,script=no,downscript=no \ |
| 214 | +-device e1000,netdev=mynet0,mac=52:54:00:12:34:56 \ |
| 215 | +-nographic -serial mon:stdio |
| 216 | +
|
| 217 | +# Create machine using virtio driver |
| 218 | +qemu-system-x86_64 \ |
| 219 | +-name "Virtio-Net-Driver" \ |
| 220 | +-cpu host \ |
| 221 | +-enable-kvm \ |
| 222 | +-drive if=virtio,format=qcow2,file=virtio.qcow2 \ |
| 223 | +-drive if=virtio,format=raw,file=my-seed2.img \ |
| 224 | +-m 2048 -smp 2 \ |
| 225 | +-netdev tap,id=mynet1,ifname=tap1,script=no,downscript=no \ |
| 226 | +-device virtio-net-pci,netdev=mynet1,mac=52:54:00:12:34:57 \ |
| 227 | +-nographic -serial mon:stdio |
| 228 | +
|
| 229 | +# if dhcp with dnsmasq fail for some reason, you can configure manually IP, |
| 230 | +# routes and dns inside the virtual machines/namespace: |
| 231 | +# inside vms, set up network interface ip, a default gw to internet |
| 232 | +# through the bridge and change the dns to 8.8.8.8 manually editing |
| 233 | +# /etc/resolv.conf |
| 234 | +# sudo ip a add 192.168.100.3/24 dev ens3 |
| 235 | +# sudo ip r add default via 192.168.100.1 dev ens3 |
| 236 | +# sudo vim /etc/resolv.conf |
| 237 | +
|
| 238 | +# ------------ linux namespaces ------------- |
| 239 | +# on the host system, create a linux network namespace |
| 240 | +sudo ip netns add ns1 |
| 241 | +
|
| 242 | +# create a veth pair and move one end to the namespace |
| 243 | +sudo ip link add veth-host type veth peer name veth-ns |
| 244 | +sudo ip link set veth-ns netns ns1 |
| 245 | +
|
| 246 | +# activate both ends |
| 247 | +sudo ip netns exec ns1 ip link set veth-ns up |
| 248 | +sudo ip link set veth-host up |
| 249 | +
|
| 250 | +# add the host-side to the bridge |
| 251 | +sudo ovs-vsctl add-port ovs-br veth-host |
| 252 | +
|
| 253 | +# run bash inside the namespace |
| 254 | +sudo ip netns exec ns1 bash |
| 255 | +
|
| 256 | +# if dnsmasq is providing dhcp, get an ip using dhclient |
| 257 | +# if dnsmasq is not providing, configure ip, routes and dns manually |
| 258 | +dhclient -v |
| 259 | +
|
| 260 | +
|
| 261 | +# ------------ benchmarking ------------- |
| 262 | +
|
| 263 | +# install iperf3 on the hosts and the vms |
| 264 | +sudo apt update |
| 265 | +sudo pat install iperf3 |
| 266 | +
|
| 267 | +# Benchmarking bandwidth |
| 268 | +# on the host, start iperf3 server |
| 269 | +iperf3 -s -B 192.168.100.1 |
| 270 | +# on the virtual machines/namespaces connect to the server |
| 271 | +iperf3 -c 192.168.100.1 |
| 272 | +
|
| 273 | +
|
| 274 | +# ------------ cleanup ------------- |
| 275 | +sudo ovs-vsctl del-br ovs-br |
| 276 | +sudo ip link del tap0 |
| 277 | +sudo ip link del tap1 |
| 278 | +sudo ip netns del ns1 |
| 279 | +sudo ip link del veth-host |
| 280 | +``` |
| 281 | + |
| 282 | +## Apêndice |
| 283 | +### Cloud Init |
| 284 | +Será necessário criar os dois arquivos para adicionar ao cloud-init: |
| 285 | + |
| 286 | +``` network-config.yaml |
| 287 | +version: 2 |
| 288 | +ethernets: |
| 289 | + ens3: |
| 290 | + dhcp4: true |
| 291 | +``` |
| 292 | + |
| 293 | +``` user-data.yaml |
| 294 | +#cloud-config |
| 295 | +ssh_pwauth: True |
| 296 | +chpasswd: |
| 297 | + expire: false |
| 298 | + users: |
| 299 | + - {name: ubuntu, password: ubuntu, type: text} |
| 300 | +users: |
| 301 | + - name: ubuntu |
| 302 | + ssh-authorized-keys: |
| 303 | + - <your public key here> |
| 304 | + sudo: ['ALL=(ALL) NOPASSWD:ALL'] |
| 305 | + groups: users, sudo |
| 306 | + shell: /bin/bash |
| 307 | +``` |
| 308 | + |
| 309 | +### Servidor dhcp |
| 310 | +dnsmasq será utilizado para prover dhcp, edite o arquivo de configurações em `/etc/dnsmasq.conf` com o conteúdo a seguir: |
| 311 | +``` dnsmasq.conf |
| 312 | +interface=ovs-br |
| 313 | +dhcp-range=192.168.100.2,192.168.100.200,12h |
| 314 | +dhcp-option=option:dns-server,8.8.8.8 |
| 315 | +``` |
| 316 | + |
| 317 | +## Referências |
| 318 | + |
| 319 | +[^1]: https://www.packetcoders.io/virtual-networking-devices-tun-tap-and-veth-pairs-explained/ |
| 320 | + |
| 321 | +[^2]: https://developers.redhat.com/blog/2018/10/22/introduction-to-linux-interfaces-for-virtual-networking#bridge |
| 322 | + |
| 323 | +[^3]: https://docs.openvswitch.org/en/latest/intro/why-ovs/#why-open-vswitch |
| 324 | + |
| 325 | +[^4]: https://abdelouahabmbarki.com/linux-namespaces-network-ns/ |
| 326 | + |
| 327 | + |
0 commit comments