[ovs-dev] [RFC 2/3] OVN: introduce send_event() action

Numan Siddique nusiddiq at redhat.com
Tue May 21 07:40:13 UTC 2019


On Thu, May 16, 2019 at 9:45 PM Lorenzo Bianconi <
lorenzo.bianconi at redhat.com> wrote:

> Add send_event() ovn action in order to allow ovs-vswitchd to report
> CMS related events.
> This commit introduces a new event, empty_lb_backends. This event is
> raised if a received packet is destined for a load balancer VIP that has
> no configured backend destinations. For this event, the event info
> includes the load balancer VIP, the load balancer UUID, and the
> transport protocol.
> The use case for this particular event is for the CMS to supply backend
> resources to handle this traffic. For example, in Openshift, this event
> can be used to spin up new containers to handle the incoming traffic.
>
> Signed-off-by: Mark Michelson <mmichels at redhat.com>
> Co-authored-by: Mark Michelson <mmichels at redhat.com>
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi at redhat.com>
>

Hi Lorenzo,

Overall this series looks good to me. I haven't done any code review yet.

I have few initial comments.

How about renaming the action - "send_event" to "trigger_event"  ? Just a
suggestion.

The action send_event takes the event_type as an integer. I would suggest
to take a string value instead.
something like -  send_event(event = "lb_no_backends",  vip = "10.0.0.1:80
<http://10.0.0.1/>", protocol...)

Thanks
Numan


---
>  include/ovn/actions.h     |  17 +++-
>  ovn/controller/lflow.c    |   8 ++
>  ovn/controller/pinctrl.c  | 109 ++++++++++++++++++++++++
>  ovn/lib/actions.c         | 169 ++++++++++++++++++++++++++++++++++++++
>  ovn/lib/ovn-l7.h          |  46 +++++++++++
>  ovn/utilities/ovn-trace.c |   3 +
>  tests/ovn.at              |  10 +++
>  tests/test-ovn.c          |  11 ++-
>  8 files changed, 370 insertions(+), 3 deletions(-)
>
> diff --git a/include/ovn/actions.h b/include/ovn/actions.h
> index e07ad9aa3..0d5920023 100644
> --- a/include/ovn/actions.h
> +++ b/include/ovn/actions.h
> @@ -83,7 +83,8 @@ struct ovn_extend_table;
>      OVNACT(ND_NS,             ovnact_nest)            \
>      OVNACT(SET_METER,         ovnact_set_meter)       \
>      OVNACT(OVNFIELD_LOAD,     ovnact_load)            \
> -    OVNACT(CHECK_PKT_LARGER,  ovnact_check_pkt_larger)
> +    OVNACT(CHECK_PKT_LARGER,  ovnact_check_pkt_larger) \
> +    OVNACT(SEND_EVENT,        ovnact_controller_event)
>
>  /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
>  enum OVS_PACKED_ENUM ovnact_type {
> @@ -318,6 +319,14 @@ struct ovnact_check_pkt_larger {
>      struct expr_field dst;      /* 1-bit destination field. */
>  };
>
> +/* OVNACT_EVENT. */
> +struct ovnact_controller_event {
> +    struct ovnact ovnact;
> +    int event_type;   /* controller event type */
> +    struct ovnact_gen_option *options;
> +    size_t n_options;
> +};
> +
>  /* 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);
> @@ -486,6 +495,9 @@ enum action_opcode {
>       * The actions, in OpenFlow 1.3 format, follow the action_header.
>       */
>      ACTION_OPCODE_ICMP4_ERROR,
> +
> +    /* "send_event (event_type)" */
> +    ACTION_OPCODE_EVENT,
>  };
>
>  /* Header. */
> @@ -515,6 +527,9 @@ struct ovnact_parse_params {
>      /* hmap of 'struct gen_opts_map' to support 'put_nd_ra_opts' action */
>      const struct hmap *nd_ra_opts;
>
> +    /* Array of hmap of 'struct gen_opts_map' to support 'send_event'
> action */
> +    const struct controller_event_options *controller_event_opts;
> +
>      /* Each OVN flow exists in a logical table within a logical pipeline.
>       * These parameters express this context for a set of OVN actions
> being
>       * parsed:
> diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
> index 661407bcc..8d7f51204 100644
> --- a/ovn/controller/lflow.c
> +++ b/ovn/controller/lflow.c
> @@ -70,6 +70,7 @@ static void consider_logical_flow(
>      struct hmap *dhcp_opts,
>      struct hmap *dhcpv6_opts,
>      struct hmap *nd_ra_opts,
> +    struct controller_event_options *controller_event_opts,
>      const struct shash *addr_sets,
>      const struct shash *port_groups,
>      const struct sset *active_tunnels,
> @@ -173,11 +174,15 @@ add_logical_flows(
>      struct hmap nd_ra_opts = HMAP_INITIALIZER(&nd_ra_opts);
>      nd_ra_opts_init(&nd_ra_opts);
>
> +    struct controller_event_options controller_event_opts;
> +    controller_event_opts_init(&controller_event_opts);
> +
>      SBREC_LOGICAL_FLOW_TABLE_FOR_EACH (lflow, logical_flow_table) {
>          consider_logical_flow(sbrec_multicast_group_by_name_datapath,
>                                sbrec_port_binding_by_name,
>                                lflow, local_datapaths,
>                                chassis, &dhcp_opts, &dhcpv6_opts,
> &nd_ra_opts,
> +                              &controller_event_opts,
>                                addr_sets, port_groups, active_tunnels,
>                                local_lport_ids, &conj_id_ofs,
>                                flow_table, group_table, meter_table);
> @@ -186,6 +191,7 @@ add_logical_flows(
>      dhcp_opts_destroy(&dhcp_opts);
>      dhcp_opts_destroy(&dhcpv6_opts);
>      nd_ra_opts_destroy(&nd_ra_opts);
> +    controller_event_opts_destroy(&controller_event_opts);
>  }
>
>  static void
> @@ -198,6 +204,7 @@ consider_logical_flow(
>      struct hmap *dhcp_opts,
>      struct hmap *dhcpv6_opts,
>      struct hmap *nd_ra_opts,
> +    struct controller_event_options *controller_event_opts,
>      const struct shash *addr_sets,
>      const struct shash *port_groups,
>      const struct sset *active_tunnels,
> @@ -237,6 +244,7 @@ consider_logical_flow(
>          .dhcp_opts = dhcp_opts,
>          .dhcpv6_opts = dhcpv6_opts,
>          .nd_ra_opts = nd_ra_opts,
> +        .controller_event_opts = controller_event_opts,
>
>          .pipeline = ingress ? OVNACT_P_INGRESS : OVNACT_P_EGRESS,
>          .n_tables = LOG_PIPELINE_LEN,
> diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
> index ca191d961..6cc98c617 100644
> --- a/ovn/controller/pinctrl.c
> +++ b/ovn/controller/pinctrl.c
> @@ -208,6 +208,10 @@ static void pinctrl_handle_put_icmp4_frag_mtu(struct
> rconn *swconn,
>                                                struct ofputil_packet_in
> *pin,
>                                                struct ofpbuf *userdata,
>                                                struct ofpbuf
> *continuation);
> +static void
> +pinctrl_handle_event(struct ofpbuf *userdata)
> +    OVS_REQUIRES(pinctrl_mutex);
> +static void wait_controller_event(struct ovsdb_idl_txn *ovnsb_idl_txn);
>  static void init_ipv6_ras(void);
>  static void destroy_ipv6_ras(void);
>  static void ipv6_ra_wait(long long int send_ipv6_ra_time);
> @@ -1870,6 +1874,12 @@ process_packet_in(struct rconn *swconn, const
> struct ofp_header *msg)
>                                            &pin, &userdata, &continuation);
>          break;
>
> +    case ACTION_OPCODE_EVENT:
> +        ovs_mutex_lock(&pinctrl_mutex);
> +        pinctrl_handle_event(&userdata);
> +        ovs_mutex_unlock(&pinctrl_mutex);
> +        break;
> +
>      default:
>          VLOG_WARN_RL(&rl, "unrecognized packet-in opcode %"PRIu32,
>                       ntohl(ah->opcode));
> @@ -2378,6 +2388,7 @@ void
>  pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn)
>  {
>      wait_put_mac_bindings(ovnsb_idl_txn);
> +    wait_controller_event(ovnsb_idl_txn);
>      int64_t new_seq = seq_read(pinctrl_main_seq);
>      seq_wait(pinctrl_main_seq, new_seq);
>  }
> @@ -3417,3 +3428,101 @@ exit:
>          dp_packet_delete(pkt_out);
>      }
>  }
> +
> +static void
> +wait_controller_event(struct ovsdb_idl_txn *ovnsb_idl_txn)
> +{
> +    if (!ovnsb_idl_txn) {
> +        return;
> +    }
> +
> +    for (size_t i = 0; i < OVN_EVENT_MAX; i++) {
> +        if (!hmap_is_empty(&event_table[i])) {
> +            poll_immediate_wake();
> +            break;
> +        }
> +    }
> +}
> +
> +static bool
> +pinctrl_handle_empty_lb_backends_opts(struct ofpbuf *userdata)
> +{
> +    struct controller_event_opt_header *userdata_opt;
> +    uint32_t hash = 0;
> +    char *vip = NULL;
> +    char *protocol = NULL;
> +    char *load_balancer = NULL;
> +
> +    while (userdata->size) {
> +        userdata_opt = ofpbuf_try_pull(userdata, sizeof *userdata_opt);
> +        if (!userdata_opt) {
> +            return false;
> +        }
> +        size_t size = ntohs(userdata_opt->size);
> +        char *userdata_opt_data = ofpbuf_try_pull(userdata, size);
> +        if (!userdata_opt_data) {
> +            return false;
> +        }
> +        switch (ntohs(userdata_opt->opt_code)) {
> +        case EMPTY_LB_VIP:
> +            vip = xmemdup0(userdata_opt_data, size);
> +            break;
> +        case EMPTY_LB_PROTOCOL:
> +            protocol = xmemdup0(userdata_opt_data, size);
> +            break;
> +        case EMPTY_LB_LOAD_BALANCER:
> +            load_balancer = xmemdup0(userdata_opt_data, size);
> +            break;
> +        default:
> +            OVS_NOT_REACHED();
> +        }
> +        hash = hash_bytes(userdata_opt_data, size, hash);
> +    }
> +    ovs_assert(vip && protocol && load_balancer);
> +
> +    struct empty_lb_backends_event *event;
> +
> +    event = pinctrl_find_empty_lb_backends_event(vip, protocol,
> +                                                 load_balancer, hash);
> +    if (!event) {
> +        if (hmap_count(&event_table[OVN_EVENT_EMPTY_LB_BACKENDS]) >=
> 1000) {
> +            COVERAGE_INC(pinctrl_drop_controller_event);
> +            return false;
> +        }
> +
> +        event = xzalloc(sizeof *event);
> +        hmap_insert(&event_table[OVN_EVENT_EMPTY_LB_BACKENDS],
> +                    &event->hmap_node, hash);
> +        event->vip = vip;
> +        event->protocol = protocol;
> +        event->load_balancer = load_balancer;
> +        notify_pinctrl_main();
> +    } else {
> +        free(vip);
> +        free(protocol);
> +        free(load_balancer);
> +    }
> +    return true;
> +}
> +
> +static void
> +pinctrl_handle_event(struct ofpbuf *userdata)
> +    OVS_REQUIRES(pinctrl_mutex)
> +{
> +    ovs_be32 *pevent;
> +
> +    pevent = ofpbuf_try_pull(userdata, sizeof *pevent);
> +    if (!pevent) {
> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> +        VLOG_WARN_RL(&rl, "event not present in the userdata");
> +        return;
> +    }
> +
> +    switch (ntohl(*pevent)) {
> +    case OVN_EVENT_EMPTY_LB_BACKENDS:
> +        pinctrl_handle_empty_lb_backends_opts(userdata);
> +        break;
> +    default:
> +        return;
> +    }
> +}
> diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
> index d5909911d..1603b5d57 100644
> --- a/ovn/lib/actions.c
> +++ b/ovn/lib/actions.c
> @@ -38,6 +38,8 @@
>  #include "packets.h"
>  #include "openvswitch/shash.h"
>  #include "simap.h"
> +#include "uuid.h"
> +#include "socket-util.h"
>
>  VLOG_DEFINE_THIS_MODULE(actions);
>
> @@ -1258,6 +1260,20 @@ format_CLONE(const struct ovnact_nest *nest, struct
> ds *s)
>      format_nested_action(nest, "clone", s);
>  }
>
> +static void
> +format_SEND_EVENT(const struct ovnact_controller_event *event,
> +                  struct ds *s)
> +{
> +    ds_put_format(s, "send_event(event = %d", event->event_type);
> +    for (const struct ovnact_gen_option *o = event->options;
> +         o < &event->options[event->n_options]; o++) {
> +        ds_put_cstr(s, ", ");
> +        ds_put_format(s, "%s = ", o->option->name);
> +        expr_constant_set_format(&o->value, s);
> +    }
> +    ds_put_cstr(s, ");");
> +}
> +
>  static void
>  encode_nested_actions(const struct ovnact_nest *on,
>                        const struct ovnact_encode_params *ep,
> @@ -1361,6 +1377,52 @@ encode_CLONE(const struct ovnact_nest *on,
>      ofpact_finish_CLONE(ofpacts, &clone);
>  }
>
> +static void
> +encode_event_empty_lb_backends_opts(struct ofpbuf *ofpacts,
> +        const struct ovnact_controller_event *event)
> +{
> +    for (const struct ovnact_gen_option *o = event->options;
> +         o < &event->options[event->n_options]; o++) {
> +        struct controller_event_opt_header *hdr =
> +            ofpbuf_put_uninit(ofpacts, sizeof *hdr);
> +        const union expr_constant *c = o->value.values;
> +        size_t size;
> +        hdr->opt_code = htons(o->option->code);
> +        if (!strcmp(o->option->type, "str")) {
> +            size = strlen(c->string);
> +            hdr->size = htons(size);
> +            ofpbuf_put(ofpacts, c->string, size);
> +        } else {
> +            /* All empty_lb_backends fields are of type 'str' */
> +            OVS_NOT_REACHED();
> +        }
> +    }
> +}
> +
> +static void
> +encode_SEND_EVENT(const struct ovnact_controller_event *event,
> +                  const struct ovnact_encode_params *ep OVS_UNUSED,
> +                  struct ofpbuf *ofpacts)
> +{
> +    size_t oc_offset;
> +
> +    oc_offset = encode_start_controller_op(ACTION_OPCODE_EVENT, false,
> +                                           NX_CTLR_NO_METER, ofpacts);
> +    ovs_be32 ofs = htonl(event->event_type);
> +    ofpbuf_put(ofpacts, &ofs, sizeof ofs);
> +
> +    switch (event->event_type) {
> +    case OVN_EVENT_EMPTY_LB_BACKENDS:
> +        encode_event_empty_lb_backends_opts(ofpacts, event);
> +        break;
> +    case OVN_EVENT_MAX:
> +    default:
> +        OVS_NOT_REACHED();
> +    }
> +
> +    encode_finish_controller_op(oc_offset, ofpacts);
> +}
> +
>  static void
>  ovnact_nest_free(struct ovnact_nest *on)
>  {
> @@ -1575,6 +1637,111 @@ free_gen_options(struct ovnact_gen_option
> *options, size_t n)
>      free(options);
>  }
>
> +static void
> +validate_empty_lb_backends(struct action_context *ctx,
> +                           const struct ovnact_gen_option *options,
> +                           size_t n_options)
> +{
> +    for (const struct ovnact_gen_option *o = options;
> +         o < &options[n_options]; o++) {
> +        const union expr_constant *c = o->value.values;
> +        struct sockaddr_storage ss;
> +        struct uuid uuid;
> +
> +        if (o->value.n_values > 1 || !c->string) {
> +            lexer_error(ctx->lexer, "Invalid value for \"%s\" option",
> +                        o->option->name);
> +            return;
> +        }
> +
> +        switch (o->option->code) {
> +        case EMPTY_LB_VIP:
> +            if (!inet_parse_active(c->string, 0, &ss, false)) {
> +                lexer_error(ctx->lexer, "Invalid load balancer VIP '%s'",
> +                            c->string);
> +                return;
> +            }
> +            break;
> +        case EMPTY_LB_PROTOCOL:
> +            if (strcmp(c->string, "tcp") && strcmp(c->string, "udp")) {
> +                lexer_error(ctx->lexer,
> +                    "Load balancer protocol '%s' is not 'tcp' or 'udp'",
> +                    c->string);
> +                return;
> +            }
> +            break;
> +        case EMPTY_LB_LOAD_BALANCER:
> +            if (!uuid_from_string(&uuid, c->string)) {
> +                lexer_error(ctx->lexer, "Load balancer '%s' is not a
> UUID",
> +                            c->string);
> +                return;
> +            }
> +            break;
> +        }
> +    }
> +}
> +
> +static void
> +parse_send_event(struct action_context *ctx,
> +                 struct ovnact_controller_event *event)
> +{
> +    int event_type = 0;
> +
> +    lexer_force_match(ctx->lexer, LEX_T_LPAREN);
> +
> +    /* Event type must be listed first */
> +    if (!lexer_match_id(ctx->lexer, "event")) {
> +        lexer_syntax_error(ctx->lexer, "Expecting 'event' option");
> +        return;
> +    }
> +    if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
> +        return;
> +    }
> +    if (!lexer_force_int(ctx->lexer, &event_type)) {
> +        return;
> +    }
> +
> +    if (event_type < 0 || event_type >= OVN_EVENT_MAX) {
> +        lexer_syntax_error(ctx->lexer, "Unknown event '%d'", event_type);
> +        return;
> +    }
> +
> +    event->event_type = event_type;
> +    lexer_match(ctx->lexer, LEX_T_COMMA);
> +
> +    size_t allocated_options = 0;
> +    while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
> +        if (event->n_options >= allocated_options) {
> +            event->options = x2nrealloc(event->options,
> &allocated_options,
> +                                     sizeof *event->options);
> +        }
> +
> +        struct ovnact_gen_option *o = &event->options[event->n_options++];
> +        memset(o, 0, sizeof *o);
> +        parse_gen_opt(ctx, o,
> +
> &ctx->pp->controller_event_opts->event_opts[event_type],
> +                      event_to_string(event_type));
> +        if (ctx->lexer->error) {
> +            return;
> +        }
> +
> +        lexer_match(ctx->lexer, LEX_T_COMMA);
> +    }
> +
> +    switch (event_type) {
> +    case OVN_EVENT_EMPTY_LB_BACKENDS:
> +        validate_empty_lb_backends(ctx, event->options, event->n_options);
> +        break;
> +    default:
> +        OVS_NOT_REACHED();
> +    }
> +}
> +
> +static void
> +ovnact_controller_event_free(struct ovnact_controller_event *event
> 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,
> @@ -2511,6 +2678,8 @@ parse_action(struct action_context *ctx)
>          parse_LOG(ctx);
>      } else if (lexer_match_id(ctx->lexer, "set_meter")) {
>          parse_set_meter_action(ctx);
> +    } else if (lexer_match_id(ctx->lexer, "send_event")) {
> +        parse_send_event(ctx, ovnact_put_SEND_EVENT(ctx->ovnacts));
>      } else {
>          lexer_syntax_error(ctx->lexer, "expecting action");
>      }
> diff --git a/ovn/lib/ovn-l7.h b/ovn/lib/ovn-l7.h
> index c24201ef0..4ff458e90 100644
> --- a/ovn/lib/ovn-l7.h
> +++ b/ovn/lib/ovn-l7.h
> @@ -22,6 +22,7 @@
>  #include <netinet/icmp6.h>
>  #include "openvswitch/hmap.h"
>  #include "hash.h"
> +#include "ovn/logical-fields.h"
>
>  /* Generic options map which is used to store dhcpv4 opts and dhcpv6
> opts. */
>  struct gen_opts_map {
> @@ -272,4 +273,49 @@ nd_ra_opts_init(struct hmap *nd_ra_opts)
>      nd_ra_opt_add(nd_ra_opts, "mtu", ND_OPT_MTU, "uint32");
>  }
>
> +#define EMPTY_LB_VIP           1
> +#define EMPTY_LB_PROTOCOL      2
> +#define EMPTY_LB_LOAD_BALANCER 3
> +
> +/* Used in the OpenFlow PACKET_IN userdata */
> +struct controller_event_opt_header {
> +    ovs_be16 opt_code;
> +    ovs_be16 size;
> +};
> +
> +struct controller_event_options {
> +    struct hmap event_opts[OVN_EVENT_MAX];
> +};
> +
> +static inline void
> +controller_event_opt_add(struct controller_event_options *event_opts,
> +                         enum ovn_controller_event event_type, char
> *opt_name,
> +                         size_t opt_code, char *opt_type)
> +{
> +    gen_opt_add(&event_opts->event_opts[event_type], opt_name, opt_code,
> +                opt_type);
> +}
> +
> +static inline void
> +controller_event_opts_init(struct controller_event_options *opts)
> +{
> +    for (size_t i = 0; i < OVN_EVENT_MAX; i++) {
> +        hmap_init(&opts->event_opts[i]);
> +    }
> +    controller_event_opt_add(opts, OVN_EVENT_EMPTY_LB_BACKENDS, "vip",
> +                             EMPTY_LB_VIP, "str");
> +    controller_event_opt_add(opts, OVN_EVENT_EMPTY_LB_BACKENDS,
> "protocol",
> +                             EMPTY_LB_PROTOCOL, "str");
> +    controller_event_opt_add(opts, OVN_EVENT_EMPTY_LB_BACKENDS,
> +                             "load_balancer", EMPTY_LB_LOAD_BALANCER,
> "str");
> +}
> +
> +static inline void
> +controller_event_opts_destroy(struct controller_event_options *opts)
> +{
> +    for (size_t i = 0; i < OVN_EVENT_MAX; i++) {
> +        gen_opts_destroy(&opts->event_opts[i]);
> +    }
> +}
> +
>  #endif /* OVN_DHCP_H */
> diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c
> index 9718077aa..49c3511de 100644
> --- a/ovn/utilities/ovn-trace.c
> +++ b/ovn/utilities/ovn-trace.c
> @@ -2135,6 +2135,9 @@ trace_actions(const struct ovnact *ovnacts, size_t
> ovnacts_len,
>              execute_ovnfield_load(ovnact_get_OVNFIELD_LOAD(a), super);
>              break;
>
> +        case OVNACT_SEND_EVENT:
> +            break;
> +
>          case OVNACT_CHECK_PKT_LARGER:
>              break;
>          }
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 6499df3d3..1c54dd920 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -1333,6 +1333,16 @@ tcp_reset { };
>      encodes as controller(userdata=00.00.00.0b.00.00.00.00)
>      has prereqs tcp
>
> +# send_event
> +send_event(event = 0, vip = "10.0.0.1:80", protocol = "tcp",
> load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c");
> +    encodes as
> controller(userdata=00.00.00.0f.00.00.00.00.00.00.00.00.00.01.00.0b.31.30.2e.30.2e.30.2e.31.3a.38.30.00.02.00.03.74.63.70.00.03.00.24.31.32.33.34.35.36.37.38.2d.61.62.63.64.2d.39.38.37.36.2d.66.65.64.63.2d.31.31.31.31.39.66.38.65.37.64.36.63)
> +
> +# Testing invalid vip results in extra error messages from socket-util.c
> +send_event(event = 0, vip = "10.0.0.1:80", protocol = "sctp",
> load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c");
> +    Load balancer protocol 'sctp' is not 'tcp' or 'udp'
> +send_event(event = 0, vip = "10.0.0.1:80", protocol = "tcp",
> load_balancer = "bacon");
> +    Load balancer 'bacon' is not a UUID
> +
>  # Contradictionary prerequisites (allowed but not useful):
>  ip4.src = ip6.src[0..31];
>      encodes as move:NXM_NX_IPV6_SRC[0..31]->NXM_OF_IP_SRC[]
> diff --git a/tests/test-ovn.c b/tests/test-ovn.c
> index 7cce9c2ae..619bd3f78 100644
> --- a/tests/test-ovn.c
> +++ b/tests/test-ovn.c
> @@ -157,7 +157,8 @@ create_symtab(struct shash *symtab)
>
>  static void
>  create_gen_opts(struct hmap *dhcp_opts, struct hmap *dhcpv6_opts,
> -                struct hmap *nd_ra_opts)
> +                struct hmap *nd_ra_opts,
> +                struct controller_event_options *event_opts)
>  {
>      hmap_init(dhcp_opts);
>      dhcp_opt_add(dhcp_opts, "offerip", 0, "ipv4");
> @@ -197,6 +198,9 @@ create_gen_opts(struct hmap *dhcp_opts, struct hmap
> *dhcpv6_opts,
>      /* IPv6 ND RA options. */
>      hmap_init(nd_ra_opts);
>      nd_ra_opts_init(nd_ra_opts);
> +
> +    /* OVN controller events options. */
> +    controller_event_opts_init(event_opts);
>  }
>
>  static void
> @@ -1228,12 +1232,13 @@ test_parse_actions(struct ovs_cmdl_context *ctx
> OVS_UNUSED)
>      struct hmap dhcp_opts;
>      struct hmap dhcpv6_opts;
>      struct hmap nd_ra_opts;
> +    struct controller_event_options event_opts;
>      struct simap ports;
>      struct ds input;
>      bool ok = true;
>
>      create_symtab(&symtab);
> -    create_gen_opts(&dhcp_opts, &dhcpv6_opts, &nd_ra_opts);
> +    create_gen_opts(&dhcp_opts, &dhcpv6_opts, &nd_ra_opts, &event_opts);
>
>      /* Initialize group ids. */
>      struct ovn_extend_table group_table;
> @@ -1263,6 +1268,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx
> OVS_UNUSED)
>              .dhcp_opts = &dhcp_opts,
>              .dhcpv6_opts = &dhcpv6_opts,
>              .nd_ra_opts = &nd_ra_opts,
> +            .controller_event_opts = &event_opts,
>              .n_tables = 24,
>              .cur_ltable = 10,
>          };
> @@ -1350,6 +1356,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx
> OVS_UNUSED)
>      dhcp_opts_destroy(&dhcp_opts);
>      dhcp_opts_destroy(&dhcpv6_opts);
>      nd_ra_opts_destroy(&nd_ra_opts);
> +    controller_event_opts_destroy(&event_opts);
>      ovn_extend_table_destroy(&group_table);
>      ovn_extend_table_destroy(&meter_table);
>      exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
> --
> 2.20.1
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>


More information about the dev mailing list