This allows the tun_key tp be bassed throughout user-space, attached to a flow. This is the essence of flow-based tunneling.
This does not add tun_key or wildcards, other than the existing match for the tun_id. It is envisaged that most if not all fields of the tun_key could be wildcarded. Cc: Kyle Mestery <kmest...@cisco.com> Signed-off-by: Simon Horman <ho...@verge.net.au> --- v5 * Consistently use spaces for indentation v4 * flow_format() and ofp_print_packet_in() format strings: - Make more consistent with eachother and format_odp_key_attr() - Update for flags field of tunnel * Remove debugging message * Add struct flow_tun_key to avoid needing to use ovs_key_ipv4_tunnel which is defined in a Linux kernel header. This code should be ofproto-provider agnostic. v3 * Initial posting --- lib/classifier.c | 8 ++++---- lib/dpif-linux.c | 2 +- lib/flow.c | 31 ++++++++++++++++++++++++++----- lib/flow.h | 21 ++++++++++++++++----- lib/meta-flow.c | 4 ++-- lib/nx-match.c | 2 +- lib/odp-util.c | 24 ++++++++++++++++-------- lib/ofp-print.c | 12 ++++++++++-- lib/ofp-util.c | 4 ++-- ofproto/ofproto-dpif.c | 11 ++++++----- tests/test-classifier.c | 7 ++++--- 11 files changed, 88 insertions(+), 38 deletions(-) diff --git a/lib/classifier.c b/lib/classifier.c index 327a8b2..c71e215 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -129,7 +129,7 @@ cls_rule_set_tun_id_masked(struct cls_rule *rule, ovs_be64 tun_id, ovs_be64 mask) { rule->wc.tun_id_mask = mask; - rule->flow.tun_id = tun_id & mask; + rule->flow.tun_key.tun_id = tun_id & mask; } void @@ -588,11 +588,11 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s) case 0: break; case CONSTANT_HTONLL(UINT64_MAX): - ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tun_id)); + ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tun_key.tun_id)); break; default: ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",", - ntohll(f->tun_id), ntohll(wc->tun_id_mask)); + ntohll(f->tun_key.tun_id), ntohll(wc->tun_id_mask)); break; } if (!(w & FWW_IN_PORT)) { @@ -1196,7 +1196,7 @@ flow_equal_except(const struct flow *a, const struct flow *b, } } - return (!((a->tun_id ^ b->tun_id) & wildcards->tun_id_mask) + return (!((a->tun_key.tun_id ^ b->tun_key.tun_id) & wildcards->tun_id_mask) && !((a->nw_src ^ b->nw_src) & wildcards->nw_src_mask) && !((a->nw_dst ^ b->nw_dst) & wildcards->nw_dst_mask) && (wc & FWW_IN_PORT || a->in_port == b->in_port) diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index 256c9d6..0e5cdd2 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -1292,7 +1292,7 @@ dpif_linux_vport_send(int dp_ifindex, uint32_t port_no, uint64_t action; ofpbuf_use_const(&packet, data, size); - flow_extract(&packet, 0, htonll(0), 0, &flow); + flow_extract(&packet, 0, NULL, 0, &flow); ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &flow); diff --git a/lib/flow.c b/lib/flow.c index 46e0e2d..88735e7 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -330,7 +330,8 @@ invalid: * present and has a correct length, and otherwise NULL. */ void -flow_extract(struct ofpbuf *packet, uint32_t skb_priority, ovs_be64 tun_id, +flow_extract(struct ofpbuf *packet, uint32_t skb_priority, + const struct flow_tun_key *tun_key, uint16_t ofp_in_port, struct flow *flow) { struct ofpbuf b = *packet; @@ -339,7 +340,9 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, ovs_be64 tun_id, COVERAGE_INC(flow_extract); memset(flow, 0, sizeof *flow); - flow->tun_id = tun_id; + if (tun_key) { + flow->tun_key = *tun_key;; + } flow->in_port = ofp_in_port; flow->skb_priority = skb_priority; @@ -449,7 +452,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards) for (i = 0; i < FLOW_N_REGS; i++) { flow->regs[i] &= wildcards->reg_masks[i]; } - flow->tun_id &= wildcards->tun_id_mask; + flow->tun_key.tun_id &= wildcards->tun_id_mask; flow->nw_src &= wildcards->nw_src_mask; flow->nw_dst &= wildcards->nw_dst_mask; if (wc & FWW_IN_PORT) { @@ -500,7 +503,7 @@ flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd) { BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11); - fmd->tun_id = flow->tun_id; + fmd->tun_key = flow->tun_key; fmd->tun_id_mask = htonll(UINT64_MAX); memcpy(fmd->regs, flow->regs, sizeof fmd->regs); @@ -520,11 +523,13 @@ flow_to_string(const struct flow *flow) void flow_format(struct ds *ds, const struct flow *flow) { + /* The tunnel key is also displayed as part of tunnel() below. + * It is here for backwards-compatibility */ ds_put_format(ds, "priority:%"PRIu32 ",tunnel:%#"PRIx64 ",in_port:%04"PRIx16, flow->skb_priority, - ntohll(flow->tun_id), + ntohll(flow->tun_key.tun_id), flow->in_port); ds_put_format(ds, ",tci("); @@ -571,6 +576,22 @@ flow_format(struct ds *ds, const struct flow *flow) ETH_ADDR_ARGS(flow->arp_sha), ETH_ADDR_ARGS(flow->arp_tha)); } + if (!eth_addr_is_zero(flow->arp_sha) || !eth_addr_is_zero(flow->arp_tha)) { + ds_put_format(ds, " arp_ha("ETH_ADDR_FMT"->"ETH_ADDR_FMT")", + ETH_ADDR_ARGS(flow->arp_sha), + ETH_ADDR_ARGS(flow->arp_tha)); + } + if (flow->tun_key.ipv4_dst != htonl(0)) { + ds_put_format(ds, " tunnel(tun_id:%"PRIx64",flags:%"PRIx32 + ",ip("IP_FMT"->"IP_FMT")," + ",tos:%"PRIx8",ttl:%"PRIu8")", + ntohll(flow->tun_key.tun_id), + flow->tun_key.tun_flags, + IP_ARGS(&flow->tun_key.ipv4_src), + IP_ARGS(&flow->tun_key.ipv4_dst), + flow->tun_key.ipv4_tos, flow->tun_key.ipv4_ttl); + } + } void diff --git a/lib/flow.h b/lib/flow.h index 1964115..18396f3 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -52,8 +52,18 @@ BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS); BUILD_ASSERT_DECL(FLOW_NW_FRAG_ANY == NX_IP_FRAG_ANY); BUILD_ASSERT_DECL(FLOW_NW_FRAG_LATER == NX_IP_FRAG_LATER); +struct flow_tun_key { + ovs_be64 tun_id; + uint32_t tun_flags; + ovs_be32 ipv4_src; + ovs_be32 ipv4_dst; + uint8_t ipv4_tos; + uint8_t ipv4_ttl; + uint8_t pad[2]; +}; + struct flow { - ovs_be64 tun_id; /* Encapsulating tunnel ID. */ + struct flow_tun_key tun_key;/* Encapsulating tunnel. */ struct in6_addr ipv6_src; /* IPv6 source address. */ struct in6_addr ipv6_dst; /* IPv6 destination address. */ struct in6_addr nd_target; /* IPv6 neighbor discovery (ND) target. */ @@ -82,7 +92,7 @@ struct flow { * indicate which metadata fields are relevant in a given context. Typically * they will be all 1 or all 0. */ struct flow_metadata { - ovs_be64 tun_id; /* Encapsulating tunnel ID. */ + struct flow_tun_key tun_key; /* Encapsulating tunnel. */ ovs_be64 tun_id_mask; /* 1-bit in each significant tun_id bit.*/ uint32_t regs[FLOW_N_REGS]; /* Registers. */ @@ -93,16 +103,17 @@ struct flow_metadata { /* Assert that there are FLOW_SIG_SIZE bytes of significant data in "struct * flow", followed by FLOW_PAD_SIZE bytes of padding. */ -#define FLOW_SIG_SIZE (110 + FLOW_N_REGS * 4) +#define FLOW_SIG_SIZE (126 + FLOW_N_REGS * 4) #define FLOW_PAD_SIZE 2 BUILD_ASSERT_DECL(offsetof(struct flow, nw_frag) == FLOW_SIG_SIZE - 1); BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->nw_frag) == 1); BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE); /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */ -BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 142 && FLOW_WC_SEQ == 11); +BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 158 && FLOW_WC_SEQ == 11); -void flow_extract(struct ofpbuf *, uint32_t priority, ovs_be64 tun_id, +void flow_extract(struct ofpbuf *, uint32_t priority, + const struct flow_tun_key *, uint16_t in_port, struct flow *); void flow_zero_wildcards(struct flow *, const struct flow_wildcards *); void flow_get_metadata(const struct flow *, struct flow_metadata *); diff --git a/lib/meta-flow.c b/lib/meta-flow.c index f18d1a0..8fa182a 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -961,7 +961,7 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, { switch (mf->id) { case MFF_TUN_ID: - value->be64 = flow->tun_id; + value->be64 = flow->tun_key.tun_id; break; case MFF_IN_PORT: @@ -1299,7 +1299,7 @@ mf_set_flow_value(const struct mf_field *mf, { switch (mf->id) { case MFF_TUN_ID: - flow->tun_id = value->be64; + flow->tun_key.tun_id = value->be64; break; case MFF_IN_PORT: diff --git a/lib/nx-match.c b/lib/nx-match.c index 5e3c3dc..c2e33a4 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -537,7 +537,7 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr, } /* Tunnel ID. */ - nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_id, cr->wc.tun_id_mask); + nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_key.tun_id, cr->wc.tun_id_mask); /* Registers. */ for (i = 0; i < FLOW_N_REGS; i++) { diff --git a/lib/odp-util.c b/lib/odp-util.c index a7b100b..ef495b9 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -1303,8 +1303,12 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow) nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->skb_priority); } - if (flow->tun_id != htonll(0)) { - nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tun_id); + if (flow->tun_key.ipv4_dst != htonl(0)) { + struct flow_tun_key *tun_key; + + tun_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_IPV4_TUNNEL, + sizeof *tun_key); + *tun_key = flow->tun_key; } if (flow->in_port != OFPP_NONE && flow->in_port != OFPP_CONTROLLER) { @@ -1795,9 +1799,13 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len, expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_PRIORITY; } - if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TUN_ID)) { - flow->tun_id = nl_attr_get_be64(attrs[OVS_KEY_ATTR_TUN_ID]); - expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_TUN_ID; + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4_TUNNEL)) { + const struct flow_tun_key *tun_key; + + tun_key = nl_attr_get(attrs[OVS_KEY_ATTR_IPV4_TUNNEL]); + flow->tun_key = *tun_key; + + expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IPV4_TUNNEL; } if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IN_PORT)) { @@ -1891,13 +1899,13 @@ static void commit_set_tun_id_action(const struct flow *flow, struct flow *base, struct ofpbuf *odp_actions) { - if (base->tun_id == flow->tun_id) { + if (base->tun_key.tun_id == flow->tun_key.tun_id) { return; } - base->tun_id = flow->tun_id; + base->tun_key.tun_id = flow->tun_key.tun_id; commit_set_action(odp_actions, OVS_KEY_ATTR_TUN_ID, - &base->tun_id, sizeof(base->tun_id)); + &base->tun_key.tun_id, sizeof(base->tun_key.tun_id)); } static void diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 9d4396c..3e75f8f 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -106,11 +106,19 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh, ds_put_format(string, " total_len=%"PRIu16" in_port=", pin.total_len); ofputil_format_port(pin.fmd.in_port, string); - if (pin.fmd.tun_id_mask) { - ds_put_format(string, " tun_id=0x%"PRIx64, ntohll(pin.fmd.tun_id)); + if (pin.fmd.tun_key.ipv4_dst != htonl(0)) { + ds_put_format(string, " tunnel(tun_id=0x%"PRIx64, + ntohll(pin.fmd.tun_key.tun_id)); if (pin.fmd.tun_id_mask != htonll(UINT64_MAX)) { ds_put_format(string, "/0x%"PRIx64, ntohll(pin.fmd.tun_id_mask)); } + ds_put_format(string, ",flags=%"PRIx32",ip="IP_FMT"->"IP_FMT"," + "tos=%"PRIx8",ttl=%"PRIu8")", + pin.fmd.tun_key.tun_flags, + IP_ARGS(&pin.fmd.tun_key.ipv4_src), + IP_ARGS(&pin.fmd.tun_key.ipv4_dst), + pin.fmd.tun_key.ipv4_tos, + pin.fmd.tun_key.ipv4_ttl); } for (i = 0; i < FLOW_N_REGS; i++) { diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 5c5fc99..bd9776f 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -2097,7 +2097,7 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin, pin->fmd.in_port = rule.flow.in_port; - pin->fmd.tun_id = rule.flow.tun_id; + pin->fmd.tun_key.tun_id = rule.flow.tun_key.tun_id; pin->fmd.tun_id_mask = rule.wc.tun_id_mask; memcpy(pin->fmd.regs, rule.flow.regs, sizeof pin->fmd.regs); @@ -2150,7 +2150,7 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin, + 2 + send_len); cls_rule_init_catchall(&rule, 0); - cls_rule_set_tun_id_masked(&rule, pin->fmd.tun_id, + cls_rule_set_tun_id_masked(&rule, pin->fmd.tun_key.tun_id, pin->fmd.tun_id_mask); for (i = 0; i < FLOW_N_REGS; i++) { diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index e3e8666..17aed6e 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -3081,7 +3081,7 @@ handle_miss_upcalls(struct ofproto_dpif *ofproto, struct dpif_upcall *upcalls, continue; } flow_extract(upcall->packet, miss->flow.skb_priority, - miss->flow.tun_id, miss->flow.in_port, &miss->flow); + &miss->flow.tun_key, miss->flow.in_port, &miss->flow); /* Add other packets to a to-do list. */ hash = flow_hash(&miss->flow, 0); @@ -5465,7 +5465,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, case OFPUTIL_NXAST_SET_TUNNEL: nast = (const struct nx_action_set_tunnel *) ia; tun_id = htonll(ntohl(nast->tun_id)); - ctx->flow.tun_id = tun_id; + ctx->flow.tun_key.tun_id = tun_id; break; case OFPUTIL_NXAST_SET_QUEUE: @@ -5493,7 +5493,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, case OFPUTIL_NXAST_SET_TUNNEL64: tun_id = ((const struct nx_action_set_tunnel64 *) ia)->tun_id; - ctx->flow.tun_id = tun_id; + ctx->flow.tun_key.tun_id = tun_id; break; case OFPUTIL_NXAST_MULTIPATH: @@ -5577,7 +5577,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx, ctx->ofproto = ofproto; ctx->flow = *flow; ctx->base_flow = ctx->flow; - ctx->base_flow.tun_id = 0; + ctx->base_flow.tun_key.ipv4_src = 0; ctx->base_flow.vlan_tci = initial_tci; ctx->rule = rule; ctx->packet = packet; @@ -6746,6 +6746,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], const char *packet_s = argv[5]; uint16_t in_port = ofp_port_to_odp_port(atoi(in_port_s)); ovs_be64 tun_id = htonll(strtoull(tun_id_s, NULL, 0)); + struct ovs_key_ipv4_tunnel tun_key = { .tun_id = tun_id }; uint32_t priority = atoi(priority_s); const char *msg; @@ -6760,7 +6761,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], ds_put_cstr(&result, s); free(s); - flow_extract(packet, priority, tun_id, in_port, &flow); + flow_extract(packet, priority, &tun_key, in_port, &flow); initial_tci = flow.vlan_tci; } else { unixctl_command_reply_error(conn, "Bad command syntax"); diff --git a/tests/test-classifier.c b/tests/test-classifier.c index 7403159..faca74c 100644 --- a/tests/test-classifier.c +++ b/tests/test-classifier.c @@ -44,7 +44,7 @@ /* struct flow all-caps */ \ /* FWW_* bit(s) member name name */ \ /* -------------------------- ----------- -------- */ \ - CLS_FIELD(0, tun_id, TUN_ID) \ + CLS_FIELD(0, tun_key.tun_id, TUN_ID) \ CLS_FIELD(0, nw_src, NW_SRC) \ CLS_FIELD(0, nw_dst, NW_DST) \ CLS_FIELD(FWW_IN_PORT, in_port, IN_PORT) \ @@ -212,7 +212,8 @@ match(const struct cls_rule *wild, const struct flow *fixed) eq = !((fixed->vlan_tci ^ wild->flow.vlan_tci) & wild->wc.vlan_tci_mask); } else if (f_idx == CLS_F_IDX_TUN_ID) { - eq = !((fixed->tun_id ^ wild->flow.tun_id) & wild->wc.tun_id_mask); + eq = !((fixed->tun_key.tun_id ^ wild->flow.tun_key.tun_id) & + wild->wc.tun_id_mask); } else if (f_idx == CLS_F_IDX_NW_DSCP) { eq = !((fixed->nw_tos ^ wild->flow.nw_tos) & IP_DSCP_MASK); } else { @@ -368,7 +369,7 @@ compare_classifiers(struct classifier *cls, struct tcls *tcls) x = rand () % N_FLOW_VALUES; flow.nw_src = nw_src_values[get_value(&x, N_NW_SRC_VALUES)]; flow.nw_dst = nw_dst_values[get_value(&x, N_NW_DST_VALUES)]; - flow.tun_id = tun_id_values[get_value(&x, N_TUN_ID_VALUES)]; + flow.tun_key.tun_id = tun_id_values[get_value(&x, N_TUN_ID_VALUES)]; flow.in_port = in_port_values[get_value(&x, N_IN_PORT_VALUES)]; flow.vlan_tci = vlan_tci_values[get_value(&x, N_VLAN_TCI_VALUES)]; flow.dl_type = dl_type_values[get_value(&x, N_DL_TYPE_VALUES)]; -- 1.7.10.2.484.gcd07cc5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev