forked from iqiyi/dpvs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path0001-kni-use-netlink-event-for-multicast-driver-part.patch
124 lines (115 loc) · 4.09 KB
/
0001-kni-use-netlink-event-for-multicast-driver-part.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
From 659c6e84e3ae0c5e5b93894aa15dd4983b3ac6c3 Mon Sep 17 00:00:00 2001
From: ywc689 <[email protected]>
Date: Fri, 28 Jun 2019 16:52:24 +0800
Subject: [PATCH 1/3] kni: use netlink event for multicast (driver part)
kni driver send netlink event every time hw-multicast list updated by
kernel, the user kni app should capture the event and update multicast
to kni device.
original way is using rte_kni_request to pass hw-multicast to user kni
module. that method works but finally memory corruption found, which is
to kni device.
---
kernel/linux/kni/kni_net.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/kernel/linux/kni/kni_net.c b/kernel/linux/kni/kni_net.c
index 7371b6d..edc1416 100644
--- a/kernel/linux/kni/kni_net.c
+++ b/kernel/linux/kni/kni_net.c
@@ -16,6 +16,8 @@
#include <linux/skbuff.h>
#include <linux/kthread.h>
#include <linux/delay.h>
+#include <linux/inetdevice.h>
+#include <net/netlink.h>
#include <exec-env/rte_kni_common.h>
#include <kni_fifo.h>
@@ -103,6 +105,7 @@
ret_val = wait_event_interruptible_timeout(kni->wq,
kni_fifo_count(kni->resp_q), 3 * HZ);
if (signal_pending(current) || ret_val <= 0) {
+ pr_err("%s: wait_event_interruptible timeout\n", __func__);
ret = -ETIME;
goto fail;
}
@@ -605,9 +608,75 @@ void kni_net_release_fifo_phy(struct kni_dev *kni)
return -EOPNOTSUPP;
}
+static size_t
+kni_nlmsg_size(void)
+{
+ return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
+ + nla_total_size(4) /* IFA_ADDRESS */
+ + nla_total_size(4) /* IFA_LOCAL */
+ + nla_total_size(4) /* IFA_BROADCAST */
+ + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
+ + nla_total_size(4) /* IFA_FLAGS */
+ + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
+}
+
static void
kni_net_set_rx_mode(struct net_device *dev)
{
+ /*
+ * send event to notify user (DPDK KNI app) that multicast list changed,
+ * so that it can monitor multicast join/leave and set HW mc-addrs to
+ * kni dev accordinglly.
+ *
+ * this event is just an notification, we do not save any mc-addr here
+ * (so attribute space for us). user kni app should get maddrs after
+ * receive this notification.
+ *
+ * I was expecting kernel send some rtnl event for multicast join/leave,
+ * but it doesn't. By checking the call-chain of SIOCADDMULTI (ip maddr,
+ * manages only hardware multicast) and IP_ADD_MEMBERSHIP (ip_mc_join_group,
+ * used to for IPv4 multicast), no rtnl event sent.
+ *
+ * so as workaround, modify kni driver here to send RTM_NEWADDR.
+ * it may not suitalbe to use this event for mcast, but that should works.
+ * hope that won't affect other listener to this event.
+ *
+ * previous solution was using rte_kni_request to pass hw-maddr list to user.
+ * it "works" for times but finally memory corruption found, which is
+ * not easy to address (lock was added and reviewed). That's why we use
+ * netlink event instead.
+ */
+ struct sk_buff *skb;
+ struct net *net = dev_net(dev);
+ struct nlmsghdr *nlh;
+ struct ifaddrmsg *ifm;
+
+ skb = nlmsg_new(kni_nlmsg_size(), GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ /* no other event for us ? */
+ nlh = nlmsg_put(skb, 0, 0, RTM_NEWADDR, sizeof(*ifm), 0);
+ if (!nlh) {
+ kfree_skb(skb);
+ return;
+ }
+
+ /* just send an notification so no other info */
+ ifm = nlmsg_data(nlh);
+ memset(ifm, 0, sizeof(*ifm));
+ ifm->ifa_family = AF_UNSPEC;
+ ifm->ifa_prefixlen = 0;
+ ifm->ifa_flags = 0;
+ ifm->ifa_scope = RT_SCOPE_NOWHERE;
+ ifm->ifa_index = 0;
+
+ nlmsg_end(skb, nlh);
+
+ /* other group ? */
+ pr_debug("%s: rx-mode/multicast-list changed\n", __func__);
+ rtnl_notify(skb, net, 0, RTNLGRP_NOTIFY, NULL, GFP_ATOMIC);
+ return;
}
static int
@@ -727,6 +796,7 @@ void kni_net_release_fifo_phy(struct kni_dev *kni)
kni = netdev_priv(netdev);
ret = kni_net_process_request(kni, &req);
+ pr_info("%s request returns %d!\n", __func__, ret);
return (ret == 0 ? req.result : ret);
}
--
1.8.3.1