Skip to content

Commit

Permalink
tunneling: Add support for tunnel ID.
Browse files Browse the repository at this point in the history
Add a tun_id field which contains the ID of the encapsulating tunnel
on which a packet was received (0 if not received on a tunnel).  Also
add an action which allows the tunnel ID to be set for outgoing
packets.  At this point there aren't any tunnel implementations so
these fields don't have any effect.

The matching is exposed to OpenFlow by overloading the high 32 bits
of the cookie as the tunnel ID.  ovs-ofctl is capable of turning
on this special behavior using a new "tun-cookie" command but this
command is intentially undocumented to avoid it being used without
a full understanding of the consequences.
  • Loading branch information
jessegross committed Apr 19, 2010
1 parent db0e2ad commit 659586e
Show file tree
Hide file tree
Showing 25 changed files with 275 additions and 86 deletions.
11 changes: 11 additions & 0 deletions datapath/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ make_writable(struct sk_buff *skb, unsigned min_headroom, gfp_t gfp)
return NULL;
}

static void set_tunnel(struct sk_buff *skb, struct odp_flow_key *key,
__be32 tun_id)
{
OVS_CB(skb)->tun_id = key->tun_id = tun_id;
}

static struct sk_buff *
vlan_pull_tag(struct sk_buff *skb)
Expand Down Expand Up @@ -477,6 +482,8 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
}
}

OVS_CB(skb)->tun_id = 0;

for (; n_actions > 0; a++, n_actions--) {
WARN_ON_ONCE(skb_shared(skb));
if (prev_port != -1) {
Expand All @@ -502,6 +509,10 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
}
break;

case ODPAT_SET_TUNNEL:
set_tunnel(skb, key, a->tunnel.tun_id);
break;

case ODPAT_SET_VLAN_VID:
case ODPAT_SET_VLAN_PCP:
skb = modify_vlan_tci(dp, skb, key, a, n_actions, gfp);
Expand Down
4 changes: 3 additions & 1 deletion datapath/datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ void dp_process_received_packet(struct sk_buff *skb, struct net_bridge_port *p)
WARN_ON_ONCE(skb_shared(skb));

compute_ip_summed(skb, false);
OVS_CB(skb)->tun_id = 0;

/* BHs are off so we don't have to use get_cpu()/put_cpu() here. */
stats = percpu_ptr(dp->stats_percpu, smp_processor_id());
Expand All @@ -558,7 +559,7 @@ void dp_process_received_packet(struct sk_buff *skb, struct net_bridge_port *p)
stats->n_hit++;
} else {
stats->n_missed++;
dp_output_control(dp, skb, _ODPL_MISS_NR, 0);
dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id);
}
}

Expand Down Expand Up @@ -1302,6 +1303,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *executep)
skb = alloc_skb(execute.length, GFP_KERNEL);
if (!skb)
goto error_free_actions;

if (execute.in_port < DP_MAX_PORTS) {
struct net_bridge_port *p = dp->ports[execute.in_port];
if (p)
Expand Down
3 changes: 2 additions & 1 deletion datapath/datapath.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ enum csum_type {
* kernel versions.
*/
struct ovs_skb_cb {
enum csum_type ip_summed;
enum csum_type ip_summed;
__be32 tun_id;
};
#define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)

Expand Down
3 changes: 2 additions & 1 deletion datapath/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,9 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
int nh_ofs;

memset(key, 0, sizeof *key);
key->dl_vlan = htons(ODP_VLAN_NONE);
key->tun_id = OVS_CB(skb)->tun_id;
key->in_port = in_port;
key->dl_vlan = htons(ODP_VLAN_NONE);

if (skb->len < sizeof *eth)
return 0;
Expand Down
37 changes: 34 additions & 3 deletions include/openflow/nicira-ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ enum nicira_type {
NXT_FLOW_END_CONFIG__OBSOLETE,
NXT_FLOW_END__OBSOLETE,
NXT_MGMT__OBSOLETE,

/* Use the high 32 bits of the cookie field as the tunnel ID in the flow
* match. */
NXT_TUN_ID_FROM_COOKIE,
};

struct nicira_header {
Expand All @@ -54,6 +58,14 @@ struct nicira_header {
};
OFP_ASSERT(sizeof(struct nicira_header) == 16);

struct nxt_tun_id_cookie {
struct ofp_header header;
uint32_t vendor; /* NX_VENDOR_ID. */
uint32_t subtype; /* NXT_TUN_ID_FROM_COOKIE */
uint8_t set; /* Nonzero to enable, zero to disable. */
uint8_t pad[7];
};
OFP_ASSERT(sizeof(struct nxt_tun_id_cookie) == 24);

enum nx_action_subtype {
NXAST_SNAT__OBSOLETE, /* No longer used. */
Expand All @@ -80,28 +92,47 @@ enum nx_action_subtype {
*
* NXAST_RESUBMIT may be used any number of times within a set of actions.
*/
NXAST_RESUBMIT
NXAST_RESUBMIT,

NXAST_SET_TUNNEL /* Set encapsulating tunnel ID. */
};

/* Action structure for NXAST_RESUBMIT. */
struct nx_action_resubmit {
uint16_t type; /* OFPAT_VENDOR. */
uint16_t len; /* Length is 8. */
uint16_t len; /* Length is 16. */
uint32_t vendor; /* NX_VENDOR_ID. */
uint16_t subtype; /* NXAST_RESUBMIT. */
uint16_t in_port; /* New in_port for checking flow table. */
uint8_t pad[4];
};
OFP_ASSERT(sizeof(struct nx_action_resubmit) == 16);

/* Action structure for NXAST_SET_TUNNEL. */
struct nx_action_set_tunnel {
uint16_t type; /* OFPAT_VENDOR. */
uint16_t len; /* Length is 16. */
uint32_t vendor; /* NX_VENDOR_ID. */
uint16_t subtype; /* NXAST_SET_TUNNEL. */
uint8_t pad[2];
uint32_t tun_id; /* Tunnel ID. */
};
OFP_ASSERT(sizeof(struct nx_action_set_tunnel) == 16);

/* Header for Nicira-defined actions. */
struct nx_action_header {
uint16_t type; /* OFPAT_VENDOR. */
uint16_t len; /* Length is 8. */
uint16_t len; /* Length is 16. */
uint32_t vendor; /* NX_VENDOR_ID. */
uint16_t subtype; /* NXAST_*. */
uint8_t pad[6];
};
OFP_ASSERT(sizeof(struct nx_action_header) == 16);

/* Wildcard for tunnel ID. */
#define NXFW_TUN_ID (1 << 25)

#define NXFW_ALL NXFW_TUN_ID
#define OVSFW_ALL (OFPFW_ALL | NXFW_ALL)

#endif /* openflow/nicira-ext.h */
14 changes: 12 additions & 2 deletions include/openvswitch/datapath-protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ struct odp_stats {
* @arg: Argument value whose meaning depends on @type.
*
* For @type == %_ODPL_MISS_NR, the header is followed by packet data. The
* @arg member is unused and set to 0.
* @arg member is the ID (in network byte order) of the tunnel that
* encapsulated this packet. It is 0 if the packet was not received on a tunnel.
*
* For @type == %_ODPL_ACTION_NR, the header is followed by packet data. The
* @arg member is copied from the &struct odp_action_controller that caused
Expand Down Expand Up @@ -191,6 +192,7 @@ struct odp_flow_stats {
};

struct odp_flow_key {
__be32 tun_id; /* Encapsulating tunnel ID. */
__be32 nw_src; /* IP source address. */
__be32 nw_dst; /* IP destination address. */
__u16 in_port; /* Input switch port. */
Expand Down Expand Up @@ -253,7 +255,8 @@ struct odp_flowvec {
#define ODPAT_SET_NW_TOS 10 /* IP ToS/DSCP field (6 bits). */
#define ODPAT_SET_TP_SRC 11 /* TCP/UDP source port. */
#define ODPAT_SET_TP_DST 12 /* TCP/UDP destination port. */
#define ODPAT_N_ACTIONS 13
#define ODPAT_SET_TUNNEL 13 /* Set the encapsulating tunnel ID. */
#define ODPAT_N_ACTIONS 14

struct odp_action_output {
__u16 type; /* ODPAT_OUTPUT. */
Expand All @@ -275,6 +278,12 @@ struct odp_action_controller {
__u32 arg; /* Copied to struct odp_msg 'arg' member. */
};

struct odp_action_tunnel {
__u16 type; /* ODPAT_SET_TUNNEL. */
__u16 reserved;
__be32 tun_id; /* Tunnel ID. */
};

/* Action structure for ODPAT_SET_VLAN_VID. */
struct odp_action_vlan_vid {
__u16 type; /* ODPAT_SET_VLAN_VID. */
Expand Down Expand Up @@ -326,6 +335,7 @@ union odp_action {
struct odp_action_output output;
struct odp_action_output_group output_group;
struct odp_action_controller controller;
struct odp_action_tunnel tunnel;
struct odp_action_vlan_vid vlan_vid;
struct odp_action_vlan_pcp vlan_pcp;
struct odp_action_dl_addr dl_addr;
Expand Down
20 changes: 11 additions & 9 deletions lib/classifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ static bool rules_match_2wild(const struct cls_rule *wild1,
/* Converts the flow in 'flow' into a cls_rule in 'rule', with the given
* 'wildcards' and 'priority'.*/
void
cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
uint32_t wildcards, unsigned int priority)
cls_rule_from_flow(const flow_t *flow, uint32_t wildcards,
unsigned int priority, struct cls_rule *rule)
{
assert(!flow->reserved[0] && !flow->reserved[1] && !flow->reserved[2]);
rule->flow = *flow;
Expand All @@ -66,13 +66,15 @@ cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
}

/* Converts the ofp_match in 'match' into a cls_rule in 'rule', with the given
* 'priority'. */
* 'priority'. If 'tun_id_from_cookie' is set then the upper 32 bits of
* 'cookie' are stored in the rule as the tunnel ID. */
void
cls_rule_from_match(struct cls_rule *rule, const struct ofp_match *match,
unsigned int priority)
cls_rule_from_match(const struct ofp_match *match, unsigned int priority,
bool tun_id_from_cookie, uint64_t cookie,
struct cls_rule *rule)
{
uint32_t wildcards;
flow_from_match(&rule->flow, &wildcards, match);
flow_from_match(match, tun_id_from_cookie, cookie, &rule->flow, &wildcards);
flow_wildcards_init(&rule->wc, wildcards);
rule->priority = rule->wc.wildcards ? priority : UINT16_MAX;
rule->table_idx = table_idx_from_wildcards(rule->wc.wildcards);
Expand Down Expand Up @@ -305,7 +307,7 @@ classifier_lookup_wild(const struct classifier *cls, const flow_t *flow)
struct cls_rule target;
int i;

cls_rule_from_flow(&target, flow, 0, 0);
cls_rule_from_flow(flow, 0, 0, &target);
for (i = 0; i < CLS_N_FIELDS; i++) {
struct cls_rule *rule = search_table(&cls->tables[i], i, &target);
if (rule && (!best || rule->priority > best->priority)) {
Expand All @@ -330,7 +332,7 @@ classifier_find_rule_exactly(const struct classifier *cls,
return search_exact_table(cls, flow_hash(target, 0), target);
}

assert(wildcards == (wildcards & OFPFW_ALL));
assert(wildcards == (wildcards & OVSFW_ALL));
table_idx = table_idx_from_wildcards(wildcards);
hash = hash_fields(target, table_idx);
HMAP_FOR_EACH_WITH_HASH (bucket, struct cls_bucket, hmap_node, hash,
Expand Down Expand Up @@ -367,7 +369,7 @@ classifier_rule_overlaps(const struct classifier *cls,
true : false;
}

cls_rule_from_flow(&target_rule, target, wildcards, priority);
cls_rule_from_flow(target, wildcards, priority, &target_rule);

for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) {
struct cls_bucket *bucket;
Expand Down
13 changes: 8 additions & 5 deletions lib/classifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@
#include "flow.h"
#include "hmap.h"
#include "list.h"
#include "openflow/nicira-ext.h"
#include "openflow/openflow.h"

/* Number of bytes of fields in a rule. */
#define CLS_N_BYTES 31
#define CLS_N_BYTES 37

/* Fields in a rule.
*
Expand All @@ -59,6 +60,7 @@
/* wildcard bit(s) member name name */ \
/* ----------------- ----------- -------- */ \
CLS_FIELD(OFPFW_IN_PORT, in_port, IN_PORT) \
CLS_FIELD(NXFW_TUN_ID, tun_id, TUN_ID) \
CLS_FIELD(OFPFW_DL_VLAN, dl_vlan, DL_VLAN) \
CLS_FIELD(OFPFW_DL_VLAN_PCP, dl_vlan_pcp, DL_VLAN_PCP) \
CLS_FIELD(OFPFW_DL_SRC, dl_src, DL_SRC) \
Expand Down Expand Up @@ -121,10 +123,11 @@ struct cls_rule {
unsigned int table_idx; /* Index into struct classifier 'tables'. */
};

void cls_rule_from_flow(struct cls_rule *, const flow_t *, uint32_t wildcards,
unsigned int priority);
void cls_rule_from_match(struct cls_rule *, const struct ofp_match *,
unsigned int priority);
void cls_rule_from_flow(const flow_t *, uint32_t wildcards,
unsigned int priority, struct cls_rule *);
void cls_rule_from_match(const struct ofp_match *, unsigned int priority,
bool tun_id_from_cookie, uint64_t cookie,
struct cls_rule *);
char *cls_rule_to_string(const struct cls_rule *);
void cls_rule_print(const struct cls_rule *);
void cls_rule_moved(struct classifier *,
Expand Down
2 changes: 1 addition & 1 deletion lib/dhcp-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ do_receive_msg(struct dhclient *cli, struct dhcp_msg *msg)
goto drained;
}

flow_extract(&b, 0, &flow);
flow_extract(&b, 0, 0, &flow);
if (flow.dl_type != htons(ETH_TYPE_IP)
|| flow.nw_proto != IP_TYPE_UDP
|| flow.tp_dst != htons(DHCP_CLIENT_PORT)
Expand Down
4 changes: 2 additions & 2 deletions lib/dpif-netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ dpif_netdev_execute(struct dpif *dpif, uint16_t in_port,
* if we don't. */
copy = *packet;
}
flow_extract(&copy, in_port, &flow);
flow_extract(&copy, 0, in_port, &flow);
error = dp_netdev_execute_actions(dp, &copy, &flow, actions, n_actions);
if (mutates) {
ofpbuf_uninit(&copy);
Expand Down Expand Up @@ -1026,7 +1026,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
struct dp_netdev_flow *flow;
flow_t key;

if (flow_extract(packet, port->port_no, &key) && dp->drop_frags) {
if (flow_extract(packet, 0, port->port_no, &key) && dp->drop_frags) {
dp->n_frags++;
return;
}
Expand Down
Loading

0 comments on commit 659586e

Please sign in to comment.