1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <net/if.h>
4 #include <netinet/in.h>
5 #include <linux/if_arp.h>
6
7 #include "conf-parser.h"
8 #include "macvlan.h"
9 #include "macvlan-util.h"
10 #include "networkd-network.h"
11 #include "parse-util.h"
12
13 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
14
netdev_macvlan_fill_message_create(NetDev * netdev,Link * link,sd_netlink_message * req)15 static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
16 MacVlan *m;
17 int r;
18
19 assert(netdev);
20 assert(link);
21 assert(netdev->ifname);
22 assert(link->network);
23
24 if (netdev->kind == NETDEV_KIND_MACVLAN)
25 m = MACVLAN(netdev);
26 else
27 m = MACVTAP(netdev);
28
29 assert(m);
30
31 if (m->mode == NETDEV_MACVLAN_MODE_SOURCE && !set_isempty(m->match_source_mac)) {
32 const struct ether_addr *mac_addr;
33
34 r = sd_netlink_message_append_u32(req, IFLA_MACVLAN_MACADDR_MODE, MACVLAN_MACADDR_SET);
35 if (r < 0)
36 return r;
37
38 r = sd_netlink_message_open_container(req, IFLA_MACVLAN_MACADDR_DATA);
39 if (r < 0)
40 return r;
41
42 SET_FOREACH(mac_addr, m->match_source_mac) {
43 r = sd_netlink_message_append_ether_addr(req, IFLA_MACVLAN_MACADDR, mac_addr);
44 if (r < 0)
45 return r;
46 }
47
48 r = sd_netlink_message_close_container(req);
49 if (r < 0)
50 return r;
51 }
52
53 if (m->mode != _NETDEV_MACVLAN_MODE_INVALID) {
54 r = sd_netlink_message_append_u32(req, IFLA_MACVLAN_MODE, m->mode);
55 if (r < 0)
56 return r;
57 }
58
59 /* set the nopromisc flag if Promiscuous= of the link is explicitly set to false */
60 if (m->mode == NETDEV_MACVLAN_MODE_PASSTHRU && link->network->promiscuous == 0) {
61 r = sd_netlink_message_append_u16(req, IFLA_MACVLAN_FLAGS, MACVLAN_FLAG_NOPROMISC);
62 if (r < 0)
63 return r;
64 }
65
66 if (m->bc_queue_length != UINT32_MAX) {
67 r = sd_netlink_message_append_u32(req, IFLA_MACVLAN_BC_QUEUE_LEN, m->bc_queue_length);
68 if (r < 0)
69 return r;
70 }
71
72 return 0;
73 }
74
config_parse_macvlan_broadcast_queue_size(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)75 int config_parse_macvlan_broadcast_queue_size(
76 const char *unit,
77 const char *filename,
78 unsigned line,
79 const char *section,
80 unsigned section_line,
81 const char *lvalue,
82 int ltype,
83 const char *rvalue,
84 void *data,
85 void *userdata) {
86
87 MacVlan *m = userdata;
88 uint32_t v;
89 int r;
90
91 assert(filename);
92 assert(section);
93 assert(lvalue);
94 assert(rvalue);
95 assert(data);
96 assert(userdata);
97
98 if (isempty(rvalue)) {
99 m->bc_queue_length = UINT32_MAX;
100 return 0;
101 }
102
103 r = safe_atou32(rvalue, &v);
104 if (r < 0) {
105 log_syntax(unit, LOG_WARNING, filename, line, r,
106 "Failed to parse BroadcastMulticastQueueLength=%s, ignoring assignment: %m", rvalue);
107 return 0;
108 }
109
110 if (v == UINT32_MAX) {
111 log_syntax(unit, LOG_WARNING, filename, line, 0,
112 "Invalid BroadcastMulticastQueueLength=%s, ignoring assignment: %m", rvalue);
113 return 0;
114 }
115
116 m->bc_queue_length = v;
117 return 0;
118 }
119
macvlan_done(NetDev * n)120 static void macvlan_done(NetDev *n) {
121 MacVlan *m;
122
123 assert(n);
124
125 if (n->kind == NETDEV_KIND_MACVLAN)
126 m = MACVLAN(n);
127 else
128 m = MACVTAP(n);
129
130 assert(m);
131
132 set_free(m->match_source_mac);
133 }
134
macvlan_init(NetDev * n)135 static void macvlan_init(NetDev *n) {
136 MacVlan *m;
137
138 assert(n);
139
140 if (n->kind == NETDEV_KIND_MACVLAN)
141 m = MACVLAN(n);
142 else
143 m = MACVTAP(n);
144
145 assert(m);
146
147 m->mode = _NETDEV_MACVLAN_MODE_INVALID;
148 m->bc_queue_length = UINT32_MAX;
149 }
150
151 const NetDevVTable macvtap_vtable = {
152 .object_size = sizeof(MacVlan),
153 .init = macvlan_init,
154 .done = macvlan_done,
155 .sections = NETDEV_COMMON_SECTIONS "MACVTAP\0",
156 .fill_message_create = netdev_macvlan_fill_message_create,
157 .create_type = NETDEV_CREATE_STACKED,
158 .iftype = ARPHRD_ETHER,
159 .generate_mac = true,
160 };
161
162 const NetDevVTable macvlan_vtable = {
163 .object_size = sizeof(MacVlan),
164 .init = macvlan_init,
165 .done = macvlan_done,
166 .sections = NETDEV_COMMON_SECTIONS "MACVLAN\0",
167 .fill_message_create = netdev_macvlan_fill_message_create,
168 .create_type = NETDEV_CREATE_STACKED,
169 .iftype = ARPHRD_ETHER,
170 .generate_mac = true,
171 };
172