Hi Alexandra, see in-line for comments.
On 7/31/25 8:01 AM, Alexandra Rukomoinikova wrote:
This commit implements ARP/ND responder flows for IC-learned service monitors,
similar to existing local service monitors. Key changes include:
1. Extracted common ARP/ND response logic into helper function
`build_arp_nd_service_monitor_lflow()` to avoid code duplication
2. Split service monitor flow generation into two separate functions:
- `build_lswitch_arp_nd_local_svc_mon()` for local service monitors
- `build_lswitch_arp_nd_ic_learned_svc_mon()` for IC-learned monitors
3. Added flow generation for IC-learned monitors in main flow build path
4. Maintained existing behavior for local service monitors
5. Updated parallel and non-parallel build paths consistently
Signed-off-by: Alexandra Rukomoinikova <arukomoinikova@k2.cloud>
---
northd/northd.c | 160 +++++++++++++++++++++++++++++++-----------------
1 file changed, 104 insertions(+), 56 deletions(-)
diff --git a/northd/northd.c b/northd/northd.c
index b0d43511c..a7be29619 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -9883,6 +9883,48 @@ build_lswitch_lflows_admission_control(struct
ovn_datapath *od,
lflow_ref);
}
+static void
+build_arp_nd_service_monitor_lflow(const char *svc_monitor_mac,
+ const char *svc_src_ip,
+ struct ds *action,
+ struct ds *match,
+ bool is_ipv4)
+{
+ if (is_ipv4) {
+ ds_put_format(match, "arp.tpa == %s && arp.op == 1",
+ svc_src_ip);
+ ds_put_format(action,
+ "eth.dst = eth.src; "
+ "eth.src = %s; "
+ "arp.op = 2; /* ARP reply */ "
+ "arp.tha = arp.sha; "
+ "arp.sha = %s; "
+ "arp.tpa = arp.spa; "
+ "arp.spa = %s; "
+ "outport = inport; "
+ "flags.loopback = 1; "
+ "output;",
+ svc_monitor_mac, svc_monitor_mac,
+ svc_src_ip);
+ } else {
+ ds_put_format(match, "nd_ns && nd.target == %s",
+ svc_src_ip);
+ ds_put_format(action,
+ "nd_na { "
+ "eth.dst = eth.src; "
+ "eth.src = %s; "
+ "ip6.src = %s; "
+ "nd.target = %s; "
+ "nd.tll = %s; "
+ "outport = inport; "
+ "flags.loopback = 1; "
+ "output; "
+ "};",
+ svc_monitor_mac, svc_src_ip,
+ svc_src_ip, svc_monitor_mac);
+ }
+}
+
/* Ingress table 19: ARP/ND responder, skip requests coming from localnet
* ports. (priority 100); see ovn-northd.8.xml for the rationale. */
@@ -10253,12 +10295,12 @@ build_lswitch_arp_nd_responder_default(struct ovn_datapath *od,
/* Ingress table 19: ARP/ND responder for service monitor source ip.
* (priority 110)*/
static void
-build_lswitch_arp_nd_service_monitor(const struct ovn_lb_datapaths *lb_dps,
- const struct hmap *ls_ports,
- const char *svc_monitor_mac,
- struct lflow_table *lflows,
- struct ds *actions,
- struct ds *match)
+build_lswitch_arp_nd_local_svc_mon(const struct ovn_lb_datapaths *lb_dps,
+ const struct hmap *ls_ports,
+ const char *svc_monitor_mac,
+ struct lflow_table *lflows,
+ struct ds *actions,
+ struct ds *match)
{
const struct ovn_northd_lb *lb = lb_dps->lb;
for (size_t i = 0; i < lb->n_vips; i++) {
@@ -10284,41 +10326,11 @@ build_lswitch_arp_nd_service_monitor(const struct
ovn_lb_datapaths *lb_dps,
ds_clear(match);
ds_clear(actions);
- if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
- ds_put_format(match, "arp.tpa == %s && arp.op == 1",
- backend_nb->svc_mon_src_ip);
- ds_put_format(actions,
- "eth.dst = eth.src; "
- "eth.src = %s; "
- "arp.op = 2; /* ARP reply */ "
- "arp.tha = arp.sha; "
- "arp.sha = %s; "
- "arp.tpa = arp.spa; "
- "arp.spa = %s; "
- "outport = inport; "
- "flags.loopback = 1; "
- "output;",
- svc_monitor_mac, svc_monitor_mac,
- backend_nb->svc_mon_src_ip);
- } else {
- ds_put_format(match, "nd_ns && nd.target == %s",
- backend_nb->svc_mon_src_ip);
- ds_put_format(actions,
- "nd_na { "
- "eth.dst = eth.src; "
- "eth.src = %s; "
- "ip6.src = %s; "
- "nd.target = %s; "
- "nd.tll = %s; "
- "outport = inport; "
- "flags.loopback = 1; "
- "output; "
- "};",
- svc_monitor_mac,
- backend_nb->svc_mon_src_ip,
- backend_nb->svc_mon_src_ip,
- svc_monitor_mac);
- }
+
+ build_arp_nd_service_monitor_lflow(svc_monitor_mac,
+ backend_nb->svc_mon_src_ip, actions, match,
+ IN6_IS_ADDR_V4MAPPED(&lb_vip->vip) ? true : false);
+
ovn_lflow_add_with_hint(lflows,
op->od,
S_SWITCH_IN_ARP_ND_RSP, 110,
@@ -10329,6 +10341,37 @@ build_lswitch_arp_nd_service_monitor(const struct
ovn_lb_datapaths *lb_dps,
}
}
+static void
+build_lswitch_arp_nd_ic_learned_svc_mon(struct hmap *ic_learned_svcs_map,
+ const struct hmap *ls_ports,
+ const char *svc_monitor_mac,
+ struct lflow_table *lflows,
+ struct lflow_ref *lflow_ref)
+{
+ struct ds action = DS_EMPTY_INITIALIZER;
+ struct ds match = DS_EMPTY_INITIALIZER;
+
+ struct service_monitor_info *mon_info;
+ HMAP_FOR_EACH (mon_info, hmap_node, ic_learned_svcs_map) {
+ struct ovn_port *op = ovn_port_find(ls_ports,
+ mon_info->sbrec_mon->logical_port);
Please add a NULL check for op here. If ip_port_mappings are
misconfigured, and a non-existent logical port name is used, then this
could result in a NULL return.
+
+ bool is_ipv4 = strchr(mon_info->sbrec_mon->ip, '.') ? true : false;
+
+ build_arp_nd_service_monitor_lflow(svc_monitor_mac,
+ mon_info->sbrec_mon->src_ip,
+ &action, &match, is_ipv4);
In build_lswitch_arp_nd_service_monitor(), there are checks performed to
ensure that health checks are enabled for a particular VIP before
installing the ARP responder flow. I'm curious why such checks are not
performed for remote service monitors.
+
+ ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP,
+ 110, ds_cstr(&match), ds_cstr(&action), lflow_ref);
+
+ ds_clear(&match);
+ ds_clear(&action);
+ }
+
+ ds_destroy(&match);
+ ds_destroy(&action);
+}
/* Logical switch ingress table 20 and 21: DHCP options and response
* priority 100 flows. */
@@ -18307,12 +18350,12 @@ build_lflows_thread(void *arg)
if (stop_parallel_processing()) {
return NULL;
}
- build_lswitch_arp_nd_service_monitor(lb_dps,
- lsi->ls_ports,
- lsi->svc_monitor_mac,
- lsi->lflows,
- &lsi->match,
- &lsi->actions);
+ build_lswitch_arp_nd_local_svc_mon(lb_dps,
+ lsi->ls_ports,
+ lsi->svc_monitor_mac,
+ lsi->lflows,
+ &lsi->match,
+ &lsi->actions);
build_lrouter_defrag_flows_for_lb(lb_dps, lsi->lflows,
lsi->lr_datapaths,
&lsi->match);
@@ -18554,10 +18597,10 @@ build_lswitch_and_lrouter_flows(
stopwatch_stop(LFLOWS_PORTS_STOPWATCH_NAME, time_msec());
stopwatch_start(LFLOWS_LBS_STOPWATCH_NAME, time_msec());
HMAP_FOR_EACH (lb_dps, hmap_node, lb_dps_map) {
- build_lswitch_arp_nd_service_monitor(lb_dps, lsi.ls_ports,
- lsi.svc_monitor_mac,
- lsi.lflows, &lsi.actions,
- &lsi.match);
+ build_lswitch_arp_nd_local_svc_mon(lb_dps, lsi.ls_ports,
+ lsi.svc_monitor_mac,
+ lsi.lflows, &lsi.actions,
+ &lsi.match);
build_lrouter_defrag_flows_for_lb(lb_dps, lsi.lflows,
lsi.lr_datapaths, &lsi.match);
build_lrouter_flows_for_lb(lb_dps, lsi.lflows, lsi.meter_groups,
@@ -18689,7 +18732,12 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn,
build_igmp_lflows(input_data->igmp_groups,
&input_data->ls_datapaths->datapaths,
lflows, input_data->igmp_lflow_ref);
-
+ build_lswitch_arp_nd_ic_learned_svc_mon(
+ input_data->ic_learned_svcs,
+ input_data->ls_ports,
+ input_data->svc_monitor_mac,
+ lflows,
+ input_data->ic_leared_svcs_lflow_ref);
if (parallelization_state == STATE_INIT_HASH_SIZES) {
parallelization_state = STATE_USE_PARALLELIZATION;
}
@@ -18923,10 +18971,10 @@ lflow_handle_northd_lb_changes(struct ovsdb_idl_txn
*ovnsb_txn,
struct ds match = DS_EMPTY_INITIALIZER;
struct ds actions = DS_EMPTY_INITIALIZER;
- build_lswitch_arp_nd_service_monitor(lb_dps, lflow_input->ls_ports,
- lflow_input->svc_monitor_mac,
- lflows, &actions,
- &match);
+ build_lswitch_arp_nd_local_svc_mon(lb_dps, lflow_input->ls_ports,
+ lflow_input->svc_monitor_mac,
+ lflows, &actions,
+ &match);
build_lrouter_defrag_flows_for_lb(lb_dps, lflows,
lflow_input->lr_datapaths, &match);
build_lrouter_flows_for_lb(lb_dps, lflows,
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev