>>>>> On 7/13/22 18:07, Lorenzo Bianconi wrote:
>>>>>>> On 6/17/22 00:31, Lorenzo Bianconi wrote:
>>>>>>>> When using VLAN backed networks and OVN routers leveraging the
>>>>>>>> 'ovn-chassis-mac-mappings' option, the eth.src field is replaced by the
>>>>>>>> chassis mac address in order to not expose the router mac address from
>>>>>>>> different nodes and confuse the TOR switch. However doing so the TOR
>>>>>>>> switch is not able to learn the port/mac bindings for routed E/W
>>>>>>>> traffic
>>>>>>>> and it is force to always flood it. Fix this issue adding the
>>>>>>>> capability
>>>>>>>> to send GARP traffic for logical switch ports if the corresponding
>>>>>>>> logical
>>>>>>>> switch has the ovn-lsp-garp parameter set to true in the option column.
>>>>>>>> More into about the issue can be found here [0].
>>>>>>>>
>>>>>>>> [0]
>>>>>>>> https://mail.openvswitch.org/pipermail/ovs-discuss/2020-September/050678.html
>>>>>>>>
>>>>>>>> <https://mail.openvswitch.org/pipermail/ovs-discuss/2020-September/050678.html>
>>>>>>>> Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2087779
>>>>>>>> <https://bugzilla.redhat.com/show_bug.cgi?id=2087779>
>>>>>>>>
>>>>>>>> Signed-off-by: Lorenzo Bianconi <[email protected]
>>>>>>>> <mailto:[email protected]>>
>>>>>>>> ---
>>>>>>>
>>>>>>> Hi Lorenzo,
>>>>>>
>>>>>> Hi Dumitru,
>>>>>>
>>>>>> Thanks for reviewing it :)
>>>>>>
>>>>>>>
>>>>>>> I have a few concerns with this approach:
>>>>>>>
>>>>>>> a. The CMS will have to set this option for all VMs on all logical
>>>>>>> switches which will enable periodic GARPs for all of them all the time.
>>>>>>> That seems like quite a lot of broadcast traffic in the fabric.
>>>>>>>
>>>>>>> b. There's no guarantee that the GARPs are sent in time to prevent the
>>>>>>> FDB timeouts on the ToR switches. At best we could make the interval
>>>>>>> configurable but I don't think this is way better either.
>>>>>>>
>>>>>>> c. This is not really introduced by your patch but we will be causing
>>>>>>> this more often now. With the topology:
>>>>>>>
>>>>>>> (HV1) VM1 -- LS1 --- LR -- LS2 -- VM2 (HV2)
>>>>>>> (VLAN-backed network)
>>>>>>>
>>>>>>> HV1 configured with chassis mac mapping HV1-MAC
>>>>>>> HV2 configured with chassis mac mapping HV2-MAC
>>>>>>>
>>>>>>> We're leaking MAC addresses from LS1's broadcast domain (VM1-MAC) and
>>>>>>> from LS2's broadcast domain (VM2-MAC) into the fabric. I'm not sure
>>>>>>> that's OK.
>>>>>>>
>>>>>>> I think a proper solution is to change how we run the logical pipelines
>>>>>>> in case of vlan-backed networks. We currently have an assymetry:
>>>>>>>
>>>>>>> For packets flowing from VM1 to VM2 we execute:
>>>>>>> - on HV1: LS1-ingress, LS1-egress, LR-ingress, LR-egress, LS2-ingress
>>>>>>> - on HV2: LS2-egress
>>>>>>>
>>>>>>> For packets flowing from VM2 to VM1 we execute:
>>>>>>> - on HV2: LS2-ingress, LS2-egress, LR-ingress, LR-egress, LS1-ingress
>>>>>>> - on HV1: LS1-egress
>>>>>>>
>>>>>>> What if we change this to:
>>>>>>> VM1 -> VM2:
>>>>>>> - on HV1: LS1-ingress, LS1-egress, LR-ingress
>>>>>>> - on HV2: LR-egress, LS2-ingress, LS2-egress
>>>>>>>
>>>>>>> VM2 -> VM1:
>>>>>>> - on HV2: LS2-ingress, LS2-egress, LR-ingress
>>>>>>> - on HV2: LR-egress, LS1-ingress, LS1-egress
>>>>>>
>>>>>> I do not know why the current architecture is done this way (any
>>>>>> suggestions??).
>>>>>> I guess the approach you suggested should work. Are we introducing any
>>>>>> backward
>>>>>> compatibility issue?
>>>>>
>>>>> We would probably create a compatibility issue. :)
>>>>>
>>>>> I don't know if this approach would even work, I was just trying to
>>>>> imagine how traffic from within OVN should be seen on the fabric in this
>>>>> case.
>>>>>
>>>>> Maybe we need to think some more about other options.
>>>>>
>>>>> Regards,
>>>>> Dumitru
>>>> Hi Dumitru and Lorenzo,
>>>
>>> Hi Shy Liu,
>>>
>>>> in my opinion, the flood issue maybe caused by the implemention that
>>>> logical_switch always be an arp-proxy for lsp which has known address,
>>>> but this implemention is not applicable to vlan backed network. Right ?
>>>>
>>>> I have an solution:
>>>> Maybe we can add a option named arp-proxy for logical_switch
>>>> that always be false if network type is vlan, then disable the
>>>> logical_switch response the arp for the lsp which belongs to
>>>> the vlan backed network.
>>>>
>>>> So that this solution can let the destination MAC address
>>>> always learnt by TOR for vlan backed network.
>>>
>>> For e/w routed traffic from pod A to pod B, pod A will send an arp request
>>> for the router ip address. Who is going to reply to this request in this
>>> way?
>> Hi Lorenzo,
>> sorry that I had not describe it clearly.
>> We can disable arp response for the lsp which type is not router port nor
>> localport.
>> So the logical_switch still responses the arp request for lrp.
>
> IIUC what you mean here, this approach will be helpful just if pod A and pod B
> are on the same logical switch but they are running on two different
> hypervisors,
> right? What if pod A and pod B are on the same logical switch and they are
> running
> on the same HV?
>
> Regards,
> Lorenzo
Arp request always been broadcasted to the lsps those on the
same logical_switch.
I had hardcode it like what i said, and it worked fine for that vm A and vm B
are running on the same HV:
@@ -7529,6 +7541,13 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port
*op,
return;
}
+ if (!op->od->has_arp_proxy && !lsp_is_router(op->nbsp) &&
+ strcmp(op->nbsp->type, "localport")) {
+ /* When disable arp_proxy, not Add ARP/ND reply flows
+ * for a port unless router port or localport. */
+ return;
+ }
+
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);
But there maybe any other issues I have not consider :)
>>
>>> If ovn replies to the arp request from pod A but let the request go through
>>> the router pipeline I think even the other hypervisor will reply to the arp
>>> request (please remember the logical router is distributed in ovn) and so we
>>> will confuse the TOR switch since we will see the router mac address
>>> flapping
>>> between two ports. Do you agree or am I missing something?
>>
>> We can use 'ovn-chassis-mac-mappings’ option to avoid the problem
>> that the lrp's mac address flap. Right ?
>>
>>
>>>
>>> Regards,
>>> Lorenzo
>>
>>>
>>>>
>>>> But the lrp might learn the destination MAC address and put_arp,
>>>> so this operation also should been disabled.
>>>>
>>>> This is not useful for logical_switch which is external net.
>>>>
>>>>
>>>> Reference:
>>>> [0]
>>>> https://mail.openvswitch.org/pipermail/ovs-discuss/2022-May/051837.html
>>>> <https://mail.openvswitch.org/pipermail/ovs-discuss/2022-May/051837.html>.
>>>>>
>>>>>>
>>>>>> Regards,
>>>>>> Lorenzo
>>>>>>
>>>>>>>
>>>>>>> Would this we ensure that we always only use ovn-chassis-mac-mappings on
>>>>>>> the VLAN network and avoid flooding on the ToR?
>>>>>>>
>>>>>>> Regards,
>>>>>>> Dumitru
>>>>>>>
>>>>>>>> controller/pinctrl.c | 85 +++++++++++++++++++++++++++++---------------
>>>>>>>> northd/northd.c | 29 +++++++++++++++
>>>>>>>> 2 files changed, 85 insertions(+), 29 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
>>>>>>>> index 9a1a0faa1..eb5739bfc 100644
>>>>>>>> --- a/controller/pinctrl.c
>>>>>>>> +++ b/controller/pinctrl.c
>>>>>>>> @@ -4533,7 +4533,8 @@ send_garp_rarp(struct rconn *swconn, struct
>>>>>>>> garp_rarp_data *garp_rarp,
>>>>>>>> garp_rarp->backoff *= 2;
>>>>>>>> garp_rarp->announce_time = current_time + garp_rarp->backoff *
>>>>>>>> 1000;
>>>>>>>> } else {
>>>>>>>> - garp_rarp->announce_time = LLONG_MAX;
>>>>>>>> + /* Default timeout is 180s. */
>>>>>>>> + garp_rarp->announce_time = current_time + 180 * 1000;
>>>>>>>> }
>>>>>>>> return garp_rarp->announce_time;
>>>>>>>> }
>>>>>>>> @@ -5510,14 +5511,15 @@ ip_mcast_querier_wait(long long int query_time)
>>>>>>>>
>>>>>>>> /* Get localnet vifs, local l3gw ports and ofport for localnet patch
>>>>>>>> ports. */
>>>>>>>> static void
>>>>>>>> -get_localnet_vifs_l3gwports(
>>>>>>>> +get_local_vifs_l3gwports(
>>>>>>>> struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
>>>>>>>> struct ovsdb_idl_index *sbrec_port_binding_by_name,
>>>>>>>> const struct ovsrec_bridge *br_int,
>>>>>>>> const struct sbrec_chassis *chassis,
>>>>>>>> const struct hmap *local_datapaths,
>>>>>>>> struct sset *localnet_vifs,
>>>>>>>> - struct sset *local_l3gw_ports)
>>>>>>>> + struct sset *local_l3gw_ports,
>>>>>>>> + struct sset *local_vifs)
>>>>>>>> {
>>>>>>>> for (int i = 0; i < br_int->n_ports; i++) {
>>>>>>>> const struct ovsrec_port *port_rec = br_int->ports[i];
>>>>>>>> @@ -5574,7 +5576,8 @@ get_localnet_vifs_l3gwports(
>>>>>>>> /* Get l3gw ports. Consider port bindings with type "l3gateway"
>>>>>>>> * that connect to gateway routers (if local), and consider port
>>>>>>>> * bindings of type "patch" since they might connect to
>>>>>>>> - * distributed gateway ports with NAT addresses. */
>>>>>>>> + * distributed gateway ports with NAT addresses.
>>>>>>>> + * Get LSP ports if requested by CMS. */
>>>>>>>>
>>>>>>>> sbrec_port_binding_index_set_datapath(target, ld->datapath);
>>>>>>>> SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, target,
>>>>>>>> @@ -5583,6 +5586,11 @@ get_localnet_vifs_l3gwports(
>>>>>>>> || !strcmp(pb->type, "patch")) {
>>>>>>>> sset_add(local_l3gw_ports, pb->logical_port);
>>>>>>>> }
>>>>>>>> + /* GARP packets for lsp ports. */
>>>>>>>> + if (pb->chassis == chassis &&
>>>>>>>> + smap_get_bool(&pb->options, "ovn-lsp-garp", false)) {
>>>>>>>> + sset_add(local_vifs, pb->logical_port);
>>>>>>>> + }
>>>>>>>> }
>>>>>>>> }
>>>>>>>> sbrec_port_binding_index_destroy_row(target);
>>>>>>>> @@ -5761,6 +5769,26 @@ send_garp_rarp_run(struct rconn *swconn, long
>>>>>>>> long int *send_garp_rarp_time)
>>>>>>>> }
>>>>>>>> }
>>>>>>>>
>>>>>>>> +static void
>>>>>>>> +send_garp_rarp_update_for_pb_set(
>>>>>>>> + struct ovsdb_idl_txn *ovnsb_idl_txn,
>>>>>>>> + struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
>>>>>>>> + struct ovsdb_idl_index *sbrec_port_binding_by_name,
>>>>>>>> + struct sset *vif_set, const struct hmap *local_datapaths,
>>>>>>>> + struct shash *nat_addresses)
>>>>>>>> +{
>>>>>>>> + const char *iface_id;
>>>>>>>> + SSET_FOR_EACH (iface_id, vif_set) {
>>>>>>>> + const struct sbrec_port_binding *pb = lport_lookup_by_name(
>>>>>>>> + sbrec_port_binding_by_name, iface_id);
>>>>>>>> + if (pb) {
>>>>>>>> + send_garp_rarp_update(ovnsb_idl_txn,
>>>>>>>> + sbrec_mac_binding_by_lport_ip,
>>>>>>>> + local_datapaths, pb, nat_addresses);
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> /* Called by pinctrl_run(). Runs with in the main ovn-controller
>>>>>>>> * thread context. */
>>>>>>>> static void
>>>>>>>> @@ -5776,15 +5804,17 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn
>>>>>>>> *ovnsb_idl_txn,
>>>>>>>> {
>>>>>>>> struct sset localnet_vifs = SSET_INITIALIZER(&localnet_vifs);
>>>>>>>> struct sset local_l3gw_ports = SSET_INITIALIZER(&local_l3gw_ports);
>>>>>>>> + struct sset local_vifs = SSET_INITIALIZER(&local_vifs);
>>>>>>>> struct sset nat_ip_keys = SSET_INITIALIZER(&nat_ip_keys);
>>>>>>>> struct shash nat_addresses;
>>>>>>>>
>>>>>>>> shash_init(&nat_addresses);
>>>>>>>>
>>>>>>>> - get_localnet_vifs_l3gwports(sbrec_port_binding_by_datapath,
>>>>>>>> - sbrec_port_binding_by_name,
>>>>>>>> - br_int, chassis, local_datapaths,
>>>>>>>> - &localnet_vifs, &local_l3gw_ports);
>>>>>>>> + get_local_vifs_l3gwports(sbrec_port_binding_by_datapath,
>>>>>>>> + sbrec_port_binding_by_name,
>>>>>>>> + br_int, chassis, local_datapaths,
>>>>>>>> + &localnet_vifs, &local_l3gw_ports,
>>>>>>>> + &local_vifs);
>>>>>>>>
>>>>>>>> get_nat_addresses_and_keys(sbrec_port_binding_by_name,
>>>>>>>> &nat_ip_keys, &local_l3gw_ports,
>>>>>>>> @@ -5795,36 +5825,33 @@ send_garp_rarp_prepare(struct ovsdb_idl_txn
>>>>>>>> *ovnsb_idl_txn,
>>>>>>>> struct shash_node *iter;
>>>>>>>> SHASH_FOR_EACH_SAFE (iter, &send_garp_rarp_data) {
>>>>>>>> if (!sset_contains(&localnet_vifs, iter->name) &&
>>>>>>>> - !sset_contains(&nat_ip_keys, iter->name)) {
>>>>>>>> + !sset_contains(&nat_ip_keys, iter->name) &&
>>>>>>>> + !sset_contains(&local_vifs, iter->name)) {
>>>>>>>> send_garp_rarp_delete(iter->name);
>>>>>>>> }
>>>>>>>> }
>>>>>>>>
>>>>>>>> /* Update send_garp_rarp_data. */
>>>>>>>> - const char *iface_id;
>>>>>>>> - SSET_FOR_EACH (iface_id, &localnet_vifs) {
>>>>>>>> - const struct sbrec_port_binding *pb = lport_lookup_by_name(
>>>>>>>> - sbrec_port_binding_by_name, iface_id);
>>>>>>>> - if (pb) {
>>>>>>>> - send_garp_rarp_update(ovnsb_idl_txn,
>>>>>>>> - sbrec_mac_binding_by_lport_ip,
>>>>>>>> - local_datapaths, pb,
>>>>>>>> &nat_addresses);
>>>>>>>> - }
>>>>>>>> - }
>>>>>>>> -
>>>>>>>> + send_garp_rarp_update_for_pb_set(ovnsb_idl_txn,
>>>>>>>> + sbrec_mac_binding_by_lport_ip,
>>>>>>>> + sbrec_port_binding_by_name,
>>>>>>>> + &localnet_vifs, local_datapaths,
>>>>>>>> + &nat_addresses);
>>>>>>>> + send_garp_rarp_update_for_pb_set(ovnsb_idl_txn,
>>>>>>>> + sbrec_mac_binding_by_lport_ip,
>>>>>>>> + sbrec_port_binding_by_name,
>>>>>>>> + &local_vifs, local_datapaths,
>>>>>>>> + &nat_addresses);
>>>>>>>> /* Update send_garp_rarp_data for nat-addresses. */
>>>>>>>> - const char *gw_port;
>>>>>>>> - SSET_FOR_EACH (gw_port, &local_l3gw_ports) {
>>>>>>>> - const struct sbrec_port_binding *pb
>>>>>>>> - = lport_lookup_by_name(sbrec_port_binding_by_name,
>>>>>>>> gw_port);
>>>>>>>> - if (pb) {
>>>>>>>> - send_garp_rarp_update(ovnsb_idl_txn,
>>>>>>>> sbrec_mac_binding_by_lport_ip,
>>>>>>>> - local_datapaths, pb,
>>>>>>>> &nat_addresses);
>>>>>>>> - }
>>>>>>>> - }
>>>>>>>> + send_garp_rarp_update_for_pb_set(ovnsb_idl_txn,
>>>>>>>> + sbrec_mac_binding_by_lport_ip,
>>>>>>>> + sbrec_port_binding_by_name,
>>>>>>>> + &local_l3gw_ports,
>>>>>>>> local_datapaths,
>>>>>>>> + &nat_addresses);
>>>>>>>>
>>>>>>>> /* pinctrl_handler thread will send the GARPs. */
>>>>>>>>
>>>>>>>> + sset_destroy(&local_vifs);
>>>>>>>> sset_destroy(&localnet_vifs);
>>>>>>>> sset_destroy(&local_l3gw_ports);
>>>>>>>>
>>>>>>>> diff --git a/northd/northd.c b/northd/northd.c
>>>>>>>> index 0d6ebccde..9a4a880a7 100644
>>>>>>>> --- a/northd/northd.c
>>>>>>>> +++ b/northd/northd.c
>>>>>>>> @@ -6446,6 +6446,34 @@ ovn_update_ipv6_options(struct hmap *ports)
>>>>>>>> }
>>>>>>>> }
>>>>>>>>
>>>>>>>> +static void
>>>>>>>> +ovn_update_lsp_garp_options(struct hmap *ports)
>>>>>>>> +{
>>>>>>>> + struct ovn_port *op;
>>>>>>>> + HMAP_FOR_EACH (op, key_node, ports) {
>>>>>>>> + if (!op->nbsp) {
>>>>>>>> + continue;
>>>>>>>> + }
>>>>>>>> + if (op->nbsp->type[0] || op->nbsp->parent_name) {
>>>>>>>> + continue;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + struct ovn_datapath *od = op->od;
>>>>>>>> + if (!od || !od->nbs) {
>>>>>>>> + continue;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + struct smap options;
>>>>>>>> + smap_clone(&options, &op->sb->options);
>>>>>>>> +
>>>>>>>> + bool ovn_lsp_garp = smap_get_bool(&od->nbs->other_config,
>>>>>>>> + "ovn-lsp-garp", false);
>>>>>>>> + smap_add(&options, "ovn-lsp-garp", ovn_lsp_garp ? "true" :
>>>>>>>> "false");
>>>>>>>> + sbrec_port_binding_set_options(op->sb, &options);
>>>>>>>> + smap_destroy(&options);
>>>>>>>> + }
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> static void
>>>>>>>> build_port_group_lswitches(struct northd_input *input_data,
>>>>>>>> struct hmap *pgs,
>>>>>>>> @@ -15381,6 +15409,7 @@ ovnnb_db_run(struct northd_input *input_data,
>>>>>>>> stopwatch_start(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec());
>>>>>>>> ovn_update_ipv6_options(&data->ports);
>>>>>>>> ovn_update_ipv6_prefix(&data->ports);
>>>>>>>> + ovn_update_lsp_garp_options(&data->ports);
>>>>>>>>
>>>>>>>> sync_lbs(input_data, ovnsb_txn, &data->datapaths, &data->lbs);
>>>>>>>> sync_address_sets(input_data, ovnsb_txn, &data->datapaths);
>>>>>>>
>>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev