[ovs-dev] [PATCH v8 4/4] ovn: Generate Neighbor Solicitation packet for unknown MAC IPv6 packets

Numan Siddique nusiddiq at redhat.com
Thu Sep 28 10:10:47 UTC 2017


On Thu, Sep 28, 2017 at 2:12 AM, Mark Michelson <mmichels at redhat.com> wrote:

>
>
> On Thu, Sep 21, 2017 at 11:12 AM <nusiddiq at redhat.com> wrote:
>
>> From: Numan Siddique <nusiddiq at redhat.com>
>>
>> In the router ingress pipeline, if the destination mac is unresolved
>> by the time the packet reaches the ARP_REQUEST stage, OVN should generate
>> an
>> IPv6 Neighbor Solicitation packet to learn the MAC address. This feature
>> is
>> presently missing. This patch adds this feature.  A new action "nd_ns" is
>> added  which replaces an IPv6 packet being processed with an IPv6 Neighbor
>> Solicitation packet. ovn-northd adds a flow in the ARP_REQUEST router
>> ingress
>> pipeline stage if the eth.dst is zero which applies this action. This
>> action is
>> similar to the IPv4 counterpart "arp" action.
>>
>> OVN already has the support to learn the MAC from the IPv6 Neighbor
>> Advertisement
>> packets and storing in the south bound MAC_Binding table.
>>
>> Signed-off-by: Numan Siddique <nusiddiq at redhat.com>
>> ---
>>  include/ovn/actions.h       |   9 +++-
>>  ovn/controller/pinctrl.c    | 122 +++++++++++++++++++++++-------
>> --------------
>>  ovn/lib/actions.c           |  22 ++++++++
>>  ovn/northd/ovn-northd.8.xml |  24 ++++++---
>>  ovn/northd/ovn-northd.c     |   8 ++-
>>  ovn/ovn-sb.xml              |  37 ++++++++++++++
>>  ovn/utilities/ovn-trace.c   |  30 +++++++++++
>>  tests/ovn.at                | 116 ++++++++++++++++++++++++++++++
>> +++++++++++
>>  8 files changed, 302 insertions(+), 66 deletions(-)
>>
>> diff --git a/include/ovn/actions.h b/include/ovn/actions.h
>> index 15cee478d..8c7208ffc 100644
>> --- a/include/ovn/actions.h
>> +++ b/include/ovn/actions.h
>> @@ -73,7 +73,8 @@ struct simap;
>>      OVNACT(SET_QUEUE,         ovnact_set_queue)       \
>>      OVNACT(DNS_LOOKUP,        ovnact_dns_lookup)      \
>>      OVNACT(LOG,               ovnact_log)             \
>> -    OVNACT(PUT_ND_RA_OPTS,    ovnact_put_opts)
>> +    OVNACT(PUT_ND_RA_OPTS,    ovnact_put_opts)        \
>> +    OVNACT(ND_NS,             ovnact_nest)
>>
>>  /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
>>  enum OVS_PACKED_ENUM ovnact_type {
>> @@ -427,6 +428,12 @@ enum action_opcode {
>>       *   - Any number of ICMPv6 options.
>>       */
>>      ACTION_OPCODE_PUT_ND_RA_OPTS,
>> +
>> +    /* "nd_ns { ...actions... }".
>> +     *
>> +     * The actions, in OpenFlow 1.3 format, follow the action_header.
>> +     */
>> +    ACTION_OPCODE_ND_NS,
>>  };
>>
>>  /* Header. */
>> diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
>> index 6dbea4efa..cad0f67ba 100644
>> --- a/ovn/controller/pinctrl.c
>> +++ b/ovn/controller/pinctrl.c
>> @@ -85,6 +85,9 @@ static void pinctrl_handle_put_nd_ra_opts(
>>      const struct flow *ip_flow, struct dp_packet *pkt_in,
>>      struct ofputil_packet_in *pin, struct ofpbuf *userdata,
>>      struct ofpbuf *continuation OVS_UNUSED);
>> +static void pinctrl_handle_nd_ns(const struct flow *ip_flow,
>> +                                 const struct match *md,
>> +                                 struct ofpbuf *userdata);
>>
>>  COVERAGE_DEFINE(pinctrl_drop_put_mac_binding);
>>
>> @@ -132,6 +135,43 @@ set_switch_config(struct rconn *swconn,
>>  }
>>
>>  static void
>> +set_actions_and_enqueu_msg(const struct dp_packet *packet,
>>
>
> Nit: The word is spelled "enqueue", not "enqueu". This could potentially
> lead to some confusion if left this way.
>


Thanks Mark for the comments. I will take care of this in the next patch
set. I will wait for a while so that I can incorporate review comments (if
any) from the other patches in this series.



>
>> +                           const struct match *md,
>> +                           struct ofpbuf *userdata)
>> +{
>> +    /* Copy metadata from 'md' into the packet-out via "set_field"
>> +     * actions, then add actions from 'userdata'.
>> +     */
>> +    uint64_t ofpacts_stub[4096 / 8];
>> +    struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
>> +    enum ofp_version version = rconn_get_version(swconn);
>> +
>> +    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));
>> +        ofpbuf_uninit(&ofpacts);
>> +        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(ofputil_encode_packet_out(&po, proto));
>> +    ofpbuf_uninit(&ofpacts);
>> +}
>> +
>> +static void
>>  pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md,
>>                     struct ofpbuf *userdata)
>>  {
>> @@ -166,40 +206,8 @@ pinctrl_handle_arp(const struct flow *ip_flow, const
>> struct match *md,
>>                        ip_flow->vlans[0].tci);
>>      }
>>
>> -    /* Compose actions.
>> -     *
>> -     * First, copy metadata from 'md' into the packet-out via "set_field"
>> -     * actions, then add actions from 'userdata'.
>> -     */
>> -    uint64_t ofpacts_stub[4096 / 8];
>> -    struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
>> -    enum ofp_version version = rconn_get_version(swconn);
>> -
>> -    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 arp actions (%s)",
>> -                     ofperr_to_string(error));
>> -        goto exit;
>> -    }
>> -
>> -    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(ofputil_encode_packet_out(&po, proto));
>> -
>> -exit:
>> +    set_actions_and_enqueu_msg(&packet, md, userdata);
>>      dp_packet_uninit(&packet);
>> -    ofpbuf_uninit(&ofpacts);
>>  }
>>
>>  static void
>> @@ -994,6 +1002,10 @@ process_packet_in(const struct ofp_header *msg,
>> struct controller_ctx *ctx)
>>                                        &continuation);
>>          break;
>>
>> +    case ACTION_OPCODE_ND_NS:
>> +        pinctrl_handle_nd_ns(&headers, &pin.flow_metadata, &userdata);
>> +        break;
>> +
>>      default:
>>          VLOG_WARN_RL(&rl, "unrecognized packet-in opcode %"PRIu32,
>>                       ntohl(ah->opcode));
>> @@ -1812,9 +1824,6 @@ pinctrl_handle_nd_na(const struct flow *ip_flow,
>> const struct match *md,
>>          return;
>>      }
>>
>> -    enum ofp_version version = rconn_get_version(swconn);
>> -    enum ofputil_protocol proto = ofputil_protocol_from_ofp_
>> version(version);
>> -
>>      uint64_t packet_stub[128 / 8];
>>      struct dp_packet packet;
>>      dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
>> @@ -1827,35 +1836,32 @@ pinctrl_handle_nd_na(const struct flow *ip_flow,
>> const struct match *md,
>>                    &ip_flow->nd_target, &ip_flow->ipv6_src,
>>                    htonl(ND_RSO_SOLICITED | ND_RSO_OVERRIDE));
>>
>> -    /* Reload previous packet metadata. */
>> -    uint64_t ofpacts_stub[4096 / 8];
>> -    struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
>> -    reload_metadata(&ofpacts, md);
>> +    /* Reload previous packet metadata and set actions from userdata. */
>> +    set_actions_and_enqueu_msg(&packet, md, userdata);
>> +    dp_packet_uninit(&packet);
>> +}
>>
>> -    enum ofperr error = ofpacts_pull_openflow_actions(userdata,
>> userdata->size,
>> -                                                      version, NULL,
>> NULL,
>> -                                                      &ofpacts);
>> -    if (error) {
>> +static void
>> +pinctrl_handle_nd_ns(const struct flow *ip_flow, const struct match *md,
>> +                     struct ofpbuf *userdata)
>> +{
>> +    /* This action only works for IPv6 packets. */
>> +    if (get_dl_type(ip_flow) != htons(ETH_TYPE_IPV6)) {
>>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>> -        VLOG_WARN_RL(&rl, "failed to parse actions for 'na' (%s)",
>> -                     ofperr_to_string(error));
>> -        goto exit;
>> +        VLOG_WARN_RL(&rl, "NS action on non-IPv6 packet");
>> +        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);
>> +    uint64_t packet_stub[128 / 8];
>> +    struct dp_packet packet;
>> +    dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
>>
>> -    queue_msg(ofputil_encode_packet_out(&po, proto));
>> +    compose_nd_ns(&packet, ip_flow->dl_src, &ip_flow->ipv6_src,
>> +                  &ip_flow->ipv6_dst);
>>
>> -exit:
>> +    /* Reload previous packet metadata and set actions from userdata. */
>> +    set_actions_and_enqueu_msg(&packet, md, userdata);
>>      dp_packet_uninit(&packet);
>> -    ofpbuf_uninit(&ofpacts);
>>  }
>>
>>  static void
>> diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
>> index 2981d89f6..5e5c666a9 100644
>> --- a/ovn/lib/actions.c
>> +++ b/ovn/lib/actions.c
>> @@ -1134,6 +1134,12 @@ parse_ND_NA(struct action_context *ctx)
>>  }
>>
>>  static void
>> +parse_ND_NS(struct action_context *ctx)
>> +{
>> +    parse_nested_action(ctx, OVNACT_ND_NS, "ip6");
>> +}
>> +
>> +static void
>>  parse_CLONE(struct action_context *ctx)
>>  {
>>      parse_nested_action(ctx, OVNACT_CLONE, NULL);
>> @@ -1161,6 +1167,12 @@ format_ND_NA(const struct ovnact_nest *nest,
>> struct ds *s)
>>  }
>>
>>  static void
>> +format_ND_NS(const struct ovnact_nest *nest, struct ds *s)
>> +{
>> +    format_nested_action(nest, "nd_ns", s);
>> +}
>> +
>> +static void
>>  format_CLONE(const struct ovnact_nest *nest, struct ds *s)
>>  {
>>      format_nested_action(nest, "clone", s);
>> @@ -1207,6 +1219,14 @@ encode_ND_NA(const struct ovnact_nest *on,
>>  }
>>
>>  static void
>> +encode_ND_NS(const struct ovnact_nest *on,
>> +             const struct ovnact_encode_params *ep,
>> +             struct ofpbuf *ofpacts)
>> +{
>> +    encode_nested_neighbor_actions(on, ep, ACTION_OPCODE_ND_NS,
>> ofpacts);
>> +}
>> +
>> +static void
>>  encode_CLONE(const struct ovnact_nest *on,
>>               const struct ovnact_encode_params *ep,
>>               struct ofpbuf *ofpacts)
>> @@ -2146,6 +2166,8 @@ parse_action(struct action_context *ctx)
>>          parse_ARP(ctx);
>>      } else if (lexer_match_id(ctx->lexer, "nd_na")) {
>>          parse_ND_NA(ctx);
>> +    } else if (lexer_match_id(ctx->lexer, "nd_ns")) {
>> +        parse_ND_NS(ctx);
>>      } 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")) {
>> diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml
>> index a994abf78..17123c690 100644
>> --- a/ovn/northd/ovn-northd.8.xml
>> +++ b/ovn/northd/ovn-northd.8.xml
>> @@ -1915,15 +1915,15 @@ next;
>>
>>      <p>
>>        In the common case where the Ethernet destination has been
>> resolved, this
>> -      table outputs the packet.  Otherwise, it composes and sends an ARP
>> -      request.  It holds the following flows:
>> +      table outputs the packet.  Otherwise, it composes and sends an ARP
>> or
>> +      IPv6 Neighbor Solicitation request.  It holds the following flows:
>>      </p>
>>
>>      <ul>
>>        <li>
>>          <p>
>> -          Unknown MAC address.  A priority-100 flow with match
>> <code>eth.dst ==
>> -          00:00:00:00:00:00</code> has the following actions:
>> +          Unknown MAC address.  A priority-100 flow for IPv4 packets
>> with match
>> +          <code>eth.dst == 00:00:00:00:00:00</code> has the following
>> actions:
>>          </p>
>>
>>          <pre>
>> @@ -1937,13 +1937,25 @@ arp {
>>          </pre>
>>
>>          <p>
>> +          Unknown MAC address.  A priority-100 flow for IPv6 packets
>> with match
>> +          <code>eth.dst == 00:00:00:00:00:00</code> has the following
>> actions:
>> +        </p>
>> +
>> +        <pre>
>> +nd_ns {
>> +    nd.target = xxreg0;
>> +    output;
>> +};
>> +        </pre>
>> +
>> +        <p>
>>            (Ingress table <code>IP Routing</code> initialized
>> <code>reg1</code>
>>            with the IP address owned by <code>outport</code> and
>> -          <code>reg0</code> with the next-hop IP address)
>> +          <code>(xx)reg0</code> with the next-hop IP address)
>>          </p>
>>
>>          <p>
>> -          The IP packet that triggers the ARP request is dropped.
>> +          The IP packet that triggers the ARP/IPv6 NS request is dropped.
>>          </p>
>>        </li>
>>
>> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
>> index 3da20d25b..b4ea34bc6 100644
>> --- a/ovn/northd/ovn-northd.c
>> +++ b/ovn/northd/ovn-northd.c
>> @@ -5703,7 +5703,7 @@ build_lrouter_flows(struct hmap *datapaths, struct
>> hmap *ports,
>>       *
>>       * In the common case where the Ethernet destination has been
>> resolved,
>>       * this table outputs the packet (priority 0).  Otherwise, it
>> composes
>> -     * and sends an ARP request (priority 100). */
>> +     * and sends an ARP/IPv6 NA request (priority 100). */
>>      HMAP_FOR_EACH (od, key_node, datapaths) {
>>          if (!od->nbr) {
>>              continue;
>> @@ -5718,6 +5718,12 @@ build_lrouter_flows(struct hmap *datapaths, struct
>> hmap *ports,
>>                        "arp.op = 1; " /* ARP request */
>>                        "output; "
>>                        "};");
>> +        ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
>> +                      "eth.dst == 00:00:00:00:00:00",
>> +                      "nd_ns { "
>> +                      "nd.target = xxreg0; "
>> +                      "output; "
>> +                      "};");
>>          ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1",
>> "output;");
>>      }
>>
>> diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
>> index 2e4f28b96..ca8cbecdd 100644
>> --- a/ovn/ovn-sb.xml
>> +++ b/ovn/ovn-sb.xml
>> @@ -1258,6 +1258,43 @@
>>            <p><b>Example:</b> <code>put_arp(inport, arp.spa,
>> arp.sha);</code></p>
>>          </dd>
>>
>> +        <dt><code>nd_ns { <var>action</var>; </code>...<code>
>> };</code></dt>
>> +        <dd>
>> +          <p>
>> +            Temporarily replaces the IPv6 packet being processed by an
>> IPv6
>> +            Neighbor Solicitation packet and executes each nested
>> +            <var>action</var> on the IPv6 NS packet.  Actions following
>> the
>> +            <var>nd_ns</var> action, if any, apply to the original,
>> unmodified
>> +            packet.
>> +          </p>
>> +
>> +          <p>
>> +            The IPv6 NS packet that this action operates on is
>> initialized
>> +            based on the IPv6 packet being processed, as follows.  These
>> are
>> +            default values that the nested actions will probably want to
>> +            change:
>> +          </p>
>> +
>> +          <ul>
>> +            <li><code>eth.src</code> unchanged</li>
>> +            <li><code>eth.dst</code> set to IPv6 multicast MAC
>> address</li>
>> +            <li><code>eth.type = 0x86dd</code></li>
>> +            <li><code>ip6.src</code> copied from
>> <code>ip6.src</code></li>
>> +            <li>
>> +              <code>ip6.dst</code> set to IPv6 Solicited-Node multicast
>> address
>> +            </li>
>> +            <li><code>icmp6.type = 135</code> (Neighbor
>> Solicitation)</li>
>> +            <li><code>nd.target</code> copied from
>> <code>ip6.dst</code></li>
>> +          </ul>
>> +
>> +          <p>
>> +            The IPv6 NS packet has the same VLAN header, if any, as the
>> IP
>> +            packet it replaces.
>> +          </p>
>> +
>> +          <p><b>Prerequisite:</b> <code>ip6</code></p>
>> +        </dd>
>> +
>>          <dt>
>>            <code>nd_na { <var>action</var>; </code>...<code> };</code>
>>          </dt>
>> diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c
>> index 211148b8b..e457284fc 100644
>> --- a/ovn/utilities/ovn-trace.c
>> +++ b/ovn/utilities/ovn-trace.c
>> @@ -1510,6 +1510,31 @@ execute_nd_na(const struct ovnact_nest *on, const
>> struct ovntrace_datapath *dp,
>>  }
>>
>>  static void
>> +execute_nd_ns(const struct ovnact_nest *on, const struct
>> ovntrace_datapath *dp,
>> +              const struct flow *uflow, uint8_t table_id,
>> +              enum ovnact_pipeline pipeline, struct ovs_list *super)
>> +{
>> +    struct flow na_flow = *uflow;
>> +
>> +    /* Update fields for NA. */
>> +    na_flow.dl_src = uflow->dl_src;
>> +    na_flow.ipv6_src = uflow->ipv6_src;
>> +    na_flow.ipv6_dst = uflow->ipv6_dst;
>> +    struct in6_addr sn_addr;
>> +    in6_addr_solicited_node(&sn_addr, &uflow->ipv6_dst);
>> +    ipv6_multicast_to_ethernet(&na_flow.dl_dst, &sn_addr);
>> +    na_flow.tp_src = htons(135);
>> +    na_flow.arp_sha = eth_addr_zero;
>> +    na_flow.arp_tha = uflow->dl_dst;
>> +
>> +    struct ovntrace_node *node = ovntrace_node_append(
>> +        super, OVNTRACE_NODE_TRANSFORMATION, "nd_ns");
>> +
>> +    trace_actions(on->nested, on->nested_len, dp, &na_flow,
>> +                  table_id, pipeline, &node->subs);
>> +}
>> +
>> +static void
>>  execute_get_mac_bind(const struct ovnact_get_mac_bind *bind,
>>                       const struct ovntrace_datapath *dp,
>>                       struct flow *uflow, struct ovs_list *super)
>> @@ -1811,6 +1836,11 @@ trace_actions(const struct ovnact *ovnacts, size_t
>> ovnacts_len,
>>                            super);
>>              break;
>>
>> +        case OVNACT_ND_NS:
>> +            execute_nd_ns(ovnact_get_ND_NS(a), dp, uflow, table_id,
>> pipeline,
>> +                          super);
>> +            break;
>> +
>>          case OVNACT_GET_ARP:
>>              execute_get_mac_bind(ovnact_get_GET_ARP(a), dp, uflow,
>> super);
>>              break;
>> diff --git a/tests/ovn.at b/tests/ovn.at
>> index 3aa4e5e22..13cdc1679 100644
>> --- a/tests/ovn.at
>> +++ b/tests/ovn.at
>> @@ -993,6 +993,16 @@ reg1[0] = put_dhcp_opts(offerip="xyzzy");
>>  reg1[0] = put_dhcp_opts(offerip=1.2.3.4, domain=1.2.3.4);
>>      DHCPv4 option domain requires string value.
>>
>> +# nd_ns
>> +nd_ns { nd.target = xxreg0; output; };
>> +    encodes as controller(userdata=00.00.00.
>> 09.00.00.00.00.ff.ff.00.18.00.00.23.20.00.06.00.80.00.00.00.
>> 00.00.01.de.10.00.01.2e.10.ff.ff.00.10.00.00.23.20.00.0e.ff.
>> f8.40.00.00.00)
>> +    has prereqs ip6
>> +
>> +nd_ns { };
>> +    formats as nd_ns { drop; };
>> +    encodes as controller(userdata=00.00.00.09.00.00.00.00)
>> +    has prereqs ip6
>> +
>>  # nd_na
>>  nd_na { 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_na { eth.src = 12:34:56:78:9a:bc; nd.tll =
>> 12:34:56:78:9a:bc; outport = inport; inport = ""; output; };
>> @@ -8795,6 +8805,112 @@ OVN_CLEANUP([gw1],[gw2],[hv1])
>>
>>  AT_CLEANUP
>>
>> +AT_SETUP([ovn -- IPv6 Neighbor Solicitation for unknown MAC])
>> +AT_KEYWORDS([ovn-nd_ns for unknown mac])
>> +AT_SKIP_IF([test $HAVE_PYTHON = no])
>> +ovn_start
>> +
>> +ovn-nbctl ls-add sw0_ip6
>> +ovn-nbctl lsp-add sw0_ip6 sw0_ip6-port1
>> +ovn-nbctl lsp-set-addresses sw0_ip6-port1 \
>> +"50:64:00:00:00:02 aef0::5264:00ff:fe00:0002"
>> +
>> +ovn-nbctl lsp-set-port-security sw0_ip6-port1 \
>> +"50:64:00:00:00:02 aef0::5264:00ff:fe00:0002"
>> +
>> +ovn-nbctl lr-add lr0_ip6
>> +ovn-nbctl lrp-add lr0_ip6 lrp0_ip6 00:00:00:00:af:01 aef0::/64
>> +ovn-nbctl lsp-add sw0_ip6 lrp0_ip6-attachment
>> +ovn-nbctl lsp-set-type lrp0_ip6-attachment router
>> +ovn-nbctl lsp-set-addresses lrp0_ip6-attachment 00:00:00:00:af:01
>> +ovn-nbctl lsp-set-options lrp0_ip6-attachment router-port=lrp0_ip6
>> +ovn-nbctl set logical_router_port lrp0_ip6 ipv6_ra_configs:address_mode=
>> slaac
>> +
>> +ovn-nbctl ls-add public
>> +ovn-nbctl lsp-add public ln-public
>> +ovn-nbctl lsp-set-addresses ln-public unknown
>> +ovn-nbctl lsp-set-type ln-public localnet
>> +ovn-nbctl lsp-set-options ln-public network_name=phys
>> +
>> +ovn-nbctl lrp-add lr0_ip6 ip6_public 00:00:02:01:02:04 \
>> +2001:db8:1:0:200:02ff:fe01:0204/64 \
>> +-- set Logical_Router_port ip6_public options:redirect-chassis="hv1"
>> +
>> +
>> +ovn-nbctl lsp-add public rp-ip6_public -- set Logical_Switch_Port \
>> +rp-ip6_public  type=router options:router-port=ip6_public \
>> +-- lsp-set-addresses rp-ip6_public router
>> +
>> +net_add n1
>> +sim_add hv1
>> +as hv1
>> +ovs-vsctl add-br br-phys
>> +ovn_attach n1 br-phys 192.168.0.2
>> +
>> +ovs-vsctl -- add-port br-int hv1-vif1 -- \
>> +    set interface hv1-vif1 external-ids:iface-id=sw0_ip6-port1 \
>> +    options:tx_pcap=hv1/vif1-tx.pcap \
>> +    options:rxq_pcap=hv1/vif1-rx.pcap \
>> +    ofport-request=1
>> +ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
>> +
>> +# Allow some time for ovn-northd and ovn-controller to catch up.
>> +# XXX This should be more systematic.
>> +sleep 1
>> +
>> +trim_zeros() {
>> +    sed 's/\(00\)\{1,\}$//'
>> +}
>> +
>> +# Test the IPv6 Neighbor Solicitation (NS) - nd_ns action for unknown MAC
>> +# addresses. ovn-controller should generate an IPv6 NS request for IPv6
>> +# packets whose MAC is unknown (in the ARP_REQUEST router pipeline stage.
>> +# test_ipv6 INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT...
>> +# This function sends ipv6 packet
>> +test_ipv6() {
>> +    local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4
>> +    dst_ip=20010db800010000020002fffe010205
>> +
>> +    local packet=${dst_mac}${src_mac}86dd6000000000083aff${src_ip}$
>> {dst_ip}
>> +    packet=${packet}8000000000000000
>> +    shift; shift; shift; shift
>> +
>> +    dst_mac=3333ff010205
>> +    src_mac=000002010204
>> +    mcast_node_ip=ff0200000000000000000001ff010205
>> +    expected_packet=${dst_mac}${src_mac}86dd6000000000203aff${src_ip}
>> +    expected_packet=${expected_packet}${mcast_node_ip}
>> 8700XXXX00000000${dst_ip}
>> +    expected_packet=${expected_packet}0101${src_mac}
>> +
>> +    as hv1 ovs-appctl netdev-dummy/receive hv1-vif${inport} $packet
>> +    echo $expected_packet >> ipv6_ns.expected
>> +}
>> +
>> +src_mac=506400000002
>> +dst_mac=00000000af01
>> +src_ip=aef0000000000000526400fffe000002
>> +# Send an IPv6 packet. Generated IPv6 Neighbor solicitation packet
>> +# should be received by the ports attached to br-phys.
>> +test_ipv6 1 $src_mac $dst_mac $src_ip 2
>> +
>> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-phys_n1-tx.pcap | \
>> +trim_zeros > 1.packets
>> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-phys-tx.pcap | \
>> +trim_zeros > 2.packets
>> +
>> +cat ipv6_ns.expected | cut -c -112 > expout
>> +AT_CHECK([cat 1.packets | cut -c -112], [0], [expout])
>> +AT_CHECK([cat 2.packets | cut -c -112], [0], [expout])
>> +
>> +# Skipping the ICMPv6 checksum
>> +cat ipv6_ns.expected | cut -c 117- > expout
>> +AT_CHECK([cat 1.packets | cut -c 117-], [0], [expout])
>> +AT_CHECK([cat 2.packets | cut -c 117-], [0], [expout])
>> +
>> +OVN_CLEANUP([hv1])
>> +
>> +AT_CLEANUP
>> +
>>  AT_SETUP([ovn -- options:requested-chassis for logical port])
>>  ovn_start
>>
>> --
>> 2.13.3
>>
>> _______________________________________________
>> dev mailing list
>> dev at openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>
>


More information about the dev mailing list