Differences

This shows you the differences between two versions of the page.

Link to this comparison view

rl:labs:10 [2025/12/08 13:20]
vlad_andrei.badoiu [Utilizare]
rl:labs:10 [2025/12/08 14:06] (current)
vlad_andrei.badoiu [Utilizare]
Line 57: Line 57:
 De asemenea, se pot folosi apelurile de sistem din Linux pentru a interacționa cu API-ul de bridge. Sunt două metode: prin **IOCTL** (varianta veche) și prin socket-uri **Netlink**. Mai jos este un exemplu cu IOCTL. De asemenea, se pot folosi apelurile de sistem din Linux pentru a interacționa cu API-ul de bridge. Sunt două metode: prin **IOCTL** (varianta veche) și prin socket-uri **Netlink**. Mai jos este un exemplu cu IOCTL.
  
 +<spoiler ioctl_create_bridge.c>​
 <code C> <code C>
 #include <​stdio.h>​ #include <​stdio.h>​
Line 87: Line 88:
 } }
 </​code>​ </​code>​
 +</​spoiler>​
  
 ==== VETH ==== ==== VETH ====
Line 128: Line 129:
 In cele ce urmeaza vom implementa diagrama de mai jos: In cele ce urmeaza vom implementa diagrama de mai jos:
  
-{{:​rl:​labs:​rl_ns_diagram.png?​300|}}+{{:​rl:​labs:​rl_ns_diagram.png?​500|}}
  
 **Crearea de namespace-uri** **Crearea de namespace-uri**
Line 275: Line 276:
 </​code>​ </​code>​
  
