diff mbox series

[ovs-dev,v2] dpif-netlink: Fix feature negotiation for older kernels

Message ID 20210915150803.512312-1-mark.d.gray@redhat.com
State Accepted
Delegated to: Ilya Maximets
Headers show
Series [ovs-dev,v2] dpif-netlink: Fix feature negotiation for older kernels | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed

Commit Message

Mark Gray Sept. 15, 2021, 3:08 p.m. UTC
Older kernels do not reject unsupported features. This can lead
to a situation in which 'ovs-vswitchd' believes that a feature is
supported when, in fact, it is not.

This patch probes for this by attempting to set a known unsupported
feature.

Reported-by: Dumitru Ceara <dceara@redhat.com>
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2004083
Suggested-by: Ilya Maximets <i.maximets@ovn.org>
Signed-off-by: Mark Gray <mark.d.gray@redhat.com>
---

Notes:
    v2: Fix case raised by Dumitru in which kernel is already configured with
        unsupported features.

 lib/dpif-netlink.c | 72 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 50 insertions(+), 22 deletions(-)

Comments

Dumitru Ceara Sept. 16, 2021, 8:40 a.m. UTC | #1
On 9/15/21 5:08 PM, Mark Gray wrote:
> Older kernels do not reject unsupported features. This can lead
> to a situation in which 'ovs-vswitchd' believes that a feature is
> supported when, in fact, it is not.
> 
> This patch probes for this by attempting to set a known unsupported
> feature.
> 
> Reported-by: Dumitru Ceara <dceara@redhat.com>
> Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2004083
> Suggested-by: Ilya Maximets <i.maximets@ovn.org>
> Signed-off-by: Mark Gray <mark.d.gray@redhat.com>
> ---

This works for me, for this version:

Tested-by: Dumitru Ceara <dceara@redhat.com>

I do have a small comment below, thanks!

> 
> Notes:
>     v2: Fix case raised by Dumitru in which kernel is already configured with
>         unsupported features.
> 
>  lib/dpif-netlink.c | 72 ++++++++++++++++++++++++++++++++--------------
>  1 file changed, 50 insertions(+), 22 deletions(-)
> 
> diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
> index 34fc04237333..5f4b60c5a6d6 100644
> --- a/lib/dpif-netlink.c
> +++ b/lib/dpif-netlink.c
> @@ -84,6 +84,8 @@ enum { MAX_PORTS = USHRT_MAX };
>  #define EPOLLEXCLUSIVE (1u << 28)
>  #endif
>  
> +#define OVS_DP_F_UNSUPPORTED (1 << 31);
> +
>  /* This PID is not used by the kernel datapath when using dispatch per CPU,
>   * but it is required to be set (not zero). */
>  #define DPIF_NETLINK_PER_CPU_PID UINT32_MAX
> @@ -382,36 +384,62 @@ dpif_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name,
>          dp_request.cmd = OVS_DP_CMD_SET;
>      }
>  
> -    /* The Open vSwitch kernel module has two modes for dispatching upcalls:
> -     * per-vport and per-cpu.
> -     *
> -     * When dispatching upcalls per-vport, the kernel will
> -     * send the upcall via a Netlink socket that has been selected based on the
> -     * vport that received the packet that is causing the upcall.
> -     *
> -     * When dispatching upcall per-cpu, the kernel will send the upcall via
> -     * a Netlink socket that has been selected based on the cpu that received
> -     * the packet that is causing the upcall.
> -     *
> -     * First we test to see if the kernel module supports per-cpu dispatching
> -     * (the preferred method). If it does not support per-cpu dispatching, we
> -     * fall back to the per-vport dispatch mode.
> +    /* Some older kernels will not reject unknown features. This will cause
> +     * 'ovs-vswitchd' to incorrectly assume a feature is supported. In order to
> +     * test for that, we attempt to set a feature that we know is not supported
> +     * by any kernel. If this feature is not rejected, we can assume we are
> +     * running on one of these older kernels.
>       */
>      dp_request.user_features |= OVS_DP_F_UNALIGNED;
> -    dp_request.user_features &= ~OVS_DP_F_VPORT_PIDS;
> -    dp_request.user_features |= OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
> +    dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
> +    dp_request.user_features |= OVS_DP_F_UNSUPPORTED;

Nit: Sorry, I missed this on v1, but I guess we could just remove the
lines that set OVS_DP_F_UNALIGNED and OVS_DP_F_VPORT_PIDS here, and just
request OVS_DP_F_UNSUPPORTED.  We set the correct features anyway, in
all cases, below.

