/src/systemd/src/network/netdev/bond.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | | |
3 | | #include "sd-netlink.h" |
4 | | |
5 | | #include "alloc-util.h" |
6 | | #include "bond.h" |
7 | | #include "conf-parser.h" |
8 | | #include "ether-addr-util.h" |
9 | | #include "extract-word.h" |
10 | | #include "netlink-util.h" |
11 | | #include "networkd-manager.h" |
12 | | #include "string-table.h" |
13 | | #include "string-util.h" |
14 | | |
15 | | /* |
16 | | * Number of seconds between instances where the bonding |
17 | | * driver sends learning packets to each slaves peer switch |
18 | | */ |
19 | 1.15k | #define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC) |
20 | 0 | #define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC) |
21 | | |
22 | | /* Number of IGMP membership reports to be issued after |
23 | | * a failover event. |
24 | | */ |
25 | | #define RESEND_IGMP_MIN 0 |
26 | 297 | #define RESEND_IGMP_MAX 255 |
27 | 1.15k | #define RESEND_IGMP_DEFAULT 1 |
28 | | |
29 | | /* |
30 | | * Number of packets to transmit through a slave before |
31 | | * moving to the next one. |
32 | | */ |
33 | | #define PACKETS_PER_SLAVE_MIN 0 |
34 | 594 | #define PACKETS_PER_SLAVE_MAX 65535 |
35 | 1.15k | #define PACKETS_PER_SLAVE_DEFAULT 1 |
36 | | |
37 | | /* |
38 | | * Number of peer notifications (gratuitous ARPs and |
39 | | * unsolicited IPv6 Neighbor Advertisements) to be issued after a |
40 | | * failover event. |
41 | | */ |
42 | | #define GRATUITOUS_ARP_MIN 0 |
43 | 297 | #define GRATUITOUS_ARP_MAX 255 |
44 | 1.15k | #define GRATUITOUS_ARP_DEFAULT 1 |
45 | | |
46 | | static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = { |
47 | | [NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr", |
48 | | [NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup", |
49 | | [NETDEV_BOND_MODE_BALANCE_XOR] = "balance-xor", |
50 | | [NETDEV_BOND_MODE_BROADCAST] = "broadcast", |
51 | | [NETDEV_BOND_MODE_802_3AD] = "802.3ad", |
52 | | [NETDEV_BOND_MODE_BALANCE_TLB] = "balance-tlb", |
53 | | [NETDEV_BOND_MODE_BALANCE_ALB] = "balance-alb", |
54 | | }; |
55 | | |
56 | | DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode); |
57 | | DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode, "Failed to parse bond mode"); |
58 | | |
59 | | static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = { |
60 | | [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2", |
61 | | [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4", |
62 | | [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23] = "layer2+3", |
63 | | [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23] = "encap2+3", |
64 | | [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34] = "encap3+4", |
65 | | }; |
66 | | |
67 | | DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy); |
68 | | DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy, |
69 | | bond_xmit_hash_policy, |
70 | | BondXmitHashPolicy, |
71 | | "Failed to parse bond transmit hash policy") |
72 | | |
73 | | static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = { |
74 | | [NETDEV_BOND_LACP_RATE_SLOW] = "slow", |
75 | | [NETDEV_BOND_LACP_RATE_FAST] = "fast", |
76 | | }; |
77 | | |
78 | | DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate); |
79 | | DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate") |
80 | | |
81 | | static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = { |
82 | | [NETDEV_BOND_AD_SELECT_STABLE] = "stable", |
83 | | [NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth", |
84 | | [NETDEV_BOND_AD_SELECT_COUNT] = "count", |
85 | | }; |
86 | | |
87 | | DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect); |
88 | | DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select, bond_ad_select, BondAdSelect, "Failed to parse bond AD select"); |
89 | | |
90 | | static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = { |
91 | | [NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none", |
92 | | [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active", |
93 | | [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow", |
94 | | }; |
95 | | |
96 | | DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac); |
97 | | DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac, bond_fail_over_mac, BondFailOverMac, "Failed to parse bond fail over MAC"); |
98 | | |
99 | | static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = { |
100 | | [NETDEV_BOND_ARP_VALIDATE_NONE] = "none", |
101 | | [NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active", |
102 | | [NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup", |
103 | | [NETDEV_BOND_ARP_VALIDATE_ALL]= "all", |
104 | | }; |
105 | | |
106 | | DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate); |
107 | | DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate, bond_arp_validate, BondArpValidate, "Failed to parse bond arp validate"); |
108 | | |
109 | | static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = { |
110 | | [NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any", |
111 | | [NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all", |
112 | | }; |
113 | | |
114 | | DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets); |
115 | | DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets, "Failed to parse bond Arp all targets"); |
116 | | |
117 | | static const char *const bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = { |
118 | | [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always", |
119 | | [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better", |
120 | | [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure", |
121 | | }; |
122 | | |
123 | | DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect); |
124 | | DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect, "Failed to parse bond primary reselect"); |
125 | | |
126 | 297 | static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { |
127 | 297 | Bond *b; |
128 | 297 | int r; |
129 | 297 | |
130 | 297 | assert(netdev); |
131 | 297 | assert(!link); |
132 | 297 | assert(m); |
133 | 297 | |
134 | 297 | b = BOND(netdev); |
135 | 297 | |
136 | 297 | assert(b); |
137 | 297 | |
138 | 297 | if (b->mode != _NETDEV_BOND_MODE_INVALID) { |
139 | 7 | r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE, b->mode); |
140 | 7 | if (r < 0) |
141 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MODE attribute: %m"); |
142 | 297 | } |
143 | 297 | |
144 | 297 | if (b->xmit_hash_policy != _NETDEV_BOND_XMIT_HASH_POLICY_INVALID) { |
145 | 2 | r = sd_netlink_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY, b->xmit_hash_policy); |
146 | 2 | if (r < 0) |
147 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m"); |
148 | 297 | } |
149 | 297 | |
150 | 297 | if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID && |
151 | 297 | b->mode == NETDEV_BOND_MODE_802_3AD) { |
152 | 2 | r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate); |
153 | 2 | if (r < 0) |
154 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m"); |
155 | 297 | } |
156 | 297 | |
157 | 297 | if (b->miimon != 0) { |
158 | 46 | r = sd_netlink_message_append_u32(m, IFLA_BOND_MIIMON, b->miimon / USEC_PER_MSEC); |
159 | 46 | if (r < 0) |
160 | 46 | log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_BOND_MIIMON attribute: %m"); |
161 | 46 | } |
162 | 297 | |
163 | 297 | if (b->downdelay != 0) { |
164 | 42 | r = sd_netlink_message_append_u32(m, IFLA_BOND_DOWNDELAY, b->downdelay / USEC_PER_MSEC); |
165 | 42 | if (r < 0) |
166 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_DOWNDELAY attribute: %m"); |
167 | 297 | } |
168 | 297 | |
169 | 297 | if (b->updelay != 0) { |
170 | 74 | r = sd_netlink_message_append_u32(m, IFLA_BOND_UPDELAY, b->updelay / USEC_PER_MSEC); |
171 | 74 | if (r < 0) |
172 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_UPDELAY attribute: %m"); |
173 | 297 | } |
174 | 297 | |
175 | 297 | if (b->arp_interval != 0) { |
176 | 0 | r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_INTERVAL, b->arp_interval / USEC_PER_MSEC); |
177 | 0 | if (r < 0) |
178 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m"); |
179 | 0 | |
180 | 0 | if (b->lp_interval >= LEARNING_PACKETS_INTERVAL_MIN_SEC && |
181 | 0 | b->lp_interval <= LEARNING_PACKETS_INTERVAL_MAX_SEC) { |
182 | 0 | r = sd_netlink_message_append_u32(m, IFLA_BOND_LP_INTERVAL, b->lp_interval / USEC_PER_SEC); |
183 | 0 | if (r < 0) |
184 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m"); |
185 | 297 | } |
186 | 0 | } |
187 | 297 | |
188 | 297 | if (b->ad_select != _NETDEV_BOND_AD_SELECT_INVALID && |
189 | 297 | b->mode == NETDEV_BOND_MODE_802_3AD) { |
190 | 0 | r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_SELECT, b->ad_select); |
191 | 0 | if (r < 0) |
192 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_SELECT attribute: %m"); |
193 | 297 | } |
194 | 297 | |
195 | 297 | if (b->fail_over_mac != _NETDEV_BOND_FAIL_OVER_MAC_INVALID && |
196 | 297 | b->mode == NETDEV_BOND_MODE_ACTIVE_BACKUP) { |
197 | 0 | r = sd_netlink_message_append_u8(m, IFLA_BOND_FAIL_OVER_MAC, b->fail_over_mac); |
198 | 0 | if (r < 0) |
199 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %m"); |
200 | 297 | } |
201 | 297 | |
202 | 297 | if (b->arp_validate != _NETDEV_BOND_ARP_VALIDATE_INVALID) { |
203 | 0 | r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_VALIDATE, b->arp_validate); |
204 | 0 | if (r < 0) |
205 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m"); |
206 | 297 | } |
207 | 297 | |
208 | 297 | if (b->arp_all_targets != _NETDEV_BOND_ARP_ALL_TARGETS_INVALID) { |
209 | 0 | r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->arp_all_targets); |
210 | 0 | if (r < 0) |
211 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m"); |
212 | 297 | } |
213 | 297 | |
214 | 297 | if (b->primary_reselect != _NETDEV_BOND_PRIMARY_RESELECT_INVALID) { |
215 | 0 | r = sd_netlink_message_append_u8(m, IFLA_BOND_PRIMARY_RESELECT, b->primary_reselect); |
216 | 0 | if (r < 0) |
217 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_PRIMARY_RESELECT attribute: %m"); |
218 | 297 | } |
219 | 297 | |
220 | 297 | if (b->resend_igmp <= RESEND_IGMP_MAX) { |
221 | 274 | r = sd_netlink_message_append_u32(m, IFLA_BOND_RESEND_IGMP, b->resend_igmp); |
222 | 274 | if (r < 0) |
223 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_RESEND_IGMP attribute: %m"); |
224 | 297 | } |
225 | 297 | |
226 | 297 | if (b->packets_per_slave <= PACKETS_PER_SLAVE_MAX && |
227 | 297 | b->mode == NETDEV_BOND_MODE_BALANCE_RR) { |
228 | 0 | r = sd_netlink_message_append_u32(m, IFLA_BOND_PACKETS_PER_SLAVE, b->packets_per_slave); |
229 | 0 | if (r < 0) |
230 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m"); |
231 | 297 | } |
232 | 297 | |
233 | 297 | if (b->num_grat_arp <= GRATUITOUS_ARP_MAX) { |
234 | 297 | r = sd_netlink_message_append_u8(m, IFLA_BOND_NUM_PEER_NOTIF, b->num_grat_arp); |
235 | 297 | if (r < 0) |
236 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m"); |
237 | 297 | } |
238 | 297 | |
239 | 297 | if (b->min_links != 0) { |
240 | 38 | r = sd_netlink_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links); |
241 | 38 | if (r < 0) |
242 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MIN_LINKS attribute: %m"); |
243 | 297 | } |
244 | 297 | |
245 | 297 | if (b->ad_actor_sys_prio != 0) { |
246 | 16 | r = sd_netlink_message_append_u16(m, IFLA_BOND_AD_ACTOR_SYS_PRIO, b->ad_actor_sys_prio); |
247 | 16 | if (r < 0) |
248 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_ACTOR_SYS_PRIO attribute: %m"); |
249 | 297 | } |
250 | 297 | |
251 | 297 | if (b->ad_user_port_key != 0) { |
252 | 9 | r = sd_netlink_message_append_u16(m, IFLA_BOND_AD_USER_PORT_KEY, b->ad_user_port_key); |
253 | 9 | if (r < 0) |
254 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_USER_PORT_KEY attribute: %m"); |
255 | 297 | } |
256 | 297 | |
257 | 297 | if (!ether_addr_is_null(&b->ad_actor_system)) { |
258 | 4 | r = sd_netlink_message_append_ether_addr(m, IFLA_BOND_AD_ACTOR_SYSTEM, &b->ad_actor_system); |
259 | 4 | if (r < 0) |
260 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_ACTOR_SYSTEM attribute: %m"); |
261 | 297 | } |
262 | 297 | |
263 | 297 | r = sd_netlink_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active); |
264 | 297 | if (r < 0) |
265 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m"); |
266 | 297 | |
267 | 297 | if (b->tlb_dynamic_lb >= 0) { |
268 | 0 | r = sd_netlink_message_append_u8(m, IFLA_BOND_TLB_DYNAMIC_LB, b->tlb_dynamic_lb); |
269 | 0 | if (r < 0) |
270 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_TLB_DYNAMIC_LB attribute: %m"); |
271 | 297 | } |
272 | 297 | |
273 | 297 | if (b->arp_interval > 0 && !ordered_set_isempty(b->arp_ip_targets)) { |
274 | 0 | Iterator i; |
275 | 0 | void *val; |
276 | 0 | int n = 0; |
277 | 0 |
|
278 | 0 | r = sd_netlink_message_open_container(m, IFLA_BOND_ARP_IP_TARGET); |
279 | 0 | if (r < 0) |
280 | 0 | return log_netdev_error_errno(netdev, r, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m"); |
281 | 0 | |
282 | 0 | ORDERED_SET_FOREACH(val, b->arp_ip_targets, i) { |
283 | 0 | r = sd_netlink_message_append_u32(m, n++, PTR_TO_UINT32(val)); |
284 | 0 | if (r < 0) |
285 | 0 | return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m"); |
286 | 0 | } |
287 | 0 |
|
288 | 0 | r = sd_netlink_message_close_container(m); |
289 | 0 | if (r < 0) |
290 | 0 | return log_netdev_error_errno(netdev, r, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m"); |
291 | 297 | } |
292 | 297 | |
293 | 297 | return 0; |
294 | 297 | } |
295 | | |
296 | 0 | static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { |
297 | 0 | int r; |
298 | 0 |
|
299 | 0 | assert(m); |
300 | 0 | assert(link); |
301 | 0 | assert(link->ifname); |
302 | 0 |
|
303 | 0 | if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) |
304 | 0 | return 1; |
305 | 0 | |
306 | 0 | r = sd_netlink_message_get_errno(m); |
307 | 0 | if (r < 0) { |
308 | 0 | log_link_warning_errno(link, r, "Could not set bonding interface: %m"); |
309 | 0 | return 1; |
310 | 0 | } |
311 | 0 |
|
312 | 0 | return 1; |
313 | 0 | } |
314 | | |
315 | 0 | int link_set_bond(Link *link) { |
316 | 0 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; |
317 | 0 | int r; |
318 | 0 |
|
319 | 0 | assert(link); |
320 | 0 | assert(link->network); |
321 | 0 |
|
322 | 0 | r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_NEWLINK, link->network->bond->ifindex); |
323 | 0 | if (r < 0) |
324 | 0 | return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); |
325 | 0 | |
326 | 0 | r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK); |
327 | 0 | if (r < 0) |
328 | 0 | return log_link_error_errno(link, r, "Could not set netlink flags: %m"); |
329 | 0 | |
330 | 0 | r = sd_netlink_message_open_container(req, IFLA_LINKINFO); |
331 | 0 | if (r < 0) |
332 | 0 | return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m"); |
333 | 0 | |
334 | 0 | r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, "bond"); |
335 | 0 | if (r < 0) |
336 | 0 | return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m"); |
337 | 0 | |
338 | 0 | if (link->network->active_slave) { |
339 | 0 | r = sd_netlink_message_append_u32(req, IFLA_BOND_ACTIVE_SLAVE, link->ifindex); |
340 | 0 | if (r < 0) |
341 | 0 | return log_link_error_errno(link, r, "Could not append IFLA_BOND_ACTIVE_SLAVE attribute: %m"); |
342 | 0 | } |
343 | 0 | |
344 | 0 | if (link->network->primary_slave) { |
345 | 0 | r = sd_netlink_message_append_u32(req, IFLA_BOND_PRIMARY, link->ifindex); |
346 | 0 | if (r < 0) |
347 | 0 | return log_link_error_errno(link, r, "Could not append IFLA_BOND_PRIMARY attribute: %m"); |
348 | 0 | } |
349 | 0 | |
350 | 0 | r = sd_netlink_message_close_container(req); |
351 | 0 | if (r < 0) |
352 | 0 | return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m"); |
353 | 0 | |
354 | 0 | r = sd_netlink_message_close_container(req); |
355 | 0 | if (r < 0) |
356 | 0 | return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m"); |
357 | 0 | |
358 | 0 | r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_bond_handler, |
359 | 0 | link_netlink_destroy_callback, link); |
360 | 0 | if (r < 0) |
361 | 0 | return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); |
362 | 0 | |
363 | 0 | link_ref(link); |
364 | 0 |
|
365 | 0 | return r; |
366 | 0 | } |
367 | | |
368 | | int config_parse_arp_ip_target_address( |
369 | | const char *unit, |
370 | | const char *filename, |
371 | | unsigned line, |
372 | | const char *section, |
373 | | unsigned section_line, |
374 | | const char *lvalue, |
375 | | int ltype, |
376 | | const char *rvalue, |
377 | | void *data, |
378 | 0 | void *userdata) { |
379 | 0 |
|
380 | 0 | Bond *b = userdata; |
381 | 0 | int r; |
382 | 0 |
|
383 | 0 | assert(filename); |
384 | 0 | assert(lvalue); |
385 | 0 | assert(rvalue); |
386 | 0 | assert(data); |
387 | 0 |
|
388 | 0 | if (isempty(rvalue)) { |
389 | 0 | b->arp_ip_targets = ordered_set_free(b->arp_ip_targets); |
390 | 0 | return 0; |
391 | 0 | } |
392 | 0 | |
393 | 0 | for (;;) { |
394 | 0 | _cleanup_free_ char *n = NULL; |
395 | 0 | union in_addr_union ip; |
396 | 0 |
|
397 | 0 | r = extract_first_word(&rvalue, &n, NULL, 0); |
398 | 0 | if (r < 0) { |
399 | 0 | log_syntax(unit, LOG_ERR, filename, line, r, |
400 | 0 | "Failed to parse Bond ARP ip target address, ignoring assignment: %s", |
401 | 0 | rvalue); |
402 | 0 | return 0; |
403 | 0 | } |
404 | 0 | if (r == 0) |
405 | 0 | return 0; |
406 | 0 | |
407 | 0 | r = in_addr_from_string(AF_INET, n, &ip); |
408 | 0 | if (r < 0) { |
409 | 0 | log_syntax(unit, LOG_ERR, filename, line, r, |
410 | 0 | "Bond ARP ip target address is invalid, ignoring assignment: %s", n); |
411 | 0 | continue; |
412 | 0 | } |
413 | 0 |
|
414 | 0 | r = ordered_set_ensure_allocated(&b->arp_ip_targets, NULL); |
415 | 0 | if (r < 0) |
416 | 0 | return log_oom(); |
417 | 0 | |
418 | 0 | if (ordered_set_size(b->arp_ip_targets) >= NETDEV_BOND_ARP_TARGETS_MAX) { |
419 | 0 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
420 | 0 | "Too many ARP ip targets are specified. The maximum number is %d. Ignoring assignment: %s", |
421 | 0 | NETDEV_BOND_ARP_TARGETS_MAX, n); |
422 | 0 | continue; |
423 | 0 | } |
424 | 0 |
|
425 | 0 | r = ordered_set_put(b->arp_ip_targets, UINT32_TO_PTR(ip.in.s_addr)); |
426 | 0 | if (r == -EEXIST) |
427 | 0 | log_syntax(unit, LOG_WARNING, filename, line, r, |
428 | 0 | "Bond ARP ip target address is duplicated, ignoring assignment: %s", n); |
429 | 0 | if (r < 0) |
430 | 0 | log_syntax(unit, LOG_ERR, filename, line, r, |
431 | 0 | "Failed to store bond ARP ip target address '%s', ignoring assignment: %m", n); |
432 | 0 | } |
433 | 0 | } |
434 | | |
435 | | int config_parse_ad_actor_sys_prio( |
436 | | const char *unit, |
437 | | const char *filename, |
438 | | unsigned line, |
439 | | const char *section, |
440 | | unsigned section_line, |
441 | | const char *lvalue, |
442 | | int ltype, |
443 | | const char *rvalue, |
444 | | void *data, |
445 | 744 | void *userdata) { |
446 | 744 | Bond *b = userdata; |
447 | 744 | uint16_t v; |
448 | 744 | int r; |
449 | 744 | |
450 | 744 | assert(filename); |
451 | 744 | assert(lvalue); |
452 | 744 | assert(rvalue); |
453 | 744 | assert(data); |
454 | 744 | |
455 | 744 | r = safe_atou16(rvalue, &v); |
456 | 744 | if (r < 0) { |
457 | 201 | log_syntax(unit, LOG_ERR, filename, line, r, |
458 | 201 | "Failed to parse actor system priority '%s', ignoring: %m", rvalue); |
459 | 201 | return 0; |
460 | 201 | } |
461 | 543 | |
462 | 543 | if (v == 0) { |
463 | 196 | log_syntax(unit, LOG_ERR, filename, line, 0, |
464 | 196 | "Failed to parse actor system priority '%s'. Range is [1,65535], ignoring.", |
465 | 196 | rvalue); |
466 | 196 | return 0; |
467 | 196 | } |
468 | 347 | |
469 | 347 | b->ad_actor_sys_prio = v; |
470 | 347 | |
471 | 347 | return 0; |
472 | 347 | } |
473 | | |
474 | | int config_parse_ad_user_port_key( |
475 | | const char *unit, |
476 | | const char *filename, |
477 | | unsigned line, |
478 | | const char *section, |
479 | | unsigned section_line, |
480 | | const char *lvalue, |
481 | | int ltype, |
482 | | const char *rvalue, |
483 | | void *data, |
484 | 709 | void *userdata) { |
485 | 709 | Bond *b = userdata; |
486 | 709 | uint16_t v; |
487 | 709 | int r; |
488 | 709 | |
489 | 709 | assert(filename); |
490 | 709 | assert(lvalue); |
491 | 709 | assert(rvalue); |
492 | 709 | assert(data); |
493 | 709 | |
494 | 709 | r = safe_atou16(rvalue, &v); |
495 | 709 | if (r < 0) { |
496 | 237 | log_syntax(unit, LOG_ERR, filename, line, r, |
497 | 237 | "Failed to parse user port key '%s', ignoring: %m", rvalue); |
498 | 237 | return 0; |
499 | 237 | } |
500 | 472 | |
501 | 472 | if (v > 1023) { |
502 | 213 | log_syntax(unit, LOG_ERR, filename, line, 0, |
503 | 213 | "Failed to parse user port key '%s'. Range is [0…1023], ignoring.", rvalue); |
504 | 213 | return 0; |
505 | 213 | } |
506 | 259 | |
507 | 259 | b->ad_user_port_key = v; |
508 | 259 | |
509 | 259 | return 0; |
510 | 259 | } |
511 | | |
512 | | int config_parse_ad_actor_system( |
513 | | const char *unit, |
514 | | const char *filename, |
515 | | unsigned line, |
516 | | const char *section, |
517 | | unsigned section_line, |
518 | | const char *lvalue, |
519 | | int ltype, |
520 | | const char *rvalue, |
521 | | void *data, |
522 | 872 | void *userdata) { |
523 | 872 | Bond *b = userdata; |
524 | 872 | struct ether_addr n; |
525 | 872 | int r; |
526 | 872 | |
527 | 872 | assert(filename); |
528 | 872 | assert(lvalue); |
529 | 872 | assert(rvalue); |
530 | 872 | assert(data); |
531 | 872 | |
532 | 872 | r = ether_addr_from_string(rvalue, &n); |
533 | 872 | if (r < 0) { |
534 | 252 | log_syntax(unit, LOG_ERR, filename, line, r, |
535 | 252 | "Not a valid MAC address %s. Ignoring assignment: %m", |
536 | 252 | rvalue); |
537 | 252 | return 0; |
538 | 252 | } |
539 | 620 | if (ether_addr_is_null(&n) || (n.ether_addr_octet[0] & 0x01)) { |
540 | 391 | log_syntax(unit, LOG_ERR, filename, line, 0, |
541 | 391 | "Not a valid MAC address %s, can not be null or multicast. Ignoring assignment.", |
542 | 391 | rvalue); |
543 | 391 | return 0; |
544 | 391 | } |
545 | 229 | |
546 | 229 | b->ad_actor_system = n; |
547 | 229 | |
548 | 229 | return 0; |
549 | 229 | } |
550 | | |
551 | 1.15k | static void bond_done(NetDev *netdev) { |
552 | 1.15k | Bond *b; |
553 | 1.15k | |
554 | 1.15k | assert(netdev); |
555 | 1.15k | b = BOND(netdev); |
556 | 1.15k | assert(b); |
557 | 1.15k | |
558 | 1.15k | ordered_set_free(b->arp_ip_targets); |
559 | 1.15k | } |
560 | | |
561 | 1.15k | static void bond_init(NetDev *netdev) { |
562 | 1.15k | Bond *b; |
563 | 1.15k | |
564 | 1.15k | assert(netdev); |
565 | 1.15k | |
566 | 1.15k | b = BOND(netdev); |
567 | 1.15k | |
568 | 1.15k | assert(b); |
569 | 1.15k | |
570 | 1.15k | b->mode = _NETDEV_BOND_MODE_INVALID; |
571 | 1.15k | b->xmit_hash_policy = _NETDEV_BOND_XMIT_HASH_POLICY_INVALID; |
572 | 1.15k | b->lacp_rate = _NETDEV_BOND_LACP_RATE_INVALID; |
573 | 1.15k | b->ad_select = _NETDEV_BOND_AD_SELECT_INVALID; |
574 | 1.15k | b->fail_over_mac = _NETDEV_BOND_FAIL_OVER_MAC_INVALID; |
575 | 1.15k | b->arp_validate = _NETDEV_BOND_ARP_VALIDATE_INVALID; |
576 | 1.15k | b->arp_all_targets = _NETDEV_BOND_ARP_ALL_TARGETS_INVALID; |
577 | 1.15k | b->primary_reselect = _NETDEV_BOND_PRIMARY_RESELECT_INVALID; |
578 | 1.15k | |
579 | 1.15k | b->all_slaves_active = false; |
580 | 1.15k | b->tlb_dynamic_lb = -1; |
581 | 1.15k | |
582 | 1.15k | b->resend_igmp = RESEND_IGMP_DEFAULT; |
583 | 1.15k | b->packets_per_slave = PACKETS_PER_SLAVE_DEFAULT; |
584 | 1.15k | b->num_grat_arp = GRATUITOUS_ARP_DEFAULT; |
585 | 1.15k | b->lp_interval = LEARNING_PACKETS_INTERVAL_MIN_SEC; |
586 | 1.15k | } |
587 | | |
588 | | const NetDevVTable bond_vtable = { |
589 | | .object_size = sizeof(Bond), |
590 | | .init = bond_init, |
591 | | .done = bond_done, |
592 | | .sections = "Match\0NetDev\0Bond\0", |
593 | | .fill_message_create = netdev_bond_fill_message_create, |
594 | | .create_type = NETDEV_CREATE_MASTER, |
595 | | .generate_mac = true, |
596 | | }; |