From: Numan Siddique <num...@ovn.org> This patch adds a new table 'Load_Balancer' in SB DB and syncs the Load_Balancer table rows from NB DB to SB DB. An upcoming patch will make use of this table for handling the load balancer hairpin traffic.
Co-authored-by: Dumitru Ceara <dce...@redhat.com> Signed-off-by: Dumitru Ceara <dce...@redhat.com> Signed-off-by: Numan Siddique <num...@ovn.org> --- northd/ovn-northd.c | 114 ++++++++++++++++++++++++++++++++++++++++-- ovn-sb.ovsschema | 27 +++++++++- ovn-sb.xml | 45 +++++++++++++++++ tests/ovn-northd.at | 87 ++++++++++++++++++++++++++++++++ utilities/ovn-sbctl.c | 3 ++ 5 files changed, 270 insertions(+), 6 deletions(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 4d4190cb9b..7f470afe89 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -3324,9 +3324,14 @@ struct ovn_lb { struct hmap_node hmap_node; const struct nbrec_load_balancer *nlb; /* May be NULL. */ + const struct sbrec_load_balancer *slb; /* May be NULL. */ char *selection_fields; struct lb_vip *vips; size_t n_vips; + + size_t n_dps; + size_t n_allocated_dps; + const struct sbrec_datapath_binding **dps; }; struct lb_vip { @@ -3353,7 +3358,7 @@ struct lb_vip_backend { static inline struct ovn_lb * -ovn_lb_find(struct hmap *lbs, struct uuid *uuid) +ovn_lb_find(struct hmap *lbs, const struct uuid *uuid) { struct ovn_lb *lb; size_t hash = uuid_hash(uuid); @@ -3366,6 +3371,14 @@ ovn_lb_find(struct hmap *lbs, struct uuid *uuid) return NULL; } +static void +ovn_lb_add_datapath(struct ovn_lb *lb, struct ovn_datapath *od) +{ + if (lb->n_allocated_dps == lb->n_dps) { + lb->dps = x2nrealloc(lb->dps, &lb->n_allocated_dps, sizeof *lb->dps); + } + lb->dps[lb->n_dps++] = od->sb; +} struct service_monitor_info { struct hmap_node hmap_node; @@ -3594,6 +3607,7 @@ ovn_lb_destroy(struct ovn_lb *lb) } free(lb->vips); free(lb->selection_fields); + free(lb->dps); } static void build_lb_vip_ct_lb_actions(struct lb_vip *lb_vip, @@ -3639,8 +3653,8 @@ static void build_lb_vip_ct_lb_actions(struct lb_vip *lb_vip, } static void -build_ovn_lbs(struct northd_context *ctx, struct hmap *ports, - struct hmap *lbs) +build_ovn_lbs(struct northd_context *ctx, struct hmap *datapaths, + struct hmap *ports, struct hmap *lbs) { hmap_init(lbs); struct hmap monitor_map = HMAP_INITIALIZER(&monitor_map); @@ -3661,6 +3675,88 @@ build_ovn_lbs(struct northd_context *ctx, struct hmap *ports, ovn_lb_create(ctx, lbs, nbrec_lb, ports, &monitor_map); } + struct ovn_datapath *od; + HMAP_FOR_EACH (od, key_node, datapaths) { + if (!od->nbs) { + continue; + } + + for (size_t i = 0; i < od->nbs->n_load_balancer; i++) { + const struct uuid *lb_uuid = + &od->nbs->load_balancer[i]->header_.uuid; + struct ovn_lb *lb = ovn_lb_find(lbs, lb_uuid); + + ovn_lb_add_datapath(lb, od); + } + } + + struct ovn_lb *lb; + + /* Delete any stale SB load balancer rows. */ + const struct sbrec_load_balancer *sbrec_lb, *next; + SBREC_LOAD_BALANCER_FOR_EACH_SAFE (sbrec_lb, next, ctx->ovnsb_idl) { + const char *nb_lb_uuid = smap_get(&sbrec_lb->external_ids, "lb_id"); + struct uuid lb_uuid; + if (!nb_lb_uuid || !uuid_from_string(&lb_uuid, nb_lb_uuid)) { + sbrec_load_balancer_delete(sbrec_lb); + continue; + } + + lb = ovn_lb_find(lbs, &lb_uuid); + if (lb && lb->n_dps) { + lb->slb = sbrec_lb; + } else { + sbrec_load_balancer_delete(sbrec_lb); + } + } + + /* Create SB Load balancer records if not present and sync + * the SB load balancer columns. */ + HMAP_FOR_EACH (lb, hmap_node, lbs) { + if (!lb->n_dps) { + continue; + } + + if (!lb->slb) { + sbrec_lb = sbrec_load_balancer_insert(ctx->ovnsb_txn); + lb->slb = sbrec_lb; + char *lb_id = xasprintf( + UUID_FMT, UUID_ARGS(&lb->nlb->header_.uuid)); + const struct smap external_ids = + SMAP_CONST1(&external_ids, "lb_id", lb_id); + sbrec_load_balancer_set_external_ids(sbrec_lb, &external_ids); + free(lb_id); + } + sbrec_load_balancer_set_name(lb->slb, lb->nlb->name); + sbrec_load_balancer_set_vips(lb->slb, &lb->nlb->vips); + sbrec_load_balancer_set_protocol(lb->slb, lb->nlb->protocol); + sbrec_load_balancer_set_datapaths( + lb->slb, (struct sbrec_datapath_binding **)lb->dps, + lb->n_dps); + } + + /* Set the list of associated load balanacers to a logical switch + * datapath binding in the SB DB. */ + HMAP_FOR_EACH (od, key_node, datapaths) { + if (!od->nbs) { + continue; + } + + const struct sbrec_load_balancer **sbrec_lbs = + xmalloc(od->nbs->n_load_balancer * sizeof *sbrec_lbs); + for (size_t i = 0; i < od->nbs->n_load_balancer; i++) { + const struct uuid *lb_uuid = + &od->nbs->load_balancer[i]->header_.uuid; + lb = ovn_lb_find(lbs, lb_uuid); + sbrec_lbs[i] = lb->slb; + } + + sbrec_datapath_binding_set_load_balancers( + od->sb, (struct sbrec_load_balancer **)sbrec_lbs, + od->nbs->n_load_balancer); + free(sbrec_lbs); + } + struct service_monitor_info *mon_info; HMAP_FOR_EACH_POP (mon_info, hmap_node, &monitor_map) { if (!mon_info->required) { @@ -12155,7 +12251,7 @@ ovnnb_db_run(struct northd_context *ctx, build_datapaths(ctx, datapaths, lr_list); build_ports(ctx, sbrec_chassis_by_name, datapaths, ports); - build_ovn_lbs(ctx, ports, &lbs); + build_ovn_lbs(ctx, datapaths, ports, &lbs); build_ipam(datapaths, ports); build_port_group_lswitches(ctx, &port_groups, ports); build_lrouter_groups(ports, lr_list); @@ -12931,6 +13027,8 @@ main(int argc, char *argv[]) ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_datapath_binding); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_datapath_binding_col_tunnel_key); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_datapath_binding_col_load_balancers); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_datapath_binding_col_external_ids); @@ -13098,6 +13196,14 @@ main(int argc, char *argv[]) add_column_noalert(ovnsb_idl_loop.idl, &sbrec_service_monitor_col_external_ids); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_load_balancer); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_datapaths); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_name); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_vips); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_protocol); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_load_balancer_col_external_ids); + struct ovsdb_idl_index *sbrec_chassis_by_name = chassis_index_create(ovnsb_idl_loop.idl); diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index d1c506a22c..a1ee8d8d1f 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "2.10.0", - "cksum": "2548342632 22615", + "version": "2.11.0", + "cksum": "455413803 23814", "tables": { "SB_Global": { "columns": { @@ -152,6 +152,11 @@ "type": {"key": {"type": "integer", "minInteger": 1, "maxInteger": 16777215}}}, + "load_balancers": {"type": {"key": {"type": "uuid", + "refTable": "Load_Balancer", + "refType": "weak"}, + "min": 0, + "max": "unlimited"}}, "external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, @@ -447,6 +452,24 @@ "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, "indexes": [["logical_port", "ip", "port", "protocol"]], + "isRoot": true}, + "Load_Balancer": { + "columns": { + "name": {"type": "string"}, + "vips": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}, + "protocol": { + "type": {"key": {"type": "string", + "enum": ["set", ["tcp", "udp", "sctp"]]}, + "min": 0, "max": 1}}, + "datapaths": { + "type": {"key": {"type": "uuid", + "refTable": "Datapath_Binding"}, + "min": 0, "max": "unlimited"}}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, "isRoot": true} } } diff --git a/ovn-sb.xml b/ovn-sb.xml index ebe2893e3c..b8fd7e873b 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -2500,6 +2500,12 @@ tcp.flags = RST; constructed for each supported encapsulation. </column> + <column name="load_balancers"> + <p> + Load balancers associated with the datapath. + </p> + </column> + <group title="OVN_Northbound Relationship"> <p> Each row in <ref table="Datapath_Binding"/> is associated with some @@ -4129,4 +4135,43 @@ tcp.flags = RST; </column> </group> </table> + + <table name="Load_Balancer"> + <p> + Each row represents a load balancer. + </p> + + <column name="name"> + A name for the load balancer. This name has no special meaning or + purpose other than to provide convenience for human interaction with + the ovn-nb database. + </column> + + <column name="vips"> + A map of virtual IP addresses (and an optional port number with + <code>:</code> as a separator) associated with this load balancer and + their corresponding endpoint IP addresses (and optional port numbers + with <code>:</code> as separators) separated by commas. + </column> + + <column name="protocol"> + <p> + Valid protocols are <code>tcp</code>, <code>udp</code>, or + <code>sctp</code>. This column is useful when a port number is + provided as part of the <code>vips</code> column. If this column is + empty and a port number is provided as part of <code>vips</code> + column, OVN assumes the protocol to be <code>tcp</code>. + </p> + </column> + + <column name="datapaths"> + Datapaths to which this load balancer applies to. + </column> + + <group title="Common Columns"> + <column name="external_ids"> + See <em>External IDs</em> at the beginning of this document. + </column> + </group> + </table> </database> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 26376c3671..aba9283d2a 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -1914,4 +1914,91 @@ AT_CHECK( [ovn-nbctl --wait=sb set logical-switch-port lsp01 options:requested-tnl-key=2]) get_tunnel_keys AT_CHECK([test $lsp02 = 3 && test $ls1 = 123]) + +AT_CLEANUP + +AT_SETUP([ovn -- NB to SB load balancer sync]) +ovn_start + +check ovn-nbctl --wait=hv lb-add lb0 10.0.0.10:80 10.0.0.4:8080 +check_row_count nb:load_balancer 1 + +echo +echo "__file__:__line__: Check that there are no SB load balancer rows." +check_row_count sb:load_balancer 0 + +check ovn-nbctl ls-add sw0 +check ovn-nbctl --wait=hv ls-lb-add sw0 lb0 +sw0_sb_uuid=$(fetch_column datapath_binding _uuid external_ids:name=sw0) + +echo +echo "__file__:__line__: Check that there are is SB load balancer row for lb0." +check_row_count sb:load_balancer 1 +check_column "10.0.0.10:80=10.0.0.4:8080 tcp" sb:load_balancer vips,protocol name=lb0 + +lb0_uuid=$(fetch_column sb:load_balancer _uuid name=lb0) + +echo +echo "__file__:__line__: Check that SB lb0 has sw0 in datapaths column." + +check_column "$sw0_sb_uuid" sb:load_balancer datapaths name=lb0 +check_column "$lb0_uuid" sb:datapath_binding load_balancers external_ids:name=sw0 + +check ovn-nbctl --wait=sb set load_balancer . vips:"10.0.0.20\:90"="20.0.0.4:8080,30.0.0.4:8080" + +echo +echo "__file__:__line__: Check that SB lb0 has vips and protocol columns are set properly." + +check_column "10.0.0.10:80=10.0.0.4:8080 10.0.0.20:90=20.0.0.4:8080,30.0.0.4:8080 tcp" \ +sb:load_balancer vips,protocol name=lb0 + +check ovn-nbctl lr-add lr0 +check ovn-nbctl --wait=sb lr-lb-add lr0 lb0 + +echo +echo "__file__:__line__: Check that SB lb0 has only sw0 in datapaths column." +check_column "$sw0_sb_uuid" sb:load_balancer datapaths name=lb0 + +check ovn-nbctl ls-add sw1 +check ovn-nbctl --wait=sb ls-lb-add sw1 lb0 +sw1_sb_uuid=$(fetch_column datapath_binding _uuid external_ids:name=sw1) + +echo +echo "__file__:__line__: Check that SB lb0 has sw0 and sw1 in datapaths column." +check_column "$sw0_sb_uuid $sw1_sb_uuid" sb:load_balancer datapaths name=lb0 +check_column "$lb0_uuid" sb:datapath_binding load_balancers external_ids:name=sw1 + +check ovn-nbctl --wait=sb lb-add lb1 10.0.0.30:80 20.0.0.50:8080 udp +check_row_count sb:load_balancer 1 + +check ovn-nbctl --wait=sb lr-lb-add lr0 lb1 +check_row_count sb:load_balancer 1 + +echo +echo "__file__:__line__: Associate lb1 to sw1 and check that lb1 is created in SB DB." + +check ovn-nbctl --wait=sb ls-lb-add sw1 lb1 +check_row_count sb:load_balancer 2 + +echo +echo "__file__:__line__: Check that SB lb1 has vips and protocol columns are set properly." +check_column "10.0.0.30:80=20.0.0.50:8080 udp" sb:load_balancer vips,protocol name=lb1 + +lb1_uuid=$(fetch_column sb:load_balancer _uuid name=lb1) + +echo +echo "__file__:__line__: Check that SB lb1 has sw1 in datapaths column." + +check_column "$sw1_sb_uuid" sb:load_balancer datapaths name=lb1 + +echo +echo "__file__:__line__: check that datapath sw1 has lb0 and lb1 set in the load_balancers column." +check_column "$lb0_uuid $lb1_uuid" sb:datapath_binding load_balancers external_ids:name=sw1 + +echo +echo "__file__:__line__: Delete load balancer lb1 an check that datapath sw1's load_balancers are updated accordingly." + +ovn-nbctl --wait=sb lb-del lb1 +check_column "$lb0_uuid" sb:datapath_binding load_balancers external_ids:name=sw1 + AT_CLEANUP diff --git a/utilities/ovn-sbctl.c b/utilities/ovn-sbctl.c index 85e448ec04..00c112c7e5 100644 --- a/utilities/ovn-sbctl.c +++ b/utilities/ovn-sbctl.c @@ -1441,6 +1441,9 @@ static const struct ctl_table_class tables[SBREC_N_TABLES] = { [SBREC_TABLE_GATEWAY_CHASSIS].row_ids[0] = {&sbrec_gateway_chassis_col_name, NULL, NULL}, + + [SBREC_TABLE_LOAD_BALANCER].row_ids[0] + = {&sbrec_load_balancer_col_name, NULL, NULL}, }; -- 2.28.0 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev