1 /* 2 * iplink_bridge_slave.c Bridge slave device support 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Jiri Pirko <jiri (at) resnulli.us> 10 */ 11 12 #include <stdio.h> 13 #include <sys/socket.h> 14 #include <netinet/in.h> 15 #include <linux/if_link.h> 16 #include <linux/if_bridge.h> 17 18 #include "rt_names.h" 19 #include "utils.h" 20 #include "ip_common.h" 21 22 static void print_explain(FILE *f) 23 { 24 fprintf(f, 25 "Usage: ... bridge_slave [ state STATE ] [ priority PRIO ] [cost COST ]\n" 26 " [ guard {on | off} ]\n" 27 " [ hairpin {on | off} ] \n" 28 " [ fastleave {on | off} ]\n" 29 " [ root_block {on | off} ]\n" 30 " [ learning {on | off} ]\n" 31 " [ flood {on | off} ]\n" 32 ); 33 } 34 35 static void explain(void) 36 { 37 print_explain(stderr); 38 } 39 40 static const char *port_states[] = { 41 [BR_STATE_DISABLED] = "disabled", 42 [BR_STATE_LISTENING] = "listening", 43 [BR_STATE_LEARNING] = "learning", 44 [BR_STATE_FORWARDING] = "forwarding", 45 [BR_STATE_BLOCKING] = "blocking", 46 }; 47 48 static void print_portstate(FILE *f, __u8 state) 49 { 50 if (state <= BR_STATE_BLOCKING) 51 fprintf(f, "state %s ", port_states[state]); 52 else 53 fprintf(f, "state (%d) ", state); 54 } 55 56 static void print_onoff(FILE *f, char *flag, __u8 val) 57 { 58 fprintf(f, "%s %s ", flag, val ? "on" : "off"); 59 } 60 61 static void bridge_slave_print_opt(struct link_util *lu, FILE *f, 62 struct rtattr *tb[]) 63 { 64 if (!tb) 65 return; 66 67 if (tb[IFLA_BRPORT_STATE]) 68 print_portstate(f, rta_getattr_u8(tb[IFLA_BRPORT_STATE])); 69 70 if (tb[IFLA_BRPORT_PRIORITY]) 71 fprintf(f, "priority %d ", 72 rta_getattr_u16(tb[IFLA_BRPORT_PRIORITY])); 73 74 if (tb[IFLA_BRPORT_COST]) 75 fprintf(f, "cost %d ", 76 rta_getattr_u32(tb[IFLA_BRPORT_COST])); 77 78 if (tb[IFLA_BRPORT_MODE]) 79 print_onoff(f, "hairpin", 80 rta_getattr_u8(tb[IFLA_BRPORT_MODE])); 81 82 if (tb[IFLA_BRPORT_GUARD]) 83 print_onoff(f, "guard", 84 rta_getattr_u8(tb[IFLA_BRPORT_GUARD])); 85 86 if (tb[IFLA_BRPORT_PROTECT]) 87 print_onoff(f, "root_block", 88 rta_getattr_u8(tb[IFLA_BRPORT_PROTECT])); 89 90 if (tb[IFLA_BRPORT_FAST_LEAVE]) 91 print_onoff(f, "fastleave", 92 rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE])); 93 94 if (tb[IFLA_BRPORT_LEARNING]) 95 print_onoff(f, "learning", 96 rta_getattr_u8(tb[IFLA_BRPORT_LEARNING])); 97 98 if (tb[IFLA_BRPORT_UNICAST_FLOOD]) 99 print_onoff(f, "flood", 100 rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD])); 101 } 102 103 static void bridge_slave_parse_on_off(char *arg_name, char *arg_val, 104 struct nlmsghdr *n, int type) 105 { 106 __u8 val; 107 108 if (strcmp(arg_val, "on") == 0) 109 val = 1; 110 else if (strcmp(arg_val, "off") == 0) 111 val = 0; 112 else 113 invarg("should be \"on\" or \"off\"", arg_name); 114 115 addattr8(n, 1024, type, val); 116 } 117 118 static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv, 119 struct nlmsghdr *n) 120 { 121 __u8 state; 122 __u16 priority; 123 __u32 cost; 124 125 while (argc > 0) { 126 if (matches(*argv, "state") == 0) { 127 NEXT_ARG(); 128 if (get_u8(&state, *argv, 0)) 129 invarg("state is invalid", *argv); 130 addattr8(n, 1024, IFLA_BRPORT_STATE, state); 131 } else if (matches(*argv, "priority") == 0) { 132 NEXT_ARG(); 133 if (get_u16(&priority, *argv, 0)) 134 invarg("priority is invalid", *argv); 135 addattr16(n, 1024, IFLA_BRPORT_PRIORITY, priority); 136 } else if (matches(*argv, "cost") == 0) { 137 NEXT_ARG(); 138 if (get_u32(&cost, *argv, 0)) 139 invarg("cost is invalid", *argv); 140 addattr32(n, 1024, IFLA_BRPORT_COST, cost); 141 } else if (matches(*argv, "hairpin") == 0) { 142 NEXT_ARG(); 143 bridge_slave_parse_on_off("hairpin", *argv, n, 144 IFLA_BRPORT_MODE); 145 } else if (matches(*argv, "guard") == 0) { 146 NEXT_ARG(); 147 bridge_slave_parse_on_off("guard", *argv, n, 148 IFLA_BRPORT_GUARD); 149 } else if (matches(*argv, "root_block") == 0) { 150 NEXT_ARG(); 151 bridge_slave_parse_on_off("root_block", *argv, n, 152 IFLA_BRPORT_PROTECT); 153 } else if (matches(*argv, "fastleave") == 0) { 154 NEXT_ARG(); 155 bridge_slave_parse_on_off("fastleave", *argv, n, 156 IFLA_BRPORT_FAST_LEAVE); 157 } else if (matches(*argv, "learning") == 0) { 158 NEXT_ARG(); 159 bridge_slave_parse_on_off("learning", *argv, n, 160 IFLA_BRPORT_LEARNING); 161 } else if (matches(*argv, "flood") == 0) { 162 NEXT_ARG(); 163 bridge_slave_parse_on_off("flood", *argv, n, 164 IFLA_BRPORT_UNICAST_FLOOD); 165 } else if (matches(*argv, "help") == 0) { 166 explain(); 167 return -1; 168 } else { 169 fprintf(stderr, "bridge_slave: unknown option \"%s\"?\n", 170 *argv); 171 explain(); 172 return -1; 173 } 174 argc--, argv++; 175 } 176 177 return 0; 178 } 179 180 static void bridge_slave_print_help(struct link_util *lu, int argc, char **argv, 181 FILE *f) 182 { 183 print_explain(f); 184 } 185 186 struct link_util bridge_slave_link_util = { 187 .id = "bridge", 188 .maxattr = IFLA_BRPORT_MAX, 189 .print_opt = bridge_slave_print_opt, 190 .parse_opt = bridge_slave_parse_opt, 191 .print_help = bridge_slave_print_help, 192 .slave = true, 193 }; 194