From 831ed9fc9cd0d0d194e72aaded701b878ab1c2ca Mon Sep 17 00:00:00 2001 From: Tarrade Nicolas Date: Mon, 23 Oct 2017 16:27:05 +0200 Subject: [PATCH] dhcp : brick and tests (DON'T Merge) Signed-off-by: Tarrade Nicolas --- include/packetgraph/iprange.h | 82 +++++++++ src/dhcp.c | 7 +- tests/dhcp/test.sh | 2 + tests/dhcp/tests.c | 307 ++++++++++++++++++++++++++++++++++ 4 files changed, 395 insertions(+), 3 deletions(-) create mode 100644 include/packetgraph/iprange.h create mode 100644 tests/dhcp/test.sh create mode 100644 tests/dhcp/tests.c diff --git a/include/packetgraph/iprange.h b/include/packetgraph/iprange.h new file mode 100644 index 000000000..26c5552d6 --- /dev/null +++ b/include/packetgraph/iprange.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2003 Gabriel L. Somlo + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To compile: + * on Linux: + * gcc -o iprange iprange.c -O2 -Wall + * on Solaris 8, Studio 8 CC: + * cc -xO5 -xarch=v8plusa -xdepend iprange.c -o iprange -lnsl -lresolv + * + * CHANGELOG : + * 2004-10-16 Paul Townsend (alpha alpha beta at purdue dot edu) + * more general input/output formatting + */ + +#include +#include +#include +#include +#include +#include +#include + +/*---------------------------------------------------------------------*/ +/* network address type: one field for the net address, one for prefix */ +/*---------------------------------------------------------------------*/ +typedef struct network_addr { + in_addr_t addr; + int pfx; +} network_addr_t; + +/*------------------------------------------------------------------*/ +/* Set a bit to a given value (0 or 1); MSB is bit 1, LSB is bit 32 */ +/*------------------------------------------------------------------*/ +in_addr_t set_bit(in_addr_t addr, int bitno, int val); + +/*----------------------------------------------------*/ +/* Compute broadcast address given address and prefix */ +/*----------------------------------------------------*/ +in_addr_t broadcast(in_addr_t addr, int prefix); + +/*--------------------------------------*/ +/* Compute netmask address given prefix */ +/*--------------------------------------*/ +in_addr_t netmask(int prefix); + +/*------------------------------------------------*/ +/* Print out a 32-bit address in A.B.C.D/M format */ +/*------------------------------------------------*/ +void print_addr(in_addr_t addr, int prefix); + +/*-----------------------------------------------------------*/ +/* Convert an A.B.C.D address into a 32-bit host-order value */ +/*-----------------------------------------------------------*/ +in_addr_t a_to_hl(const char *ipstr); + +/*--------------------------------------------------*/ +/* Compute network address given address and prefix */ +/*--------------------------------------------------*/ +in_addr_t network(in_addr_t addr, int prefix); + +/*-----------------------------------------------------------------*/ +/* convert a network address char string into a host-order network */ +/* address and an integer prefix value */ +/*-----------------------------------------------------------------*/ +int str_to_netaddr(const char *ipstr, network_addr_t *netaddr); + +/*------------------------------------------------------*/ +/* Print out an address range in a.b.c.d-A.B.C.D format */ +/*------------------------------------------------------*/ +void print_addr_range(in_addr_t lo, in_addr_t hi); diff --git a/src/dhcp.c b/src/dhcp.c index bd009ec7f..9a1f896f0 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -118,7 +118,7 @@ static int dhcp_burst(struct pg_brick *brick, enum pg_side from, it_mask = pkts_mask; for (; it_mask;) { - j = 0; + j = 1; pg_low_bit_iterate_full(it_mask, bit, i); tmp = pkts[i]; struct ether_hdr *eth = (struct ether_hdr *) @@ -138,14 +138,14 @@ static int dhcp_burst(struct pg_brick *brick, enum pg_side from, if (is_discover(tmp)) { while(state->check_ip[j] != 0) j++; - in_addr_t ip_offer = + uint32_t ip_offer = state->addr_net + j; pkt_offer = pg_dhcp_packet_create(brick, 2, eth->s_addr, ip_offer, 3600, state->addr_net, netmask(state->prefix)); - return pg_brick_burst(s->edge.link, + return pg_brick_burst(s->edge.link, from, s->edge.pair_index, pkt_offer, pkts_mask, errp); } @@ -154,6 +154,7 @@ static int dhcp_burst(struct pg_brick *brick, enum pg_side from, state->addr_net; if (!state->check_ip[index]) { + printf("check \n"); pkt_offer = pg_dhcp_packet_create(brick, 5, eth->s_addr, diff --git a/tests/dhcp/test.sh b/tests/dhcp/test.sh new file mode 100644 index 000000000..5c15edaca --- /dev/null +++ b/tests/dhcp/test.sh @@ -0,0 +1,2 @@ +#!/bin/sh +sudo ./tests-dhcp -c1 -n1 --socket-mem 64 --no-shconf diff --git a/tests/dhcp/tests.c b/tests/dhcp/tests.c new file mode 100644 index 000000000..620d45095 --- /dev/null +++ b/tests/dhcp/tests.c @@ -0,0 +1,307 @@ + /* Copyright 2017 + * + * This file is part of Packetgraph. + * + * Packetgraph is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * Packetgraph is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Packetgraph. If not, see . + */ + +#include +#include + +#define __FAVOR_BSD +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "utils/tests.h" +#include +#include +#include "brick-int.h" +#include "collect.h" +#include "fail.h" +#include "packetsgen.h" +#include "packets.h" +#include "utils/mempool.h" +#include "utils/qemu.h" +#include "utils/mac.h" +#include "utils/bitmask.h" + +extern char * ether_ntoa(struct ether_addr *e); +static uint16_t ssh_port_id = 65000; + +struct dhcp_messages_payload { + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint32_t xid; + uint16_t secs; + uint16_t flags; + uint32_t ciaddr; + uint32_t yiaddr; + uint32_t siaddr; + uint32_t giaddr; + struct ether_addr mac_client; + char * server_name; + char * file; + uint8_t dhcp_m_type; + struct ether_addr client_id; + uint32_t subnet_mask; + uint32_t request_ip; + uint32_t server_identifier; + uint32_t router_ip; + int lease_time; + uint8_t *options; + GList *request_parameters; +}; + +struct pg_dhcp_state { + struct pg_brick brick; + struct ether_addr **mac; + in_addr_t addr_net; + in_addr_t addr_broad; + int *check_ip; + int prefix; +}; + +static void test_dhcp_discover(void) +{ + struct pg_brick *dhcp; + struct pg_brick *collect; + struct ether_addr eth_dst; + struct ether_addr eth_src; + struct ether_addr eth_dhcp; + struct rte_mbuf **pkts; + struct rte_mbuf **sended_pkts; + struct dhcp_messages_payload dhcp_hdr; + char *tmp; + uint64_t nb_packets = pg_mask_firsts(1); + uint8_t dhcp_mes_type = 2; + struct pg_error *error = NULL; + + pg_scan_ether_addr(ð_dst, "FF:FF:FF:FF:FF:FF"); + pg_scan_ether_addr(ð_src, "00:18:b9:56:2e:73"); + pg_scan_ether_addr(ð_dhcp, "44:82:c9:2b:a2:37"); + pkts = pg_packets_append_ether(pg_packets_create(nb_packets), + nb_packets, ð_src, ð_dst, + ETHER_TYPE_IPv4); + pg_packets_append_ipv4(pkts, nb_packets, 0x00000000, 0xFFFFFFFF, + sizeof(struct ipv4_hdr), 17); + + pg_packets_append_udp(pkts, nb_packets, 68, 67, sizeof(struct udp_hdr)); + + PG_FOREACH_BIT(nb_packets, j) { + if (!pkts[j]) + continue; + dhcp_hdr.mac_client = eth_src; + dhcp_hdr.dhcp_m_type = 1; + dhcp_hdr.client_id = eth_src; + tmp = rte_pktmbuf_append(pkts[j], sizeof(struct dhcp_messages_payload)); + if (!tmp) + printf("error buffer\n"); + memcpy(tmp, &dhcp_hdr, sizeof(struct dhcp_messages_payload)); + } + + collect = pg_collect_new("collect", &error); + g_assert(!error); + + dhcp = pg_dhcp_new("dhcp", "192.54.30.200/24", eth_dhcp, &error); + g_assert(!error); + + pg_brick_link(dhcp, collect, &error); + g_assert(!error); + + pg_brick_burst_to_east(dhcp, 0, pkts, nb_packets, &error); + g_assert(!error); + + sended_pkts = pg_brick_west_burst_get(collect, &nb_packets, &error); + g_assert(!error); + + PG_FOREACH_BIT(nb_packets, j) { + if (!pkts[j]) + continue; + uint32_t hdrs_len = sizeof(struct ether_hdr) + + sizeof(struct ipv4_hdr) + + sizeof(struct udp_hdr); + struct dhcp_messages_payload *dhcp_hdr_sended = + (struct dhcp_messages_payload *) + rte_pktmbuf_mtod_offset(sended_pkts[j], char *, hdrs_len); + g_assert(dhcp_hdr_sended->dhcp_m_type == dhcp_mes_type); + } + + pg_brick_destroy(collect); + pg_brick_destroy(dhcp); + pg_packets_free(pkts, pg_mask_firsts(1)); + g_free(pkts); +} + +static void test_dhcp_packets_registering(void) +{ + struct pg_brick *dhcp; + struct pg_brick *packets_gen; + struct rte_mbuf **pkts; + struct pg_error *error = NULL; + struct ether_addr eth_dst; + struct ether_addr eth_src; + struct ether_addr eth_dhcp; + struct dhcp_messages_payload dhcp_hdr; + char *tmp; + uint16_t nb_packets = 1; + + pg_scan_ether_addr(ð_dst, "FF:FF:FF:FF:FF:FF"); + pg_scan_ether_addr(ð_src, "00:18:b9:56:2e:73"); + pg_scan_ether_addr(ð_dhcp, "44:82:c9:2b:a2:37"); + pkts = pg_packets_append_ether(pg_packets_create(pg_mask_firsts(1)), + pg_mask_firsts(1), ð_src, ð_dst, + ETHER_TYPE_IPv4); + pg_packets_append_ipv4(pkts, pg_mask_firsts(1), 0x00000000, 0xFFFFFFFF, + sizeof(struct ipv4_hdr), 17); + + pg_packets_append_udp(pkts, pg_mask_firsts(1), 68, 67, sizeof(struct udp_hdr)); + + PG_FOREACH_BIT(pg_mask_firsts(1), j) { + if (!pkts[j]) + continue; + dhcp_hdr.mac_client = eth_src; + dhcp_hdr.dhcp_m_type = 3; + dhcp_hdr.client_id = eth_src; + dhcp_hdr.request_ip = 0xC0361E01; + tmp = rte_pktmbuf_append(pkts[j], sizeof(struct dhcp_messages_payload)); + if (!tmp) + printf("error buffer\n"); + memcpy(tmp, &dhcp_hdr, sizeof(struct dhcp_messages_payload)); + } + + packets_gen = pg_packetsgen_new("packetsgen", 1, 1, PG_EAST_SIDE, pkts, + 1, &error); + g_assert(!error); + + dhcp = pg_dhcp_new("dhcp", "192.54.30.200/24", eth_dhcp, &error); + g_assert(!error); + + pg_brick_link(packets_gen, dhcp, &error); + g_assert(!error); + + pg_brick_poll(packets_gen, &nb_packets, &error); + g_assert(!error); + + struct pg_dhcp_state *state = pg_brick_get_state(dhcp, + struct pg_dhcp_state); + int size = sizeof(state->mac) / sizeof(struct ether_addr); + for(int i = 1; i <= size ; i++) { + printf("%i \n", i); + if (state->mac[i]) { + printf("%s\n", ether_ntoa(state->mac[i])); + } + else { + printf("No Mac assigned\n"); + } + } + + pg_brick_destroy(packets_gen); + pg_brick_destroy(dhcp); + pg_packets_free(pkts, pg_mask_firsts(1)); + g_free(pkts); + +} + +static void test_adressing_vm(void) +{ + struct pg_brick *dhcp, *vhost, *print, *collect; + const char *socket_path; + struct ether_addr mac_vm; + struct ether_addr mac_dhcp; + pg_scan_ether_addr(&mac_vm, "42:18:b9:56:2e:73"); + pg_scan_ether_addr(&mac_dhcp, "55:27:c9:ea:9d:36"); + struct pg_error *error = NULL; + int ret, qemu_pid; + + /* start vhost */ + ret = pg_vhost_start("/tmp", &error); + g_assert(ret == 0); + g_assert(!error); + + /* instanciate brick */ + vhost = pg_vhost_new("vhost", PG_VHOST_USER_DEQUEUE_ZERO_COPY, + &error); + g_assert(!error); + g_assert(vhost); + + dhcp = pg_dhcp_new("dhcp", "192.54.30.200/24", mac_dhcp, &error); + g_assert(!error); + g_assert(dhcp); + + collect = pg_collect_new("collect", &error); + g_assert(!error); + g_assert(collect); + + print = pg_print_new("My print", NULL, PG_PRINT_FLAG_MAX, NULL, + &error); + g_assert(!error); + g_assert(print); + + /* build the graph */ + pg_brick_link(collect, vhost, &error); + g_assert(!error); + + /* spawn first QEMU */ + socket_path = pg_vhost_socket_path(vhost, &error); + g_assert(!error); + g_assert(socket_path); + + qemu_pid = pg_util_spawn_qemu(socket_path, NULL, mac_vm, NULL, + glob_vm_path, glob_vm_key_path, + glob_hugepages_path, &error); + + g_assert(!error); + g_assert(qemu_pid); + +# define SSH(c) \ + g_assert(pg_util_ssh("localhost", ssh_port_id, \ + glob_vm_key_path, c) == 0) + SSH("dhclient ens4"); +# undef SSH + + pg_util_stop_qemu(qemu_pid, qemu_exit_signal); + +} + +static void test_dhcp(void) +{ + pg_test_add_func("/dhcp/discover\n", + test_dhcp_discover); + pg_test_add_func("/dhcp/packets_registering\n", + test_dhcp_packets_registering); +} + +int main(int argc, char **argv) +{ + /* tests in the same order as the header function declarations */ + g_test_init(&argc, &argv, NULL); + + /* initialize packetgraph */ + g_assert(pg_start(argc, argv) >= 0); + + test_dhcp(); + int r = g_test_run(); + + pg_stop(); + return r; +}