]>
Commit | Line | Data |
---|---|---|
8c39db39 JP |
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 explain(void) | |
23 | { | |
24 | fprintf(stderr, | |
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 const char *port_states[] = { | |
36 | [BR_STATE_DISABLED] = "disabled", | |
37 | [BR_STATE_LISTENING] = "listening", | |
38 | [BR_STATE_LEARNING] = "learning", | |
39 | [BR_STATE_FORWARDING] = "forwarding", | |
40 | [BR_STATE_BLOCKING] = "blocking", | |
41 | }; | |
42 | ||
43 | static void print_portstate(FILE *f, __u8 state) | |
44 | { | |
45 | if (state <= BR_STATE_BLOCKING) | |
46 | fprintf(f, "state %s ", port_states[state]); | |
47 | else | |
48 | fprintf(f, "state (%d) ", state); | |
49 | } | |
50 | ||
51 | static void print_onoff(FILE *f, char *flag, __u8 val) | |
52 | { | |
53 | fprintf(f, "%s %s ", flag, val ? "on" : "off"); | |
54 | } | |
55 | ||
56 | static void bridge_slave_print_opt(struct link_util *lu, FILE *f, | |
57 | struct rtattr *tb[]) | |
58 | { | |
59 | if (!tb) | |
60 | return; | |
61 | ||
62 | if (tb[IFLA_BRPORT_STATE]) | |
63 | print_portstate(f, rta_getattr_u8(tb[IFLA_BRPORT_STATE])); | |
64 | ||
65 | if (tb[IFLA_BRPORT_PRIORITY]) | |
66 | fprintf(f, "priority %d ", | |
67 | rta_getattr_u16(tb[IFLA_BRPORT_PRIORITY])); | |
68 | ||
69 | if (tb[IFLA_BRPORT_COST]) | |
70 | fprintf(f, "cost %d ", | |
71 | rta_getattr_u32(tb[IFLA_BRPORT_COST])); | |
72 | ||
73 | if (tb[IFLA_BRPORT_MODE]) | |
74 | print_onoff(f, "hairpin", | |
75 | rta_getattr_u8(tb[IFLA_BRPORT_MODE])); | |
76 | ||
77 | if (tb[IFLA_BRPORT_GUARD]) | |
78 | print_onoff(f, "guard", | |
79 | rta_getattr_u8(tb[IFLA_BRPORT_GUARD])); | |
80 | ||
81 | if (tb[IFLA_BRPORT_PROTECT]) | |
82 | print_onoff(f, "root_block", | |
83 | rta_getattr_u8(tb[IFLA_BRPORT_PROTECT])); | |
84 | ||
85 | if (tb[IFLA_BRPORT_FAST_LEAVE]) | |
86 | print_onoff(f, "fastleave", | |
87 | rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE])); | |
88 | ||
89 | if (tb[IFLA_BRPORT_LEARNING]) | |
90 | print_onoff(f, "learning", | |
91 | rta_getattr_u8(tb[IFLA_BRPORT_LEARNING])); | |
92 | ||
93 | if (tb[IFLA_BRPORT_UNICAST_FLOOD]) | |
94 | print_onoff(f, "flood", | |
95 | rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD])); | |
96 | } | |
97 | ||
98 | static void bridge_slave_parse_on_off(char *arg_name, char *arg_val, | |
99 | struct nlmsghdr *n, int type) | |
100 | { | |
101 | __u8 val; | |
102 | ||
103 | if (strcmp(arg_val, "on") == 0) | |
104 | val = 1; | |
105 | else if (strcmp(arg_val, "off") == 0) | |
106 | val = 0; | |
107 | else | |
108 | invarg("should be \"on\" or \"off\"", arg_name); | |
109 | ||
110 | addattr8(n, 1024, type, val); | |
111 | } | |
112 | ||
113 | static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv, | |
114 | struct nlmsghdr *n) | |
115 | { | |
116 | __u8 state; | |
117 | __u16 priority; | |
118 | __u32 cost; | |
119 | ||
120 | while (argc > 0) { | |
121 | if (matches(*argv, "state") == 0) { | |
122 | NEXT_ARG(); | |
123 | if (get_u8(&state, *argv, 0)) | |
124 | invarg("state is invalid", *argv); | |
125 | addattr8(n, 1024, IFLA_BRPORT_STATE, state); | |
126 | } else if (matches(*argv, "priority") == 0) { | |
127 | NEXT_ARG(); | |
128 | if (get_u16(&priority, *argv, 0)) | |
129 | invarg("priority is invalid", *argv); | |
130 | addattr16(n, 1024, IFLA_BRPORT_PRIORITY, priority); | |
131 | } else if (matches(*argv, "cost") == 0) { | |
132 | NEXT_ARG(); | |
133 | if (get_u32(&cost, *argv, 0)) | |
134 | invarg("cost is invalid", *argv); | |
135 | addattr32(n, 1024, IFLA_BRPORT_COST, cost); | |
136 | } else if (matches(*argv, "hairpin") == 0) { | |
137 | NEXT_ARG(); | |
138 | bridge_slave_parse_on_off("hairpin", *argv, n, | |
139 | IFLA_BRPORT_MODE); | |
140 | } else if (matches(*argv, "guard") == 0) { | |
141 | NEXT_ARG(); | |
142 | bridge_slave_parse_on_off("guard", *argv, n, | |
143 | IFLA_BRPORT_GUARD); | |
144 | } else if (matches(*argv, "root_block") == 0) { | |
145 | NEXT_ARG(); | |
146 | bridge_slave_parse_on_off("root_block", *argv, n, | |
147 | IFLA_BRPORT_PROTECT); | |
148 | } else if (matches(*argv, "fastleave") == 0) { | |
149 | NEXT_ARG(); | |
150 | bridge_slave_parse_on_off("fastleave", *argv, n, | |
151 | IFLA_BRPORT_FAST_LEAVE); | |
152 | } else if (matches(*argv, "learning") == 0) { | |
153 | NEXT_ARG(); | |
154 | bridge_slave_parse_on_off("learning", *argv, n, | |
155 | IFLA_BRPORT_LEARNING); | |
156 | } else if (matches(*argv, "flood") == 0) { | |
157 | NEXT_ARG(); | |
158 | bridge_slave_parse_on_off("flood", *argv, n, | |
159 | IFLA_BRPORT_UNICAST_FLOOD); | |
160 | } else if (matches(*argv, "help") == 0) { | |
161 | explain(); | |
162 | return -1; | |
163 | } else { | |
164 | fprintf(stderr, "bridge_slave: unknown option \"%s\"?\n", | |
165 | *argv); | |
166 | explain(); | |
167 | return -1; | |
168 | } | |
169 | argc--, argv++; | |
170 | } | |
171 | ||
172 | return 0; | |
173 | } | |
174 | ||
175 | struct link_util bridge_slave_link_util = { | |
176 | .id = "bridge", | |
177 | .maxattr = IFLA_BRPORT_MAX, | |
178 | .print_opt = bridge_slave_print_opt, | |
179 | .parse_opt = bridge_slave_parse_opt, | |
180 | .slave = true, | |
181 | }; |