History

macvlan: add source mode

This patch adds a new mode of operation to macvlan, called "source". It allows one to set a list of allowed mac address, which is used to match against source mac address from received frames on underlying interface. This enables creating mac based VLAN associations, instead of standard port or tag based. The feature is useful to deploy 802.1x mac based behavior, where drivers of underlying interfaces doesn't allows that. Configuration is done through the netlink interface using e.g.: ip link add link eth0 name macvlan0 type macvlan mode source ip link add link eth0 name macvlan1 type macvlan mode source ip link set link dev macvlan0 type macvlan macaddr add 00:11:11:11:11:11 ip link set link dev macvlan0 type macvlan macaddr add 00:22:22:22:22:22 ip link set link dev macvlan0 type macvlan macaddr add 00:33:33:33:33:33 ip link set link dev macvlan1 type macvlan macaddr add 00:33:33:33:33:33 ip link set link dev macvlan1 type macvlan macaddr add 00:44:44:44:44:44 This allows clients with MAC addresses 00:11:11:11:11:11, 00:22:22:22:22:22 to be part of only VLAN associated with macvlan0 interface. Clients with MAC addresses 00:44:44:44:44:44 with only VLAN associated with macvlan1 interface. And client with MAC address 00:33:33:33:33:33 to be associated with both VLANs. Based on work of Stefan Gula <steweg@gmail.com> v8: last version of Stefan Gula for Kernel 3.2.1 v9: rework onto linux-next 2014-03-12 by Michael Braun add MACADDR_SET command, enable to configure mac for source mode while creating interface v10: - reduce indention level - rename source_list to source_entry - use aligned 64bit ether address - use hash_64 instead of addr[5] v11: - rebase for 3.14 / linux-next 20.04.2014 v12 - rebase for linux-next 2014-09-25

Michael Braun committed 12 years ago

Commit 79cf79a1 parent 85224843 files · +314 −3Browse files

Unified · Split

3 files
  1. drivers/net/macvlan.c +301 −3
  2. include/linux/if_macvlan.h +1 −0
  3. include/uapi/linux/if_link.h +12 −0