-Acum putem scrie mesaje în clientul din ''​ns1''​ și acestea vor apărea în serverul din ''​ns2'',​ demonstrând ​comunicarea completă ​între cele două namespace-uri izolate prin intermediul bridge-ului.+Acum putem scrie mesaje în clientul din ''​ns1''​ și acestea vor apărea în serverul din ''​ns2'',​ demonstrând ​conectivitatea ​între cele două namespace-uri izolate prin intermediul bridge-ului. 
 + 
 +==== Netlink ==== 
 + 
 +Netlink este un API din Linux utilizat pentru comunicarea inter-proces (IPC) atât între kernel și procesele userspace, cât și între diferite procese userspace, într-un mod similar socket-urilor de domeniu Unix. 
 + 
 +Introdus inițial pentru a rezolva problema ioctl-urilor (API-ul de ''​ioctl''​ necesita modificări în kernel pentru fiecare nou protocol de comunicare),​ Netlink este mecanism extensibil de comunicare între spațiul utilizator și kernel. Spre deosebire de ''​ioctl'',​ Netlink permite adăugarea de noi funcționalități fără a modifica codul kernel-ului,​ evitând astfel procesul de aprobare și integrare în kernel. Acesta a fost ulterior adaptat pentru a interacționa cu mai multe subsisteme. 
 + 
 +La fel ca socket-urile de domeniu Unix și spre deosebire de socket-urile INET, comunicarea Netlink nu poate traversa granițele gazdei. Netlink oferă o interfață standard bazată pe socket-uri pentru procesele userspace și un API pentru nucleu destinat utilizării interne de către modulele nucleului. Inițial, Netlink a folosit familia de socket-uri AF_NETLINK. Netlink este conceput pentru a fi un succesor mai flexibil al ioctl; RFC 3549 descrie protocolul în detaliu. 
 + 
 +Netlink este folosit, printre altele, de ''​ip route''​ sau ''​iptables''​. Mai jos gasim un exemplu de cod ce face toggle up <-> down la ''​some_interface''​. 
 + 
 +<spoiler switch_inferface_state.c>​ 
 +<code C> 
 +#include <​stdio.h>​ 
 +#include <​stdlib.h>​ 
 +#include <​unistd.h>​ 
 +#include <​string.h>​ 
 +#include <​time.h>​ 
 +#include <​errno.h>​ 
 + 
 +#include <​netinet/​in.h>​ 
 +#include <​netinet/​tcp.h>​ 
 + 
 +#include <​linux/​sockios.h>​ 
 +#include <​linux/​if.h>​ 
 +#include <​linux/​if_link.h>​ 
 +#include <​linux/​rtnetlink.h>​ 
 + 
 +#define ALIGNTO 4 
 +#define ALIGN(len) (((len)+ALIGNTO-1) & ~(ALIGNTO-1)) 
 +#define ATTR_HDRLEN ALIGN(sizeof(struct nlattr)) 
 +#define SOCKET_BUFFER_SIZE (sysconf(_SC_PAGESIZE) < 8192L ? sysconf(_SC_PAGESIZE) : 8192L) 
 + 
 +int main() 
 +
 + int nls = -1; 
 + struct sockaddr_nl kernel_nladdr;​ 
 + struct iovec io; 
 + struct msghdr msg; 
 + struct ifinfomsg *ifm; 
 + unsigned int change, flags, seq; 
 + char *ifname; 
 + char buf[SOCKET_BUFFER_SIZE];​ /* 8192 by default */ 
 + 
 + struct nlmsghdr *nlmsg; 
 + seq = time(NULL);​ 
 + 
 + /* The netlink message is destined to the kernel so nl_pid == 0. */ 
 + memset(&​kernel_nladdr,​ 0, sizeof(kernel_nladdr));​ 
 + kernel_nladdr.nl_family = AF_NETLINK;​ 
 + kernel_nladdr.nl_groups = 0; /* unicast */ 
 + kernel_nladdr.nl_pid = 0; 
 + 
 + nls = socket(AF_NETLINK,​ SOCK_RAW, NETLINK_ROUTE);​ 
 + if (nls == -1) 
 +
 + printf("​cannot open socket %s\n", strerror(errno));​ 
 + return -1; 
 +
 + 
 + int br; 
 + 
 + br = bind(nls, (struct sockaddr *) &​kernel_nladdr,​ sizeof (kernel_nladdr));​ 
 + if (br == -1) 
 +
 + printf("​cannot bind to socket\n"​);​ 
 + return -1; 
 +
 + 
 + int hlen = ALIGN(sizeof(struct nlmsghdr));​ 
 + nlmsg = buf; 
 + memset(buf,​ 0, hlen); 
 + nlmsg->​nlmsg_len = hlen; 
 + 
 + nlmsg->​nlmsg_type = RTM_NEWLINK;​ 
 + nlmsg->​nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;​ 
 + nlmsg->​nlmsg_seq = seq; 
 + 
 + /* extra header */ 
 + char *ptr = (char *)nlmsg + nlmsg->​nlmsg_len;​ 
 + size_t ehlen = ALIGN(sizeof(*ifm));​ 
 + nlmsg->​nlmsg_len += ehlen; 
 + memset(ptr,​ 0, ehlen); 
 + 
 + /* put interface down */ 
 + change = 0; 
 + flags = 0; 
 + change |= IFF_UP; 
 + flags &= ~IFF_UP; /* down = !up, obviously */ 
 + 
 + ifm = (void *)ptr; 
 + ifm->​ifi_family = AF_UNSPEC;​ 
 + ifm->​ifi_change = change; 
 + ifm->​ifi_flags = flags; 
 +  
 + /* add payload details - nlattr & padding */ 
 + ifname = "​some_interface";​ 
 + struct nlattr *attr = (void *)nlmsg + ALIGN(nlmsg->​nlmsg_len);​ 
 + uint16_t payload_len = ALIGN(sizeof(struct nlattr)) + strlen(ifname);​ 
 + int pad; 
 + 
 + attr->​nla_type = IFLA_IFNAME;​ 
 + attr->​nla_len = payload_len;​ 
 + memcpy((void *)attr + ATTR_HDRLEN,​ ifname, strlen(ifname));​ 
 + pad = ALIGN(strlen(ifname)) - strlen(ifname);​ 
 + if (pad > 0) 
 + memset((void *)attr + ATTR_HDRLEN + strlen(ifname),​ 0, pad); 
 + 
 + nlmsg->​nlmsg_len += ALIGN(payload_len);​ 
 + 
 + /* end of inner netlink nlattr details */ 
 + 
 + /* Stick the request in an io vector */ 
 + io.iov_base = (void *)nlmsg; 
 + io.iov_len = nlmsg->​nlmsg_len;​ 
 +  
 + /* Wrap it in a msg */  
 + memset(&​msg,​ 0, sizeof(msg));​ 
 + msg.msg_iov = &io; 
 + msg.msg_iovlen = 1; 
 + msg.msg_name = (void *)&​kernel_nladdr;​ 
 + msg.msg_namelen = sizeof(kernel_nladdr);​ 
 + 
 + /* Send it */ 
 + int res = sendmsg(nls,​ &msg, 0); 
 + printf("​result of send: %d", res); 
 +  
 + return 0; 
 +
 +</​code>​ 
 + 
 +Codul de mai sus: 
 +  * Deschide un socket cu AF_NETLINK ca familie 
 +  * Setează id-ul adresei la 0 (pentru kernel) 
 +  * Creează antetul standard al mesajului 
 +  * Atașează payload-ul corect (incluzând ifinfomsg și numele NIC-ului) 
 +  * Apelează sendmsg 
 + 
 +<code bash> 
 +> gcc switch_interface_state.c -o switch_interface_state 
 +> ip a show some_interface 
 +> sudo ./​switch_interface_state 
 +> ip a show some_interface 
 +</​code>​
  
 +</​spoiler>​
 ==== Exercitii ==== ==== Exercitii ====
  
rl/labs/10.1765192848.txt.gz · Last modified: 2025/12/08 13:20 by vlad_andrei.badoiu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0