<div dir="ltr">Thanks very much for the review!~ ;D<br><div class="gmail_extra"><br>Please see my reply inline,<br><br><br><div class="gmail_quote">On Thu, Feb 20, 2014 at 3:25 PM, Pravin Shelar <span dir="ltr">&lt;<a href="mailto:pshelar@nicira.com" target="_blank">pshelar@nicira.com</a>&gt;</span> wrote:<br>









<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><span style="color:rgb(80,0,80)">&gt;                 upcall.cmd = OVS_PACKET_CMD_MISS;</span><br>

</div><div>
<div>
&gt;                 upcall.key = &amp;key;<br>
&gt;                 upcall.userdata = NULL;<br>
&gt; -               upcall.portid = p-&gt;upcall_portid;<br>
&gt; +               upcall.portid = ovs_vport_find_pid(p, &amp;key);<br>
&gt;                 ovs_dp_upcall(dp, skb, &amp;upcall);<br>
<br>
</div></div>Can you use different name than pid? pid is generally used for process id.<br>
<div><br></div></blockquote><div><br></div><div><br></div><div><br></div><div>I&#39;ll use &#39;portid&#39; for consistency.  In userspace, we call it pid (e.g. nl_sock_pid(),</div><div>VPORT_ATTR_UPCALL_PID).  So I&#39;ll keep using it.</div>









<div><br></div><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

<div>&gt; @@ -1459,7 +1459,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {<br>








&gt;         [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) },<br>
&gt;         [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 },<br>
&gt;         [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },<br>
&gt; -       [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 },<br>
&gt; +       [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_UNSPEC },<br>
&gt;         [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },<br>
&gt;  };<br>
&gt;<br>
<br>
</div>Have you tried this patch with old userspace to check compatibility?</blockquote><div><br></div><div><br></div><div>Will make sure the kernel module is compatible with old userspace.</div><div><br></div><div>Also, you just reminded me that this patch can be cut into series! ;D  So, I&#39;m</div>









<div>planning to do that and resend it as series of patches.</div><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

<div>
&gt; @@ -1579,8 +1581,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)<br>
&gt;         int err;<br>
&gt;<br>
&gt;         err = -EINVAL;<br>
&gt; -       if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] ||<br>
&gt; -           !a[OVS_VPORT_ATTR_UPCALL_PID])<br>
&gt; +       if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE])<br>
&gt;                 goto exit;<br>
&gt;<br>
<br>
</div>Port ids array should be mandatory. as it is today.<br></blockquote><div><br></div><div><br></div><div><br></div><div>Yeah, I&#39;ll change accordingly to honor the API and guarantee compatibility,</div>


<div><br></div><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


<div><div>&gt; +static void __vport_pids_destroy(struct vport_pids *pids)<br>
&gt; +{<br>
&gt; +       if (pids-&gt;pids)<br>
&gt; +               kfree(pids-&gt;pids);<br>
&gt; +<br>
&gt; +       kfree(pids);<br>
&gt; +}<br>
&gt; +<br>
<br>
</div></div>This is not called from anywhere else. Can you use rcu-callback<br>
function to free?<br>
<div><div><br></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><div>
&gt; +static void vport_pids_destroy_rcu_cb(struct rcu_head *rcu)<br>
&gt; +{<br>
&gt; +       struct vport_pids *pids = container_of(rcu, struct vport_pids, rcu);<br>
&gt; +<br>
&gt; +       __vport_pids_destroy(pids);<br>
&gt; +}<br></div></div></blockquote><div><br></div><div><br></div><div>I see, I&#39;ll combine the two.</div><div><br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">









