summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJoe Stringer <joestringer@nicira.com>2015-09-15 14:29:16 -0700
committerJoe Stringer <joestringer@nicira.com>2015-10-13 15:34:16 -0700
commitd787ad39b8eb8fb9136837e1c65d0a18a1056eda (patch)
treec233e0ce5d00b526d3316c4c70028b2156f39123 /lib
parent9daf23484fb1f0d8fe8bf807a82c3d5b571a3dea (diff)
downloadopenvswitch-d787ad39b8eb8fb9136837e1c65d0a18a1056eda.tar.gz
Add support for connection tracking helper/ALGs.
This patch adds support for specifying a "helper" or ALG to assist connection tracking for protocols that consist of multiple streams. Initially, only support for FTP is included. Below is an example set of flows to allow FTP control connections from port 1->2 to establish active data connections in the reverse direction: table=0,priority=1,action=drop table=0,arp,action=normal table=0,in_port=1,tcp,action=ct(alg=ftp,commit),2 table=0,in_port=2,tcp,ct_state=-trk,action=ct(table=1) table=1,in_port=2,tcp,ct_state=+trk+est,action=1 table=1,in_port=2,tcp,ct_state=+trk+rel,action=ct(commit),1 Signed-off-by: Joe Stringer <joestringer@nicira.com> Acked-by: Jarno Rajahalme <jrajahalme@nicira.com> Acked-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/netlink.c11
-rw-r--r--lib/netlink.h2
-rw-r--r--lib/odp-util.c26
-rw-r--r--lib/ofp-actions.c41
-rw-r--r--lib/ofp-actions.h1
-rw-r--r--lib/ofp-parse.c15
-rw-r--r--lib/ofp-parse.h1
7 files changed, 95 insertions, 2 deletions
diff --git a/lib/netlink.c b/lib/netlink.c
index 6bb353719..a2be59d02 100644
--- a/lib/netlink.c
+++ b/lib/netlink.c
@@ -325,6 +325,17 @@ nl_msg_put_odp_port(struct ofpbuf *msg, uint16_t type, odp_port_t value)
nl_msg_put_u32(msg, type, odp_to_u32(value));
}
+/* Appends a Netlink attribute of the given 'type' with the 'len' characters
+ * of 'value', followed by the null byte to 'msg'. */
+void
+nl_msg_put_string__(struct ofpbuf *msg, uint16_t type, const char *value,
+ size_t len)
+{
+ char *data = nl_msg_put_unspec_uninit(msg, type, len + 1);
+
+ memcpy(data, value, len);
+ data[len] = '\0';
+}
/* Appends a Netlink attribute of the given 'type' and the given
* null-terminated string 'value' to 'msg'. */
diff --git a/lib/netlink.h b/lib/netlink.h
index eed71dd2e..b931a412f 100644
--- a/lib/netlink.h
+++ b/lib/netlink.h
@@ -73,6 +73,8 @@ void nl_msg_put_be64(struct ofpbuf *, uint16_t type, ovs_be64 value);
void nl_msg_put_in6_addr(struct ofpbuf *msg, uint16_t type,
const struct in6_addr *value);
void nl_msg_put_odp_port(struct ofpbuf *, uint16_t type, odp_port_t value);
+void nl_msg_put_string__(struct ofpbuf *, uint16_t type, const char *value,
+ size_t len);
void nl_msg_put_string(struct ofpbuf *, uint16_t type, const char *value);
size_t nl_msg_start_nested(struct ofpbuf *, uint16_t type);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 86798bdfe..e131e3670 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -52,6 +52,7 @@ VLOG_DEFINE_THIS_MODULE(odp_util);
/* The set of characters that may separate one action or one key attribute
* from another. */
static const char *delimiters = ", \t\r\n";
+static const char *delimiters_end = ", \t\r\n)";
struct attr_len_tbl {
int len;
@@ -548,6 +549,8 @@ static const struct nl_policy ovs_conntrack_policy[] = {
.min_len = sizeof(uint32_t) * 2 },
[OVS_CT_ATTR_LABELS] = { .type = NL_A_UNSPEC, .optional = true,
.min_len = sizeof(struct ovs_key_ct_labels) * 2 },
+ [OVS_CT_ATTR_HELPER] = { .type = NL_A_STRING, .optional = true,
+ .min_len = 1, .max_len = 16 },
};
static void
@@ -556,6 +559,7 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr)
struct nlattr *a[ARRAY_SIZE(ovs_conntrack_policy)];
const ovs_u128 *label;
const uint32_t *mark;
+ const char *helper;
uint16_t zone;
bool commit;
@@ -568,9 +572,10 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr)
zone = a[OVS_CT_ATTR_ZONE] ? nl_attr_get_u16(a[OVS_CT_ATTR_ZONE]) : 0;
mark = a[OVS_CT_ATTR_MARK] ? nl_attr_get(a[OVS_CT_ATTR_MARK]) : NULL;
label = a[OVS_CT_ATTR_LABELS] ? nl_attr_get(a[OVS_CT_ATTR_LABELS]): NULL;
+ helper = a[OVS_CT_ATTR_HELPER] ? nl_attr_get(a[OVS_CT_ATTR_HELPER]) : NULL;
ds_put_format(ds, "ct");
- if (commit || zone || mark || label) {
+ if (commit || zone || mark || label || helper) {
ds_put_cstr(ds, "(");
if (commit) {
ds_put_format(ds, "commit,");
@@ -586,6 +591,9 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr)
ds_put_format(ds, "label=");
format_u128(ds, label, label + 1, true);
}
+ if (helper) {
+ ds_put_format(ds, "helper=%s,", helper);
+ }
ds_chomp(ds, ',');
ds_put_cstr(ds, ")");
}
@@ -1027,6 +1035,8 @@ parse_conntrack_action(const char *s_, struct ofpbuf *actions)
const char *s = s_;
if (ovs_scan(s, "ct")) {
+ const char *helper = NULL;
+ size_t helper_len = 0;
bool commit = false;
uint16_t zone = 0;
struct {
@@ -1084,6 +1094,16 @@ parse_conntrack_action(const char *s_, struct ofpbuf *actions)
s += retval;
continue;
}
+ if (ovs_scan(s, "helper=%n", &n)) {
+ s += n;
+ helper_len = strcspn(s, delimiters_end);
+ if (!helper_len || helper_len > 15) {
+ return -EINVAL;
+ }
+ helper = s;
+ s += helper_len;
+ continue;
+ }
return -EINVAL;
}
@@ -1105,6 +1125,10 @@ parse_conntrack_action(const char *s_, struct ofpbuf *actions)
nl_msg_put_unspec(actions, OVS_CT_ATTR_LABELS, &ct_label,
sizeof ct_label);
}
+ if (helper) {
+ nl_msg_put_string__(actions, OVS_CT_ATTR_HELPER, helper,
+ helper_len);
+ }
nl_msg_end_nested(actions, start);
}
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 4176ebb00..5f72fda16 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -15,6 +15,8 @@
*/
#include <config.h>
+#include <netinet/in.h>
+
#include "ofp-actions.h"
#include "bundle.h"
#include "byte-order.h"
@@ -4662,6 +4664,26 @@ format_DEBUG_RECIRC(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
* It is strongly recommended that this table is later than the current
* table, to prevent loops.
*
+ * The "alg" attaches protocol-specific behaviour to this action:
+ *
+ * The ALG is a 16-bit number which specifies that additional
+ * processing should be applied to this traffic.
+ *
+ * Protocol | Value | Meaning
+ * --------------------------------------------------------------------
+ * None | 0 | No protocol-specific behaviour.
+ * FTP | 21 | Parse FTP control connections and observe the
+ * | | negotiation of related data connections.
+ * Other | Other | Unsupported protocols.
+ *
+ * By way of example, if FTP control connections have this action applied
+ * with the ALG set to FTP (21), then the connection tracker will observe
+ * the negotiation of data connections. This allows the connection
+ * tracker to identify subsequent data connections as "related" to this
+ * existing connection. The "related" flag will be populated in the
+ * NXM_NX_CT_STATE field for such connections if the 'recirc_table' is
+ * specified.
+ *
* Zero or more actions may immediately follow this action. These actions will
* be executed within the context of the connection tracker, and they require
* the NX_CT_F_COMMIT flag to be set.
@@ -4680,7 +4702,9 @@ struct nx_action_conntrack {
};
uint8_t recirc_table; /* Recirculate to a specific table, or
NX_CT_RECIRC_NONE for no recirculation. */
- uint8_t pad[5]; /* Zeroes */
+ uint8_t pad[3]; /* Zeroes */
+ ovs_be16 alg; /* Well-known port number for the protocol.
+ * 0 indicates no ALG is required. */
/* Followed by a sequence of zero or more OpenFlow actions. The length of
* these is included in 'len'. */
};
@@ -4730,6 +4754,7 @@ decode_NXAST_RAW_CT(const struct nx_action_conntrack *nac,
goto out;
}
conntrack->recirc_table = nac->recirc_table;
+ conntrack->alg = ntohs(nac->alg);
ofpbuf_pull(out, sizeof(*conntrack));
@@ -4777,6 +4802,7 @@ encode_CT(const struct ofpact_conntrack *conntrack,
nac->zone_imm = htons(conntrack->zone_imm);
}
nac->recirc_table = conntrack->recirc_table;
+ nac->alg = htons(conntrack->alg);
len = ofpacts_put_openflow_actions(conntrack->actions,
ofpact_ct_get_action_len(conntrack),
@@ -4821,6 +4847,8 @@ parse_CT(char *arg, struct ofpbuf *ofpacts,
return error;
}
}
+ } else if (!strcmp(key, "alg")) {
+ error = str_to_connhelper(value, &oc->alg);
} else if (!strcmp(key, "exec")) {
/* Hide existing actions from ofpacts_parse_copy(), so the
* nesting can be handled transparently. */
@@ -4844,6 +4872,16 @@ parse_CT(char *arg, struct ofpbuf *ofpacts,
}
static void
+format_alg(int port, struct ds *s)
+{
+ if (port == IPPORT_FTP) {
+ ds_put_format(s, "alg=ftp,");
+ } else if (port) {
+ ds_put_format(s, "alg=%d,", port);
+ }
+}
+
+static void
format_CT(const struct ofpact_conntrack *a, struct ds *s)
{
ds_put_cstr(s, "ct(");
@@ -4865,6 +4903,7 @@ format_CT(const struct ofpact_conntrack *a, struct ds *s)
ofpacts_format(a->actions, ofpact_ct_get_action_len(a), s);
ds_put_format(s, "),");
}
+ format_alg(a->alg, s);
ds_chomp(s, ',');
ds_put_char(s, ')');
}
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index e359b8296..0ad2e3f9f 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -495,6 +495,7 @@ struct { \
uint16_t flags; \
uint16_t zone_imm; \
struct mf_subfield zone_src; \
+ uint16_t alg; \
uint8_t recirc_table; \
}
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 5950f06ee..843765650 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -21,6 +21,7 @@
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
+#include <netinet/in.h>
#include "byte-order.h"
#include "dynamic-string.h"
@@ -168,6 +169,20 @@ str_to_ip(const char *str, ovs_be32 *ip)
return NULL;
}
+/* Parses 'str' as a conntrack helper into 'alg'.
+ *
+ * Returns NULL if successful, otherwise a malloc()'d string describing the
+ * error. The caller is responsible for freeing the returned string. */
+char * OVS_WARN_UNUSED_RESULT
+str_to_connhelper(const char *str, uint16_t *alg)
+{
+ if (!strcmp(str, "ftp")) {
+ *alg = IPPORT_FTP;
+ return NULL;
+ }
+ return xasprintf("invalid conntrack helper \"%s\"", str);
+}
+
struct protocol {
const char *name;
uint16_t dl_type;
diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h
index b64a32ebd..36f9acc2d 100644
--- a/lib/ofp-parse.h
+++ b/lib/ofp-parse.h
@@ -99,5 +99,6 @@ char *str_to_u64(const char *str, uint64_t *valuep) OVS_WARN_UNUSED_RESULT;
char *str_to_be64(const char *str, ovs_be64 *valuep) OVS_WARN_UNUSED_RESULT;
char *str_to_mac(const char *str, struct eth_addr *mac) OVS_WARN_UNUSED_RESULT;
char *str_to_ip(const char *str, ovs_be32 *ip) OVS_WARN_UNUSED_RESULT;
+char *str_to_connhelper(const char *str, uint16_t *alg) OVS_WARN_UNUSED_RESULT;
#endif /* ofp-parse.h */