]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iplink_bridge_slave.c
Merge branch 'master' into net-next
[mirror_iproute2.git] / ip / iplink_bridge_slave.c
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@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 };