1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include <netinet/in.h>
5 #include <linux/if_arp.h>
6 #include <linux/if_bridge.h>
9 #include "netlink-util.h"
10 #include "networkd-manager.h"
11 #include "string-table.h"
12 #include "vlan-util.h"
14 assert_cc((int) MULTICAST_ROUTER_NONE
== (int) MDB_RTR_TYPE_DISABLED
);
15 assert_cc((int) MULTICAST_ROUTER_TEMPORARY_QUERY
== (int) MDB_RTR_TYPE_TEMP_QUERY
);
16 assert_cc((int) MULTICAST_ROUTER_PERMANENT
== (int) MDB_RTR_TYPE_PERM
);
17 assert_cc((int) MULTICAST_ROUTER_TEMPORARY
== (int) MDB_RTR_TYPE_TEMP
);
19 static const char* const multicast_router_table
[_MULTICAST_ROUTER_MAX
] = {
20 [MULTICAST_ROUTER_NONE
] = "no",
21 [MULTICAST_ROUTER_TEMPORARY_QUERY
] = "query",
22 [MULTICAST_ROUTER_PERMANENT
] = "permanent",
23 [MULTICAST_ROUTER_TEMPORARY
] = "temporary",
26 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(multicast_router
, MulticastRouter
, _MULTICAST_ROUTER_INVALID
);
27 DEFINE_CONFIG_PARSE_ENUM(config_parse_multicast_router
, multicast_router
, MulticastRouter
,
28 "Failed to parse bridge multicast router setting");
30 /* callback for bridge netdev's parameter set */
31 static int netdev_bridge_set_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, NetDev
*netdev
) {
37 r
= sd_netlink_message_get_errno(m
);
39 log_netdev_warning_errno(netdev
, r
, "Bridge parameters could not be set: %m");
43 log_netdev_debug(netdev
, "Bridge parameters set success");
48 static int netdev_bridge_post_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
49 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
59 r
= sd_rtnl_message_new_link(netdev
->manager
->rtnl
, &req
, RTM_NEWLINK
, netdev
->ifindex
);
61 return log_netdev_error_errno(netdev
, r
, "Could not allocate RTM_SETLINK message: %m");
63 r
= sd_netlink_message_set_flags(req
, NLM_F_REQUEST
| NLM_F_ACK
);
65 return log_link_error_errno(link
, r
, "Could not set netlink flags: %m");
67 r
= sd_netlink_message_open_container(req
, IFLA_LINKINFO
);
69 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_LINKINFO attribute: %m");
71 r
= sd_netlink_message_open_container_union(req
, IFLA_INFO_DATA
, netdev_kind_to_string(netdev
->kind
));
73 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_INFO_DATA attribute: %m");
75 /* convert to jiffes */
76 if (b
->forward_delay
!= USEC_INFINITY
) {
77 r
= sd_netlink_message_append_u32(req
, IFLA_BR_FORWARD_DELAY
, usec_to_jiffies(b
->forward_delay
));
79 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_FORWARD_DELAY attribute: %m");
82 if (b
->hello_time
> 0) {
83 r
= sd_netlink_message_append_u32(req
, IFLA_BR_HELLO_TIME
, usec_to_jiffies(b
->hello_time
));
85 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_HELLO_TIME attribute: %m");
89 r
= sd_netlink_message_append_u32(req
, IFLA_BR_MAX_AGE
, usec_to_jiffies(b
->max_age
));
91 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_MAX_AGE attribute: %m");
94 if (b
->ageing_time
!= USEC_INFINITY
) {
95 r
= sd_netlink_message_append_u32(req
, IFLA_BR_AGEING_TIME
, usec_to_jiffies(b
->ageing_time
));
97 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_AGEING_TIME attribute: %m");
100 if (b
->priority
> 0) {
101 r
= sd_netlink_message_append_u16(req
, IFLA_BR_PRIORITY
, b
->priority
);
103 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_PRIORITY attribute: %m");
106 if (b
->group_fwd_mask
> 0) {
107 r
= sd_netlink_message_append_u16(req
, IFLA_BR_GROUP_FWD_MASK
, b
->group_fwd_mask
);
109 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_GROUP_FWD_MASK attribute: %m");
112 if (b
->default_pvid
!= VLANID_INVALID
) {
113 r
= sd_netlink_message_append_u16(req
, IFLA_BR_VLAN_DEFAULT_PVID
, b
->default_pvid
);
115 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_VLAN_DEFAULT_PVID attribute: %m");
118 if (b
->mcast_querier
>= 0) {
119 r
= sd_netlink_message_append_u8(req
, IFLA_BR_MCAST_QUERIER
, b
->mcast_querier
);
121 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_MCAST_QUERIER attribute: %m");
124 if (b
->mcast_snooping
>= 0) {
125 r
= sd_netlink_message_append_u8(req
, IFLA_BR_MCAST_SNOOPING
, b
->mcast_snooping
);
127 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_MCAST_SNOOPING attribute: %m");
130 if (b
->vlan_filtering
>= 0) {
131 r
= sd_netlink_message_append_u8(req
, IFLA_BR_VLAN_FILTERING
, b
->vlan_filtering
);
133 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_VLAN_FILTERING attribute: %m");
136 if (b
->vlan_protocol
>= 0) {
137 r
= sd_netlink_message_append_u16(req
, IFLA_BR_VLAN_PROTOCOL
, b
->vlan_protocol
);
139 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_VLAN_PROTOCOL attribute: %m");
143 r
= sd_netlink_message_append_u32(req
, IFLA_BR_STP_STATE
, b
->stp
);
145 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_STP_STATE attribute: %m");
148 if (b
->igmp_version
> 0) {
149 r
= sd_netlink_message_append_u8(req
, IFLA_BR_MCAST_IGMP_VERSION
, b
->igmp_version
);
151 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_BR_MCAST_IGMP_VERSION attribute: %m");
154 r
= sd_netlink_message_close_container(req
);
156 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_LINKINFO attribute: %m");
158 r
= sd_netlink_message_close_container(req
);
160 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_INFO_DATA attribute: %m");
162 r
= netlink_call_async(netdev
->manager
->rtnl
, NULL
, req
, netdev_bridge_set_handler
,
163 netdev_destroy_callback
, netdev
);
165 return log_netdev_error_errno(netdev
, r
, "Could not send rtnetlink message: %m");
172 int config_parse_bridge_igmp_version(
174 const char *filename
,
177 unsigned section_line
,
184 Bridge
*b
= userdata
;
193 if (isempty(rvalue
)) {
194 b
->igmp_version
= 0; /* 0 means unset. */
198 r
= safe_atou8(rvalue
, &u
);
200 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
201 "Failed to parse bridge's multicast IGMP version number '%s', ignoring assignment: %m",
205 if (!IN_SET(u
, 2, 3)) {
206 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
207 "Invalid bridge's multicast IGMP version number '%s', ignoring assignment.", rvalue
);
216 int config_parse_bridge_port_priority(
218 const char *filename
,
221 unsigned section_line
,
236 /* This is used in networkd-network-gperf.gperf. */
238 r
= safe_atou16(rvalue
, &i
);
240 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
241 "Failed to parse bridge port priority, ignoring: %s", rvalue
);
245 if (i
> LINK_BRIDGE_PORT_PRIORITY_MAX
) {
246 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
247 "Bridge port priority is larger than maximum %u, ignoring: %s",
248 LINK_BRIDGE_PORT_PRIORITY_MAX
, rvalue
);
252 *((uint16_t *)data
) = i
;
257 static void bridge_init(NetDev
*n
) {
264 b
->mcast_querier
= -1;
265 b
->mcast_snooping
= -1;
266 b
->vlan_filtering
= -1;
267 b
->vlan_protocol
= -1;
269 b
->default_pvid
= VLANID_INVALID
;
270 b
->forward_delay
= USEC_INFINITY
;
271 b
->ageing_time
= USEC_INFINITY
;
274 const NetDevVTable bridge_vtable
= {
275 .object_size
= sizeof(Bridge
),
277 .sections
= NETDEV_COMMON_SECTIONS
"Bridge\0",
278 .post_create
= netdev_bridge_post_create
,
279 .create_type
= NETDEV_CREATE_MASTER
,
280 .iftype
= ARPHRD_ETHER
,
281 .generate_mac
= true,