This patch introduces support for the 'socket' action primitive
to the netlink attributes.  This action directly enqueues data
to a kernel socket object identified by netns and socket inode
number.  A future patch will connect this to the netlink
datapath.

Signed-off-by: Aaron Conole <[email protected]>
---
 include/linux/openvswitch.h  | 12 ++++++
 lib/dpif-netdev.c            |  1 +
 lib/dpif.c                   |  3 +-
 lib/odp-execute.c            |  2 +
 lib/odp-util.c               | 80 +++++++++++++++++++++++++++++++++++-
 ofproto/ofproto-dpif-ipfix.c |  7 ++++
 ofproto/ofproto-dpif-sflow.c |  7 ++++
 7 files changed, 110 insertions(+), 2 deletions(-)

diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index e69fed4b73..e0c906b3a9 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -1125,6 +1125,7 @@ enum ovs_action_attr {
        OVS_ACTION_ATTR_DEC_TTL,      /* Nested OVS_DEC_TTL_ATTR_*. */
        OVS_ACTION_ATTR_DROP,         /* u32 xlate_error. */
        OVS_ACTION_ATTR_PSAMPLE,      /* Nested OVS_PSAMPLE_ATTR_*. */
+       OVS_ACTION_ATTR_SOCKET,       /* struct ovs_action_socket. */
 
 #ifndef __KERNEL__
        OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/
@@ -1235,4 +1236,15 @@ enum ovs_dec_ttl_attr {
                                      * keys. False otherwise.
                                      */
 
+enum ovs_socket_action_attr {
+       OVS_SOCKET_ACTION_ATTR_UNSPEC,
+       OVS_SOCKET_ACTION_ATTR_NETNS_ID,
+       OVS_SOCKET_ACTION_ATTR_INODE,
+       OVS_SOCKET_ACTION_ATTR_ACTIONS,
+
+       __OVS_SOCKET_ACTION_ATTR_MAX
+};
+
+#define OVS_SOCKET_ACTION_ATTR_MAX (__OVS_SOCKET_ACTION_ATTR_MAX - 1)
+
 #endif /* _LINUX_OPENVSWITCH_H */
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 87d69c46d5..1013d736eb 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -9495,6 +9495,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
*packets_,
     case OVS_ACTION_ATTR_ADD_MPLS:
     case OVS_ACTION_ATTR_DEC_TTL:
     case OVS_ACTION_ATTR_PSAMPLE:
+    case OVS_ACTION_ATTR_SOCKET:
     case __OVS_ACTION_ATTR_MAX:
         OVS_NOT_REACHED();
     }
diff --git a/lib/dpif.c b/lib/dpif.c
index 070fc0131f..ed8c817cab 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1198,7 +1198,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch 
*packets_,
     case OVS_ACTION_ATTR_USERSPACE:
     case OVS_ACTION_ATTR_PSAMPLE:
     case OVS_ACTION_ATTR_SAMPLE:
-    case OVS_ACTION_ATTR_RECIRC: {
+    case OVS_ACTION_ATTR_RECIRC:
+    case OVS_ACTION_ATTR_SOCKET: {
         struct dpif_execute execute;
         struct pkt_metadata *md = &packet->md;
 
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 7f4e337f8a..36548d1529 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -854,6 +854,7 @@ requires_datapath_assistance(const struct nlattr *a)
     case OVS_ACTION_ATTR_CT:
     case OVS_ACTION_ATTR_METER:
     case OVS_ACTION_ATTR_PSAMPLE:
+    case OVS_ACTION_ATTR_SOCKET:
         return true;
 
     case OVS_ACTION_ATTR_SET:
@@ -1292,6 +1293,7 @@ odp_execute_actions(void *dp, struct dp_packet_batch 
*batch, bool steal,
         case OVS_ACTION_ATTR_POP_VLAN:
         case OVS_ACTION_ATTR_PUSH_VLAN:
         case OVS_ACTION_ATTR_SET_MASKED:
+        case OVS_ACTION_ATTR_SOCKET:
             OVS_NOT_REACHED();
         }
 
diff --git a/lib/odp-util.c b/lib/odp-util.c
index ee18682020..9346d5dd80 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -101,6 +101,10 @@ static int parse_odp_action(struct parse_odp_context 
*context, const char *s,
 static int parse_odp_action__(struct parse_odp_context *context, const char *s,
                             struct ofpbuf *actions);
 
+static int parse_action_list(struct parse_odp_context *context, const char *s,
+                             struct ofpbuf *actions);
+
+
 /* Returns one the following for the action with the given OVS_ACTION_ATTR_*
  * 'type':
  *
@@ -146,7 +150,7 @@ odp_action_len(uint16_t type)
     case OVS_ACTION_ATTR_DEC_TTL: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_DROP: return sizeof(uint32_t);
     case OVS_ACTION_ATTR_PSAMPLE: return ATTR_LEN_VARIABLE;
-
+    case OVS_ACTION_ATTR_SOCKET: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
         return ATTR_LEN_INVALID;
@@ -1173,6 +1177,73 @@ format_odp_psample_action(struct ds *ds, const struct 
nlattr *attr)
     ds_put_char(ds, ')');
 }
 
+static void
+format_odp_socket_action(struct ds *ds, const struct nlattr *attr,
+                         const struct hmap *portno_names)
+{
+    static const struct nl_policy ovs_sock_act_policy[] = {
+        [OVS_SOCKET_ACTION_ATTR_NETNS_ID] = { .type = NL_A_U32 },
+        [OVS_SOCKET_ACTION_ATTR_INODE]    = { .type = NL_A_U64 },
+        [OVS_SOCKET_ACTION_ATTR_ACTIONS]  = { .type = NL_A_NESTED },
+    };
+
+    struct nlattr *a[ARRAY_SIZE(ovs_sock_act_policy)];
+    ds_put_cstr(ds, "socket");
+    if (!nl_parse_nested(attr, ovs_sock_act_policy, a, ARRAY_SIZE(a))) {
+        ds_put_cstr(ds, "(error)");
+        return;
+    }
+
+    if (!a[OVS_SOCKET_ACTION_ATTR_NETNS_ID] ||
+        !a[OVS_SOCKET_ACTION_ATTR_INODE] ||
+        !a[OVS_SOCKET_ACTION_ATTR_ACTIONS]) {
+        ds_put_cstr(ds, "(error)");
+        return;
+    }
+
+    uint32_t netns_id = nl_attr_get_u32(a[OVS_SOCKET_ACTION_ATTR_NETNS_ID]);
+    uint64_t inode = nl_attr_get_u64(a[OVS_SOCKET_ACTION_ATTR_INODE]);
+    ds_put_format(ds, "(netns=%"PRIu32",inode=%"PRIu64",else(",
+                  netns_id, inode);
+    struct nlattr *acts = a[OVS_SOCKET_ACTION_ATTR_ACTIONS];
+    format_odp_actions(ds, nl_attr_get(acts), nl_attr_get_size(acts),
+                           portno_names);
+    ds_put_cstr(ds, "))");
+}
+
+static int
+parse_odp_socket_action(struct parse_odp_context *context, const char *s,
+                        struct ofpbuf *actions)
+{
+    uint32_t netns;
+    uint64_t inode;
+    int n = 0;
+
+    if (ovs_scan(s, "socket(netns=%"SCNu32",inode=%"SCNu64",else(%n",
+                 &netns, &inode, &n)) {
+        size_t sock_ofs, actions_ofs;
+        sock_ofs = nl_msg_start_nested(actions, OVS_ACTION_ATTR_SOCKET);
+        nl_msg_put_u32(actions, OVS_SOCKET_ACTION_ATTR_NETNS_ID, netns);
+        nl_msg_put_u64(actions, OVS_SOCKET_ACTION_ATTR_INODE, inode);
+        actions_ofs = nl_msg_start_nested(actions,
+                                          OVS_SOCKET_ACTION_ATTR_ACTIONS);
+        if (!strncasecmp(s + n, "drop", 4)) {
+            n += 4;
+        } else {
+            int retval = parse_action_list(context, s + n, actions);
+            if (retval < 0) {
+                return retval;
+            }
+            n += retval;
+        }
+        nl_msg_end_nested(actions, actions_ofs);
+        nl_msg_end_nested(actions, sock_ofs);
+        return s[n + 1] == ')' ? n + 2 : -EINVAL;
+    }
+
+    return -EINVAL;
+}
+
 static void
 format_odp_action(struct ds *ds, const struct nlattr *a,
                   const struct hmap *portno_names)
@@ -1335,6 +1406,9 @@ format_odp_action(struct ds *ds, const struct nlattr *a,
     case OVS_ACTION_ATTR_PSAMPLE:
         format_odp_psample_action(ds, a);
         break;
+    case OVS_ACTION_ATTR_SOCKET:
+        format_odp_socket_action(ds, a, portno_names);
+        break;
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
     default:
@@ -2488,6 +2562,10 @@ parse_odp_action__(struct parse_odp_context *context, 
const char *s,
         }
     }
 
+    if (!strncmp(s, "socket(", 7)) {
+        return parse_odp_socket_action(context, s, actions);
+    }
+
     {
         uint32_t bond_id;
         int n;
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
index 1f561b3bc7..bb7ca64ede 100644
--- a/ofproto/ofproto-dpif-ipfix.c
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -3097,6 +3097,13 @@ dpif_ipfix_read_actions(const struct flow *flow,
                                     ipfix_actions);
             break;
 
+        case OVS_ACTION_ATTR_SOCKET:
+            /* XXX: This action should really do some kind of
+             * proper lookup to determine the output port for the
+             * sflow details.  For now, 'drop' it, but it is a
+             * needed bit of details. */
+            break;
+
         /* OVS_ACTION_ATTR_USERSPACE and OVS_ACTION_ATTR_RECIRC actions can
          * yield absolutely any kind of behavior. Let's assume that flow drops
          * the packet if there isn't another clear OVS_ACTION_ATTR_OUTPUT
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index c5403e27aa..5a164abc2b 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -1175,6 +1175,13 @@ dpif_sflow_read_actions(const struct flow *flow,
             }
             break;
 
+        case OVS_ACTION_ATTR_SOCKET:
+            /* XXX: This action should really do some kind of
+             * proper lookup to determine the output port for the
+             * sflow details.  For now, 'drop' it, but it is a
+             * needed bit of details. */
+            break;
+
         case OVS_ACTION_ATTR_TRUNC:
         case OVS_ACTION_ATTR_USERSPACE:
         case OVS_ACTION_ATTR_RECIRC:
-- 
2.51.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to