diff options
Diffstat (limited to 'test/packetdrill/wire_client_netdev.c')
-rw-r--r-- | test/packetdrill/wire_client_netdev.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/test/packetdrill/wire_client_netdev.c b/test/packetdrill/wire_client_netdev.c new file mode 100644 index 0000000..ce4ebef --- /dev/null +++ b/test/packetdrill/wire_client_netdev.c @@ -0,0 +1,167 @@ +/* + * Copyright 2013 Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +/* + * Author: ncardwell@google.com (Neal Cardwell) + * + * Client-side network device code for remote on-the-wire testing + * using a real NIC. + */ + +#include "wire_client_netdev.h" + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "logging.h" +#include "net_utils.h" + +struct wire_client_netdev { + struct netdev netdev; /* "inherit" from netdev */ + + char *name; /* malloc-allocated copy of interface name */ +}; + +struct netdev_ops wire_client_netdev_ops; + +/* "Downcast" an abstract netdev to our flavor. */ +static inline struct wire_client_netdev *to_client_netdev( + struct netdev *netdev) +{ + return (struct wire_client_netdev *)netdev; +} + +/* Check that the remote IP is actually remote. It must be to ensure + * that test packets will pass through our device. + */ +static void check_remote_address(struct config *config, + struct wire_client_netdev *netdev) +{ + if (is_ip_local(&config->live_remote_ip)) { + die("error: live_remote_ip %s is not remote\n", + config->live_remote_ip_string); + } +} + + +/* Route traffic destined for our remote IP through this device */ +static void route_traffic_to_wire_server(struct config *config, + struct wire_client_netdev *netdev) +{ + char *route_command = NULL; +#ifdef linux + asprintf(&route_command, + "ip %s route del %s > /dev/null 2>&1 ; " + "ip %s route add %s dev %s via %s > /dev/null 2>&1", + (config->wire_protocol == AF_INET6) ? "-6" : "", + config->live_remote_prefix_string, + (config->wire_protocol == AF_INET6) ? "-6" : "", + config->live_remote_prefix_string, + netdev->name, + config->live_gateway_ip_string); +#endif +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + if (config->wire_protocol == AF_INET) { + asprintf(&route_command, + "route delete %s > /dev/null 2>&1 ; " + "route add %s %s > /dev/null 2>&1", + config->live_remote_prefix_string, + config->live_remote_prefix_string, + config->live_gateway_ip_string); + } else if (config->wire_protocol == AF_INET6) { + asprintf(&route_command, + "route delete -inet6 %s > /dev/null 2>&1 ; " + "route add -inet6 %s %s > /dev/null 2>&1", + config->live_remote_prefix_string, + config->live_remote_prefix_string, + config->live_gateway_ip_string); + } else { + assert(!"bad wire protocol"); + } +#endif /* defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) */ + + /* We intentionally ignore failures and output to stderr, + * since they can happen if there is no previously existing + * route. + */ + system(route_command); + + free(route_command); +} + +struct netdev *wire_client_netdev_new(struct config *config) +{ + DEBUGP("wire_client_netdev_new\n"); + + struct wire_client_netdev *netdev = + calloc(1, sizeof(struct wire_client_netdev)); + + netdev->netdev.ops = &wire_client_netdev_ops; + + netdev->name = strdup(config->wire_client_device); + + check_remote_address(config, netdev); + + /* Add the client live local IP to our NIC, so we can send/receive */ + net_setup_dev_address(netdev->name, + &config->live_local_ip, + config->live_prefix_len); + + route_traffic_to_wire_server(config, netdev); + + return (struct netdev *)netdev; +} + +static void wire_client_netdev_free(struct netdev *a_netdev) +{ + DEBUGP("wire_client_netdev_free\n"); + + struct wire_client_netdev *netdev = to_client_netdev(a_netdev); + + free(netdev->name); + + memset(netdev, 0, sizeof(*netdev)); /* paranoia */ + free(netdev); +} + +static int wire_client_netdev_send(struct netdev *a_netdev, + struct packet *packet) +{ + DEBUGP("wire_client_netdev_send\n"); + assert(!"wire clients should not be sending packets themselves!"); + /* The server side should be sending the packets... */ + + return STATUS_ERR; +} + +static int wire_client_netdev_receive(struct netdev *a_netdev, + struct packet **packet, char **error) +{ + DEBUGP("wire_client_netdev_receive\n"); + assert(!"wire clients should not be receiving packets themselves!"); + /* The server side should be receiving and checking the packets... */ + + return STATUS_ERR; +} + +struct netdev_ops wire_client_netdev_ops = { + .free = wire_client_netdev_free, + .send = wire_client_netdev_send, + .receive = wire_client_netdev_receive, +}; |