summaryrefslogtreecommitdiff
path: root/lib/odp-util.c
diff options
context:
space:
mode:
authorWenyu Zhang <wenyuz@vmware.com>2014-08-17 20:19:36 -0700
committerPravin B Shelar <pshelar@nicira.com>2014-08-18 01:01:10 -0700
commit8b7ea2d4803381c249f5886aac80f8dbe51ba771 (patch)
treedc30224f9405a00d13f59c02b91bdd8453198277 /lib/odp-util.c
parent84067a4c1a5033ad43ed444d1cb7f40ebddbf2e3 (diff)
downloadopenvswitch-8b7ea2d4803381c249f5886aac80f8dbe51ba771.tar.gz
Extend OVS IPFIX exporter to export tunnel headers
Extend IPFIX exporter to export tunnel headers when both input and output of the port. Add three other_config options in IPFIX table: enable-input-sampling, enable-output-sampling and enable-tunnel-sampling, to control whether sampling tunnel info, on which direction (input or output). Insert sampling action before output action and the output tunnel port is sent to datapath in the sampling action. Make datapath collect output tunnel info and send it back to userpace in upcall message with a new additional optional attribute. Add a tunnel ports map to make the tunnel port lookup faster in sampling upcalls in IPFIX exporter. Make the IPFIX exporter generate IPFIX template sets with enterprise elements for the tunnel info, save the tunnel info in IPFIX cache entries, and send IPFIX DATA with tunnel info. Add flowDirection element in IPFIX templates. Signed-off-by: Wenyu Zhang <wenyuz@vmware.com> Acked-by: Romain Lenglet <rlenglet@vmware.com> Acked-by: Ben Pfaff <blp@nicira.com> Acked-by: Pravin B Shelar <pshelar@nicira.com>
Diffstat (limited to 'lib/odp-util.c')
-rw-r--r--lib/odp-util.c184
1 files changed, 118 insertions, 66 deletions
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 162d85a70..ffc3673ee 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -261,9 +261,12 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
[OVS_USERSPACE_ATTR_PID] = { .type = NL_A_U32 },
[OVS_USERSPACE_ATTR_USERDATA] = { .type = NL_A_UNSPEC,
.optional = true },
+ [OVS_USERSPACE_ATTR_EGRESS_TUN_PORT] = { .type = NL_A_U32,
+ .optional = true },
};
struct nlattr *a[ARRAY_SIZE(ovs_userspace_policy)];
const struct nlattr *userdata_attr;
+ const struct nlattr *tunnel_out_port_attr;
if (!nl_parse_nested(attr, ovs_userspace_policy, a, ARRAY_SIZE(a))) {
ds_put_cstr(ds, "userspace(error)");
@@ -314,7 +317,8 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
cookie.flow_sample.obs_point_id);
} else if (userdata_len >= sizeof cookie.ipfix
&& cookie.type == USER_ACTION_COOKIE_IPFIX) {
- ds_put_format(ds, ",ipfix");
+ ds_put_format(ds, ",ipfix(output_port=%"PRIu32")",
+ cookie.ipfix.output_odp_port);
} else {
userdata_unspec = true;
}
@@ -330,6 +334,12 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
}
}
+ tunnel_out_port_attr = a[OVS_USERSPACE_ATTR_EGRESS_TUN_PORT];
+ if (tunnel_out_port_attr) {
+ ds_put_format(ds, ",tunnel_out_port=%"PRIu32,
+ nl_attr_get_u32(tunnel_out_port_attr));
+ }
+
ds_put_char(ds, ')');
}
@@ -506,50 +516,36 @@ format_odp_actions(struct ds *ds, const struct nlattr *actions,
}
}
+/* Separate out parse_odp_userspace_action() function. */
static int
-parse_odp_action(const char *s, const struct simap *port_names,
- struct ofpbuf *actions)
+parse_odp_userspace_action(const char *s, struct ofpbuf *actions)
{
- {
- uint32_t port;
- int n;
+ uint32_t pid;
+ union user_action_cookie cookie;
+ struct ofpbuf buf;
+ odp_port_t tunnel_out_port;
+ int n = -1;
+ void *user_data = NULL;
+ size_t user_data_size = 0;
- if (ovs_scan(s, "%"SCNi32"%n", &port, &n)) {
- nl_msg_put_u32(actions, OVS_ACTION_ATTR_OUTPUT, port);
- return n;
- }
- }
-
- if (port_names) {
- int len = strcspn(s, delimiters);
- struct simap_node *node;
-
- node = simap_find_len(port_names, s, len);
- if (node) {
- nl_msg_put_u32(actions, OVS_ACTION_ATTR_OUTPUT, node->data);
- return len;
- }
+ if (!ovs_scan(s, "userspace(pid=%"SCNi32"%n", &pid, &n)) {
+ return -EINVAL;
}
{
- uint32_t pid;
uint32_t output;
uint32_t probability;
uint32_t collector_set_id;
uint32_t obs_domain_id;
uint32_t obs_point_id;
int vid, pcp;
- int n = -1;
-
- if (ovs_scan(s, "userspace(pid=%"SCNi32")%n", &pid, &n)) {
- odp_put_userspace_action(pid, NULL, 0, actions);
- return n;
- } else if (ovs_scan(s, "userspace(pid=%"SCNi32",sFlow(vid=%i,"
- "pcp=%i,output=%"SCNi32"))%n",
- &pid, &vid, &pcp, &output, &n)) {
- union user_action_cookie cookie;
+ int n1 = -1;
+ if (ovs_scan(&s[n], ",sFlow(vid=%i,"
+ "pcp=%i,output=%"SCNi32")%n",
+ &vid, &pcp, &output, &n1)) {
uint16_t tci;
+ n += n1;
tci = vid | (pcp << VLAN_PCP_SHIFT);
if (tci) {
tci |= VLAN_CFI;
@@ -558,14 +554,13 @@ parse_odp_action(const char *s, const struct simap *port_names,
cookie.type = USER_ACTION_COOKIE_SFLOW;
cookie.sflow.vlan_tci = htons(tci);
cookie.sflow.output = output;
- odp_put_userspace_action(pid, &cookie, sizeof cookie.sflow,
- actions);
- return n;
- } else if (ovs_scan(s, "userspace(pid=%"SCNi32",slow_path%n",
- &pid, &n)) {
- union user_action_cookie cookie;
+ user_data = &cookie;
+ user_data_size = sizeof cookie.sflow;
+ } else if (ovs_scan(&s[n], ",slow_path%n",
+ &n1)) {
int res;
+ n += n1;
cookie.type = USER_ACTION_COOKIE_SLOW_PATH;
cookie.slow_path.unused = 0;
cookie.slow_path.reason = 0;
@@ -576,53 +571,91 @@ parse_odp_action(const char *s, const struct simap *port_names,
return res;
}
n += res;
- if (s[n] != ')') {
- return -EINVAL;
- }
- n++;
- odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path,
- actions);
- return n;
- } else if (ovs_scan(s, "userspace(pid=%"SCNi32","
- "flow_sample(probability=%"SCNi32","
+ user_data = &cookie;
+ user_data_size = sizeof cookie.slow_path;
+ } else if (ovs_scan(&s[n], ",flow_sample(probability=%"SCNi32","
"collector_set_id=%"SCNi32","
"obs_domain_id=%"SCNi32","
- "obs_point_id=%"SCNi32"))%n",
- &pid, &probability, &collector_set_id,
- &obs_domain_id, &obs_point_id, &n)) {
- union user_action_cookie cookie;
+ "obs_point_id=%"SCNi32")%n",
+ &probability, &collector_set_id,
+ &obs_domain_id, &obs_point_id, &n1)) {
+ n += n1;
cookie.type = USER_ACTION_COOKIE_FLOW_SAMPLE;
cookie.flow_sample.probability = probability;
cookie.flow_sample.collector_set_id = collector_set_id;
cookie.flow_sample.obs_domain_id = obs_domain_id;
cookie.flow_sample.obs_point_id = obs_point_id;
- odp_put_userspace_action(pid, &cookie, sizeof cookie.flow_sample,
- actions);
- return n;
- } else if (ovs_scan(s, "userspace(pid=%"SCNi32",ipfix)%n", &pid, &n)) {
- union user_action_cookie cookie;
-
+ user_data = &cookie;
+ user_data_size = sizeof cookie.flow_sample;
+ } else if (ovs_scan(&s[n], ",ipfix(output_port=%"SCNi32")%n",
+ &output, &n1) ) {
+ n += n1;
cookie.type = USER_ACTION_COOKIE_IPFIX;
- odp_put_userspace_action(pid, &cookie, sizeof cookie.ipfix,
- actions);
- return n;
- } else if (ovs_scan(s, "userspace(pid=%"SCNi32",userdata(%n",
- &pid, &n)) {
- struct ofpbuf buf;
+ cookie.ipfix.output_odp_port = u32_to_odp(output);
+ user_data = &cookie;
+ user_data_size = sizeof cookie.ipfix;
+ } else if (ovs_scan(&s[n], ",userdata(%n",
+ &n1)) {
char *end;
+ n += n1;
ofpbuf_init(&buf, 16);
end = ofpbuf_put_hex(&buf, &s[n], NULL);
- if (end[0] == ')' && end[1] == ')') {
- odp_put_userspace_action(pid, ofpbuf_data(&buf), ofpbuf_size(&buf), actions);
- ofpbuf_uninit(&buf);
- return (end + 2) - s;
+ if (end[0] != ')') {
+ return -EINVAL;
}
+ user_data = ofpbuf_data(&buf);
+ user_data_size = ofpbuf_size(&buf);
+ n = (end + 1) - s;
}
}
+ {
+ int n1 = -1;
+ if (ovs_scan(&s[n], ",tunnel_out_port=%"SCNi32")%n",
+ &tunnel_out_port, &n1)) {
+ odp_put_userspace_action(pid, user_data, user_data_size, tunnel_out_port, actions);
+ return n + n1;
+ } else if (s[n] == ')') {
+ odp_put_userspace_action(pid, user_data, user_data_size, ODPP_NONE, actions);
+ return n + 1;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int
+parse_odp_action(const char *s, const struct simap *port_names,
+ struct ofpbuf *actions)
+{
+ {
+ uint32_t port;
+ int n;
+
+ if (ovs_scan(s, "%"SCNi32"%n", &port, &n)) {
+ nl_msg_put_u32(actions, OVS_ACTION_ATTR_OUTPUT, port);
+ return n;
+ }
+ }
+
+ if (port_names) {
+ int len = strcspn(s, delimiters);
+ struct simap_node *node;
+
+ node = simap_find_len(port_names, s, len);
+ if (node) {
+ nl_msg_put_u32(actions, OVS_ACTION_ATTR_OUTPUT, node->data);
+ return len;
+ }
+ }
+
+ if (!strncmp(s, "userspace(", 10)) {
+ return parse_odp_userspace_action(s, actions);
+ }
+
if (!strncmp(s, "set(", 4)) {
size_t start_ofs;
int retval;
@@ -832,6 +865,8 @@ tunnel_key_attr_len(int type)
case OVS_TUNNEL_KEY_ATTR_TTL: return 1;
case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: return 0;
case OVS_TUNNEL_KEY_ATTR_CSUM: return 0;
+ case OVS_TUNNEL_KEY_ATTR_TP_SRC: return 2;
+ case OVS_TUNNEL_KEY_ATTR_TP_DST: return 2;
case OVS_TUNNEL_KEY_ATTR_OAM: return 0;
case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS: return -2;
case __OVS_TUNNEL_KEY_ATTR_MAX:
@@ -914,6 +949,12 @@ odp_tun_key_from_attr(const struct nlattr *attr, struct flow_tnl *tun)
case OVS_TUNNEL_KEY_ATTR_CSUM:
tun->flags |= FLOW_TNL_F_CSUM;
break;
+ case OVS_TUNNEL_KEY_ATTR_TP_SRC:
+ tun->tp_src = nl_attr_get_be16(a);
+ break;
+ case OVS_TUNNEL_KEY_ATTR_TP_DST:
+ tun->tp_dst = nl_attr_get_be16(a);
+ break;
case OVS_TUNNEL_KEY_ATTR_OAM:
tun->flags |= FLOW_TNL_F_OAM;
break;
@@ -970,6 +1011,12 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key)
if (tun_key->flags & FLOW_TNL_F_CSUM) {
nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_CSUM);
}
+ if (tun_key->tp_src) {
+ nl_msg_put_be16(a, OVS_TUNNEL_KEY_ATTR_TP_SRC, tun_key->tp_src);
+ }
+ if (tun_key->tp_dst) {
+ nl_msg_put_be16(a, OVS_TUNNEL_KEY_ATTR_TP_DST, tun_key->tp_dst);
+ }
if (tun_key->flags & FLOW_TNL_F_OAM) {
nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_OAM);
}
@@ -3503,6 +3550,7 @@ odp_key_fitness_to_string(enum odp_key_fitness fitness)
size_t
odp_put_userspace_action(uint32_t pid,
const void *userdata, size_t userdata_size,
+ odp_port_t tunnel_out_port,
struct ofpbuf *odp_actions)
{
size_t userdata_ofs;
@@ -3529,6 +3577,10 @@ odp_put_userspace_action(uint32_t pid,
} else {
userdata_ofs = 0;
}
+ if (tunnel_out_port != ODPP_NONE) {
+ nl_msg_put_odp_port(odp_actions, OVS_USERSPACE_ATTR_EGRESS_TUN_PORT,
+ tunnel_out_port);
+ }
nl_msg_end_nested(odp_actions, offset);
return userdata_ofs;