Skip to content

Commit

Permalink
northd: Treat reachable and unreachable VIPs differently.
Browse files Browse the repository at this point in the history
If a logical switch is used to join multiple gateway
routers and if each of these gateway routers are
configured with the same load balancer,  then after the
commit [1] it's results in a flow explosion in
the "ls_in_l2_lkup" stage of this logical switch.

So, this patch reverts parts of the commit [1] related to
the load balancer VIPs.

Eg. If a load balancer with vip - 5.0.0.48 is configured
on gateway routers g0, g1 and g2.  Then ovn-northd will add
the below logical flows

table=22(ls_in_l2_lkup), priority=80,
  match=(flags[1] == 0 && arp.op == 1 && arp.tpa == 5.0.0.48),
  action=(outport = "join-to-g0-port"; output;)
table=22(ls_in_l2_lkup), priority=80,
  match=(flags[1] == 0 && arp.op == 1 && arp.tpa == 5.0.0.48),
  action=(outport = "join-to-g1-port"; output;)
table=22(ls_in_l2_lkup), priority=80,
  match=(flags[1] == 0 && arp.op == 1 && arp.tpa == 5.0.0.48),
  action=(outport = "join-to-g2-port"; output;)

After this patch,  we will just have one lflow
table=22(ls_in_l2_lkup), priority=90,
  match=(flags[1] == 0 && arp.op == 1 && arp.tpa == 5.0.0.48),
  action=(outport = "_MC_flood"; output;)

[1] - ccbbbd0("ovn-northd: Treat reachable and unreachable addresses identically.")
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2020710
Fixes: ccbbbd0("ovn-northd: Treat reachable and unreachable addresses identically.")
Signed-off-by: Numan Siddique <numans@ovn.org>
Acked-by: Dumitru Ceara <dceara@redhat.com>
(cherry picked from commit bb71511)
  • Loading branch information
numansiddique committed Nov 9, 2021
1 parent 323f036 commit 7fd0e56
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 4 deletions.
105 changes: 103 additions & 2 deletions northd/northd.c
Expand Up @@ -6944,6 +6944,42 @@ arp_nd_ns_match(const char *ips, int addr_family, struct ds *match)
}
}

/* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the
* IPs configured on the router port.
*/
static bool
lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr)
{
for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
struct ipv4_netaddr *op_addr = &op->lrp_networks.ipv4_addrs[i];

if ((addr & op_addr->mask) == op_addr->network) {
return true;
}
}
return false;
}

/* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the
* IPs configured on the router port.
*/
static bool
lrouter_port_ipv6_reachable(const struct ovn_port *op,
const struct in6_addr *addr)
{
for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
struct ipv6_netaddr *op_addr = &op->lrp_networks.ipv6_addrs[i];

struct in6_addr nat_addr6_masked =
ipv6_addr_bitand(addr, &op_addr->mask);

if (ipv6_addr_equals(&nat_addr6_masked, &op_addr->network)) {
return true;
}
}
return false;
}

