On Tue, Oct 14, 2025 at 4:48 PM Mark Michelson via dev
<[email protected]> wrote:
>
> By default, northd does not install any responder flows for unicast ARP.
> These are intended to be forwarded to the destination so that the
> destination can respond appropriately. For VIF ports, this tends to work
> as expected in most scenarios.
>
> When proxy ARP is configured on a logical switch port connected to a
> logical router, then we install low priority flows to ensure that
> ARPs for the configured proxy addresses are responded to by the logical
> switch. These proxy ARP flows are hit when unicast ARP requests are sent
> for the VIF ports on the logical switch. We therefore end up responding
> incorrectly to unicast ARP requests with the proxy ARP MAC instead of
> forwarding the ARP request to the proper VIF port.
>
> This commit fixes the issue by installing explicit "next;" actions for
> unicast ARP requests directed towards VIFs so that the proxy ARP flows
> will not be hit. These flows are only installed if proxy ARP is
> configured, since they are unnecessary otherwise.
>
> Reported-at: https://issues.redhat.com/browse/FDP-1646
> Signed-off-by: Mark Michelson <[email protected]>
> ---
> v3:
>  * Split the new build_lswitch_arp_nd_unicast_flows() function into
>    smaller pieces. This has several benefits:
>      * v2 had several checkpatch warnings about the lines exceeding 80
>        characters. This made it easier to stay under the line length
>        limit.
>      * v2 had a subtle indexing error that caused a crash in the
>        proxy_arp test. Splitting this up helps make the indexing easier
>        to follow.
>      * This makes the logic much easier to understand, visually.
>  * Fixed some typos in the commit message.
>
> v2:
>  * This version also fixes the problem with IPv6 ND_NS packets. The
>    tests have been updated to test for IPv6.
>  * This version only installs unicast ARP/ND_NS flows if the LSP
>    address overlaps with the configured proxy_arp addresses. The
>    ovn-northd test has been updated to ensure that this is correct. The
>    code that does this is pretty gnarly, since it's four levels of
>    for loops. But it works!
>  * Fixed nits from Xavier (removed ofport request, removed unnecessary
>    lflow-list, etc.).
> ---
>
>  northd/northd.c     | 132 +++++++++++++++++++++++++++++++++++++++-----
>  northd/northd.h     |   7 +++
>  tests/ovn-northd.at |  93 +++++++++++++++++++++++++++++++
>  tests/ovn.at        |  76 +++++++++++++++++++++++++
>  4 files changed, 294 insertions(+), 14 deletions(-)
>
> diff --git a/northd/northd.c b/northd/northd.c
> index 3b1d3eba7..9eaa88d95 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -557,6 +557,7 @@ ovn_datapath_create(struct hmap *datapaths, const struct 
> uuid *key,
>      od->tunnel_key = sdp->sb_dp->tunnel_key;
>      init_mcast_info_for_datapath(od);
>      od->datapath_lflows = lflow_ref_create();
> +    od->proxy_arp_addrs = VECTOR_EMPTY_INITIALIZER(struct lport_addresses);
>      return od;
>  }
>
> @@ -586,6 +587,11 @@ ovn_datapath_destroy(struct ovn_datapath *od)
>          destroy_ports_for_datapath(od);
>          sset_destroy(&od->router_ips);
>          lflow_ref_destroy(od->datapath_lflows);
> +        /* The ovn_ports own the proxy_arp_addresses, so we do not
> +         * need to call destroy_lport_addresses() on the components
> +         * of the vector
> +         */
> +        vector_destroy(&od->proxy_arp_addrs);
>          free(od);
>      }
>  }
> @@ -1876,6 +1882,8 @@ join_logical_ports(const struct 
> sbrec_port_binding_table *sbrec_pb_table,
>                  if (extract_addresses(arp_proxy, &op->proxy_arp_addrs, &ofs) 
> ||
>                      extract_ip_addresses(arp_proxy, &op->proxy_arp_addrs)) {
>                      op->od->has_arp_proxy_port = true;
> +                    vector_push(&op->od->proxy_arp_addrs,
> +                                &op->proxy_arp_addrs);
>                  } else {
>                      static struct vlog_rate_limit rl =
>                          VLOG_RATE_LIMIT_INIT(1, 5);
> @@ -9836,6 +9844,112 @@ build_lswitch_arp_nd_responder_skip_local(struct 
> ovn_port *op,
>                                        &op->nbsp->header_, op->lflow_ref);
>  }
>
> +static void
> +build_arp_match(struct ds *match, const char *ipv4_addr, const char *mac)
> +{
> +    ds_put_format(match, "arp.tpa == %s && arp.op == 1 && eth.dst == %s",
> +                  ipv4_addr, mac);
> +}
> +
> +static void
> +build_nd_match(struct ds *match, const struct ipv6_netaddr *ipv6_addr,
> +               bool is_multicast)
> +{
> +    if (is_multicast) {
> +        ds_put_format(match, "nd_ns_mcast && ip6.dst == %s && nd.target == 
> %s",
> +                      ipv6_addr->sn_addr_s, ipv6_addr->addr_s);
> +    } else {
> +        ds_put_format(match, "nd_ns && ip6.dst == %s && nd.target == %s",
> +                      ipv6_addr->addr_s, ipv6_addr->addr_s);
> +    }
> +}
> +
> +static void
> +build_arp_unicast_flows_for_addrs(
> +    const struct lport_addresses *proxy_arp_addrs,
> +    const struct lport_addresses *lsp_addrs,
> +    struct ovn_port *op,
> +    struct lflow_table *lflows,
> +    struct ds *match)
> +{
> +    for (size_t i = 0; i < proxy_arp_addrs->n_ipv4_addrs; i++) {
> +        struct ipv4_netaddr *proxy_arp_ipv4 =
> +            &proxy_arp_addrs->ipv4_addrs[i];
> +        for (size_t j = 0; j < lsp_addrs->n_ipv4_addrs; j++) {
> +            struct ipv4_netaddr *lsp_ipv4 = &lsp_addrs->ipv4_addrs[j];
> +            ovs_be32 lsp_network = lsp_ipv4->addr & proxy_arp_ipv4->mask;
> +            if (lsp_network != proxy_arp_ipv4->network) {
> +                continue;
> +            }
> +            ds_clear(match);
> +            build_arp_match(match, lsp_ipv4->addr_s, lsp_addrs->ea_s);
> +            ovn_lflow_add_with_hint(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 
> 50,
> +                                    ds_cstr(match), "next;",
> +                                    &op->nbsp->header_, op->lflow_ref);
> +        }
> +    }
> +}
> +
> +static void
> +build_nd_ns_unicast_flows_for_addrs(
> +    const struct lport_addresses *proxy_arp_addrs,
> +    const struct lport_addresses *lsp_addrs,
> +    struct ovn_port *op,
> +    struct lflow_table *lflows,
> +    struct ds *match)
> +{
> +    for (size_t i = 0; i < proxy_arp_addrs->n_ipv6_addrs; i++) {
> +        struct ipv6_netaddr *proxy_arp_ipv6 =
> +            &proxy_arp_addrs->ipv6_addrs[i];
> +        for (size_t j = 0; j < lsp_addrs->n_ipv6_addrs; j++) {
> +            struct ipv6_netaddr *lsp_ipv6 = &lsp_addrs->ipv6_addrs[j];
> +            struct in6_addr *proxy_arp_mask = &proxy_arp_ipv6->mask;
> +            struct in6_addr *proxy_arp_network = &proxy_arp_ipv6->network;
> +            struct in6_addr network = ipv6_addr_bitand(&lsp_ipv6->addr,
> +                                                       proxy_arp_mask);
> +            if (!ipv6_addr_equals(proxy_arp_network, &network)) {
> +                continue;
> +            }
> +            ds_clear(match);
> +            build_nd_match(match, lsp_ipv6, false);
> +            ovn_lflow_add_with_hint(lflows, op->od,
> +                                    S_SWITCH_IN_ARP_ND_RSP, 50,
> +                                    ds_cstr(match),
> +                                    "next;", &op->nbsp->header_,
> +                                    op->lflow_ref);
> +        }
> +    }
> +}
> +
> +static void
> +build_lswitch_arp_nd_unicast_flows(struct ovn_port *op,
> +                                   struct lflow_table *lflows,
> +                                   struct ds *match)
> +{
> +    /* Typically, we don't need to build any unicast flows for ARP or ND
> +     * since the natural switching behavior of the logical switch will
> +     * get the packet to its intended destination. However, if proxy ARP
> +     * is configured, then we may need to install flows to ensure that
> +     * we do not incorrectly respond to unicast ARPs destined to a known
> +     * IP with the proxy ARP instead.
> +     */
> +    if (!op->od->nbs || !op->od->has_arp_proxy_port) {
> +        return;
> +    }
> +
> +    struct lport_addresses *proxy_arp_addrs;
> +    VECTOR_FOR_EACH_PTR (&op->od->proxy_arp_addrs, proxy_arp_addrs) {
> +        for (size_t i = 0; i < op->n_lsp_addrs; i++) {
> +            build_arp_unicast_flows_for_addrs(proxy_arp_addrs,
> +                                              &op->lsp_addrs[i],
> +                                              op, lflows, match);
> +            build_nd_ns_unicast_flows_for_addrs(proxy_arp_addrs,
> +                                                &op->lsp_addrs[i],
> +                                                op, lflows, match);
> +        }
> +    }
> +}
> +
>  /* Ingress table 24: ARP/ND responder, reply for known IPs.
>   * (priority 50). */
>  static void
> @@ -9956,15 +10070,8 @@ build_lswitch_arp_nd_responder_known_ips(struct 
> ovn_port *op,
>          for (size_t i = 0; i < op->n_lsp_addrs; i++) {
>              for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) {
>                  ds_clear(match);
> -                /* Do not reply on unicast ARPs, forward them to the target
> -                 * to have ability to monitor target liveness via unicast
> -                 * ARP requests.
> -                */
> -                ds_put_format(match,
> -                    "arp.tpa == %s && "
> -                    "arp.op == 1 && "
> -                    "eth.dst == ff:ff:ff:ff:ff:ff",
> -                    op->lsp_addrs[i].ipv4_addrs[j].addr_s);
> +                build_arp_match(match, op->lsp_addrs[i].ipv4_addrs[j].addr_s,
> +                                "ff:ff:ff:ff:ff:ff");
>                  ds_clear(actions);
>                  ds_put_format(actions,
>                      "eth.dst = eth.src; "
> @@ -10017,11 +10124,7 @@ build_lswitch_arp_nd_responder_known_ips(struct 
> ovn_port *op,
>               */
>              for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) {
>                  ds_clear(match);
> -                ds_put_format(
> -                    match,
> -                    "nd_ns_mcast && ip6.dst == %s && nd.target == %s",
> -                    op->lsp_addrs[i].ipv6_addrs[j].sn_addr_s,
> -                    op->lsp_addrs[i].ipv6_addrs[j].addr_s);
> +                build_nd_match(match, &op->lsp_addrs[i].ipv6_addrs[j], true);
>
>                  ds_clear(actions);
>                  ds_put_format(actions,
> @@ -10061,6 +10164,7 @@ build_lswitch_arp_nd_responder_known_ips(struct 
> ovn_port *op,
>                                                    op->lflow_ref);
>              }
>          }
> +        build_lswitch_arp_nd_unicast_flows(op, lflows, match);
>      }
>      if (op->proxy_arp_addrs.n_ipv4_addrs ||
>          op->proxy_arp_addrs.n_ipv6_addrs) {
> diff --git a/northd/northd.h b/northd/northd.h
> index cdc532954..dc863ec48 100644
> --- a/northd/northd.h
> +++ b/northd/northd.h
> @@ -471,6 +471,13 @@ struct ovn_datapath {
>      /* Reference to the lflows belonging to this datapath currently router
>       * only lflows. */
>      struct lflow_ref *datapath_lflows;
> +
> +    /* This vector contains pointers to struct lport_addresses. These are
> +     * the configured "arp_proxy" addresses of all logical switch ports on
> +     * this datapath. The ovn_ports own these addresses, so we should not
> +     * free them when destroying the ovn_datapath.
> +     */
> +    struct vector proxy_arp_addrs;
>  };
>
>  const struct ovn_datapath *ovn_datapath_find(const struct hmap *datapaths,
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 07fb57bd6..6b978bd6a 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -18716,3 +18716,96 @@ AT_CHECK(
>
>  AT_CLEANUP
>  ])
> +
> +OVN_FOR_EACH_NORTHD_NO_HV([
> +AT_SETUP([Unicast ARP flows])
> +ovn_start
> +
> +# Typically on logical switches, the ARP responder stage installs nothing
> +# for unicast ARPs towards VIF MACs. Instead, we rely on the default priority
> +# 1 "next;" action to move these ARPs through the pipeline, eventually 
> resulting
> +# in the ARP reaching the destination. When proxy ARP is configured, we need
> +# to install explicit flows for the unicast ARPs at a higher priority. 
> Otherwise
> +# the proxy ARP responder may respond with incorrect information.
> +#
> +# In this test, we are ensuring that the unicast flows in the ARP responder 
> stage
> +# are only installed when proxy ARP is enabled.
> +
> +check ovn-nbctl ls-add ls1
> +check ovn-nbctl lsp-add ls1 vm1 -- \
> +      lsp-set-addresses vm1 "00:00:00:00:00:02 192.168.0.2 fd01::2"
> +
> +check ovn-nbctl lr-add lr1
> +check ovn-nbctl lrp-add lr1 lr1-ls1 00:00:00:00:00:01 192.168.0.1 fd01::1
> +check ovn-nbctl lsp-add ls1 ls1-lr1 -- \
> +      lsp-set-addresses ls1-lr1 router -- \
> +      lsp-set-type ls1-lr1 router -- \
> +      lsp-set-options ls1-lr1 router-port=lr1-ls1
> +
> +check ovn-nbctl --wait=sb sync
> +
> +# If we check the ARP responder flows in ls1, we should not see any unicast
> +# flows for vm1 (00:00:00:00:00:02). We also should not see any unicast
> +# IPv6 ND flows for vm1 (fd01::2)
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "eth.dst == 
> 00:00:00:00:00:02" | ovn_strip_lflows], [0], [dnl
> +])
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "ip6.dst == 
> fd01::2" | ovn_strip_lflows], [0], [dnl
> +])
> +
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "eth.dst == 
> 00:00:00:00:00:01" | ovn_strip_lflows], [0], [dnl
> +])
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "ip6.dst == 
> fd01::1" | ovn_strip_lflows], [0], [dnl
> +])
> +
> +# Add ARP proxy configuration on the router port.
> +check ovn-nbctl set logical_switch_port ls1-lr1 
> options:arp_proxy="192.168.0.0/24 fd01::/64"
> +check ovn-nbctl --wait=sb sync
> +
> +# Now that we have ARP proxy configured, we should see flows for
> +# vm1's MAC.
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "eth.dst == 
> 00:00:00:00:00:02" | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_arp_rsp      ), priority=50   , match=(arp.tpa == 
> 192.168.0.2 && arp.op == 1 && eth.dst == 00:00:00:00:00:02), action=(next;)
> +])
> +# And we should see unicast ND flows for vm1's IP address
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "ip6.dst == 
> fd01::2" | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_arp_rsp      ), priority=50   , match=(nd_ns && ip6.dst == 
> fd01::2 && nd.target == fd01::2), action=(next;)
> +])
> +
> +# We should also see an ARP flow for ls1-lr1's MAC.
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "eth.dst == 
> 00:00:00:00:00:01" | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_arp_rsp      ), priority=50   , match=(arp.tpa == 
> 192.168.0.1 && arp.op == 1 && eth.dst == 00:00:00:00:00:01), action=(next;)
> +])
> +# And we should see an ND flow for ls1-lr1's IPv6 address.
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "ip6.dst == 
> fd01::1" | ovn_strip_lflows], [0], [dnl
> +  table=??(ls_in_arp_rsp      ), priority=50   , match=(nd_ns && ip6.dst == 
> fd01::1 && nd.target == fd01::1), action=(next;)
> +])
> +
> +check ovn-nbctl remove logical_switch_port ls1-lr1 options arp_proxy
> +check ovn-nbctl --wait=sb sync
> +
> +# We have removed ARP proxy, so we should no longer see a unicast ARP or ND 
> flow.
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "eth.dst == 
> 00:00:00:00:00:02" | ovn_strip_lflows], [0], [dnl
> +])
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "ip6.dst == 
> fd01::2" | ovn_strip_lflows], [0], [dnl
> +])
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "eth.dst == 
> 00:00:00:00:00:01" | ovn_strip_lflows], [0], [dnl
> +])
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "ip6.dst == 
> fd01::1" | ovn_strip_lflows], [0], [dnl
> +])
> +
> +# Now we'll set up ARP proxy flows for networks that are different from our
> +# LSPs. This should result in no unicast ARP/ND flows being installed.
> +check ovn-nbctl set logical_switch_port ls1-lr1 
> options:arp_proxy="193.168.0.0/24 fd11::/64"
> +check ovn-nbctl --wait=sb sync
> +
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "eth.dst == 
> 00:00:00:00:00:02" | ovn_strip_lflows], [0], [dnl
> +])
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "ip6.dst == 
> fd01::2" | ovn_strip_lflows], [0], [dnl
> +])
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "eth.dst == 
> 00:00:00:00:00:01" | ovn_strip_lflows], [0], [dnl
> +])
> +AT_CHECK([ovn-sbctl lflow-list ls1 | grep ls_in_arp_rsp | grep "ip6.dst == 
> fd01::1" | ovn_strip_lflows], [0], [dnl
> +])
> +
> +AT_CLEANUP
> +])
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 3f340e7b3..0783376bc 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -44371,3 +44371,79 @@ check ovn-nbctl --wait=hv sync
>  OVN_CLEANUP([hv1],[hv2],[hv3])
>  AT_CLEANUP
>  ])
> +
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([Unicast ARP when proxy ARP is configured])

