Some of the CTA_PROTOINFO_TCP nested attributes are not always
included in the received message, but the parsing logic considers them
as required, failing in case they are not found.

This was observed while monitoring some connections by reading the
events sent by conntrack:

./ovstest test-netlink-conntrack monitor
[...]
2022-08-04T09:39:02Z|00007|netlink_conntrack|ERR|Could not parse nested TCP 
protoinfo
  options. Possibly incompatible Linux kernel version.
2022-08-04T09:39:02Z|00008|netlink_notifier|WARN|unexpected netlink message 
contents
[...]

All the TCP DELETE/DESTROY events fail to parse with the message
above.

Fix it by turning the relevant attributes to optional.

Signed-off-by: Paolo Valerio <pvale...@redhat.com>
---
- [1] is the related piece of code that skips flags and wscale for the
  destroy evts.

[1] 
https://github.com/torvalds/linux/blob/master/net/netfilter/nf_conntrack_proto_tcp.c#L1202
---
 lib/netlink-conntrack.c |   45 +++++++++++++++++++++++++++------------------
 1 file changed, 27 insertions(+), 18 deletions(-)

diff --git a/lib/netlink-conntrack.c b/lib/netlink-conntrack.c
index 78f1bf60b..4fcde9ba1 100644
--- a/lib/netlink-conntrack.c
+++ b/lib/netlink-conntrack.c
@@ -672,13 +672,13 @@ nl_ct_parse_protoinfo_tcp(struct nlattr *nla,
     static const struct nl_policy policy[] = {
         [CTA_PROTOINFO_TCP_STATE] = { .type = NL_A_U8, .optional = false },
         [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NL_A_U8,
-                                                .optional = false },
+                                                .optional = true },
         [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NL_A_U8,
-                                             .optional = false },
+                                             .optional = true },
         [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .type = NL_A_U16,
-                                               .optional = false },
+                                               .optional = true },
         [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .type = NL_A_U16,
-                                            .optional = false },
+                                            .optional = true },
     };
     struct nlattr *attrs[ARRAY_SIZE(policy)];
     bool parsed;
@@ -695,20 +695,29 @@ nl_ct_parse_protoinfo_tcp(struct nlattr *nla,
          * connection, but our structures store a separate state for
          * each endpoint.  Here we duplicate the state. */
         protoinfo->tcp.state_orig = protoinfo->tcp.state_reply = state;
-        protoinfo->tcp.wscale_orig = nl_attr_get_u8(
-            attrs[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]);
-        protoinfo->tcp.wscale_reply = nl_attr_get_u8(
-            attrs[CTA_PROTOINFO_TCP_WSCALE_REPLY]);
-        flags_orig =
-            nl_attr_get_unspec(attrs[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL],
-                               sizeof *flags_orig);
-        protoinfo->tcp.flags_orig =
-            ip_ct_tcp_flags_to_dpif(flags_orig->flags);
-        flags_reply =
-            nl_attr_get_unspec(attrs[CTA_PROTOINFO_TCP_FLAGS_REPLY],
-                               sizeof *flags_reply);
-        protoinfo->tcp.flags_reply =
-            ip_ct_tcp_flags_to_dpif(flags_reply->flags);
+
+        if (attrs[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]) {
+            protoinfo->tcp.wscale_orig =
+                nl_attr_get_u8(attrs[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]);
+        }
+        if (attrs[CTA_PROTOINFO_TCP_WSCALE_REPLY]) {
+            protoinfo->tcp.wscale_reply =
+                nl_attr_get_u8(attrs[CTA_PROTOINFO_TCP_WSCALE_REPLY]);
+        }
+        if (attrs[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]) {
+            flags_orig =
+                nl_attr_get_unspec(attrs[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL],
+                                   sizeof *flags_orig);
+            protoinfo->tcp.flags_orig =
+                ip_ct_tcp_flags_to_dpif(flags_orig->flags);
+        }
+        if (attrs[CTA_PROTOINFO_TCP_FLAGS_REPLY]) {
+            flags_reply =
+                nl_attr_get_unspec(attrs[CTA_PROTOINFO_TCP_FLAGS_REPLY],
+                                   sizeof *flags_reply);
+            protoinfo->tcp.flags_reply =
+                ip_ct_tcp_flags_to_dpif(flags_reply->flags);
+        }
     } else {
         VLOG_ERR_RL(&rl, "Could not parse nested TCP protoinfo options. "
                     "Possibly incompatible Linux kernel version.");

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to