As far as I can tell this doesn't affect functionality; I tested with
the two lines removed and it looks OK to me.  If you send a v3 removing
these two lines please feel free to keep the "tested-by".

>      error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
>      if (error) {
> -        dp_request.user_features &= ~OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
> +        /* The Open vSwitch kernel module has two modes for dispatching
> +         * upcalls: per-vport and per-cpu.
> +         *
> +         * When dispatching upcalls per-vport, the kernel will
> +         * send the upcall via a Netlink socket that has been selected based on
> +         * the vport that received the packet that is causing the upcall.
> +         *
> +         * When dispatching upcall per-cpu, the kernel will send the upcall via
> +         * a Netlink socket that has been selected based on the cpu that
> +         * received the packet that is causing the upcall.
> +         *
> +         * First we test to see if the kernel module supports per-cpu
> +         * dispatching (the preferred method). If it does not support per-cpu
> +         * dispatching, we fall back to the per-vport dispatch mode.
> +         */
> +        dp_request.user_features &= ~OVS_DP_F_UNSUPPORTED;
> +        dp_request.user_features |= OVS_DP_F_UNALIGNED;
> +        dp_request.user_features &= ~OVS_DP_F_VPORT_PIDS;
> +        dp_request.user_features |= OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
> +        error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
> +        if (error) {
> +            dp_request.user_features &= ~OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
> +            dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
> +            error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
> +        }
> +        if (error) {
> +            return error;
> +        }
> +
> +        error = open_dpif(&dp, dpifp);
> +        dpif_netlink_set_features(*dpifp, OVS_DP_F_TC_RECIRC_SHARING);
> +    } else {
> +        VLOG_INFO("Kernel does not correctly support feature negotiation. "
> +                  "Using standard features.");
> +        dp_request.cmd = OVS_DP_CMD_SET;
> +        dp_request.user_features = 0;
> +        dp_request.user_features |= OVS_DP_F_UNALIGNED;
>          dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
>          error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
> -    }
> -    if (error) {
> -        return error;
> +        if (error) {
> +            return error;
> +        }
> +        error = open_dpif(&dp, dpifp);
>      }
>  
> -    error = open_dpif(&dp, dpifp);
> -    dpif_netlink_set_features(*dpifp, OVS_DP_F_TC_RECIRC_SHARING);
>      ofpbuf_delete(buf);
>  
>      if (create) {
>
Mark Gray Sept. 16, 2021, 10:04 a.m. UTC | #2
On 16/09/2021 09:40, Dumitru Ceara wrote:
> On 9/15/21 5:08 PM, Mark Gray wrote:
>> Older kernels do not reject unsupported features. This can lead
>> to a situation in which 'ovs-vswitchd' believes that a feature is
>> supported when, in fact, it is not.
>>
>> This patch probes for this by attempting to set a known unsupported
>> feature.
>>
>> Reported-by: Dumitru Ceara <dceara@redhat.com>
>> Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2004083
>> Suggested-by: Ilya Maximets <i.maximets@ovn.org>
>> Signed-off-by: Mark Gray <mark.d.gray@redhat.com>
>> ---
> 
> This works for me, for this version:
> 
> Tested-by: Dumitru Ceara <dceara@redhat.com>
> 
> I do have a small comment below, thanks!
> 
>>
>> Notes:
>>     v2: Fix case raised by Dumitru in which kernel is already configured with
>>         unsupported features.
>>
>>  lib/dpif-netlink.c | 72 ++++++++++++++++++++++++++++++++--------------
>>  1 file changed, 50 insertions(+), 22 deletions(-)
>>
>> diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
>> index 34fc04237333..5f4b60c5a6d6 100644
>> --- a/lib/dpif-netlink.c
>> +++ b/lib/dpif-netlink.c
>> @@ -84,6 +84,8 @@ enum { MAX_PORTS = USHRT_MAX };
>>  #define EPOLLEXCLUSIVE (1u << 28)
>>  #endif
>>  
>> +#define OVS_DP_F_UNSUPPORTED (1 << 31);
>> +
>>  /* This PID is not used by the kernel datapath when using dispatch per CPU,
>>   * but it is required to be set (not zero). */
>>  #define DPIF_NETLINK_PER_CPU_PID UINT32_MAX
>> @@ -382,36 +384,62 @@ dpif_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name,
>>          dp_request.cmd = OVS_DP_CMD_SET;
>>      }
>>  
>> -    /* The Open vSwitch kernel module has two modes for dispatching upcalls:
>> -     * per-vport and per-cpu.
>> -     *
>> -     * When dispatching upcalls per-vport, the kernel will
>> -     * send the upcall via a Netlink socket that has been selected based on the
>> -     * vport that received the packet that is causing the upcall.
>> -     *
>> -     * When dispatching upcall per-cpu, the kernel will send the upcall via
>> -     * a Netlink socket that has been selected based on the cpu that received
>> -     * the packet that is causing the upcall.
>> -     *
>> -     * First we test to see if the kernel module supports per-cpu dispatching
>> -     * (the preferred method). If it does not support per-cpu dispatching, we
>> -     * fall back to the per-vport dispatch mode.
>> +    /* Some older kernels will not reject unknown features. This will cause
>> +     * 'ovs-vswitchd' to incorrectly assume a feature is supported. In order to
>> +     * test for that, we attempt to set a feature that we know is not supported
>> +     * by any kernel. If this feature is not rejected, we can assume we are
>> +     * running on one of these older kernels.
>>       */
>>      dp_request.user_features |= OVS_DP_F_UNALIGNED;
>> -    dp_request.user_features &= ~OVS_DP_F_VPORT_PIDS;
>> -    dp_request.user_features |= OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
>> +    dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
>> +    dp_request.user_features |= OVS_DP_F_UNSUPPORTED;
> 
> Nit: Sorry, I missed this on v1, but I guess we could just remove the
> lines that set OVS_DP_F_UNALIGNED and OVS_DP_F_VPORT_PIDS here, and just
> request OVS_DP_F_UNSUPPORTED.  We set the correct features anyway, in
> all cases, below.

