On 12/14/23 16:29, Ales Musil wrote:
> The fields that are not directly supported by OvS were encoded
> via additional controller action that changed the required value.
> This was most notably needed for ICMP need frag messages.
>
> Encode the field value loads as note action instead. This allows
> us to find the note and act accordingly in the first controller
> action without the need to send it to pinctrl again, parse and
> change the packet. This way we can also encode any future fields
> that might be needed as this method should be flexible enough.
>
> This change is completely transparent to the user and shouldn't
> cause any disruptions.
>
> Signed-off-by: Ales Musil <[email protected]>
> ---
> v2: Fix the wrong checksum for the ICMP packet.
> ---
Hi Ales,
Thanks for the patch, I have a few comments though.
> controller/physical.c | 14 ++--
> controller/pinctrl.c | 183 +++++++++++++++++++++---------------------
> include/ovn/actions.h | 16 ++++
> lib/actions.c | 44 +++++++---
> tests/ovn.at | 10 +--
> 5 files changed, 154 insertions(+), 113 deletions(-)
>
> diff --git a/controller/physical.c b/controller/physical.c
> index ce3b88d16..161b4f073 100644
> --- a/controller/physical.c
> +++ b/controller/physical.c
> @@ -1222,7 +1222,7 @@ reply_imcp_error_if_pkt_too_big(struct
> ovn_desired_flow_table *flow_table,
> ip_ttl->ttl = 255;
>
> uint16_t frag_mtu = mtu - ETHERNET_OVERHEAD;
> - size_t frag_mtu_oc_offset;
> + size_t note_offset;
> if (is_ipv6) {
> /* icmp6.type = 2 (Packet Too Big) */
> /* icmp6.code = 0 */
> @@ -1234,9 +1234,8 @@ reply_imcp_error_if_pkt_too_big(struct
> ovn_desired_flow_table *flow_table,
> &inner_ofpacts, mf_from_id(MFF_ICMPV6_CODE), &icmp_code, NULL);
>
> /* icmp6.frag_mtu */
> - frag_mtu_oc_offset = encode_start_controller_op(
> - ACTION_OPCODE_PUT_ICMP6_FRAG_MTU, true, NX_CTLR_NO_METER,
> - &inner_ofpacts);
> + note_offset = encode_start_ovn_field_note(OVN_ICMP6_FRAG_MTU,
> + &inner_ofpacts);
> ovs_be32 frag_mtu_ovs = htonl(frag_mtu);
> ofpbuf_put(&inner_ofpacts, &frag_mtu_ovs, sizeof(frag_mtu_ovs));
> } else {
> @@ -1250,13 +1249,12 @@ reply_imcp_error_if_pkt_too_big(struct
> ovn_desired_flow_table *flow_table,
> &inner_ofpacts, mf_from_id(MFF_ICMPV4_CODE), &icmp_code, NULL);
>
> /* icmp4.frag_mtu = */
> - frag_mtu_oc_offset = encode_start_controller_op(
> - ACTION_OPCODE_PUT_ICMP4_FRAG_MTU, true, NX_CTLR_NO_METER,
> - &inner_ofpacts);
> + note_offset = encode_start_ovn_field_note(OVN_ICMP4_FRAG_MTU,
> + &inner_ofpacts);
> ovs_be16 frag_mtu_ovs = htons(frag_mtu);
> ofpbuf_put(&inner_ofpacts, &frag_mtu_ovs, sizeof(frag_mtu_ovs));
> }
> - encode_finish_controller_op(frag_mtu_oc_offset, &inner_ofpacts);
> + encode_finish_ovn_field_note(note_offset, &inner_ofpacts);
>
> /* Finally, submit the ICMP error back to the ingress pipeline */
> put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &inner_ofpacts);
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index 5a35d56f6..7925f4c92 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -259,12 +259,7 @@ static void pinctrl_handle_nd_ns(struct rconn *swconn,
> struct dp_packet *pkt_in,
> const struct match *md,
> struct ofpbuf *userdata);
> -static void pinctrl_handle_put_icmp_frag_mtu(struct rconn *swconn,
> - const struct flow *in_flow,
> - struct dp_packet *pkt_in,
> - struct ofputil_packet_in *pin,
> - struct ofpbuf *userdata,
> - struct ofpbuf *continuation);
> +
> static void
> pinctrl_handle_event(struct ofpbuf *userdata)
> OVS_REQUIRES(pinctrl_mutex);
> @@ -606,6 +601,23 @@ set_switch_config(struct rconn *swconn,
> queue_msg(swconn, request);
> }
>
> +static void
> +enqueue_packet(struct rconn *swconn, enum ofp_version version,
> + const struct dp_packet *packet, const struct ofpbuf *ofpacts)
> +{
> + struct ofputil_packet_out po = {
Nit: (struct ofputil_packet_out) {
> + .packet = dp_packet_data(packet),
> + .packet_len = dp_packet_size(packet),
> + .buffer_id = UINT32_MAX,
> + .ofpacts = ofpacts->data,
> + .ofpacts_len = ofpacts->size,
Nit: 4 spaces too much for indentation.
> + };
> +
> + match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
> + enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
> + queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
> +}
> +
> static void
> set_actions_and_enqueue_msg(struct rconn *swconn,
> const struct dp_packet *packet,
> @@ -631,19 +643,59 @@ set_actions_and_enqueue_msg(struct rconn *swconn,
> return;
> }
>
> - struct ofputil_packet_out po = {
> - .packet = dp_packet_data(packet),
> - .packet_len = dp_packet_size(packet),
> - .buffer_id = UINT32_MAX,
> - .ofpacts = ofpacts.data,
> - .ofpacts_len = ofpacts.size,
> - };
> - match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
> - enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
> - queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
> + enqueue_packet(swconn, version, packet, &ofpacts);
> ofpbuf_uninit(&ofpacts);
> }
>
> +static bool
> +ofpacts_decode_and_reload_metadata(enum ofp_version version,
> + const struct match *md,
> + struct ofpbuf *userdata,
> + struct ofpbuf *ofpacts)
> +{
> + /* Copy metadata from 'md' into the packet-out via "set_field"
> + * actions, then add actions from 'userdata'.
> + */
> + reload_metadata(ofpacts, md);
> + enum ofperr error = ofpacts_pull_openflow_actions(userdata,
> userdata->size,
> + version, NULL, NULL,
> + ofpacts);
> + if (error) {
> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> + VLOG_WARN_RL(&rl, "failed to parse actions from userdata (%s)",
> + ofperr_to_string(error));
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static void *
> +ofpacts_get_ovn_field(const struct ofpbuf *ofpacts,
> + enum ovn_field_id id)
> +{
> + const struct ovn_field *field = ovn_field_from_id(id);
> +
> + struct ofpact *ofpact;
> + OFPACT_FOR_EACH (ofpact, ofpacts->data, ofpacts->size) {
> + if (ofpact->type != OFPACT_NOTE) {
> + continue;
> + }
> +
> + struct ofpact_note *note = ofpact_get_NOTE(ofpact);
> + struct ovn_field_note_header *hdr = (void *) note->data;
> + /* The data can contain padding bytes from NXAST_NOTE encode/decode.
> */
> + size_t data_len = note->length - sizeof *hdr;
> +
> + if (!strncmp(hdr->magic, OVN_FIELD_NOTE_MAGIC, sizeof hdr->magic) &&
> + field->id == ntohs(hdr->type) && data_len >= field->n_bytes) {
> + return hdr->data;
> + }
> + }
> +
> + return NULL;
> +}
> +
> /* Forwards a packet to 'out_port_key' even if that's on a remote
> * hypervisor, i.e., the packet is re-injected in table OFTABLE_OUTPUT_INIT.
> */
> @@ -1546,6 +1598,8 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct
> flow *ip_flow,
> const struct match *md, struct ofpbuf *userdata,
> bool set_icmp_code, bool loopback)
> {
> + enum ofp_version version = rconn_get_version(swconn);
> +
> /* This action only works for IP packets, and the switch should only send
> * us IP packets this way, but check here just to be sure. */
> if (ip_flow->dl_type != htons(ETH_TYPE_IP) &&
> @@ -1557,6 +1611,14 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct
> flow *ip_flow,
> return;
> }
>
> + uint64_t ofpacts_stub[4096 / 8];
> + struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
> +
> + if (!ofpacts_decode_and_reload_metadata(version, md, userdata,
> &ofpacts)) {
> + ofpbuf_uninit(&ofpacts);
> + return;
> + }
> +
> uint64_t packet_stub[128 / 8];
> struct dp_packet packet;
>
> @@ -1572,6 +1634,7 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct
> flow *ip_flow,
> VLOG_WARN_RL(&rl,
> "ICMP action on IP packet with invalid length (%u)",
> in_ip_len);
> + ofpbuf_uninit(&ofpacts);
> return;
> }
>
> @@ -1615,6 +1678,12 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct
> flow *ip_flow,
> void *data = ih + 1;
> memcpy(data, in_ip, in_ip_len);
>
> + ovs_be16 *mtu = ofpacts_get_ovn_field(&ofpacts, OVN_ICMP4_FRAG_MTU);
Doesn't this temporarily disrupt upgrades? Shouldn't we try to detect
if this userdata is indeed using the new note action?
> + if (mtu) {
> + ih->icmp_fields.frag.mtu = *mtu;
> + ih->icmp_code = 4;
> + }
> +
> ih->icmp_csum = 0;
> ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len);
> } else {
> @@ -1662,6 +1731,12 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct
> flow *ip_flow,
> }
> ih->icmp6_base.icmp6_cksum = 0;
>
> + ovs_be32 *mtu = ofpacts_get_ovn_field(&ofpacts, OVN_ICMP6_FRAG_MTU);
> + if (mtu) {
> + put_16aligned_be32(ih->icmp6_data.be32, *mtu);
> + ih->icmp6_base.icmp6_type = ICMP6_PACKET_TOO_BIG;
> + }
> +
> void *data = ih + 1;
> memcpy(data, in_ip, in_ip_len);
> uint32_t icmpv6_csum =
> @@ -1676,8 +1751,9 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct
> flow *ip_flow,
> ip_flow->vlans[0].tci);
> }
>
> - set_actions_and_enqueue_msg(swconn, &packet, md, userdata);
> + enqueue_packet(swconn, version, &packet, &ofpacts);
> dp_packet_uninit(&packet);
> + ofpbuf_uninit(&ofpacts);
> }
>
> /* Called with in the pinctrl_handler thread context. */
> @@ -3285,12 +3361,6 @@ process_packet_in(struct rconn *swconn, const struct
> ofp_header *msg)
> &userdata);
> break;
>
> - case ACTION_OPCODE_PUT_ICMP4_FRAG_MTU:
> - case ACTION_OPCODE_PUT_ICMP6_FRAG_MTU:
> - pinctrl_handle_put_icmp_frag_mtu(swconn, &headers, &packet, &pin,
> - &userdata, &continuation);
> - break;
> -
> case ACTION_OPCODE_EVENT:
> ovs_mutex_lock(&pinctrl_mutex);
> pinctrl_handle_event(&userdata);
> @@ -6312,73 +6382,6 @@ exit:
> dp_packet_uninit(pkt_out_ptr);
> }
>
> -/* Called with in the pinctrl_handler thread context. */
> -static void
> -pinctrl_handle_put_icmp_frag_mtu(struct rconn *swconn,
> - const struct flow *in_flow,
> - struct dp_packet *pkt_in,
> - struct ofputil_packet_in *pin,
> - struct ofpbuf *userdata,
> - struct ofpbuf *continuation)
> -{
> - enum ofp_version version = rconn_get_version(swconn);
> - enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
> - struct dp_packet *pkt_out = NULL;
> -
> - /* This action only works for ICMPv4/v6 packets. */
> - if (!is_icmpv4(in_flow, NULL) && !is_icmpv6(in_flow, NULL)) {
> - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> - VLOG_WARN_RL(&rl,
> - "put_icmp(4/6)_frag_mtu action on non-ICMPv4/v6
> packet");
> - goto exit;
> - }
> -
> - pkt_out = dp_packet_clone(pkt_in);
> - pkt_out->l2_5_ofs = pkt_in->l2_5_ofs;
> - pkt_out->l2_pad_size = pkt_in->l2_pad_size;
> - pkt_out->l3_ofs = pkt_in->l3_ofs;
> - pkt_out->l4_ofs = pkt_in->l4_ofs;
> -
> - if (is_icmpv4(in_flow, NULL)) {
> - ovs_be16 *mtu = ofpbuf_try_pull(userdata, sizeof *mtu);
> - if (!mtu) {
> - goto exit;
> - }
> -
> - struct ip_header *nh = dp_packet_l3(pkt_out);
> - struct icmp_header *ih = dp_packet_l4(pkt_out);
> - ovs_be16 old_frag_mtu = ih->icmp_fields.frag.mtu;
> - ih->icmp_fields.frag.mtu = *mtu;
> - ih->icmp_csum = recalc_csum16(ih->icmp_csum, old_frag_mtu, *mtu);
> - nh->ip_csum = 0;
> - nh->ip_csum = csum(nh, sizeof *nh);
> - } else {
> - ovs_be32 *mtu = ofpbuf_try_pull(userdata, sizeof *mtu);
> - if (!mtu) {
> - goto exit;
> - }
> -
> - struct icmp6_data_header *ih = dp_packet_l4(pkt_out);
> - put_16aligned_be32(ih->icmp6_data.be32, *mtu);
> -
> - /* compute checksum and set correct mtu */
> - ih->icmp6_base.icmp6_cksum = 0;
> - uint32_t csum = packet_csum_pseudoheader6(dp_packet_l3(pkt_out));
> - uint32_t size = (uint8_t *)dp_packet_tail(pkt_out) - (uint8_t *)ih;
> - ih->icmp6_base.icmp6_cksum = csum_finish(
> - csum_continue(csum, ih, size));
> - }
> -
> - pin->packet = dp_packet_data(pkt_out);
> - pin->packet_len = dp_packet_size(pkt_out);
> -
> -exit:
> - queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto));
> - if (pkt_out) {
> - dp_packet_delete(pkt_out);
> - }
> -}
> -
> static void
> wait_controller_event(struct ovsdb_idl_txn *ovnsb_idl_txn)
> {
> diff --git a/include/ovn/actions.h b/include/ovn/actions.h
> index 49cfe0624..70c11ff7a 100644
> --- a/include/ovn/actions.h
> +++ b/include/ovn/actions.h
> @@ -514,6 +514,18 @@ struct ovnact_commit_lb_aff {
> uint16_t timeout;
> };
>
> +#define OVN_FIELD_NOTE_MAGIC "ovn"
> +
> +struct ovn_field_note_header {
> + char magic[4];
> + uint8_t pad[2];
> + ovs_be16 type; /* The type of ovn field note, based
> + * on 'enum ovn_field_id'. */
> + uint8_t data[];
> +};
> +
To make sure we always have the right padding this should be:
struct ovn_field_note_header {
OFPACT_PADDED_MEMBERS(
char magic[4];
ovs_be16 type; /* The type of ovn field note, based
* on 'enum ovn_field_id'. */
);
uint8_t data[];
};
> +BUILD_ASSERT_DECL(sizeof(struct ovn_field_note_header) == 8);
> +
> /* Internal use by the helpers below. */
> void ovnact_init(struct ovnact *, enum ovnact_type, size_t len);
> void *ovnact_put(struct ofpbuf *, enum ovnact_type, size_t len);
> @@ -901,4 +913,8 @@ void encode_finish_controller_op(size_t ofs, struct
> ofpbuf *ofpacts);
> void encode_controller_op(enum action_opcode opcode, uint32_t meter_id,
> struct ofpbuf *ofpacts);
>
> +size_t encode_start_ovn_field_note(enum ovn_field_id id,
Nit: 'id' is not really needed in the prototype and without it this fits
on a single line.
> + struct ofpbuf *ofpacts);
> +void encode_finish_ovn_field_note(size_t offset, struct ofpbuf *ofpacts);
> +
> #endif /* ovn/actions.h */
> diff --git a/lib/actions.c b/lib/actions.c
> index a73fe1a1e..f1facc6ef 100644
> --- a/lib/actions.c
> +++ b/lib/actions.c
> @@ -117,6 +117,34 @@ encode_controller_op(enum action_opcode opcode, uint32_t
> meter_id,
> encode_finish_controller_op(ofs, ofpacts);
> }
>
> +size_t
> +encode_start_ovn_field_note(enum ovn_field_id id, struct ofpbuf *ofpacts)
> +{
Nit: With "struct ovn_field_note_header *hdr;" here we'd avoid the not
so pretty newline below where we set 'hdr'.
> + size_t offset = ofpacts->size;
> +
> + ofpact_put_NOTE(ofpacts);
> + struct ovn_field_note_header *hdr = ofpbuf_put_uninit(ofpacts,
> + sizeof *hdr);
If we remove the explicit 'pad' and rely on OFPACT_PADDED_MEMBERS in the
structure definition then we should use ofpbuf_put_zeros() here. At
least to make the unit tests happy.
> + *hdr = (struct ovn_field_note_header) {
> + .magic = OVN_FIELD_NOTE_MAGIC,
> + .pad = {0},
> + .type = htons(id),
Nit: 4 spaces too much for indentation.
> + };
> +
> + return offset;
> +}
> +
> +void
> +encode_finish_ovn_field_note(size_t offset, struct ofpbuf *ofpacts)
> +{
> + struct ofpact_note *note = ofpbuf_at_assert(ofpacts, offset, sizeof
> *note);
> +
> + ofpacts->header = note;
> + note->length = ofpacts->size - (offset + sizeof *note);
> +
> + ofpact_finish_NOTE(ofpacts, ¬e);
> +}
> +
> static void
> init_stack(struct ofpact_stack *stack, enum mf_field_id field)
> {
> @@ -3757,31 +3785,27 @@ format_OVNFIELD_LOAD(const struct ovnact_load *load ,
> struct ds *s)
>
> static void
> encode_OVNFIELD_LOAD(const struct ovnact_load *load,
> - const struct ovnact_encode_params *ep,
> - struct ofpbuf *ofpacts)
> + const struct ovnact_encode_params *ep OVS_UNUSED,
> + struct ofpbuf *ofpacts)
> {
> const struct ovn_field *f = ovn_field_from_name(load->dst.symbol->name);
> + size_t offset = encode_start_ovn_field_note(f->id, ofpacts);
> +
> switch (f->id) {
> case OVN_ICMP4_FRAG_MTU: {
> - size_t oc_offset = encode_start_controller_op(
> - ACTION_OPCODE_PUT_ICMP4_FRAG_MTU, true,
> - ep->ctrl_meter_id, ofpacts);
> ofpbuf_put(ofpacts, &load->imm.value.be16_int, sizeof(ovs_be16));
> - encode_finish_controller_op(oc_offset, ofpacts);
> break;
> }
> case OVN_ICMP6_FRAG_MTU: {
> - size_t oc_offset = encode_start_controller_op(
> - ACTION_OPCODE_PUT_ICMP6_FRAG_MTU, true,
> - ep->ctrl_meter_id, ofpacts);
> ofpbuf_put(ofpacts, &load->imm.value.be32_int, sizeof(ovs_be32));
> - encode_finish_controller_op(oc_offset, ofpacts);
> break;
> }
> case OVN_FIELD_N_IDS:
> default:
> OVS_NOT_REACHED();
> }
> +
> + encode_finish_ovn_field_note(offset, ofpacts);
> }
>
> static void
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 918f97a9e..968997d1d 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -1867,7 +1867,7 @@ icmp4 { };
>
> # icmp4 with icmp4.frag_mtu
> icmp4 { eth.dst = ff:ff:ff:ff:ff:ff; icmp4.frag_mtu = 1500; output; };
> output;
> - encodes as
> controller(userdata=00.00.00.0a.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.28.00.00.23.20.00.25.00.00.00.00.00.00.00.03.00.0e.00.00.00.0d.00.00.00.00.05.dc.00.00.00.04.00.04.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00),resubmit(,64)
> + encodes as
> controller(userdata=00.00.00.0a.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.18.00.00.23.20.00.08.6f.76.6e.00.00.00.00.00.05.dc.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00),resubmit(,64)
> has prereqs ip4
>
> # icmp4_error
> @@ -1882,11 +1882,11 @@ icmp4_error { };
>
> # icmp4_error with icmp4.frag_mtu
> icmp4_error { eth.dst = ff:ff:ff:ff:ff:ff; icmp4.frag_mtu = 1500; output; };
> output;
> - encodes as
> controller(userdata=00.00.00.0e.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.28.00.00.23.20.00.25.00.00.00.00.00.00.00.03.00.0e.00.00.00.0d.00.00.00.00.05.dc.00.00.00.04.00.04.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00),resubmit(,64)
> + encodes as
> controller(userdata=00.00.00.0e.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.18.00.00.23.20.00.08.6f.76.6e.00.00.00.00.00.05.dc.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00),resubmit(,64)
> has prereqs ip4
>
> icmp4.frag_mtu = 1500;
> - encodes as controller(userdata=00.00.00.0d.00.00.00.00.05.dc,pause)
> + encodes as note:6f.76.6e.00.00.00.00.00.05.dc
>
> # icmp6
> icmp6 { eth.dst = ff:ff:ff:ff:ff:ff; output; }; output;
> @@ -1910,11 +1910,11 @@ icmp6_error { };
>
> # icmp6_error with icmp6.frag_mtu
> icmp6_error { eth.dst = ff:ff:ff:ff:ff:ff; icmp6.frag_mtu = 1500; output; };
> output;
> - encodes as
> controller(userdata=00.00.00.14.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.28.00.00.23.20.00.25.00.00.00.00.00.00.00.03.00.10.00.00.00.15.00.00.00.00.00.00.05.dc.00.04.00.04.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00),resubmit(,64)
> + encodes as
> controller(userdata=00.00.00.14.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.18.00.00.23.20.00.08.6f.76.6e.00.00.00.00.01.00.00.05.dc.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00),resubmit(,64)
> has prereqs ip6
>
> icmp6.frag_mtu = 1500;
> - encodes as controller(userdata=00.00.00.15.00.00.00.00.00.00.05.dc,pause)
> + encodes as note:6f.76.6e.00.00.00.00.01.00.00.05.dc
>
> # tcp_reset
> tcp_reset { eth.dst = ff:ff:ff:ff:ff:ff; output; }; output;
Regards,
Dumitru
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev