NEW OVN ACTIONS --------------- 1. dhcp_relay_req_chk(<relay-ip>, <server-ip>) - This action executes on the source node on which the DHCP request originated. - This action relays the DHCP request coming from client to the server. Relay-ip is used to update GIADDR in the DHCP header. 2. dhcp_relay_resp_chk(<relay-ip>, <server-ip>) - This action executes on the first node (RC node) which processes the DHCP response from the server. - This action updates the destination MAC and destination IP so that the response can be forwarded to the appropriate node from which request was originated. - Relay-ip, server-ip are used to validate GIADDR and SERVER ID in the DHCP payload.
Signed-off-by: Naveen Yerramneni <naveen.yerramn...@nutanix.com> --- include/ovn/actions.h | 27 ++++++++ lib/actions.c | 149 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 49fb96fc6..a8e4393ed 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -95,6 +95,8 @@ struct collector_set_ids; OVNACT(LOOKUP_ND_IP, ovnact_lookup_mac_bind_ip) \ OVNACT(PUT_DHCPV4_OPTS, ovnact_put_opts) \ OVNACT(PUT_DHCPV6_OPTS, ovnact_put_opts) \ + OVNACT(DHCPV4_RELAY_REQ_CHK, ovnact_dhcp_relay) \ + OVNACT(DHCPV4_RELAY_RESP_CHK, ovnact_dhcp_relay) \ OVNACT(SET_QUEUE, ovnact_set_queue) \ OVNACT(DNS_LOOKUP, ovnact_result) \ OVNACT(LOG, ovnact_log) \ @@ -395,6 +397,15 @@ struct ovnact_put_opts { size_t n_options; }; +/* OVNACT_DHCP_RELAY. */ +struct ovnact_dhcp_relay { + struct ovnact ovnact; + int family; + struct expr_field dst; /* 1-bit destination field. */ + ovs_be32 relay_ipv4; + ovs_be32 server_ipv4; +}; + /* Valid arguments to SET_QUEUE action. * * QDISC_MIN_QUEUE_ID is the default queue, so user-defined queues should @@ -758,6 +769,22 @@ enum action_opcode { /* multicast group split buffer action. */ ACTION_OPCODE_MG_SPLIT_BUF, + + /* "dhcp_relay_req_chk(relay_ip, server_ip)". + * + * Arguments follow the action_header, in this format: + * - The 32-bit DHCP relay IP. + * - The 32-bit DHCP server IP. + */ + ACTION_OPCODE_DHCP_RELAY_REQ_CHK, + + /* "dhcp_relay_resp_chk(relay_ip, server_ip)". + * + * Arguments follow the action_header, in this format: + * - The 32-bit DHCP relay IP. + * - The 32-bit DHCP server IP. + */ + ACTION_OPCODE_DHCP_RELAY_RESP_CHK, }; /* Header. */ diff --git a/lib/actions.c b/lib/actions.c index a45874dfb..d55b5153f 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -2680,6 +2680,149 @@ ovnact_controller_event_free(struct ovnact_controller_event *event) free_gen_options(event->options, event->n_options); } +static void +format_DHCPV4_RELAY_REQ_CHK(const struct ovnact_dhcp_relay *dhcp_relay, + struct ds *s) +{ + expr_field_format(&dhcp_relay->dst, s); + ds_put_format(s, " = dhcp_relay_req_chk("IP_FMT", "IP_FMT");", + IP_ARGS(dhcp_relay->relay_ipv4), + IP_ARGS(dhcp_relay->server_ipv4)); +} + +static void +parse_dhcp_relay_req_chk(struct action_context *ctx, + const struct expr_field *dst, + struct ovnact_dhcp_relay *dhcp_relay) +{ + /* Skip dhcp_relay_req_chk( */ + lexer_force_match(ctx->lexer, LEX_T_LPAREN); + + /* Validate that the destination is a 1-bit, modifiable field. */ + char *error = expr_type_check(dst, 1, true, ctx->scope); + if (error) { + lexer_error(ctx->lexer, "%s", error); + free(error); + return; + } + dhcp_relay->dst = *dst; + + /* Parse relay ip and server ip. */ + if (ctx->lexer->token.format == LEX_F_IPV4) { + dhcp_relay->family = AF_INET; + dhcp_relay->relay_ipv4 = ctx->lexer->token.value.ipv4; + lexer_get(ctx->lexer); + lexer_match(ctx->lexer, LEX_T_COMMA); + if (ctx->lexer->token.format == LEX_F_IPV4) { + dhcp_relay->family = AF_INET; + dhcp_relay->server_ipv4 = ctx->lexer->token.value.ipv4; + lexer_get(ctx->lexer); + } else { + lexer_syntax_error(ctx->lexer, "expecting IPv4 dhcp server ip"); + return; + } + } else { + lexer_syntax_error(ctx->lexer, "expecting IPv4 dhcp relay " + "and server ips"); + return; + } + lexer_force_match(ctx->lexer, LEX_T_RPAREN); +} + +static void +encode_DHCPV4_RELAY_REQ_CHK(const struct ovnact_dhcp_relay *dhcp_relay, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + struct mf_subfield dst = expr_resolve_field(&dhcp_relay->dst); + size_t oc_offset = encode_start_controller_op( + ACTION_OPCODE_DHCP_RELAY_REQ_CHK, + true, ep->ctrl_meter_id, + ofpacts); + nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false); + ovs_be32 ofs = htonl(dst.ofs); + ofpbuf_put(ofpacts, &ofs, sizeof ofs); + ofpbuf_put(ofpacts, &dhcp_relay->relay_ipv4, + sizeof(dhcp_relay->relay_ipv4)); + ofpbuf_put(ofpacts, &dhcp_relay->server_ipv4, + sizeof(dhcp_relay->server_ipv4)); + encode_finish_controller_op(oc_offset, ofpacts); +} + +static void +format_DHCPV4_RELAY_RESP_CHK(const struct ovnact_dhcp_relay *dhcp_relay, + struct ds *s) +{ + expr_field_format(&dhcp_relay->dst, s); + ds_put_format(s, " = dhcp_relay_resp_chk("IP_FMT", "IP_FMT");", + IP_ARGS(dhcp_relay->relay_ipv4), + IP_ARGS(dhcp_relay->server_ipv4)); +} + +static void +parse_dhcp_relay_resp_chk(struct action_context *ctx, + const struct expr_field *dst, + struct ovnact_dhcp_relay *dhcp_relay) +{ + /* Skip dhcp_relay_resp_chk( */ + lexer_force_match(ctx->lexer, LEX_T_LPAREN); + + /* Validate that the destination is a 1-bit, modifiable field. */ + char *error = expr_type_check(dst, 1, true, ctx->scope); + if (error) { + lexer_error(ctx->lexer, "%s", error); + free(error); + return; + } + dhcp_relay->dst = *dst; + + /* Parse relay ip and server ip. */ + if (ctx->lexer->token.format == LEX_F_IPV4) { + dhcp_relay->family = AF_INET; + dhcp_relay->relay_ipv4 = ctx->lexer->token.value.ipv4; + lexer_get(ctx->lexer); + lexer_match(ctx->lexer, LEX_T_COMMA); + if (ctx->lexer->token.format == LEX_F_IPV4) { + dhcp_relay->family = AF_INET; + dhcp_relay->server_ipv4 = ctx->lexer->token.value.ipv4; + lexer_get(ctx->lexer); + } else { + lexer_syntax_error(ctx->lexer, "expecting IPv4 dhcp server ip"); + return; + } + } else { + lexer_syntax_error(ctx->lexer, "expecting IPv4 dhcp relay and " + "server ips"); + return; + } + lexer_force_match(ctx->lexer, LEX_T_RPAREN); +} + +static void +encode_DHCPV4_RELAY_RESP_CHK(const struct ovnact_dhcp_relay *dhcp_relay, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + struct mf_subfield dst = expr_resolve_field(&dhcp_relay->dst); + size_t oc_offset = encode_start_controller_op( + ACTION_OPCODE_DHCP_RELAY_RESP_CHK, + true, ep->ctrl_meter_id, + ofpacts); + nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false); + ovs_be32 ofs = htonl(dst.ofs); + ofpbuf_put(ofpacts, &ofs, sizeof ofs); + ofpbuf_put(ofpacts, &dhcp_relay->relay_ipv4, + sizeof(dhcp_relay->relay_ipv4)); + ofpbuf_put(ofpacts, &dhcp_relay->server_ipv4, + sizeof(dhcp_relay->server_ipv4)); + encode_finish_controller_op(oc_offset, ofpacts); +} + +static void ovnact_dhcp_relay_free( + struct ovnact_dhcp_relay *dhcp_relay OVS_UNUSED) +{ +} + static void parse_put_opts(struct action_context *ctx, const struct expr_field *dst, struct ovnact_put_opts *po, const struct hmap *gen_opts, @@ -5384,6 +5527,12 @@ parse_set_action(struct action_context *ctx) lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { parse_chk_lb_aff(ctx, &lhs, ovnact_put_CHK_LB_AFF(ctx->ovnacts)); + } else if (lexer_match_id(ctx->lexer, "dhcp_relay_req_chk")) { + parse_dhcp_relay_req_chk(ctx, &lhs, + ovnact_put_DHCPV4_RELAY_REQ_CHK(ctx->ovnacts)); + } else if (lexer_match_id(ctx->lexer, "dhcp_relay_resp_chk")) { + parse_dhcp_relay_resp_chk(ctx, &lhs, + ovnact_put_DHCPV4_RELAY_RESP_CHK(ctx->ovnacts)); } else { parse_assignment_action(ctx, false, &lhs); } -- 2.36.6 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev