From: Zongkai LI <zealo...@gmail.com> This patch adds specific inner actions 'put_nd_ra', 'put_nd_opt_prefix', 'put_nd_opt_mtu', 'put_nd_opt_sll' for action 'nd_ra'.
Action put_nd_ra will set cur_hop_limit(8-bit unsigned integer), "Managed address configuration" and "Other configuration" flags(8-bit unsigned integer, with 6-bit 0 in low endian), router lifetime(16-bit unsigned integer), reachable time(32-bit unsigned integer), retrans timer (32-bit unsigned integer) in RA packet. e.g. put_nd_ra(64,0,10800,0,0); Action put_nd_ra_opt_sll will append Source Link-layer Address Option for RA message with inner ethernet address parameter. e.g. put_nd_ra_opt_sll(12:34:56:78:9a:bc); Action put_nd_ra_opt_mtu will append MTU Option for RA message with inner integer value(32-bit unsigned integer). e.g. put_nd_ra_opt_mtu(1450); Action put_nd_ra_opt_prefix will append Prefix Information Option for RA message with inner parameters. The inner parameters will set prefix length (8-bit unsigned integer), on-link flag and autonomous address-configuration flag(8-bit unsigned integer, with 6-bit 0 in low endian), valid lifetime (32-bit unsigned integer), preferred lifetime(32-bit unsigned integer), prefix(128-bit IPv6 address prefix) in Prefix Information Option. e.g. put_nd_ra_opt_prefix(64,192,10800,10800,fdad:a0f9:a012::); --- include/ovn/actions.h | 79 ++++++++++++++- ovn/controller/pinctrl.c | 160 +++++++++++++++++++++++++++++- ovn/lib/actions.c | 243 +++++++++++++++++++++++++++++++++++++++++++++- ovn/ovn-sb.xml | 39 ++++++++ ovn/utilities/ovn-trace.c | 4 + tests/ovn.at | 16 ++- 6 files changed, 534 insertions(+), 7 deletions(-) diff --git a/include/ovn/actions.h b/include/ovn/actions.h index c1dda2f..fb30821 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -68,7 +68,11 @@ struct simap; OVNACT(GET_ND, ovnact_get_mac_bind) \ OVNACT(PUT_ND, ovnact_put_mac_bind) \ OVNACT(PUT_DHCPV4_OPTS, ovnact_put_dhcp_opts) \ - OVNACT(PUT_DHCPV6_OPTS, ovnact_put_dhcp_opts) + OVNACT(PUT_DHCPV6_OPTS, ovnact_put_dhcp_opts) \ + OVNACT(PUT_ND_RA, ovnact_put_nd_ra) \ + OVNACT(PUT_ND_OPT_SLL, ovnact_put_nd_opt_sll) \ + OVNACT(PUT_ND_OPT_MTU, ovnact_put_nd_opt_mtu) \ + OVNACT(PUT_ND_OPT_PREFIX, ovnact_put_nd_opt_prefix) /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */ enum OVS_PACKED_ENUM ovnact_type { @@ -228,6 +232,38 @@ struct ovnact_put_dhcp_opts { size_t n_options; }; +/* OVNACT_PUt_ND_RA. */ +struct ovnact_put_nd_ra { + struct ovnact ovnact; + uint8_t cur_hop_limit; + uint8_t mo_flags; + uint16_t router_lifetime; + uint32_t reachable_time; + uint32_t retrans_timer; +}; + +/* OVNACT_PUT_ND_OPT_SLL. */ +struct ovnact_put_nd_opt_sll { + struct ovnact ovnact; + struct eth_addr mac; +}; + +/* OVNACT_PUT_ND_OPT_MTU. */ +struct ovnact_put_nd_opt_mtu { + struct ovnact ovnact; + uint32_t mtu; +}; + +/* OVNACT_PUT_ND_OPT_PREFIX. */ +struct ovnact_put_nd_opt_prefix { + struct ovnact ovnact; + uint8_t prefix_len; + uint8_t la_flags; + uint32_t valid_lifetime; + uint32_t preferred_lifetime; + struct in6_addr prefix; +}; + /* 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); @@ -360,6 +396,44 @@ enum action_opcode { * The actions, in OpenFlow 1.3 format, follow the action_header. */ ACTION_OPCODE_ND_RA, + + /* "put_nd_ra(c, mo, router_lt, reach_t, retrans_t)". + * + * Specific inner action for ACTION_OPCODE_ND_RA. Arguments in this format: + * - c: 8-bit unsigned integer for current hop limit. + * - mo: 8-bit unsigned integer for Managed address configuration flag + * and Other configuration flag. (including 6-bit reserved 0) + * - router_lt: 16-bit unsigned integer for router lifetime. + * - reach_t: 32-bit unisgned integer for reachable time. + * - retrans_t: 32-bit unsigned integer for retrans timer. + */ + ACTION_OPCODE_PUT_ND_RA, + + /* "put_nd_opt_sll(mac)". + * + * Specific inner action for ACTION_OPCODE_ND_RA. Arguments in this format: + * - mac: 48-bit ethernet address. + */ + ACTION_OPCODE_PUT_ND_OPT_SLL, + + /* "put_nd_opt_mtu(mtu)". + * + * Specific inner action for ACTION_OPCODE_ND_RA. Arguments in this format: + * - mtu: 32-bit unsigned integer MTU. + */ + ACTION_OPCODE_PUT_ND_OPT_MTU, + + /* "put_nd_opt_prefix(plen, la, valid_lt, preferred_lt, prefix)". + * + * Specific inner action for ACTION_OPCODE_ND_RA. Arguments in this format: + * - plen: 8-bit unsigned integer for prefix length. + * - la: 8-bit unsigned integer for on-link flag and autonomous + * address-configuration flag. (including 6-bit reserved 0) + * - valid_lt: 32-bit unsigned integer for valid_lifetime. + * - preferred_lt: 32-bit unsigned integer for preferred_lifetime. + * - prefix: 128-bit IPv6 address. + */ + ACTION_OPCODE_PUT_ND_OPT_PREFIX, }; /* Header. */ @@ -445,6 +519,9 @@ struct ovnact_encode_params { resubmit. */ }; +void ovnact_encode(const struct ovnact *a, const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts); + void ovnacts_encode(const struct ovnact[], size_t ovnacts_len, const struct ovnact_encode_params *, struct ofpbuf *ofpacts); diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index 464c90d..47c9bf7 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -1352,6 +1352,113 @@ reload_metadata(struct ofpbuf *ofpacts, const struct match *md) } } +static bool parse_nd_ra_args(struct ofpbuf *userdata, uint8_t *chl, + uint8_t *mo, ovs_be16 *rlt, + ovs_be32 *rcht, ovs_be32 *rtrt, + uint16_t *args_left_size) +{ + int put_nd_ra_args_len = + sizeof(uint8_t) * 2 + sizeof(uint16_t) + sizeof(uint32_t) * 2; + uint8_t *cur_hop_limit = ofpbuf_try_pull(userdata, sizeof(uint8_t)); + if (!cur_hop_limit) { + return false; + } + uint8_t *mo_flags = ofpbuf_try_pull(userdata, sizeof(uint8_t)); + if (!mo_flags) { + return false; + } + ovs_be16 *router_lifetime = ofpbuf_try_pull(userdata, sizeof(ovs_be16)); + if (!router_lifetime) { + return false; + } + ovs_be32 *reachable_time = ofpbuf_try_pull(userdata, sizeof(ovs_be32)); + if (!reachable_time) { + return false; + } + ovs_be32 *retrans_timer = ofpbuf_try_pull(userdata, sizeof(ovs_be32)); + if (!retrans_timer) { + return false; + } + *chl = *cur_hop_limit; + *mo = *mo_flags; + *rlt = *router_lifetime; + *rcht = *reachable_time; + *rtrt = *retrans_timer; + *args_left_size -= put_nd_ra_args_len; + return true; +} + +static bool parse_nd_prefix_opt_args(struct ofpbuf *userdata, + uint8_t *plen, uint8_t *la, ovs_be32 *vl, + ovs_be32 *pl, ovs_be32 *p, + uint16_t *args_left_size) +{ + int put_nd_prefix_opt_args_len = + sizeof(uint8_t) * 2 + sizeof(uint32_t) *2 + sizeof(struct in6_addr); + if (*args_left_size < put_nd_prefix_opt_args_len) { + return false; + } + uint8_t *prefix_len = ofpbuf_try_pull(userdata, sizeof(uint8_t)); + if (!prefix_len || *prefix_len == 0 || *prefix_len == 128) { + return false; + } + uint8_t *la_flags = ofpbuf_try_pull(userdata, sizeof(uint8_t)); + if (!la_flags) { + return false; + } + ovs_be32 *valid_lifetime = ofpbuf_try_pull(userdata, sizeof(ovs_be32)); + if (!valid_lifetime || *valid_lifetime == 0) { + return false; + } + ovs_be32 *preferred_lifetime = ofpbuf_try_pull(userdata, sizeof(ovs_be32)); + if (!preferred_lifetime || *preferred_lifetime == 0) { + return false; + } + struct in6_addr *prefix = ofpbuf_try_pull(userdata, + sizeof(struct in6_addr)); + if (!prefix) { + return false; + } + *plen = *prefix_len; + *la = *la_flags; + *vl = *valid_lifetime; + *pl = *preferred_lifetime; + memcpy(p, prefix, sizeof(struct in6_addr)); + *args_left_size -= put_nd_prefix_opt_args_len; + return true; +} + +static bool parse_nd_sll_opt_arg(struct ofpbuf *userdata, + struct eth_addr *e, uint16_t *args_left_size) +{ + if (*args_left_size < sizeof(struct eth_addr)) { + return false; + } + struct eth_addr *sll = ofpbuf_try_pull(userdata, sizeof(struct eth_addr)); + if (!sll) { + return false; + } + memcpy(e, sll, sizeof(struct eth_addr)); + *args_left_size -= sizeof(struct eth_addr); + return true; +} + +static bool parse_nd_mtu_opt_arg(struct ofpbuf *userdata, + ovs_be32 *m, uint16_t *args_left_size) +{ + if (*args_left_size < sizeof(ovs_be32)) { + return false; + } + ovs_be32 *mtu = ofpbuf_try_pull(userdata, sizeof(ovs_be32)); + /* Per RFC 2460, consider 1280 as minimum IPv6 MTU. */ + if (!mtu || *mtu < 1280) { + return false; + } + *m = *mtu; + *args_left_size -= sizeof(ovs_be32); + return true; +} + static void pinctrl_handle_nd(const struct flow *ip_flow, const struct match *md, struct ofpbuf *userdata) @@ -1385,18 +1492,67 @@ pinctrl_handle_nd(const struct flow *ip_flow, const struct match *md, &ip_flow->nd_target, &ip_flow->ipv6_src, htonl(ND_RSO_SOLICITED | ND_RSO_OVERRIDE)); } else { - /* xxx Using hardcode data to compose RA packet. - * xxx The following patch should fix this. */ uint8_t cur_hop_limit = 64; uint8_t mo_flags = 0; ovs_be16 router_lifetime = htons(0x2a30); /* 3 hours. */ ovs_be32 reachable_time = 0; ovs_be32 retrans_timer = 0; + uint16_t *args_len_p = ofpbuf_try_pull(userdata, sizeof(uint16_t)); + uint16_t args_len = args_len_p ? ntohs(*args_len_p) : 0; + uint8_t *arg = NULL; + bool continue_parse = false; + if (args_len >= sizeof(uint8_t)) { + arg = ofpbuf_try_pull(userdata, sizeof(uint8_t)); + args_len -= sizeof(uint8_t); + if (arg && *arg == ACTION_OPCODE_PUT_ND_RA) { + continue_parse = parse_nd_ra_args( + userdata, &cur_hop_limit, &mo_flags, &router_lifetime, + &reachable_time, &retrans_timer, &args_len); + } + } compose_nd_ra(&packet, ip_flow->dl_dst, ip_flow->dl_src, &ip_flow->ipv6_dst, &ip_flow->ipv6_src, cur_hop_limit, mo_flags, router_lifetime, reachable_time, retrans_timer); + if (continue_parse && args_len > sizeof(uint8_t)) { + bool sll_opt_parsed = false; + bool mtu_opt_parsed = false; + struct eth_addr sll; + ovs_be32 mtu; + uint8_t prefix_len = 0; + uint8_t la_flags = 0; + ovs_be32 valid_lifetime = 0; + ovs_be32 preferred_lifetime = 0; + ovs_be32 prefix[4]; + while (args_len > 0) { + arg = ofpbuf_try_pull(userdata, sizeof(uint8_t)); + args_len -= sizeof(uint8_t); + if (arg && *arg == ACTION_OPCODE_PUT_ND_OPT_PREFIX + && parse_nd_prefix_opt_args(userdata, &prefix_len, + &la_flags, &valid_lifetime, + &preferred_lifetime, prefix, + &args_len)) { + packet_put_ra_prefix_opt(&packet, prefix_len, la_flags, + valid_lifetime, preferred_lifetime, + prefix); + } else if (arg && *arg == ACTION_OPCODE_PUT_ND_OPT_SLL + && !sll_opt_parsed + && parse_nd_sll_opt_arg(userdata, &sll, &args_len)) { + packet_put_ra_sll_opt(&packet, sll); + sll_opt_parsed = true; + } else if (arg && *arg == ACTION_OPCODE_PUT_ND_OPT_MTU + && !mtu_opt_parsed + && parse_nd_mtu_opt_arg(userdata, &mtu, &args_len)) { + packet_put_ra_mtu_opt(&packet, mtu); + mtu_opt_parsed = true; + } else { + VLOG_WARN_RL(&rl, "Unknown to parse inner arguments for" + " 'nd_ra'"); + break; + } + } + } } /* Reload previous packet metadata. */ diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c index 96b2f6b..c2f79ad 100644 --- a/ovn/lib/actions.c +++ b/ovn/lib/actions.c @@ -1159,7 +1159,45 @@ encode_ND_RA(const struct ovnact_nest *on, const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_nested_actions(on, ep, ACTION_OPCODE_ND_RA, ofpacts); + uint64_t inner_ofpacts_stub[1024 / 8]; + uint64_t inner_args_stub[1024 / 8]; + struct ofpbuf inner_args = OFPBUF_STUB_INITIALIZER(inner_args_stub); + struct ofpbuf inner_ofpacts = OFPBUF_STUB_INITIALIZER(inner_ofpacts_stub); + const struct ovnact *a; + OVNACT_FOR_EACH (a, on->nested, on->nested_len) { + if (a->type == OVNACT_PUT_ND_RA) { + encode_PUT_ND_RA( + (const struct ovnact_put_nd_ra *)a, ep, &inner_args); + } else if (a->type == OVNACT_PUT_ND_OPT_SLL) { + encode_PUT_ND_OPT_SLL( + (const struct ovnact_put_nd_opt_sll *)a, ep, &inner_args); + } else if (a->type == OVNACT_PUT_ND_OPT_MTU) { + encode_PUT_ND_OPT_MTU( + (const struct ovnact_put_nd_opt_mtu *)a, ep, &inner_args); + } else if (a->type == OVNACT_PUT_ND_OPT_PREFIX) { + encode_PUT_ND_OPT_PREFIX( + (const struct ovnact_put_nd_opt_prefix *)a, ep, &inner_args); + } else { + ovnact_encode(a, ep, &inner_ofpacts); + } + } + uint16_t inner_args_size = inner_args.size ? htons(inner_args.size) : 0; + + /* Add a "controller" action with the data and actions parsed from nested + * actions inside "{...}", converted to OpenFlow, as its userdata. + * ovn-controller will convert the packet to RA and then send the packet + * and actions back to the switch inside an OFPT_PACKET_OUT message. */ + size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_ND_RA, + false, ofpacts); + ofpbuf_put(ofpacts, &inner_args_size, sizeof(uint16_t)); + ofpbuf_put(ofpacts, inner_args.data, inner_args.size); + ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size, + ofpacts, OFP13_VERSION); + encode_finish_controller_op(oc_offset, ofpacts); + + /* Free memory. */ + ofpbuf_uninit(&inner_args); + ofpbuf_uninit(&inner_ofpacts); } static void @@ -1678,7 +1716,199 @@ parse_set_action(struct action_context *ctx) lexer_syntax_error(ctx->lexer, "expecting `=' or `<->'"); } } + +/* Parse put_nd_ra, put_nd_opt_sll, put_nd_prefix, put_nd_mtu action. */ +static void +parse_put_nd_ra(struct action_context *ctx, + struct ovnact_put_nd_ra *put_ra) +{ + lexer_force_match(ctx->lexer, LEX_T_LPAREN); + int field = 0; + int n_fields = 5; + while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) { + if (!lexer_match(ctx->lexer, LEX_T_INTEGER) + || ctx->lexer->token.format != LEX_F_DECIMAL) { + break; + } + if (field == 0) { + put_ra->cur_hop_limit = ctx->lexer->token.value.u8_val; + } else if (field == 1) { + put_ra->mo_flags = ctx->lexer->token.value.u8_val; + } else if (field == 2) { + put_ra->router_lifetime = ntohs(ctx->lexer->token.value.be16_int); + } else if (field == 3) { + put_ra->reachable_time = ntohl(ctx->lexer->token.value.be32_int); + } else if (field == 4) { + put_ra->retrans_timer = ntohl(ctx->lexer->token.value.be32_int); + } + lexer_match(ctx->lexer, LEX_T_COMMA); + field++; + } + if (field != n_fields) { + lexer_syntax_error(ctx->lexer, "not enough fields parsed"); + } +} +static void +parse_put_nd_opt_prefix(struct action_context *ctx, + struct ovnact_put_nd_opt_prefix *prefix) +{ + lexer_force_match(ctx->lexer, LEX_T_LPAREN); + + int field = 0; + int n_fields = 5; + while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) { + if (!lexer_match(ctx->lexer, LEX_T_INTEGER)) { + break; + } + if (field < 4 && ctx->lexer->token.format != LEX_F_DECIMAL) { + lexer_syntax_error(ctx->lexer, "expecting demical integer"); + } + if (field == 0) { + prefix->prefix_len = ctx->lexer->token.value.u8_val; + } else if (field == 1) { + prefix->la_flags = ctx->lexer->token.value.u8_val; + } else if (field == 2) { + prefix->valid_lifetime = ntohl(ctx->lexer->token.value.be32_int); + } else if (field == 3) { + prefix->preferred_lifetime = + ntohl(ctx->lexer->token.value.be32_int); + } else if (field == 4) { + if (ctx->lexer->token.format != LEX_F_IPV6) { + lexer_syntax_error(ctx->lexer, "expecting IPv6 address"); + } + memcpy(&prefix->prefix, &ctx->lexer->token.value.ipv6, + sizeof(struct in6_addr)); + } + lexer_match(ctx->lexer, LEX_T_COMMA); + field++; + } + if (field != n_fields) { + lexer_syntax_error(ctx->lexer, "not enough fields parsed"); + } +} +static void +parse_put_nd_opt_sll(struct action_context *ctx, + struct ovnact_put_nd_opt_sll *sll) +{ + lexer_force_match(ctx->lexer, LEX_T_LPAREN); + if (!lexer_match(ctx->lexer, LEX_T_INTEGER) + || ctx->lexer->token.format != LEX_F_ETHERNET) { + lexer_syntax_error(ctx->lexer, "expecting ether address"); + } + sll->mac = ctx->lexer->token.value.mac; + lexer_force_match(ctx->lexer, LEX_T_RPAREN); +} +static void +parse_put_nd_opt_mtu(struct action_context *ctx, + struct ovnact_put_nd_opt_mtu *mtu) +{ + lexer_force_match(ctx->lexer, LEX_T_LPAREN); + if (!lexer_match(ctx->lexer, LEX_T_INTEGER) + || ctx->lexer->token.format != LEX_F_DECIMAL) { + lexer_syntax_error(ctx->lexer, "expecting decimal integer"); + } + mtu->mtu = ntohl(ctx->lexer->token.value.be32_int); + lexer_force_match(ctx->lexer, LEX_T_RPAREN); +} + +static void +format_PUT_ND_RA(const struct ovnact_put_nd_ra *ra, struct ds *s) +{ + ds_put_format(s, "put_nd_ra(%u, %u, %u, %u, %u);", + ra->cur_hop_limit, ra->mo_flags, ra->router_lifetime, + ra->reachable_time, ra->retrans_timer); +} +static void +format_PUT_ND_OPT_PREFIX(const struct ovnact_put_nd_opt_prefix *p, + struct ds *s) +{ + ds_put_format(s, "put_nd_opt_prefix(%u, %u, %u, %u, ", + p->prefix_len, p->la_flags, p->valid_lifetime, + p->preferred_lifetime); + ipv6_format_addr(&p->prefix, s); + ds_put_cstr(s, ");"); +} +static void +format_PUT_ND_OPT_SLL(const struct ovnact_put_nd_opt_sll *sll, struct ds *s) +{ + ds_put_cstr(s, "put_nd_opt_sll("); + ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(sll->mac)); + ds_put_cstr(s, ");"); +} +static void +format_PUT_ND_OPT_MTU(const struct ovnact_put_nd_opt_mtu *mtu, struct ds *s) +{ + ds_put_format(s, "put_nd_opt_mtu(%u);", mtu->mtu); +} + +static void +encode_PUT_ND_RA(const struct ovnact_put_nd_ra *ra, + const struct ovnact_encode_params *ep OVS_UNUSED, + struct ofpbuf *ofpacts) +{ + uint8_t inner_code = ACTION_OPCODE_PUT_ND_RA; + ofpbuf_put(ofpacts, &inner_code, sizeof(uint8_t)); + ofpbuf_put(ofpacts, &ra->cur_hop_limit, sizeof(uint8_t)); + ofpbuf_put(ofpacts, &ra->mo_flags, sizeof(uint8_t)); + uint16_t rlt = htons(ra->router_lifetime); + uint32_t rt = htonl(ra->reachable_time); + uint32_t rtt = htonl(ra->retrans_timer); + ofpbuf_put(ofpacts, &rlt, sizeof(uint16_t)); + ofpbuf_put(ofpacts, &rt, sizeof(uint32_t)); + ofpbuf_put(ofpacts, &rtt, sizeof(uint32_t)); +} +static void +encode_PUT_ND_OPT_PREFIX(const struct ovnact_put_nd_opt_prefix *prefix, + const struct ovnact_encode_params *ep OVS_UNUSED, + struct ofpbuf *ofpacts) +{ + uint8_t inner_code = ACTION_OPCODE_PUT_ND_OPT_PREFIX; + ofpbuf_put(ofpacts, &inner_code, sizeof(uint8_t)); + ofpbuf_put(ofpacts, &prefix->prefix_len, sizeof(uint8_t)); + ofpbuf_put(ofpacts, &prefix->la_flags, sizeof(uint8_t)); + uint32_t vlt = htonl(prefix->valid_lifetime); + uint32_t plt = htonl(prefix->preferred_lifetime); + ofpbuf_put(ofpacts, &vlt, sizeof(uint32_t)); + ofpbuf_put(ofpacts, &plt, sizeof(uint32_t)); + ofpbuf_put(ofpacts, &prefix->prefix, sizeof(struct in6_addr)); +} +static void +encode_PUT_ND_OPT_SLL(const struct ovnact_put_nd_opt_sll *sll, + const struct ovnact_encode_params *ep OVS_UNUSED, + struct ofpbuf *ofpacts) +{ + uint8_t inner_code = ACTION_OPCODE_PUT_ND_OPT_SLL; + ofpbuf_put(ofpacts, &inner_code, sizeof(uint8_t)); + ofpbuf_put(ofpacts, &sll->mac, sizeof(struct eth_addr)); +} +static void +encode_PUT_ND_OPT_MTU(const struct ovnact_put_nd_opt_mtu *mtu, + const struct ovnact_encode_params *ep OVS_UNUSED, + struct ofpbuf *ofpacts) +{ + uint8_t inner_code = ACTION_OPCODE_PUT_ND_OPT_MTU; + ofpbuf_put(ofpacts, &inner_code, sizeof(uint8_t)); + uint32_t m = htonl(mtu->mtu); + ofpbuf_put(ofpacts, &m, sizeof(uint32_t)); +} +static void +free_PUT_ND_RA(struct ovnact_put_nd_ra *ra OVS_UNUSED) +{ +} +static void +free_PUT_ND_OPT_PREFIX(struct ovnact_put_nd_opt_prefix *prefix OVS_UNUSED) +{ +} +static void +free_PUT_ND_OPT_SLL(struct ovnact_put_nd_opt_sll *sll OVS_UNUSED) +{ +} +static void +free_PUT_ND_OPT_MTU(struct ovnact_put_nd_opt_mtu *mtu OVS_UNUSED) +{ +} + static bool parse_action(struct action_context *ctx) { @@ -1713,6 +1943,15 @@ parse_action(struct action_context *ctx) parse_ND_NA(ctx); } else if (lexer_match_id(ctx->lexer, "nd_ra")) { parse_ND_RA(ctx); + } else if (lexer_match_id(ctx->lexer, "put_nd_ra")) { + parse_put_nd_ra(ctx, ovnact_put_PUT_ND_RA(ctx->ovnacts)); + } else if (lexer_match_id(ctx->lexer, "put_nd_opt_prefix")) { + parse_put_nd_opt_prefix(ctx, + ovnact_put_PUT_ND_OPT_PREFIX(ctx->ovnacts)); + } else if (lexer_match_id(ctx->lexer, "put_nd_opt_sll")) { + parse_put_nd_opt_sll(ctx, ovnact_put_PUT_ND_OPT_SLL(ctx->ovnacts)); + } else if (lexer_match_id(ctx->lexer, "put_nd_opt_mtu")) { + parse_put_nd_opt_mtu(ctx, ovnact_put_PUT_ND_OPT_MTU(ctx->ovnacts)); } else if (lexer_match_id(ctx->lexer, "get_arp")) { parse_get_mac_bind(ctx, 32, ovnact_put_GET_ARP(ctx->ovnacts)); } else if (lexer_match_id(ctx->lexer, "put_arp")) { @@ -1850,7 +2089,7 @@ ovnacts_format(const struct ovnact *ovnacts, size_t ovnacts_len, /* Encoding ovnacts to OpenFlow. */ -static void +void ovnact_encode(const struct ovnact *a, const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml index 7b17d9d..1f60863 100644 --- a/ovn/ovn-sb.xml +++ b/ovn/ovn-sb.xml @@ -1242,6 +1242,45 @@ </ul> <p> + The 'nd_ra' action has specific inner action + <code>put_nd_ra(h,mo,lt,ct,tr)</code> to hold values for fields + and flags in RA message. + <b>Parameters</b>: 8-bit unsigned integer cur_hop_limit field + <var>h</var>, 8-bit unsigned integer for "Managed address + configuration" and "Other configuration" flags with 6-bit reserved + 0 in field <var>mo</var>, 16-bit unsigned integer router_lifetime + field <var>lt</var>, 32-bit unsigned integer reachable_time + field <var>ct</var>, 32-bit unsigned integer retrans_timer + field <var>tr</var>. + </p> + + <p> + The 'nd_ra' action has specific inner action + <code>put_nd_opt_prefix(pl,la,vt,pt,p)</code> to hold values for + fields and flags in Prefix Information Option for RA message. + <b>Parameters</b>: 8-bit unsigned integer prefix lenght field + <var>pl</var>, 8-bit unsigned integer for on-link flag and + autonomous address-configuration flag with 6-bit reserved 0 in + field <var>mo</var>, 32-bit unsigned integer valid_lifetime field + <var>vt</var>, 32-bit unsigned integer preferred_lifetime field + <var>pt</var>, 128-bit IPv6 prefix field <var>p</var>. + </p> + + <p> + The 'nd_ra' action has specific inner action + <code>put_nd_opt_mtu(m)</code> to hold value for mtu field in MTU + Option for RA message. + <b>Parameters</b>: 32-bit unsigned integer mtu field <var>m</var>. + </p> + + <p> + The 'nd_ra' action has specific inner action + <code>put_nd_opt_sll(s)</code> to hold value for link-layer address + field in Source Link-layer Address Option for RA message. + <b>Parameters</b>: 48-bit Ethernet address field <var>s</var>. + </p> + + <p> The ND packet has the same VLAN header, if any, as the IPv6 packet it replaces. </p> diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c index 8583d6d..3ee7ade 100644 --- a/ovn/utilities/ovn-trace.c +++ b/ovn/utilities/ovn-trace.c @@ -1268,6 +1268,10 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, case OVNACT_PUT_ARP: case OVNACT_PUT_ND: + case OVNACT_PUT_ND_RA: + case OVNACT_PUT_ND_OPT_PREFIX: + case OVNACT_PUT_ND_OPT_SLL: + case OVNACT_PUT_ND_OPT_MTU: /* Nothing to do for tracing. */ break; diff --git a/tests/ovn.at b/tests/ovn.at index 788cc0e..3091131 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -886,9 +886,21 @@ nd_na { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inpor has prereqs nd_ns # nd_ra -nd_ra{eth.src = 12:34:56:78:9a:bc; ip6.src = fdad:1234:5678::1; outport = inport; flags.loopback = 1; output;}; +nd_ra { eth.src = 12:34:56:78:9a:bc; ip6.src = fdad:1234:5678::1; outport = inport; flags.loopback = 1; output;}; formats as nd_ra { eth.src = 12:34:56:78:9a:bc; ip6.src = fdad:1234:5678::1; outport = inport; flags.loopback = 1; output; }; - encodes as controller(userdata=00.00.00.06.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.18.80.00.34.10.fd.ad.12.34.56.78.00.00.00.00.00.00.00.00.00.01.ff.ff.00.18.00.00.23.20.00.06.00.20.00.00.00.00.00.01.1c.04.00.01.1e.04.ff.ff.00.18.00.00.23.20.00.07.00.00.00.01.14.04.00.00.00.00.00.00.00.01.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00) + encodes as controller(userdata=00.00.00.06.00.00.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.18.80.00.34.10.fd.ad.12.34.56.78.00.00.00.00.00.00.00.00.00.01.ff.ff.00.18.00.00.23.20.00.06.00.20.00.00.00.00.00.01.1c.04.00.01.1e.04.ff.ff.00.18.00.00.23.20.00.07.00.00.00.01.14.04.00.00.00.00.00.00.00.01.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00) + has prereqs nd_rs +nd_ra { put_nd_ra(64,0,10800,0,0);}; + formats as nd_ra { put_nd_ra(64, 0, 10800, 0, 0); }; + encodes as controller(userdata=00.00.00.06.00.00.00.00.00.0d.07.40.00.2a.30.00.00.00.00.00.00.00.00) + has prereqs nd_rs +nd_ra { put_nd_opt_sll(12:34:56:78:9a:bc); put_nd_opt_mtu(1280); put_nd_opt_prefix(64,0,10800,10800,fdad:1234:5678::);}; + formats as nd_ra { put_nd_opt_sll(12:34:56:78:9a:bc); put_nd_opt_mtu(1280); put_nd_opt_prefix(64, 0, 10800, 10800, fdad:1234:5678::); }; + encodes as controller(userdata=00.00.00.06.00.00.00.00.00.27.08.12.34.56.78.9a.bc.09.00.00.05.00.0a.40.00.00.00.2a.30.00.00.2a.30.fd.ad.12.34.56.78.00.00.00.00.00.00.00.00.00.00) + has prereqs nd_rs +nd_ra { put_nd_ra(64,0,10800,0,0); put_nd_opt_sll(12:34:56:78:9a:bc); put_nd_opt_mtu(1280); put_nd_opt_prefix(64,0,10800,10800,fdad:1234:5678::); eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; /* Allow sending out inport. */ output; }; + formats as nd_ra { put_nd_ra(64, 0, 10800, 0, 0); put_nd_opt_sll(12:34:56:78:9a:bc); put_nd_opt_mtu(1280); put_nd_opt_prefix(64, 0, 10800, 10800, fdad:1234:5678::); eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; output; }; + encodes as controller(userdata=00.00.00.06.00.00.00.00.00.34.07.40.00.2a.30.00.00.00.00.00.00.00.00.08.12.34.56.78.9a.bc.09.00.00.05.00.0a.40.00.00.00.2a.30.00.00.2a.30.fd.ad.12.34.56.78.00.00.00.00.00.00.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.ff.ff.00.18.00.00.23.20.00.06.00.20.00.00.00.00.00.01.1c.04.00.01.1e.04.00.19.00.10.00.01.1c.04.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00) has prereqs nd_rs # get_nd -- 1.9.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev