X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=0d17dbf42b181c596798e06a1705cd324f678b8d;hb=e3d8644df32fc4664970ec5e02cffe9fe742f681;hp=33b09c633176539809a792612412d914669103b9;hpb=d8558b4ae86f0f64afe520c4c1d99f55a94063d8;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 33b09c633..0d17dbf42 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -20,6 +20,7 @@ #include +#include "bfd.h" #include "bond.h" #include "bundle.h" #include "byte-order.h" @@ -46,6 +47,7 @@ #include "ofp-parse.h" #include "ofp-print.h" #include "ofproto-dpif-governor.h" +#include "ofproto-dpif-ipfix.h" #include "ofproto-dpif-sflow.h" #include "poll-loop.h" #include "simap.h" @@ -303,9 +305,6 @@ struct initial_vals { * This member should be removed when the VLAN splinters feature is no * longer needed. */ ovs_be16 vlan_tci; - - /* If received on a tunnel, the IP TOS value of the tunnel. */ - uint8_t tunnel_ip_tos; }; static void action_xlate_ctx_init(struct action_xlate_ctx *, @@ -325,7 +324,8 @@ static void xlate_table_action(struct action_xlate_ctx *, uint16_t in_port, static size_t put_userspace_action(const struct ofproto_dpif *, struct ofpbuf *odp_actions, const struct flow *, - const union user_action_cookie *); + const union user_action_cookie *, + const size_t); static void compose_slow_path(const struct ofproto_dpif *, const struct flow *, enum slow_path_reason, @@ -529,6 +529,7 @@ struct ofport_dpif { struct ofbundle *bundle; /* Bundle that contains this port, if any. */ struct list bundle_node; /* In struct ofbundle's "ports" list. */ struct cfm *cfm; /* Connectivity Fault Management, if any. */ + struct bfd *bfd; /* BFD, if any. */ tag_type tag; /* Tag associated with this port. */ bool may_enable; /* May be enabled in bonds. */ long long int carrier_seq; /* Carrier status changes. */ @@ -589,7 +590,6 @@ static uint16_t odp_port_to_ofp_port(const struct ofproto_dpif *, static struct ofport_dpif * ofport_dpif_cast(const struct ofport *ofport) { - ovs_assert(ofport->ofproto->ofproto_class == &ofproto_dpif_class); return ofport ? CONTAINER_OF(ofport, struct ofport_dpif, up) : NULL; } @@ -695,6 +695,7 @@ struct ofproto_dpif { /* Bridging. */ struct netflow *netflow; struct dpif_sflow *sflow; + struct dpif_ipfix *ipfix; struct hmap bundles; /* Contains "struct ofbundle"s. */ struct mac_learning *ml; struct ofmirror *mirrors[MAX_MIRRORS]; @@ -820,6 +821,9 @@ static int send_packet(const struct ofport_dpif *, struct ofpbuf *packet); static size_t compose_sflow_action(const struct ofproto_dpif *, struct ofpbuf *odp_actions, const struct flow *, uint32_t odp_port); +static void compose_ipfix_action(const struct ofproto_dpif *, + struct ofpbuf *odp_actions, + const struct flow *); static void add_mirror_actions(struct action_xlate_ctx *ctx, const struct flow *flow); /* Global variables. */ @@ -1349,6 +1353,7 @@ construct(struct ofproto *ofproto_) ofproto->netflow = NULL; ofproto->sflow = NULL; + ofproto->ipfix = NULL; ofproto->stp = NULL; hmap_init(&ofproto->bundles); ofproto->ml = mac_learning_create(MAC_ENTRY_DEFAULT_IDLE_TIME); @@ -1771,6 +1776,7 @@ port_construct(struct ofport *port_) ofproto->backer->need_revalidate = REV_RECONFIGURE; port->bundle = NULL; port->cfm = NULL; + port->bfd = NULL; port->tag = tag_create_random(); port->may_enable = true; port->stp_port = NULL; @@ -1782,7 +1788,11 @@ port_construct(struct ofport *port_) port->carrier_seq = netdev_get_carrier_resets(netdev); if (netdev_vport_is_patch(netdev)) { - /* XXX By bailing out here, we don't do required sFlow work. */ + /* By bailing out here, we don't submit the port to the sFlow module + * to be considered for counter polling export. This is correct + * because the patch port represents an interface that sFlow considers + * to be "internal" to the switch as a whole, and therefore not an + * candidate for counter polling. */ port->odp_port = OVSP_NONE; return 0; } @@ -1913,6 +1923,32 @@ set_sflow(struct ofproto *ofproto_, return 0; } +static int +set_ipfix( + struct ofproto *ofproto_, + const struct ofproto_ipfix_bridge_exporter_options *bridge_exporter_options, + const struct ofproto_ipfix_flow_exporter_options *flow_exporters_options, + size_t n_flow_exporters_options) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + struct dpif_ipfix *di = ofproto->ipfix; + + if (bridge_exporter_options || flow_exporters_options) { + if (!di) { + di = ofproto->ipfix = dpif_ipfix_create(); + } + dpif_ipfix_set_options( + di, bridge_exporter_options, flow_exporters_options, + n_flow_exporters_options); + } else { + if (di) { + dpif_ipfix_destroy(di); + ofproto->ipfix = NULL; + } + } + return 0; +} + static int set_cfm(struct ofport *ofport_, const struct cfm_settings *s) { @@ -1957,6 +1993,35 @@ get_cfm_status(const struct ofport *ofport_, return false; } } + +static int +set_bfd(struct ofport *ofport_, const struct smap *cfg) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport_->ofproto); + struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); + struct bfd *old; + + old = ofport->bfd; + ofport->bfd = bfd_configure(old, netdev_get_name(ofport->up.netdev), cfg); + if (ofport->bfd != old) { + ofproto->backer->need_revalidate = REV_RECONFIGURE; + } + + return 0; +} + +static int +get_bfd_status(struct ofport *ofport_, struct smap *smap) +{ + struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); + + if (ofport->bfd) { + bfd_get_status(ofport->bfd, smap); + return 0; + } else { + return ENOENT; + } +} /* Spanning Tree. */ @@ -3096,6 +3161,15 @@ port_run_fast(struct ofport_dpif *ofport) send_packet(ofport, &packet); ofpbuf_uninit(&packet); } + + if (ofport->bfd && bfd_should_send_packet(ofport->bfd)) { + struct ofpbuf packet; + + ofpbuf_init(&packet, 0); + bfd_put_packet(ofport->bfd, &packet, ofport->up.pp.hw_addr); + send_packet(ofport, &packet); + ofpbuf_uninit(&packet); + } } static void @@ -3126,6 +3200,11 @@ port_run(struct ofport_dpif *ofport) } } + if (ofport->bfd) { + bfd_run(ofport->bfd); + enable = enable && bfd_forwarding(ofport->bfd); + } + if (ofport->bundle) { enable = enable && lacp_slave_may_enable(ofport->bundle->lacp, ofport); if (carrier_changed) { @@ -3150,6 +3229,10 @@ port_wait(struct ofport_dpif *ofport) if (ofport->cfm) { cfm_wait(ofport->cfm); } + + if (ofport->bfd) { + bfd_wait(ofport->bfd); + } } static int @@ -3473,6 +3556,11 @@ process_special(struct ofproto_dpif *ofproto, const struct flow *flow, cfm_process_heartbeat(ofport->cfm, packet); } return SLOW_CFM; + } else if (ofport->bfd && bfd_should_process_flow(flow)) { + if (packet) { + bfd_process_packet(ofport->bfd, flow, packet); + } + return SLOW_BFD; } else if (ofport->bundle && ofport->bundle->lacp && flow->dl_type == htons(ETH_TYPE_LACP)) { if (packet) { @@ -3800,8 +3888,7 @@ drop_key_clear(struct dpif_backer *backer) * to the VLAN TCI with which the packet was really received, that is, the * actual VLAN TCI extracted by odp_flow_key_to_flow(). (This differs from * the value returned in flow->vlan_tci only for packets received on - * VLAN splinters.) Also, if received on an IP tunnel, sets - * 'initial_vals->tunnel_ip_tos' to the tunnel's IP TOS. + * VLAN splinters.) * * Similarly, this function also includes some logic to help with tunnels. It * may modify 'flow' as necessary to make the tunneling implementation @@ -3828,7 +3915,6 @@ ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet, if (initial_vals) { initial_vals->vlan_tci = flow->vlan_tci; - initial_vals->tunnel_ip_tos = flow->tunnel.ip_tos; } if (odp_in_port) { @@ -3843,9 +3929,6 @@ ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet, } port = ofport_dpif_cast(ofport); - /* We can't reproduce 'key' from 'flow'. */ - fitness = fitness == ODP_FIT_PERFECT ? ODP_FIT_TOO_MUCH : fitness; - /* XXX: Since the tunnel module is not scoped per backer, it's * theoretically possible that we'll receive an ofport belonging to an * entirely different datapath. In practice, this can't happen because @@ -4006,9 +4089,11 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls, hmap_destroy(&todo); } -static enum { SFLOW_UPCALL, MISS_UPCALL, BAD_UPCALL } +static enum { SFLOW_UPCALL, MISS_UPCALL, BAD_UPCALL, FLOW_SAMPLE_UPCALL, + IPFIX_UPCALL } classify_upcall(const struct dpif_upcall *upcall) { + size_t userdata_len; union user_action_cookie cookie; /* First look at the upcall type. */ @@ -4030,23 +4115,30 @@ classify_upcall(const struct dpif_upcall *upcall) VLOG_WARN_RL(&rl, "action upcall missing cookie"); return BAD_UPCALL; } - if (nl_attr_get_size(upcall->userdata) != sizeof(cookie)) { + userdata_len = nl_attr_get_size(upcall->userdata); + if (userdata_len < sizeof cookie.type + || userdata_len > sizeof cookie) { VLOG_WARN_RL(&rl, "action upcall cookie has unexpected size %zu", - nl_attr_get_size(upcall->userdata)); + userdata_len); return BAD_UPCALL; } - memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie)); - switch (cookie.type) { - case USER_ACTION_COOKIE_SFLOW: + memset(&cookie, 0, sizeof cookie); + memcpy(&cookie, nl_attr_get(upcall->userdata), userdata_len); + if (userdata_len == sizeof cookie.sflow + && cookie.type == USER_ACTION_COOKIE_SFLOW) { return SFLOW_UPCALL; - - case USER_ACTION_COOKIE_SLOW_PATH: + } else if (userdata_len == sizeof cookie.slow_path + && cookie.type == USER_ACTION_COOKIE_SLOW_PATH) { return MISS_UPCALL; - - case USER_ACTION_COOKIE_UNSPEC: - default: - VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64, - nl_attr_get_u64(upcall->userdata)); + } else if (userdata_len == sizeof cookie.flow_sample + && cookie.type == USER_ACTION_COOKIE_FLOW_SAMPLE) { + return FLOW_SAMPLE_UPCALL; + } else if (userdata_len == sizeof cookie.ipfix + && cookie.type == USER_ACTION_COOKIE_IPFIX) { + return IPFIX_UPCALL; + } else { + VLOG_WARN_RL(&rl, "invalid user cookie of type %"PRIu16 + " and size %zu", cookie.type, userdata_len); return BAD_UPCALL; } } @@ -4066,11 +4158,56 @@ handle_sflow_upcall(struct dpif_backer *backer, return; } - memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie)); + memset(&cookie, 0, sizeof cookie); + memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof cookie.sflow); dpif_sflow_received(ofproto->sflow, upcall->packet, &flow, odp_in_port, &cookie); } +static void +handle_flow_sample_upcall(struct dpif_backer *backer, + const struct dpif_upcall *upcall) +{ + struct ofproto_dpif *ofproto; + union user_action_cookie cookie; + struct flow flow; + + if (ofproto_receive(backer, upcall->packet, upcall->key, upcall->key_len, + &flow, NULL, &ofproto, NULL, NULL) + || !ofproto->ipfix) { + return; + } + + memset(&cookie, 0, sizeof cookie); + memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof cookie.flow_sample); + + /* The flow reflects exactly the contents of the packet. Sample + * the packet using it. */ + dpif_ipfix_flow_sample(ofproto->ipfix, upcall->packet, &flow, + cookie.flow_sample.collector_set_id, + cookie.flow_sample.probability, + cookie.flow_sample.obs_domain_id, + cookie.flow_sample.obs_point_id); +} + +static void +handle_ipfix_upcall(struct dpif_backer *backer, + const struct dpif_upcall *upcall) +{ + struct ofproto_dpif *ofproto; + struct flow flow; + + if (ofproto_receive(backer, upcall->packet, upcall->key, upcall->key_len, + &flow, NULL, &ofproto, NULL, NULL) + || !ofproto->ipfix) { + return; + } + + /* The flow reflects exactly the contents of the packet. Sample + * the packet using it. */ + dpif_ipfix_bridge_sample(ofproto->ipfix, upcall->packet, &flow); +} + static int handle_upcalls(struct dpif_backer *backer, unsigned int max_batch) { @@ -4108,6 +4245,16 @@ handle_upcalls(struct dpif_backer *backer, unsigned int max_batch) ofpbuf_uninit(buf); break; + case FLOW_SAMPLE_UPCALL: + handle_flow_sample_upcall(backer, upcall); + ofpbuf_uninit(buf); + break; + + case IPFIX_UPCALL: + handle_ipfix_upcall(backer, upcall); + ofpbuf_uninit(buf); + break; + case BAD_UPCALL: ofpbuf_uninit(buf); break; @@ -4426,7 +4573,7 @@ expire_subfacets(struct ofproto_dpif *ofproto, int dp_max_idle) &ofproto->subfacets) { long long int cutoff; - cutoff = (subfacet->slow & (SLOW_CFM | SLOW_LACP | SLOW_STP) + cutoff = (subfacet->slow & (SLOW_CFM | SLOW_BFD | SLOW_LACP | SLOW_STP) ? special_cutoff : normal_cutoff); if (subfacet->used < cutoff) { @@ -5651,7 +5798,6 @@ rule_dpif_execute(struct rule_dpif *rule, const struct flow *flow, rule_credit_stats(rule, &stats); initial_vals.vlan_tci = flow->vlan_tci; - initial_vals.tunnel_ip_tos = flow->tunnel.ip_tos; ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub); action_xlate_ctx_init(&ctx, ofproto, flow, &initial_vals, rule, stats.tcp_flags, packet); @@ -5747,6 +5893,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) ofp_port_to_odp_port(ofproto, flow.in_port)); compose_sflow_action(ofproto, &odp_actions, &flow, odp_port); + compose_ipfix_action(ofproto, &odp_actions, &flow); nl_msg_put_u32(&odp_actions, OVS_ACTION_ATTR_OUTPUT, odp_port); error = dpif_execute(ofproto->backer->dpif, @@ -5794,11 +5941,12 @@ compose_slow_path(const struct ofproto_dpif *ofproto, const struct flow *flow, cookie.slow_path.reason = slow; ofpbuf_use_stack(&buf, stub, stub_size); - if (slow & (SLOW_CFM | SLOW_LACP | SLOW_STP)) { + if (slow & (SLOW_CFM | SLOW_BFD | SLOW_LACP | SLOW_STP)) { uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX); - odp_put_userspace_action(pid, &cookie, sizeof cookie, &buf); + odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path, &buf); } else { - put_userspace_action(ofproto, &buf, flow, &cookie); + put_userspace_action(ofproto, &buf, flow, &cookie, + sizeof cookie.slow_path); } *actionsp = buf.data; *actions_lenp = buf.size; @@ -5808,14 +5956,43 @@ static size_t put_userspace_action(const struct ofproto_dpif *ofproto, struct ofpbuf *odp_actions, const struct flow *flow, - const union user_action_cookie *cookie) + const union user_action_cookie *cookie, + const size_t cookie_size) { uint32_t pid; pid = dpif_port_get_pid(ofproto->backer->dpif, ofp_port_to_odp_port(ofproto, flow->in_port)); - return odp_put_userspace_action(pid, cookie, sizeof *cookie, odp_actions); + return odp_put_userspace_action(pid, cookie, cookie_size, odp_actions); +} + +/* Compose SAMPLE action for sFlow or IPFIX. The given probability is + * the number of packets out of UINT32_MAX to sample. The given + * cookie is passed back in the callback for each sampled packet. + */ +static size_t +compose_sample_action(const struct ofproto_dpif *ofproto, + struct ofpbuf *odp_actions, + const struct flow *flow, + const uint32_t probability, + const union user_action_cookie *cookie, + const size_t cookie_size) +{ + size_t sample_offset, actions_offset; + int cookie_offset; + + sample_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SAMPLE); + + nl_msg_put_u32(odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, probability); + + actions_offset = nl_msg_start_nested(odp_actions, OVS_SAMPLE_ATTR_ACTIONS); + cookie_offset = put_userspace_action(ofproto, odp_actions, flow, cookie, + cookie_size); + + nl_msg_end_nested(odp_actions, actions_offset); + nl_msg_end_nested(odp_actions, sample_offset); + return cookie_offset; } static void @@ -5850,7 +6027,7 @@ compose_sflow_cookie(const struct ofproto_dpif *ofproto, } } -/* Compose SAMPLE action for sFlow. */ +/* Compose SAMPLE action for sFlow bridge sampling. */ static size_t compose_sflow_action(const struct ofproto_dpif *ofproto, struct ofpbuf *odp_actions, @@ -5859,32 +6036,60 @@ compose_sflow_action(const struct ofproto_dpif *ofproto, { uint32_t probability; union user_action_cookie cookie; - size_t sample_offset, actions_offset; - int cookie_offset; if (!ofproto->sflow || flow->in_port == OFPP_NONE) { return 0; } - sample_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SAMPLE); - - /* Number of packets out of UINT_MAX to sample. */ probability = dpif_sflow_get_probability(ofproto->sflow); - nl_msg_put_u32(odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, probability); - - actions_offset = nl_msg_start_nested(odp_actions, OVS_SAMPLE_ATTR_ACTIONS); compose_sflow_cookie(ofproto, htons(0), odp_port, odp_port == OVSP_NONE ? 0 : 1, &cookie); - cookie_offset = put_userspace_action(ofproto, odp_actions, flow, &cookie); - nl_msg_end_nested(odp_actions, actions_offset); - nl_msg_end_nested(odp_actions, sample_offset); - return cookie_offset; + return compose_sample_action(ofproto, odp_actions, flow, probability, + &cookie, sizeof cookie.sflow); +} + +static void +compose_flow_sample_cookie(uint16_t probability, uint32_t collector_set_id, + uint32_t obs_domain_id, uint32_t obs_point_id, + union user_action_cookie *cookie) +{ + 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; +} + +static void +compose_ipfix_cookie(union user_action_cookie *cookie) +{ + cookie->type = USER_ACTION_COOKIE_IPFIX; } -/* SAMPLE action must be first action in any given list of actions. - * At this point we do not have all information required to build it. So try to - * build sample action as complete as possible. */ +/* Compose SAMPLE action for IPFIX bridge sampling. */ +static void +compose_ipfix_action(const struct ofproto_dpif *ofproto, + struct ofpbuf *odp_actions, + const struct flow *flow) +{ + uint32_t probability; + union user_action_cookie cookie; + + if (!ofproto->ipfix || flow->in_port == OFPP_NONE) { + return; + } + + probability = dpif_ipfix_get_bridge_exporter_probability(ofproto->ipfix); + compose_ipfix_cookie(&cookie); + + compose_sample_action(ofproto, odp_actions, flow, probability, + &cookie, sizeof cookie.ipfix); +} + +/* SAMPLE action for sFlow must be first action in any given list of + * actions. At this point we do not have all information required to + * build it. So try to build sample action as complete as possible. */ static void add_sflow_action(struct action_xlate_ctx *ctx) { @@ -5895,6 +6100,14 @@ add_sflow_action(struct action_xlate_ctx *ctx) ctx->sflow_n_outputs = 0; } +/* SAMPLE action for IPFIX must be 1st or 2nd action in any given list + * of actions, eventually after the SAMPLE action for sFlow. */ +static void +add_ipfix_action(struct action_xlate_ctx *ctx) +{ + compose_ipfix_action(ctx->ofproto, ctx->odp_actions, &ctx->flow); +} + /* Fix SAMPLE action according to data collected while composing ODP actions. * We need to fix SAMPLE actions OVS_SAMPLE_ATTR_ACTIONS attribute, i.e. nested * USERSPACE action's user-cookie which is required for sflow. */ @@ -5909,7 +6122,7 @@ fix_sflow_action(struct action_xlate_ctx *ctx) } cookie = ofpbuf_at(ctx->odp_actions, ctx->user_cookie_offset, - sizeof(*cookie)); + sizeof cookie->sflow); ovs_assert(cookie->type == USER_ACTION_COOKIE_SFLOW); compose_sflow_cookie(ctx->ofproto, base->vlan_tci, @@ -6540,6 +6753,23 @@ xlate_fin_timeout(struct action_xlate_ctx *ctx, } } +static void +xlate_sample_action(struct action_xlate_ctx *ctx, + const struct ofpact_sample *os) +{ + union user_action_cookie cookie; + /* Scale the probability from 16-bit to 32-bit while representing + * the same percentage. */ + uint32_t probability = (os->probability << 16) | os->probability; + + commit_odp_actions(&ctx->flow, &ctx->base_flow, ctx->odp_actions); + + compose_flow_sample_cookie(os->probability, os->collector_set_id, + os->obs_domain_id, os->obs_point_id, &cookie); + compose_sample_action(ctx->ofproto, ctx->odp_actions, &ctx->flow, + probability, &cookie, sizeof cookie.flow_sample); +} + static bool may_receive(const struct ofport_dpif *port, struct action_xlate_ctx *ctx) { @@ -6565,7 +6795,7 @@ static bool tunnel_ecn_ok(struct action_xlate_ctx *ctx) { if (is_ip_any(&ctx->base_flow) - && (ctx->base_flow.tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE) { + && (ctx->flow.tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE) { if ((ctx->base_flow.nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) { VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE" " but is not ECN capable"); @@ -6820,6 +7050,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, } break; } + + case OFPACT_SAMPLE: + xlate_sample_action(ctx, ofpact_get_SAMPLE(a)); + break; } } @@ -6836,8 +7070,6 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx, struct rule_dpif *rule, uint8_t tcp_flags, const struct ofpbuf *packet) { - ovs_be64 initial_tun_id = flow->tunnel.tun_id; - /* Flow initialization rules: * - 'base_flow' must match the kernel's view of the packet at the * time that action processing starts. 'flow' represents any @@ -6849,23 +7081,21 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx, * to another device without any modifications this will cause us to * insert a new tag since the original one was stripped off by the * VLAN device. - * - Tunnel 'flow' is largely cleared when transitioning between - * the input and output stages since it does not make sense to output - * a packet with the exact headers that it was received with (i.e. - * the destination IP is us). The one exception is the tun_id, which - * is preserved to allow use in later resubmit lookups and loads into - * registers. + * - Tunnel metadata as received is retained in 'flow'. This allows + * tunnel metadata matching also in later tables. + * Since a kernel action for setting the tunnel metadata will only be + * generated with actual tunnel output, changing the tunnel metadata + * values in 'flow' (such as tun_id) will only have effect with a later + * tunnel output action. * - Tunnel 'base_flow' is completely cleared since that is what the * kernel does. If we wish to maintain the original values an action * needs to be generated. */ ctx->ofproto = ofproto; ctx->flow = *flow; - memset(&ctx->flow.tunnel, 0, sizeof ctx->flow.tunnel); ctx->base_flow = ctx->flow; + memset(&ctx->base_flow.tunnel, 0, sizeof ctx->base_flow.tunnel); ctx->base_flow.vlan_tci = initial_vals->vlan_tci; - ctx->base_flow.tunnel.ip_tos = initial_vals->tunnel_ip_tos; - ctx->flow.tunnel.tun_id = initial_tun_id; ctx->rule = rule; ctx->packet = packet; ctx->may_learn = packet != NULL; @@ -6948,12 +7178,14 @@ xlate_actions(struct action_xlate_ctx *ctx, } else { static struct vlog_rate_limit trace_rl = VLOG_RATE_LIMIT_INIT(1, 1); struct initial_vals initial_vals; + size_t sample_actions_len; uint32_t local_odp_port; initial_vals.vlan_tci = ctx->base_flow.vlan_tci; - initial_vals.tunnel_ip_tos = ctx->base_flow.tunnel.ip_tos; add_sflow_action(ctx); + add_ipfix_action(ctx); + sample_actions_len = ctx->odp_actions->size; if (tunnel_ecn_ok(ctx) && (!in_port || may_receive(in_port, ctx))) { do_xlate_actions(ofpacts, ofpacts_len, ctx); @@ -6961,8 +7193,7 @@ xlate_actions(struct action_xlate_ctx *ctx, /* We've let OFPP_NORMAL and the learning action look at the * packet, so drop it now if forwarding is disabled. */ if (in_port && !stp_forward_in_state(in_port->stp_state)) { - ofpbuf_clear(ctx->odp_actions); - add_sflow_action(ctx); + ctx->odp_actions->size = sample_actions_len; } } @@ -7714,7 +7945,6 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, dpif_flow_stats_extract(flow, packet, time_msec(), &stats); initial_vals.vlan_tci = flow->vlan_tci; - initial_vals.tunnel_ip_tos = 0; action_xlate_ctx_init(&ctx, ofproto, flow, &initial_vals, NULL, packet_get_tcp_flags(packet, flow), packet); ctx.resubmit_stats = &stats; @@ -8017,7 +8247,6 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], } initial_vals.vlan_tci = flow.vlan_tci; - initial_vals.tunnel_ip_tos = flow.tunnel.ip_tos; } /* Generate a packet, if requested. */ @@ -8052,7 +8281,6 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], flow_extract(packet, priority, mark, NULL, in_port, &flow); flow.tunnel.tun_id = tun_id; initial_vals.vlan_tci = flow.vlan_tci; - initial_vals.tunnel_ip_tos = flow.tunnel.ip_tos; } else { unixctl_command_reply_error(conn, "Bad command syntax"); goto exit; @@ -8131,6 +8359,9 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow, case SLOW_STP: ds_put_cstr(ds, "\n\t- Consists of STP packets."); break; + case SLOW_BFD: + ds_put_cstr(ds, "\n\t- Consists of BFD packets."); + break; case SLOW_IN_BAND: ds_put_cstr(ds, "\n\t- Needs in-band special case " "processing."); @@ -8852,8 +9083,11 @@ const struct ofproto_class ofproto_dpif_class = { set_netflow, get_netflow_ids, set_sflow, + set_ipfix, set_cfm, get_cfm_status, + set_bfd, + get_bfd_status, set_stp, get_stp_status, set_stp_port,