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
