198937Sdes/* 298937Sdes * Copyright (C) 2013-2014 Michio Honda. All rights reserved. 398937Sdes * 498937Sdes * Redistribution and use in source and binary forms, with or without 598937Sdes * modification, are permitted provided that the following conditions 698937Sdes * are met: 798937Sdes * 1. Redistributions of source code must retain the above copyright 898937Sdes * notice, this list of conditions and the following disclaimer. 998937Sdes * 2. Redistributions in binary form must reproduce the above copyright 1098937Sdes * notice, this list of conditions and the following disclaimer in the 1198937Sdes * documentation and/or other materials provided with the distribution. 1298937Sdes * 1398937Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1498937Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1598937Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1698937Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1798937Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1898937Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1998937Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2098937Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2198937Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2298937Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2398937Sdes * SUCH DAMAGE. 2498937Sdes */ 2598937Sdes 2698937Sdes/* $FreeBSD$ */ 2798937Sdes 2898937Sdes#include <errno.h> 2998937Sdes#include <stdio.h> 3098937Sdes#include <inttypes.h> /* PRI* macros */ 3198937Sdes#include <string.h> /* strcmp */ 3298937Sdes#include <fcntl.h> /* open */ 3398937Sdes#include <unistd.h> /* close */ 34162852Sdes#include <sys/ioctl.h> /* ioctl */ 35162852Sdes#include <sys/param.h> 36162852Sdes#include <sys/socket.h> /* apple needs sockaddr */ 37162852Sdes#include <net/if.h> /* ifreq */ 3898937Sdes#include <net/netmap.h> 3998937Sdes#include <net/netmap_user.h> 4098937Sdes#include <libgen.h> /* basename */ 4198937Sdes#include <stdlib.h> /* atoi, free */ 4298937Sdes 4398937Sdes/* debug support */ 4498937Sdes#define ND(format, ...) do {} while(0) 4598937Sdes#define D(format, ...) \ 4698937Sdes fprintf(stderr, "%s [%d] " format "\n", \ 4798937Sdes __FUNCTION__, __LINE__, ##__VA_ARGS__) 4898937Sdes 4998937Sdes/* XXX cut and paste from pkt-gen.c because I'm not sure whether this 5098937Sdes * program may include nm_util.h 5198937Sdes */ 5298937Sdesvoid parse_nmr_config(const char* conf, struct nmreq *nmr) 5398937Sdes{ 5498937Sdes char *w, *tok; 5598937Sdes int i, v; 5698937Sdes 5798937Sdes nmr->nr_tx_rings = nmr->nr_rx_rings = 0; 5898937Sdes nmr->nr_tx_slots = nmr->nr_rx_slots = 0; 5998937Sdes if (conf == NULL || ! *conf) 6098937Sdes return; 6198937Sdes w = strdup(conf); 6298937Sdes for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) { 6398937Sdes v = atoi(tok); 6498937Sdes switch (i) { 6598937Sdes case 0: 6698937Sdes nmr->nr_tx_slots = nmr->nr_rx_slots = v; 6798937Sdes break; 6898937Sdes case 1: 6998937Sdes nmr->nr_rx_slots = v; 7098937Sdes break; 7198937Sdes case 2: 7298937Sdes nmr->nr_tx_rings = nmr->nr_rx_rings = v; 7398937Sdes break; 7498937Sdes case 3: 7598937Sdes nmr->nr_rx_rings = v; 7698937Sdes break; 7798937Sdes default: 7898937Sdes D("ignored config: %s", tok); 7998937Sdes break; 8098937Sdes } 8198937Sdes } 8298937Sdes D("txr %d txd %d rxr %d rxd %d", 8398937Sdes nmr->nr_tx_rings, nmr->nr_tx_slots, 8498937Sdes nmr->nr_rx_rings, nmr->nr_rx_slots); 8598937Sdes free(w); 8698937Sdes} 8798937Sdes 8898937Sdesstatic int 8998937Sdesbdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config) 9098937Sdes{ 9198937Sdes struct nmreq nmr; 9298937Sdes int error = 0; 9398937Sdes int fd = open("/dev/netmap", O_RDWR); 9498937Sdes 9598937Sdes if (fd == -1) { 9698937Sdes D("Unable to open /dev/netmap"); 9798937Sdes return -1; 9898937Sdes } 9998937Sdes 10098937Sdes bzero(&nmr, sizeof(nmr)); 10198937Sdes nmr.nr_version = NETMAP_API; 10298937Sdes if (name != NULL) /* might be NULL */ 10398937Sdes strncpy(nmr.nr_name, name, sizeof(nmr.nr_name)); 10498937Sdes nmr.nr_cmd = nr_cmd; 10598937Sdes parse_nmr_config(nmr_config, &nmr); 10698937Sdes 10798937Sdes switch (nr_cmd) { 10898937Sdes case NETMAP_BDG_DELIF: 10998937Sdes case NETMAP_BDG_NEWIF: 11098937Sdes error = ioctl(fd, NIOCREGIF, &nmr); 11198937Sdes if (error == -1) { 11298937Sdes ND("Unable to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name); 11398937Sdes perror(name); 11498937Sdes } else { 11598937Sdes ND("Success to %s %s", nr_cmd == NETMAP_BDG_DELIF ? "delete":"create", name); 11698937Sdes } 11798937Sdes break; 11898937Sdes case NETMAP_BDG_ATTACH: 11998937Sdes case NETMAP_BDG_DETACH: 12098937Sdes if (nr_arg && nr_arg != NETMAP_BDG_HOST) 12198937Sdes nr_arg = 0; 12298937Sdes nmr.nr_arg1 = nr_arg; 12398937Sdes error = ioctl(fd, NIOCREGIF, &nmr); 12498937Sdes if (error == -1) { 12598937Sdes ND("Unable to %s %s to the bridge", nr_cmd == 12698937Sdes NETMAP_BDG_DETACH?"detach":"attach", name); 12798937Sdes perror(name); 12898937Sdes } else 12998937Sdes ND("Success to %s %s to the bridge", nr_cmd == 13098937Sdes NETMAP_BDG_DETACH?"detach":"attach", name); 13198937Sdes break; 13298937Sdes 13398937Sdes case NETMAP_BDG_LIST: 13498937Sdes if (strlen(nmr.nr_name)) { /* name to bridge/port info */ 13598937Sdes error = ioctl(fd, NIOCGINFO, &nmr); 13698937Sdes if (error) { 13798937Sdes ND("Unable to obtain info for %s", name); 13898937Sdes perror(name); 13998937Sdes } else 14098937Sdes D("%s at bridge:%d port:%d", name, nmr.nr_arg1, 14198937Sdes nmr.nr_arg2); 14298937Sdes break; 14398937Sdes } 14498937Sdes 14598937Sdes /* scan all the bridges and ports */ 14698937Sdes nmr.nr_arg1 = nmr.nr_arg2 = 0; 14798937Sdes for (; !ioctl(fd, NIOCGINFO, &nmr); nmr.nr_arg2++) { 14898937Sdes D("bridge:%d port:%d %s", nmr.nr_arg1, nmr.nr_arg2, 14998937Sdes nmr.nr_name); 15098937Sdes nmr.nr_name[0] = '\0'; 15198937Sdes } 15298937Sdes 15398937Sdes break; 15498937Sdes 15598937Sdes default: /* GINFO */ 15698937Sdes nmr.nr_cmd = nmr.nr_arg1 = nmr.nr_arg2 = 0; 15798937Sdes error = ioctl(fd, NIOCGINFO, &nmr); 15898937Sdes if (error) { 15998937Sdes ND("Unable to get if info for %s", name); 16098937Sdes perror(name); 16198937Sdes } else 16298937Sdes D("%s: %d queues.", name, nmr.nr_rx_rings); 16398937Sdes break; 16498937Sdes } 16598937Sdes close(fd); 16698937Sdes return error; 16798937Sdes} 16898937Sdes 16998937Sdesint 17098937Sdesmain(int argc, char *argv[]) 17198937Sdes{ 17298937Sdes int ch, nr_cmd = 0, nr_arg = 0; 17398937Sdes const char *command = basename(argv[0]); 17498937Sdes char *name = NULL, *nmr_config = NULL; 17598937Sdes 17698937Sdes if (argc > 3) { 17798937Sdesusage: 17898937Sdes fprintf(stderr, 17998937Sdes "Usage:\n" 18098937Sdes "%s arguments\n" 18198937Sdes "\t-g interface interface name to get info\n" 18298937Sdes "\t-d interface interface name to be detached\n" 18398937Sdes "\t-a interface interface name to be attached\n" 18498937Sdes "\t-h interface interface name to be attached with the host stack\n" 18598937Sdes "\t-n interface interface name to be created\n" 18698937Sdes "\t-r interface interface name to be deleted\n" 18798937Sdes "\t-l list all or specified bridge's interfaces (default)\n" 18898937Sdes "\t-C string ring/slot setting of an interface creating by -n\n" 18998937Sdes "", command); 19098937Sdes return 0; 19198937Sdes } 19298937Sdes 19398937Sdes while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:")) != -1) { 19498937Sdes name = optarg; /* default */ 19598937Sdes switch (ch) { 19698937Sdes default: 19798937Sdes fprintf(stderr, "bad option %c %s", ch, optarg); 19898937Sdes goto usage; 19998937Sdes case 'd': 20098937Sdes nr_cmd = NETMAP_BDG_DETACH; 20198937Sdes break; 20298937Sdes case 'a': 20398937Sdes nr_cmd = NETMAP_BDG_ATTACH; 20498937Sdes break; 20598937Sdes case 'h': 20698937Sdes nr_cmd = NETMAP_BDG_ATTACH; 20798937Sdes nr_arg = NETMAP_BDG_HOST; 20898937Sdes break; 20998937Sdes case 'n': 21098937Sdes nr_cmd = NETMAP_BDG_NEWIF; 21198937Sdes break; 21298937Sdes case 'r': 21398937Sdes nr_cmd = NETMAP_BDG_DELIF; 21498937Sdes break; 21598937Sdes case 'g': 21698937Sdes nr_cmd = 0; 21798937Sdes break; 21898937Sdes case 'l': 21998937Sdes nr_cmd = NETMAP_BDG_LIST; 22098937Sdes if (optind < argc && argv[optind][0] == '-') 22198937Sdes name = NULL; 22298937Sdes break; 22398937Sdes case 'C': 22498937Sdes nmr_config = strdup(optarg); 22598937Sdes break; 22698937Sdes } 22798937Sdes if (optind != argc) { 22898937Sdes // fprintf(stderr, "optind %d argc %d\n", optind, argc); 22998937Sdes goto usage; 23098937Sdes } 23198937Sdes } 23298937Sdes if (argc == 1) 23398937Sdes nr_cmd = NETMAP_BDG_LIST; 23498937Sdes return bdg_ctl(name, nr_cmd, nr_arg, nmr_config) ? 1 : 0; 23598937Sdes} 23698937Sdes