blob: b3dd782260abbfed3cd6b195f6789dd6a2c6f78a [file] [log] [blame]
developer8efbb8e2022-10-17 22:55:12 +08001diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
developere1abd052022-11-17 14:17:21 +08002index 9e8a5c4..9104255 100644
developer8efbb8e2022-10-17 22:55:12 +08003--- a/net/openvswitch/actions.c
4+++ b/net/openvswitch/actions.c
5@@ -919,6 +919,10 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
6 struct sw_flow_key *key)
7 {
8 struct vport *vport = ovs_vport_rcu(dp, out_port);
9+ struct multicast_data_base *mdb;
10+ struct multicast_table *table;
11+ struct multicast_table_entry *entry;
12+ struct sk_buff *skb_cpy;
13
14 if (likely(vport)) {
15 u16 mru = OVS_CB(skb)->mru;
developere1abd052022-11-17 14:17:21 +080016@@ -933,7 +937,31 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
developer8efbb8e2022-10-17 22:55:12 +080017
18 if (likely(!mru ||
19 (skb->len <= mru + vport->dev->hard_header_len))) {
20- ovs_vport_send(vport, skb, ovs_key_mac_proto(key));
developere1abd052022-11-17 14:17:21 +080021+ if (is_multicast_addr(skb) && !is_igmp_mld(skb)) {
developer8efbb8e2022-10-17 22:55:12 +080022+ mdb = vport->mdb;
23+ spin_lock(&mdb->tbl_lock);
24+ list_for_each_entry(table, &mdb->list_head, mdb_node) {
developere1abd052022-11-17 14:17:21 +080025+ if ((key->eth.type == htons(ETH_P_IP) &&
26+ table->group_addr.u.ip4 == key->ipv4.addr.dst) ||
27+ (key->eth.type == htons(ETH_P_IPV6) &&
28+ ipv6_addr_equal(&table->group_addr.u.ip6, &key->ipv6.addr.dst))) {
developer8efbb8e2022-10-17 22:55:12 +080029+ list_for_each_entry(entry, &table->entry_list, entry_node) {
30+ skb_cpy = skb_copy(skb, GFP_ATOMIC);
31+ if (!skb_cpy) {
32+ kfree_skb(skb);
developere1abd052022-11-17 14:17:21 +080033+ pr_err("%s(): skb copy error\n", __func__);
developer8efbb8e2022-10-17 22:55:12 +080034+ spin_unlock(&mdb->tbl_lock);
35+ return;
36+ }
37+ memcpy(skb_cpy->data, entry->eth_addr, ETH_ALEN);
38+ ovs_vport_send(vport, skb_cpy, ovs_key_mac_proto(key));
39+ }
40+ }
41+ }
42+ spin_unlock(&mdb->tbl_lock);
43+ kfree_skb(skb);
44+ } else
45+ ovs_vport_send(vport, skb, ovs_key_mac_proto(key));
46 } else if (mru <= vport->dev->mtu) {
47 struct net *net = read_pnet(&dp->net);
48
49diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
developere1abd052022-11-17 14:17:21 +080050index 4f097bd..2f39f07 100644
developer8efbb8e2022-10-17 22:55:12 +080051--- a/net/openvswitch/datapath.c
52+++ b/net/openvswitch/datapath.c
developere1abd052022-11-17 14:17:21 +080053@@ -11,6 +11,9 @@
developer8efbb8e2022-10-17 22:55:12 +080054 #include <linux/if_vlan.h>
55 #include <linux/in.h>
56 #include <linux/ip.h>
57+#include <linux/igmp.h>
developere1abd052022-11-17 14:17:21 +080058+#include <net/mld.h>
59+#include <linux/icmpv6.h>
developer8efbb8e2022-10-17 22:55:12 +080060 #include <linux/jhash.h>
61 #include <linux/delay.h>
62 #include <linux/time.h>
developere1abd052022-11-17 14:17:21 +080063@@ -530,6 +533,262 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
developer8efbb8e2022-10-17 22:55:12 +080064 return err;
65 }
66
developere1abd052022-11-17 14:17:21 +080067+static int ovs_multicast_add_group(struct ip_addr *_group_addr,
68+ const u8 *entry_addr,
69+ struct vport *input_vport)
developer8efbb8e2022-10-17 22:55:12 +080070+{
71+ struct multicast_data_base *mdb;
72+ struct multicast_table *table;
73+ struct multicast_table_entry *entry;
developere1abd052022-11-17 14:17:21 +080074+ int err;
developer8efbb8e2022-10-17 22:55:12 +080075+
76+ mdb = input_vport->mdb;
77+ spin_lock(&mdb->tbl_lock);
78+ list_for_each_entry(table, &mdb->list_head, mdb_node) {
developere1abd052022-11-17 14:17:21 +080079+ if (!memcmp(&table->group_addr.u, &_group_addr->u, sizeof(struct ip_addr))) {
developer8efbb8e2022-10-17 22:55:12 +080080+ list_for_each_entry(entry, &table->entry_list, entry_node) {
developere1abd052022-11-17 14:17:21 +080081+ if (ether_addr_equal(entry->eth_addr, entry_addr))
82+ goto out;
developer8efbb8e2022-10-17 22:55:12 +080083+ }
developere1abd052022-11-17 14:17:21 +080084+
developer8efbb8e2022-10-17 22:55:12 +080085+ entry = kzalloc(sizeof(struct multicast_table_entry), GFP_ATOMIC);
86+ if (!entry) {
developere1abd052022-11-17 14:17:21 +080087+ err = -ENOMEM;
88+ goto err;
developer8efbb8e2022-10-17 22:55:12 +080089+ }
90+
91+ memcpy(entry->eth_addr, entry_addr, ETH_ALEN);
92+ list_add(&entry->entry_node, &table->entry_list);
developere1abd052022-11-17 14:17:21 +080093+ goto out;
developer8efbb8e2022-10-17 22:55:12 +080094+ }
95+ }
96+
97+ table = kzalloc(sizeof(struct multicast_table), GFP_ATOMIC);
98+ if (!table) {
developere1abd052022-11-17 14:17:21 +080099+ err = -ENOMEM;
100+ goto err;
developer8efbb8e2022-10-17 22:55:12 +0800101+ }
102+
103+ INIT_LIST_HEAD(&table->entry_list);
104+ entry = kzalloc(sizeof(struct multicast_table_entry), GFP_ATOMIC);
105+ if (!entry) {
106+ kfree(table);
developere1abd052022-11-17 14:17:21 +0800107+ err = -ENOMEM;
108+ goto err;
developer8efbb8e2022-10-17 22:55:12 +0800109+ }
110+
111+ memcpy(entry->eth_addr, entry_addr, ETH_ALEN);
112+ list_add(&entry->entry_node, &table->entry_list);
113+
developere1abd052022-11-17 14:17:21 +0800114+ table->group_addr.u = _group_addr->u;
developer8efbb8e2022-10-17 22:55:12 +0800115+ list_add(&table->mdb_node, &mdb->list_head);
116+
developere1abd052022-11-17 14:17:21 +0800117+out:
118+ err = 0;
119+err:
developer8efbb8e2022-10-17 22:55:12 +0800120+ spin_unlock(&mdb->tbl_lock);
developere1abd052022-11-17 14:17:21 +0800121+ return err;
developer8efbb8e2022-10-17 22:55:12 +0800122+}
123+
developere1abd052022-11-17 14:17:21 +0800124+static int ovs_multicast_leave_group(struct ip_addr *_group_addr,
125+ const u8 *entry_addr,
126+ struct vport *input_vport)
developer8efbb8e2022-10-17 22:55:12 +0800127+{
128+ struct multicast_data_base *mdb;
129+ struct multicast_table *table, *table_tmp;
130+ struct multicast_table_entry *entry, *entry_tmp;
developere1abd052022-11-17 14:17:21 +0800131+ int err;
developer8efbb8e2022-10-17 22:55:12 +0800132+
133+ mdb = input_vport->mdb;
134+ spin_lock(&mdb->tbl_lock);
135+ list_for_each_entry_safe(table, table_tmp, &mdb->list_head, mdb_node) {
developere1abd052022-11-17 14:17:21 +0800136+ if (!memcmp(&table->group_addr.u, &_group_addr->u, sizeof(struct ip_addr))) {
developer8efbb8e2022-10-17 22:55:12 +0800137+ list_for_each_entry_safe(entry, entry_tmp, &table->entry_list, entry_node) {
developere1abd052022-11-17 14:17:21 +0800138+ if (ether_addr_equal(entry->eth_addr, entry_addr)) {
developer8efbb8e2022-10-17 22:55:12 +0800139+ list_del(&entry->entry_node);
140+ kfree(entry);
141+
142+ if (list_empty(&table->entry_list)) {
143+ list_del(&table->mdb_node);
144+ kfree(table);
145+ }
developere1abd052022-11-17 14:17:21 +0800146+
147+ goto out;
developer8efbb8e2022-10-17 22:55:12 +0800148+ }
149+ }
150+ }
151+ }
developere1abd052022-11-17 14:17:21 +0800152+
153+out:
154+ err = 0;
developer8efbb8e2022-10-17 22:55:12 +0800155+ spin_unlock(&mdb->tbl_lock);
developere1abd052022-11-17 14:17:21 +0800156+ return err;
developer8efbb8e2022-10-17 22:55:12 +0800157+}
158+
159+static int ovs_multicast_ipv4_rcv(struct sk_buff *skb, struct vport *input_vport)
160+{
161+ struct ethhdr *eth_hdr;
162+ const u8 *dl_src;
developere1abd052022-11-17 14:17:21 +0800163+ struct ip_addr group_addr = {0};
developer8efbb8e2022-10-17 22:55:12 +0800164+ struct iphdr *ip_header;
developere1abd052022-11-17 14:17:21 +0800165+ struct igmphdr *igmp_header;
developer8efbb8e2022-10-17 22:55:12 +0800166+ int i;
167+ struct igmpv3_report *igmpv3_hdr;
168+ u16 group_num;
169+ struct igmpv3_grec *grec;
170+ u8 group_type;
171+ u8 aux_data_len;
172+ u16 num_of_source;
173+ int err;
174+
175+ err = ip_mc_check_igmp(skb);
developere1abd052022-11-17 14:17:21 +0800176+ if (err)
developer8efbb8e2022-10-17 22:55:12 +0800177+ return 0;
178+
179+ eth_hdr = skb_eth_hdr(skb);
180+ dl_src = eth_hdr->h_source;
developere1abd052022-11-17 14:17:21 +0800181+ ip_header = ip_hdr(skb);
182+ igmp_header = igmp_hdr(skb);
developer8efbb8e2022-10-17 22:55:12 +0800183+
developere1abd052022-11-17 14:17:21 +0800184+ switch (igmp_header->type) {
developer8efbb8e2022-10-17 22:55:12 +0800185+ case IGMP_HOST_MEMBERSHIP_REPORT:
186+ case IGMPV2_HOST_MEMBERSHIP_REPORT:
developere1abd052022-11-17 14:17:21 +0800187+ group_addr.u.ip4 = igmp_header->group;
188+ if (ipv4_is_local_multicast(group_addr.u.ip4))
189+ return 0;
190+ ovs_multicast_add_group(&group_addr, dl_src, input_vport);
developer8efbb8e2022-10-17 22:55:12 +0800191+ break;
192+ case IGMP_HOST_LEAVE_MESSAGE:
developere1abd052022-11-17 14:17:21 +0800193+ group_addr.u.ip4 = igmp_header->group;
194+ if (ipv4_is_local_multicast(group_addr.u.ip4))
195+ return 0;
196+ ovs_multicast_leave_group(&group_addr, dl_src, input_vport);
developer8efbb8e2022-10-17 22:55:12 +0800197+ break;
198+ case IGMPV3_HOST_MEMBERSHIP_REPORT:
developere1abd052022-11-17 14:17:21 +0800199+ igmpv3_hdr = (struct igmpv3_report *)igmp_header;
developer8efbb8e2022-10-17 22:55:12 +0800200+ group_num = ntohs(igmpv3_hdr->ngrec);
201+ grec = igmpv3_hdr->grec;
developere1abd052022-11-17 14:17:21 +0800202+
developer8efbb8e2022-10-17 22:55:12 +0800203+ for (i = 0; i < group_num; i++) {
204+ group_type = grec->grec_type;
205+ aux_data_len = grec->grec_auxwords;
206+ num_of_source = ntohs(grec->grec_nsrcs);
developere1abd052022-11-17 14:17:21 +0800207+ group_addr.u.ip4 = grec->grec_mca;
208+ if (ipv4_is_local_multicast(group_addr.u.ip4))
209+ return 0;
developer8efbb8e2022-10-17 22:55:12 +0800210+
211+ if (group_type == IGMPV3_MODE_IS_EXCLUDE ||
212+ group_type == IGMPV3_CHANGE_TO_EXCLUDE ||
213+ group_type == IGMPV3_ALLOW_NEW_SOURCES)
developere1abd052022-11-17 14:17:21 +0800214+ ovs_multicast_add_group(&group_addr, dl_src, input_vport);
developer8efbb8e2022-10-17 22:55:12 +0800215+
216+ if (group_type == IGMPV3_MODE_IS_INCLUDE ||
217+ group_type == IGMPV3_CHANGE_TO_INCLUDE ||
218+ group_type == IGMPV3_BLOCK_OLD_SOURCES)
219+ if (num_of_source == 0)
developere1abd052022-11-17 14:17:21 +0800220+ ovs_multicast_leave_group(&group_addr, dl_src, input_vport);
developer8efbb8e2022-10-17 22:55:12 +0800221+
222+ grec += (8 + (num_of_source * 4) + aux_data_len);
223+ }
224+ break;
developere1abd052022-11-17 14:17:21 +0800225+ case IGMP_HOST_MEMBERSHIP_QUERY:
226+ break;
227+ default:
228+ pr_warning("%s(): error packet type 0x%x\n", __func__, igmp_header->type);
229+ break;
230+ }
231+ return 0;
232+}
233+
234+static int ovs_multicast_ipv6_rcv(struct sk_buff *skb, struct vport *input_vport)
235+{
236+ const u8 *dl_src;
237+ struct mld_msg *mld_hdr;
238+ struct ip_addr group_addr = {0};
239+ struct icmp6hdr *icmpv6_hdr;
240+ u16 group_num;
241+ struct mld2_grec *grec;
242+ u8 group_type;
243+ u8 aux_data_len;
244+ u16 num_of_source;
245+ int i;
246+ int err;
247+
248+ err = ipv6_mc_check_mld(skb);
249+ if (err)
250+ return err;
251+
252+ mld_hdr = (struct mld_msg *)skb_transport_header(skb);
253+ dl_src = skb_eth_hdr(skb)->h_source;
254+
255+ switch (mld_hdr->mld_type) {
256+ case ICMPV6_MGM_REPORT:
257+ group_addr.u.ip6 = mld_hdr->mld_mca;
258+ if (ipv6_addr_is_ll_all_nodes(&group_addr.u.ip6))
259+ return 0;
260+ ovs_multicast_add_group(&group_addr, dl_src, input_vport);
261+ break;
262+ case ICMPV6_MGM_REDUCTION:
263+ group_addr.u.ip6 = mld_hdr->mld_mca;
264+ if (ipv6_addr_is_ll_all_nodes(&group_addr.u.ip6))
265+ return 0;
266+ ovs_multicast_leave_group(&group_addr, dl_src, input_vport);
267+ break;
268+ case ICMPV6_MLD2_REPORT:
269+ icmpv6_hdr = icmp6_hdr(skb);
270+ group_num = ntohs(icmpv6_hdr->icmp6_dataun.un_data16[1]);
271+ grec = (struct mld2_grec *)(skb_transport_header(skb) + sizeof(struct icmp6hdr));
272+
273+ for (i = 0; i < group_num; i++) {
274+ group_type = grec->grec_type;
275+ aux_data_len = grec->grec_auxwords;
276+ num_of_source = ntohs(grec->grec_nsrcs);
277+ group_addr.u.ip6 = grec->grec_mca;
278+ if (ipv6_addr_is_ll_all_nodes(&group_addr.u.ip6))
279+ return 0;
280+
281+ if (group_type == MLD2_MODE_IS_EXCLUDE ||
282+ group_type == MLD2_CHANGE_TO_EXCLUDE ||
283+ group_type == MLD2_ALLOW_NEW_SOURCES)
284+ ovs_multicast_add_group(&group_addr, dl_src, input_vport);
285+ else if ((group_type == MLD2_MODE_IS_INCLUDE ||
286+ group_type == MLD2_CHANGE_TO_INCLUDE ||
287+ group_type == MLD2_BLOCK_OLD_SOURCES) &&
288+ num_of_source == 0)
289+ ovs_multicast_leave_group(&group_addr, dl_src, input_vport);
290+
291+ grec += (4 + (num_of_source + 1) * sizeof(struct in6_addr) + aux_data_len);
292+ }
293+ break;
294+ case ICMPV6_MGM_QUERY:
295+ break;
developer8efbb8e2022-10-17 22:55:12 +0800296+ default:
developere1abd052022-11-17 14:17:21 +0800297+ pr_warning("%s(): error packet type 0x%x\n", __func__, mld_hdr->mld_type);
developer8efbb8e2022-10-17 22:55:12 +0800298+ break;
299+ }
developere1abd052022-11-17 14:17:21 +0800300+
developer8efbb8e2022-10-17 22:55:12 +0800301+ return 0;
302+}
303+
developere1abd052022-11-17 14:17:21 +0800304+static int ovs_multicast_rcv(struct sk_buff *skb, struct vport *input_vport)
305+{
306+ int ret = 0;
307+
308+ if (!skb)
309+ return -EINVAL;
310+
311+ switch (skb->protocol) {
312+ case htons(ETH_P_IP):
313+ ret = ovs_multicast_ipv4_rcv(skb, input_vport);
314+ break;
315+ case htons(ETH_P_IPV6):
316+ ret = ovs_multicast_ipv6_rcv(skb, input_vport);
317+ break;
318+ }
319+
320+ return ret;
321+}
322+
developer8efbb8e2022-10-17 22:55:12 +0800323 static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
324 {
325 struct ovs_header *ovs_header = info->userhdr;
developere1abd052022-11-17 14:17:21 +0800326@@ -604,6 +863,9 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
developer8efbb8e2022-10-17 22:55:12 +0800327 OVS_CB(packet)->input_vport = input_vport;
328 sf_acts = rcu_dereference(flow->sf_acts);
329
developere1abd052022-11-17 14:17:21 +0800330+ if (is_multicast_addr(packet))
331+ ovs_multicast_rcv(packet, input_vport);
developer8efbb8e2022-10-17 22:55:12 +0800332+
333 local_bh_disable();
334 err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
335 local_bh_enable();
developere1abd052022-11-17 14:17:21 +0800336@@ -2183,6 +2445,9 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
developer8efbb8e2022-10-17 22:55:12 +0800337 struct datapath *dp;
338 struct vport *vport;
339 unsigned int new_headroom;
340+ struct multicast_data_base *mdb;
341+ struct multicast_table *table, *table_tmp;
342+ struct multicast_table_entry *entry, *entry_tmp;
343 int err;
344
345 reply = ovs_vport_cmd_alloc_info();
developere1abd052022-11-17 14:17:21 +0800346@@ -2210,6 +2475,22 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
developer8efbb8e2022-10-17 22:55:12 +0800347 if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
348 update_headroom = true;
349
350+ mdb = vport->mdb;
351+ spin_lock(&mdb->tbl_lock);
352+ list_for_each_entry_safe(table, table_tmp, &mdb->list_head, mdb_node) {
353+ list_for_each_entry_safe(entry, entry_tmp, &table->entry_list, entry_node) {
354+ list_del(&entry->entry_node);
355+ kfree(entry);
356+
357+ if (list_empty(&table->entry_list)) {
358+ list_del(&table->mdb_node);
359+ kfree(table);
360+ }
361+ }
362+ }
363+ spin_unlock(&mdb->tbl_lock);
364+ kfree(mdb);
365+
366 netdev_reset_rx_headroom(vport->dev);
367 ovs_dp_detach_port(vport);
368
369diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
developere1abd052022-11-17 14:17:21 +0800370index 81e85dd..6830d3b 100644
developer8efbb8e2022-10-17 22:55:12 +0800371--- a/net/openvswitch/datapath.h
372+++ b/net/openvswitch/datapath.h
developere1abd052022-11-17 14:17:21 +0800373@@ -215,6 +215,38 @@ static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
developer8efbb8e2022-10-17 22:55:12 +0800374 return dp;
375 }
376
developere1abd052022-11-17 14:17:21 +0800377+static inline bool is_multicast_addr(struct sk_buff *skb)
developer8efbb8e2022-10-17 22:55:12 +0800378+{
developere1abd052022-11-17 14:17:21 +0800379+ struct ethhdr *eth_hdr;
developer8efbb8e2022-10-17 22:55:12 +0800380+
developere1abd052022-11-17 14:17:21 +0800381+ if (!skb)
382+ return 0;
383+
384+ eth_hdr = skb_eth_hdr(skb);
385+
386+ return (eth_hdr->h_dest[0] == 0x01 && skb->protocol == htons(ETH_P_IP)) ||
387+ (eth_hdr->h_dest[0] == 0x33 && skb->protocol == htons(ETH_P_IPV6));
developer8efbb8e2022-10-17 22:55:12 +0800388+}
389+
developere1abd052022-11-17 14:17:21 +0800390+static inline bool is_igmp_mld(struct sk_buff *skb)
developer8efbb8e2022-10-17 22:55:12 +0800391+{
392+ struct ethhdr *eth_hdr;
developere1abd052022-11-17 14:17:21 +0800393+ int err = 0;
developer8efbb8e2022-10-17 22:55:12 +0800394+
395+ if (!skb)
developere1abd052022-11-17 14:17:21 +0800396+ return err;
developer8efbb8e2022-10-17 22:55:12 +0800397+
398+ eth_hdr = skb_eth_hdr(skb);
399+
developere1abd052022-11-17 14:17:21 +0800400+ if (skb->protocol == htons(ETH_P_IP)) {
401+ err = ip_hdr(skb)->protocol == IPPROTO_IGMP;
402+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
403+ err = !ipv6_mc_check_mld(skb);
404+ }
405+
406+ return err;
developer8efbb8e2022-10-17 22:55:12 +0800407+}
408+
409 extern struct notifier_block ovs_dp_device_notifier;
410 extern struct genl_family dp_vport_genl_family;
411
412diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
413index 19af0ef..77bc923 100644
414--- a/net/openvswitch/vport.c
415+++ b/net/openvswitch/vport.c
416@@ -141,6 +141,14 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
417 return ERR_PTR(-EINVAL);
418 }
419
420+ vport->mdb = kzalloc(sizeof(struct multicast_data_base), GFP_KERNEL);
421+ if (!vport->mdb) {
422+ kfree(vport);
423+ return ERR_PTR(-ENOMEM);
424+ }
425+ INIT_LIST_HEAD(&vport->mdb->list_head);
426+ spin_lock_init(&vport->mdb->tbl_lock);
427+
428 return vport;
429 }
430 EXPORT_SYMBOL_GPL(ovs_vport_alloc);
431diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
432index 1eb7495..eb69d6c 100644
433--- a/net/openvswitch/vport.h
434+++ b/net/openvswitch/vport.h
435@@ -55,6 +55,30 @@ struct vport_portids {
436 u32 ids[];
437 };
438
439+struct ip_addr {
440+ union {
441+ __be32 ip4;
442+ struct in6_addr ip6;
443+ } u;
444+};
445+
446+struct multicast_table_entry {
447+ struct list_head entry_node;
448+ u8 eth_addr[ETH_ALEN];
449+};
450+
451+struct multicast_table {
452+ struct list_head mdb_node;
453+ struct list_head entry_list;
454+ struct ip_addr group_addr;
455+};
456+
457+struct multicast_data_base {
458+ struct list_head list_head;
459+ spinlock_t tbl_lock;
460+};
461+
462+
463 /**
464 * struct vport - one port within a datapath
465 * @dev: Pointer to net_device.
466@@ -79,6 +103,8 @@ struct vport {
467
468 struct list_head detach_list;
469 struct rcu_head rcu;
470+
471+ struct multicast_data_base *mdb;
472 };
473
474 /**