Skip to content

Commit

Permalink
Extend OVS IPFIX exporter to export tunnel headers
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Romain Lenglet <[email protected]>
Acked-by: Ben Pfaff <[email protected]>
Acked-by: Pravin B Shelar <[email protected]>
  • Loading branch information
WenyuZhang authored and Pravin B Shelar committed Aug 18, 2014
1 parent 84067a4 commit 8b7ea2d
Show file tree
Hide file tree
Showing 34 changed files with 1,170 additions and 201 deletions.
1 change: 1 addition & 0 deletions datapath-windows/ovsext/OvsNetProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ typedef UINT64 IP6UnitLength;
#define IPPROTO_ICMP 1
#define IPPROTO_IGMP 2
#define IPPROTO_UDP 17
#define IPPROTO_GRE 47
#define IPPROTO_TCP 6
#define IPPROTO_RSVD 0xff

Expand Down
19 changes: 19 additions & 0 deletions datapath/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -637,10 +637,12 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
struct dp_upcall_info upcall;
const struct nlattr *a;
int rem;
struct ovs_tunnel_info info;

upcall.cmd = OVS_PACKET_CMD_ACTION;
upcall.userdata = NULL;
upcall.portid = 0;
upcall.egress_tun_info = NULL;

for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
a = nla_next(a, &rem)) {
Expand All @@ -652,7 +654,24 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
case OVS_USERSPACE_ATTR_PID:
upcall.portid = nla_get_u32(a);
break;

case OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: {
/* Get out tunnel info. */
struct vport *vport;

vport = ovs_vport_rcu(dp, nla_get_u32(a));
if (vport) {
int err;

err = ovs_vport_get_egress_tun_info(vport, skb,
&info);
if (!err)
upcall.egress_tun_info = &info;
}
break;
}

} /* End of switch. */
}

return ovs_dp_upcall(dp, skb, &upcall);
Expand Down
21 changes: 17 additions & 4 deletions datapath/datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, bool recirc)
upcall.cmd = OVS_PACKET_CMD_MISS;
upcall.userdata = NULL;
upcall.portid = ovs_vport_find_upcall_portid(p, skb);
upcall.egress_tun_info = NULL;
ovs_dp_upcall(dp, skb, &upcall);
consume_skb(skb);
stats_counter = &stats->n_missed;
Expand Down Expand Up @@ -369,16 +370,20 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
return err;
}

