<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:ËÎÌå;
panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
{font-family:"\@ËÎÌå";
panose-1:2 1 6 0 3 1 1 1 1 1;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
font-size:10.5pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:#0563C1;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:#954F72;
text-decoration:underline;}
p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
{mso-style-priority:34;
margin:0cm;
margin-bottom:.0001pt;
text-align:justify;
text-justify:inter-ideograph;
text-indent:21.0pt;
font-size:10.5pt;
font-family:"Calibri",sans-serif;}
span.EmailStyle18
{mso-style-type:personal;
font-family:"Calibri",sans-serif;
color:windowtext;}
span.EmailStyle19
{mso-style-type:personal-reply;
font-family:"Calibri",sans-serif;
color:#1F497D;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;}
div.WordSection1
{page:WordSection1;}
/* List Definitions */
@list l0
{mso-list-id:929196264;
mso-list-type:hybrid;
mso-list-template-ids:677022758 237530476 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l0:level1
{mso-level-text:%1£®;
mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:18.0pt;
text-indent:-18.0pt;}
@list l0:level2
{mso-level-number-format:alpha-lower;
mso-level-text:"%2\)";
mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:42.0pt;
text-indent:-21.0pt;}
@list l0:level3
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
margin-left:63.0pt;
text-indent:-21.0pt;}
@list l0:level4
{mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:84.0pt;
text-indent:-21.0pt;}
@list l0:level5
{mso-level-number-format:alpha-lower;
mso-level-text:"%5\)";
mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:105.0pt;
text-indent:-21.0pt;}
@list l0:level6
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
margin-left:126.0pt;
text-indent:-21.0pt;}
@list l0:level7
{mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:147.0pt;
text-indent:-21.0pt;}
@list l0:level8
{mso-level-number-format:alpha-lower;
mso-level-text:"%8\)";
mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:168.0pt;
text-indent:-21.0pt;}
@list l0:level9
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
margin-left:189.0pt;
text-indent:-21.0pt;}
@list l1
{mso-list-id:948778664;
mso-list-type:hybrid;
mso-list-template-ids:154963342 -2145249214 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l1:level1
{mso-level-text:"%1\)";
mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:54.75pt;
text-indent:-18.0pt;}
@list l1:level2
{mso-level-number-format:alpha-lower;
mso-level-text:"%2\)";
mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:78.75pt;
text-indent:-21.0pt;}
@list l1:level3
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
margin-left:99.75pt;
text-indent:-21.0pt;}
@list l1:level4
{mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:120.75pt;
text-indent:-21.0pt;}
@list l1:level5
{mso-level-number-format:alpha-lower;
mso-level-text:"%5\)";
mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:5.0cm;
text-indent:-21.0pt;}
@list l1:level6
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
margin-left:162.75pt;
text-indent:-21.0pt;}
@list l1:level7
{mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:183.75pt;
text-indent:-21.0pt;}
@list l1:level8
{mso-level-number-format:alpha-lower;
mso-level-text:"%8\)";
mso-level-tab-stop:none;
mso-level-number-position:left;
margin-left:204.75pt;
text-indent:-21.0pt;}
@list l1:level9
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
margin-left:225.75pt;
text-indent:-21.0pt;}
ol
{margin-bottom:0cm;}
ul
{margin-bottom:0cm;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="ZH-CN" link="#0563C1" vlink="#954F72" style="text-justify-trim:punctuation">
<div class="WordSection1">
<p class="MsoNormal" align="left" style="text-align:left"><span lang="EN-US">Hi All,<o:p></o:p></span></p>
<p class="MsoNormal" align="left" style="text-align:left"><span lang="EN-US"><br>
Recently we found a problem, as follow:<o:p></o:p></span></p>
<p class="MsoNormal" align="left" style="text-align:left"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:-18.0pt;mso-list:l0 level1 lfo2">
<![if !supportLists]><span lang="EN-US"><span style="mso-list:Ignore">1£®<span style="font:7.0pt "Times New Roman"">
</span></span></span><![endif]><span lang="EN-US">Problem description:<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:5.25pt"><span lang="EN-US">PVECTOR_FOR_EACH use ovsrcu_get to get pvector¡¯s current impl pointer, and the memory_order_consume<o:p></o:p></span></p>
<p class="MsoNormal" style="text-indent:21.0pt"><span lang="EN-US">in ovsrcu_get will ensure *impl is read after this instruction, so we can get the the correct ptr value in<o:p></o:p></span></p>
<p class="MsoNormal" style="text-indent:21.0pt"><span lang="EN-US">impl->vector[0], but it seems that we cannot make sure that the *ptr value is also correct.<o:p></o:p></span></p>
<p class="MsoNormal" style="text-indent:21.0pt"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:-18.0pt;mso-list:l0 level1 lfo2">
<![if !supportLists]><span lang="EN-US"><span style="mso-list:Ignore">2£®<span style="font:7.0pt "Times New Roman"">
</span></span></span><![endif]><span lang="EN-US">Verification through testing:<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:0cm"><span lang="EN-US">Copy the test code into file lib/dpif-netdev.c, and the modify fuction pmd_thread_main, insert the following line<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:0cm"><span lang="EN-US">in the for (;;) loop</span><span style="font-family:ËÎÌå">£º</span>
<span lang="EN-US"><o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:18.0pt;text-indent:15.75pt"><span lang="EN-US">do_atomic_test(pmd);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> if the do_atomic_consumer is implement without mutex lock, we can easily get the following log in ovs-vswitchd.log:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> ----my_itrator:143, my_value:144 (we may get other values, and my_itrator = my_value - 1 stay true.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> The consumer thread can get dirty memory with memory_order_consume, if we change ovsrcu_get to get values<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> with memory_order_acquire, we can still get the error message (my_itrator = my_value - 1).<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> <o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> We can fix this problem if consumer thread access data with g_pvector_lock¡¯ protection, but pvector is designed<o:p></o:p></span></p>
<p class="MsoNormal" style="text-indent:10.5pt"><span lang="EN-US">to use without locks. Where did it go wrong? Can anyone here give some comments?<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">--------------------------------------------- A error case truly happened whining using pvector --------------------------<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">Suppose a scenario as follows:<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:54.75pt;text-indent:-18.0pt;mso-list:l1 level1 lfo4">
<![if !supportLists]><span lang="EN-US"><span style="mso-list:Ignore">1)<span style="font:7.0pt "Times New Roman"">
</span></span></span><![endif]><span lang="EN-US">handler thread insert a dpcls_subtable, whose address is p,
<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:54.75pt;text-indent:0cm"><span lang="EN-US">to datapath classifier¡¯s (struct dpcls) pvector;<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:54.75pt;text-indent:-18.0pt;mso-list:l1 level1 lfo4">
<![if !supportLists]><span lang="EN-US"><span style="mso-list:Ignore">2)<span style="font:7.0pt "Times New Roman"">
</span></span></span><![endif]><span lang="EN-US">pmd thread call fast_path_processing to find the subtable and access address p;<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:54.75pt;text-indent:-18.0pt;mso-list:l1 level1 lfo4">
<![if !supportLists]><span lang="EN-US"><span style="mso-list:Ignore">3)<span style="font:7.0pt "Times New Roman"">
</span></span></span><![endif]><span lang="EN-US">the subtable above is destroyed by someone;<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:54.75pt;text-indent:-18.0pt;mso-list:l1 level1 lfo4">
<![if !supportLists]><span lang="EN-US"><span style="mso-list:Ignore">4)<span style="font:7.0pt "Times New Roman"">
</span></span></span><![endif]><span lang="EN-US">handler thread insert another subtable, whose address is also p,<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:54.75pt;text-indent:0cm"><span lang="EN-US">and insert to dpcls¡¯s pvector;<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:54.75pt;text-indent:-18.0pt;mso-list:l1 level1 lfo4">
<![if !supportLists]><span lang="EN-US"><span style="mso-list:Ignore">5)<span style="font:7.0pt "Times New Roman"">
</span></span></span><![endif]><span lang="EN-US">pmd thread call fast_path_processing -> dp_netdev_pmd_lookup_flow<o:p></o:p></span></p>
<p class="MsoListParagraph" style="margin-left:54.75pt;text-indent:0cm"><span lang="EN-US">-> dpcls_lookup to access the subtable from pvector.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">We use PVECTOR_FOR_EACH to iterate the pvector in step 5, no locks is used, dirty memory access may<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">cause to ovs-vswitchd process coredump.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">----------------------------------------------Testing codes are as follows ---------------------------------------------<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static struct pvector g_atomic_test;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static unsigned char g_my_data[65536];<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static unsigned char g_value = 0;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static int g_index = 0;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static struct ovs_mutex g_pvector_lock = OVS_MUTEX_INITIALIZER;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static void do_atomic_producer(void)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">{<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> ovs_mutex_lock(&g_pvector_lock);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> if (g_index < 65536) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> g_my_data[g_index] = g_value;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> pvector_insert(&g_atomic_test, (void *)&g_my_data[g_index], 0);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> g_index++;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> } else {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> for (int i = 0; i < g_index; i++) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> pvector_remove(&g_atomic_test, (void *)&g_my_data[i]);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> g_index = 0;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> g_value++; //value can loops to zero;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> pvector_publish(&g_atomic_test);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> ovs_mutex_unlock(&g_pvector_lock);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static void do_atomic_consumer(void)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">{<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> unsigned char *my_itr;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> unsigned char my_value;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> bool first = true;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> // ovs_mutex_lock(&g_pvector_lock);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> PVECTOR_FOR_EACH (my_itr, &g_atomic_test) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> if (first) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> my_value = *my_itr;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> first = false;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> } else if (*my_itr != my_value) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> VLOG_ERR("----my_itrator:%u, my_value:%u\n", *my_itr, my_value);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> break;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> // ovs_mutex_unlock(&g_pvector_lock);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">static void do_atomic_test(struct dp_netdev_pmd_thread *pmd)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">{<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> if (pmd->core_id == 1) {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> do_atomic_producer();<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> } else {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> do_atomic_consumer();<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"> }<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>
</div>
</body>
</html>