I don't want to do that because it would change the behaviour of the
"create" case. In the previous code, when we are creating the datapath,
we set UNALIGNED, VPORT_PIDs using the NEW command. If I remove that, I
will call NEW without the flags and then SET them flags after. Not sure
if it will have any adverse consequences on some version of the kernel
so it may not be worth the risk. What do you think?

> 
> As far as I can tell this doesn't affect functionality; I tested with
> the two lines removed and it looks OK to me.  If you send a v3 removing
> these two lines please feel free to keep the "tested-by".
> 
>>      error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
>>      if (error) {
>> -        dp_request.user_features &= ~OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
>> +        /* The Open vSwitch kernel module has two modes for dispatching
>> +         * upcalls: per-vport and per-cpu.
>> +         *
>> +         * When dispatching upcalls per-vport, the kernel will
>> +         * send the upcall via a Netlink socket that has been selected based on
>> +         * the vport that received the packet that is causing the upcall.
>> +         *
>> +         * When dispatching upcall per-cpu, the kernel will send the upcall via
>> +         * a Netlink socket that has been selected based on the cpu that
>> +         * received the packet that is causing the upcall.
>> +         *
>> +         * First we test to see if the kernel module supports per-cpu
>> +         * dispatching (the preferred method). If it does not support per-cpu
>> +         * dispatching, we fall back to the per-vport dispatch mode.
>> +         */
>> +        dp_request.user_features &= ~OVS_DP_F_UNSUPPORTED;
>> +        dp_request.user_features |= OVS_DP_F_UNALIGNED;
>> +        dp_request.user_features &= ~OVS_DP_F_VPORT_PIDS;
>> +        dp_request.user_features |= OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
>> +        error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
>> +        if (error) {
>> +            dp_request.user_features &= ~OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
>> +            dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
>> +            error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
>> +        }
>> +        if (error) {
>> +            return error;
>> +        }
>> +
>> +        error = open_dpif(&dp, dpifp);
>> +        dpif_netlink_set_features(*dpifp, OVS_DP_F_TC_RECIRC_SHARING);
>> +    } else {
>> +        VLOG_INFO("Kernel does not correctly support feature negotiation. "
>> +                  "Using standard features.");
>> +        dp_request.cmd = OVS_DP_CMD_SET;
>> +        dp_request.user_features = 0;
>> +        dp_request.user_features |= OVS_DP_F_UNALIGNED;
>>          dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
>>          error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
>> -    }
>> -    if (error) {
>> -        return error;
>> +        if (error) {
>> +            return error;
>> +        }
>> +        error = open_dpif(&dp, dpifp);
>>      }
>>  
>> -    error = open_dpif(&dp, dpifp);
>> -    dpif_netlink_set_features(*dpifp, OVS_DP_F_TC_RECIRC_SHARING);
>>      ofpbuf_delete(buf);
>>  
>>      if (create) {
>>
>
Dumitru Ceara Sept. 16, 2021, 10:09 a.m. UTC | #3
On 9/16/21 12:04 PM, Mark Gray wrote:
> On 16/09/2021 09:40, Dumitru Ceara wrote:
>> On 9/15/21 5:08 PM, Mark Gray wrote:
>>> Older kernels do not reject unsupported features. This can lead
>>> to a situation in which 'ovs-vswitchd' believes that a feature is
>>> supported when, in fact, it is not.
>>>
>>> This patch probes for this by attempting to set a known unsupported
>>> feature.
>>>
>>> Reported-by: Dumitru Ceara <dceara@redhat.com>
>>> Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2004083
>>> Suggested-by: Ilya Maximets <i.maximets@ovn.org>
>>> Signed-off-by: Mark Gray <mark.d.gray@redhat.com>
>>> ---
>>
>> This works for me, for this version:
>>
>> Tested-by: Dumitru Ceara <dceara@redhat.com>
>>
>> I do have a small comment below, thanks!
>>
>>>
>>> Notes:
>>>     v2: Fix case raised by Dumitru in which kernel is already configured with
>>>         unsupported features.
>>>
>>>  lib/dpif-netlink.c | 72 ++++++++++++++++++++++++++++++++--------------
>>>  1 file changed, 50 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
>>> index 34fc04237333..5f4b60c5a6d6 100644
>>> --- a/lib/dpif-netlink.c
>>> +++ b/lib/dpif-netlink.c
>>> @@ -84,6 +84,8 @@ enum { MAX_PORTS = USHRT_MAX };
>>>  #define EPOLLEXCLUSIVE (1u << 28)
>>>  #endif
>>>  
>>> +#define OVS_DP_F_UNSUPPORTED (1 << 31);
>>> +
>>>  /* This PID is not used by the kernel datapath when using dispatch per CPU,
>>>   * but it is required to be set (not zero). */
>>>  #define DPIF_NETLINK_PER_CPU_PID UINT32_MAX
>>> @@ -382,36 +384,62 @@ dpif_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name,
>>>          dp_request.cmd = OVS_DP_CMD_SET;
>>>      }
>>>  
>>> -    /* The Open vSwitch kernel module has two modes for dispatching upcalls:
>>> -     * per-vport and per-cpu.
>>> -     *
>>> -     * When dispatching upcalls per-vport, the kernel will
>>> -     * send the upcall via a Netlink socket that has been selected based on the
>>> -     * vport that received the packet that is causing the upcall.
>>> -     *
>>> -     * When dispatching upcall per-cpu, the kernel will send the upcall via
>>> -     * a Netlink socket that has been selected based on the cpu that received
>>> -     * the packet that is causing the upcall.
>>> -     *
>>> -     * First we test to see if the kernel module supports per-cpu dispatching
>>> -     * (the preferred method). If it does not support per-cpu dispatching, we
>>> -     * fall back to the per-vport dispatch mode.
>>> +    /* Some older kernels will not reject unknown features. This will cause
>>> +     * 'ovs-vswitchd' to incorrectly assume a feature is supported. In order to
>>> +     * test for that, we attempt to set a feature that we know is not supported
>>> +     * by any kernel. If this feature is not rejected, we can assume we are
>>> +     * running on one of these older kernels.
>>>       */
>>>      dp_request.user_features |= OVS_DP_F_UNALIGNED;
>>> -    dp_request.user_features &= ~OVS_DP_F_VPORT_PIDS;
>>> -    dp_request.user_features |= OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
>>> +    dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
>>> +    dp_request.user_features |= OVS_DP_F_UNSUPPORTED;
>>
>> Nit: Sorry, I missed this on v1, but I guess we could just remove the
>> lines that set OVS_DP_F_UNALIGNED and OVS_DP_F_VPORT_PIDS here, and just
>> request OVS_DP_F_UNSUPPORTED.  We set the correct features anyway, in
>> all cases, below.
> 
> I don't want to do that because it would change the behaviour of the
> "create" case. In the previous code, when we are creating the datapath,
> we set UNALIGNED, VPORT_PIDs using the NEW command. If I remove that, I
> will call NEW without the flags and then SET them flags after. Not sure
> if it will have any adverse consequences on some version of the kernel
> so it may not be worth the risk. What do you think?
> 