static size_t upcall_msg_size(const struct nlattr *userdata,
static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
unsigned int hdrlen)
{
size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
+ nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
+ nla_total_size(ovs_key_attr_size()); /* OVS_PACKET_ATTR_KEY */

/* OVS_PACKET_ATTR_USERDATA */
if (userdata)
size += NLA_ALIGN(userdata->nla_len);
if (upcall_info->userdata)
size += NLA_ALIGN(upcall_info->userdata->nla_len);

/* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
if (upcall_info->egress_tun_info)
size += nla_total_size(ovs_tun_key_attr_size());

return size;
}
Expand Down Expand Up @@ -438,7 +443,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
else
hlen = skb->len;

len = upcall_msg_size(upcall_info->userdata, hlen);
len = upcall_msg_size(upcall_info, hlen);
user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
if (!user_skb) {
err = -ENOMEM;
Expand All @@ -459,6 +464,14 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
nla_len(upcall_info->userdata),
nla_data(upcall_info->userdata));

if (upcall_info->egress_tun_info) {
nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY);
err = ovs_nla_put_egress_tunnel_key(user_skb,
upcall_info->egress_tun_info);
BUG_ON(err);
nla_nest_end(user_skb, nla);
}

/* Only reserve room for attribute header, packet data is added
* in skb_zerocopy() */
if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {
Expand Down
2 changes: 2 additions & 0 deletions datapath/datapath.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,13 @@ struct ovs_skb_cb {
* @portid: Netlink PID to which packet should be sent. If @portid is 0 then no
* packet is sent and the packet is accounted in the datapath's @n_lost
* counter.
* @egress_tun_info: If nonnull, becomes %OVS_PACKET_ATTR_EGRESS_TUN_KEY.
*/
struct dp_upcall_info {
const struct nlattr *userdata;
u32 portid;
u8 cmd;
const struct ovs_tunnel_info *egress_tun_info;
};

/**
Expand Down
60 changes: 45 additions & 15 deletions datapath/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ struct sk_buff;

/* Used to memset ovs_key_ipv4_tunnel padding. */
#define OVS_TUNNEL_KEY_SIZE \
(offsetof(struct ovs_key_ipv4_tunnel, ipv4_ttl) + \
FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, ipv4_ttl))
(offsetof(struct ovs_key_ipv4_tunnel, tp_dst) + \
FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, tp_dst))

struct ovs_key_ipv4_tunnel {
__be64 tun_id;
Expand All @@ -49,6 +49,8 @@ struct ovs_key_ipv4_tunnel {
__be16 tun_flags;
u8 ipv4_tos;
u8 ipv4_ttl;
__be16 tp_src;
__be16 tp_dst;
} __packed __aligned(4); /* Minimize padding. */

struct ovs_tunnel_info {
Expand All @@ -66,32 +68,60 @@ struct ovs_tunnel_info {
FIELD_SIZEOF(struct sw_flow_key, tun_opts) - \
opt_len)

static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
const struct iphdr *iph, __be64 tun_id,
__be16 tun_flags,
struct geneve_opt *opts,
u8 opts_len)
static inline void __ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
__be32 saddr, __be32 daddr,
u8 tos, u8 ttl,
__be16 tp_src,
__be16 tp_dst,
__be64 tun_id,
__be16 tun_flags,
struct geneve_opt *opts,
u8 opts_len)
{
tun_info->tunnel.tun_id = tun_id;
tun_info->tunnel.ipv4_src = iph->saddr;
tun_info->tunnel.ipv4_dst = iph->daddr;
tun_info->tunnel.ipv4_tos = iph->tos;
tun_info->tunnel.ipv4_ttl = iph->ttl;
tun_info->tunnel.ipv4_src = saddr;
tun_info->tunnel.ipv4_dst = daddr;
tun_info->tunnel.ipv4_tos = tos;
tun_info->tunnel.ipv4_ttl = ttl;
tun_info->tunnel.tun_flags = tun_flags;

/* clear struct padding. */
memset((unsigned char *) &tun_info->tunnel + OVS_TUNNEL_KEY_SIZE, 0,
sizeof(tun_info->tunnel) - OVS_TUNNEL_KEY_SIZE);
/* For the tunnel types on the top of IPsec, the tp_src and tp_dst of
* the upper tunnel are used.
* E.g: GRE over IPSEC, the tp_src and tp_port are zero.
*/
tun_info->tunnel.tp_src = tp_src;
tun_info->tunnel.tp_dst = tp_dst;

/* Clear struct padding. */
if (sizeof(tun_info->tunnel) != OVS_TUNNEL_KEY_SIZE)
memset((unsigned char *) &tun_info->tunnel +
OVS_TUNNEL_KEY_SIZE,
0, sizeof(tun_info->tunnel) - OVS_TUNNEL_KEY_SIZE);

tun_info->options = opts;
tun_info->options_len = opts_len;
}

static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
const struct iphdr *iph,
__be16 tp_src,
__be16 tp_dst,
__be64 tun_id,
__be16 tun_flags,
struct geneve_opt *opts,
u8 opts_len)
{
__ovs_flow_tun_info_init(tun_info, iph->saddr, iph->daddr,
iph->tos, iph->ttl,
tp_src, tp_dst,
tun_id, tun_flags,
opts, opts_len);
}

#define OVS_SW_FLOW_KEY_METADATA_SIZE \
(offsetof(struct sw_flow_key, recirc_id) + \
FIELD_SIZEOF(struct sw_flow_key, recirc_id))