/*
* Ingress table 22: Flows that forward ARP/ND requests only to the routers
* that own the addresses. Other ARP/ND packets are still flooded in the
Expand Down Expand Up @@ -7015,7 +7051,8 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op,
/* Check if the ovn port has a network configured on which we could
* expect ARP requests for the LB VIP.
*/
if (ip_parse(ip_addr, &ipv4_addr)) {
if (ip_parse(ip_addr, &ipv4_addr) &&
lrouter_port_ipv4_reachable(op, ipv4_addr)) {
build_lswitch_rport_arp_req_flow(
ip_addr, AF_INET, sw_op, sw_od, 80, lflows,
stage_hint);
Expand All @@ -7027,7 +7064,8 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op,
/* Check if the ovn port has a network configured on which we could
* expect NS requests for the LB VIP.
*/
if (ipv6_parse(ip_addr, &ipv6_addr)) {
if (ipv6_parse(ip_addr, &ipv6_addr) &&
lrouter_port_ipv6_reachable(op, &ipv6_addr)) {
build_lswitch_rport_arp_req_flow(
ip_addr, AF_INET6, sw_op, sw_od, 80, lflows,
stage_hint);
Expand Down Expand Up @@ -7087,6 +7125,68 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op,
}
}

static void
build_lflows_for_unreachable_vips(struct ovn_northd_lb *lb,
struct ovn_lb_vip *lb_vip,
struct hmap *lflows,
struct ds *match)
{
static const char *action = "outport = \"_MC_flood\"; output;";
bool ipv4 = IN6_IS_ADDR_V4MAPPED(&lb_vip->vip);
ovs_be32 ipv4_addr;

ds_clear(match);
if (ipv4) {
if (!ip_parse(lb_vip->vip_str, &ipv4_addr)) {
return;
}
ds_put_format(match, "%s && arp.op == 1 && arp.tpa == %s",
FLAGBIT_NOT_VXLAN, lb_vip->vip_str);
} else {
ds_put_format(match, "%s && nd_ns && nd.target == %s",
FLAGBIT_NOT_VXLAN, lb_vip->vip_str);
}

struct ovn_lflow *lflow_ref = NULL;
uint32_t hash = ovn_logical_flow_hash(
ovn_stage_get_table(S_SWITCH_IN_L2_LKUP),
ovn_stage_get_pipeline(S_SWITCH_IN_L2_LKUP), 90,
ds_cstr(match), action);

for (size_t i = 0; i < lb->n_nb_lr; i++) {
struct ovn_datapath *od = lb->nb_lr[i];

if (!od->is_gw_router && !od->n_l3dgw_ports) {
continue;
}

struct ovn_port *op;
LIST_FOR_EACH (op, dp_node, &od->port_list) {
if (!od->is_gw_router && !is_l3dgw_port(op)) {
continue;
}

struct ovn_port *peer = op->peer;
if (!peer || !peer->nbsp || lsp_is_external(peer->nbsp)) {
continue;
}

if ((ipv4 && lrouter_port_ipv4_reachable(op, ipv4_addr)) ||
(!ipv4 && lrouter_port_ipv6_reachable(op, &lb_vip->vip))) {
continue;
}

if (ovn_dp_group_add_with_reference(lflow_ref, peer->od)) {
continue;
}
lflow_ref = ovn_lflow_add_at_with_hash(
lflows, peer->od, S_SWITCH_IN_L2_LKUP, 90, ds_cstr(match),
action, NULL, NULL, &peer->nbsp->header_,
OVS_SOURCE_LOCATOR, hash);
}
}
}

static void
build_dhcpv4_options_flows(struct ovn_port *op,
struct lport_addresses *lsp_addrs,
Expand Down Expand Up @@ -9574,6 +9674,7 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
for (size_t i = 0; i < lb->n_vips; i++) {
struct ovn_lb_vip *lb_vip = &lb->vips[i];

build_lflows_for_unreachable_vips(lb, lb_vip, lflows, match);
build_lrouter_nat_flows_for_lb(lb_vip, lb, &lb->vips_nb[i],
lflows, match, action,
meter_groups);
Expand Down
8 changes: 8 additions & 0 deletions northd/ovn-northd.8.xml
Expand Up @@ -1582,6 +1582,14 @@ output;
<ref column="options" table="Logical_Router"/>:mcast_relay='true'.
</li>

<li>
Priority-90 flows for each VIP address of a load balancer configured
outside its owning router port's subnet. These flows match ARP
requests and ND packets for the specific IP addresses. Matched packets
are forwarded to the <code>MC_FLOOD</code> multicast group which
contains all connected logical ports.
</li>

<li>
A priority-85 flow that forwards all IP multicast traffic destined to
224.0.0.X to the <code>MC_FLOOD</code> multicast group, which
Expand Down

0 comments on commit 7fd0e56

Please sign in to comment.