ICMP redirect (icmp type 5, code 1 - Redirect for the Host) is used to tell sender to use more efficient route for sending packets to a destination. When a router receives a packet and determines that another router on the same network provides a shorter path, it sends an ICMP Redirect message to sender, advising it to send future packets to the optimal router. The use of this functionality in northd will be implemented in the next commit.
Signed-off-by: Alexandra Rukomoinikova <[email protected]> --- controller/pinctrl.c | 38 ++++++++++++++++++++++++++++++-------- include/ovn/actions.h | 11 ++++++++++- lib/actions.c | 23 +++++++++++++++++++++++ 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 333dcedb6..40ad64a2a 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -1701,7 +1701,7 @@ static void pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow, struct dp_packet *pkt_in, const struct match *md, struct ofpbuf *userdata, - bool set_icmp_code, bool loopback) + bool set_icmp_code, bool loopback, bool redirect) { enum ofp_version version = rconn_get_version(swconn); @@ -1716,6 +1716,14 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow, return; } + /* Northd decides whether a packet deserves an ICMP Redirect, but one of + * the conditions - that the next hop is not the source of the packet - + * compares two run-time values, which the logical flow match language + * cannot express. So check it here instead. */ + if (redirect && htonl(md->flow.regs[0]) == ip_flow->nw_src) { + return; + } + uint64_t ofpacts_stub[4096 / 8]; struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); @@ -1784,10 +1792,18 @@ 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); - if (mtu) { - ih->icmp_fields.frag.mtu = *mtu; - ih->icmp_code = 4; + if (redirect) { + put_16aligned_be32(&ih->icmp_fields.gateway, + htonl(md->flow.regs[0])); + ih->icmp_type = ICMP4_REDIRECT; + ih->icmp_code = 1; + } else { + ovs_be16 *mtu = ofpacts_get_ovn_field(&ofpacts, + OVN_ICMP4_FRAG_MTU); + if (mtu) { + ih->icmp_fields.frag.mtu = *mtu; + ih->icmp_code = 4; + } } ih->icmp_csum = 0; @@ -2072,7 +2088,8 @@ pinctrl_handle_reject(struct rconn *swconn, const struct flow *ip_flow, } else if (ip_flow->nw_proto == IPPROTO_SCTP) { pinctrl_handle_sctp_abort(swconn, ip_flow, pkt_in, md, userdata, true); } else { - pinctrl_handle_icmp(swconn, ip_flow, pkt_in, md, userdata, true, true); + pinctrl_handle_icmp(swconn, ip_flow, pkt_in, md, userdata, true, true, + false); } } @@ -3852,13 +3869,18 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg) case ACTION_OPCODE_ICMP: pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata, - &userdata, true, false); + &userdata, true, false, false); + break; + + case ACTION_OPCODE_ICMP4_REDIRECT: + pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata, + &userdata, false, false, true); break; case ACTION_OPCODE_ICMP4_ERROR: case ACTION_OPCODE_ICMP6_ERROR: pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata, - &userdata, false, false); + &userdata, false, false, false); break; case ACTION_OPCODE_TCP_RESET: diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 7def8917e..997b0e05b 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -139,6 +139,7 @@ struct collector_set_ids; OVNACT(CHK_EVPN_ARP, ovnact_chk_evpn_arp) \ OVNACT(NF_LEARN_ORIG_INPORT, ovnact_nf_learn) \ OVNACT(NF_LOOKUP_ORIG_INPORT, ovnact_nf_lookup) \ + OVNACT(ICMP4_REDIRECT, ovnact_nest) \ /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */ enum OVS_PACKED_ENUM ovnact_type { @@ -845,7 +846,15 @@ OVNACTS * Arguments follow the action_header, in this format: * - The 32-bit IPv4 address. */ \ - ACTION_OPCODE(PUT_ICMP4_INNER_IP4_SRC) + ACTION_OPCODE(PUT_ICMP4_INNER_IP4_SRC) \ + \ + /* "icmp4_redirect { ...actions... }". + * + * The actions, in OpenFlow 1.3 format, follow the action_header. The + * address of the better first hop is taken from reg0, where the logical + * router pipeline leaves the resolved next hop. + */ \ + ACTION_OPCODE(ICMP4_REDIRECT) enum action_opcode { diff --git a/lib/actions.c b/lib/actions.c index 0e95e2d70..026d9ed5a 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -1828,6 +1828,12 @@ parse_ICMP4(struct action_context *ctx) parse_nested_action(ctx, OVNACT_ICMP4, "ip4", ctx->scope); } +static void +parse_ICMP4_REDIRECT(struct action_context *ctx) +{ + parse_nested_action(ctx, OVNACT_ICMP4_REDIRECT, "ip4", ctx->scope); +} + static void parse_ICMP4_ERROR(struct action_context *ctx) { @@ -1909,6 +1915,12 @@ format_ICMP4(const struct ovnact_nest *nest, struct ds *s) format_nested_action(nest, "icmp4", s); } +static void +format_ICMP4_REDIRECT(const struct ovnact_nest *nest, struct ds *s) +{ + format_nested_action(nest, "icmp4_redirect", s); +} + static void format_ICMP4_ERROR(const struct ovnact_nest *nest, struct ds *s) { @@ -2010,6 +2022,7 @@ is_paused_nested_action(enum action_opcode opcode) case ACTION_OPCODE_PUT_ND_RA_OPTS: case ACTION_OPCODE_ICMP: case ACTION_OPCODE_ICMP4_ERROR: + case ACTION_OPCODE_ICMP4_REDIRECT: case ACTION_OPCODE_ICMP6_ERROR: case ACTION_OPCODE_TCP_RESET: case ACTION_OPCODE_SCTP_ABORT: @@ -2073,6 +2086,14 @@ encode_ICMP4(const struct ovnact_nest *on, encode_nested_actions(on, ep, ACTION_OPCODE_ICMP, ofpacts); } +static void +encode_ICMP4_REDIRECT(const struct ovnact_nest *on, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + encode_nested_actions(on, ep, ACTION_OPCODE_ICMP4_REDIRECT, ofpacts); +} + static void encode_ICMP4_ERROR(const struct ovnact_nest *on, const struct ovnact_encode_params *ep, @@ -5942,6 +5963,8 @@ parse_action(struct action_context *ctx) parse_CLONE(ctx); } else if (lexer_match_id(ctx->lexer, "arp")) { parse_ARP(ctx); + } else if (lexer_match_id(ctx->lexer, "icmp4_redirect")) { + parse_ICMP4_REDIRECT(ctx); } else if (lexer_match_id(ctx->lexer, "icmp4")) { parse_ICMP4(ctx); } else if (lexer_match_id(ctx->lexer, "icmp4_error")) { -- 2.48.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
