1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright 2011-2014 Autronica Fire and Security AS |
3 | * |
4 | * Author(s): |
5 | * 2011-2014 Arvid Brodin, arvid.brodin@alten.se |
6 | * |
7 | * Routines for handling Netlink messages for HSR and PRP. |
8 | */ |
9 | |
10 | #include "hsr_netlink.h" |
11 | #include <linux/kernel.h> |
12 | #include <net/rtnetlink.h> |
13 | #include <net/genetlink.h> |
14 | #include "hsr_main.h" |
15 | #include "hsr_device.h" |
16 | #include "hsr_framereg.h" |
17 | |
18 | static const struct nla_policy hsr_policy[IFLA_HSR_MAX + 1] = { |
19 | [IFLA_HSR_SLAVE1] = { .type = NLA_U32 }, |
20 | [IFLA_HSR_SLAVE2] = { .type = NLA_U32 }, |
21 | [IFLA_HSR_MULTICAST_SPEC] = { .type = NLA_U8 }, |
22 | [IFLA_HSR_VERSION] = { .type = NLA_U8 }, |
23 | [IFLA_HSR_SUPERVISION_ADDR] = { .len = ETH_ALEN }, |
24 | [IFLA_HSR_SEQ_NR] = { .type = NLA_U16 }, |
25 | [IFLA_HSR_PROTOCOL] = { .type = NLA_U8 }, |
26 | }; |
27 | |
28 | /* Here, it seems a netdevice has already been allocated for us, and the |
29 | * hsr_dev_setup routine has been executed. Nice! |
30 | */ |
31 | static int hsr_newlink(struct net *src_net, struct net_device *dev, |
32 | struct nlattr *tb[], struct nlattr *data[], |
33 | struct netlink_ext_ack *extack) |
34 | { |
35 | enum hsr_version proto_version; |
36 | unsigned char multicast_spec; |
37 | u8 proto = HSR_PROTOCOL_HSR; |
38 | struct net_device *link[2]; |
39 | |
40 | if (!data) { |
41 | NL_SET_ERR_MSG_MOD(extack, "No slave devices specified" ); |
42 | return -EINVAL; |
43 | } |
44 | if (!data[IFLA_HSR_SLAVE1]) { |
45 | NL_SET_ERR_MSG_MOD(extack, "Slave1 device not specified" ); |
46 | return -EINVAL; |
47 | } |
48 | link[0] = __dev_get_by_index(net: src_net, |
49 | ifindex: nla_get_u32(nla: data[IFLA_HSR_SLAVE1])); |
50 | if (!link[0]) { |
51 | NL_SET_ERR_MSG_MOD(extack, "Slave1 does not exist" ); |
52 | return -EINVAL; |
53 | } |
54 | if (!data[IFLA_HSR_SLAVE2]) { |
55 | NL_SET_ERR_MSG_MOD(extack, "Slave2 device not specified" ); |
56 | return -EINVAL; |
57 | } |
58 | link[1] = __dev_get_by_index(net: src_net, |
59 | ifindex: nla_get_u32(nla: data[IFLA_HSR_SLAVE2])); |
60 | if (!link[1]) { |
61 | NL_SET_ERR_MSG_MOD(extack, "Slave2 does not exist" ); |
62 | return -EINVAL; |
63 | } |
64 | |
65 | if (link[0] == link[1]) { |
66 | NL_SET_ERR_MSG_MOD(extack, "Slave1 and Slave2 are same" ); |
67 | return -EINVAL; |
68 | } |
69 | |
70 | if (!data[IFLA_HSR_MULTICAST_SPEC]) |
71 | multicast_spec = 0; |
72 | else |
73 | multicast_spec = nla_get_u8(nla: data[IFLA_HSR_MULTICAST_SPEC]); |
74 | |
75 | if (data[IFLA_HSR_PROTOCOL]) |
76 | proto = nla_get_u8(nla: data[IFLA_HSR_PROTOCOL]); |
77 | |
78 | if (proto >= HSR_PROTOCOL_MAX) { |
79 | NL_SET_ERR_MSG_MOD(extack, "Unsupported protocol" ); |
80 | return -EINVAL; |
81 | } |
82 | |
83 | if (!data[IFLA_HSR_VERSION]) { |
84 | proto_version = HSR_V0; |
85 | } else { |
86 | if (proto == HSR_PROTOCOL_PRP) { |
87 | NL_SET_ERR_MSG_MOD(extack, "PRP version unsupported" ); |
88 | return -EINVAL; |
89 | } |
90 | |
91 | proto_version = nla_get_u8(nla: data[IFLA_HSR_VERSION]); |
92 | if (proto_version > HSR_V1) { |
93 | NL_SET_ERR_MSG_MOD(extack, |
94 | "Only HSR version 0/1 supported" ); |
95 | return -EINVAL; |
96 | } |
97 | } |
98 | |
99 | if (proto == HSR_PROTOCOL_PRP) |
100 | proto_version = PRP_V1; |
101 | |
102 | return hsr_dev_finalize(hsr_dev: dev, slave: link, multicast_spec, protocol_version: proto_version, extack); |
103 | } |
104 | |
105 | static void hsr_dellink(struct net_device *dev, struct list_head *head) |
106 | { |
107 | struct hsr_priv *hsr = netdev_priv(dev); |
108 | |
109 | del_timer_sync(timer: &hsr->prune_timer); |
110 | del_timer_sync(timer: &hsr->announce_timer); |
111 | |
112 | hsr_debugfs_term(priv: hsr); |
113 | hsr_del_ports(hsr); |
114 | |
115 | hsr_del_self_node(hsr); |
116 | hsr_del_nodes(node_db: &hsr->node_db); |
117 | |
118 | unregister_netdevice_queue(dev, head); |
119 | } |
120 | |
121 | static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) |
122 | { |
123 | struct hsr_priv *hsr = netdev_priv(dev); |
124 | u8 proto = HSR_PROTOCOL_HSR; |
125 | struct hsr_port *port; |
126 | |
127 | port = hsr_port_get_hsr(hsr, pt: HSR_PT_SLAVE_A); |
128 | if (port) { |
129 | if (nla_put_u32(skb, attrtype: IFLA_HSR_SLAVE1, value: port->dev->ifindex)) |
130 | goto nla_put_failure; |
131 | } |
132 | |
133 | port = hsr_port_get_hsr(hsr, pt: HSR_PT_SLAVE_B); |
134 | if (port) { |
135 | if (nla_put_u32(skb, attrtype: IFLA_HSR_SLAVE2, value: port->dev->ifindex)) |
136 | goto nla_put_failure; |
137 | } |
138 | |
139 | if (nla_put(skb, attrtype: IFLA_HSR_SUPERVISION_ADDR, ETH_ALEN, |
140 | data: hsr->sup_multicast_addr) || |
141 | nla_put_u16(skb, attrtype: IFLA_HSR_SEQ_NR, value: hsr->sequence_nr)) |
142 | goto nla_put_failure; |
143 | if (hsr->prot_version == PRP_V1) |
144 | proto = HSR_PROTOCOL_PRP; |
145 | if (nla_put_u8(skb, attrtype: IFLA_HSR_PROTOCOL, value: proto)) |
146 | goto nla_put_failure; |
147 | |
148 | return 0; |
149 | |
150 | nla_put_failure: |
151 | return -EMSGSIZE; |
152 | } |
153 | |
154 | static struct rtnl_link_ops hsr_link_ops __read_mostly = { |
155 | .kind = "hsr" , |
156 | .maxtype = IFLA_HSR_MAX, |
157 | .policy = hsr_policy, |
158 | .priv_size = sizeof(struct hsr_priv), |
159 | .setup = hsr_dev_setup, |
160 | .newlink = hsr_newlink, |
161 | .dellink = hsr_dellink, |
162 | .fill_info = hsr_fill_info, |
163 | }; |
164 | |
165 | /* attribute policy */ |
166 | static const struct nla_policy hsr_genl_policy[HSR_A_MAX + 1] = { |
167 | [HSR_A_NODE_ADDR] = { .len = ETH_ALEN }, |
168 | [HSR_A_NODE_ADDR_B] = { .len = ETH_ALEN }, |
169 | [HSR_A_IFINDEX] = { .type = NLA_U32 }, |
170 | [HSR_A_IF1_AGE] = { .type = NLA_U32 }, |
171 | [HSR_A_IF2_AGE] = { .type = NLA_U32 }, |
172 | [HSR_A_IF1_SEQ] = { .type = NLA_U16 }, |
173 | [HSR_A_IF2_SEQ] = { .type = NLA_U16 }, |
174 | }; |
175 | |
176 | static struct genl_family hsr_genl_family; |
177 | |
178 | static const struct genl_multicast_group hsr_mcgrps[] = { |
179 | { .name = "hsr-network" , }, |
180 | }; |
181 | |
182 | /* This is called if for some node with MAC address addr, we only get frames |
183 | * over one of the slave interfaces. This would indicate an open network ring |
184 | * (i.e. a link has failed somewhere). |
185 | */ |
186 | void hsr_nl_ringerror(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN], |
187 | struct hsr_port *port) |
188 | { |
189 | struct sk_buff *skb; |
190 | void *msg_head; |
191 | struct hsr_port *master; |
192 | int res; |
193 | |
194 | skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
195 | if (!skb) |
196 | goto fail; |
197 | |
198 | msg_head = genlmsg_put(skb, portid: 0, seq: 0, family: &hsr_genl_family, flags: 0, |
199 | cmd: HSR_C_RING_ERROR); |
200 | if (!msg_head) |
201 | goto nla_put_failure; |
202 | |
203 | res = nla_put(skb, attrtype: HSR_A_NODE_ADDR, ETH_ALEN, data: addr); |
204 | if (res < 0) |
205 | goto nla_put_failure; |
206 | |
207 | res = nla_put_u32(skb, attrtype: HSR_A_IFINDEX, value: port->dev->ifindex); |
208 | if (res < 0) |
209 | goto nla_put_failure; |
210 | |
211 | genlmsg_end(skb, hdr: msg_head); |
212 | genlmsg_multicast(family: &hsr_genl_family, skb, portid: 0, group: 0, GFP_ATOMIC); |
213 | |
214 | return; |
215 | |
216 | nla_put_failure: |
217 | kfree_skb(skb); |
218 | |
219 | fail: |
220 | rcu_read_lock(); |
221 | master = hsr_port_get_hsr(hsr, pt: HSR_PT_MASTER); |
222 | netdev_warn(dev: master->dev, format: "Could not send HSR ring error message\n" ); |
223 | rcu_read_unlock(); |
224 | } |
225 | |
226 | /* This is called when we haven't heard from the node with MAC address addr for |
227 | * some time (just before the node is removed from the node table/list). |
228 | */ |
229 | void hsr_nl_nodedown(struct hsr_priv *hsr, unsigned char addr[ETH_ALEN]) |
230 | { |
231 | struct sk_buff *skb; |
232 | void *msg_head; |
233 | struct hsr_port *master; |
234 | int res; |
235 | |
236 | skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
237 | if (!skb) |
238 | goto fail; |
239 | |
240 | msg_head = genlmsg_put(skb, portid: 0, seq: 0, family: &hsr_genl_family, flags: 0, cmd: HSR_C_NODE_DOWN); |
241 | if (!msg_head) |
242 | goto nla_put_failure; |
243 | |
244 | res = nla_put(skb, attrtype: HSR_A_NODE_ADDR, ETH_ALEN, data: addr); |
245 | if (res < 0) |
246 | goto nla_put_failure; |
247 | |
248 | genlmsg_end(skb, hdr: msg_head); |
249 | genlmsg_multicast(family: &hsr_genl_family, skb, portid: 0, group: 0, GFP_ATOMIC); |
250 | |
251 | return; |
252 | |
253 | nla_put_failure: |
254 | kfree_skb(skb); |
255 | |
256 | fail: |
257 | rcu_read_lock(); |
258 | master = hsr_port_get_hsr(hsr, pt: HSR_PT_MASTER); |
259 | netdev_warn(dev: master->dev, format: "Could not send HSR node down\n" ); |
260 | rcu_read_unlock(); |
261 | } |
262 | |
263 | /* HSR_C_GET_NODE_STATUS lets userspace query the internal HSR node table |
264 | * about the status of a specific node in the network, defined by its MAC |
265 | * address. |
266 | * |
267 | * Input: hsr ifindex, node mac address |
268 | * Output: hsr ifindex, node mac address (copied from request), |
269 | * age of latest frame from node over slave 1, slave 2 [ms] |
270 | */ |
271 | static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info) |
272 | { |
273 | /* For receiving */ |
274 | struct nlattr *na; |
275 | struct net_device *hsr_dev; |
276 | |
277 | /* For sending */ |
278 | struct sk_buff *skb_out; |
279 | void *msg_head; |
280 | struct hsr_priv *hsr; |
281 | struct hsr_port *port; |
282 | unsigned char hsr_node_addr_b[ETH_ALEN]; |
283 | int hsr_node_if1_age; |
284 | u16 hsr_node_if1_seq; |
285 | int hsr_node_if2_age; |
286 | u16 hsr_node_if2_seq; |
287 | int addr_b_ifindex; |
288 | int res; |
289 | |
290 | if (!info) |
291 | goto invalid; |
292 | |
293 | na = info->attrs[HSR_A_IFINDEX]; |
294 | if (!na) |
295 | goto invalid; |
296 | na = info->attrs[HSR_A_NODE_ADDR]; |
297 | if (!na) |
298 | goto invalid; |
299 | |
300 | rcu_read_lock(); |
301 | hsr_dev = dev_get_by_index_rcu(net: genl_info_net(info), |
302 | ifindex: nla_get_u32(nla: info->attrs[HSR_A_IFINDEX])); |
303 | if (!hsr_dev) |
304 | goto rcu_unlock; |
305 | if (!is_hsr_master(dev: hsr_dev)) |
306 | goto rcu_unlock; |
307 | |
308 | /* Send reply */ |
309 | skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
310 | if (!skb_out) { |
311 | res = -ENOMEM; |
312 | goto fail; |
313 | } |
314 | |
315 | msg_head = genlmsg_put(skb: skb_out, NETLINK_CB(skb_in).portid, |
316 | seq: info->snd_seq, family: &hsr_genl_family, flags: 0, |
317 | cmd: HSR_C_SET_NODE_STATUS); |
318 | if (!msg_head) { |
319 | res = -ENOMEM; |
320 | goto nla_put_failure; |
321 | } |
322 | |
323 | res = nla_put_u32(skb: skb_out, attrtype: HSR_A_IFINDEX, value: hsr_dev->ifindex); |
324 | if (res < 0) |
325 | goto nla_put_failure; |
326 | |
327 | hsr = netdev_priv(dev: hsr_dev); |
328 | res = hsr_get_node_data(hsr, |
329 | addr: (unsigned char *) |
330 | nla_data(nla: info->attrs[HSR_A_NODE_ADDR]), |
331 | addr_b: hsr_node_addr_b, |
332 | addr_b_ifindex: &addr_b_ifindex, |
333 | if1_age: &hsr_node_if1_age, |
334 | if1_seq: &hsr_node_if1_seq, |
335 | if2_age: &hsr_node_if2_age, |
336 | if2_seq: &hsr_node_if2_seq); |
337 | if (res < 0) |
338 | goto nla_put_failure; |
339 | |
340 | res = nla_put(skb: skb_out, attrtype: HSR_A_NODE_ADDR, ETH_ALEN, |
341 | data: nla_data(nla: info->attrs[HSR_A_NODE_ADDR])); |
342 | if (res < 0) |
343 | goto nla_put_failure; |
344 | |
345 | if (addr_b_ifindex > -1) { |
346 | res = nla_put(skb: skb_out, attrtype: HSR_A_NODE_ADDR_B, ETH_ALEN, |
347 | data: hsr_node_addr_b); |
348 | if (res < 0) |
349 | goto nla_put_failure; |
350 | |
351 | res = nla_put_u32(skb: skb_out, attrtype: HSR_A_ADDR_B_IFINDEX, |
352 | value: addr_b_ifindex); |
353 | if (res < 0) |
354 | goto nla_put_failure; |
355 | } |
356 | |
357 | res = nla_put_u32(skb: skb_out, attrtype: HSR_A_IF1_AGE, value: hsr_node_if1_age); |
358 | if (res < 0) |
359 | goto nla_put_failure; |
360 | res = nla_put_u16(skb: skb_out, attrtype: HSR_A_IF1_SEQ, value: hsr_node_if1_seq); |
361 | if (res < 0) |
362 | goto nla_put_failure; |
363 | port = hsr_port_get_hsr(hsr, pt: HSR_PT_SLAVE_A); |
364 | if (port) |
365 | res = nla_put_u32(skb: skb_out, attrtype: HSR_A_IF1_IFINDEX, |
366 | value: port->dev->ifindex); |
367 | if (res < 0) |
368 | goto nla_put_failure; |
369 | |
370 | res = nla_put_u32(skb: skb_out, attrtype: HSR_A_IF2_AGE, value: hsr_node_if2_age); |
371 | if (res < 0) |
372 | goto nla_put_failure; |
373 | res = nla_put_u16(skb: skb_out, attrtype: HSR_A_IF2_SEQ, value: hsr_node_if2_seq); |
374 | if (res < 0) |
375 | goto nla_put_failure; |
376 | port = hsr_port_get_hsr(hsr, pt: HSR_PT_SLAVE_B); |
377 | if (port) |
378 | res = nla_put_u32(skb: skb_out, attrtype: HSR_A_IF2_IFINDEX, |
379 | value: port->dev->ifindex); |
380 | if (res < 0) |
381 | goto nla_put_failure; |
382 | |
383 | rcu_read_unlock(); |
384 | |
385 | genlmsg_end(skb: skb_out, hdr: msg_head); |
386 | genlmsg_unicast(net: genl_info_net(info), skb: skb_out, portid: info->snd_portid); |
387 | |
388 | return 0; |
389 | |
390 | rcu_unlock: |
391 | rcu_read_unlock(); |
392 | invalid: |
393 | netlink_ack(in_skb: skb_in, nlh: nlmsg_hdr(skb: skb_in), err: -EINVAL, NULL); |
394 | return 0; |
395 | |
396 | nla_put_failure: |
397 | kfree_skb(skb: skb_out); |
398 | /* Fall through */ |
399 | |
400 | fail: |
401 | rcu_read_unlock(); |
402 | return res; |
403 | } |
404 | |
405 | /* Get a list of MacAddressA of all nodes known to this node (including self). |
406 | */ |
407 | static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info) |
408 | { |
409 | unsigned char addr[ETH_ALEN]; |
410 | struct net_device *hsr_dev; |
411 | struct sk_buff *skb_out; |
412 | struct hsr_priv *hsr; |
413 | bool restart = false; |
414 | struct nlattr *na; |
415 | void *pos = NULL; |
416 | void *msg_head; |
417 | int res; |
418 | |
419 | if (!info) |
420 | goto invalid; |
421 | |
422 | na = info->attrs[HSR_A_IFINDEX]; |
423 | if (!na) |
424 | goto invalid; |
425 | |
426 | rcu_read_lock(); |
427 | hsr_dev = dev_get_by_index_rcu(net: genl_info_net(info), |
428 | ifindex: nla_get_u32(nla: info->attrs[HSR_A_IFINDEX])); |
429 | if (!hsr_dev) |
430 | goto rcu_unlock; |
431 | if (!is_hsr_master(dev: hsr_dev)) |
432 | goto rcu_unlock; |
433 | |
434 | restart: |
435 | /* Send reply */ |
436 | skb_out = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); |
437 | if (!skb_out) { |
438 | res = -ENOMEM; |
439 | goto fail; |
440 | } |
441 | |
442 | msg_head = genlmsg_put(skb: skb_out, NETLINK_CB(skb_in).portid, |
443 | seq: info->snd_seq, family: &hsr_genl_family, flags: 0, |
444 | cmd: HSR_C_SET_NODE_LIST); |
445 | if (!msg_head) { |
446 | res = -ENOMEM; |
447 | goto nla_put_failure; |
448 | } |
449 | |
450 | if (!restart) { |
451 | res = nla_put_u32(skb: skb_out, attrtype: HSR_A_IFINDEX, value: hsr_dev->ifindex); |
452 | if (res < 0) |
453 | goto nla_put_failure; |
454 | } |
455 | |
456 | hsr = netdev_priv(dev: hsr_dev); |
457 | |
458 | if (!pos) |
459 | pos = hsr_get_next_node(hsr, NULL, addr); |
460 | while (pos) { |
461 | res = nla_put(skb: skb_out, attrtype: HSR_A_NODE_ADDR, ETH_ALEN, data: addr); |
462 | if (res < 0) { |
463 | if (res == -EMSGSIZE) { |
464 | genlmsg_end(skb: skb_out, hdr: msg_head); |
465 | genlmsg_unicast(net: genl_info_net(info), skb: skb_out, |
466 | portid: info->snd_portid); |
467 | restart = true; |
468 | goto restart; |
469 | } |
470 | goto nla_put_failure; |
471 | } |
472 | pos = hsr_get_next_node(hsr, pos: pos, addr); |
473 | } |
474 | rcu_read_unlock(); |
475 | |
476 | genlmsg_end(skb: skb_out, hdr: msg_head); |
477 | genlmsg_unicast(net: genl_info_net(info), skb: skb_out, portid: info->snd_portid); |
478 | |
479 | return 0; |
480 | |
481 | rcu_unlock: |
482 | rcu_read_unlock(); |
483 | invalid: |
484 | netlink_ack(in_skb: skb_in, nlh: nlmsg_hdr(skb: skb_in), err: -EINVAL, NULL); |
485 | return 0; |
486 | |
487 | nla_put_failure: |
488 | nlmsg_free(skb: skb_out); |
489 | /* Fall through */ |
490 | |
491 | fail: |
492 | rcu_read_unlock(); |
493 | return res; |
494 | } |
495 | |
496 | static const struct genl_small_ops hsr_ops[] = { |
497 | { |
498 | .cmd = HSR_C_GET_NODE_STATUS, |
499 | .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
500 | .flags = 0, |
501 | .doit = hsr_get_node_status, |
502 | .dumpit = NULL, |
503 | }, |
504 | { |
505 | .cmd = HSR_C_GET_NODE_LIST, |
506 | .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
507 | .flags = 0, |
508 | .doit = hsr_get_node_list, |
509 | .dumpit = NULL, |
510 | }, |
511 | }; |
512 | |
513 | static struct genl_family hsr_genl_family __ro_after_init = { |
514 | .hdrsize = 0, |
515 | .name = "HSR" , |
516 | .version = 1, |
517 | .maxattr = HSR_A_MAX, |
518 | .policy = hsr_genl_policy, |
519 | .netnsok = true, |
520 | .module = THIS_MODULE, |
521 | .small_ops = hsr_ops, |
522 | .n_small_ops = ARRAY_SIZE(hsr_ops), |
523 | .resv_start_op = HSR_C_SET_NODE_LIST + 1, |
524 | .mcgrps = hsr_mcgrps, |
525 | .n_mcgrps = ARRAY_SIZE(hsr_mcgrps), |
526 | }; |
527 | |
528 | int __init hsr_netlink_init(void) |
529 | { |
530 | int rc; |
531 | |
532 | rc = rtnl_link_register(ops: &hsr_link_ops); |
533 | if (rc) |
534 | goto fail_rtnl_link_register; |
535 | |
536 | rc = genl_register_family(family: &hsr_genl_family); |
537 | if (rc) |
538 | goto fail_genl_register_family; |
539 | |
540 | hsr_debugfs_create_root(); |
541 | return 0; |
542 | |
543 | fail_genl_register_family: |
544 | rtnl_link_unregister(ops: &hsr_link_ops); |
545 | fail_rtnl_link_register: |
546 | |
547 | return rc; |
548 | } |
549 | |
550 | void __exit hsr_netlink_exit(void) |
551 | { |
552 | genl_unregister_family(family: &hsr_genl_family); |
553 | rtnl_link_unregister(ops: &hsr_link_ops); |
554 | } |
555 | |
556 | MODULE_ALIAS_RTNL_LINK("hsr" ); |
557 | |