<div><div>&gt; + */<br>
&gt; +int ovs_vport_set_upcall_pids(struct vport *vport,  struct nlattr *pids)<br>
&gt; +{<br>
&gt; +       struct vport_pids *old;<br>
&gt; +<br>
&gt; +       if (pids &amp;&amp; nla_len(pids) % sizeof(u32))<br>
&gt; +               return -EINVAL;<br>
&gt; +<br>
&gt; +       old = ovsl_dereference(vport-&gt;upcall_pids);<br>
&gt; +</div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div>
&gt; +       if (pids) {<br>
&gt; +               struct vport_pids *vport_pids;<br>
&gt; +<br>
&gt; +               vport_pids = kmalloc(sizeof *vport_pids, GFP_KERNEL);<br>
&gt; +               vport_pids-&gt;pids = kmalloc(nla_len(pids), GFP_KERNEL);<br>
&gt; +               vport_pids-&gt;n_pids = nla_len(pids)<br>
&gt; +                       / (sizeof *vport_pids-&gt;pids);<br>
&gt; +               memcpy(vport_pids-&gt;pids, nla_data(pids), nla_len(pids));<br>
&gt; +<br>
<br>
</div>We can just use single memory space to allocate both struct vport_pids<br>
and array. Same is done for flow-stats.<br>
<div><br></div></blockquote><div><br></div><div><br></div><div><br></div><div>Thx for the good suggestion, I&#39;ll adjust my code accordingly.</div><div><br></div><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">








<div>
&gt; +               rcu_assign_pointer(vport-&gt;upcall_pids, vport_pids);<br>
&gt; +       } else if (old) {<br>
&gt; +               rcu_assign_pointer(vport-&gt;upcall_pids, NULL);<br>
&gt; +       }<br>
&gt; +<br>
&gt; +       if (old)<br>
&gt; +               call_rcu(&amp;old-&gt;rcu, vport_pids_destroy_rcu_cb);<br>
&gt; +<br>
<br>
</div>This is bit confusing. We can free pids array in from vport destroy callback.<br>
So there is no  need to handle case where pids is NULL.<br>
<div><br></div></blockquote><div><br></div><div><br></div><div><br></div><div>Sure, changes are made so  that vport_pids will never be NULL, except for the first</div><div>time it is configured.</div><div><br></div>





<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div>&gt; +int ovs_vport_get_upcall_pids(const struct vport *vport, struct sk_buff *skb)<br>







&gt; +{<br>
&gt; +       struct vport_pids *pids;<br>
&gt; +       int err = 0;<br>
&gt; +<br>
&gt; +       rcu_read_lock();<br>
&gt; +       pids = ovsl_dereference(vport-&gt;upcall_pids);<br>
&gt; +<br>
</div>This function is always called with rcu or ovs mutex. so there is no<br>
need to take extra lock.<br>
<div><br></div></blockquote><div><br></div><div><br></div><div>I should check for that next time.  Fixed.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">









<div>
&gt; +       if (!pids)<br>
&gt; +               goto exit;<br>
&gt; +<br>
<br>
</div>pids should not be NULL in this case.</blockquote><div><br></div><div> </div><div>Yes, I&#39;ll remove it.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">









<div><div>
&gt; + * Returns the pid of the target socket.  Must be called with rcu_read_lock.<br>
&gt; + */<br>
&gt; +u32 ovs_vport_find_pid(const struct vport *p, const struct sw_flow_key *key)<br>
&gt; +{<br>
&gt; +       struct vport_pids *pids;<br>
&gt; +       u32 hash;<br>
&gt; +<br>
&gt; +       pids = ovsl_dereference(p-&gt;upcall_pids);<br>
&gt; +<br>
</div></div>This function is only called under rcu read context, therefore<br>
rcu_dereference is sufficient.<br>
<div><br></div></blockquote><div><br></div><div><br></div><div>Thanks, fixed.</div><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">







<div>
&gt; +       if (!pids)<br>
&gt; +               return 0;<br>
&gt; +<br>
</div>pids should not be NULL in this case.<br>
<div><br></div></blockquote><div><br></div><div><br></div><div>Yes, I&#39;ll remove it.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">






<div>
&gt; +       hash = key-&gt;ipv4.addr.src ^ key-&gt;ipv4.addr.dst<br>
&gt; +               ^ key-&gt;ip.proto ^ key-&gt;ipv4.tp.src<br>
&gt; +               ^ key-&gt;ipv4.tp.dst;<br>
&gt; +<br>
<br>
</div>skb_get_rxhash() should be cheaper in general than calculating hash.<br>
<div><br></div></blockquote><div><br></div><div><br></div><div>Thanks for the suggestion, I&#39;ll use it.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


<div>
&gt; +       return pids-&gt;pids[jhash((void *) &amp;hash, 4, 0) % pids-&gt;n_pids];<br>
&gt; +}<br>
&gt; +<br>
<br>
</div> We should use hash seed here since we are using values from packet<br>
coming from network.<br>
<div><div><br></div></div></blockquote><div><br></div><div><br></div><div>Since i&#39;ll use skb_get_rxhash(), I will just used the skb_get_rxhash() return value.</div><div>So, no seed is needed.</div><div><br></div><div>

<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div>&gt; -        int idx = dpif-&gt;epoll_events[dpif-&gt;event_offset].data.u32;<br>
&gt; -        struct dpif_channel *ch = &amp;dpif-&gt;channels[idx];<br>
&gt; +    while (epoll-&gt;event_offset &lt; epoll-&gt;n_events) {<br>
&gt; +        int idx = epoll-&gt;epoll_events[epoll-&gt;event_offset].data.u32;<br>
&gt; +        struct dpif_channel *ch = &amp;dpif-&gt;channels[idx][handler_id];<br>
&gt;<br>
<br>
</div>I have not looked at whole userspace part, but just noticed that this<br>
channels access pattern is not good for cpu cacheline.<br>
Is there reason for doing it this way rather than channel[handler_id][idx] ?<br></blockquote><div><br></div><div><br></div><div>I just haven&#39;t thought about the cacheline benefits.  Will make the change.  Thanks.</div>






<div> </div></div><br></div></div>