I realized that this test is missing

AT_SKIP_IF([test $HAVE_SCAPY = no])

since it uses fmt_pkt(). If this patch gets Acked, then this should be
corrected when merging. If this patch has other issues and requires a
v4, I'll fix it in that version.

> +ovn_start
> +
> +check ovn-nbctl ls-add ls1
> +check ovn-nbctl lsp-add ls1 vm1 -- \
> +      lsp-set-addresses vm1 "00:00:00:00:00:02 10.0.0.2 fd01::2"
> +check ovn-nbctl lsp-add ls1 vm2 -- \
> +      lsp-set-addresses vm2 "00:00:00:00:00:03 10.0.0.3 fd01::3"
> +
> +check ovn-nbctl lr-add lr1
> +check ovn-nbctl lrp-add lr1 lr1-ls1 00:00:00:00:00:01 10.0.0.1 fd01::1
> +check ovn-nbctl lsp-add ls1 ls1-lr1 -- \
> +      lsp-set-addresses ls1-lr1 router -- \
> +      lsp-set-type ls1-lr1 router -- \
> +      lsp-set-options ls1-lr1 router-port=lr1-ls1
> +
> +check ovn-nbctl --wait=hv sync
> +
> +net_add n1
> +sim_add hv1
> +as hv1
> +ovs-vsctl add-br br-phys
> +ovn_attach n1 br-phys 192.168.0.1
> +ovs-vsctl add-port br-int vif1 -- set Interface vif1 
> external-ids:iface-id=vm1 \
> +    options:tx_pcap=hv1/vif1-tx.pcap \
> +    options:rxq_pcap=hv1/vif1-rx.pcap
> +ovs-vsctl add-port br-int vif2 -- set Interface vif2 
> external-ids:iface-id=vm2 \
> +    options:tx_pcap=hv1/vif2-tx.pcap \
> +    options:rxq_pcap=hv1/vif2-rx.pcap
> +
> +OVN_POPULATE_ARP
> +
> +wait_for_ports_up
> +
> +arp=$(fmt_pkt "Ether(dst='00:00:00:00:00:02', src='00:00:00:00:00:03')/ \
> +               ARP(hwsrc='00:00:00:00:00:03', hwdst='00:00:00:00:00:02',
> +                   psrc='10.0.0.3', pdst='10.0.0.2')")
> +nd_ns=$(fmt_pkt "Ether(dst='00:00:00:00:00:02', src='00:00:00:00:00:03')/ \
> +                 IPv6(src='fd01::3', dst='fd01::2')/ \
> +                 ICMPv6ND_NS(tgt='fd01::2')")
> +
> +# If we send a unicast ARP from vm2 towards vm1, the ARP should be forwarded
> +# to vm1 by ls1.
> +as hv1 ovs-appctl netdev-dummy/receive vif2 $arp
> +echo $arp > expected
> +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], expected)
> +
> +# And if we send a unicast ND_NS from vm2 towards vm1, the ND_NS should be
> +# forwarded to vm1 by ls1.
> +as hv1 ovs-appctl netdev-dummy/receive vif2 $nd_ns
> +echo $nd_ns >> expected
> +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], expected)
> +
> +
> +# Add ARP proxy configuration on the router port. The subnet for the ARP 
> proxy
> +# addresses overlaps with the VIF addresses for vm1 and vm2.
> +check ovn-nbctl set logical_switch_port ls1-lr1 
> options:arp_proxy="10.0.0.0/8 fd01::/64"
> +check ovn-nbctl --wait=hv sync
> +
> +# Sending a unicast ARP from vm2 towards vm1 should still result in the ARP 
> being
> +# forwarded to vm1 by ls1.
> +as hv1 ovs-appctl netdev-dummy/receive vif2 $arp
> +echo $arp >> expected
> +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], expected)
> +
> +# Sending a unicast ND_NS from vm2 towards vm1 should still result in the 
> ND_NS being
> +# forwarded to vm1 by ls1.
> +as hv1 ovs-appctl netdev-dummy/receive vif2 $nd_ns
> +echo $nd_ns >> expected
> +OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], expected)
> +
> +OVN_CLEANUP([hv1])
> +AT_CLEANUP
> +])
> --
> 2.50.1
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to