struct sw_flow_key {
u8 tun_opts[255];
u8 tun_opts_len;
Expand Down
85 changes: 66 additions & 19 deletions datapath/flow_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,23 @@ static bool match_validate(const struct sw_flow_match *match,
return true;
}

size_t ovs_tun_key_attr_size(void)
{
/* Whenever adding new OVS_TUNNEL_KEY_ FIELDS, we should consider
* updating this function. */
return nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */
+ nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */
+ nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
+ nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
+ nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
+ nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
}

size_t ovs_key_attr_size(void)
{
/* Whenever adding new OVS_KEY_ FIELDS, we should consider
Expand All @@ -254,15 +271,7 @@ size_t ovs_key_attr_size(void)

return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
+ nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
+ nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */
+ nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */
+ nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
+ nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
+ nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
+ nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
+ ovs_tun_key_attr_size()
+ nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */
+ nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */
+ nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */
Expand Down Expand Up @@ -392,6 +401,8 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
[OVS_TUNNEL_KEY_ATTR_TTL] = 1,
[OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0,
[OVS_TUNNEL_KEY_ATTR_CSUM] = 0,
[OVS_TUNNEL_KEY_ATTR_TP_SRC] = sizeof(u16),
[OVS_TUNNEL_KEY_ATTR_TP_DST] = sizeof(u16),
[OVS_TUNNEL_KEY_ATTR_OAM] = 0,
[OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = -1,
};
Expand Down Expand Up @@ -439,6 +450,14 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
case OVS_TUNNEL_KEY_ATTR_CSUM:
tun_flags |= TUNNEL_CSUM;
break;
case OVS_TUNNEL_KEY_ATTR_TP_SRC:
SW_FLOW_KEY_PUT(match, tun_key.tp_src,
nla_get_be16(a), is_mask);
break;
case OVS_TUNNEL_KEY_ATTR_TP_DST:
SW_FLOW_KEY_PUT(match, tun_key.tp_dst,
nla_get_be16(a), is_mask);
break;
case OVS_TUNNEL_KEY_ATTR_OAM:
tun_flags |= TUNNEL_OAM;
break;
Expand Down Expand Up @@ -521,17 +540,11 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
return 0;
}

static int ipv4_tun_to_nlattr(struct sk_buff *skb,
const struct ovs_key_ipv4_tunnel *output,
const struct geneve_opt *tun_opts,
int swkey_tun_opts_len)
static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
const struct ovs_key_ipv4_tunnel *output,
const struct geneve_opt *tun_opts,
int swkey_tun_opts_len)
{
struct nlattr *nla;

nla = nla_nest_start(skb, OVS_KEY_ATTR_TUNNEL);
if (!nla)
return -EMSGSIZE;

if (output->tun_flags & TUNNEL_KEY &&
nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id))
return -EMSGSIZE;
Expand All @@ -552,6 +565,12 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb,
if ((output->tun_flags & TUNNEL_CSUM) &&
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM))
return -EMSGSIZE;
if (output->tp_src &&
nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_SRC, output->tp_src))
return -EMSGSIZE;
if (output->tp_dst &&
nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_DST, output->tp_dst))
return -EMSGSIZE;
if ((output->tun_flags & TUNNEL_OAM) &&
nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
return -EMSGSIZE;
Expand All @@ -560,10 +579,37 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb,
swkey_tun_opts_len, tun_opts))
return -EMSGSIZE;

return 0;
}


static int ipv4_tun_to_nlattr(struct sk_buff *skb,
const struct ovs_key_ipv4_tunnel *output,
const struct geneve_opt *tun_opts,
int swkey_tun_opts_len)
{
struct nlattr *nla;
int err;

nla = nla_nest_start(skb, OVS_KEY_ATTR_TUNNEL);
if (!nla)
return -EMSGSIZE;

err = __ipv4_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len);
if (err)
return err;

nla_nest_end(skb, nla);
return 0;
}

int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb,
const struct ovs_tunnel_info *egress_tun_info)
{
return __ipv4_tun_to_nlattr(skb, &egress_tun_info->tunnel,
egress_tun_info->options,
egress_tun_info->options_len);
}

static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
const struct nlattr **a, bool is_mask)
Expand Down Expand Up @@ -1650,6 +1696,7 @@ static int validate_userspace(const struct nlattr *attr)
static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = {
[OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
[OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
[OVS_USERSPACE_ATTR_EGRESS_TUN_PORT] = {.type = NLA_U32 },
};
struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
int error;
Expand Down
3 changes: 3 additions & 0 deletions datapath/flow_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#include "flow.h"

size_t ovs_tun_key_attr_size(void);
size_t ovs_key_attr_size(void);

void ovs_match_init(struct sw_flow_match *match,
Expand All @@ -49,6 +50,8 @@ int ovs_nla_get_flow_metadata(const struct nlattr *, struct sw_flow_key *);
int ovs_nla_get_match(struct sw_flow_match *match,
const struct nlattr *,
const struct nlattr *);
int ovs_nla_put_egress_tunnel_key(struct sk_buff *,
const struct ovs_tunnel_info *);

int ovs_nla_copy_actions(const struct nlattr *attr,
const struct sw_flow_key *key,
Expand Down
Loading

0 comments on commit 8b7ea2d

Please sign in to comment.