Home | History | Annotate | Download | only in bridge
      1 /*
      2  * Get/set/delete bridge with netlink
      3  *
      4  * Authors:	Stephen Hemminger <shemminger (at) vyatta.com>
      5  */
      6 
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <unistd.h>
     10 #include <sys/socket.h>
     11 #include <string.h>
     12 #include <errno.h>
     13 
     14 #include "SNAPSHOT.h"
     15 #include "utils.h"
     16 #include "br_common.h"
     17 #include "namespace.h"
     18 
     19 struct rtnl_handle rth = { .fd = -1 };
     20 int preferred_family = AF_UNSPEC;
     21 int oneline;
     22 int show_stats;
     23 int show_details;
     24 int compress_vlans;
     25 int json_output;
     26 int timestamp;
     27 char *batch_file;
     28 int force;
     29 const char *_SL_;
     30 
     31 static void usage(void) __attribute__((noreturn));
     32 
     33 static void usage(void)
     34 {
     35 	fprintf(stderr,
     36 "Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n"
     37 "       bridge [ -force ] -batch filename\n"
     38 "where	OBJECT := { link | fdb | mdb | vlan | monitor }\n"
     39 "	OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
     40 "		     -o[neline] | -t[imestamp] | -n[etns] name |\n"
     41 "		     -c[ompressvlans] -j{son} }\n");
     42 	exit(-1);
     43 }
     44 
     45 static int do_help(int argc, char **argv)
     46 {
     47 	usage();
     48 }
     49 
     50 
     51 static const struct cmd {
     52 	const char *cmd;
     53 	int (*func)(int argc, char **argv);
     54 } cmds[] = {
     55 	{ "link",	do_link },
     56 	{ "fdb",	do_fdb },
     57 	{ "mdb",	do_mdb },
     58 	{ "vlan",	do_vlan },
     59 	{ "monitor",	do_monitor },
     60 	{ "help",	do_help },
     61 	{ 0 }
     62 };
     63 
     64 static int do_cmd(const char *argv0, int argc, char **argv)
     65 {
     66 	const struct cmd *c;
     67 
     68 	for (c = cmds; c->cmd; ++c) {
     69 		if (matches(argv0, c->cmd) == 0)
     70 			return c->func(argc-1, argv+1);
     71 	}
     72 
     73 	fprintf(stderr,
     74 		"Object \"%s\" is unknown, try \"bridge help\".\n", argv0);
     75 	return -1;
     76 }
     77 
     78 static int batch(const char *name)
     79 {
     80 	char *line = NULL;
     81 	size_t len = 0;
     82 	int ret = EXIT_SUCCESS;
     83 
     84 	if (name && strcmp(name, "-") != 0) {
     85 		if (freopen(name, "r", stdin) == NULL) {
     86 			fprintf(stderr,
     87 				"Cannot open file \"%s\" for reading: %s\n",
     88 				name, strerror(errno));
     89 			return EXIT_FAILURE;
     90 		}
     91 	}
     92 
     93 	if (rtnl_open(&rth, 0) < 0) {
     94 		fprintf(stderr, "Cannot open rtnetlink\n");
     95 		return EXIT_FAILURE;
     96 	}
     97 
     98 	cmdlineno = 0;
     99 	while (getcmdline(&line, &len, stdin) != -1) {
    100 		char *largv[100];
    101 		int largc;
    102 
    103 		largc = makeargs(line, largv, 100);
    104 		if (largc == 0)
    105 			continue;       /* blank line */
    106 
    107 		if (do_cmd(largv[0], largc, largv)) {
    108 			fprintf(stderr, "Command failed %s:%d\n",
    109 				name, cmdlineno);
    110 			ret = EXIT_FAILURE;
    111 			if (!force)
    112 				break;
    113 		}
    114 	}
    115 	if (line)
    116 		free(line);
    117 
    118 	rtnl_close(&rth);
    119 	return ret;
    120 }
    121 
    122 int
    123 main(int argc, char **argv)
    124 {
    125 	while (argc > 1) {
    126 		const char *opt = argv[1];
    127 
    128 		if (strcmp(opt, "--") == 0) {
    129 			argc--; argv++;
    130 			break;
    131 		}
    132 		if (opt[0] != '-')
    133 			break;
    134 		if (opt[1] == '-')
    135 			opt++;
    136 
    137 		if (matches(opt, "-help") == 0) {
    138 			usage();
    139 		} else if (matches(opt, "-Version") == 0) {
    140 			printf("bridge utility, 0.0\n");
    141 			exit(0);
    142 		} else if (matches(opt, "-stats") == 0 ||
    143 			   matches(opt, "-statistics") == 0) {
    144 			++show_stats;
    145 		} else if (matches(opt, "-details") == 0) {
    146 			++show_details;
    147 		} else if (matches(opt, "-oneline") == 0) {
    148 			++oneline;
    149 		} else if (matches(opt, "-timestamp") == 0) {
    150 			++timestamp;
    151 		} else if (matches(opt, "-family") == 0) {
    152 			argc--;
    153 			argv++;
    154 			if (argc <= 1)
    155 				usage();
    156 			if (strcmp(argv[1], "inet") == 0)
    157 				preferred_family = AF_INET;
    158 			else if (strcmp(argv[1], "inet6") == 0)
    159 				preferred_family = AF_INET6;
    160 			else if (strcmp(argv[1], "help") == 0)
    161 				usage();
    162 			else
    163 				invarg("invalid protocol family", argv[1]);
    164 		} else if (strcmp(opt, "-4") == 0) {
    165 			preferred_family = AF_INET;
    166 		} else if (strcmp(opt, "-6") == 0) {
    167 			preferred_family = AF_INET6;
    168 		} else if (matches(opt, "-netns") == 0) {
    169 			NEXT_ARG();
    170 			if (netns_switch(argv[1]))
    171 				exit(-1);
    172 		} else if (matches(opt, "-compressvlans") == 0) {
    173 			++compress_vlans;
    174 		} else if (matches(opt, "-force") == 0) {
    175 			++force;
    176 		} else if (matches(opt, "-json") == 0) {
    177 			++json_output;
    178 		} else if (matches(opt, "-batch") == 0) {
    179 			argc--;
    180 			argv++;
    181 			if (argc <= 1)
    182 				usage();
    183 			batch_file = argv[1];
    184 		} else {
    185 			fprintf(stderr,
    186 				"Option \"%s\" is unknown, try \"bridge help\".\n",
    187 				opt);
    188 			exit(-1);
    189 		}
    190 		argc--;	argv++;
    191 	}
    192 
    193 	_SL_ = oneline ? "\\" : "\n";
    194 
    195 	if (batch_file)
    196 		return batch(batch_file);
    197 
    198 	if (rtnl_open(&rth, 0) < 0)
    199 		exit(1);
    200 
    201 	if (argc > 1)
    202 		return do_cmd(argv[1], argc-1, argv+1);
    203 
    204 	rtnl_close(&rth);
    205 	usage();
    206 }
    207