]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/bridge.c
network: make DEFINE_NETDEV_CAST() assert on input and output
[thirdparty/systemd.git] / src / network / netdev / bridge.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
6235b3de 2
540eb5f0 3#include <net/if.h>
ad851cae 4#include <netinet/in.h>
9f0cf80d 5#include <linux/if_arp.h>
ad851cae 6#include <linux/if_bridge.h>
6235b3de 7
737f1405 8#include "bridge.h"
540eb5f0 9#include "netlink-util.h"
23f53b99 10#include "networkd-manager.h"
8e2cb51c 11#include "string-table.h"
0d6c68eb 12#include "vlan-util.h"
540eb5f0 13
ad851cae
YW
14assert_cc((int) MULTICAST_ROUTER_NONE == (int) MDB_RTR_TYPE_DISABLED);
15assert_cc((int) MULTICAST_ROUTER_TEMPORARY_QUERY == (int) MDB_RTR_TYPE_TEMP_QUERY);
16assert_cc((int) MULTICAST_ROUTER_PERMANENT == (int) MDB_RTR_TYPE_PERM);
17assert_cc((int) MULTICAST_ROUTER_TEMPORARY == (int) MDB_RTR_TYPE_TEMP);
18
8e2cb51c 19static const char* const multicast_router_table[_MULTICAST_ROUTER_MAX] = {
ad851cae 20 [MULTICAST_ROUTER_NONE] = "no",
8e2cb51c 21 [MULTICAST_ROUTER_TEMPORARY_QUERY] = "query",
ad851cae
YW
22 [MULTICAST_ROUTER_PERMANENT] = "permanent",
23 [MULTICAST_ROUTER_TEMPORARY] = "temporary",
8e2cb51c
YW
24};
25
26DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(multicast_router, MulticastRouter, _MULTICAST_ROUTER_INVALID);
27DEFINE_CONFIG_PARSE_ENUM(config_parse_multicast_router, multicast_router, MulticastRouter,
28 "Failed to parse bridge multicast router setting");
29
5238e957 30/* callback for bridge netdev's parameter set */
302a796f 31static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
540eb5f0
SS
32 int r;
33
34 assert(netdev);
35 assert(m);
36
37 r = sd_netlink_message_get_errno(m);
38 if (r < 0) {
39 log_netdev_warning_errno(netdev, r, "Bridge parameters could not be set: %m");
40 return 1;
41 }
42
82936769 43 log_netdev_debug(netdev, "Bridge parameters set success");
540eb5f0
SS
44
45 return 1;
46}
47
81f01be0 48static int netdev_bridge_post_create_message(NetDev *netdev, sd_netlink_message *req) {
117843fe 49 Bridge *b = BRIDGE(netdev);
257cebb6 50 int r;
540eb5f0
SS
51
52 r = sd_netlink_message_open_container(req, IFLA_LINKINFO);
53 if (r < 0)
81f01be0 54 return r;
540eb5f0
SS
55
56 r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
57 if (r < 0)
81f01be0 58 return r;
540eb5f0 59
1a14863e 60 /* convert to jiffes */
730389b6 61 if (b->forward_delay != USEC_INFINITY) {
1a14863e 62 r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, usec_to_jiffies(b->forward_delay));
540eb5f0 63 if (r < 0)
81f01be0 64 return r;
540eb5f0
SS
65 }
66
67 if (b->hello_time > 0) {
1a14863e 68 r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, usec_to_jiffies(b->hello_time));
540eb5f0 69 if (r < 0)
81f01be0 70 return r;
540eb5f0
SS
71 }
72
73 if (b->max_age > 0) {
1a14863e 74 r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, usec_to_jiffies(b->max_age));
540eb5f0 75 if (r < 0)
81f01be0 76 return r;
540eb5f0
SS
77 }
78
0da81203 79 if (b->ageing_time != USEC_INFINITY) {
c7440e74
TJ
80 r = sd_netlink_message_append_u32(req, IFLA_BR_AGEING_TIME, usec_to_jiffies(b->ageing_time));
81 if (r < 0)
81f01be0 82 return r;
c7440e74
TJ
83 }
84
85 if (b->priority > 0) {
86 r = sd_netlink_message_append_u16(req, IFLA_BR_PRIORITY, b->priority);
87 if (r < 0)
81f01be0 88 return r;
c7440e74
TJ
89 }
90
c4819961
JC
91 if (b->group_fwd_mask > 0) {
92 r = sd_netlink_message_append_u16(req, IFLA_BR_GROUP_FWD_MASK, b->group_fwd_mask);
93 if (r < 0)
81f01be0 94 return r;
c4819961
JC
95 }
96
0d6c68eb 97 if (b->default_pvid != VLANID_INVALID) {
c7440e74
TJ
98 r = sd_netlink_message_append_u16(req, IFLA_BR_VLAN_DEFAULT_PVID, b->default_pvid);
99 if (r < 0)
81f01be0 100 return r;
c7440e74
TJ
101 }
102
3fef7a3f
SS
103 if (b->mcast_querier >= 0) {
104 r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_QUERIER, b->mcast_querier);
105 if (r < 0)
81f01be0 106 return r;
3fef7a3f
SS
107 }
108
6df6d898
SS
109 if (b->mcast_snooping >= 0) {
110 r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_SNOOPING, b->mcast_snooping);
111 if (r < 0)
81f01be0 112 return r;
6df6d898
SS
113 }
114
c6f8d17d
TJ
115 if (b->vlan_filtering >= 0) {
116 r = sd_netlink_message_append_u8(req, IFLA_BR_VLAN_FILTERING, b->vlan_filtering);
117 if (r < 0)
81f01be0 118 return r;
c6f8d17d
TJ
119 }
120
4df4df5b 121 if (b->vlan_protocol >= 0) {
6eb35be8 122 r = sd_netlink_message_append_u16(req, IFLA_BR_VLAN_PROTOCOL, htobe16(b->vlan_protocol));
4df4df5b 123 if (r < 0)
81f01be0 124 return r;
4df4df5b
RF
125 }
126
b760a9af
SS
127 if (b->stp >= 0) {
128 r = sd_netlink_message_append_u32(req, IFLA_BR_STP_STATE, b->stp);
129 if (r < 0)
81f01be0 130 return r;
b760a9af
SS
131 }
132
afa51e2d
SS
133 if (b->igmp_version > 0) {
134 r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_IGMP_VERSION, b->igmp_version);
135 if (r < 0)
81f01be0 136 return r;
afa51e2d
SS
137 }
138
540eb5f0
SS
139 r = sd_netlink_message_close_container(req);
140 if (r < 0)
81f01be0 141 return r;
540eb5f0
SS
142
143 r = sd_netlink_message_close_container(req);
144 if (r < 0)
81f01be0
ZJS
145 return r;
146
147 return 0;
148}
149
c2b19b8f 150static int netdev_bridge_post_create(NetDev *netdev, Link *link) {
81f01be0
ZJS
151 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
152 int r;
153
154 assert(netdev);
155
156 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, netdev->ifindex);
157 if (r < 0)
158 return log_netdev_error_errno(netdev, r, "Could not allocate netlink message: %m");
159
160 r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK);
161 if (r < 0)
162 return log_link_error_errno(link, r, "Could not set netlink message flags: %m");
163
164 r = netdev_bridge_post_create_message(netdev, req);
165 if (r < 0)
166 return log_netdev_error_errno(netdev, r, "Could not create netlink message: %m");
540eb5f0 167
302a796f
YW
168 r = netlink_call_async(netdev->manager->rtnl, NULL, req, netdev_bridge_set_handler,
169 netdev_destroy_callback, netdev);
540eb5f0 170 if (r < 0)
81f01be0 171 return log_netdev_error_errno(netdev, r, "Could not send netlink message: %m");
540eb5f0
SS
172
173 netdev_ref(netdev);
174
175 return r;
176}
6235b3de 177
afa51e2d
SS
178int config_parse_bridge_igmp_version(
179 const char *unit,
180 const char *filename,
181 unsigned line,
182 const char *section,
183 unsigned section_line,
184 const char *lvalue,
185 int ltype,
186 const char *rvalue,
187 void *data,
188 void *userdata) {
189
afa51e2d
SS
190 assert(filename);
191 assert(lvalue);
192 assert(rvalue);
193 assert(data);
194
851cdffd
ZJS
195 Bridge *b = ASSERT_PTR(userdata);
196
afa51e2d
SS
197 if (isempty(rvalue)) {
198 b->igmp_version = 0; /* 0 means unset. */
199 return 0;
200 }
201
851cdffd
ZJS
202 return config_parse_uint8_bounded(
203 unit, filename, line, section, section_line, lvalue, rvalue,
204 2, 3, true,
205 &b->igmp_version);
afa51e2d
SS
206}
207
796aa313
YW
208int config_parse_bridge_port_priority(
209 const char *unit,
210 const char *filename,
211 unsigned line,
212 const char *section,
213 unsigned section_line,
214 const char *lvalue,
215 int ltype,
216 const char *rvalue,
217 void *data,
218 void *userdata) {
219
796aa313
YW
220 assert(filename);
221 assert(lvalue);
222 assert(rvalue);
796aa313 223
851cdffd 224 uint16_t *prio = ASSERT_PTR(data);
796aa313 225
851cdffd
ZJS
226 return config_parse_uint16_bounded(
227 unit, filename, line, section, section_line, lvalue, rvalue,
228 0, LINK_BRIDGE_PORT_PRIORITY_MAX, true,
229 prio);
796aa313
YW
230}
231
257cebb6 232static void bridge_init(NetDev *netdev) {
117843fe 233 Bridge *b = BRIDGE(netdev);
3fef7a3f
SS
234
235 b->mcast_querier = -1;
6df6d898 236 b->mcast_snooping = -1;
c6f8d17d 237 b->vlan_filtering = -1;
4df4df5b 238 b->vlan_protocol = -1;
b760a9af 239 b->stp = -1;
0d6c68eb 240 b->default_pvid = VLANID_INVALID;
730389b6 241 b->forward_delay = USEC_INFINITY;
0da81203 242 b->ageing_time = USEC_INFINITY;
3fef7a3f
SS
243}
244
3be1d7e0 245const NetDevVTable bridge_vtable = {
aa9f1140 246 .object_size = sizeof(Bridge),
3fef7a3f 247 .init = bridge_init,
130b812f 248 .sections = NETDEV_COMMON_SECTIONS "Bridge\0",
540eb5f0 249 .post_create = netdev_bridge_post_create,
97b2bc35 250 .create_type = NETDEV_CREATE_INDEPENDENT,
9f0cf80d 251 .iftype = ARPHRD_ETHER,
5b8bdd20 252 .generate_mac = true,
3be1d7e0 253};