Differences

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

Link to this comparison view

rl:labs:10 [2025/12/08 13:10]
vlad_andrei.badoiu [Bridge]
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 125: Line 126:
  
 ==== Utilizare ==== ==== Utilizare ====
 +
 +In cele ce urmeaza vom implementa diagrama de mai jos:
 +
 +{{:​rl:​labs:​rl_ns_diagram.png?​500|}}
  
 **Crearea de namespace-uri** **Crearea de namespace-uri**
 +
 Pentru a crea un namespace, vom folosi utilitarul ''​ip''​. Pentru a crea un namespace, vom folosi utilitarul ''​ip''​.
  
Line 270: 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 ====
  
Line 383: Line 534:
 </​code>​ </​code>​
  
-<solution ​-hidden>+<spoiler În caz că vă blocați :-P>
 Modificam programul. Modificam programul.
 <code diff> <code diff>
Line 409: Line 560:
      ​iov[0].iov_base = (void *) &​nlh; ​                 /* include nl header ​  */      ​iov[0].iov_base = (void *) &​nlh; ​                 /* include nl header ​  */
 </​code>​ </​code>​
 +
  
 Testam: Testam:
Line 426: Line 578:
 [-] main.c:​133 ​ rto    :          0 [microsec] [-] main.c:​133 ​ rto    :          0 [microsec]
 </​code>​ </​code>​
-</solution>+</spoiler>
  
 === Namespaces === === Namespaces ===
rl/labs/10.1765192205.txt.gz · Last modified: 2025/12/08 13:10 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