diff options
-rw-r--r-- | drivers/net/macvlan.c | 304 | ||||
-rw-r--r-- | include/linux/if_macvlan.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/if_link.h | 12 |
3 files changed, 314 insertions, 3 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 726edabff26b..e8a453f1b458 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c | |||
@@ -35,7 +35,8 @@ | |||
35 | #include <net/xfrm.h> | 35 | #include <net/xfrm.h> |
36 | #include <linux/netpoll.h> | 36 | #include <linux/netpoll.h> |
37 | 37 | ||
38 | #define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE) | 38 | #define MACVLAN_HASH_BITS 8 |
39 | #define MACVLAN_HASH_SIZE (1<<MACVLAN_HASH_BITS) | ||
39 | #define MACVLAN_BC_QUEUE_LEN 1000 | 40 | #define MACVLAN_BC_QUEUE_LEN 1000 |
40 | 41 | ||
41 | struct macvlan_port { | 42 | struct macvlan_port { |
@@ -47,6 +48,14 @@ struct macvlan_port { | |||
47 | struct work_struct bc_work; | 48 | struct work_struct bc_work; |
48 | bool passthru; | 49 | bool passthru; |
49 | int count; | 50 | 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; | ||
50 | }; | 59 | }; |
51 | 60 | ||
52 | struct macvlan_skb_cb { | 61 | struct macvlan_skb_cb { |
@@ -57,6 +66,20 @@ struct macvlan_skb_cb { | |||
57 | 66 | ||
58 | static void macvlan_port_destroy(struct net_device *dev); | 67 | static void macvlan_port_destroy(struct net_device *dev); |
59 | 68 | ||
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 | |||
60 | static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev) | 83 | static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev) |
61 | { | 84 | { |
62 | return rcu_dereference(dev->rx_handler_data); | 85 | return rcu_dereference(dev->rx_handler_data); |
@@ -73,20 +96,68 @@ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port, | |||
73 | const unsigned char *addr) | 96 | const unsigned char *addr) |
74 | { | 97 | { |
75 | struct macvlan_dev *vlan; | 98 | struct macvlan_dev *vlan; |
99 | u32 idx = macvlan_eth_hash(addr); | ||
76 | 100 | ||
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) { |
78 | if (ether_addr_equal_64bits(vlan->dev->dev_addr, addr)) | 102 | if (ether_addr_equal_64bits(vlan->dev->dev_addr, addr)) |
79 | return vlan; | 103 | return vlan; |
80 | } | 104 | } |
81 | return NULL; | 105 | return NULL; |
82 | } | 106 | } |
83 | 107 | ||
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 | |||
84 | static void macvlan_hash_add(struct macvlan_dev *vlan) | 148 | static void macvlan_hash_add(struct macvlan_dev *vlan) |
85 | { | 149 | { |
86 | struct macvlan_port *port = vlan->port; | 150 | struct macvlan_port *port = vlan->port; |
87 | const unsigned char *addr = vlan->dev->dev_addr; | 151 | const unsigned char *addr = vlan->dev->dev_addr; |
152 | u32 idx = macvlan_eth_hash(addr); | ||
88 | 153 | ||
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); | ||
90 | } | 161 | } |
91 | 162 | ||
92 | static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync) | 163 | static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync) |
@@ -267,6 +338,65 @@ err: | |||
267 | atomic_long_inc(&skb->dev->rx_dropped); | 338 | atomic_long_inc(&skb->dev->rx_dropped); |
268 | } | 339 | } |
269 | 340 | ||
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 | |||
270 | /* called under rcu_read_lock() from netif_receive_skb */ | 400 | /* called under rcu_read_lock() from netif_receive_skb */ |
271 | static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) | 401 | static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) |
272 | { | 402 | { |
@@ -285,6 +415,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) | |||
285 | if (!skb) | 415 | if (!skb) |
286 | return RX_HANDLER_CONSUMED; | 416 | return RX_HANDLER_CONSUMED; |
287 | eth = eth_hdr(skb); | 417 | eth = eth_hdr(skb); |
418 | macvlan_forward_source(skb, port, eth->h_source); | ||
288 | src = macvlan_hash_lookup(port, eth->h_source); | 419 | src = macvlan_hash_lookup(port, eth->h_source); |
289 | if (src && src->mode != MACVLAN_MODE_VEPA && | 420 | if (src && src->mode != MACVLAN_MODE_VEPA && |
290 | src->mode != MACVLAN_MODE_BRIDGE) { | 421 | src->mode != MACVLAN_MODE_BRIDGE) { |
@@ -301,6 +432,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) | |||
301 | return RX_HANDLER_PASS; | 432 | return RX_HANDLER_PASS; |
302 | } | 433 | } |
303 | 434 | ||
435 | macvlan_forward_source(skb, port, eth->h_source); | ||
304 | if (port->passthru) | 436 | if (port->passthru) |
305 | vlan = list_first_or_null_rcu(&port->vlans, | 437 | vlan = list_first_or_null_rcu(&port->vlans, |
306 | struct macvlan_dev, list); | 438 | struct macvlan_dev, list); |
@@ -667,6 +799,7 @@ static void macvlan_uninit(struct net_device *dev) | |||
667 | 799 | ||
668 | free_percpu(vlan->pcpu_stats); | 800 | free_percpu(vlan->pcpu_stats); |
669 | 801 | ||
802 | macvlan_flush_sources(port, vlan); | ||
670 | port->count -= 1; | 803 | port->count -= 1; |
671 | if (!port->count) | 804 | if (!port->count) |
672 | macvlan_port_destroy(port->dev); | 805 | macvlan_port_destroy(port->dev); |
@@ -925,6 +1058,8 @@ static int macvlan_port_create(struct net_device *dev) | |||
925 | INIT_LIST_HEAD(&port->vlans); | 1058 | INIT_LIST_HEAD(&port->vlans); |
926 | for (i = 0; i < MACVLAN_HASH_SIZE; i++) | 1059 | for (i = 0; i < MACVLAN_HASH_SIZE; i++) |
927 | INIT_HLIST_HEAD(&port->vlan_hash[i]); | 1060 | 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]); | ||
928 | 1063 | ||
929 | skb_queue_head_init(&port->bc_queue); | 1064 | skb_queue_head_init(&port->bc_queue); |
930 | INIT_WORK(&port->bc_work, macvlan_process_broadcast); | 1065 | INIT_WORK(&port->bc_work, macvlan_process_broadcast); |
@@ -966,11 +1101,102 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
966 | case MACVLAN_MODE_VEPA: | 1101 | case MACVLAN_MODE_VEPA: |
967 | case MACVLAN_MODE_BRIDGE: | 1102 | case MACVLAN_MODE_BRIDGE: |
968 | case MACVLAN_MODE_PASSTHRU: | 1103 | 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: | ||
969 | break; | 1117 | break; |
970 | default: | 1118 | default: |
971 | return -EINVAL; | 1119 | return -EINVAL; |
972 | } | 1120 | } |
973 | } | 1121 | } |
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 | |||
974 | return 0; | 1200 | return 0; |
975 | } | 1201 | } |
976 | 1202 | ||
@@ -981,6 +1207,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, | |||
981 | struct macvlan_port *port; | 1207 | struct macvlan_port *port; |
982 | struct net_device *lowerdev; | 1208 | struct net_device *lowerdev; |
983 | int err; | 1209 | int err; |
1210 | int macmode; | ||
984 | 1211 | ||
985 | if (!tb[IFLA_LINK]) | 1212 | if (!tb[IFLA_LINK]) |
986 | return -EINVAL; | 1213 | return -EINVAL; |
@@ -1034,6 +1261,15 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, | |||
1034 | eth_hw_addr_inherit(dev, lowerdev); | 1261 | eth_hw_addr_inherit(dev, lowerdev); |
1035 | } | 1262 | } |
1036 | 1263 | ||
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 | |||
1037 | port->count += 1; | 1273 | port->count += 1; |
1038 | err = register_netdevice(dev); | 1274 | err = register_netdevice(dev); |
1039 | if (err < 0) | 1275 | if (err < 0) |
@@ -1070,6 +1306,8 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head) | |||
1070 | { | 1306 | { |
1071 | struct macvlan_dev *vlan = netdev_priv(dev); | 1307 | struct macvlan_dev *vlan = netdev_priv(dev); |
1072 | 1308 | ||
1309 | if (vlan->mode == MACVLAN_MODE_SOURCE) | ||
1310 | macvlan_flush_sources(vlan->port, vlan); | ||
1073 | list_del_rcu(&vlan->list); | 1311 | list_del_rcu(&vlan->list); |
1074 | unregister_netdevice_queue(dev, head); | 1312 | unregister_netdevice_queue(dev, head); |
1075 | netdev_upper_dev_unlink(vlan->lowerdev, dev); | 1313 | netdev_upper_dev_unlink(vlan->lowerdev, dev); |
@@ -1082,6 +1320,8 @@ static int macvlan_changelink(struct net_device *dev, | |||
1082 | struct macvlan_dev *vlan = netdev_priv(dev); | 1320 | struct macvlan_dev *vlan = netdev_priv(dev); |
1083 | enum macvlan_mode mode; | 1321 | enum macvlan_mode mode; |
1084 | bool set_mode = false; | 1322 | bool set_mode = false; |
1323 | enum macvlan_macaddr_mode macmode; | ||
1324 | int ret; | ||
1085 | 1325 | ||
1086 | /* Validate mode, but don't set yet: setting flags may fail. */ | 1326 | /* Validate mode, but don't set yet: setting flags may fail. */ |
1087 | if (data && data[IFLA_MACVLAN_MODE]) { | 1327 | if (data && data[IFLA_MACVLAN_MODE]) { |
@@ -1091,6 +1331,9 @@ static int macvlan_changelink(struct net_device *dev, | |||
1091 | if ((mode == MACVLAN_MODE_PASSTHRU) != | 1331 | if ((mode == MACVLAN_MODE_PASSTHRU) != |
1092 | (vlan->mode == MACVLAN_MODE_PASSTHRU)) | 1332 | (vlan->mode == MACVLAN_MODE_PASSTHRU)) |
1093 | return -EINVAL; | 1333 | return -EINVAL; |
1334 | if (vlan->mode == MACVLAN_MODE_SOURCE && | ||
1335 | vlan->mode != mode) | ||
1336 | macvlan_flush_sources(vlan->port, vlan); | ||
1094 | } | 1337 | } |
1095 | 1338 | ||
1096 | if (data && data[IFLA_MACVLAN_FLAGS]) { | 1339 | if (data && data[IFLA_MACVLAN_FLAGS]) { |
@@ -1110,26 +1353,77 @@ static int macvlan_changelink(struct net_device *dev, | |||
1110 | } | 1353 | } |
1111 | if (set_mode) | 1354 | if (set_mode) |
1112 | vlan->mode = mode; | 1355 | 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 | } | ||
1113 | return 0; | 1364 | return 0; |
1114 | } | 1365 | } |
1115 | 1366 | ||
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 | |||
1116 | static size_t macvlan_get_size(const struct net_device *dev) | 1375 | static size_t macvlan_get_size(const struct net_device *dev) |
1117 | { | 1376 | { |
1377 | struct macvlan_dev *vlan = netdev_priv(dev); | ||
1378 | |||
1118 | return (0 | 1379 | return (0 |
1119 | + nla_total_size(4) /* IFLA_MACVLAN_MODE */ | 1380 | + nla_total_size(4) /* IFLA_MACVLAN_MODE */ |
1120 | + nla_total_size(2) /* IFLA_MACVLAN_FLAGS */ | 1381 | + 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 */ | ||
1121 | ); | 1384 | ); |
1122 | } | 1385 | } |
1123 | 1386 | ||
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 | |||
1124 | static int macvlan_fill_info(struct sk_buff *skb, | 1403 | static int macvlan_fill_info(struct sk_buff *skb, |
1125 | const struct net_device *dev) | 1404 | const struct net_device *dev) |
1126 | { | 1405 | { |
1127 | struct macvlan_dev *vlan = netdev_priv(dev); | 1406 | struct macvlan_dev *vlan = netdev_priv(dev); |
1407 | int i; | ||
1408 | struct nlattr *nest; | ||
1128 | 1409 | ||
1129 | if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode)) | 1410 | if (nla_put_u32(skb, IFLA_MACVLAN_MODE, vlan->mode)) |
1130 | goto nla_put_failure; | 1411 | goto nla_put_failure; |
1131 | if (nla_put_u16(skb, IFLA_MACVLAN_FLAGS, vlan->flags)) | 1412 | if (nla_put_u16(skb, IFLA_MACVLAN_FLAGS, vlan->flags)) |
1132 | goto nla_put_failure; | 1413 | 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 | } | ||
1133 | return 0; | 1427 | return 0; |
1134 | 1428 | ||
1135 | nla_put_failure: | 1429 | nla_put_failure: |
@@ -1139,6 +1433,10 @@ nla_put_failure: | |||
1139 | static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { | 1433 | static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { |
1140 | [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, | 1434 | [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, |
1141 | [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 }, | 1435 | [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 }, | ||
1142 | }; | 1440 | }; |
1143 | 1441 | ||
1144 | int macvlan_link_register(struct rtnl_link_ops *ops) | 1442 | int macvlan_link_register(struct rtnl_link_ops *ops) |
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h index 6b2c7cf352a5..6f6929ea8a0c 100644 --- a/include/linux/if_macvlan.h +++ b/include/linux/if_macvlan.h | |||
@@ -60,6 +60,7 @@ struct macvlan_dev { | |||
60 | #ifdef CONFIG_NET_POLL_CONTROLLER | 60 | #ifdef CONFIG_NET_POLL_CONTROLLER |
61 | struct netpoll *netpoll; | 61 | struct netpoll *netpoll; |
62 | #endif | 62 | #endif |
63 | unsigned int macaddr_count; | ||
63 | }; | 64 | }; |
64 | 65 | ||
65 | static inline void macvlan_count_rx(const struct macvlan_dev *vlan, | 66 | static inline void macvlan_count_rx(const struct macvlan_dev *vlan, |
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index c80f95f6ee78..0bdb77e16875 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h | |||
@@ -303,6 +303,10 @@ enum { | |||
303 | IFLA_MACVLAN_UNSPEC, | 303 | IFLA_MACVLAN_UNSPEC, |
304 | IFLA_MACVLAN_MODE, | 304 | IFLA_MACVLAN_MODE, |
305 | IFLA_MACVLAN_FLAGS, | 305 | IFLA_MACVLAN_FLAGS, |
306 | IFLA_MACVLAN_MACADDR_MODE, | ||
307 | IFLA_MACVLAN_MACADDR, | ||
308 | IFLA_MACVLAN_MACADDR_DATA, | ||
309 | IFLA_MACVLAN_MACADDR_COUNT, | ||
306 | __IFLA_MACVLAN_MAX, | 310 | __IFLA_MACVLAN_MAX, |
307 | }; | 311 | }; |
308 | 312 | ||
@@ -313,6 +317,14 @@ enum macvlan_mode { | |||
313 | MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */ | 317 | MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */ |
314 | MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */ | 318 | MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */ |
315 | MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */ | 319 | 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, | ||
316 | }; | 328 | }; |
317 | 329 | ||
318 | #define MACVLAN_FLAG_NOPROMISC 1 | 330 | #define MACVLAN_FLAG_NOPROMISC 1 |