Ok, I see now, thanks for the follow up!  Let's leave it as is then.

Regards,
Dumitru
Ilya Maximets Oct. 12, 2021, 7:27 p.m. UTC | #4
On 9/16/21 10:40, Dumitru Ceara wrote:
> On 9/15/21 5:08 PM, Mark Gray wrote:
>> Older kernels do not reject unsupported features. This can lead
>> to a situation in which 'ovs-vswitchd' believes that a feature is
>> supported when, in fact, it is not.
>>
>> This patch probes for this by attempting to set a known unsupported
>> feature.
>>
>> Reported-by: Dumitru Ceara <dceara@redhat.com>
>> Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2004083
>> Suggested-by: Ilya Maximets <i.maximets@ovn.org>
>> Signed-off-by: Mark Gray <mark.d.gray@redhat.com>
>> ---
> 
> This works for me, for this version:
> 
> Tested-by: Dumitru Ceara <dceara@redhat.com>

Thanks!  Applied and backported to 2.16.

Best regards, Ilya Maximets.
diff mbox series

Patch

diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index 34fc04237333..5f4b60c5a6d6 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -84,6 +84,8 @@  enum { MAX_PORTS = USHRT_MAX };
 #define EPOLLEXCLUSIVE (1u << 28)
 #endif
 
