blob: c707ee29726590047e8af10056189cbc9498b822 [file] [log] [blame]
developer8efbb8e2022-10-17 22:55:12 +08001diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
developer0a744a82023-01-10 15:08:53 +08002index 9e8a5c4..d5bf30d 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;
developer0a744a82023-01-10 15:08:53 +080016@@ -933,6 +937,32 @@ 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))) {
developere1abd052022-11-17 14:17:21 +080020+ if (is_multicast_addr(skb) && !is_igmp_mld(skb)) {
developer8efbb8e2022-10-17 22:55:12 +080021+ mdb = vport->mdb;
22+ spin_lock(&mdb->tbl_lock);
23+ list_for_each_entry(table, &mdb->list_head, mdb_node) {
developere1abd052022-11-17 14:17:21 +080024+ if ((key->eth.type == htons(ETH_P_IP) &&
25+ table->group_addr.u.ip4 == key->ipv4.addr.dst) ||
26+ (key->eth.type == htons(ETH_P_IPV6) &&
27+ ipv6_addr_equal(&table->group_addr.u.ip6, &key->ipv6.addr.dst))) {
developer8efbb8e2022-10-17 22:55:12 +080028+ list_for_each_entry(entry, &table->entry_list, entry_node) {
29+ skb_cpy = skb_copy(skb, GFP_ATOMIC);
30+ if (!skb_cpy) {
31+ kfree_skb(skb);
developere1abd052022-11-17 14:17:21 +080032+ pr_err("%s(): skb copy error\n", __func__);
developer8efbb8e2022-10-17 22:55:12 +080033+ spin_unlock(&mdb->tbl_lock);
34+ return;
35+ }
36+ memcpy(skb_cpy->data, entry->eth_addr, ETH_ALEN);
37+ ovs_vport_send(vport, skb_cpy, ovs_key_mac_proto(key));
38+ }
developer0a744a82023-01-10 15:08:53 +080039+ spin_unlock(&mdb->tbl_lock);
40+ kfree_skb(skb);
41+ return;
developer8efbb8e2022-10-17 22:55:12 +080042+ }
43+ }
44+ spin_unlock(&mdb->tbl_lock);
developer0a744a82023-01-10 15:08:53 +080045+ }
46 ovs_vport_send(vport, skb, ovs_key_mac_proto(key));
developer8efbb8e2022-10-17 22:55:12 +080047 } else if (mru <= vport->dev->mtu) {
48 struct net *net = read_pnet(&dp->net);
developer8efbb8e2022-10-17 22:55:12 +080049diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
developer0a744a82023-01-10 15:08:53 +080050index 4f097bd..9a2a8c0 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>
developer0a744a82023-01-10 15:08:53 +080063@@ -530,6 +533,270 @@ 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+
developer0a744a82023-01-10 15:08:53 +0800281+ if ((group_type == MLD2_MODE_IS_EXCLUDE ||
developere1abd052022-11-17 14:17:21 +0800282+ group_type == MLD2_CHANGE_TO_EXCLUDE ||
developer0a744a82023-01-10 15:08:53 +0800283+ group_type == MLD2_ALLOW_NEW_SOURCES) &&
284+ num_of_source == 0)
developere1abd052022-11-17 14:17:21 +0800285+ ovs_multicast_add_group(&group_addr, dl_src, input_vport);
286+ else if ((group_type == MLD2_MODE_IS_INCLUDE ||
287+ group_type == MLD2_CHANGE_TO_INCLUDE ||
288+ group_type == MLD2_BLOCK_OLD_SOURCES) &&
289+ num_of_source == 0)
290+ ovs_multicast_leave_group(&group_addr, dl_src, input_vport);
developer0a744a82023-01-10 15:08:53 +0800291+ else {
292+ pr_info("%s(): group_type(%d), aux_data_len(%d),\
293+ num_of_source(%d), group_addr(%pI6)\n",
294+ __func__, group_type, aux_data_len,
295+ num_of_source, &group_addr.u.ip6);
296+ return 0;
297+ }
298+ grec = (struct mld2_grec *)((u8 *)grec + sizeof(struct mld2_grec)
299+ + aux_data_len * sizeof(u32));
developere1abd052022-11-17 14:17:21 +0800300+ }
301+ break;
302+ case ICMPV6_MGM_QUERY:
303+ break;
developer8efbb8e2022-10-17 22:55:12 +0800304+ default:
developere1abd052022-11-17 14:17:21 +0800305+ pr_warning("%s(): error packet type 0x%x\n", __func__, mld_hdr->mld_type);
developer8efbb8e2022-10-17 22:55:12 +0800306+ break;
307+ }
developere1abd052022-11-17 14:17:21 +0800308+
developer8efbb8e2022-10-17 22:55:12 +0800309+ return 0;
310+}
311+
developere1abd052022-11-17 14:17:21 +0800312+static int ovs_multicast_rcv(struct sk_buff *skb, struct vport *input_vport)
313+{
314+ int ret = 0;
315+
316+ if (!skb)
317+ return -EINVAL;
318+
319+ switch (skb->protocol) {
320+ case htons(ETH_P_IP):
321+ ret = ovs_multicast_ipv4_rcv(skb, input_vport);
322+ break;
323+ case htons(ETH_P_IPV6):
324+ ret = ovs_multicast_ipv6_rcv(skb, input_vport);
325+ break;
326+ }
327+
328+ return ret;
329+}
330+
developer8efbb8e2022-10-17 22:55:12 +0800331 static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
332 {
333 struct ovs_header *ovs_header = info->userhdr;
developer0a744a82023-01-10 15:08:53 +0800334@@ -604,6 +871,9 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
developer8efbb8e2022-10-17 22:55:12 +0800335 OVS_CB(packet)->input_vport = input_vport;
336 sf_acts = rcu_dereference(flow->sf_acts);
337
developere1abd052022-11-17 14:17:21 +0800338+ if (is_multicast_addr(packet))
339+ ovs_multicast_rcv(packet, input_vport);
developer8efbb8e2022-10-17 22:55:12 +0800340+
341 local_bh_disable();
342 err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
343 local_bh_enable();
developer0a744a82023-01-10 15:08:53 +0800344@@ -2183,6 +2453,9 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
developer8efbb8e2022-10-17 22:55:12 +0800345 struct datapath *dp;
346 struct vport *vport;
347 unsigned int new_headroom;
348+ struct multicast_data_base *mdb;
349+ struct multicast_table *table, *table_tmp;
350+ struct multicast_table_entry *entry, *entry_tmp;
351 int err;
352
353 reply = ovs_vport_cmd_alloc_info();
developer0a744a82023-01-10 15:08:53 +0800354@@ -2210,6 +2483,22 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
developer8efbb8e2022-10-17 22:55:12 +0800355 if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
356 update_headroom = true;
357
358+ mdb = vport->mdb;
359+ spin_lock(&mdb->tbl_lock);
360+ list_for_each_entry_safe(table, table_tmp, &mdb->list_head, mdb_node) {
361+ list_for_each_entry_safe(entry, entry_tmp, &table->entry_list, entry_node) {
362+ list_del(&entry->entry_node);
363+ kfree(entry);
364+
365+ if (list_empty(&table->entry_list)) {
366+ list_del(&table->mdb_node);
367+ kfree(table);
368+ }
369+ }
370+ }
371+ spin_unlock(&mdb->tbl_lock);
372+ kfree(mdb);
373+
374 netdev_reset_rx_headroom(vport->dev);
375 ovs_dp_detach_port(vport);
376
377diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
developere1abd052022-11-17 14:17:21 +0800378index 81e85dd..6830d3b 100644
developer8efbb8e2022-10-17 22:55:12 +0800379--- a/net/openvswitch/datapath.h
380+++ b/net/openvswitch/datapath.h
developere1abd052022-11-17 14:17:21 +0800381@@ -215,6 +215,38 @@ static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
developer8efbb8e2022-10-17 22:55:12 +0800382 return dp;
383 }
384
developere1abd052022-11-17 14:17:21 +0800385+static inline bool is_multicast_addr(struct sk_buff *skb)
developer8efbb8e2022-10-17 22:55:12 +0800386+{
developere1abd052022-11-17 14:17:21 +0800387+ struct ethhdr *eth_hdr;
developer8efbb8e2022-10-17 22:55:12 +0800388+
developere1abd052022-11-17 14:17:21 +0800389+ if (!skb)
390+ return 0;
391+
392+ eth_hdr = skb_eth_hdr(skb);
393+
394+ return (eth_hdr->h_dest[0] == 0x01 && skb->protocol == htons(ETH_P_IP)) ||
395+ (eth_hdr->h_dest[0] == 0x33 && skb->protocol == htons(ETH_P_IPV6));
developer8efbb8e2022-10-17 22:55:12 +0800396+}
397+
developere1abd052022-11-17 14:17:21 +0800398+static inline bool is_igmp_mld(struct sk_buff *skb)
developer8efbb8e2022-10-17 22:55:12 +0800399+{
400+ struct ethhdr *eth_hdr;
developere1abd052022-11-17 14:17:21 +0800401+ int err = 0;
developer8efbb8e2022-10-17 22:55:12 +0800402+
403+ if (!skb)
developere1abd052022-11-17 14:17:21 +0800404+ return err;
developer8efbb8e2022-10-17 22:55:12 +0800405+
406+ eth_hdr = skb_eth_hdr(skb);
407+
developere1abd052022-11-17 14:17:21 +0800408+ if (skb->protocol == htons(ETH_P_IP)) {
409+ err = ip_hdr(skb)->protocol == IPPROTO_IGMP;
410+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
411+ err = !ipv6_mc_check_mld(skb);
412+ }
413+
414+ return err;
developer8efbb8e2022-10-17 22:55:12 +0800415+}
416+
417 extern struct notifier_block ovs_dp_device_notifier;
418 extern struct genl_family dp_vport_genl_family;
419
420diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
421index 19af0ef..77bc923 100644
422--- a/net/openvswitch/vport.c
423+++ b/net/openvswitch/vport.c
424@@ -141,6 +141,14 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
425 return ERR_PTR(-EINVAL);
426 }
427
428+ vport->mdb = kzalloc(sizeof(struct multicast_data_base), GFP_KERNEL);
429+ if (!vport->mdb) {
430+ kfree(vport);
431+ return ERR_PTR(-ENOMEM);
432+ }
433+ INIT_LIST_HEAD(&vport->mdb->list_head);
434+ spin_lock_init(&vport->mdb->tbl_lock);
435+
436 return vport;
437 }
438 EXPORT_SYMBOL_GPL(ovs_vport_alloc);
439diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
440index 1eb7495..eb69d6c 100644
441--- a/net/openvswitch/vport.h
442+++ b/net/openvswitch/vport.h
443@@ -55,6 +55,30 @@ struct vport_portids {
444 u32 ids[];
445 };
446
447+struct ip_addr {
448+ union {
449+ __be32 ip4;
450+ struct in6_addr ip6;
451+ } u;
452+};
453+
454+struct multicast_table_entry {
455+ struct list_head entry_node;
456+ u8 eth_addr[ETH_ALEN];
457+};
458+
459+struct multicast_table {
460+ struct list_head mdb_node;
461+ struct list_head entry_list;
462+ struct ip_addr group_addr;
463+};
464+
465+struct multicast_data_base {
466+ struct list_head list_head;
467+ spinlock_t tbl_lock;
468+};
469+
470+
471 /**
472 * struct vport - one port within a datapath
473 * @dev: Pointer to net_device.
474@@ -79,6 +103,8 @@ struct vport {
475
476 struct list_head detach_list;
477 struct rcu_head rcu;
478+
479+ struct multicast_data_base *mdb;
480 };
481
482 /**