This shows you the differences between two versions of the page.
|
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 === | ||