+#define OVS_DP_F_UNSUPPORTED (1 << 31);
+
 /* This PID is not used by the kernel datapath when using dispatch per CPU,
  * but it is required to be set (not zero). */
 #define DPIF_NETLINK_PER_CPU_PID UINT32_MAX
@@ -382,36 +384,62 @@  dpif_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name,
         dp_request.cmd = OVS_DP_CMD_SET;
     }
 
-    /* The Open vSwitch kernel module has two modes for dispatching upcalls:
-     * per-vport and per-cpu.
-     *
-     * When dispatching upcalls per-vport, the kernel will
-     * send the upcall via a Netlink socket that has been selected based on the
-     * vport that received the packet that is causing the upcall.
-     *
-     * When dispatching upcall per-cpu, the kernel will send the upcall via
-     * a Netlink socket that has been selected based on the cpu that received
-     * the packet that is causing the upcall.
-     *
-     * First we test to see if the kernel module supports per-cpu dispatching
-     * (the preferred method). If it does not support per-cpu dispatching, we
-     * fall back to the per-vport dispatch mode.
+    /* Some older kernels will not reject unknown features. This will cause
+     * 'ovs-vswitchd' to incorrectly assume a feature is supported. In order to
+     * test for that, we attempt to set a feature that we know is not supported
+     * by any kernel. If this feature is not rejected, we can assume we are
+     * running on one of these older kernels.
      */
     dp_request.user_features |= OVS_DP_F_UNALIGNED;
-    dp_request.user_features &= ~OVS_DP_F_VPORT_PIDS;
-    dp_request.user_features |= OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
+    dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
+    dp_request.user_features |= OVS_DP_F_UNSUPPORTED;
     error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
     if (error) {
-        dp_request.user_features &= ~OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
+        /* The Open vSwitch kernel module has two modes for dispatching
+         * upcalls: per-vport and per-cpu.
+         *
+         * When dispatching upcalls per-vport, the kernel will
+         * send the upcall via a Netlink socket that has been selected based on
+         * the vport that received the packet that is causing the upcall.
+         *
+         * When dispatching upcall per-cpu, the kernel will send the upcall via
+         * a Netlink socket that has been selected based on the cpu that
+         * received the packet that is causing the upcall.
+         *
+         * First we test to see if the kernel module supports per-cpu
+         * dispatching (the preferred method). If it does not support per-cpu
+         * dispatching, we fall back to the per-vport dispatch mode.
+         */
+        dp_request.user_features &= ~OVS_DP_F_UNSUPPORTED;
+        dp_request.user_features |= OVS_DP_F_UNALIGNED;
+        dp_request.user_features &= ~OVS_DP_F_VPORT_PIDS;
+        dp_request.user_features |= OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
+        error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
+        if (error) {
+            dp_request.user_features &= ~OVS_DP_F_DISPATCH_UPCALL_PER_CPU;
+            dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
+            error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
+        }
+        if (error) {
+            return error;
+        }
+
+        error = open_dpif(&dp, dpifp);
+        dpif_netlink_set_features(*dpifp, OVS_DP_F_TC_RECIRC_SHARING);
+    } else {
+        VLOG_INFO("Kernel does not correctly support feature negotiation. "
+                  "Using standard features.");
+        dp_request.cmd = OVS_DP_CMD_SET;
+        dp_request.user_features = 0;
+        dp_request.user_features |= OVS_DP_F_UNALIGNED;
         dp_request.user_features |= OVS_DP_F_VPORT_PIDS;
         error = dpif_netlink_dp_transact(&dp_request, &dp, &buf);
-    }
-    if (error) {
-        return error;
+        if (error) {
+            return error;
+        }
+        error = open_dpif(&dp, dpifp);
     }
 
-    error = open_dpif(&dp, dpifp);
-    dpif_netlink_set_features(*dpifp, OVS_DP_F_TC_RECIRC_SHARING);
     ofpbuf_delete(buf);
 
     if (create) {