/* * iplink_bridge_slave.c Bridge slave device support * * 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. * * Authors: Jiri Pirko <jiri@resnulli.us> */ #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <linux/if_link.h> #include <linux/if_bridge.h> #include "rt_names.h" #include "utils.h" #include "ip_common.h" static void print_explain(FILE *f) { fprintf(f, "Usage: ... bridge_slave [ state STATE ] [ priority PRIO ] [cost COST ]\n" " [ guard {on | off} ]\n" " [ hairpin {on | off} ] \n" " [ fastleave {on | off} ]\n" " [ root_block {on | off} ]\n" " [ learning {on | off} ]\n" " [ flood {on | off} ]\n" ); } static void explain(void) { print_explain(stderr); } static const char *port_states[] = { [BR_STATE_DISABLED] = "disabled", [BR_STATE_LISTENING] = "listening", [BR_STATE_LEARNING] = "learning", [BR_STATE_FORWARDING] = "forwarding", [BR_STATE_BLOCKING] = "blocking", }; static void print_portstate(FILE *f, __u8 state) { if (state <= BR_STATE_BLOCKING) fprintf(f, "state %s ", port_states[state]); else fprintf(f, "state (%d) ", state); } static void print_onoff(FILE *f, char *flag, __u8 val) { fprintf(f, "%s %s ", flag, val ? "on" : "off"); } static void bridge_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { if (!tb) return; if (tb[IFLA_BRPORT_STATE]) print_portstate(f, rta_getattr_u8(tb[IFLA_BRPORT_STATE])); if (tb[IFLA_BRPORT_PRIORITY]) fprintf(f, "priority %d ", rta_getattr_u16(tb[IFLA_BRPORT_PRIORITY])); if (tb[IFLA_BRPORT_COST]) fprintf(f, "cost %d ", rta_getattr_u32(tb[IFLA_BRPORT_COST])); if (tb[IFLA_BRPORT_MODE]) print_onoff(f, "hairpin", rta_getattr_u8(tb[IFLA_BRPORT_MODE])); if (tb[IFLA_BRPORT_GUARD]) print_onoff(f, "guard", rta_getattr_u8(tb[IFLA_BRPORT_GUARD])); if (tb[IFLA_BRPORT_PROTECT]) print_onoff(f, "root_block", rta_getattr_u8(tb[IFLA_BRPORT_PROTECT])); if (tb[IFLA_BRPORT_FAST_LEAVE]) print_onoff(f, "fastleave", rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE])); if (tb[IFLA_BRPORT_LEARNING]) print_onoff(f, "learning", rta_getattr_u8(tb[IFLA_BRPORT_LEARNING])); if (tb[IFLA_BRPORT_UNICAST_FLOOD]) print_onoff(f, "flood", rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD])); } static void bridge_slave_parse_on_off(char *arg_name, char *arg_val, struct nlmsghdr *n, int type) { __u8 val; if (strcmp(arg_val, "on") == 0) val = 1; else if (strcmp(arg_val, "off") == 0) val = 0; else invarg("should be \"on\" or \"off\"", arg_name); addattr8(n, 1024, type, val); } static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { __u8 state; __u16 priority; __u32 cost; while (argc > 0) { if (matches(*argv, "state") == 0) { NEXT_ARG(); if (get_u8(&state, *argv, 0)) invarg("state is invalid", *argv); addattr8(n, 1024, IFLA_BRPORT_STATE, state); } else if (matches(*argv, "priority") == 0) { NEXT_ARG(); if (get_u16(&priority, *argv, 0)) invarg("priority is invalid", *argv); addattr16(n, 1024, IFLA_BRPORT_PRIORITY, priority); } else if (matches(*argv, "cost") == 0) { NEXT_ARG(); if (get_u32(&cost, *argv, 0)) invarg("cost is invalid", *argv); addattr32(n, 1024, IFLA_BRPORT_COST, cost); } else if (matches(*argv, "hairpin") == 0) { NEXT_ARG(); bridge_slave_parse_on_off("hairpin", *argv, n, IFLA_BRPORT_MODE); } else if (matches(*argv, "guard") == 0) { NEXT_ARG(); bridge_slave_parse_on_off("guard", *argv, n, IFLA_BRPORT_GUARD); } else if (matches(*argv, "root_block") == 0) { NEXT_ARG(); bridge_slave_parse_on_off("root_block", *argv, n, IFLA_BRPORT_PROTECT); } else if (matches(*argv, "fastleave") == 0) { NEXT_ARG(); bridge_slave_parse_on_off("fastleave", *argv, n, IFLA_BRPORT_FAST_LEAVE); } else if (matches(*argv, "learning") == 0) { NEXT_ARG(); bridge_slave_parse_on_off("learning", *argv, n, IFLA_BRPORT_LEARNING); } else if (matches(*argv, "flood") == 0) { NEXT_ARG(); bridge_slave_parse_on_off("flood", *argv, n, IFLA_BRPORT_UNICAST_FLOOD); } else if (matches(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "bridge_slave: unknown option \"%s\"?\n", *argv); explain(); return -1; } argc--, argv++; } return 0; } static void bridge_slave_print_help(struct link_util *lu, int argc, char **argv, FILE *f) { print_explain(f); } struct link_util bridge_slave_link_util = { .id = "bridge", .maxattr = IFLA_BRPORT_MAX, .print_opt = bridge_slave_print_opt, .parse_opt = bridge_slave_parse_opt, .print_help = bridge_slave_print_help, .slave = true, };