diff --git a/Makefile.am b/Makefile.am
index 7f323cb92..aff07ecf7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -37,7 +37,9 @@ libpacketgraph_la_SOURCES = \
src/switch.c\
src/pmtud.c\
src/thread.c\
- src/ip-fragment.c
+ src/ip-fragment.c\
+ src/iprange.c\
+ src/dhcp.c
pkginclude_HEADERS = \
include/packetgraph/common.h\
@@ -63,7 +65,8 @@ pkginclude_HEADERS = \
include/packetgraph/queue.h\
include/packetgraph/pmtud.h\
include/packetgraph/ip-fragment.h\
- include/packetgraph/errors.h
+ include/packetgraph/errors.h\
+ include/packetgraph/dhcp.h
libpacketgraph_la_LIBADD = $(RTE_SDK_LIBS) $(GLIB_LIBS)
# FIXME '^pg_[^_]' does not take all symbols needed (i.e. __pg_error_*)
@@ -76,7 +79,7 @@ include npfmakefile.am
dist_doc_DATA = README.md
-check_PROGRAMS = tests-antispoof tests-core tests-diode tests-rxtx tests-firewall tests-integration tests-nic tests-print tests-queue tests-switch tests-vhost tests-vtep tests-pmtud tests-tap tests-ip-fragment tests-thread
+check_PROGRAMS = tests-antispoof tests-core tests-diode tests-rxtx tests-firewall tests-integration tests-nic tests-print tests-queue tests-switch tests-vhost tests-vtep tests-pmtud tests-tap tests-ip-fragment tests-thread tests-dhcp
noinst_LTLIBRARIES += libpacketgraph-dev.la
libpacketgraph_dev_la_SOURCES = $(libpacketgraph_la_SOURCES)
@@ -195,6 +198,12 @@ tests_thread_CFLAGS = $(libpacketgraph_dev_la_CFLAGS)
tests_thread_LDFLAGS = libpacketgraph-dev.la
EXTRA_tests_thread_DEPENDENCIES = libpacketgraph-dev.la
+tests_dhcp_SOURCES = \
+ tests/dhcp/tests.c
+tests_dhcp_CFLAGS = $(libpacketgraph_dev_la_CFLAGS)
+tests_dhcp_LDFLAGS = libpacketgraph-dev.la
+EXTRA_tests_thread_DEPENDENCIES = libpacketgraph-dev.la
+
TESTS = \
tests/antispoof/test.sh\
tests/core/test.sh\
@@ -211,7 +220,8 @@ TESTS = \
tests/tap/test.sh\
tests/thread/test.sh\
tests/integration/test.sh\
- tests/vhost/test.sh
+ tests/vhost/test.sh\
+ tests/dhcp/test.sh
noinst_PROGRAMS =
@@ -408,4 +418,4 @@ doc: doxygen.conf
$(srcdir)/doc/deploy_documentation.sh
# libtoolize recommanded this
-ACLOCAL_AMFLAGS = -I m4
+ACLOCAL_AMFLAGS = -I
diff --git a/configure_clang b/configure_clang
index bd8438867..bd35e987e 100755
--- a/configure_clang
+++ b/configure_clang
@@ -1,7 +1,4 @@
#!/bin/bash
export CC="clang"
-export AR="llvm-ar"
-export NM="llvm-nm"
-export RANLIB="llvm-ranlib"
root=$(cd "$(dirname $0)" && pwd)
-$root/configure ${@:1}
+$root/configure CFLAGS="-O0 -g" ${@:1}
diff --git a/include/packetgraph/dhcp.h b/include/packetgraph/dhcp.h
new file mode 100644
index 000000000..4b508bb81
--- /dev/null
+++ b/include/packetgraph/dhcp.h
@@ -0,0 +1,77 @@
+/* Copyright 2017 Outscale SAS
+ *
+ * This file is part of Butterfly.
+ *
+ * Butterfly 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.
+ *
+ * Butterfly 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 Butterfly. If not, see .
+ */
+
+#ifndef _PG_DHCP_H
+#define _PG_DHCP_H
+
+#include
+#include
+#include
+
+/**
+ * Create a new dhcp brick.
+ * dhcp brick allow ip adress to mac adresses
+ * @name: name of the brick
+ * @cidr: range of ip adresses
+ * @errp: set in case of an error
+ * @return: a pointer to a brick structure on success, NULL on error
+ **/
+
+struct pg_brick *pg_dhcp_new(const char *name, const char *cidr,
+ struct ether_addr mac_dhcp,
+ struct pg_error **errp);
+
+/**
+ * Calculate the number of potential adresses
+ * @ipcidr : ip adress with cidr to calculate the range
+ */
+int pg_calcul_range_ip(network_addr_t ipcidr);
+
+/**
+ * Check if a packet is a dhcp discover packet
+ * @pkts : the packet to check
+ */
+bool is_discover(struct rte_mbuf *pkts);
+
+/**
+ * Check if a packet is a dhcp discover packet
+ * @pkts : the packet to check
+ */
+bool is_request(struct rte_mbuf *pkts);
+
+/**
+ * Create dhcp packet to burst
+ * @msg_type : dhcp message type : 1 : Discover
+ * 2 : Offer
+ * 3 : Request
+ * 4 : Decline
+ * 5 : Acknowledgment
+ * 6 : Negative Acknowledgment
+ * 7 : Realease
+ * 8 : Informationnal
+ * @mac : Mac adresse of the brick
+ * @ip_offer : ip to give to the brick
+ * @bail : number of seconds for bail of the ip adresse to the brick
+ * @ip_router : ip of the default gateaway
+ * @mask : subnet mask used by the client
+ */
+struct rte_mbuf **pg_dhcp_packet_create(struct pg_brick *brick,
+ uint8_t msg_type, struct ether_addr mac,
+ uint32_t ip_offer, int bail,
+ uint32_t ip_router, uint32_t mask);
+
+#endif /* _PG_DHCP_H */
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/include/packetgraph/packetgraph.h b/include/packetgraph/packetgraph.h
index cd1837192..772d30748 100644
--- a/include/packetgraph/packetgraph.h
+++ b/include/packetgraph/packetgraph.h
@@ -42,5 +42,7 @@
#include
#include
#include
+#include
+#include
#endif /* _PG_PACKETGRAPH_H */
diff --git a/src/dhcp.c b/src/dhcp.c
new file mode 100644
index 000000000..9a1f896f0
--- /dev/null
+++ b/src/dhcp.c
@@ -0,0 +1,342 @@
+/* Copyright 2017 Outscale SAS
+ *
+ * This file is part of Butterfly.
+ *
+ * Butterfly 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.
+ *
+ * Butterfly 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 Butterfly. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include "utils/mac.h"
+
+#include
+#include "utils/bitmask.h"
+#include "utils/mempool.h"
+#include "packets.h"
+#include "brick-int.h"
+#include "utils/network.h"
+#include "src/npf/npf/dpdk/npf_dpdk.h"
+
+#define DHCP_SIDE_TO_NPF(side) \
+ ((side) == PG_WEST_SIDE ? PFIL_OUT : PFIL_IN)
+
+bool eth_compare(uint8_t eth1[6], uint8_t eth2[6]);
+
+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;
+ struct ether_addr mac_dhcp;
+ in_addr_t addr_net;
+ in_addr_t addr_broad;
+ int *check_ip;
+ int prefix;
+};
+
+struct pg_dhcp_config {
+ struct network_addr cidr;
+ struct ether_addr mac_dhcp;
+};
+
+static struct pg_brick_config *dhcp_config_new(const char *name,
+ const char *cidr,
+ struct ether_addr mac_dhcp)
+{
+ char cidrip[17];
+ strcpy(cidrip, cidr);
+ struct pg_brick_config *config;
+ struct pg_dhcp_config *dhcp_config;
+ dhcp_config = g_new0(struct pg_dhcp_config, 1);
+ network_addr_t ip_cidr;
+ int ret = str_to_netaddr(cidrip, &ip_cidr);
+ if(ret == -1)
+ printf("error registering\n");
+ dhcp_config->cidr = ip_cidr;
+ dhcp_config->mac_dhcp = mac_dhcp;
+ config = g_new0(struct pg_brick_config, 1);
+ config->brick_config = (void *) dhcp_config;
+ return pg_brick_config_init(config, name, 1, 1, PG_MONOPOLE);
+}
+
+static int dhcp_burst(struct pg_brick *brick, enum pg_side from,
+ uint16_t edge_index, struct rte_mbuf **pkts,
+ uint64_t pkts_mask, struct pg_error **errp)
+{
+ struct pg_dhcp_state *state;
+ struct pg_brick_side *s = &brick->sides[pg_flip_side(from)];
+ struct ether_addr *mac_pkts;
+ uint64_t it_mask;
+ struct rte_mbuf **pkt_offer;
+ uint64_t bit;
+ struct rte_mbuf *tmp;
+ uint16_t ether_type;
+ uint16_t i;
+ int j;
+ uint32_t hdrs_len = sizeof(struct ether_hdr) +
+ sizeof(struct ipv4_hdr) +
+ sizeof(struct udp_hdr);
+
+ state = pg_brick_get_state(brick, struct pg_dhcp_state);
+
+ it_mask = pkts_mask;
+ for (; it_mask;) {
+ j = 1;
+ pg_low_bit_iterate_full(it_mask, bit, i);
+ tmp = pkts[i];
+ struct ether_hdr *eth = (struct ether_hdr *)
+ rte_pktmbuf_mtod(tmp, char *);
+ struct dhcp_messages_payload *dhcp_hdr =
+ (struct dhcp_messages_payload *)
+ rte_pktmbuf_mtod_offset(tmp, char *, hdrs_len);
+ ether_type = pg_utils_get_ether_type(tmp);
+ /* DHCP only manage IPv4 adressing
+ * Let non-ip packets (like ARP) pass.
+ */
+ if (unlikely(ether_type != PG_BE_ETHER_TYPE_IPv4)) {
+ continue;
+ }
+ if (RTE_ETH_IS_IPV4_HDR(tmp->packet_type)) {
+ if (((tmp->packet_type) & RTE_PTYPE_L4_UDP)) {
+ if (is_discover(tmp)) {
+ while(state->check_ip[j] != 0)
+ j++;
+ 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,
+ from, s->edge.pair_index, pkt_offer,
+ pkts_mask, errp);
+ }
+ if (is_request(tmp)) {
+ uint32_t index = dhcp_hdr->request_ip -
+ state->addr_net;
+ if (!state->check_ip[index])
+ {
+ printf("check \n");
+ pkt_offer =
+ pg_dhcp_packet_create(brick, 5,
+ eth->s_addr,
+ dhcp_hdr->request_ip, 3600,
+ state->addr_net,
+ netmask(state->prefix));
+ mac_pkts = ð->s_addr;
+ state->mac[j] = mac_pkts;
+ return pg_brick_burst(s->edge.link,
+ from, s->edge.pair_index, pkt_offer,
+ pkts_mask, errp);
+ }
+ }
+ }
+ }
+ }
+ return pg_brick_burst(s->edge.link, from,
+ s->edge.pair_index, pkts, pkts_mask, errp);
+
+}
+
+static int dhcp_init(struct pg_brick *brick,
+ struct pg_brick_config *config,
+ struct pg_error **errp)
+{
+ struct pg_dhcp_state *state = pg_brick_get_state(brick,
+ struct pg_dhcp_state);
+ struct pg_dhcp_config *dhcp_config;
+
+ state = pg_brick_get_state(brick, struct pg_dhcp_state);
+
+ dhcp_config = (struct pg_dhcp_config *) config->brick_config;
+ state->mac = g_malloc0(pg_calcul_range_ip(dhcp_config->cidr) *
+ sizeof(struct ether_addr));
+ state->mac_dhcp = dhcp_config->mac_dhcp;
+ state->addr_net = network(dhcp_config->cidr.addr,
+ dhcp_config->cidr.pfx);
+ state->addr_broad = broadcast(dhcp_config->cidr.addr,
+ dhcp_config->cidr.pfx);
+ state->check_ip = g_malloc0(pg_calcul_range_ip(dhcp_config->cidr) *
+ sizeof(bool));
+ state->prefix = dhcp_config->cidr.pfx;
+
+ for (int i = 0 ; i < pg_calcul_range_ip(dhcp_config->cidr); i++) {
+ state->check_ip[i] = 0;
+ }
+ /* initialize fast path */
+ brick->burst = dhcp_burst;
+
+ return 0;
+}
+
+int pg_calcul_range_ip(network_addr_t ipcidr) {
+ return 1 << ((32 - (ipcidr.pfx - 1)) - 1);
+}
+
+#define PG_PACKETS_TEST_DHCP(pkts, msg_type) \
+ bool result = true; \
+ uint8_t eth_dest[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};\
+ uint8_t eth_src[6] = {0x00, 0x18, 0xb9, 0x56, 0x2e, 0x73}; \
+ uint32_t ip_dest; \
+ inet_pton(AF_INET, "255.255.255.255", &ip_dest); \
+ uint32_t ip_src; \
+ inet_pton(AF_INET, "0.0.0.0", &ip_src); \
+ uint16_t udp_dest = 67; \
+ uint16_t udp_src = 68; \
+ uint8_t dhcp_mes_type = msg_type; \
+ uint32_t hdrs_len = sizeof(struct ether_hdr) + \
+ sizeof(struct ipv4_hdr) + \
+ sizeof(struct udp_hdr); \
+ struct ether_hdr *ethernet = (struct ether_hdr *) \
+ rte_pktmbuf_mtod(pkts, char *);\
+ struct ipv4_hdr *ip = (struct ipv4_hdr *) \
+ pg_utils_get_l3(pkts); \
+ struct udp_hdr *udp = (struct udp_hdr *) \
+ pg_utils_get_l4(pkts); \
+ struct dhcp_messages_payload *dhcp_hdr = \
+ (struct dhcp_messages_payload *) \
+ rte_pktmbuf_mtod_offset(pkts, char *, hdrs_len); \
+ \
+ if (eth_compare(ethernet->d_addr.addr_bytes, eth_dest) == false) \
+ result = false; \
+ if (eth_compare(ethernet->s_addr.addr_bytes, eth_src) == false) \
+ result = false; \
+ if (ip->dst_addr != ip_dest) \
+ result = false; \
+ if (ip->src_addr != ip_src) \
+ result = false; \
+ if (rte_be_to_cpu_16(udp->dst_port) != udp_dest) \
+ result = false; \
+ if (rte_be_to_cpu_16(udp->src_port) != udp_src) \
+ result = false; \
+ if (dhcp_hdr->dhcp_m_type != dhcp_mes_type) \
+ result = false; \
+ \
+ return result; \
+
+
+bool is_discover(struct rte_mbuf *pkts) {
+ PG_PACKETS_TEST_DHCP(pkts, 1);
+}
+
+bool is_request(struct rte_mbuf *pkts) {
+ PG_PACKETS_TEST_DHCP(pkts, 3);
+}
+
+bool eth_compare(uint8_t eth1[6], uint8_t eth2[6]) {
+ bool result = true;
+ for(int i = 0; i < 6 ; i++) {
+ if (eth1[i] != eth2[i])
+ result = false;
+ }
+ return result;
+}
+
+struct rte_mbuf **pg_dhcp_packet_create(struct pg_brick *brick,
+ uint8_t msg_type, struct ether_addr mac,
+ uint32_t ip_offer, int bail,
+ uint32_t ip_router, uint32_t mask)
+{
+ struct rte_mbuf **pkts;
+ struct ether_addr eth_dst;
+ struct ether_addr eth_src;
+ struct dhcp_messages_payload dhcp_hdr;
+ char *tmp;
+ struct pg_dhcp_state *state;
+
+ state = pg_brick_get_state(brick, struct pg_dhcp_state);
+
+ pg_scan_ether_addr(ð_dst, "FF:FF:FF:FF:FF:FF");
+ eth_src = state->mac_dhcp;
+
+ 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), state->addr_net,
+ 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 = mac;
+ dhcp_hdr.dhcp_m_type = msg_type;
+ dhcp_hdr.subnet_mask = mask;
+ dhcp_hdr.yiaddr = ip_offer;
+ dhcp_hdr.router_ip = ip_router;
+ dhcp_hdr.lease_time = bail;
+ dhcp_hdr.server_identifier = state->addr_net;
+ 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));
+ }
+
+ return pkts;
+}
+
+struct pg_brick *pg_dhcp_new(const char *name, const char *cidr,
+ struct ether_addr mac_dhcp,
+ struct pg_error **errp)
+{
+ struct pg_brick_config *config;
+ struct pg_brick *ret;
+
+ config = dhcp_config_new(name, cidr, mac_dhcp);
+ ret = pg_brick_new("dhcp", config, errp);
+
+ pg_brick_config_free(config);
+
+ return ret;
+}
+
+static struct pg_brick_ops dhcp_ops = {
+ .name = "dhcp",
+ .state_size = sizeof(struct pg_dhcp_state),
+
+ .init = dhcp_init,
+
+ .unlink = pg_brick_generic_unlink,
+};
+
+pg_brick_register(dhcp, &dhcp_ops);
diff --git a/src/iprange.c b/src/iprange.c
new file mode 100644
index 000000000..b9b4cec71
--- /dev/null
+++ b/src/iprange.c
@@ -0,0 +1,161 @@
+/*
+ * 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
+#include
+
+static char *PROG;
+
+/*------------------------------------------------------------------*/
+/* 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 ) {
+
+ if ( val )
+ return( addr | (1 << (32 - bitno)) );
+ else
+ return( addr & ~(1 << (32 - bitno)) );
+
+} /* set_bit() */
+
+
+/*--------------------------------------*/
+/* Compute netmask address given prefix */
+/*--------------------------------------*/
+in_addr_t netmask( int prefix ) {
+
+ if ( prefix == 0 )
+ return( ~((in_addr_t) -1) );
+ else
+ return( ~((1 << (32 - prefix)) - 1) );
+
+} /* netmask() */
+
+
+/*----------------------------------------------------*/
+/* Compute broadcast address given address and prefix */
+/*----------------------------------------------------*/
+in_addr_t broadcast( in_addr_t addr, int prefix ) {
+
+ return( addr | ~netmask(prefix) );
+
+} /* broadcast() */
+
+
+/*--------------------------------------------------*/
+/* Compute network address given address and prefix */
+/*--------------------------------------------------*/
+in_addr_t network( in_addr_t addr, int prefix ) {
+
+ return( addr & netmask(prefix) );
+
+} /* network() */
+
+
+/*------------------------------------------------*/
+/* Print out a 32-bit address in A.B.C.D/M format */
+/*------------------------------------------------*/
+void print_addr( in_addr_t addr, int prefix ) {
+
+ struct in_addr in;
+
+ in.s_addr = htonl( addr );
+ if ( prefix < 32 )
+ printf( "%s/%d\n", inet_ntoa(in), prefix );
+ else
+ printf( "%s\n", inet_ntoa(in));
+
+} /* print_addr() */
+
+/*-----------------------------------------------------------*/
+/* Convert an A.B.C.D address into a 32-bit host-order value */
+/*-----------------------------------------------------------*/
+in_addr_t a_to_hl(const char *ipstr ) {
+ struct in_addr in;
+ if ( !inet_aton(ipstr, &in) ) {
+ fprintf( stderr, "%s: Invalid address %s!\n", PROG, ipstr );
+ exit( 1 );
+ }
+
+ return( ntohl(in.s_addr) );
+
+} /* a_to_hl() */
+
+
+/*-----------------------------------------------------------------*/
+/* 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) {
+ long int prefix = 32;
+ char *prefixstr;
+
+ if ( (prefixstr = strchr(ipstr, '/')) ) {
+ *prefixstr = '\0';
+ prefixstr++;
+ prefix = strtol( prefixstr, (char **) NULL, 10 );
+ if ((*prefixstr == '\0') || (prefix < 0) || (prefix > 32)) {
+ fprintf( stderr, "%s: Invalid prefix /%s...!\n", PROG, prefixstr );
+ return -1;
+ }
+ }
+ else {
+ printf("no prefix");
+ }
+
+ netaddr->pfx = (int) prefix;
+ netaddr->addr = network( a_to_hl(ipstr), prefix );
+ return 0;
+
+} /* str_to_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 ) {
+
+ struct in_addr in;
+
+ if ( lo != hi ) {
+ in.s_addr = htonl( lo );
+ printf( "%s-", inet_ntoa(in) );
+ }
+
+ in.s_addr = htonl( hi );
+ printf( "%s\n", inet_ntoa(in) );
+
+} /* print_addr_range() */
+
+/*----------------------------------------------------------------------------*/
+/*----------------------------------------------------------------------------*/
+
diff --git a/src/packets.c b/src/packets.c
index 637d3ce21..9a45f500c 100644
--- a/src/packets.c
+++ b/src/packets.c
@@ -142,6 +142,7 @@ struct rte_mbuf **pg_packets_prepend_str(struct rte_mbuf **pkts,
if (!tmp) \
return NULL; \
rte_memcpy(tmp, &ip_hdr, sizeof(ip_hdr)); \
+ pkts[j]->packet_type += 16; \
pkts[j]->l3_len = sizeof(struct ipv4_hdr); \
} \
@@ -214,6 +215,8 @@ struct rte_mbuf **pg_packets_append_ipv6(struct rte_mbuf **pkts,
tmp = rte_pktmbuf_##ops(pkts[j], sizeof(udp_hdr)); \
if (!tmp) \
return NULL; \
+ pkts[j]->l4_len = sizeof(struct udp_hdr); \
+ pkts[j]->packet_type += 512; \
memcpy(tmp, &udp_hdr, sizeof(udp_hdr)); \
} \
@@ -286,6 +289,7 @@ struct rte_mbuf **pg_packets_prepend_vxlan(struct rte_mbuf **pkts,
if (!tmp) \
return NULL; \
rte_memcpy(tmp, ð_hdr, sizeof(eth_hdr)); \
+ pkts[j]->packet_type += 1; \
pkts[j]->l2_len = sizeof(struct ether_hdr); \
} \
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..3dae20f20
--- /dev/null
+++ b/tests/dhcp/tests.c
@@ -0,0 +1,303 @@
+ /* 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;
+
+ ret = pg_vhost_start("/tmp", &error);
+ g_assert(ret == 0);
+ g_assert(!error);
+
+ 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);
+
+ pg_brick_link(collect, vhost, &error);
+ g_assert(!error);
+
+ 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;
+}