<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>