drivers/net/macvlan.c+301−3
@@ -35,7 +35,8 @@ · 34 unmodified lines
3535 #include <net/xfrm.h>
3636 #include <linux/netpoll.h>
3737
38−#define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE)
38+#define MACVLAN_HASH_BITS 8
39+#define MACVLAN_HASH_SIZE (1<<MACVLAN_HASH_BITS)
3940 #define MACVLAN_BC_QUEUE_LEN 1000
4041
4142 struct macvlan_port {
@@ -47,6 +48,14 @@ struct macvlan_port { · 5 unmodified lines
4748 struct work_struct bc_work;
4849 bool passthru;
4950 int count;
51+ struct hlist_head vlan_source_hash[MACVLAN_HASH_SIZE];
52+};
53+
54+struct macvlan_source_entry {
55+ struct hlist_node hlist;
56+ struct macvlan_dev *vlan;
57+ unsigned char addr[6+2] __aligned(sizeof(u16));
58+ struct rcu_head rcu;
5059 };
5160
5261 struct macvlan_skb_cb {
@@ -57,6 +66,20 @@ struct macvlan_skb_cb { · 4 unmodified lines
5766
5867 static void macvlan_port_destroy(struct net_device *dev);
5968
69+/* Hash Ethernet address */
70+static u32 macvlan_eth_hash(const unsigned char *addr)
71+{
72+ u64 value = get_unaligned((u64 *)addr);
73+
74+ /* only want 6 bytes */
75+#ifdef __BIG_ENDIAN
76+ value >>= 16;
77+#else
78+ value <<= 16;
79+#endif
80+ return hash_64(value, MACVLAN_HASH_BITS);
81+}
82+
6083 static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev)
6184 {
6285 return rcu_dereference(dev->rx_handler_data);
@@ -73,20 +96,68 @@ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port, · 10 unmodified lines
7396 const unsigned char *addr)
7497 {
7598 struct macvlan_dev *vlan;
99+ u32 idx = macvlan_eth_hash(addr);
76100
77− hlist_for_each_entry_rcu(vlan, &port->vlan_hash[addr[5]], hlist) {
101+ hlist_for_each_entry_rcu(vlan, &port->vlan_hash[idx], hlist) {
78102 if (ether_addr_equal_64bits(vlan->dev->dev_addr, addr))
79103 return vlan;
80104 }
81105 return NULL;
82106 }
83107
108+static struct macvlan_source_entry *macvlan_hash_lookup_source(
109+ const struct macvlan_dev *vlan,
110+ const unsigned char *addr)
111+{
112+ struct macvlan_source_entry *entry;
113+ u32 idx = macvlan_eth_hash(addr);
114+ struct hlist_head *h = &vlan->port->vlan_source_hash[idx];
115+
116+ hlist_for_each_entry_rcu(entry, h, hlist) {
117+ if (ether_addr_equal_64bits(entry->addr, addr) &&
118+ entry->vlan == vlan)
119+ return entry;
120+ }
121+ return NULL;
122+}
123+
124+static int macvlan_hash_add_source(struct macvlan_dev *vlan,
125+ const unsigned char *addr)
126+{
127+ struct macvlan_port *port = vlan->port;
128+ struct macvlan_source_entry *entry;
129+ struct hlist_head *h;
130+
131+ entry = macvlan_hash_lookup_source(vlan, addr);
132+ if (entry)
133+ return 0;
134+
135+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
136+ if (!entry)
137+ return -ENOMEM;
138+
139+ ether_addr_copy(entry->addr, addr);
140+ entry->vlan = vlan;
141+ h = &port->vlan_source_hash[macvlan_eth_hash(addr)];
142+ hlist_add_head_rcu(&entry->hlist, h);
143+ vlan->macaddr_count++;
144+
145+ return 0;
146+}
147+
84148 static void macvlan_hash_add(struct macvlan_dev *vlan)
85149 {
86150 struct macvlan_port *port = vlan->port;
87151 const unsigned char *addr = vlan->dev->dev_addr;
152+ u32 idx = macvlan_eth_hash(addr);
88153
89− hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]);
154+ hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[idx]);
155+}
156+
157+static void macvlan_hash_del_source(struct macvlan_source_entry *entry)
158+{
159+ hlist_del_rcu(&entry->hlist);
160+ kfree_rcu(entry, rcu);
90161 }
91162
92163 static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync)
@@ -267,6 +338,65 @@ err: · 174 unmodified lines
267338 atomic_long_inc(&skb->dev->rx_dropped);
268339 }
269340
341+static void macvlan_flush_sources(struct macvlan_port *port,
342+ struct macvlan_dev *vlan)
343+{
344+ int i;
345+
346+ for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
347+ struct hlist_node *h, *n;
348+
349+ hlist_for_each_safe(h, n, &port->vlan_source_hash[i]) {
350+ struct macvlan_source_entry *entry;
351+
352+ entry = hlist_entry(h, struct macvlan_source_entry,
353+ hlist);
354+ if (entry->vlan == vlan)
355+ macvlan_hash_del_source(entry);
356+ }
357+ }
358+ vlan->macaddr_count = 0;
359+}
360+
361+static void macvlan_forward_source_one(struct sk_buff *skb,
362+ struct macvlan_dev *vlan)
363+{
364+ struct sk_buff *nskb;
365+ struct net_device *dev;
366+ int len;
367+ int ret;
368+
369+ dev = vlan->dev;
370+ if (unlikely(!(dev->flags & IFF_UP)))
371+ return;
372+
373+ nskb = skb_clone(skb, GFP_ATOMIC);
374+ if (!nskb)
375+ return;
376+
377+ len = nskb->len + ETH_HLEN;
378+ nskb->dev = dev;
379+ nskb->pkt_type = PACKET_HOST;
380+
381+ ret = netif_rx(nskb);
382+ macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0);
383+}
384+
385+static void macvlan_forward_source(struct sk_buff *skb,
386+ struct macvlan_port *port,
387+ const unsigned char *addr)
388+{
389+ struct macvlan_source_entry *entry;
390+ u32 idx = macvlan_eth_hash(addr);
391+ struct hlist_head *h = &port->vlan_source_hash[idx];
392+
393+ hlist_for_each_entry_rcu(entry, h, hlist) {
394+ if (ether_addr_equal_64bits(entry->addr, addr))
395+ if (entry->vlan->dev->flags & IFF_UP)
396+ macvlan_forward_source_one(skb, entry->vlan);
397+ }
398+}
399+
270400 /* called under rcu_read_lock() from netif_receive_skb */
271401 static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
272402 {
@@ -285,6 +415,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) · 12 unmodified lines
285415 if (!skb)
286416 return RX_HANDLER_CONSUMED;
287417 eth = eth_hdr(skb);
418+ macvlan_forward_source(skb, port, eth->h_source);
288419 src = macvlan_hash_lookup(port, eth->h_source);
289420 if (src && src->mode != MACVLAN_MODE_VEPA &&
290421 src->mode != MACVLAN_MODE_BRIDGE) {
@@ -301,6 +432,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) · 10 unmodified lines
301432 return RX_HANDLER_PASS;
302433 }
303434
435+ macvlan_forward_source(skb, port, eth->h_source);
304436 if (port->passthru)
305437 vlan = list_first_or_null_rcu(&port->vlans,
306438 struct macvlan_dev, list);
@@ -667,6 +799,7 @@ static void macvlan_uninit(struct net_device *dev) · 360 unmodified lines
667799
668800 free_percpu(vlan->pcpu_stats);
669801
802+ macvlan_flush_sources(port, vlan);
670803 port->count -= 1;
671804 if (!port->count)
672805 macvlan_port_destroy(port->dev);
@@ -925,6 +1058,8 @@ static int macvlan_port_create(struct net_device *dev) · 252 unmodified lines
9251058 INIT_LIST_HEAD(&port->vlans);
9261059 for (i = 0; i < MACVLAN_HASH_SIZE; i++)
9271060 INIT_HLIST_HEAD(&port->vlan_hash[i]);
1061+ for (i = 0; i < MACVLAN_HASH_SIZE; i++)
1062+ INIT_HLIST_HEAD(&port->vlan_source_hash[i]);
9281063
9291064 skb_queue_head_init(&port->bc_queue);
9301065 INIT_WORK(&port->bc_work, macvlan_process_broadcast);
@@ -966,11 +1101,102 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) · 35 unmodified lines
9661101 case MACVLAN_MODE_VEPA:
9671102 case MACVLAN_MODE_BRIDGE:
9681103 case MACVLAN_MODE_PASSTHRU:
1104+ case MACVLAN_MODE_SOURCE:
1105+ break;
1106+ default:
1107+ return -EINVAL;
1108+ }
1109+ }
1110+
1111+ if (data && data[IFLA_MACVLAN_MACADDR_MODE]) {
1112+ switch (nla_get_u32(data[IFLA_MACVLAN_MACADDR_MODE])) {
1113+ case MACVLAN_MACADDR_ADD:
1114+ case MACVLAN_MACADDR_DEL:
1115+ case MACVLAN_MACADDR_FLUSH:
1116+ case MACVLAN_MACADDR_SET:
9691117 break;
9701118 default:
9711119 return -EINVAL;
9721120 }
9731121 }
1122+
1123+ if (data && data[IFLA_MACVLAN_MACADDR]) {
1124+ if (nla_len(data[IFLA_MACVLAN_MACADDR]) != ETH_ALEN)
1125+ return -EINVAL;
1126+
1127+ if (!is_valid_ether_addr(nla_data(data[IFLA_MACVLAN_MACADDR])))
1128+ return -EADDRNOTAVAIL;
1129+ }
1130+
1131+ if (data && data[IFLA_MACVLAN_MACADDR_COUNT])
1132+ return -EINVAL;
1133+
1134+ return 0;
1135+}
1136+
1137+/**
1138+ * reconfigure list of remote source mac address
1139+ * (only for macvlan devices in source mode)
1140+ * Note regarding alignment: all netlink data is aligned to 4 Byte, which
1141+ * suffices for both ether_addr_copy and ether_addr_equal_64bits usage.
1142+ */
1143+static int macvlan_changelink_sources(struct macvlan_dev *vlan, u32 mode,
1144+ struct nlattr *data[])
1145+{
1146+ char *addr = NULL;
1147+ int ret, rem, len;
1148+ struct nlattr *nla, *head;
1149+ struct macvlan_source_entry *entry;
1150+
1151+ if (data[IFLA_MACVLAN_MACADDR])
1152+ addr = nla_data(data[IFLA_MACVLAN_MACADDR]);
1153+
1154+ if (mode == MACVLAN_MACADDR_ADD) {
1155+ if (!addr)
1156+ return -EINVAL;
1157+
1158+ return macvlan_hash_add_source(vlan, addr);
1159+
1160+ } else if (mode == MACVLAN_MACADDR_DEL) {
1161+ if (!addr)
1162+ return -EINVAL;
1163+
1164+ entry = macvlan_hash_lookup_source(vlan, addr);
1165+ if (entry) {
1166+ macvlan_hash_del_source(entry);
1167+ vlan->macaddr_count--;
1168+ }
1169+ } else if (mode == MACVLAN_MACADDR_FLUSH) {
1170+ macvlan_flush_sources(vlan->port, vlan);
1171+ } else if (mode == MACVLAN_MACADDR_SET) {
1172+ macvlan_flush_sources(vlan->port, vlan);
1173+
1174+ if (addr) {
1175+ ret = macvlan_hash_add_source(vlan, addr);
1176+ if (ret)
1177+ return ret;
1178+ }
1179+
1180+ if (!data || !data[IFLA_MACVLAN_MACADDR_DATA])
1181+ return 0;
1182+
1183+ head = nla_data(data[IFLA_MACVLAN_MACADDR_DATA]);
1184+ len = nla_len(data[IFLA_MACVLAN_MACADDR_DATA]);
1185+
1186+ nla_for_each_attr(nla, head, len, rem) {
1187+ if (nla_type(nla) != IFLA_MACVLAN_MACADDR ||
1188+ nla_len(nla) != ETH_ALEN)
1189+ continue;
1190+
1191+ addr = nla_data(nla);
1192+ ret = macvlan_hash_add_source(vlan, addr);
1193+ if (ret)
1194+ return ret;
1195+ }
1196+ } else {
1197+ return -EINVAL;
1198+ }
1199+
9741200 return 0;
9751201 }
9761202
@@ -981,6 +1207,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, · 4 unmodified lines
9811207 struct macvlan_port *port;
9821208 struct net_device *lowerdev;
9831209 int err;
1210+ int macmode;
9841211
9851212 if (!tb[IFLA_LINK])
9861213 return -EINVAL;
@@ -1034,6 +1261,15 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, · 47 unmodified lines
10341261 eth_hw_addr_inherit(dev, lowerdev);
10351262 }
10361263
1264+ if (data && data[IFLA_MACVLAN_MACADDR_MODE]) {
1265+ if (vlan->mode != MACVLAN_MODE_SOURCE)
1266+ return -EINVAL;
1267+ macmode = nla_get_u32(data[IFLA_MACVLAN_MACADDR_MODE]);
1268+ err = macvlan_changelink_sources(vlan, macmode, data);
1269+ if (err)
1270+ return err;
1271+ }
1272+
10371273 port->count += 1;
10381274 err = register_netdevice(dev);
10391275 if (err < 0)
@@ -1070,6 +1306,8 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head) · 30 unmodified lines
10701306 {
10711307 struct macvlan_dev *vlan = netdev_priv(dev);
10721308
1309+ if (vlan->mode == MACVLAN_MODE_SOURCE)
1310+ macvlan_flush_sources(vlan->port, vlan);
10731311 list_del_rcu(&vlan->list);
10741312 unregister_netdevice_queue(dev, head);
10751313 netdev_upper_dev_unlink(vlan->lowerdev, dev);
@@ -1082,6 +1320,8 @@ static int macvlan_changelink(struct net_device *dev, · 6 unmodified lines
10821320 struct macvlan_dev *vlan = netdev_priv(dev);
10831321 enum macvlan_mode mode;
10841322 bool set_mode = false;
1323+ enum macvlan_macaddr_mode macmode;
1324+ int ret;
10851325
10861326 /* Validate mode, but don't set yet: setting flags may fail. */
10871327 if (data && data[IFLA_MACVLAN_MODE]) {
@@ -1091,6 +1331,9 @@ static int macvlan_changelink(struct net_device *dev, · 3 unmodified lines
10911331 if ((mode == MACVLAN_MODE_PASSTHRU) !=
10921332 (vlan->mode == MACVLAN_MODE_PASSTHRU))
10931333 return -EINVAL;
1334+ if (vlan->mode == MACVLAN_MODE_SOURCE &&
1335+ vlan->mode != mode)
1336+ macvlan_flush_sources(vlan->port, vlan);
10941337 }
10951338
10961339 if (data && data[IFLA_MACVLAN_FLAGS]) {
@@ -1110,26 +1353,77 @@ static int macvlan_changelink(struct net_device *dev, · 13 unmodified lines
11101353 }
11111354 if (set_mode)
11121355 vlan->mode = mode;
1356+ if (data && data[IFLA_MACVLAN_MACADDR_MODE]) {
1357+ if (vlan->mode != MACVLAN_MODE_SOURCE)
1358+ return -EINVAL;
1359+ macmode = nla_get_u32(data[IFLA_MACVLAN_MACADDR_MODE]);
1360+ ret = macvlan_changelink_sources(vlan, macmode, data);
1361+ if (ret)
1362+ return ret;
1363+ }
11131364 return 0;
11141365 }
11151366
1367+static size_t macvlan_get_size_mac(const struct macvlan_dev *vlan)
1368+{
1369+ if (vlan->macaddr_count == 0)
1370+ return 0;
1371+ return nla_total_size(0) /* IFLA_MACVLAN_MACADDR_DATA */
1372+ + vlan->macaddr_count * nla_total_size(sizeof(u8) * ETH_ALEN);
1373+}
1374+
11161375 static size_t macvlan_get_size(const struct net_device *dev)
11171376 {
1377+ struct macvlan_dev *vlan = netdev_priv(dev);
1378+
11181379 return (0
11191380 + nla_total_size(4) /* IFLA_MACVLAN_MODE */
11201381 + nla_total_size(2) /* IFLA_MACVLAN_FLAGS */
1382+ + nla_total_size(4) /* IFLA_MACVLAN_MACADDR_COUNT */
1383+ + macvlan_get_size_mac(vlan) /* IFLA_MACVLAN_MACADDR */
11211384 );
11221385 }
11231386
1387+static int macvlan_fill_info_macaddr(struct sk_buff *skb,
1388+ const struct macvlan_dev *vlan,
1389+ const int i)
1390+{
1391+ struct hlist_head *h = &vlan->port->vlan_source_hash[i];
1392+ struct macvlan_source_entry *entry;
1393+
1394+ hlist_for_each_entry_rcu(entry, h, hlist) {
1395+ if (entry->vlan != vlan)
1396+ continue;
1397+ if (nla_put(skb, IFLA_MACVLAN_MACADDR, ETH_ALEN, entry->addr))
1398+ return 1;
1399+ }
1400+ return 0;
1401+}
1402+
11241403 static int macvlan_fill_info(struct sk_buff *skb,
11251404 const struct net_device *dev)
11261405 {
11271406 struct macvlan_dev *vlan = netdev_priv(dev);
1407+ int i;
1408+ struct nlattr *nest;
11281409
11291410 if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode))
11301411 goto nla_put_failure;
11311412 if (nla_put_u16(skb, IFLA_MACVLAN_FLAGS, vlan->flags))
11321413 goto nla_put_failure;
1414+ if (nla_put_u32(skb, IFLA_MACVLAN_MACADDR_COUNT, vlan->macaddr_count))
1415+ goto nla_put_failure;
1416+ if (vlan->macaddr_count > 0) {
1417+ nest = nla_nest_start(skb, IFLA_MACVLAN_MACADDR_DATA);
1418+ if (nest == NULL)
1419+ goto nla_put_failure;
1420+
1421+ for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
1422+ if (macvlan_fill_info_macaddr(skb, vlan, i))
1423+ goto nla_put_failure;
1424+ }
1425+ nla_nest_end(skb, nest);
1426+ }
11331427 return 0;
11341428
11351429 nla_put_failure:
@@ -1139,6 +1433,10 @@ nla_put_failure: · 3 unmodified lines
11391433 static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = {
11401434 [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
11411435 [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
1436+ [IFLA_MACVLAN_MACADDR_MODE] = { .type = NLA_U32 },
1437+ [IFLA_MACVLAN_MACADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1438+ [IFLA_MACVLAN_MACADDR_DATA] = { .type = NLA_NESTED },
1439+ [IFLA_MACVLAN_MACADDR_COUNT] = { .type = NLA_U32 },
11421440 };
11431441
11441442 int macvlan_link_register(struct rtnl_link_ops *ops)
include/linux/if_macvlan.h+1−0
@@ -60,6 +60,7 @@ struct macvlan_dev { · 59 unmodified lines
6060 #ifdef CONFIG_NET_POLL_CONTROLLER
6161 struct netpoll *netpoll;
6262 #endif
63+ unsigned int macaddr_count;
6364 };
6465
6566 static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
include/uapi/linux/if_link.h+12−0
@@ -303,6 +303,10 @@ enum { · 302 unmodified lines
303303 IFLA_MACVLAN_UNSPEC,
304304 IFLA_MACVLAN_MODE,
305305 IFLA_MACVLAN_FLAGS,
306+ IFLA_MACVLAN_MACADDR_MODE,
307+ IFLA_MACVLAN_MACADDR,
308+ IFLA_MACVLAN_MACADDR_DATA,
309+ IFLA_MACVLAN_MACADDR_COUNT,
306310 __IFLA_MACVLAN_MAX,
307311 };
308312
@@ -313,6 +317,14 @@ enum macvlan_mode { · 4 unmodified lines
313317 MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */
314318 MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */
315319 MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
320+ MACVLAN_MODE_SOURCE = 16,/* use source MAC address list to assign */
321+};
322+
323+enum macvlan_macaddr_mode {
324+ MACVLAN_MACADDR_ADD,
325+ MACVLAN_MACADDR_DEL,
326+ MACVLAN_MACADDR_FLUSH,
327+ MACVLAN_MACADDR_SET,
316328 };
317329
318330 #define MACVLAN_FLAG_NOPROMISC 1