]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-netdev-bond.c
tree-wide: drop {} from one-line if blocks
[thirdparty/systemd.git] / src / network / networkd-netdev-bond.c
CommitLineData
fe8ac65b
SS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Tom Gundersen <teg@jklm.no>
7 Copyright 2014 Susant Sahani
8
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21***/
22
23#include <netinet/ether.h>
b621239e 24#include <linux/if_bonding.h>
fe8ac65b
SS
25
26#include "conf-parser.h"
1c4baffc 27#include "sd-netlink.h"
3be1d7e0 28#include "networkd-netdev-bond.h"
fe8ac65b
SS
29#include "missing.h"
30
81bd37a8
SS
31/*
32 * Number of seconds between instances where the bonding
33 * driver sends learning packets to each slaves peer switch
34 */
35#define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
36#define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
37
38/* Number of IGMP membership reports to be issued after
39 * a failover event.
40 */
41#define RESEND_IGMP_MIN 0
42#define RESEND_IGMP_MAX 255
43#define RESEND_IGMP_DEFAULT 1
44
45/*
46 * Number of packets to transmit through a slave before
47 * moving to the next one.
48 */
49#define PACKETS_PER_SLAVE_MIN 0
50#define PACKETS_PER_SLAVE_MAX 65535
51#define PACKETS_PER_SLAVE_DEFAULT 1
52
53/*
54 * Number of peer notifications (gratuitous ARPs and
55 * unsolicited IPv6 Neighbor Advertisements) to be issued after a
56 * failover event.
57 */
58#define GRATUITOUS_ARP_MIN 0
59#define GRATUITOUS_ARP_MAX 255
60#define GRATUITOUS_ARP_DEFAULT 1
61
fe8ac65b
SS
62static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
63 [NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr",
64 [NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup",
65 [NETDEV_BOND_MODE_BALANCE_XOR] = "balance-xor",
66 [NETDEV_BOND_MODE_BROADCAST] = "broadcast",
67 [NETDEV_BOND_MODE_802_3AD] = "802.3ad",
68 [NETDEV_BOND_MODE_BALANCE_TLB] = "balance-tlb",
69 [NETDEV_BOND_MODE_BALANCE_ALB] = "balance-alb",
70};
71
72DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
73DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode, "Failed to parse bond mode");
74
227cdf2c
SS
75static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = {
76 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2",
77 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4",
78 [NETDEV_BOND_XMIT_HASH_POLICY_LAYER23] = "layer2+3",
79 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23] = "encap2+3",
80 [NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34] = "encap3+4",
81};
82
83DEFINE_STRING_TABLE_LOOKUP(bond_xmit_hash_policy, BondXmitHashPolicy);
84DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_xmit_hash_policy,
85 bond_xmit_hash_policy,
86 BondXmitHashPolicy,
87 "Failed to parse bond transmit hash policy")
88
fb1021a2
SS
89static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = {
90 [NETDEV_BOND_LACP_RATE_SLOW] = "slow",
91 [NETDEV_BOND_LACP_RATE_FAST] = "fast",
92};
93
94DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
95DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate")
96
81bd37a8
SS
97static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = {
98 [NETDEV_BOND_AD_SELECT_STABLE] = "stable",
99 [NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth",
100 [NETDEV_BOND_AD_SELECT_COUNT] = "count",
101};
102
103DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
104DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select, bond_ad_select, BondAdSelect, "Failed to parse bond AD select");
105
106static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = {
107 [NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none",
108 [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active",
109 [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow",
110};
111
112DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
113DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac, bond_fail_over_mac, BondFailOverMac, "Failed to parse bond fail over MAC");
114
115static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = {
116 [NETDEV_BOND_ARP_VALIDATE_NONE] = "none",
117 [NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active",
118 [NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup",
119 [NETDEV_BOND_ARP_VALIDATE_ALL]= "all",
120};
121
122DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
123DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate, bond_arp_validate, BondArpValidate, "Failed to parse bond arp validate");
124
125static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = {
126 [NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any",
127 [NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all",
128};
129
130DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
131DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets, "Failed to parse bond Arp all targets");
132
133static const char *bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
134 [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
135 [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
136 [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
137};
138
139DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
140DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect, "Failed to parse bond primary reselect");
141
b621239e
TG
142static uint8_t bond_mode_to_kernel(BondMode mode) {
143 switch (mode) {
144 case NETDEV_BOND_MODE_BALANCE_RR:
145 return BOND_MODE_ROUNDROBIN;
146 case NETDEV_BOND_MODE_ACTIVE_BACKUP:
147 return BOND_MODE_ACTIVEBACKUP;
148 case NETDEV_BOND_MODE_BALANCE_XOR:
149 return BOND_MODE_XOR;
150 case NETDEV_BOND_MODE_BROADCAST:
151 return BOND_MODE_BROADCAST;
152 case NETDEV_BOND_MODE_802_3AD:
153 return BOND_MODE_8023AD;
154 case NETDEV_BOND_MODE_BALANCE_TLB:
155 return BOND_MODE_TLB;
156 case NETDEV_BOND_MODE_BALANCE_ALB:
157 return BOND_MODE_ALB;
158 default:
159 return (uint8_t) -1;
160 }
161}
162
227cdf2c
SS
163static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) {
164 switch (policy) {
165 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER2:
166 return BOND_XMIT_POLICY_LAYER2;
167 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER34:
168 return BOND_XMIT_POLICY_LAYER34;
169 case NETDEV_BOND_XMIT_HASH_POLICY_LAYER23:
170 return BOND_XMIT_POLICY_LAYER23;
171 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23:
172 return BOND_XMIT_POLICY_ENCAP23;
173 case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34:
174 return BOND_XMIT_POLICY_ENCAP34;
175 default:
176 return (uint8_t) -1;
177 }
178}
179
1c4baffc 180static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
aa9f1140 181 Bond *b = BOND(netdev);
81bd37a8
SS
182 ArpIpTarget *target = NULL;
183 int r, i = 0;
fe8ac65b 184
aa9f1140
TG
185 assert(netdev);
186 assert(!link);
187 assert(b);
fe8ac65b
SS
188 assert(m);
189
aa9f1140 190 if (b->mode != _NETDEV_BOND_MODE_INVALID) {
1c4baffc 191 r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE,
aa9f1140 192 bond_mode_to_kernel(b->mode));
a668086e
SS
193 if (r < 0)
194 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MODE attribute: %m");
fe8ac65b
SS
195 }
196
227cdf2c 197 if (b->xmit_hash_policy != _NETDEV_BOND_XMIT_HASH_POLICY_INVALID) {
1c4baffc 198 r = sd_netlink_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY,
227cdf2c 199 bond_xmit_hash_policy_to_kernel(b->xmit_hash_policy));
a668086e
SS
200 if (r < 0)
201 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
227cdf2c
SS
202 }
203
fb1021a2
SS
204 if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID &&
205 b->mode == NETDEV_BOND_MODE_802_3AD) {
1c4baffc 206 r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate );
ece174c5 207 if (r < 0)
a668086e 208 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
fb1021a2
SS
209 }
210
d9c52fa0 211 if (b->miimon != 0) {
1c4baffc 212 r = sd_netlink_message_append_u32(m, IFLA_BOND_MIIMON, b->miimon / USEC_PER_MSEC);
a668086e
SS
213 if (r < 0)
214 log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_BOND_MIIMON attribute: %m");
d9c52fa0
SS
215 }
216
217 if (b->downdelay != 0) {
1c4baffc 218 r = sd_netlink_message_append_u32(m, IFLA_BOND_DOWNDELAY, b->downdelay / USEC_PER_MSEC);
a668086e
SS
219 if (r < 0)
220 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_DOWNDELAY attribute: %m");
d9c52fa0
SS
221 }
222
223 if (b->updelay != 0) {
1c4baffc 224 r = sd_netlink_message_append_u32(m, IFLA_BOND_UPDELAY, b->updelay / USEC_PER_MSEC);
a668086e
SS
225 if (r < 0)
226 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_UPDELAY attribute: %m");
d9c52fa0
SS
227 }
228
81bd37a8 229 if (b->arp_interval != 0) {
1c4baffc 230 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_INTERVAL, b->arp_interval / USEC_PER_MSEC);
a668086e
SS
231 if (r < 0)
232 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m");
233
234 if ((b->lp_interval >= LEARNING_PACKETS_INTERVAL_MIN_SEC) &&
235 (b->lp_interval <= LEARNING_PACKETS_INTERVAL_MAX_SEC)) {
1c4baffc 236 r = sd_netlink_message_append_u32(m, IFLA_BOND_LP_INTERVAL, b->lp_interval / USEC_PER_SEC);
a668086e
SS
237 if (r < 0)
238 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m");
81bd37a8
SS
239 }
240 }
241
242 if (b->ad_select != _NETDEV_BOND_AD_SELECT_INVALID &&
76f0a567 243 b->mode == NETDEV_BOND_MODE_802_3AD) {
1c4baffc 244 r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_SELECT, b->ad_select);
a668086e
SS
245 if (r < 0)
246 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_SELECT attribute: %m");
81bd37a8
SS
247 }
248
249 if (b->fail_over_mac != _NETDEV_BOND_FAIL_OVER_MAC_INVALID &&
250 b->mode == NETDEV_BOND_MODE_ACTIVE_BACKUP) {
1c4baffc 251 r = sd_netlink_message_append_u8(m, IFLA_BOND_FAIL_OVER_MAC, b->fail_over_mac);
a668086e
SS
252 if (r < 0)
253 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %m");
81bd37a8
SS
254 }
255
256 if (b->arp_validate != _NETDEV_BOND_ARP_VALIDATE_INVALID) {
1c4baffc 257 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_VALIDATE, b->arp_validate);
a668086e
SS
258 if (r < 0)
259 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
81bd37a8
SS
260 }
261
262 if (b->arp_all_targets != _NETDEV_BOND_ARP_ALL_TARGETS_INVALID) {
1c4baffc 263 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->arp_all_targets);
a668086e
SS
264 if (r < 0)
265 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m");
81bd37a8
SS
266 }
267
268 if (b->primary_reselect != _NETDEV_BOND_PRIMARY_RESELECT_INVALID) {
1c4baffc 269 r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->primary_reselect);
a668086e
SS
270 if (r < 0)
271 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
81bd37a8
SS
272 }
273
274 if (b->resend_igmp <= RESEND_IGMP_MAX) {
1c4baffc 275 r = sd_netlink_message_append_u32(m, IFLA_BOND_RESEND_IGMP, b->resend_igmp);
a668086e
SS
276 if (r < 0)
277 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_RESEND_IGMP attribute: %m");
81bd37a8
SS
278 }
279
76f0a567
TG
280 if (b->packets_per_slave <= PACKETS_PER_SLAVE_MAX &&
281 b->mode == NETDEV_BOND_MODE_BALANCE_RR) {
1c4baffc 282 r = sd_netlink_message_append_u32(m, IFLA_BOND_PACKETS_PER_SLAVE, b->packets_per_slave);
a668086e
SS
283 if (r < 0)
284 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %m");
81bd37a8
SS
285 }
286
287 if (b->num_grat_arp <= GRATUITOUS_ARP_MAX) {
1c4baffc 288 r = sd_netlink_message_append_u8(m, IFLA_BOND_NUM_PEER_NOTIF, b->num_grat_arp);
a668086e
SS
289 if (r < 0)
290 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %m");
81bd37a8
SS
291 }
292
293 if (b->min_links != 0) {
1c4baffc 294 r = sd_netlink_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links);
a668086e
SS
295 if (r < 0)
296 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MIN_LINKS attribute: %m");
81bd37a8
SS
297 }
298
1c4baffc 299 r = sd_netlink_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
a668086e
SS
300 if (r < 0)
301 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %m");
81bd37a8
SS
302
303 if (b->arp_interval > 0) {
304 if (b->n_arp_ip_targets > 0) {
305
1c4baffc 306 r = sd_netlink_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
a668086e
SS
307 if (r < 0)
308 return log_netdev_error_errno(netdev, r, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
81bd37a8
SS
309
310 LIST_FOREACH(arp_ip_target, target, b->arp_ip_targets) {
1c4baffc 311 r = sd_netlink_message_append_u32(m, i++, target->ip.in.s_addr);
a668086e
SS
312 if (r < 0)
313 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
81bd37a8
SS
314 }
315
1c4baffc 316 r = sd_netlink_message_close_container(m);
a668086e
SS
317 if (r < 0)
318 return log_netdev_error_errno(netdev, r, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
81bd37a8
SS
319 }
320 }
321
aa9f1140
TG
322 return 0;
323}
fe8ac65b 324
81bd37a8
SS
325int config_parse_arp_ip_target_address(const char *unit,
326 const char *filename,
327 unsigned line,
328 const char *section,
329 unsigned section_line,
330 const char *lvalue,
331 int ltype,
332 const char *rvalue,
333 void *data,
334 void *userdata) {
335 Bond *b = userdata;
336 const char *word, *state;
337 size_t l;
338 int r;
339
340 assert(filename);
341 assert(lvalue);
342 assert(rvalue);
343 assert(data);
344
345 FOREACH_WORD_QUOTED(word, l, rvalue, state) {
346 _cleanup_free_ ArpIpTarget *buffer = NULL;
347 _cleanup_free_ char *n = NULL;
348 int f;
349
350 n = strndup(word, l);
351 if (!n)
352 return -ENOMEM;
353
354 buffer = new0(ArpIpTarget, 1);
355 if (!buffer)
356 return -ENOMEM;
357
358 r = in_addr_from_string_auto(n, &f, &buffer->ip);
359 if (r < 0) {
360 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
361 return 0;
362 }
363
364 if (f != AF_INET) {
365 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
366 return 0;
367 }
368
369 LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer);
370 b->n_arp_ip_targets ++;
371
372 buffer = NULL;
81bd37a8
SS
373 }
374
dd906398
DH
375 if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX)
376 log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
377
81bd37a8
SS
378 return 0;
379}
380
381static void bond_done(NetDev *netdev) {
382 ArpIpTarget *t = NULL, *n = NULL;
383 Bond *b = BOND(netdev);
384
385 assert(netdev);
386 assert(b);
387
388 LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets)
389 free(t);
390
391 b->arp_ip_targets = NULL;
392}
393
aa9f1140
TG
394static void bond_init(NetDev *netdev) {
395 Bond *b = BOND(netdev);
396
397 assert(netdev);
398 assert(b);
fe8ac65b 399
aa9f1140 400 b->mode = _NETDEV_BOND_MODE_INVALID;
227cdf2c 401 b->xmit_hash_policy = _NETDEV_BOND_XMIT_HASH_POLICY_INVALID;
fb1021a2 402 b->lacp_rate = _NETDEV_BOND_LACP_RATE_INVALID;
81bd37a8
SS
403 b->ad_select = _NETDEV_BOND_AD_SELECT_INVALID;
404 b->fail_over_mac = _NETDEV_BOND_FAIL_OVER_MAC_INVALID;
405 b->arp_validate = _NETDEV_BOND_ARP_VALIDATE_INVALID;
406 b->arp_all_targets = _NETDEV_BOND_ARP_ALL_TARGETS_INVALID;
407 b->primary_reselect = _NETDEV_BOND_PRIMARY_RESELECT_INVALID;
408
409 b->all_slaves_active = false;
410
411 b->resend_igmp = RESEND_IGMP_DEFAULT;
412 b->packets_per_slave = PACKETS_PER_SLAVE_DEFAULT;
413 b->num_grat_arp = GRATUITOUS_ARP_DEFAULT;
414 b->lp_interval = LEARNING_PACKETS_INTERVAL_MIN_SEC;
415
416 LIST_HEAD_INIT(b->arp_ip_targets);
417 b->n_arp_ip_targets = 0;
fe8ac65b
SS
418}
419
3be1d7e0 420const NetDevVTable bond_vtable = {
aa9f1140
TG
421 .object_size = sizeof(Bond),
422 .init = bond_init,
81bd37a8 423 .done = bond_done,
aa9f1140 424 .sections = "Match\0NetDev\0Bond\0",
3be1d7e0 425 .fill_message_create = netdev_bond_fill_message_create,
aa9f1140 426 .create_type = NETDEV_CREATE_MASTER,
3be1d7e0 427};