get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/1525569/
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1525569,
    "url": "http://patchwork.ozlabs.org/api/patches/1525569/",
    "web_url": "http://patchwork.ozlabs.org/project/ovn/patch/20210907224516.489604-2-blp@ovn.org/",
    "project": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/projects/68/",
        "name": "Open Virtual Network development",
        "link_name": "ovn",
        "list_id": "ovs-dev.openvswitch.org",
        "list_email": "ovs-dev@openvswitch.org",
        "web_url": "http://openvswitch.org/",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20210907224516.489604-2-blp@ovn.org>",
    "list_archive_url": null,
    "date": "2021-09-07T22:45:07",
    "name": "[ovs-dev,v2,01/10] ovn-northd-ddlog: Intern all strings in OVSDB tables.",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "50653f5ac85fc109f83eed1ac567fe70d011140b",
    "submitter": {
        "id": 67603,
        "url": "http://patchwork.ozlabs.org/api/people/67603/",
        "name": "Ben Pfaff",
        "email": "blp@ovn.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/ovn/patch/20210907224516.489604-2-blp@ovn.org/mbox/",
    "series": [
        {
            "id": 261352,
            "url": "http://patchwork.ozlabs.org/api/series/261352/",
            "web_url": "http://patchwork.ozlabs.org/project/ovn/list/?series=261352",
            "date": "2021-09-07T22:45:06",
            "name": "3x performance improvement for ddlog with load balancer benchmark",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/261352/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1525569/comments/",
    "check": "fail",
    "checks": "http://patchwork.ozlabs.org/api/patches/1525569/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<ovs-dev-bounces@openvswitch.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "dev@openvswitch.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "ovs-dev@lists.linuxfoundation.org"
        ],
        "Authentication-Results": "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=140.211.166.136; helo=smtp3.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN>)",
        "Received": [
            "from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 4H40jV0pCSz9t10\n\tfor <incoming@patchwork.ozlabs.org>; Wed,  8 Sep 2021 08:45:49 +1000 (AEST)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp3.osuosl.org (Postfix) with ESMTP id 035A261388;\n\tTue,  7 Sep 2021 22:45:46 +0000 (UTC)",
            "from smtp3.osuosl.org ([127.0.0.1])\n\tby localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id PNOyqAKSjZev; Tue,  7 Sep 2021 22:45:40 +0000 (UTC)",
            "from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])\n\tby smtp3.osuosl.org (Postfix) with ESMTPS id 22DF5607B1;\n\tTue,  7 Sep 2021 22:45:39 +0000 (UTC)",
            "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 99F0BC002C;\n\tTue,  7 Sep 2021 22:45:36 +0000 (UTC)",
            "from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 1E2B9C0027\n for <dev@openvswitch.org>; Tue,  7 Sep 2021 22:45:35 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp2.osuosl.org (Postfix) with ESMTP id 4877A40243\n for <dev@openvswitch.org>; Tue,  7 Sep 2021 22:45:33 +0000 (UTC)",
            "from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n with ESMTP id GyL2ZPPUO_EH for <dev@openvswitch.org>;\n Tue,  7 Sep 2021 22:45:30 +0000 (UTC)",
            "from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net\n [217.70.183.201])\n by smtp2.osuosl.org (Postfix) with ESMTPS id 88F1940219\n for <dev@openvswitch.org>; Tue,  7 Sep 2021 22:45:29 +0000 (UTC)",
            "(Authenticated sender: blp@ovn.org)\n by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id CEFD51BF204;\n Tue,  7 Sep 2021 22:45:25 +0000 (UTC)"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.8.0",
        "From": "Ben Pfaff <blp@ovn.org>",
        "To": "dev@openvswitch.org",
        "Date": "Tue,  7 Sep 2021 15:45:07 -0700",
        "Message-Id": "<20210907224516.489604-2-blp@ovn.org>",
        "X-Mailer": "git-send-email 2.31.1",
        "In-Reply-To": "<20210907224516.489604-1-blp@ovn.org>",
        "References": "<20210907224516.489604-1-blp@ovn.org>",
        "MIME-Version": "1.0",
        "Cc": "Leonid Ryzhyk <lryzhyk@vmware.com>, Ben Pfaff <blp@ovn.org>",
        "Subject": "[ovs-dev] [PATCH ovn v2 01/10] ovn-northd-ddlog: Intern all strings\n\tin OVSDB tables.",
        "X-BeenThere": "ovs-dev@openvswitch.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "<ovs-dev.openvswitch.org>",
        "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>",
        "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>",
        "List-Post": "<mailto:ovs-dev@openvswitch.org>",
        "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>",
        "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "ovs-dev-bounces@openvswitch.org",
        "Sender": "\"dev\" <ovs-dev-bounces@openvswitch.org>"
    },
    "content": "From: Leonid Ryzhyk <lryzhyk@vmware.com>\n\nThe ovsdb2ddlog compiler now represents all OVSDB strings as `istring`\ninstead of `string`.  This commit fixes type errors resulting from that\nchange.  ovn-northd-ddlog should be somewhat faster and leaner now.\n\nSigned-off-by: Leonid Ryzhyk <lryzhyk@vmware.com>\nSigned-off-by: Ben Pfaff <blp@ovn.org>\n---\n configure.ac         |    2 +-\n manpages.mk          |    1 -\n northd/copp.dl       |   32 +-\n northd/helpers.dl    |   14 +-\n northd/ipam.dl       |   17 +-\n northd/lrouter.dl    |  133 ++--\n northd/lswitch.dl    |  149 ++--\n northd/multicast.dl  |   44 +-\n northd/ovn-nb.dlopts |    1 +\n northd/ovn-sb.dlopts |    1 +\n northd/ovn.dl        |    7 +\n northd/ovn_northd.dl | 1541 +++++++++++++++++++++---------------------\n northd/ovsdb2ddlog2c |    6 +-\n tests/ovn-ic.at      |    8 +-\n tests/ovn.at         |    6 +-\n 15 files changed, 980 insertions(+), 982 deletions(-)",
    "diff": "diff --git a/configure.ac b/configure.ac\nindex df0b98295..4728fa0a6 100644\n--- a/configure.ac\n+++ b/configure.ac\n@@ -169,7 +169,7 @@ OVS_CONDITIONAL_CC_OPTION([-Wno-unused-parameter], [HAVE_WNO_UNUSED_PARAMETER])\n OVS_ENABLE_WERROR\n OVS_ENABLE_SPARSE\n \n-OVS_CHECK_DDLOG([0.38])\n+OVS_CHECK_DDLOG([0.47])\n OVS_CHECK_PRAGMA_MESSAGE\n OVN_CHECK_OVS\n OVS_CTAGS_IDENTIFIERS\ndiff --git a/manpages.mk b/manpages.mk\nindex 3334b38f9..9f7a0ced3 100644\n--- a/manpages.mk\n+++ b/manpages.mk\n@@ -9,4 +9,3 @@ utilities/ovn-detrace.1.in:\n lib/common-syn.man:\n lib/common.man:\n lib/ovs.tmac:\n-\ndiff --git a/northd/copp.dl b/northd/copp.dl\nindex ffb9fb32e..c4f3b7e70 100644\n--- a/northd/copp.dl\n+++ b/northd/copp.dl\n@@ -12,19 +12,19 @@\n  * limitations under the License.\n  */\n \n-function cOPP_ARP() : string { \"arp\" }\n-function cOPP_ARP_RESOLVE() : string { \"arp-resolve\" }\n-function cOPP_DHCPV4_OPTS() : string { \"dhcpv4-opts\" }\n-function cOPP_DHCPV6_OPTS() : string { \"dhcpv6-opts\" }\n-function cOPP_DNS() : string { \"dns\" }\n-function cOPP_EVENT_ELB() : string { \"event-elb\" }\n-function cOPP_ICMP4_ERR() : string { \"icmp4-error\" }\n-function cOPP_ICMP6_ERR() : string { \"icmp6-error\" }\n-function cOPP_IGMP() : string { \"igmp\" }\n-function cOPP_ND_NA() : string { \"nd-na\" }\n-function cOPP_ND_NS() : string { \"nd-ns\" }\n-function cOPP_ND_NS_RESOLVE() : string { \"nd-ns-resolve\" }\n-function cOPP_ND_RA_OPTS() : string { \"nd-ra-opts\" }\n-function cOPP_TCP_RESET() : string { \"tcp-reset\" }\n-function cOPP_REJECT() : string { \"reject\" }\n-function cOPP_BFD() : string { \"bfd\" }\n+function cOPP_ARP() : istring { i\"arp\" }\n+function cOPP_ARP_RESOLVE() : istring { i\"arp-resolve\" }\n+function cOPP_DHCPV4_OPTS() : istring { i\"dhcpv4-opts\" }\n+function cOPP_DHCPV6_OPTS() : istring { i\"dhcpv6-opts\" }\n+function cOPP_DNS() : istring { i\"dns\" }\n+function cOPP_EVENT_ELB() : istring { i\"event-elb\" }\n+function cOPP_ICMP4_ERR() : istring { i\"icmp4-error\" }\n+function cOPP_ICMP6_ERR() : istring { i\"icmp6-error\" }\n+function cOPP_IGMP() : istring { i\"igmp\" }\n+function cOPP_ND_NA() : istring { i\"nd-na\" }\n+function cOPP_ND_NS() : istring { i\"nd-ns\" }\n+function cOPP_ND_NS_RESOLVE() : istring { i\"nd-ns-resolve\" }\n+function cOPP_ND_RA_OPTS() : istring { i\"nd-ra-opts\" }\n+function cOPP_TCP_RESET() : istring { i\"tcp-reset\" }\n+function cOPP_REJECT() : istring { i\"reject\" }\n+function cOPP_BFD() : istring { i\"bfd\" }\ndiff --git a/northd/helpers.dl b/northd/helpers.dl\nindex 757532e46..50e137d99 100644\n--- a/northd/helpers.dl\n+++ b/northd/helpers.dl\n@@ -21,15 +21,15 @@ import ovn\n output relation Warning[string]\n \n /* Switch-to-router logical port connections */\n-relation SwitchRouterPeer(lsp: uuid, lsp_name: string, lrp: uuid)\n+relation SwitchRouterPeer(lsp: uuid, lsp_name: istring, lrp: uuid)\n SwitchRouterPeer(lsp, lsp_name, lrp) :-\n-    &nb::Logical_Switch_Port(._uuid = lsp, .name = lsp_name, .__type = \"router\", .options = options),\n-    Some{var router_port} = options.get(\"router-port\"),\n+    &nb::Logical_Switch_Port(._uuid = lsp, .name = lsp_name, .__type = i\"router\", .options = options),\n+    Some{var router_port} = options.get(i\"router-port\"),\n     &nb::Logical_Router_Port(.name = router_port, ._uuid = lrp).\n \n-function get_bool_def(m: Map<string, string>, k: string, def: bool): bool = {\n+function get_bool_def(m: Map<istring, istring>, k: istring, def: bool): bool = {\n     m.get(k)\n-     .and_then(|x| match (str_to_lower(x)) {\n+     .and_then(|x| match (x.to_lowercase()) {\n                        \"false\" -> Some{false},\n                        \"true\" -> Some{true},\n                        _ -> None\n@@ -37,8 +37,8 @@ function get_bool_def(m: Map<string, string>, k: string, def: bool): bool = {\n      .unwrap_or(def)\n }\n \n-function get_int_def(m: Map<string, string>, k: string, def: integer): integer = {\n-    m.get(k).and_then(parse_dec_u64).unwrap_or(def)\n+function get_int_def(m: Map<istring, istring>, k: istring, def: integer): integer = {\n+    m.get(k).and_then(|v| v.ival().parse_dec_u64()).unwrap_or(def)\n }\n \n function clamp(x: 'A, range: ('A, 'A)): 'A {\ndiff --git a/northd/ipam.dl b/northd/ipam.dl\nindex 4665a28cb..600c55f5c 100644\n--- a/northd/ipam.dl\n+++ b/northd/ipam.dl\n@@ -101,9 +101,9 @@ SwitchIPv4ReservedAddress(.lswitch = sw._uuid,\n     var exclude_ips = {\n         var exclude_ips = set_singleton(start_ipv4);\n         exclude_ips.insert(start_ipv4 + total_ipv4s - 1);\n-        match (map_get(sw.other_config, \"exclude_ips\")) {\n+        match (map_get(sw.other_config, i\"exclude_ips\")) {\n             None -> exclude_ips,\n-            Some{exclude_ip_list} -> match (parse_ip_list(exclude_ip_list)) {\n+            Some{exclude_ip_list} -> match (parse_ip_list(exclude_ip_list.ival())) {\n                 Left{err} -> {\n                     warn(\"logical switch ${uuid2str(sw._uuid)}: bad exclude_ips (${err})\");\n                     exclude_ips\n@@ -297,18 +297,17 @@ SwitchPortNewIPv4DynAddress(lsport, addr) :-\n  * Dynamic MAC address allocation.\n  */\n \n-function get_mac_prefix(options: Map<string,string>, uuid: uuid) : bit<48> =\n+function get_mac_prefix(options: Map<istring,istring>, uuid: uuid) : bit<48>\n {\n-    match (map_get(options, \"mac_prefix\").and_then(scan_eth_addr_prefix)) {\n+    match (map_get(options, i\"mac_prefix\").and_then(|pref| pref.ival().scan_eth_addr_prefix())) {\n         Some{prefix} -> prefix.ha,\n         None -> eth_addr_pseudorandom(uuid, 16'h1234).ha & 48'hffffff000000\n     }\n }\n-function put_mac_prefix(options: Map<string,string>, mac_prefix: bit<48>)\n-    : Map<string,string> =\n+function put_mac_prefix(options: mut Map<istring,istring>, mac_prefix: bit<48>)\n {\n-    map_insert_imm(options, \"mac_prefix\",\n-                   string_substr(to_string(EthAddr{mac_prefix}), 0, 8))\n+    map_insert(options, i\"mac_prefix\",\n+               string_substr(to_string(EthAddr{mac_prefix}), 0, 8).intern())\n }\n relation MacPrefix(mac_prefix: bit<48>)\n MacPrefix(get_mac_prefix(options, uuid)) :-\n@@ -436,7 +435,7 @@ SwitchPortNewMACDynAddress(lsp._uuid, mac_addr) :-\n         None -> None,\n         Some{addr} -> {\n             if (sw.subnet.is_some() or sw.ipv6_prefix.is_some() or\n-                map_get(sw.other_config, \"mac_only\") == Some{\"true\"}) {\n+                map_get(sw.other_config, i\"mac_only\") == Some{i\"true\"}) {\n                 Some{addr}\n             } else {\n                 None\ndiff --git a/northd/lrouter.dl b/northd/lrouter.dl\nindex 1835d4c78..cc3dced5f 100644\n--- a/northd/lrouter.dl\n+++ b/northd/lrouter.dl\n@@ -20,6 +20,7 @@ import ovsdb\n import ovn\n import helpers\n import lswitch\n+import set\n \n function is_enabled(lr: nb::Logical_Router): bool { is_enabled(lr.enabled) }\n function is_enabled(lrp: Intern<nb::Logical_Router_Port>): bool { is_enabled(lrp.enabled) }\n@@ -90,11 +91,11 @@ FirstHopLogicalRouter(lrouter, lswitch) :-\n   lrp in &nb::Logical_Router_Port(._uuid = lrp_uuid, .peer = None),\n   LogicalSwitchRouterPort(lsp_uuid, lrp.name, lswitch).\n \n-relation LogicalSwitchRouterPort(lsp: uuid, lsp_router_port: string, ls: uuid)\n+relation LogicalSwitchRouterPort(lsp: uuid, lsp_router_port: istring, ls: uuid)\n LogicalSwitchRouterPort(lsp, lsp_router_port, ls) :-\n   LogicalSwitchPort(lsp, ls),\n-  &nb::Logical_Switch_Port(._uuid = lsp, .__type = \"router\", .options = options),\n-  Some{var lsp_router_port} = options.get(\"router-port\").\n+  &nb::Logical_Switch_Port(._uuid = lsp, .__type = i\"router\", .options = options),\n+  Some{var lsp_router_port} = options.get(i\"router-port\").\n \n /* Undirected edges connecting one router and another.\n  * This is a building block for ConnectedLogicalRouter. */\n@@ -134,7 +135,7 @@ Warning[message] :-\n Warning[message] :-\n     lrp in &nb::Logical_Router_Port(),\n     lrp.ha_chassis_group.is_some() or not lrp.gateway_chassis.is_empty(),\n-    lrp.options.contains_key(\"chassis\"),\n+    lrp.options.contains_key(i\"chassis\"),\n     var message = \"Bad configuration: distributed gateway port configured on \"\n     \"port ${lrp.name} on L3 gateway router\".\n \n@@ -149,7 +150,7 @@ DistributedGatewayPort(lrp, lr_uuid) :-\n     lr in nb::Logical_Router(._uuid = lr_uuid),\n     LogicalRouterPort(lrp_uuid, lr._uuid),\n     lrp in &nb::Logical_Router_Port(._uuid = lrp_uuid),\n-    not lrp.options.contains_key(\"chassis\"),\n+    not lrp.options.contains_key(i\"chassis\"),\n     var has_hcg = lrp.ha_chassis_group.is_some(),\n     var has_gc = not lrp.gateway_chassis.is_empty(),\n     has_hcg or has_gc.\n@@ -166,9 +167,9 @@ DistributedGatewayPort(lrp, lr_uuid) :-\n  * were ever defined. */\n relation HAChassis(hacg_uuid: uuid,\n                    hac_uuid: uuid,\n-                   chassis_name: string,\n+                   chassis_name: istring,\n                    priority: integer,\n-                   external_ids: Map<string,string>)\n+                   external_ids: Map<istring,istring>)\n HAChassis(ha_chassis_group_uuid(lrp._uuid), gw_chassis_uuid,\n           chassis_name, priority, external_ids) :-\n     DistributedGatewayPort(.lrp = lrp),\n@@ -178,7 +179,7 @@ HAChassis(ha_chassis_group_uuid(lrp._uuid), gw_chassis_uuid,\n                        .chassis_name = chassis_name,\n                        .priority = priority,\n                        .external_ids = eids),\n-    var external_ids = eids.insert_imm(\"chassis-name\", chassis_name).\n+    var external_ids = eids.insert_imm(i\"chassis-name\", chassis_name).\n HAChassis(ha_chassis_group_uuid(ha_chassis_group._uuid), ha_chassis_uuid,\n           chassis_name, priority, external_ids) :-\n     DistributedGatewayPort(.lrp = lrp),\n@@ -189,7 +190,7 @@ HAChassis(ha_chassis_group_uuid(ha_chassis_group._uuid), ha_chassis_uuid,\n                   .chassis_name = chassis_name,\n                   .priority = priority,\n                   .external_ids = eids),\n-    var external_ids = eids.insert_imm(\"chassis-name\", chassis_name).\n+    var external_ids = eids.insert_imm(i\"chassis-name\", chassis_name).\n \n /* HAChassisGroup is an abstraction for sb::HA_Chassis_Group that papers over\n  * the two southbound ways to configure it via nb::Gateway_Chassis and\n@@ -202,8 +203,8 @@ HAChassis(ha_chassis_group_uuid(ha_chassis_group._uuid), ha_chassis_uuid,\n  * we omit it so that multiple references get merged.)\n  */\n relation HAChassisGroup(uuid: uuid,\n-                        name: string,\n-                        external_ids: Map<string,string>)\n+                        name: istring,\n+                        external_ids: Map<istring,istring>)\n HAChassisGroup(ha_chassis_group_uuid(lrp._uuid), lrp.name, map_empty()) :-\n     DistributedGatewayPort(.lrp = lrp),\n     lrp.ha_chassis_group == None,\n@@ -274,22 +275,22 @@ LogicalRouterNAT0(lr, nat, external_ip, external_mac) :-\n     nb::Logical_Router(._uuid = lr, .nat = nats),\n     var nat_uuid = FlatMap(nats),\n     nat in &nb::NAT(._uuid = nat_uuid),\n-    Some{var external_ip} = ip46_parse(nat.external_ip),\n+    Some{var external_ip} = ip46_parse(nat.external_ip.ival()),\n     var external_mac = match (nat.external_mac) {\n-        Some{s} -> eth_addr_from_string(s),\n+        Some{s} -> eth_addr_from_string(s.ival()),\n         None -> None\n     }.\n Warning[\"Bad ip address ${nat.external_ip} in nat configuration for router ${lr_name}.\"] :-\n     nb::Logical_Router(._uuid = lr, .nat = nats, .name = lr_name),\n     var nat_uuid = FlatMap(nats),\n     nat in &nb::NAT(._uuid = nat_uuid),\n-    None = ip46_parse(nat.external_ip).\n+    None = ip46_parse(nat.external_ip.ival()).\n Warning[\"Bad MAC address ${s} in nat configuration for router ${lr_name}.\"] :-\n     nb::Logical_Router(._uuid = lr, .nat = nats, .name = lr_name),\n     var nat_uuid = FlatMap(nats),\n     nat in &nb::NAT(._uuid = nat_uuid),\n     Some{var s} = nat.external_mac,\n-    None = eth_addr_from_string(s).\n+    None = eth_addr_from_string(s.ival()).\n \n relation LogicalRouterNAT(lr: uuid, nat: NAT)\n LogicalRouterNAT(lr, NAT{nat, external_ip, external_mac, None}) :-\n@@ -321,10 +322,10 @@ LogicalRouterNATs(lr, vec_empty()) :-\n     nb::Logical_Router(._uuid = lr),\n     not LogicalRouterNAT(lr, _).\n \n-function get_force_snat_ip(options: Map<string,string>, key_type: string): Set<v46_ip> =\n+function get_force_snat_ip(options: Map<istring,istring>, key_type: istring): Set<v46_ip> =\n {\n     var ips = set_empty();\n-    match (options.get(key_type ++ \"_force_snat_ip\")) {\n+    match (options.get(i\"${key_type}_force_snat_ip\")) {\n         None -> (),\n         Some{s} -> {\n             for (token in s.split(\" \")) {\n@@ -338,24 +339,24 @@ function get_force_snat_ip(options: Map<string,string>, key_type: string): Set<v\n     ips\n }\n \n-function has_force_snat_ip(options: Map<string, string>, key_type: string): bool {\n+function has_force_snat_ip(options: Map<istring, istring>, key_type: istring): bool {\n     not get_force_snat_ip(options, key_type).is_empty()\n }\n \n-function lb_force_snat_router_ip(lr_options: Map<string, string>): bool {\n-    lr_options.get(\"lb_force_snat_ip\") == Some{\"router_ip\"} and\n-    lr_options.contains_key(\"chassis\")\n+function lb_force_snat_router_ip(lr_options: Map<istring, istring>): bool {\n+    lr_options.get(i\"lb_force_snat_ip\") == Some{i\"router_ip\"} and\n+    lr_options.contains_key(i\"chassis\")\n }\n \n typedef LBForceSNAT = NoForceSNAT\n                     | ForceSNAT\n                     | SkipSNAT\n \n-function snat_for_lb(lr_options: Map<string, string>, lb: Intern<nb::Load_Balancer>): LBForceSNAT {\n-    if (lb.options.get_bool_def(\"skip_snat\", false)) {\n+function snat_for_lb(lr_options: Map<istring, istring>, lb: Intern<nb::Load_Balancer>): LBForceSNAT {\n+    if (lb.options.get_bool_def(i\"skip_snat\", false)) {\n         return SkipSNAT\n     };\n-    if (not get_force_snat_ip(lr_options, \"lb\").is_empty() or lb_force_snat_router_ip(lr_options)) {\n+    if (not get_force_snat_ip(lr_options, i\"lb\").is_empty() or lb_force_snat_router_ip(lr_options)) {\n         return ForceSNAT\n     };\n     return NoForceSNAT\n@@ -372,15 +373,15 @@ function snat_for_lb(lr_options: Map<string, string>, lb: Intern<nb::Load_Balanc\n relation LogicalRouterSnatIP(lr: uuid, snat_ip: v46_ip, nat: Option<NAT>)\n LogicalRouterSnatIP(lr._uuid, force_snat_ip, None) :-\n     lr in nb::Logical_Router(),\n-    var dnat_force_snat_ips = get_force_snat_ip(lr.options, \"dnat\"),\n+    var dnat_force_snat_ips = get_force_snat_ip(lr.options, i\"dnat\"),\n     var lb_force_snat_ips = if (lb_force_snat_router_ip(lr.options)) {\n         set_empty()\n     } else {\n-        get_force_snat_ip(lr.options, \"lb\")\n+        get_force_snat_ip(lr.options, i\"lb\")\n     },\n     var force_snat_ip = FlatMap(dnat_force_snat_ips.union(lb_force_snat_ips)).\n LogicalRouterSnatIP(lr, snat_ip, Some{nat}) :-\n-    LogicalRouterNAT(lr, nat@NAT{.nat = &nb::NAT{.__type = \"snat\"}, .external_ip = snat_ip}).\n+    LogicalRouterNAT(lr, nat@NAT{.nat = &nb::NAT{.__type = i\"snat\"}, .external_ip = snat_ip}).\n \n function group_to_setunionmap(g: Group<'K1, ('K2,Set<'V>)>): Map<'K2,Set<'V>> {\n     var map = map_empty();\n@@ -420,13 +421,13 @@ LogicalRouterLBs(lr, vec_empty()) :-\n \n // LogicalRouterCopp maps from each LR to its collection of Copp meters,\n // dropping any Copp meter whose meter name doesn't exist.\n-relation LogicalRouterCopp(lr: uuid, meters: Map<string,string>)\n+relation LogicalRouterCopp(lr: uuid, meters: Map<istring,istring>)\n LogicalRouterCopp(lr, meters) :- LogicalRouterCopp0(lr, meters).\n LogicalRouterCopp(lr, map_empty()) :-\n     nb::Logical_Router(._uuid = lr),\n     not LogicalRouterCopp0(lr, _).\n \n-relation LogicalRouterCopp0(lr: uuid, meters: Map<string,string>)\n+relation LogicalRouterCopp0(lr: uuid, meters: Map<istring,istring>)\n LogicalRouterCopp0(lr, meters) :-\n     nb::Logical_Router(._uuid = lr, .copp = Some{copp_uuid}),\n     nb::Copp(._uuid = copp_uuid, .meters = meters),\n@@ -445,18 +446,18 @@ LogicalRouterCopp0(lr, meters) :-\n  *      should always be learned\n  */\n \n-function chassis_redirect_name(port_name: string): string = \"cr-${port_name}\"\n+function chassis_redirect_name(port_name: istring): string = \"cr-${port_name}\"\n \n typedef Router = Router {\n     /* Fields copied from nb::Logical_Router. */\n     _uuid:              uuid,\n-    name:               string,\n+    name:               istring,\n     policies:           Set<uuid>,\n     enabled:            Option<bool>,\n     nat:                Set<uuid>,\n     load_balancer:      Set<uuid>,\n-    options:            Map<string,string>,\n-    external_ids:       Map<string,string>,\n+    options:            Map<istring,istring>,\n+    external_ids:       Map<istring,istring>,\n \n     /* Additional computed fields. */\n     l3dgw_ports:        Vec<Intern<nb::Logical_Router_Port>>,\n@@ -467,7 +468,7 @@ typedef Router = Router {\n     mcast_cfg:          Intern<McastRouterCfg>,\n     learn_from_arp_request: bool,\n     force_lb_snat: bool,\n-    copp:               Map<string, string>,\n+    copp:               Map<istring, istring>,\n }\n \n relation Router[Intern<Router>]\n@@ -483,7 +484,7 @@ Router[Router{\n         .external_ids  =    lr.external_ids,\n \n         .l3dgw_ports = l3dgw_ports,\n-        .is_gateway  = lr.options.contains_key(\"chassis\"),\n+        .is_gateway  = lr.options.contains_key(i\"chassis\"),\n         .nats        = nats,\n         .snat_ips    = snat_ips,\n         .lbs         = lbs,\n@@ -499,7 +500,7 @@ Router[Router{\n     LogicalRouterSnatIPs(lr._uuid, snat_ips),\n     LogicalRouterCopp(lr._uuid, copp),\n     mcast_cfg in &McastRouterCfg(.datapath = lr._uuid),\n-    var learn_from_arp_request = lr.options.get_bool_def(\"always_learn_from_arp_request\", true),\n+    var learn_from_arp_request = lr.options.get_bool_def(i\"always_learn_from_arp_request\", true),\n     var force_lb_snat = lb_force_snat_router_ip(lr.options).\n \n /* RouterLB: many-to-many relation between logical routers and nb::LB */\n@@ -513,16 +514,15 @@ RouterLB(router, lb) :-\n relation RouterLBVIP(\n     router: Intern<Router>,\n     lb: Intern<nb::Load_Balancer>,\n-    vip: string,\n-    backends: string)\n+    vip: istring,\n+    backends: istring)\n \n RouterLBVIP(router, lb, vip, backends) :-\n     RouterLB(router, lb@(&nb::Load_Balancer{.vips = vips})),\n-    var kv = FlatMap(vips),\n-    (var vip, var backends) = kv.\n+    (var vip, var backends) = FlatMap(vips).\n \n /* Router-to-router logical port connections */\n-relation RouterRouterPeer(rport1: uuid, rport2: uuid, rport2_name: string)\n+relation RouterRouterPeer(rport1: uuid, rport2: uuid, rport2_name: istring)\n \n RouterRouterPeer(rport1, rport2, peer_name) :-\n     &nb::Logical_Router_Port(._uuid = rport1, .peer = peer),\n@@ -532,11 +532,11 @@ RouterRouterPeer(rport1, rport2, peer_name) :-\n /* Router port can peer with anothe router port, a switch port or have\n  * no peer.\n  */\n-typedef RouterPeer = PeerRouter{rport: uuid, name: string}\n-                   | PeerSwitch{sport: uuid, name: string}\n+typedef RouterPeer = PeerRouter{rport: uuid, name: istring}\n+                   | PeerSwitch{sport: uuid, name: istring}\n                    | PeerNone\n \n-function router_peer_name(peer: RouterPeer): Option<string> = {\n+function router_peer_name(peer: RouterPeer): Option<istring> = {\n     match (peer) {\n         PeerRouter{_, n} -> Some{n},\n         PeerSwitch{_, n} -> Some{n},\n@@ -563,14 +563,14 @@ RouterPortPeer(rport, PeerNone) :-\n  * most of the options in that column.  (northd unconditionally sets the\n  * ipv6_prefix_delegation and ipv6_prefix options, so we remove them for\n  * faster convergence.) */\n-relation RouterPortSbOptions(lrp_uuid: uuid, options: Map<string,string>)\n+relation RouterPortSbOptions(lrp_uuid: uuid, options: Map<istring,istring>)\n RouterPortSbOptions(lrp._uuid, options) :-\n     lrp in &nb::Logical_Router_Port(),\n     pb in sb::Port_Binding(._uuid = lrp._uuid),\n     var options = {\n         var options = pb.options;\n-        options.remove(\"ipv6_prefix\");\n-        options.remove(\"ipv6_prefix_delegation\");\n+        options.remove(i\"ipv6_prefix\");\n+        options.remove(i\"ipv6_prefix_delegation\");\n         options\n     }.\n RouterPortSbOptions(lrp._uuid, map_empty()) :-\n@@ -595,7 +595,7 @@ typedef RouterPort = RouterPort {\n     is_redirect:      bool,\n     peer:             RouterPeer,\n     mcast_cfg:        Intern<McastPortCfg>,\n-    sb_options:       Map<string,string>,\n+    sb_options:       Map<istring,istring>,\n     has_bfd:          bool\n }\n \n@@ -603,7 +603,7 @@ relation RouterPort[Intern<RouterPort>]\n \n RouterPort[RouterPort{\n                .lrp                = lrp,\n-               .json_name          = json_string_escape(lrp.name),\n+               .json_name          = json_escape(lrp.name),\n                .networks           = networks,\n                .router             = router,\n                .is_redirect        = is_redirect,\n@@ -613,7 +613,7 @@ RouterPort[RouterPort{\n                .has_bfd            = has_bfd\n            }.intern()] :-\n     lrp in &nb::Logical_Router_Port(),\n-    Some{var networks} = extract_lrp_networks(lrp.mac, lrp.networks),\n+    Some{var networks} = extract_lrp_networks(lrp.mac.ival(), lrp.networks.map(ival)),\n     LogicalRouterPort(lrp._uuid, lrouter_uuid),\n     router in &Router(._uuid = lrouter_uuid),\n     RouterPortIsRedirect(lrp._uuid, is_redirect),\n@@ -636,11 +636,8 @@ RouterPortNetworksIPv6Addr(port, addr) :-\n \n /* StaticRoute: Collects and parses attributes of a static route. */\n typedef route_policy = SrcIp | DstIp\n-function route_policy_from_string(s: Option<string>): route_policy = {\n-    match (s) {\n-        Some{\"src-ip\"} -> SrcIp,\n-        _ -> DstIp\n-    }\n+function route_policy_from_string(s: Option<istring>): route_policy = {\n+    if (s == Some{i\"src-ip\"}) { SrcIp } else { DstIp }\n }\n function to_string(policy: route_policy): string = {\n     match (policy) {\n@@ -664,15 +661,13 @@ StaticRouteDown(lrsr_uuid) :-\n     bfd in nb::BFD(._uuid = bfd_uuid, .dst_ip = nexthop),\n     match (bfd.status) {\n         None -> true,\n-        Some{\"admin_down\"} -> true,\n-        Some{\"down\"} -> true,\n-        _ -> false\n+        Some{status} -> (status == i\"admin_down\" or status == i\"down\")\n     }.\n \n relation &StaticRoute(lrsr: nb::Logical_Router_Static_Route,\n                       key: route_key,\n                       nexthop: v46_ip,\n-                      output_port: Option<string>,\n+                      output_port: Option<istring>,\n                       ecmp_symmetric_reply: bool)\n \n &StaticRoute(.lrsr        = lrsr,\n@@ -683,29 +678,29 @@ relation &StaticRoute(lrsr: nb::Logical_Router_Static_Route,\n     lrsr in nb::Logical_Router_Static_Route(),\n     not StaticRouteDown(lrsr._uuid),\n     var policy = route_policy_from_string(lrsr.policy),\n-    Some{(var nexthop, var nexthop_plen)} = ip46_parse_cidr(lrsr.nexthop),\n+    Some{(var nexthop, var nexthop_plen)} = ip46_parse_cidr(lrsr.nexthop.ival()),\n     match (nexthop) {\n         IPv4{_} -> nexthop_plen == 32,\n         IPv6{_} -> nexthop_plen == 128\n     },\n-    Some{(var ip_prefix, var plen)} = ip46_parse_cidr(lrsr.ip_prefix),\n+    Some{(var ip_prefix, var plen)} = ip46_parse_cidr(lrsr.ip_prefix.ival()),\n     match ((nexthop, ip_prefix)) {\n         (IPv4{_}, IPv4{_}) -> true,\n         (IPv6{_}, IPv6{_}) -> true,\n         _ -> false\n     },\n-    var esr = lrsr.options.get_bool_def(\"ecmp_symmetric_reply\", false).\n+    var esr = lrsr.options.get_bool_def(i\"ecmp_symmetric_reply\", false).\n \n relation &StaticRouteEmptyNextHop(lrsr: nb::Logical_Router_Static_Route,\n                                   key: route_key,\n-                                  output_port: Option<string>)\n+                                  output_port: Option<istring>)\n &StaticRouteEmptyNextHop(.lrsr        = lrsr,\n                          .key         = RouteKey{policy, ip_prefix, plen},\n                          .output_port = lrsr.output_port) :-\n-    lrsr in nb::Logical_Router_Static_Route(.nexthop = \"\"),\n+    lrsr in nb::Logical_Router_Static_Route(.nexthop = i\"\"),\n     not StaticRouteDown(lrsr._uuid),\n     var policy = route_policy_from_string(lrsr.policy),\n-    Some{(var ip_prefix, var plen)} = ip46_parse_cidr(lrsr.ip_prefix).\n+    Some{(var ip_prefix, var plen)} = ip46_parse_cidr(lrsr.ip_prefix.ival()).\n \n /* Returns the IP address of the router port 'op' that\n  * overlaps with 'ip'.  If one is not found, returns None. */\n@@ -745,7 +740,7 @@ relation RouterStaticRoute_(\n     router      : Intern<Router>,\n     key         : route_key,\n     nexthop     : v46_ip,\n-    output_port : Option<string>,\n+    output_port : Option<istring>,\n     ecmp_symmetric_reply : bool)\n \n RouterStaticRoute_(.router = router,\n@@ -761,7 +756,7 @@ RouterStaticRoute_(.router = router,\n relation RouterStaticRouteEmptyNextHop_(\n     router      : Intern<Router>,\n     key         : route_key,\n-    output_port : Option<string>)\n+    output_port : Option<istring>)\n \n RouterStaticRouteEmptyNextHop_(.router = router,\n                                .key = route.key,\n@@ -874,9 +869,9 @@ relation &DiscardRoute(lrsr: nb::Logical_Router_Static_Route,\n                        key: route_key)\n &DiscardRoute(.lrsr        = lrsr,\n               .key         = RouteKey{policy, ip_prefix, plen}) :-\n-    lrsr in nb::Logical_Router_Static_Route(.nexthop = \"discard\"),\n+    lrsr in nb::Logical_Router_Static_Route(.nexthop = i\"discard\"),\n     var policy = route_policy_from_string(lrsr.policy),\n-    Some{(var ip_prefix, var plen)} = ip46_parse_cidr(lrsr.ip_prefix).\n+    Some{(var ip_prefix, var plen)} = ip46_parse_cidr(lrsr.ip_prefix.ival()).\n \n relation RouterDiscardRoute_(\n     router      : Intern<Router>,\ndiff --git a/northd/lswitch.dl b/northd/lswitch.dl\nindex 868ae115f..ad6475a91 100644\n--- a/northd/lswitch.dl\n+++ b/northd/lswitch.dl\n@@ -21,6 +21,7 @@ import multicast\n import helpers\n import ipam\n import vec\n+import set\n \n function is_enabled(lsp: Intern<nb::Logical_Switch_Port>): bool { is_enabled(lsp.enabled) }\n function is_enabled(sp: SwitchPort): bool { sp.lsp.is_enabled() }\n@@ -67,7 +68,7 @@ relation LogicalSwitchPortWithUnknownAddress(ls: uuid, lsp: uuid)\n LogicalSwitchPortWithUnknownAddress(ls_uuid, lsp_uuid) :-\n     LogicalSwitchPort(lsp_uuid, ls_uuid),\n     lsp in &nb::Logical_Switch_Port(._uuid = lsp_uuid),\n-    lsp.is_enabled() and lsp.addresses.contains(\"unknown\").\n+    lsp.is_enabled() and lsp.addresses.contains(i\"unknown\").\n \n // \"Pitfalls of projections\" in ddlog-new-feature.rst explains why this\n // is an output relation:\n@@ -78,18 +79,17 @@ LogicalSwitchHasUnknownPorts(ls, false) :-\n     not LogicalSwitchPortWithUnknownAddress(ls, _).\n \n /* PortStaticAddresses: static IP addresses associated with each Logical_Switch_Port */\n-relation PortStaticAddresses(lsport: uuid, ip4addrs: Set<string>, ip6addrs: Set<string>)\n+relation PortStaticAddresses(lsport: uuid, ip4addrs: Set<istring>, ip6addrs: Set<istring>)\n \n PortStaticAddresses(.lsport     = port_uuid,\n-                    .ip4addrs   = ip4_addrs.union(),\n-                    .ip6addrs   = ip6_addrs.union()) :-\n+                    .ip4addrs   = ip4_addrs.union().map(intern),\n+                    .ip6addrs   = ip6_addrs.union().map(intern)) :-\n     &nb::Logical_Switch_Port(._uuid = port_uuid, .addresses = addresses),\n-    var address = FlatMap(if (addresses.is_empty()) { set_singleton(\"\") } else { addresses }),\n-    (var ip4addrs, var ip6addrs) = if (not is_dynamic_lsp_address(address)) {\n-        split_addresses(address)\n+    var address = FlatMap(if (addresses.is_empty()) { set_singleton(i\"\") } else { addresses }),\n+    (var ip4addrs, var ip6addrs) = if (not is_dynamic_lsp_address(address.ival())) {\n+        split_addresses(address.ival())\n     } else { (set_empty(), set_empty()) },\n-    var static_addrs = (ip4addrs, ip6addrs).group_by(port_uuid).group_unzip(),\n-    (var ip4_addrs, var ip6_addrs) = static_addrs.\n+    (var ip4_addrs, var ip6_addrs) = (ip4addrs, ip6addrs).group_by(port_uuid).group_unzip().\n \n relation PortInGroup(port: uuid, group: uuid)\n \n@@ -115,7 +115,7 @@ relation LogicalSwitchStatefulACL(ls: uuid, acl: uuid)\n \n LogicalSwitchStatefulACL(ls, acl) :-\n     LogicalSwitchACL(ls, acl),\n-    &nb::ACL(._uuid = acl, .action = \"allow-related\").\n+    &nb::ACL(._uuid = acl, .action = i\"allow-related\").\n \n // \"Pitfalls of projections\" in ddlog-new-feature.rst explains why this\n // is an output relation:\n@@ -144,14 +144,14 @@ LogicalSwitchHasACLs(ls, false) :-\n  * to the logical switch's set of localnet ports.  Each localnet\n  * port is expressed as a tuple of its UUID and its name.\n  */\n-relation LogicalSwitchLocalnetPort0(ls_uuid: uuid, lsp: (uuid, string))\n+relation LogicalSwitchLocalnetPort0(ls_uuid: uuid, lsp: (uuid, istring))\n LogicalSwitchLocalnetPort0(ls_uuid, (lsp_uuid, lsp.name)) :-\n     ls in &nb::Logical_Switch(._uuid = ls_uuid),\n     var lsp_uuid = FlatMap(ls.ports),\n     lsp in &nb::Logical_Switch_Port(._uuid = lsp_uuid),\n-    lsp.__type == \"localnet\".\n+    lsp.__type == i\"localnet\".\n \n-relation LogicalSwitchLocalnetPorts(ls_uuid: uuid, localnet_ports: Vec<(uuid, string)>)\n+relation LogicalSwitchLocalnetPorts(ls_uuid: uuid, localnet_ports: Vec<(uuid, istring)>)\n LogicalSwitchLocalnetPorts(ls_uuid, localnet_ports) :-\n     LogicalSwitchLocalnetPort0(ls_uuid, lsp),\n     var localnet_ports = lsp.group_by(ls_uuid).to_vec().\n@@ -191,7 +191,7 @@ LogicalSwitchHasNonRouterPort0(ls_uuid) :-\n     ls in &nb::Logical_Switch(._uuid = ls_uuid),\n     var lsp_uuid = FlatMap(ls.ports),\n     lsp in &nb::Logical_Switch_Port(._uuid = lsp_uuid),\n-    lsp.__type != \"router\".\n+    lsp.__type != i\"router\".\n \n // \"Pitfalls of projections\" in ddlog-new-feature.rst explains why this\n // is an output relation:\n@@ -204,13 +204,13 @@ LogicalSwitchHasNonRouterPort(ls, false) :-\n \n // LogicalSwitchCopp maps from each LS to its collection of Copp meters,\n // dropping any Copp meter whose meter name doesn't exist.\n-relation LogicalSwitchCopp(ls: uuid, meters: Map<string,string>)\n+relation LogicalSwitchCopp(ls: uuid, meters: Map<istring,istring>)\n LogicalSwitchCopp(ls, meters) :- LogicalSwitchCopp0(ls, meters).\n LogicalSwitchCopp(ls, map_empty()) :-\n     &nb::Logical_Switch(._uuid = ls),\n     not LogicalSwitchCopp0(ls, _).\n \n-relation LogicalSwitchCopp0(ls: uuid, meters: Map<string,string>)\n+relation LogicalSwitchCopp0(ls: uuid, meters: Map<istring,istring>)\n LogicalSwitchCopp0(ls, meters) :-\n     &nb::Logical_Switch(._uuid = ls, .copp = Some{copp_uuid}),\n     nb::Copp(._uuid = copp_uuid, .meters = meters),\n@@ -224,10 +224,10 @@ LogicalSwitchCopp0(ls, meters) :-\n typedef Switch = Switch {\n     /* Fields copied from nb::Logical_Switch_Port. */\n     _uuid:             uuid,\n-    name:              string,\n+    name:              istring,\n     load_balancer:     Set<uuid>,\n-    other_config:      Map<string,string>,\n-    external_ids:      Map<string,string>,\n+    other_config:      Map<istring,istring>,\n+    external_ids:      Map<istring,istring>,\n \n     /* Additional computed fields. */\n     has_stateful_acl:  bool,\n@@ -235,12 +235,12 @@ typedef Switch = Switch {\n     has_lb_vip:        bool,\n     has_dns_records:   bool,\n     has_unknown_ports: bool,\n-    localnet_ports:    Vec<(uuid, string)>,  // UUID and name of each localnet port.\n+    localnet_ports:    Vec<(uuid, istring)>,  // UUID and name of each localnet port.\n     subnet:            Option<(in_addr/*subnet*/, in_addr/*mask*/, bit<32>/*start_ipv4*/, bit<32>/*total_ipv4s*/)>,\n     ipv6_prefix:       Option<in6_addr>,\n     mcast_cfg:         Intern<McastSwitchCfg>,\n     is_vlan_transparent: bool,\n-    copp:              Map<string, string>,\n+    copp:              Map<istring, istring>,\n \n     /* Does this switch have at least one port with type != \"router\"? */\n     has_non_router_port: bool\n@@ -291,10 +291,10 @@ Switch[Switch{\n     LogicalSwitchCopp(ls._uuid, copp),\n     mcast_cfg in &McastSwitchCfg(.datapath = ls._uuid),\n     var subnet =\n-        match (ls.other_config.get(\"subnet\")) {\n+        match (ls.other_config.get(i\"subnet\")) {\n             None -> None,\n             Some{subnet_str} -> {\n-                match (ip_parse_masked(subnet_str)) {\n+                match (ip_parse_masked(subnet_str.ival())) {\n                     Left{err} -> {\n                         warn(\"bad 'subnet' ${subnet_str}\");\n                         None\n@@ -311,11 +311,11 @@ Switch[Switch{\n             }\n         },\n     var ipv6_prefix =\n-        match (ls.other_config.get(\"ipv6_prefix\")) {\n+        match (ls.other_config.get(i\"ipv6_prefix\")) {\n             None -> None,\n-            Some{prefix} -> ipv6_parse_prefix(prefix)\n+            Some{prefix} -> ipv6_parse_prefix(prefix.ival())\n         },\n-    var is_vlan_transparent = ls.other_config.get_bool_def(\"vlan-passthru\", false).\n+    var is_vlan_transparent = ls.other_config.get_bool_def(i\"vlan-passthru\", false).\n \n /* SwitchLB: many-to-many relation between logical switches and nb::LB */\n relation SwitchLB(sw_uuid: uuid, lb: Intern<nb::Load_Balancer>)\n@@ -325,7 +325,7 @@ SwitchLB(sw_uuid, lb) :-\n     lb in &nb::Load_Balancer(._uuid = lb_id).\n \n /* Load balancer VIPs associated with switch */\n-relation SwitchLBVIP(sw_uuid: uuid, lb: Intern<nb::Load_Balancer>, vip: string, backends: string)\n+relation SwitchLBVIP(sw_uuid: uuid, lb: Intern<nb::Load_Balancer>, vip: istring, backends: istring)\n SwitchLBVIP(sw_uuid, lb, vip, backends) :-\n     SwitchLB(sw_uuid, lb@(&nb::Load_Balancer{.vips = vips})),\n     var kv = FlatMap(vips),\n@@ -349,8 +349,8 @@ LogicalSwitchHasLBVIP(sw_uuid, false) :-\n  */\n relation LBVIP0(\n     lb: Intern<nb::Load_Balancer>,\n-    vip_key: string,\n-    backend_ips: string,\n+    vip_key: istring,\n+    backend_ips: istring,\n     health_check: Intern<nb::Load_Balancer_Health_Check>)\n LBVIP0(lb, vip_key, backend_ips, health_check) :-\n     lb in &nb::Load_Balancer(),\n@@ -361,8 +361,8 @@ LBVIP0(lb, vip_key, backend_ips, health_check) :-\n \n relation LBVIP1(\n     lb: Intern<nb::Load_Balancer>,\n-    vip_key: string,\n-    backend_ips: string,\n+    vip_key: istring,\n+    backend_ips: istring,\n     health_check: Option<Intern<nb::Load_Balancer_Health_Check>>)\n LBVIP1(lb, vip_key, backend_ips, Some{health_check}) :-\n     LBVIP0(lb, vip_key, backend_ips, health_check).\n@@ -374,8 +374,8 @@ LBVIP1(lb, vip_key, backend_ips, None) :-\n \n typedef LBVIP = LBVIP {\n     lb: Intern<nb::Load_Balancer>,\n-    vip_key: string,\n-    backend_ips: string,\n+    vip_key: istring,\n+    backend_ips: istring,\n     health_check: Option<Intern<nb::Load_Balancer_Health_Check>>,\n     vip_addr: v46_ip,\n     vip_port: bit<16>,\n@@ -386,13 +386,13 @@ relation LBVIP[Intern<LBVIP>]\n \n LBVIP[LBVIP{lb, vip_key, backend_ips, health_check, vip_addr, vip_port, backends}.intern()] :-\n     LBVIP1(lb, vip_key, backend_ips, health_check),\n-    Some{(var vip_addr, var vip_port)} = ip_address_and_port_from_lb_key(vip_key),\n+    Some{(var vip_addr, var vip_port)} = ip_address_and_port_from_lb_key(vip_key.ival()),\n     var backends = backend_ips.split(\",\").filter_map(\n         |ip| parse_vip_backend(ip, lb.ip_port_mappings)).\n \n typedef svc_monitor = SvcMonitor{\n-    port_name: string,          // Might name a switch or router port.\n-    src_ip: string\n+    port_name: istring,          // Might name a switch or router port.\n+    src_ip: istring\n }\n \n /* Backends for load balancer virtual IPs.\n@@ -407,25 +407,24 @@ typedef lb_vip_backend = LBVIPBackend{\n     svc_monitor: Option<svc_monitor>}\n \n function parse_vip_backend(backend_ip: string,\n-                           mappings: Map<string,string>): Option<lb_vip_backend> {\n+                           mappings: Map<istring,istring>): Option<lb_vip_backend> {\n     match (ip_address_and_port_from_lb_key(backend_ip)) {\n         Some{(ip, port)} -> Some{LBVIPBackend{ip, port, parse_ip_port_mapping(mappings, ip)}},\n         _ -> None\n     }\n }\n \n-function parse_ip_port_mapping(mappings: Map<string,string>, ip: v46_ip)\n+function parse_ip_port_mapping(mappings: Map<istring,istring>, ip: v46_ip)\n     : Option<svc_monitor> {\n-    for (kv in mappings) {\n-        (var key, var value) = kv;\n-        if (ip46_parse(key) == Some{ip}) {\n-            var strs = string_split(value, \":\");\n+    for ((key, value) in mappings) {\n+        if (ip46_parse(key.ival()) == Some{ip}) {\n+            var strs = value.split(\":\");\n             if (strs.len() != 2) {\n                 return None\n             };\n \n             return match ((strs.nth(0), strs.nth(1))) {\n-                (Some{port_name}, Some{src_ip}) -> Some{SvcMonitor{port_name, src_ip}},\n+                (Some{port_name}, Some{src_ip}) -> Some{SvcMonitor{port_name.intern(), src_ip.intern()}},\n                 _ -> None\n             }\n         }\n@@ -433,23 +432,23 @@ function parse_ip_port_mapping(mappings: Map<string,string>, ip: v46_ip)\n     return None\n }\n \n-function is_online(status: Option<string>): bool = {\n+function is_online(status: Option<istring>): bool = {\n     match (status) {\n-        Some{s} -> s == \"online\",\n+        Some{s} -> s == i\"online\",\n         _ -> true\n     }\n }\n-function default_protocol(protocol: Option<string>): string = {\n+function default_protocol(protocol: Option<istring>): istring = {\n     match (protocol) {\n         Some{x} -> x,\n-        None -> \"tcp\"\n+        None -> i\"tcp\"\n     }\n }\n \n typedef LBVIPWithStatus = LBVIPWithStatus {\n     lb: Intern<nb::Load_Balancer>,\n-    vip_key: string,\n-    backend_ips: string,\n+    vip_key: istring,\n+    backend_ips: istring,\n     health_check: Option<Intern<nb::Load_Balancer_Health_Check>>,\n     vip_addr: v46_ip,\n     vip_port: bit<16>,\n@@ -479,7 +478,7 @@ LBVIPBackendStatus0(lbvip, backend, is_online(sm.status)) :-\n     var backend = FlatMap(lbvip.backends),\n     Some{var svc_monitor} = backend.svc_monitor,\n     sm in &sb::Service_Monitor(.port = backend.port as integer),\n-    ip46_parse(sm.ip) == Some{backend.ip},\n+    ip46_parse(sm.ip.ival()) == Some{backend.ip},\n     svc_monitor.port_name == sm.logical_port,\n     default_protocol(lb.protocol) == default_protocol(sm.protocol).\n \n@@ -500,7 +499,7 @@ relation SwitchPortDHCPv4Options(\n \n SwitchPortDHCPv4Options(port, options) :-\n     port in &SwitchPort(.lsp = lsp),\n-    port.lsp.__type != \"external\",\n+    port.lsp.__type != i\"external\",\n     Some{var dhcpv4_uuid} = lsp.dhcpv4_options,\n     options in &nb::DHCP_Options(._uuid = dhcpv4_uuid).\n \n@@ -511,7 +510,7 @@ relation SwitchPortDHCPv6Options(\n \n SwitchPortDHCPv6Options(port, options) :-\n     port in &SwitchPort(.lsp = lsp),\n-    port.lsp.__type != \"external\",\n+    port.lsp.__type != i\"external\",\n     Some{var dhcpv6_uuid} = lsp.dhcpv6_options,\n     options in &nb::DHCP_Options(._uuid = dhcpv6_uuid).\n \n@@ -553,10 +552,10 @@ relation &SwitchACL(sw: Intern<Switch>,\n     acl in &nb::ACL(._uuid = acl_uuid),\n     ACLHasFairMeter(acl, has_fair_meter).\n \n-function oVN_FEATURE_PORT_UP_NOTIF(): string { \"port-up-notif\" }\n+function oVN_FEATURE_PORT_UP_NOTIF(): istring { i\"port-up-notif\" }\n relation SwitchPortUp0(lsp: uuid)\n SwitchPortUp0(lsp) :-\n-    &nb::Logical_Switch_Port(._uuid = lsp, .__type = \"router\").\n+    &nb::Logical_Switch_Port(._uuid = lsp, .__type = i\"router\").\n SwitchPortUp0(lsp) :-\n     &nb::Logical_Switch_Port(._uuid = lsp, .name = lsp_name, .__type = __type),\n     sb::Port_Binding(.logical_port = lsp_name, .up = up, .chassis = Some{chassis_uuid}),\n@@ -574,7 +573,7 @@ SwitchPortUp(lsp, false) :- &nb::Logical_Switch_Port(._uuid = lsp), not SwitchPo\n relation SwitchPortHAChassisGroup0(lsp_uuid: uuid, hac_group_uuid: uuid)\n SwitchPortHAChassisGroup0(lsp_uuid, ha_chassis_group_uuid(ls_uuid)) :-\n     lsp in &nb::Logical_Switch_Port(._uuid = lsp_uuid),\n-    lsp.__type == \"external\",\n+    lsp.__type == i\"external\",\n     Some{var hac_group_uuid} = lsp.ha_chassis_group,\n     ha_chassis_group in nb::HA_Chassis_Group(._uuid = hac_group_uuid),\n     /* If the group is empty, then HA_Chassis_Group record will not be created in SB,\n@@ -603,7 +602,7 @@ SwitchPortHAChassisGroup(lsp_uuid, None) :-\n  */\n typedef SwitchPort = SwitchPort {\n     lsp:                        Intern<nb::Logical_Switch_Port>,\n-    json_name:                  string,\n+    json_name:                  istring,\n     sw:                         Intern<Switch>,\n     peer:                       Option<Intern<RouterPort>>,\n     static_addresses:           Vec<lport_addresses>,\n@@ -612,8 +611,8 @@ typedef SwitchPort = SwitchPort {\n     static_dynamic_ipv4:        Option<in_addr>,\n     static_dynamic_ipv6:        Option<in6_addr>,\n     ps_addresses:               Vec<lport_addresses>,\n-    ps_eth_addresses:           Vec<string>,\n-    parent_name:                Option<string>,\n+    ps_eth_addresses:           Vec<istring>,\n+    parent_name:                Option<istring>,\n     needs_dynamic_ipv4address:  bool,\n     needs_dynamic_macaddress:   bool,\n     needs_dynamic_ipv6address:  bool,\n@@ -627,7 +626,7 @@ relation SwitchPort[Intern<SwitchPort>]\n \n SwitchPort[SwitchPort{\n               .lsp                        = lsp,\n-              .json_name                  = json_string_escape(lsp.name),\n+              .json_name                  = lsp.name.json_escape().intern(),\n               .sw                         = sw,\n               .peer                       = peer,\n               .static_addresses           = static_addresses,\n@@ -658,8 +657,8 @@ SwitchPort[SwitchPort{\n     var static_addresses = {\n         var static_addresses = vec_empty();\n         for (addr in lsp.addresses) {\n-            if ((addr != \"router\") and (not is_dynamic_lsp_address(addr))) {\n-                match (extract_lsp_addresses(addr)) {\n+            if ((addr != i\"router\") and (not is_dynamic_lsp_address(addr.ival()))) {\n+                match (extract_lsp_addresses(addr.ival())) {\n                     None -> (),\n                     Some{lport_addr} -> static_addresses.push(lport_addr)\n                 }\n@@ -670,7 +669,7 @@ SwitchPort[SwitchPort{\n     var ps_addresses = {\n         var ps_addresses = vec_empty();\n         for (addr in lsp.port_security) {\n-            match (extract_lsp_addresses(addr)) {\n+            match (extract_lsp_addresses(addr.ival())) {\n                 None -> (),\n                 Some{lport_addr} -> ps_addresses.push(lport_addr)\n             }\n@@ -680,13 +679,13 @@ SwitchPort[SwitchPort{\n     var ps_eth_addresses = {\n         var ps_eth_addresses = vec_empty();\n         for (ps_addr in ps_addresses) {\n-            ps_eth_addresses.push(\"${ps_addr.ea}\")\n+            ps_eth_addresses.push(i\"${ps_addr.ea}\")\n         };\n         ps_eth_addresses\n     },\n     var dynamic_address = match (lsp.dynamic_addresses) {\n         None -> None,\n-        Some{lport_addr} -> extract_lsp_addresses(lport_addr)\n+        Some{lport_addr} -> extract_lsp_addresses(lport_addr.ival())\n     },\n     (var static_dynamic_mac,\n      var static_dynamic_ipv4,\n@@ -694,7 +693,7 @@ SwitchPort[SwitchPort{\n      var has_dyn_lsp_addr) = {\n         var dynamic_address_request = None;\n         for (addr in lsp.addresses) {\n-            dynamic_address_request = parse_dynamic_address_request(addr);\n+            dynamic_address_request = parse_dynamic_address_request(addr.ival());\n             if (dynamic_address_request.is_some()) {\n                 break\n             }\n@@ -709,11 +708,11 @@ SwitchPort[SwitchPort{\n                                     static_dynamic_ipv4 == None,\n     var needs_dynamic_macaddress = has_dyn_lsp_addr and peer == None and static_dynamic_mac == None and\n                                    (subnet.is_some() or ipv6_prefix.is_some() or\n-                                    other_config.get(\"mac_only\") == Some{\"true\"}),\n+                                    other_config.get(i\"mac_only\") == Some{i\"true\"}),\n     var needs_dynamic_ipv6address = has_dyn_lsp_addr and peer == None and ipv6_prefix.is_some() and static_dynamic_ipv6 == None,\n     var parent_name = match (lsp.parent_name) {\n         None -> None,\n-        Some{pname} -> if (pname == \"\") { None } else { Some{pname} }\n+        Some{pname} -> if (pname == i\"\") { None } else { Some{pname} }\n     },\n     /* Port needs dynamic tag if it has a parent and its `tag_request` is 0. */\n     var needs_dynamic_tag = parent_name.is_some() and lsp.tag_request == Some{0},\n@@ -761,7 +760,7 @@ SwitchPortAddresses(port, addrs) :-\n     Some{var addrs} = {\n         var opt_addrs = None;\n         for (addr in lsp.addresses) {\n-            if (addr == \"router\") {\n+            if (addr == i\"router\") {\n                 opt_addrs = Some{rport.networks}\n             } else ()\n         };\n@@ -793,13 +792,13 @@ SwitchPortIPv6Address(port, ea, addr) :-\n  * of this mac when sending out the packets to monitor the services\n  * defined in Service_Monitor Southbound table. Since these packets\n  * all locally handled, having just one mac is good enough. */\n-function get_svc_monitor_mac(options: Map<string,string>, uuid: uuid)\n+function get_svc_monitor_mac(options: Map<istring,istring>, uuid: uuid)\n     : eth_addr =\n {\n     var existing_mac = match (\n-        options.get(\"svc_monitor_mac\"))\n+        options.get(i\"svc_monitor_mac\"))\n     {\n-        Some{mac} -> scan_eth_addr(mac),\n+        Some{mac} -> scan_eth_addr(mac.ival()),\n         None -> None\n     };\n     match (existing_mac) {\n@@ -807,17 +806,17 @@ function get_svc_monitor_mac(options: Map<string,string>, uuid: uuid)\n         None -> eth_addr_pseudorandom(uuid, 'h5678)\n     }\n }\n-function put_svc_monitor_mac(options: Map<string,string>,\n-                             svc_monitor_mac: eth_addr) : Map<string,string> =\n+function put_svc_monitor_mac(options: mut Map<istring,istring>,\n+                             svc_monitor_mac: eth_addr)\n {\n-    options.insert_imm(\"svc_monitor_mac\", to_string(svc_monitor_mac))\n+    options.insert(i\"svc_monitor_mac\", svc_monitor_mac.to_string().intern());\n }\n relation SvcMonitorMac(mac: eth_addr)\n SvcMonitorMac(get_svc_monitor_mac(options, uuid)) :-\n     nb::NB_Global(._uuid = uuid, .options = options).\n \n relation UseCtInvMatch[bool]\n-UseCtInvMatch[options.get_bool_def(\"use_ct_inv_match\", true)] :-\n+UseCtInvMatch[options.get_bool_def(i\"use_ct_inv_match\", true)] :-\n     nb::NB_Global(.options = options).\n UseCtInvMatch[true] :-\n     Unit(),\ndiff --git a/northd/multicast.dl b/northd/multicast.dl\nindex ef365b408..074caf654 100644\n--- a/northd/multicast.dl\n+++ b/northd/multicast.dl\n@@ -36,9 +36,9 @@ typedef McastSwitchCfg = McastSwitchCfg {\n     enabled       : bool,\n     querier       : bool,\n     flood_unreg   : bool,\n-    eth_src       : string,\n-    ip4_src       : string,\n-    ip6_src       : string,\n+    eth_src       : istring,\n+    ip4_src       : istring,\n+    ip6_src       : istring,\n     table_size    : integer,\n     idle_timeout  : integer,\n     query_interval: integer,\n@@ -53,24 +53,24 @@ relation McastSwitchCfg[Intern<McastSwitchCfg>]\n \n McastSwitchCfg[McastSwitchCfg {\n                    .datapath       = ls_uuid,\n-                   .enabled        = other_config.get_bool_def(\"mcast_snoop\", false),\n-                   .querier        = other_config.get_bool_def(\"mcast_querier\", true),\n-                   .flood_unreg    = other_config.get_bool_def(\"mcast_flood_unregistered\", false),\n-                   .eth_src        = other_config.get(\"mcast_eth_src\").unwrap_or(\"\"),\n-                   .ip4_src        = other_config.get(\"mcast_ip4_src\").unwrap_or(\"\"),\n-                   .ip6_src        = other_config.get(\"mcast_ip6_src\").unwrap_or(\"\"),\n-                   .table_size     = other_config.get_int_def(\"mcast_table_size\", mCAST_DEFAULT_MAX_ENTRIES()),\n+                   .enabled        = other_config.get_bool_def(i\"mcast_snoop\", false),\n+                   .querier        = other_config.get_bool_def(i\"mcast_querier\", true),\n+                   .flood_unreg    = other_config.get_bool_def(i\"mcast_flood_unregistered\", false),\n+                   .eth_src        = other_config.get(i\"mcast_eth_src\").unwrap_or(i\"\"),\n+                   .ip4_src        = other_config.get(i\"mcast_ip4_src\").unwrap_or(i\"\"),\n+                   .ip6_src        = other_config.get(i\"mcast_ip6_src\").unwrap_or(i\"\"),\n+                   .table_size     = other_config.get_int_def(i\"mcast_table_size\", mCAST_DEFAULT_MAX_ENTRIES()),\n                    .idle_timeout   = idle_timeout,\n                    .query_interval = query_interval,\n                    .query_max_resp = query_max_resp\n                }.intern()] :-\n     &nb::Logical_Switch(._uuid        = ls_uuid,\n                       .other_config = other_config),\n-    var idle_timeout = other_config.get_int_def(\"mcast_idle_timeout\", mCAST_DEFAULT_IDLE_TIMEOUT_S())\n+    var idle_timeout = other_config.get_int_def(i\"mcast_idle_timeout\", mCAST_DEFAULT_IDLE_TIMEOUT_S())\n                                    .clamp(mCAST_IDLE_TIMEOUT_S_RANGE()),\n-    var query_interval = other_config.get_int_def(\"mcast_query_interval\", idle_timeout / 2)\n+    var query_interval = other_config.get_int_def(i\"mcast_query_interval\", idle_timeout / 2)\n                                      .clamp(mCAST_QUERY_INTERVAL_S_RANGE()),\n-    var query_max_resp = other_config.get_int_def(\"mcast_query_max_response\",\n+    var query_max_resp = other_config.get_int_def(i\"mcast_query_max_response\",\n                                                   mCAST_DEFAULT_QUERY_MAX_RESPONSE_S()).\n \n /* IP Multicast per router configuration. */\n@@ -83,7 +83,7 @@ relation McastRouterCfg[Intern<McastRouterCfg>]\n \n McastRouterCfg[McastRouterCfg{lr_uuid, mcast_relay}.intern()] :-\n     nb::Logical_Router(._uuid = lr_uuid, .options = options),\n-    var mcast_relay = options.get_bool_def(\"mcast_relay\", false).\n+    var mcast_relay = options.get_bool_def(i\"mcast_relay\", false).\n \n /* IP Multicast port configuration. */\n typedef McastPortCfg = McastPortCfg {\n@@ -97,12 +97,12 @@ relation McastPortCfg[Intern<McastPortCfg>]\n \n McastPortCfg[McastPortCfg{lsp_uuid, false, flood, flood_reports}.intern()] :-\n     &nb::Logical_Switch_Port(._uuid = lsp_uuid, .options = options),\n-    var flood = options.get_bool_def(\"mcast_flood\", false),\n-    var flood_reports = options.get_bool_def(\"mcast_flood_reports\", false).\n+    var flood = options.get_bool_def(i\"mcast_flood\", false),\n+    var flood_reports = options.get_bool_def(i\"mcast_flood_reports\", false).\n \n McastPortCfg[McastPortCfg{lrp_uuid, true, flood, flood}.intern()] :-\n     &nb::Logical_Router_Port(._uuid = lrp_uuid, .options = options),\n-    var flood = options.get_bool_def(\"mcast_flood\", false).\n+    var flood = options.get_bool_def(i\"mcast_flood\", false).\n \n /* Mapping between Switch and the set of router port uuids on which to flood\n  * IP multicast for relay.\n@@ -185,7 +185,7 @@ RouterMcastFloodPorts(router, set_empty()) :-\n \n /* Flattened IGMP group. One record per address-port tuple. */\n relation IgmpSwitchGroupPort(\n-    address: string,\n+    address: istring,\n     switch : Intern<Switch>,\n     port   : uuid\n )\n@@ -205,7 +205,7 @@ IgmpSwitchGroupPort(address, switch, localnet_port.0) :-\n  * address-switch tuple from all chassis.\n  */\n relation IgmpSwitchMulticastGroup(\n-    address: string,\n+    address: istring,\n     switch : Intern<Switch>,\n     ports  : Set<uuid>\n )\n@@ -219,7 +219,7 @@ IgmpSwitchMulticastGroup(address, switch, ports) :-\n  * connected to the router.\n  */\n relation IgmpRouterGroupPort(\n-    address: string,\n+    address: istring,\n     router : Intern<Router>,\n     port   : uuid\n )\n@@ -230,7 +230,7 @@ IgmpRouterGroupPort(address, rtr_port.router, rtr_port.lrp._uuid) :-\n     /* For IPv6 only relay routable multicast groups\n      * (RFC 4291 2.7).\n      */\n-    match (ipv6_parse(address)) {\n+    match (ipv6_parse(address.ival())) {\n         Some{ipv6} -> ipv6.is_routable_multicast(),\n         None -> true\n     },\n@@ -242,7 +242,7 @@ IgmpRouterGroupPort(address, rtr_port.router, rtr_port.lrp._uuid) :-\n  * a given address-router tuple from all connected switches.\n  */\n relation IgmpRouterMulticastGroup(\n-    address: string,\n+    address: istring,\n     router : Intern<Router>,\n     ports  : Set<uuid>\n )\ndiff --git a/northd/ovn-nb.dlopts b/northd/ovn-nb.dlopts\nindex c22130004..9a460adef 100644\n--- a/northd/ovn-nb.dlopts\n+++ b/northd/ovn-nb.dlopts\n@@ -1,3 +1,4 @@\n+--intern-strings\n -o BFD\n --rw BFD.status\n -o Logical_Router_Port\ndiff --git a/northd/ovn-sb.dlopts b/northd/ovn-sb.dlopts\nindex ea4952758..99b65f101 100644\n--- a/northd/ovn-sb.dlopts\n+++ b/northd/ovn-sb.dlopts\n@@ -1,3 +1,4 @@\n+--intern-strings\n -o Address_Set\n -o BFD\n -o DHCP_Options\ndiff --git a/northd/ovn.dl b/northd/ovn.dl\nindex 3c7a734dd..3585eb3dc 100644\n--- a/northd/ovn.dl\n+++ b/northd/ovn.dl\n@@ -375,6 +375,13 @@ extern function ovn_internal_version(): string\n  */\n extern function json_string_escape(s: string): string\n \n+function json_escape(s: string): string {\n+    s.json_string_escape()\n+}\n+function json_escape(s: istring): string {\n+    s.ival().json_string_escape()\n+}\n+\n /* For a 'key' of the form \"IP:port\" or just \"IP\", returns\n  * (v46_ip, port) tuple. */\n extern function ip_address_and_port_from_lb_key(k: string): Option<(v46_ip, bit<16>)>\ndiff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl\nindex ff92c989c..4402b17d2 100644\n--- a/northd/ovn_northd.dl\n+++ b/northd/ovn_northd.dl\n@@ -48,29 +48,29 @@ sb::Out_Meter(._uuid = hash128(name),\n               .unit = meter.unit,\n               .bands = meter.bands) :-\n     ACLWithFairMeter(acl, meter),\n-    var name = acl_log_meter_name(meter.name, acl._uuid).\n+    var name = acl_log_meter_name(meter.name, acl._uuid).intern().\n \n /* Proxy table for Out_Datapath_Binding: contains all Datapath_Binding fields,\n  * except tunnel id, which is allocated separately (see TunKeyAllocation). */\n relation OutProxy_Datapath_Binding (\n     _uuid: uuid,\n-    external_ids: Map<string,string>\n+    external_ids: Map<istring,istring>\n )\n \n /* Datapath_Binding table */\n OutProxy_Datapath_Binding(uuid, external_ids) :-\n     &nb::Logical_Switch(._uuid = uuid, .name = name, .external_ids = ids,\n                        .other_config = other_config),\n-    var uuid_str = uuid2str(uuid),\n+    var uuid_str = uuid2str(uuid).intern(),\n     var external_ids = {\n-        var eids = [\"logical-switch\" -> uuid_str, \"name\" -> name];\n-        match (ids.get(\"neutron:network_name\")) {\n+        var eids = [i\"logical-switch\" -> uuid_str, i\"name\" -> name];\n+        match (ids.get(i\"neutron:network_name\")) {\n             None -> (),\n-            Some{nnn} -> eids.insert(\"name2\", nnn)\n+            Some{nnn} -> eids.insert(i\"name2\", nnn)\n         };\n-        match (other_config.get(\"interconn-ts\")) {\n+        match (other_config.get(i\"interconn-ts\")) {\n             None -> (),\n-            Some{value} -> eids.insert(\"interconn-ts\", value)\n+            Some{value} -> eids.insert(i\"interconn-ts\", value)\n         };\n         eids\n     }.\n@@ -79,20 +79,20 @@ OutProxy_Datapath_Binding(uuid, external_ids) :-\n     lr in nb::Logical_Router(._uuid = uuid, .name = name, .external_ids = ids,\n                              .options = options),\n     lr.is_enabled(),\n-    var uuid_str = uuid2str(uuid),\n+    var uuid_str = uuid2str(uuid).intern(),\n     var external_ids = {\n-        var eids = [\"logical-router\" -> uuid_str, \"name\" -> name];\n-        match (ids.get(\"neutron:router_name\")) {\n+        var eids = [i\"logical-router\" -> uuid_str, i\"name\" -> name];\n+        match (ids.get(i\"neutron:router_name\")) {\n             None -> (),\n-            Some{nnn} -> eids.insert(\"name2\", nnn)\n+            Some{nnn} -> eids.insert(i\"name2\", nnn)\n         };\n-        match (options.get(\"snat-ct-zone\").and_then(parse_dec_u64)) {\n+        match (options.get(i\"snat-ct-zone\").and_then(parse_dec_u64)) {\n             None -> (),\n-            Some{zone} -> eids.insert(\"snat-ct-zone\", \"${zone}\")\n+            Some{zone} -> eids.insert(i\"snat-ct-zone\", i\"${zone}\")\n         };\n-        var learn_from_arp_request = options.get_bool_def(\"always_learn_from_arp_request\", true);\n+        var learn_from_arp_request = options.get_bool_def(i\"always_learn_from_arp_request\", true);\n         if (not learn_from_arp_request) {\n-            eids.insert(\"always_learn_from_arp_request\", \"false\")\n+            eids.insert(i\"always_learn_from_arp_request\", i\"false\")\n         };\n         eids\n     }.\n@@ -110,17 +110,17 @@ sb::Out_Datapath_Binding(uuid, tunkey, load_balancers, external_ids) :-\n  * except tunnel id, which is allocated separately (see PortTunKeyAllocation). */\n relation OutProxy_Port_Binding (\n     _uuid: uuid,\n-    logical_port: string,\n-    __type: string,\n+    logical_port: istring,\n+    __type: istring,\n     gateway_chassis: Set<uuid>,\n     ha_chassis_group: Option<uuid>,\n-    options: Map<string,string>,\n+    options: Map<istring,istring>,\n     datapath: uuid,\n-    parent_port: Option<string>,\n+    parent_port: Option<istring>,\n     tag: Option<integer>,\n-    mac: Set<string>,\n-    nat_addresses: Set<string>,\n-    external_ids: Map<string,string>\n+    mac: Set<istring>,\n+    nat_addresses: Set<istring>,\n+    external_ids: Map<istring,istring>\n )\n \n /* Case 1: Create a Port_Binding per logical switch port that is not of type \"router\" */\n@@ -142,20 +142,19 @@ OutProxy_Port_Binding(._uuid              = lsp._uuid,\n         None -> lsp.tag,\n         Some{t} -> Some{t}\n     },\n-    lsp.__type != \"router\",\n+    lsp.__type != i\"router\",\n     var eids = {\n         var eids = lsp.external_ids;\n-        match (lsp.external_ids.get(\"neutron:port_name\")) {\n+        match (lsp.external_ids.get(i\"neutron:port_name\")) {\n             None -> (),\n-            Some{name} -> eids.insert(\"name\", name)\n+            Some{name} -> eids.insert(i\"name\", name)\n         };\n         eids\n     },\n     var options = {\n         var options = lsp.options;\n-        match (sw.other_config.get(\"vlan-passthru\")) {\n-            Some{\"true\"} -> options.insert(\"vlan-passthru\", \"true\"),\n-            _ -> ()\n+        if (sw.other_config.get(i\"vlan-passthru\") == Some{i\"true\"}) {\n+            options.insert(i\"vlan-passthru\", i\"true\")\n         };\n         options\n     }.\n@@ -177,47 +176,50 @@ OutProxy_Port_Binding(._uuid              = lsp._uuid,\n     &SwitchPort(.lsp = lsp, .sw = sw, .peer = peer),\n     var eids = {\n         var eids = lsp.external_ids;\n-        match (lsp.external_ids.get(\"neutron:port_name\")) {\n+        match (lsp.external_ids.get(i\"neutron:port_name\")) {\n             None -> (),\n-            Some{name} -> eids.insert(\"name\", name)\n+            Some{name} -> eids.insert(i\"name\", name)\n         };\n         eids\n     },\n-    Some{var router_port} = lsp.options.get(\"router-port\"),\n-    var opt_chassis = peer.and_then(|p| p.router.options.get(\"chassis\")),\n+    Some{var router_port} = lsp.options.get(i\"router-port\"),\n+    var opt_chassis = peer.and_then(|p| p.router.options.get(i\"chassis\")),\n     var l3dgw_port = peer.and_then(|p| p.router.l3dgw_ports.nth(0)),\n     (var __type, var options) = {\n-        var options = [\"peer\" -> router_port];\n+        var options = [i\"peer\" -> router_port];\n         match (opt_chassis) {\n             None -> {\n-                (\"patch\", options)\n+                (i\"patch\", options)\n             },\n             Some{chassis} -> {\n-                options.insert(\"l3gateway-chassis\", chassis);\n-                (\"l3gateway\", options)\n+                options.insert(i\"l3gateway-chassis\", chassis);\n+                (i\"l3gateway\", options)\n             }\n         }\n     },\n     var base_nat_addresses = {\n-        match (lsp.options.get(\"nat-addresses\")) {\n+        match (lsp.options.get(i\"nat-addresses\")) {\n             None -> { set_empty() },\n-            Some{\"router\"} -> match ((l3dgw_port, opt_chassis, peer)) {\n-                                 (None, None, _) -> set_empty(),\n-                                 (_, _, None) -> set_empty(),\n-                                 (_, _, Some{rport}) -> get_nat_addresses(rport, false)\n-                              },\n             Some{nat_addresses} -> {\n-                /* Only accept manual specification of ethernet address\n-                 * followed by IPv4 addresses on type \"l3gateway\" ports. */\n-                if (opt_chassis.is_some()) {\n-                    match (extract_lsp_addresses(nat_addresses)) {\n-                        None -> {\n-                            warn(\"Error extracting nat-addresses.\");\n-                            set_empty()\n-                        },\n-                        Some{_} -> { set_singleton(nat_addresses) }\n+                if (nat_addresses == i\"router\") {\n+                    match ((l3dgw_port, opt_chassis, peer)) {\n+                       (None, None, _) -> set_empty(),\n+                       (_, _, None) -> set_empty(),\n+                       (_, _, Some{rport}) -> get_nat_addresses(rport, false)\n                     }\n-                } else { set_empty() }\n+                } else {\n+                    /* Only accept manual specification of ethernet address\n+                     * followed by IPv4 addresses on type \"l3gateway\" ports. */\n+                    if (opt_chassis.is_some()) {\n+                        match (extract_lsp_addresses(nat_addresses.ival())) {\n+                            None -> {\n+                                warn(\"Error extracting nat-addresses.\");\n+                                set_empty()\n+                            },\n+                            Some{_} -> { set_singleton(nat_addresses) }\n+                        }\n+                    } else { set_empty() }\n+                }\n             }\n         }\n     },\n@@ -239,13 +241,13 @@ OutProxy_Port_Binding(._uuid              = lsp._uuid,\n      * */\n     var garp_nat_addresses = match (peer) {\n         Some{rport} -> match (\n-            (rport.lrp.options.get_bool_def(\"reside-on-redirect-chassis\", false)\n+            (rport.lrp.options.get_bool_def(i\"reside-on-redirect-chassis\", false)\n              and l3dgw_port.is_some()) or\n             rport.is_redirect or\n-            (rport.router.options.contains_key(\"chassis\") and\n+            (rport.router.options.contains_key(i\"chassis\") and\n              not sw.localnet_ports.is_empty())) {\n             false -> set_empty(),\n-            true -> set_singleton(get_garp_nat_addresses(rport))\n+            true -> set_singleton(get_garp_nat_addresses(rport).intern())\n         },\n         None -> set_empty()\n     },\n@@ -261,46 +263,46 @@ OutProxy_Port_Binding(._uuid              = lrp._uuid,\n                       .datapath           = router._uuid,\n                       .parent_port        = None,\n                       .tag                = None, // always empty for router ports\n-                      .mac                = set_singleton(\"${lrp.mac} ${lrp.networks.join(\\\" \\\")}\"),\n+                      .mac                = set_singleton(i\"${lrp.mac} ${lrp.networks.map(ival).to_vec().join(\\\" \\\")}\"),\n                       .nat_addresses      = set_empty(),\n                       .external_ids       = lrp.external_ids) :-\n     rp in &RouterPort(.lrp = lrp, .router = router, .peer = peer),\n     RouterPortRAOptionsComplete(lrp._uuid, options0),\n-    (var __type, var options1) = match (router.options.get(\"chassis\")) {\n+    (var __type, var options1) = match (router.options.get(i\"chassis\")) {\n         /* TODO: derived ports */\n-        None -> (\"patch\", map_empty()),\n-        Some{lrchassis} -> (\"l3gateway\", [\"l3gateway-chassis\" -> lrchassis])\n+        None -> (i\"patch\", map_empty()),\n+        Some{lrchassis} -> (i\"l3gateway\", [i\"l3gateway-chassis\" -> lrchassis])\n     },\n     var options2 = match (router_peer_name(peer)) {\n         None -> map_empty(),\n-        Some{peer_name} -> [\"peer\" -> peer_name]\n+        Some{peer_name} -> [i\"peer\" -> peer_name]\n     },\n     var options3 = match ((peer, rp.networks.ipv6_addrs.is_empty())) {\n         (PeerSwitch{_, _}, false) -> {\n             var enabled = lrp.is_enabled();\n-            var pd = lrp.options.get_bool_def(\"prefix_delegation\", false);\n-            var p = lrp.options.get_bool_def(\"prefix\", false);\n-            [\"ipv6_prefix_delegation\" -> \"${pd and enabled}\",\n-             \"ipv6_prefix\" -> \"${p and enabled}\"]\n+            var pd = lrp.options.get_bool_def(i\"prefix_delegation\", false);\n+            var p = lrp.options.get_bool_def(i\"prefix\", false);\n+            [i\"ipv6_prefix_delegation\" -> i\"${pd and enabled}\",\n+             i\"ipv6_prefix\" -> i\"${p and enabled}\"]\n         },\n         _ -> map_empty()\n     },\n     PreserveIPv6RAPDList(lrp._uuid, ipv6_ra_pd_list),\n     var options4 = match (ipv6_ra_pd_list) {\n         None -> map_empty(),\n-        Some{value} -> [\"ipv6_ra_pd_list\" -> value]\n+        Some{value} -> [i\"ipv6_ra_pd_list\" -> value]\n     },\n     RouterPortIsRedirect(lrp._uuid, is_redirect),\n     var options5 = match (is_redirect) {\n         false -> map_empty(),\n-        true -> [\"chassis-redirect-port\" -> chassis_redirect_name(lrp.name)]\n+        true -> [i\"chassis-redirect-port\" -> chassis_redirect_name(lrp.name).intern()]\n     },\n     var options = options0.union(options1).union(options2).union(options3).union(options4).union(options5),\n     var eids = {\n         var eids = lrp.external_ids;\n-        match (lrp.external_ids.get(\"neutron:port_name\")) {\n+        match (lrp.external_ids.get(i\"neutron:port_name\")) {\n             None -> (),\n-            Some{name} -> eids.insert(\"name\", name)\n+            Some{name} -> eids.insert(i\"name\", name)\n         };\n         eids\n     }.\n@@ -308,21 +310,20 @@ OutProxy_Port_Binding(._uuid              = lrp._uuid,\n */\n function get_router_load_balancer_ips(router: Intern<Router>,\n                                       routable_only: bool) :\n-    (Set<string>, Set<string>) =\n+    (Set<istring>, Set<istring>) =\n {\n     var all_ips_v4 = set_empty();\n     var all_ips_v6 = set_empty();\n     for (lb in router.lbs) {\n-        if (routable_only and not lb.options.get_bool_def(\"add_route\", false)) {\n+        if (routable_only and not lb.options.get_bool_def(i\"add_route\", false)) {\n             continue;\n         };\n-        for (kv in lb.vips) {\n-            (var vip, _) = kv;\n+        for ((vip, _) in lb.vips) {\n             /* node->key contains IP:port or just IP. */\n-            match (ip_address_and_port_from_lb_key(vip)) {\n+            match (ip_address_and_port_from_lb_key(vip.ival())) {\n                 None -> (),\n-                Some{(IPv4{ipv4}, _)} -> all_ips_v4.insert(\"${ipv4}\"),\n-                Some{(IPv6{ipv6}, _)} -> all_ips_v6.insert(\"${ipv6}\")\n+                Some{(IPv4{ipv4}, _)} -> all_ips_v4.insert(i\"${ipv4}\"),\n+                Some{(IPv6{ipv6}, _)} -> all_ips_v6.insert(i\"${ipv6}\")\n             }\n         }\n     };\n@@ -337,11 +338,11 @@ function get_router_load_balancer_ips(router: Intern<Router>,\n  * external IP addresses of all NAT rules defined on that router, and all\n  * of the IP addresses used in load balancer VIPs defined on that router.\n  */\n-function get_nat_addresses(rport: Intern<RouterPort>, routable_only: bool): Set<string> =\n+function get_nat_addresses(rport: Intern<RouterPort>, routable_only: bool): Set<istring> =\n {\n     var addresses = set_empty();\n     var has_redirect = not rport.router.l3dgw_ports.is_empty();\n-    match (eth_addr_from_string(rport.lrp.mac)) {\n+    match (eth_addr_from_string(rport.lrp.mac.ival())) {\n         None -> addresses,\n         Some{mac} -> {\n             var c_addresses = \"${mac}\";\n@@ -350,19 +351,19 @@ function get_nat_addresses(rport: Intern<RouterPort>, routable_only: bool): Set<\n             /* Get NAT IP addresses. */\n             for (nat in rport.router.nats) {\n                 if (routable_only and\n-                    (nat.nat.__type == \"snat\" or\n-                     not nat.nat.options.get_bool_def(\"add_route\", false))) {\n+                    (nat.nat.__type == i\"snat\" or\n+                     not nat.nat.options.get_bool_def(i\"add_route\", false))) {\n                     continue;\n                 };\n                 /* Determine whether this NAT rule satisfies the conditions for\n                  * distributed NAT processing. */\n-                if (has_redirect and nat.nat.__type == \"dnat_and_snat\" and\n+                if (has_redirect and nat.nat.__type == i\"dnat_and_snat\" and\n                     nat.nat.logical_port.is_some() and nat.external_mac.is_some()) {\n                     /* Distributed NAT rule. */\n-                    var logical_port = option_unwrap_or_default(nat.nat.logical_port);\n-                    var external_mac = option_unwrap_or_default(nat.external_mac);\n-                    addresses.insert(\"${external_mac} ${nat.external_ip} \"\n-                                     \"is_chassis_resident(${json_string_escape(logical_port)})\")\n+                    var logical_port = nat.nat.logical_port.unwrap_or_default();\n+                    var external_mac = nat.external_mac.unwrap_or_default();\n+                    addresses.insert(i\"${external_mac} ${nat.external_ip} \"\n+                                      \"is_chassis_resident(${json_escape(logical_port)})\")\n                 } else {\n                     /* Centralized NAT rule, either on gateway router or distributed\n                      * router.\n@@ -409,11 +410,11 @@ function get_nat_addresses(rport: Intern<RouterPort>, routable_only: bool): Set<\n                 if (has_redirect) {\n                     c_addresses = c_addresses ++ match (rport.router.l3dgw_ports.nth(0)) {\n                         None -> \"\",\n-                        Some {var gw_port} -> \" is_chassis_resident(${json_string_escape(chassis_redirect_name(gw_port.name))})\"\n+                        Some {var gw_port} -> \" is_chassis_resident(${json_escape(chassis_redirect_name(gw_port.name))})\"\n                     }\n                 } else ();\n \n-                addresses.insert(c_addresses)\n+                addresses.insert(c_addresses.intern())\n             } else ();\n             addresses\n         }\n@@ -428,15 +429,15 @@ function get_garp_nat_addresses(rport: Intern<RouterPort>): string = {\n     match (rport.router.l3dgw_ports.nth(0)) {\n         None -> (),\n         Some {var gw_port} -> garp_info.push(\n-            \"is_chassis_resident(${json_string_escape(chassis_redirect_name(gw_port.name))})\")\n+            \"is_chassis_resident(${json_escape(chassis_redirect_name(gw_port.name))})\")\n     };\n     garp_info.join(\" \")\n }\n \n /* Extra options computed for router ports by the logical flow generation code */\n-relation RouterPortRAOptions(lrp: uuid, options: Map<string, string>)\n+relation RouterPortRAOptions(lrp: uuid, options: Map<istring, istring>)\n \n-relation RouterPortRAOptionsComplete(lrp: uuid, options: Map<string, string>)\n+relation RouterPortRAOptionsComplete(lrp: uuid, options: Map<istring, istring>)\n \n RouterPortRAOptionsComplete(lrp, options) :-\n     RouterPortRAOptions(lrp, options).\n@@ -446,7 +447,7 @@ RouterPortRAOptionsComplete(lrp, map_empty()) :-\n \n function has_distributed_nat(nats: Vec<NAT>): bool {\n     for (nat in nats) {\n-        if (nat.nat.__type == \"dnat_and_snat\") {\n+        if (nat.nat.__type == i\"dnat_and_snat\") {\n             return true\n         }\n     };\n@@ -461,31 +462,31 @@ function has_distributed_nat(nats: Vec<NAT>): bool {\n OutProxy_Port_Binding(// lrp._uuid is already in use; generate a new UUID by\n                       // hashing it.\n                       ._uuid              = hash128(lrp._uuid),\n-                      .logical_port       = chassis_redirect_name(lrp.name),\n-                      .__type             = \"chassisredirect\",\n+                      .logical_port       = chassis_redirect_name(lrp.name).intern(),\n+                      .__type             = i\"chassisredirect\",\n                       .gateway_chassis    = set_empty(),\n                       .ha_chassis_group   = Some{hacg_uuid},\n                       .options            = options,\n                       .datapath           = lr_uuid,\n                       .parent_port        = None,\n                       .tag                = None,  //always empty for router ports\n-                      .mac                = set_singleton(\"${lrp.mac} ${lrp.networks.join(\\\" \\\")}\"),\n+                      .mac                = set_singleton(i\"${lrp.mac} ${lrp.networks.map(ival).to_vec().join(\\\" \\\")}\"),\n                       .nat_addresses      = set_empty(),\n                       .external_ids       = lrp.external_ids) :-\n     DistributedGatewayPort(lrp, lr_uuid),\n     DistributedGatewayPortHAChassisGroup(lrp, hacg_uuid),\n-    var redirect_type = match (lrp.options.get(\"redirect-type\")) {\n-        Some{var value} -> [\"redirect-type\" -> value],\n+    var redirect_type = match (lrp.options.get(i\"redirect-type\")) {\n+        Some{var value} -> [i\"redirect-type\" -> value],\n         _ -> map_empty()\n     },\n     LogicalRouterNATs(lr_uuid, nats),\n     var always_redirect = if (has_distributed_nat(nats) or\n-                              lrp.options.get(\"redirect-type\") == Some{\"bridged\"}) {\n+                              lrp.options.get(i\"redirect-type\") == Some{i\"bridged\"}) {\n         map_empty()\n     } else {\n-        [\"always-redirect\" -> \"true\"]\n+        [i\"always-redirect\" -> i\"true\"]\n     },\n-    var options = redirect_type.union(always_redirect).insert_imm(\"distributed-port\", lrp.name).\n+    var options = redirect_type.union(always_redirect).insert_imm(i\"distributed-port\", lrp.name).\n \n /*\n  * We want to preserve 'up' (set by ovn-controller) for Port_Binding rows.\n@@ -523,7 +524,7 @@ sb::Out_Port_Binding(._uuid              = pbinding._uuid,\n     PortBindingUp(pbinding._uuid, up),\n     var options0 = match (qid) {\n         None -> pbinding.options,\n-        Some{id} -> pbinding.options.insert_imm(\"qdisc_queue_id\", \"${id}\")\n+        Some{id} -> pbinding.options.insert_imm(i\"qdisc_queue_id\", i\"${id}\")\n     }.\n \n /* Referenced chassis.\n@@ -578,28 +579,28 @@ HAChassisGroupRefChassisSet(hacg_uuid, chassis_uuids) :-\n /* HA_Chassis_Group and HA_Chassis. */\n sb::Out_HA_Chassis_Group(hacg_uuid, hacg_name, ha_chassis, ref_chassis, eids) :-\n     HAChassis(hacg_uuid, hac_uuid, chassis_name, _, _),\n-    var chassis_uuid = ha_chassis_uuid(chassis_name, hac_uuid),\n+    var chassis_uuid = ha_chassis_uuid(chassis_name.ival(), hac_uuid),\n     var ha_chassis = chassis_uuid.group_by(hacg_uuid).to_set(),\n     HAChassisGroup(hacg_uuid, hacg_name, eids),\n     HAChassisGroupRefChassisSet(hacg_uuid, ref_chassis).\n \n-sb::Out_HA_Chassis(ha_chassis_uuid(chassis_name, hac_uuid), chassis, priority, eids) :-\n+sb::Out_HA_Chassis(ha_chassis_uuid(chassis_name.ival(), hac_uuid), chassis, priority, eids) :-\n     HAChassis(_, hac_uuid, chassis_name, priority, eids),\n     chassis_rec in sb::Chassis(.name = chassis_name),\n     var chassis = Some{chassis_rec._uuid}.\n-sb::Out_HA_Chassis(ha_chassis_uuid(chassis_name, hac_uuid), None, priority, eids) :-\n+sb::Out_HA_Chassis(ha_chassis_uuid(chassis_name.ival(), hac_uuid), None, priority, eids) :-\n     HAChassis(_, hac_uuid, chassis_name, priority, eids),\n     not chassis_rec in sb::Chassis(.name = chassis_name).\n \n-relation HAChassisToChassis(name: string, chassis: Option<uuid>)\n+relation HAChassisToChassis(name: istring, chassis: Option<uuid>)\n HAChassisToChassis(name, Some{chassis}) :-\n     sb::Chassis(._uuid = chassis, .name = name).\n HAChassisToChassis(name, None) :-\n     nb::HA_Chassis(.chassis_name = name),\n     not sb::Chassis(.name = name).\n-sb::Out_HA_Chassis(ha_chassis_uuid(ha_chassis.chassis_name, hac_uuid), chassis, priority, eids) :-\n+sb::Out_HA_Chassis(ha_chassis_uuid(ha_chassis.chassis_name.ival(), hac_uuid), chassis, priority, eids) :-\n     sp in &SwitchPort(),\n-    sp.lsp.__type == \"external\",\n+    sp.lsp.__type == i\"external\",\n     Some{var ha_chassis_group_uuid} = sp.lsp.ha_chassis_group,\n     ha_chassis_group in nb::HA_Chassis_Group(._uuid = ha_chassis_group_uuid),\n     var hac_uuid = FlatMap(ha_chassis_group.ha_chassis),\n@@ -607,14 +608,14 @@ sb::Out_HA_Chassis(ha_chassis_uuid(ha_chassis.chassis_name, hac_uuid), chassis,\n     HAChassisToChassis(ha_chassis.chassis_name, chassis).\n sb::Out_HA_Chassis_Group(_uuid, name, ha_chassis, set_empty() /* XXX? */, eids) :-\n     sp in &SwitchPort(),\n-    sp.lsp.__type == \"external\",\n+    sp.lsp.__type == i\"external\",\n     var ls_uuid = sp.sw._uuid,\n     Some{var ha_chassis_group_uuid} = sp.lsp.ha_chassis_group,\n     ha_chassis_group in nb::HA_Chassis_Group(._uuid = ha_chassis_group_uuid, .name = name,\n                                             .external_ids = eids),\n     var hac_uuid = FlatMap(ha_chassis_group.ha_chassis),\n     ha_chassis in nb::HA_Chassis(._uuid = hac_uuid),\n-    var ha_chassis_uuid_name = ha_chassis_uuid(ha_chassis.chassis_name, hac_uuid),\n+    var ha_chassis_uuid_name = ha_chassis_uuid(ha_chassis.chassis_name.ival(), hac_uuid),\n     var ha_chassis = ha_chassis_uuid_name.group_by((ls_uuid, name, eids)).to_set(),\n     var _uuid = ha_chassis_group_uuid(ls_uuid).\n \n@@ -642,7 +643,7 @@ sb::Out_SB_Global(._uuid          = sb_global._uuid,\n relation ChassisPrivate(\n     cp: sb::Chassis_Private,\n     is_remote: bool)\n-ChassisPrivate(cp, c.other_config.get_bool_def(\"is-remote\", false)) :-\n+ChassisPrivate(cp, c.other_config.get_bool_def(i\"is-remote\", false)) :-\n     cp in sb::Chassis_Private(.chassis = Some{uuid}),\n     c in sb::Chassis(._uuid = uuid).\n ChassisPrivate(cp, false),\n@@ -708,10 +709,14 @@ OutNBGlobal0[nb::Out_NB_Global{._uuid         = _uuid,\n     MacPrefix(mac_prefix),\n     SvcMonitorMac(svc_monitor_mac),\n     OvnMaxDpKeyLocal[max_tunid],\n-    var options0 = put_mac_prefix(nbg.options, mac_prefix),\n-    var options1 = put_svc_monitor_mac(options0, svc_monitor_mac),\n-    var options2 = options1.insert_imm(\"max_tunid\", \"${max_tunid}\"),\n-    var options = options2.insert_imm(\"northd_internal_version\", ovn_internal_version()).\n+    var options = {\n+        var options = nbg.options;\n+        options.put_mac_prefix(mac_prefix);\n+        options.put_svc_monitor_mac(svc_monitor_mac);\n+        options.insert(i\"max_tunid\", i\"${max_tunid}\");\n+        options.insert(i\"northd_internal_version\", ovn_internal_version().intern());\n+        options\n+    }.\n \n relation OutNBGlobal1[nb::Out_NB_Global]\n OutNBGlobal1[x] :- OutNBGlobal0[x].\n@@ -740,12 +745,12 @@ SbCfg[sb_cfg] :- nb::Out_NB_Global(.sb_cfg = sb_cfg).\n output relation Northd_Probe_Interval[s64]\n Northd_Probe_Interval[interval] :-\n     nb in nb::NB_Global(),\n-    var interval = nb.options.get(\"northd_probe_interval\").and_then(parse_dec_i64).unwrap_or(-1).\n+    var interval = nb.options.get(i\"northd_probe_interval\").and_then(parse_dec_i64).unwrap_or(-1).\n \n relation CheckLspIsUp[bool]\n CheckLspIsUp[check_lsp_is_up] :-\n     nb in nb::NB_Global(),\n-    var check_lsp_is_up = not nb.options.get_bool_def(\"ignore_lsp_down\", false).\n+    var check_lsp_is_up = not nb.options.get_bool_def(i\"ignore_lsp_down\", false).\n CheckLspIsUp[true] :-\n     Unit(),\n     not nb in nb::NB_Global().\n@@ -763,13 +768,13 @@ sb::Out_Address_Set(._uuid     = nb_as._uuid,\n     nb_as in &nb::Address_Set().\n \n sb::Out_Address_Set(._uuid = hash128(\"svc_monitor_mac\"),\n-                   .name = \"svc_monitor_mac\",\n-                   .addresses = set_singleton(\"${svc_monitor_mac}\")) :-\n+                   .name = i\"svc_monitor_mac\",\n+                   .addresses = set_singleton(i\"${svc_monitor_mac}\")) :-\n     SvcMonitorMac(svc_monitor_mac).\n \n sb::Out_Address_Set(hash128(as_name), as_name, pg_ip4addrs.union()) :-\n     PortGroupPort(.pg_name = pg_name, .port = port_uuid),\n-    var as_name = pg_name ++ \"_ip4\",\n+    var as_name = i\"${pg_name}_ip4\",\n     // avoid name collisions with user-defined Address_Sets\n     not &nb::Address_Set(.name = as_name),\n     PortStaticAddresses(.lsport = port_uuid, .ip4addrs = stat),\n@@ -779,7 +784,7 @@ sb::Out_Address_Set(hash128(as_name), as_name, pg_ip4addrs.union()) :-\n         None -> set_empty(),\n         Some{lpaddress} -> match (lpaddress.ipv4_addrs.nth(0)) {\n             None -> set_empty(),\n-            Some{addr} -> set_singleton(\"${addr.addr}\")\n+            Some{addr} -> set_singleton(i\"${addr.addr}\")\n         }\n     },\n     //PortDynamicAddresses(.lsport = port_uuid, .ip4addrs = dynamic),\n@@ -788,13 +793,13 @@ sb::Out_Address_Set(hash128(as_name), as_name, pg_ip4addrs.union()) :-\n \n sb::Out_Address_Set(hash128(as_name), as_name, set_empty()) :-\n     nb::Port_Group(.ports = set_empty(), .name = pg_name),\n-    var as_name = pg_name ++ \"_ip4\",\n+    var as_name = i\"${pg_name}_ip4\",\n     // avoid name collisions with user-defined Address_Sets\n     not &nb::Address_Set(.name = as_name).\n \n sb::Out_Address_Set(hash128(as_name), as_name, pg_ip6addrs.union()) :-\n     PortGroupPort(.pg_name = pg_name, .port = port_uuid),\n-    var as_name = pg_name ++ \"_ip6\",\n+    var as_name = i\"${pg_name}_ip6\",\n     // avoid name collisions with user-defined Address_Sets\n     not &nb::Address_Set(.name = as_name),\n     PortStaticAddresses(.lsport = port_uuid, .ip6addrs = stat),\n@@ -804,7 +809,7 @@ sb::Out_Address_Set(hash128(as_name), as_name, pg_ip6addrs.union()) :-\n         None -> set_empty(),\n         Some{lpaddress} -> match (lpaddress.ipv6_addrs.nth(0)) {\n             None -> set_empty(),\n-            Some{addr} -> set_singleton(\"${addr.addr}\")\n+            Some{addr} -> set_singleton(i\"${addr.addr}\")\n         }\n     },\n     //PortDynamicAddresses(.lsport = port_uuid, .ip6addrs = dynamic),\n@@ -813,7 +818,7 @@ sb::Out_Address_Set(hash128(as_name), as_name, pg_ip6addrs.union()) :-\n \n sb::Out_Address_Set(hash128(as_name), as_name, set_empty()) :-\n     nb::Port_Group(.ports = set_empty(), .name = pg_name),\n-    var as_name = pg_name ++ \"_ip6\",\n+    var as_name = i\"${pg_name}_ip6\",\n     // avoid name collisions with user-defined Address_Sets\n     not &nb::Address_Set(.name = as_name).\n \n@@ -828,7 +833,7 @@ sb::Out_Address_Set(hash128(as_name), as_name, set_empty()) :-\n \n relation PortGroupPort(\n     pg_uuid: uuid,\n-    pg_name: string,\n+    pg_name: istring,\n     port: uuid)\n \n PortGroupPort(pg_uuid, pg_name, port) :-\n@@ -841,7 +846,7 @@ sb::Out_Port_Group(._uuid = hash128(sb_name), .name = sb_name, .ports = port_nam\n                                                     .name = port_name},\n                 .sw = &Switch{._uuid = ls_uuid}),\n     TunKeyAllocation(.datapath = ls_uuid, .tunkey = tunkey),\n-    var sb_name = \"${tunkey}_${nb_name}\",\n+    var sb_name = i\"${tunkey}_${nb_name}\",\n     var port_names = port_name.group_by((_uuid, sb_name)).to_set().\n \n /*\n@@ -852,29 +857,29 @@ sb::Out_Port_Group(._uuid = hash128(sb_name), .name = sb_name, .ports = port_nam\n  * - dynamically created rows based on IGMP groups learned by controllers.\n  */\n \n-function mC_FLOOD():         (string, integer) =\n-    (\"_MC_flood\", 32768)\n+function mC_FLOOD():         (istring, integer) =\n+    (i\"_MC_flood\", 32768)\n \n-function mC_UNKNOWN():       (string, integer) =\n-    (\"_MC_unknown\", 32769)\n+function mC_UNKNOWN():       (istring, integer) =\n+    (i\"_MC_unknown\", 32769)\n \n-function mC_MROUTER_FLOOD(): (string, integer) =\n-    (\"_MC_mrouter_flood\", 32770)\n+function mC_MROUTER_FLOOD(): (istring, integer) =\n+    (i\"_MC_mrouter_flood\", 32770)\n \n-function mC_MROUTER_STATIC(): (string, integer) =\n-    (\"_MC_mrouter_static\", 32771)\n+function mC_MROUTER_STATIC(): (istring, integer) =\n+    (i\"_MC_mrouter_static\", 32771)\n \n-function mC_STATIC(): (string, integer) =\n-    (\"_MC_static\", 32772)\n+function mC_STATIC(): (istring, integer) =\n+    (i\"_MC_static\", 32772)\n \n-function mC_FLOOD_L2(): (string, integer) =\n-    (\"_MC_flood_l2\", 32773)\n+function mC_FLOOD_L2(): (istring, integer) =\n+    (i\"_MC_flood_l2\", 32773)\n \n-function mC_IP_MCAST_MIN():  (string, integer) =\n-    (\"_MC_ip_mcast_min\", 32774)\n+function mC_IP_MCAST_MIN():  (istring, integer) =\n+    (i\"_MC_ip_mcast_min\", 32774)\n \n-function mC_IP_MCAST_MAX():  (string, integer) =\n-    (\"_MC_ip_mcast_max\", 65535)\n+function mC_IP_MCAST_MAX():  (istring, integer) =\n+    (i\"_MC_ip_mcast_max\", 65535)\n \n \n // TODO: check that Multicast_Group.ports should not include derived ports\n@@ -885,7 +890,7 @@ function mC_IP_MCAST_MAX():  (string, integer) =\n  * MulticastGroupTunKeyAllocation). */\n relation OutProxy_Multicast_Group (\n     datapath: uuid,\n-    name: string,\n+    name: istring,\n     ports: Set<uuid>\n )\n \n@@ -910,7 +915,7 @@ sb::Out_Multicast_Group (._uuid      = hash128((datapath,name)),\n                         .ports      = port_ids) :-\n     &SwitchPort(.lsp = lsp, .sw = sw),\n     lsp.is_enabled(),\n-    lsp.__type != \"router\",\n+    lsp.__type != i\"router\",\n     var datapath = sw._uuid,\n     var port_ids = lsp._uuid.group_by((datapath)).to_set(),\n     (var name, var tunnel_key) = mC_FLOOD_L2().\n@@ -1015,261 +1020,261 @@ sb::Out_MAC_Binding (._uuid        = mb._uuid,\n  */\n sb::Out_DHCP_Options (\n     ._uuid  = 128'h7d9d898a_179b_4898_8382_b73bec391f23,\n-    .name   = \"offerip\",\n+    .name   = i\"offerip\",\n     .code   = 0,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hea5e7d14_fd97_491c_8004_a120bdbc4306,\n-    .name   = \"netmask\",\n+    .name   = i\"netmask\",\n     .code   = 1,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hdab5e39b_6702_4245_9573_6c142aa3724c,\n-    .name   = \"router\",\n+    .name   = i\"router\",\n     .code   = 3,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h340b4bc5_c5c3_43d1_ae77_564da69c8fcc,\n-    .name   = \"dns_server\",\n+    .name   = i\"dns_server\",\n     .code   = 6,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hcd1ab302_cbb2_4eab_9ec5_ec1c8541bd82,\n-    .name   = \"log_server\",\n+    .name   = i\"log_server\",\n     .code   = 7,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h1c7ea6a0_fe6b_48c1_a920_302583c1ff08,\n-    .name   = \"lpr_server\",\n+    .name   = i\"lpr_server\",\n     .code   = 9,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hae312373_2261_41b5_a2c4_186f426dd929,\n-    .name   = \"hostname\",\n+    .name   = i\"hostname\",\n     .code   = 12,\n-    .__type = \"str\"\n+    .__type = i\"str\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hae35e575_226a_4ab5_a1c4_166f426dd999,\n-    .name   = \"domain_name\",\n+    .name   = i\"domain_name\",\n     .code   = 15,\n-    .__type = \"str\"\n+    .__type = i\"str\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'had0ec3e0_8be9_4c77_bceb_f8954a34c7ba,\n-    .name   = \"swap_server\",\n+    .name   = i\"swap_server\",\n     .code   = 16,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h884c2e02_6e99_4d12_aef7_8454ebf8a3b7,\n-    .name   = \"policy_filter\",\n+    .name   = i\"policy_filter\",\n     .code   = 21,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h57cc2c61_fd2a_41c6_b6b1_6ce9a8901f86,\n-    .name   = \"router_solicitation\",\n+    .name   = i\"router_solicitation\",\n     .code   = 32,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h48249097_03f0_46c1_a32a_2dd57cd4d0f8,\n-    .name   = \"nis_server\",\n+    .name   = i\"nis_server\",\n     .code   = 41,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h333fe07e_bdd1_4371_aa4f_a412bc60f3a2,\n-    .name   = \"ntp_server\",\n+    .name   = i\"ntp_server\",\n     .code   = 42,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h6207109c_49d0_4348_8238_dd92afb69bf0,\n-    .name   = \"server_id\",\n+    .name   = i\"server_id\",\n     .code   = 54,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h2090b783_26d3_4c1d_830c_54c1b6c5d846,\n-    .name   = \"tftp_server\",\n+    .name   = i\"tftp_server\",\n     .code   = 66,\n-    .__type = \"host_id\"\n+    .__type = i\"host_id\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'ha18ff399_caea_406e_af7e_321c6f74e581,\n-    .name   = \"classless_static_route\",\n+    .name   = i\"classless_static_route\",\n     .code   = 121,\n-    .__type = \"static_routes\"\n+    .__type = i\"static_routes\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hb81ad7b4_62f0_40c7_a9a3_f96677628767,\n-    .name   = \"ms_classless_static_route\",\n+    .name   = i\"ms_classless_static_route\",\n     .code   = 249,\n-    .__type = \"static_routes\"\n+    .__type = i\"static_routes\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h0c2e144e_4b5f_4e21_8978_0e20bac9a6ea,\n-    .name   = \"ip_forward_enable\",\n+    .name   = i\"ip_forward_enable\",\n     .code   = 19,\n-    .__type = \"bool\"\n+    .__type = i\"bool\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h6feb1926_9469_4b40_bfbf_478b9888cd3a,\n-    .name   = \"router_discovery\",\n+    .name   = i\"router_discovery\",\n     .code   = 31,\n-    .__type = \"bool\"\n+    .__type = i\"bool\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hcb776249_e8b1_4502_b33b_fa294d44077d,\n-    .name   = \"ethernet_encap\",\n+    .name   = i\"ethernet_encap\",\n     .code   = 36,\n-    .__type = \"bool\"\n+    .__type = i\"bool\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'ha2df9eaa_aea9_497f_b339_0c8ec3e39a07,\n-    .name   = \"default_ttl\",\n+    .name   = i\"default_ttl\",\n     .code   = 23,\n-    .__type = \"uint8\"\n+    .__type = i\"uint8\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hb44b45a9_5004_4ef5_8e6a_aa8629e1afb1,\n-    .name   = \"tcp_ttl\",\n+    .name   = i\"tcp_ttl\",\n     .code   = 37,\n-    .__type = \"uint8\"\n+    .__type = i\"uint8\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h50f01ca7_c650_46f0_8f50_39a67ec657da,\n-    .name   = \"mtu\",\n+    .name   = i\"mtu\",\n     .code   = 26,\n-    .__type = \"uint16\"\n+    .__type = i\"uint16\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h9d31c057_6085_4810_96af_eeac7d3c5308,\n-    .name   = \"lease_time\",\n+    .name   = i\"lease_time\",\n     .code   = 51,\n-    .__type = \"uint32\"\n+    .__type = i\"uint32\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hea1e2e7a_9585_46ee_ad49_adfdefc0c4ef,\n-    .name   = \"T1\",\n+    .name   = i\"T1\",\n     .code   = 58,\n-    .__type = \"uint32\"\n+    .__type = i\"uint32\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hbc83a233_554b_453a_afca_1eadf76810d2,\n-    .name   = \"T2\",\n+    .name   = i\"T2\",\n     .code   = 59,\n-    .__type = \"uint32\"\n+    .__type = i\"uint32\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h1ab3eeca_0523_4101_9076_eea77d0232f4,\n-    .name   = \"bootfile_name\",\n+    .name   = i\"bootfile_name\",\n     .code   = 67,\n-    .__type = \"str\"\n+    .__type = i\"str\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'ha5c20b69_f7f3_4fa8_b550_8697aec6cbb7,\n-    .name   = \"wpad\",\n+    .name   = i\"wpad\",\n     .code   = 252,\n-    .__type = \"str\"\n+    .__type = i\"str\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h1516bcb6_cc93_4233_a63f_bd29c8601831,\n-    .name   = \"path_prefix\",\n+    .name   = i\"path_prefix\",\n     .code   = 210,\n-    .__type = \"str\"\n+    .__type = i\"str\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hc98e13cd_f653_473c_85c1_850dcad685fc,\n-    .name   = \"tftp_server_address\",\n+    .name   = i\"tftp_server_address\",\n     .code   = 150,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hfbe06e70_b43d_4dd9_9b21_2f27eb5da5df,\n-    .name   = \"arp_cache_timeout\",\n+    .name   = i\"arp_cache_timeout\",\n     .code   = 35,\n-    .__type = \"uint32\"\n+    .__type = i\"uint32\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h2af54a3c_545c_4104_ae1c_432caa3e085e,\n-    .name   = \"tcp_keepalive_interval\",\n+    .name   = i\"tcp_keepalive_interval\",\n     .code   = 38,\n-    .__type = \"uint32\"\n+    .__type = i\"uint32\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h4b2144e8_8d3f_4d96_9032_fe23c1866cd4,\n-    .name   = \"domain_search_list\",\n+    .name   = i\"domain_search_list\",\n     .code   = 119,\n-    .__type = \"domains\"\n+    .__type = i\"domains\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'hb7236164_eea4_4bf2_9306_8619a9e3ad1d,\n-    .name   = \"broadcast_address\",\n+    .name   = i\"broadcast_address\",\n     .code   = 28,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h32224b72_1561_4279_b430_982423b62a69,\n-    .name   = \"netbios_name_server\",\n+    .name   = i\"netbios_name_server\",\n     .code   = 44,\n-    .__type = \"ipv4\"\n+    .__type = i\"ipv4\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h691db4ae_624e_43e2_9f4a_5ed9de58f0e5,\n-    .name   = \"netbios_node_type\",\n+    .name   = i\"netbios_node_type\",\n     .code   = 46,\n-    .__type = \"uint8\"\n+    .__type = i\"uint8\"\n ).\n \n sb::Out_DHCP_Options (\n     ._uuid  = 128'h2d738583_96f4_4a78_99a1_f8f7fe328f3f,\n-    .name   = \"bootfile_name_alt\",\n+    .name   = i\"bootfile_name_alt\",\n     .code   = 254,\n-    .__type = \"str\"\n+    .__type = i\"str\"\n ).\n \n \n@@ -1278,30 +1283,30 @@ sb::Out_DHCP_Options (\n  */\n sb::Out_DHCPv6_Options (\n     ._uuid  = 128'h100b2659_0ec0_4da7_9ec3_25997f92dc00,\n-    .name   = \"server_id\",\n+    .name   = i\"server_id\",\n     .code   = 2,\n-    .__type = \"mac\"\n+    .__type = i\"mac\"\n ).\n \n sb::Out_DHCPv6_Options (\n     ._uuid  = 128'h53f49b50_db75_4b0d_83df_50d31009ca9c,\n-    .name   = \"ia_addr\",\n+    .name   = i\"ia_addr\",\n     .code   = 5,\n-    .__type = \"ipv6\"\n+    .__type = i\"ipv6\"\n ).\n \n sb::Out_DHCPv6_Options (\n     ._uuid  = 128'he3619685_d4f7_42ad_936b_4f4440b7eeb4,\n-    .name   = \"dns_server\",\n+    .name   = i\"dns_server\",\n     .code   = 23,\n-    .__type = \"ipv6\"\n+    .__type = i\"ipv6\"\n ).\n \n sb::Out_DHCPv6_Options (\n     ._uuid  = 128'hcb8a4e7f_a312_4cb1_a846_e474d9f0c531,\n-    .name   = \"domain_search\",\n+    .name   = i\"domain_search\",\n     .code   = 24,\n-    .__type = \"str\"\n+    .__type = i\"str\"\n ).\n \n \n@@ -1309,19 +1314,18 @@ sb::Out_DHCPv6_Options (\n  * DNS: copied from NB + datapaths column pointer to LS datapaths that use the record\n  */\n \n-function map_to_lowercase(m_in: Map<string,string>): Map<string,string> {\n+function map_to_lowercase(m_in: Map<istring,istring>): Map<istring,istring> {\n     var m_out = map_empty();\n-    for (node in m_in) {\n-        (var k, var v) = node;\n-        m_out.insert(string_to_lowercase(k), string_to_lowercase(v))\n+    for ((k, v) in m_in) {\n+        m_out.insert(k.to_lowercase().intern(), v.to_lowercase().intern())\n     };\n     m_out\n }\n \n-sb::Out_DNS(._uuid        = hash128(nbdns._uuid),\n+sb::Out_DNS(._uuid       = hash128(nbdns._uuid),\n            .records      = map_to_lowercase(nbdns.records),\n            .datapaths    = datapaths,\n-           .external_ids = nbdns.external_ids.insert_imm(\"dns_id\", uuid2str(nbdns._uuid))) :-\n+           .external_ids = nbdns.external_ids.insert_imm(i\"dns_id\", uuid2str(nbdns._uuid).intern())) :-\n     nb::DNS[nbdns],\n     LogicalSwitchDNS(ls_uuid, nbdns._uuid),\n     var datapaths = ls_uuid.group_by(nbdns).to_set().\n@@ -1332,77 +1336,77 @@ sb::Out_DNS(._uuid        = hash128(nbdns._uuid),\n \n sb::Out_RBAC_Permission (\n     ._uuid          = 128'h7df3749a_1754_4a78_afa4_3abf526fe510,\n-    .table          = \"Chassis\",\n-    .authorization  = set_singleton(\"name\"),\n+    .table          = i\"Chassis\",\n+    .authorization  = set_singleton(i\"name\"),\n     .insert_delete  = true,\n-    .update         = [\"nb_cfg\", \"external_ids\", \"encaps\",\n-                       \"vtep_logical_switches\", \"other_config\",\n-                       \"transport_zones\"].to_set()\n+    .update         = [i\"nb_cfg\", i\"external_ids\", i\"encaps\",\n+                       i\"vtep_logical_switches\", i\"other_config\",\n+                       i\"transport_zones\"].to_set()\n ).\n \n sb::Out_RBAC_Permission (\n     ._uuid          = 128'h07e623f7_137c_4a11_9084_3b3f89cb4a54,\n-    .table          = \"Chassis_Private\",\n-    .authorization  = set_singleton(\"name\"),\n+    .table          = i\"Chassis_Private\",\n+    .authorization  = set_singleton(i\"name\"),\n     .insert_delete  = true,\n-    .update         = [\"nb_cfg\", \"nb_cfg_timestamp\", \"chassis\", \"external_ids\"].to_set()\n+    .update         = [i\"nb_cfg\", i\"nb_cfg_timestamp\", i\"chassis\", i\"external_ids\"].to_set()\n ).\n \n sb::Out_RBAC_Permission (\n     ._uuid          = 128'h94bec860_431e_4d95_82e7_3b75d8997241,\n-    .table          = \"Encap\",\n-    .authorization  = set_singleton(\"chassis_name\"),\n+    .table          = i\"Encap\",\n+    .authorization  = set_singleton(i\"chassis_name\"),\n     .insert_delete  = true,\n-    .update         = [\"type\", \"options\", \"ip\"].to_set()\n+    .update         = [i\"type\", i\"options\", i\"ip\"].to_set()\n ).\n \n sb::Out_RBAC_Permission (\n     ._uuid          = 128'hd8ceff1a_2b11_48bd_802f_4a991aa4e908,\n-    .table          = \"Port_Binding\",\n-    .authorization  = set_singleton(\"\"),\n+    .table          = i\"Port_Binding\",\n+    .authorization  = set_singleton(i\"\"),\n     .insert_delete  = false,\n-    .update         = [\"chassis\", \"encap\", \"up\", \"virtual_parent\"].to_set()\n+    .update         = [i\"chassis\", i\"encap\", i\"up\", i\"virtual_parent\"].to_set()\n ).\n \n sb::Out_RBAC_Permission (\n     ._uuid          = 128'h6ffdc696_8bfb_4d82_b620_a00d39270b2f,\n-    .table          = \"MAC_Binding\",\n-    .authorization  = set_singleton(\"\"),\n+    .table          = i\"MAC_Binding\",\n+    .authorization  = set_singleton(i\"\"),\n     .insert_delete  = true,\n-    .update         = [\"logical_port\", \"ip\", \"mac\", \"datapath\"].to_set()\n+    .update         = [i\"logical_port\", i\"ip\", i\"mac\", i\"datapath\"].to_set()\n ).\n \n sb::Out_RBAC_Permission (\n     ._uuid          = 128'h39231c7e_4bf1_41d0_ada4_1d8a319c0da3,\n-    .table          = \"Service_Monitor\",\n-    .authorization  = set_singleton(\"\"),\n+    .table          = i\"Service_Monitor\",\n+    .authorization  = set_singleton(i\"\"),\n     .insert_delete  = false,\n-    .update         = set_singleton(\"status\")\n+    .update         = set_singleton(i\"status\")\n ).\n \n sb::Out_RBAC_Permission (\n     ._uuid          = 128'h5256f48e_172c_4d85_8f04_e199fa817633,\n-    .table          = \"IGMP_Group\",\n-    .authorization  = set_singleton(\"\"),\n+    .table          = i\"IGMP_Group\",\n+    .authorization  = set_singleton(i\"\"),\n     .insert_delete  = true,\n-    .update         = [\"address\", \"chassis\", \"datapath\", \"ports\"].to_set()\n+    .update         = [i\"address\", i\"chassis\", i\"datapath\", i\"ports\"].to_set()\n ).\n \n sb::Out_RBAC_Permission (\n     ._uuid          = 128'h2e5cbf3d_26f6_4f8a_9926_d6f77f61654f,\n-    .table          = \"Controller_Event\",\n-    .authorization  = set_singleton(\"\"),\n+    .table          = i\"Controller_Event\",\n+    .authorization  = set_singleton(i\"\"),\n     .insert_delete  = true,\n-    .update         = [\"chassis\", \"event_info\", \"event_type\",\n-                       \"seq_num\"].to_set()\n+    .update         = [i\"chassis\", i\"event_info\", i\"event_type\",\n+                       i\"seq_num\"].to_set()\n ).\n \n sb::Out_RBAC_Permission (\n     ._uuid          = 128'hb70964fc_322f_4ae5_aee4_ff6afadcc126,\n-    .table          = \"FDB\",\n-    .authorization  = set_singleton(\"\"),\n+    .table          = i\"FDB\",\n+    .authorization  = set_singleton(i\"\"),\n     .insert_delete  = true,\n-    .update         = [\"dp_key\", \"mac\", \"port_key\"].to_set()\n+    .update         = [i\"dp_key\", i\"mac\", i\"port_key\"].to_set()\n ).\n \n /*\n@@ -1410,17 +1414,17 @@ sb::Out_RBAC_Permission (\n  */\n sb::Out_RBAC_Role (\n     ._uuid       = 128'ha406b472_5de8_4456_9f38_bf344c911b22,\n-    .name        = \"ovn-controller\",\n+    .name        = i\"ovn-controller\",\n     .permissions = [\n-        \"Chassis\" -> 128'h7df3749a_1754_4a78_afa4_3abf526fe510,\n-        \"Chassis_Private\" -> 128'h07e623f7_137c_4a11_9084_3b3f89cb4a54,\n-        \"Controller_Event\" -> 128'h2e5cbf3d_26f6_4f8a_9926_d6f77f61654f,\n-        \"Encap\" -> 128'h94bec860_431e_4d95_82e7_3b75d8997241,\n-        \"FDB\" -> 128'hb70964fc_322f_4ae5_aee4_ff6afadcc126,\n-        \"IGMP_Group\" -> 128'h5256f48e_172c_4d85_8f04_e199fa817633,\n-        \"Port_Binding\" -> 128'hd8ceff1a_2b11_48bd_802f_4a991aa4e908,\n-        \"MAC_Binding\" -> 128'h6ffdc696_8bfb_4d82_b620_a00d39270b2f,\n-        \"Service_Monitor\"-> 128'h39231c7e_4bf1_41d0_ada4_1d8a319c0da3]\n+        i\"Chassis\" -> 128'h7df3749a_1754_4a78_afa4_3abf526fe510,\n+        i\"Chassis_Private\" -> 128'h07e623f7_137c_4a11_9084_3b3f89cb4a54,\n+        i\"Controller_Event\" -> 128'h2e5cbf3d_26f6_4f8a_9926_d6f77f61654f,\n+        i\"Encap\" -> 128'h94bec860_431e_4d95_82e7_3b75d8997241,\n+        i\"FDB\" -> 128'hb70964fc_322f_4ae5_aee4_ff6afadcc126,\n+        i\"IGMP_Group\" -> 128'h5256f48e_172c_4d85_8f04_e199fa817633,\n+        i\"Port_Binding\" -> 128'hd8ceff1a_2b11_48bd_802f_4a991aa4e908,\n+        i\"MAC_Binding\" -> 128'h6ffdc696_8bfb_4d82_b620_a00d39270b2f,\n+        i\"Service_Monitor\"-> 128'h39231c7e_4bf1_41d0_ada4_1d8a319c0da3]\n \n ).\n \n@@ -1430,23 +1434,23 @@ nb::Out_Logical_Switch_Port(._uuid                  = lsp._uuid,\n                            .dynamic_addresses      = dynamic_addresses,\n                            .up                     = Some{up}) :-\n     SwitchPortNewDynamicAddress(&SwitchPort{.lsp = lsp, .up = up}, opt_dyn_addr),\n-    var dynamic_addresses = opt_dyn_addr.and_then(|a| Some{\"${a}\"}),\n+    var dynamic_addresses = opt_dyn_addr.and_then(|a| Some{i\"${a}\"}),\n     SwitchPortNewDynamicTag(lsp._uuid, opt_tag),\n     var tag = match (opt_tag) {\n         None -> lsp.tag,\n         Some{t} -> Some{t}\n     }.\n \n-relation LRPIPv6Prefix0(lrp_uuid: uuid, ipv6_prefix: string)\n-LRPIPv6Prefix0(lrp._uuid, ipv6_prefix) :-\n+relation LRPIPv6Prefix0(lrp_uuid: uuid, ipv6_prefix: istring)\n+LRPIPv6Prefix0(lrp._uuid, ipv6_prefix.intern()) :-\n     lrp in &nb::Logical_Router_Port(),\n-    lrp.options.get_bool_def(\"prefix\", false),\n+    lrp.options.get_bool_def(i\"prefix\", false),\n     sb::Port_Binding(.logical_port = lrp.name, .options = options),\n-    Some{var ipv6_ra_pd_list} = options.get(\"ipv6_ra_pd_list\"),\n-    var parts = string_split(ipv6_ra_pd_list, \",\"),\n+    Some{var ipv6_ra_pd_list} = options.get(i\"ipv6_ra_pd_list\"),\n+    var parts = ipv6_ra_pd_list.split(\",\"),\n     Some{var ipv6_prefix} = parts.nth(1).\n \n-relation LRPIPv6Prefix(lrp_uuid: uuid, ipv6_prefix: Option<string>)\n+relation LRPIPv6Prefix(lrp_uuid: uuid, ipv6_prefix: Option<istring>)\n LRPIPv6Prefix(lrp_uuid, Some{ipv6_prefix}) :-\n     LRPIPv6Prefix0(lrp_uuid, ipv6_prefix).\n LRPIPv6Prefix(lrp_uuid, None) :-\n@@ -1463,74 +1467,74 @@ typedef Pipeline = Ingress | Egress\n typedef Stage = Stage {\n     pipeline    : Pipeline,\n     table_id    : bit<8>,\n-    table_name  : string\n+    table_name  : istring\n }\n \n /* Logical switch ingress stages. */\n-function s_SWITCH_IN_PORT_SEC_L2():     Intern<Stage> { Stage{Ingress,  0, \"ls_in_port_sec_l2\"}.intern() }\n-function s_SWITCH_IN_PORT_SEC_IP():     Intern<Stage> { Stage{Ingress,  1, \"ls_in_port_sec_ip\"}.intern() }\n-function s_SWITCH_IN_PORT_SEC_ND():     Intern<Stage> { Stage{Ingress,  2, \"ls_in_port_sec_nd\"}.intern() }\n-function s_SWITCH_IN_LOOKUP_FDB():      Intern<Stage> { Stage{Ingress,  3, \"ls_in_lookup_fdb\"}.intern() }\n-function s_SWITCH_IN_PUT_FDB():         Intern<Stage> { Stage{Ingress,  4, \"ls_in_put_fdb\"}.intern() }\n-function s_SWITCH_IN_PRE_ACL():         Intern<Stage> { Stage{Ingress,  5, \"ls_in_pre_acl\"}.intern() }\n-function s_SWITCH_IN_PRE_LB():          Intern<Stage> { Stage{Ingress,  6, \"ls_in_pre_lb\"}.intern() }\n-function s_SWITCH_IN_PRE_STATEFUL():    Intern<Stage> { Stage{Ingress,  7, \"ls_in_pre_stateful\"}.intern() }\n-function s_SWITCH_IN_ACL_HINT():        Intern<Stage> { Stage{Ingress,  8, \"ls_in_acl_hint\"}.intern() }\n-function s_SWITCH_IN_ACL():             Intern<Stage> { Stage{Ingress,  9, \"ls_in_acl\"}.intern() }\n-function s_SWITCH_IN_QOS_MARK():        Intern<Stage> { Stage{Ingress, 10, \"ls_in_qos_mark\"}.intern() }\n-function s_SWITCH_IN_QOS_METER():       Intern<Stage> { Stage{Ingress, 11, \"ls_in_qos_meter\"}.intern() }\n-function s_SWITCH_IN_STATEFUL():        Intern<Stage> { Stage{Ingress, 12, \"ls_in_stateful\"}.intern() }\n-function s_SWITCH_IN_PRE_HAIRPIN():     Intern<Stage> { Stage{Ingress, 13, \"ls_in_pre_hairpin\"}.intern() }\n-function s_SWITCH_IN_NAT_HAIRPIN():     Intern<Stage> { Stage{Ingress, 14, \"ls_in_nat_hairpin\"}.intern() }\n-function s_SWITCH_IN_HAIRPIN():         Intern<Stage> { Stage{Ingress, 15, \"ls_in_hairpin\"}.intern() }\n-function s_SWITCH_IN_ARP_ND_RSP():      Intern<Stage> { Stage{Ingress, 16, \"ls_in_arp_rsp\"}.intern() }\n-function s_SWITCH_IN_DHCP_OPTIONS():    Intern<Stage> { Stage{Ingress, 17, \"ls_in_dhcp_options\"}.intern() }\n-function s_SWITCH_IN_DHCP_RESPONSE():   Intern<Stage> { Stage{Ingress, 18, \"ls_in_dhcp_response\"}.intern() }\n-function s_SWITCH_IN_DNS_LOOKUP():      Intern<Stage> { Stage{Ingress, 19, \"ls_in_dns_lookup\"}.intern() }\n-function s_SWITCH_IN_DNS_RESPONSE():    Intern<Stage> { Stage{Ingress, 20, \"ls_in_dns_response\"}.intern() }\n-function s_SWITCH_IN_EXTERNAL_PORT():   Intern<Stage> { Stage{Ingress, 21, \"ls_in_external_port\"}.intern() }\n-function s_SWITCH_IN_L2_LKUP():         Intern<Stage> { Stage{Ingress, 22, \"ls_in_l2_lkup\"}.intern() }\n-function s_SWITCH_IN_L2_UNKNOWN():      Intern<Stage> { Stage{Ingress, 23, \"ls_in_l2_unknown\"}.intern() }\n+function s_SWITCH_IN_PORT_SEC_L2():     Intern<Stage> { Stage{Ingress,  0, i\"ls_in_port_sec_l2\"}.intern() }\n+function s_SWITCH_IN_PORT_SEC_IP():     Intern<Stage> { Stage{Ingress,  1, i\"ls_in_port_sec_ip\"}.intern() }\n+function s_SWITCH_IN_PORT_SEC_ND():     Intern<Stage> { Stage{Ingress,  2, i\"ls_in_port_sec_nd\"}.intern() }\n+function s_SWITCH_IN_LOOKUP_FDB():      Intern<Stage> { Stage{Ingress,  3, i\"ls_in_lookup_fdb\"}.intern() }\n+function s_SWITCH_IN_PUT_FDB():         Intern<Stage> { Stage{Ingress,  4, i\"ls_in_put_fdb\"}.intern() }\n+function s_SWITCH_IN_PRE_ACL():         Intern<Stage> { Stage{Ingress,  5, i\"ls_in_pre_acl\"}.intern() }\n+function s_SWITCH_IN_PRE_LB():          Intern<Stage> { Stage{Ingress,  6, i\"ls_in_pre_lb\"}.intern() }\n+function s_SWITCH_IN_PRE_STATEFUL():    Intern<Stage> { Stage{Ingress,  7, i\"ls_in_pre_stateful\"}.intern() }\n+function s_SWITCH_IN_ACL_HINT():        Intern<Stage> { Stage{Ingress,  8, i\"ls_in_acl_hint\"}.intern() }\n+function s_SWITCH_IN_ACL():             Intern<Stage> { Stage{Ingress,  9, i\"ls_in_acl\"}.intern() }\n+function s_SWITCH_IN_QOS_MARK():        Intern<Stage> { Stage{Ingress, 10, i\"ls_in_qos_mark\"}.intern() }\n+function s_SWITCH_IN_QOS_METER():       Intern<Stage> { Stage{Ingress, 11, i\"ls_in_qos_meter\"}.intern() }\n+function s_SWITCH_IN_STATEFUL():        Intern<Stage> { Stage{Ingress, 12, i\"ls_in_stateful\"}.intern() }\n+function s_SWITCH_IN_PRE_HAIRPIN():     Intern<Stage> { Stage{Ingress, 13, i\"ls_in_pre_hairpin\"}.intern() }\n+function s_SWITCH_IN_NAT_HAIRPIN():     Intern<Stage> { Stage{Ingress, 14, i\"ls_in_nat_hairpin\"}.intern() }\n+function s_SWITCH_IN_HAIRPIN():         Intern<Stage> { Stage{Ingress, 15, i\"ls_in_hairpin\"}.intern() }\n+function s_SWITCH_IN_ARP_ND_RSP():      Intern<Stage> { Stage{Ingress, 16, i\"ls_in_arp_rsp\"}.intern() }\n+function s_SWITCH_IN_DHCP_OPTIONS():    Intern<Stage> { Stage{Ingress, 17, i\"ls_in_dhcp_options\"}.intern() }\n+function s_SWITCH_IN_DHCP_RESPONSE():   Intern<Stage> { Stage{Ingress, 18, i\"ls_in_dhcp_response\"}.intern() }\n+function s_SWITCH_IN_DNS_LOOKUP():      Intern<Stage> { Stage{Ingress, 19, i\"ls_in_dns_lookup\"}.intern() }\n+function s_SWITCH_IN_DNS_RESPONSE():    Intern<Stage> { Stage{Ingress, 20, i\"ls_in_dns_response\"}.intern() }\n+function s_SWITCH_IN_EXTERNAL_PORT():   Intern<Stage> { Stage{Ingress, 21, i\"ls_in_external_port\"}.intern() }\n+function s_SWITCH_IN_L2_LKUP():         Intern<Stage> { Stage{Ingress, 22, i\"ls_in_l2_lkup\"}.intern() }\n+function s_SWITCH_IN_L2_UNKNOWN():      Intern<Stage> { Stage{Ingress, 23, i\"ls_in_l2_unknown\"}.intern() }\n \n /* Logical switch egress stages. */\n-function s_SWITCH_OUT_PRE_LB():         Intern<Stage> { Stage{ Egress,  0, \"ls_out_pre_lb\"}.intern() }\n-function s_SWITCH_OUT_PRE_ACL():        Intern<Stage> { Stage{ Egress,  1, \"ls_out_pre_acl\"}.intern() }\n-function s_SWITCH_OUT_PRE_STATEFUL():   Intern<Stage> { Stage{ Egress,  2, \"ls_out_pre_stateful\"}.intern() }\n-function s_SWITCH_OUT_ACL_HINT():       Intern<Stage> { Stage{ Egress,  3, \"ls_out_acl_hint\"}.intern() }\n-function s_SWITCH_OUT_ACL():            Intern<Stage> { Stage{ Egress,  4, \"ls_out_acl\"}.intern() }\n-function s_SWITCH_OUT_QOS_MARK():       Intern<Stage> { Stage{ Egress,  5, \"ls_out_qos_mark\"}.intern() }\n-function s_SWITCH_OUT_QOS_METER():      Intern<Stage> { Stage{ Egress,  6, \"ls_out_qos_meter\"}.intern() }\n-function s_SWITCH_OUT_STATEFUL():       Intern<Stage> { Stage{ Egress,  7, \"ls_out_stateful\"}.intern() }\n-function s_SWITCH_OUT_PORT_SEC_IP():    Intern<Stage> { Stage{ Egress,  8, \"ls_out_port_sec_ip\"}.intern() }\n-function s_SWITCH_OUT_PORT_SEC_L2():    Intern<Stage> { Stage{ Egress,  9, \"ls_out_port_sec_l2\"}.intern() }\n+function s_SWITCH_OUT_PRE_LB():         Intern<Stage> { Stage{ Egress,  0, i\"ls_out_pre_lb\"}.intern() }\n+function s_SWITCH_OUT_PRE_ACL():        Intern<Stage> { Stage{ Egress,  1, i\"ls_out_pre_acl\"}.intern() }\n+function s_SWITCH_OUT_PRE_STATEFUL():   Intern<Stage> { Stage{ Egress,  2, i\"ls_out_pre_stateful\"}.intern() }\n+function s_SWITCH_OUT_ACL_HINT():       Intern<Stage> { Stage{ Egress,  3, i\"ls_out_acl_hint\"}.intern() }\n+function s_SWITCH_OUT_ACL():            Intern<Stage> { Stage{ Egress,  4, i\"ls_out_acl\"}.intern() }\n+function s_SWITCH_OUT_QOS_MARK():       Intern<Stage> { Stage{ Egress,  5, i\"ls_out_qos_mark\"}.intern() }\n+function s_SWITCH_OUT_QOS_METER():      Intern<Stage> { Stage{ Egress,  6, i\"ls_out_qos_meter\"}.intern() }\n+function s_SWITCH_OUT_STATEFUL():       Intern<Stage> { Stage{ Egress,  7, i\"ls_out_stateful\"}.intern() }\n+function s_SWITCH_OUT_PORT_SEC_IP():    Intern<Stage> { Stage{ Egress,  8, i\"ls_out_port_sec_ip\"}.intern() }\n+function s_SWITCH_OUT_PORT_SEC_L2():    Intern<Stage> { Stage{ Egress,  9, i\"ls_out_port_sec_l2\"}.intern() }\n \n /* Logical router ingress stages. */\n-function s_ROUTER_IN_ADMISSION():       Intern<Stage> { Stage{Ingress,  0, \"lr_in_admission\"}.intern() }\n-function s_ROUTER_IN_LOOKUP_NEIGHBOR(): Intern<Stage> { Stage{Ingress,  1, \"lr_in_lookup_neighbor\"}.intern() }\n-function s_ROUTER_IN_LEARN_NEIGHBOR():  Intern<Stage> { Stage{Ingress,  2, \"lr_in_learn_neighbor\"}.intern() }\n-function s_ROUTER_IN_IP_INPUT():        Intern<Stage> { Stage{Ingress,  3, \"lr_in_ip_input\"}.intern() }\n-function s_ROUTER_IN_UNSNAT():          Intern<Stage> { Stage{Ingress,  4, \"lr_in_unsnat\"}.intern() }\n-function s_ROUTER_IN_DEFRAG():          Intern<Stage> { Stage{Ingress,  5, \"lr_in_defrag\"}.intern() }\n-function s_ROUTER_IN_DNAT():            Intern<Stage> { Stage{Ingress,  6, \"lr_in_dnat\"}.intern() }\n-function s_ROUTER_IN_ECMP_STATEFUL():   Intern<Stage> { Stage{Ingress,  7, \"lr_in_ecmp_stateful\"}.intern() }\n-function s_ROUTER_IN_ND_RA_OPTIONS():   Intern<Stage> { Stage{Ingress,  8, \"lr_in_nd_ra_options\"}.intern() }\n-function s_ROUTER_IN_ND_RA_RESPONSE():  Intern<Stage> { Stage{Ingress,  9, \"lr_in_nd_ra_response\"}.intern() }\n-function s_ROUTER_IN_IP_ROUTING():      Intern<Stage> { Stage{Ingress, 10, \"lr_in_ip_routing\"}.intern() }\n-function s_ROUTER_IN_IP_ROUTING_ECMP(): Intern<Stage> { Stage{Ingress, 11, \"lr_in_ip_routing_ecmp\"}.intern() }\n-function s_ROUTER_IN_POLICY():          Intern<Stage> { Stage{Ingress, 12, \"lr_in_policy\"}.intern() }\n-function s_ROUTER_IN_POLICY_ECMP():     Intern<Stage> { Stage{Ingress, 13, \"lr_in_policy_ecmp\"}.intern() }\n-function s_ROUTER_IN_ARP_RESOLVE():     Intern<Stage> { Stage{Ingress, 14, \"lr_in_arp_resolve\"}.intern() }\n-function s_ROUTER_IN_CHK_PKT_LEN():     Intern<Stage> { Stage{Ingress, 15, \"lr_in_chk_pkt_len\"}.intern() }\n-function s_ROUTER_IN_LARGER_PKTS():     Intern<Stage> { Stage{Ingress, 16, \"lr_in_larger_pkts\"}.intern() }\n-function s_ROUTER_IN_GW_REDIRECT():     Intern<Stage> { Stage{Ingress, 17, \"lr_in_gw_redirect\"}.intern() }\n-function s_ROUTER_IN_ARP_REQUEST():     Intern<Stage> { Stage{Ingress, 18, \"lr_in_arp_request\"}.intern() }\n+function s_ROUTER_IN_ADMISSION():       Intern<Stage> { Stage{Ingress,  0, i\"lr_in_admission\"}.intern() }\n+function s_ROUTER_IN_LOOKUP_NEIGHBOR(): Intern<Stage> { Stage{Ingress,  1, i\"lr_in_lookup_neighbor\"}.intern() }\n+function s_ROUTER_IN_LEARN_NEIGHBOR():  Intern<Stage> { Stage{Ingress,  2, i\"lr_in_learn_neighbor\"}.intern() }\n+function s_ROUTER_IN_IP_INPUT():        Intern<Stage> { Stage{Ingress,  3, i\"lr_in_ip_input\"}.intern() }\n+function s_ROUTER_IN_UNSNAT():          Intern<Stage> { Stage{Ingress,  4, i\"lr_in_unsnat\"}.intern() }\n+function s_ROUTER_IN_DEFRAG():          Intern<Stage> { Stage{Ingress,  5, i\"lr_in_defrag\"}.intern() }\n+function s_ROUTER_IN_DNAT():            Intern<Stage> { Stage{Ingress,  6, i\"lr_in_dnat\"}.intern() }\n+function s_ROUTER_IN_ECMP_STATEFUL():   Intern<Stage> { Stage{Ingress,  7, i\"lr_in_ecmp_stateful\"}.intern() }\n+function s_ROUTER_IN_ND_RA_OPTIONS():   Intern<Stage> { Stage{Ingress,  8, i\"lr_in_nd_ra_options\"}.intern() }\n+function s_ROUTER_IN_ND_RA_RESPONSE():  Intern<Stage> { Stage{Ingress,  9, i\"lr_in_nd_ra_response\"}.intern() }\n+function s_ROUTER_IN_IP_ROUTING():      Intern<Stage> { Stage{Ingress, 10, i\"lr_in_ip_routing\"}.intern() }\n+function s_ROUTER_IN_IP_ROUTING_ECMP(): Intern<Stage> { Stage{Ingress, 11, i\"lr_in_ip_routing_ecmp\"}.intern() }\n+function s_ROUTER_IN_POLICY():          Intern<Stage> { Stage{Ingress, 12, i\"lr_in_policy\"}.intern() }\n+function s_ROUTER_IN_POLICY_ECMP():     Intern<Stage> { Stage{Ingress, 13, i\"lr_in_policy_ecmp\"}.intern() }\n+function s_ROUTER_IN_ARP_RESOLVE():     Intern<Stage> { Stage{Ingress, 14, i\"lr_in_arp_resolve\"}.intern() }\n+function s_ROUTER_IN_CHK_PKT_LEN():     Intern<Stage> { Stage{Ingress, 15, i\"lr_in_chk_pkt_len\"}.intern() }\n+function s_ROUTER_IN_LARGER_PKTS():     Intern<Stage> { Stage{Ingress, 16, i\"lr_in_larger_pkts\"}.intern() }\n+function s_ROUTER_IN_GW_REDIRECT():     Intern<Stage> { Stage{Ingress, 17, i\"lr_in_gw_redirect\"}.intern() }\n+function s_ROUTER_IN_ARP_REQUEST():     Intern<Stage> { Stage{Ingress, 18, i\"lr_in_arp_request\"}.intern() }\n \n /* Logical router egress stages. */\n-function s_ROUTER_OUT_UNDNAT():         Intern<Stage> { Stage{ Egress,  0, \"lr_out_undnat\"}.intern() }\n-function s_ROUTER_OUT_POST_UNDNAT():    Intern<Stage> { Stage{ Egress,  1, \"lr_out_post_undnat\"}.intern() }\n-function s_ROUTER_OUT_SNAT():           Intern<Stage> { Stage{ Egress,  2, \"lr_out_snat\"}.intern() }\n-function s_ROUTER_OUT_EGR_LOOP():       Intern<Stage> { Stage{ Egress,  3, \"lr_out_egr_loop\"}.intern() }\n-function s_ROUTER_OUT_DELIVERY():       Intern<Stage> { Stage{ Egress,  4, \"lr_out_delivery\"}.intern() }\n+function s_ROUTER_OUT_UNDNAT():         Intern<Stage> { Stage{ Egress,  0, i\"lr_out_undnat\"}.intern() }\n+function s_ROUTER_OUT_POST_UNDNAT():    Intern<Stage> { Stage{ Egress,  1, i\"lr_out_post_undnat\"}.intern() }\n+function s_ROUTER_OUT_SNAT():           Intern<Stage> { Stage{ Egress,  2, i\"lr_out_snat\"}.intern() }\n+function s_ROUTER_OUT_EGR_LOOP():       Intern<Stage> { Stage{ Egress,  3, i\"lr_out_egr_loop\"}.intern() }\n+function s_ROUTER_OUT_DELIVERY():       Intern<Stage> { Stage{ Egress,  4, i\"lr_out_delivery\"}.intern() }\n \n /*\n  * OVS register usage:\n@@ -1604,28 +1608,28 @@ function s_ROUTER_OUT_DELIVERY():       Intern<Stage> { Stage{ Egress,  4, \"lr_o\n  */\n \n /* Register definitions specific to routers. */\n-function rEG_NEXT_HOP(): string = \"reg0\" /* reg0 for IPv4, xxreg0 for IPv6 */\n-function rEG_SRC(): string = \"reg1\"      /* reg1 for IPv4, xxreg1 for IPv6 */\n+function rEG_NEXT_HOP(): istring = i\"reg0\" /* reg0 for IPv4, xxreg0 for IPv6 */\n+function rEG_SRC(): istring = i\"reg1\"      /* reg1 for IPv4, xxreg1 for IPv6 */\n \n /* Register definitions specific to switches. */\n-function rEGBIT_CONNTRACK_DEFRAG() : string = \"reg0[0]\"\n-function rEGBIT_CONNTRACK_COMMIT() : string = \"reg0[1]\"\n-function rEGBIT_CONNTRACK_NAT()    : string = \"reg0[2]\"\n-function rEGBIT_DHCP_OPTS_RESULT() : string = \"reg0[3]\"\n-function rEGBIT_DNS_LOOKUP_RESULT(): string = \"reg0[4]\"\n-function rEGBIT_ND_RA_OPTS_RESULT(): string = \"reg0[5]\"\n-function rEGBIT_HAIRPIN()          : string = \"reg0[6]\"\n-function rEGBIT_ACL_HINT_ALLOW_NEW(): string = \"reg0[7]\"\n-function rEGBIT_ACL_HINT_ALLOW()   : string = \"reg0[8]\"\n-function rEGBIT_ACL_HINT_DROP()    : string = \"reg0[9]\"\n-function rEGBIT_ACL_HINT_BLOCK()   : string = \"reg0[10]\"\n-function rEGBIT_LKUP_FDB()         : string = \"reg0[11]\"\n-function rEGBIT_HAIRPIN_REPLY()    : string = \"reg0[12]\"\n-function rEGBIT_ACL_LABEL()        : string = \"reg0[13]\"\n-\n-function rEG_ORIG_DIP_IPV4()       : string = \"reg1\"\n-function rEG_ORIG_DIP_IPV6()       : string = \"xxreg1\"\n-function rEG_ORIG_TP_DPORT()       : string = \"reg2[0..15]\"\n+function rEGBIT_CONNTRACK_DEFRAG() : istring = i\"reg0[0]\"\n+function rEGBIT_CONNTRACK_COMMIT() : istring = i\"reg0[1]\"\n+function rEGBIT_CONNTRACK_NAT()    : istring = i\"reg0[2]\"\n+function rEGBIT_DHCP_OPTS_RESULT() : istring = i\"reg0[3]\"\n+function rEGBIT_DNS_LOOKUP_RESULT(): istring = i\"reg0[4]\"\n+function rEGBIT_ND_RA_OPTS_RESULT(): istring = i\"reg0[5]\"\n+function rEGBIT_HAIRPIN()          : istring = i\"reg0[6]\"\n+function rEGBIT_ACL_HINT_ALLOW_NEW(): istring = i\"reg0[7]\"\n+function rEGBIT_ACL_HINT_ALLOW()   : istring = i\"reg0[8]\"\n+function rEGBIT_ACL_HINT_DROP()    : istring = i\"reg0[9]\"\n+function rEGBIT_ACL_HINT_BLOCK()   : istring = i\"reg0[10]\"\n+function rEGBIT_LKUP_FDB()         : istring = i\"reg0[11]\"\n+function rEGBIT_HAIRPIN_REPLY()    : istring = i\"reg0[12]\"\n+function rEGBIT_ACL_LABEL()        : istring = i\"reg0[13]\"\n+\n+function rEG_ORIG_DIP_IPV4()       : istring = i\"reg1\"\n+function rEG_ORIG_DIP_IPV6()       : istring = i\"xxreg1\"\n+function rEG_ORIG_TP_DPORT()       : istring = i\"reg2[0..15]\"\n \n /* Register definitions for switches and routers. */\n \n@@ -1633,27 +1637,27 @@ function rEG_ORIG_TP_DPORT()       : string = \"reg2[0..15]\"\n  * loopback.  This allows certain checks to be bypassed, such as a\n * logical router dropping packets with source IP address equals\n * one of the logical router's own IP addresses. */\n-function rEGBIT_EGRESS_LOOPBACK()  : string = \"reg9[0]\"\n+function rEGBIT_EGRESS_LOOPBACK()  : istring = i\"reg9[0]\"\n /* Register to store the result of check_pkt_larger action. */\n-function rEGBIT_PKT_LARGER()       : string = \"reg9[1]\"\n-function rEGBIT_LOOKUP_NEIGHBOR_RESULT() : string = \"reg9[2]\"\n-function rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() : string = \"reg9[3]\"\n+function rEGBIT_PKT_LARGER()       : istring = i\"reg9[1]\"\n+function rEGBIT_LOOKUP_NEIGHBOR_RESULT() : istring = i\"reg9[2]\"\n+function rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() : istring = i\"reg9[3]\"\n \n /* Register to store the eth address associated to a router port for packets\n  * received in S_ROUTER_IN_ADMISSION.\n  */\n-function rEG_INPORT_ETH_ADDR() : string = \"xreg0[0..47]\"\n+function rEG_INPORT_ETH_ADDR() : istring = i\"xreg0[0..47]\"\n \n /* Register for ECMP bucket selection. */\n-function rEG_ECMP_GROUP_ID()  : string = \"reg8[0..15]\"\n-function rEG_ECMP_MEMBER_ID() : string = \"reg8[16..31]\"\n+function rEG_ECMP_GROUP_ID()  : istring = i\"reg8[0..15]\"\n+function rEG_ECMP_MEMBER_ID() : istring = i\"reg8[16..31]\"\n \n function rEG_ORIG_TP_DPORT_ROUTER()  : string = \"reg9[16..31]\"\n \n /* Register used for setting a label for ACLs in a Logical Switch. */\n-function rEG_LABEL() : string = \"reg3\"\n+function rEG_LABEL() : istring = i\"reg3\"\n \n-function fLAGBIT_NOT_VXLAN() : string = \"flags[1] == 0\"\n+function fLAGBIT_NOT_VXLAN() : istring = i\"flags[1] == 0\"\n \n function mFF_N_LOG_REGS()          : bit<32> = 10\n \n@@ -1678,8 +1682,8 @@ relation Flow(\n     priority:         integer,\n     __match:          istring,\n     actions:          istring,\n-    io_port:          Option<string>,\n-    controller_meter: Option<string>,\n+    io_port:          Option<istring>,\n+    controller_meter: Option<istring>,\n     stage_hint:       bit<32>\n )\n \n@@ -1692,7 +1696,7 @@ function stage_hint(_uuid: uuid): bit<32> {\n relation UseLogicalDatapathGroups[bool]\n UseLogicalDatapathGroups[use_logical_dp_groups] :-\n     nb in nb::NB_Global(),\n-    var use_logical_dp_groups = nb.options.get_bool_def(\"use_logical_dp_groups\", true).\n+    var use_logical_dp_groups = nb.options.get_bool_def(i\"use_logical_dp_groups\", true).\n UseLogicalDatapathGroups[false] :-\n     Unit(),\n     not nb in nb::NB_Global().\n@@ -1703,22 +1707,22 @@ relation AggregatedFlow (\n     priority:          integer,\n     __match:           istring,\n     actions:           istring,\n-    io_port:           Option<string>,\n-    controller_meter:  Option<string>,\n+    io_port:           Option<istring>,\n+    controller_meter:  Option<istring>,\n     stage_hint:        bit<32>\n )\n-function make_flow_tags(io_port: Option<string>): Map<string,string> {\n+function make_flow_tags(io_port: Option<istring>): Map<istring,istring> {\n     match (io_port) {\n         None -> map_empty(),\n-        Some{s} -> [ \"in_out_port\" -> s ]\n+        Some{s} -> [ i\"in_out_port\" -> s ]\n     }\n }\n-function make_flow_external_ids(stage_hint: bit<32>, stage: Intern<Stage>): Map<string,string> {\n+function make_flow_external_ids(stage_hint: bit<32>, stage: Intern<Stage>): Map<istring,istring> {\n     if (stage_hint == 0) {\n-        [\"stage-name\" -> stage.table_name]\n+        [i\"stage-name\" -> stage.table_name]\n     } else {\n-        [\"stage-name\" -> stage.table_name,\n-         \"stage-hint\" -> \"${hex(stage_hint)}\"]\n+        [i\"stage-name\" -> stage.table_name,\n+         i\"stage-hint\" -> i\"${hex(stage_hint)}\"]\n     }\n }\n AggregatedFlow(.logical_datapaths = g.to_set(),\n@@ -1743,11 +1747,11 @@ AggregatedFlow(.logical_datapaths = set_singleton(logical_datapath),\n     UseLogicalDatapathGroups[false],\n     Flow(logical_datapath, stage, priority, __match, actions, io_port, controller_meter, stage_hint).\n \n-function to_string(pipeline: Pipeline): string {\n+function to_istring(pipeline: Pipeline): istring {\n     if (pipeline == Ingress) {\n-        \"ingress\"\n+        i\"ingress\"\n     } else {\n-        \"egress\"\n+        i\"egress\"\n     }\n }\n \n@@ -1758,12 +1762,12 @@ for (f in AggregatedFlow()) {\n             ._uuid = hash128((dp, f.stage, f.priority, f.__match, f.actions, f.controller_meter, f.io_port, f.stage_hint)),\n             .logical_datapath = Some{dp},\n             .logical_dp_group = None,\n-            .pipeline         = f.stage.pipeline.to_string(),\n+            .pipeline         = f.stage.pipeline.to_istring(),\n             .table_id         = f.stage.table_id as integer,\n             .priority         = f.priority,\n             .controller_meter = f.controller_meter,\n-            .__match          = f.__match.ival(),\n-            .actions          = f.actions.ival(),\n+            .__match          = f.__match,\n+            .actions          = f.actions,\n             .tags             = make_flow_tags(f.io_port),\n             .external_ids     = make_flow_external_ids(f.stage_hint, f.stage))\n     } else {\n@@ -1772,12 +1776,12 @@ for (f in AggregatedFlow()) {\n                 ._uuid = hash128((group_uuid, f.stage, f.priority, f.__match, f.actions, f.controller_meter, f.io_port, f.stage_hint)),\n                 .logical_datapath = None,\n                 .logical_dp_group = Some{group_uuid},\n-                .pipeline         = f.stage.pipeline.to_string(),\n+                .pipeline         = f.stage.pipeline.to_istring(),\n                 .table_id         = f.stage.table_id as integer,\n                 .priority         = f.priority,\n                 .controller_meter = f.controller_meter,\n-                .__match          = f.__match.ival(),\n-                .actions          = f.actions.ival(),\n+                .__match          = f.__match,\n+                .actions          = f.actions,\n                 .tags             = make_flow_tags(f.io_port),\n                 .external_ids     = make_flow_external_ids(f.stage_hint, f.stage));\n             sb::Out_Logical_DP_Group(._uuid = group_uuid, .datapaths = f.logical_datapaths)\n@@ -1811,17 +1815,17 @@ Flow(.logical_datapath = sw._uuid,\n                   \"flags.loopback = 1; \"\n                   \"output;\".\n \n-function escape_child_ports(child_port: Set<string>): string {\n+function escape_child_ports(child_port: Set<istring>): string {\n     var escaped = vec_with_capacity(child_port.size());\n     for (s in child_port) {\n-        escaped.push(json_string_escape(s))\n+        escaped.push(json_escape(s))\n     };\n     escaped.join(\",\")\n }\n Flow(.logical_datapath = sw._uuid,\n      .stage            = s_SWITCH_IN_L2_LKUP(),\n      .priority         = 50,\n-     .__match          = __match.intern(),\n+     .__match          = __match,\n      .actions          = actions.intern(),\n      .stage_hint       = 0,\n      .io_port          = None,\n@@ -1831,7 +1835,7 @@ Flow(.logical_datapath = sw._uuid,\n     var fg_uuid = FlatMap(forwarding_groups),\n     fg in nb::Forwarding_Group(._uuid = fg_uuid),\n     not fg.child_port.is_empty(),\n-    var __match = \"eth.dst == ${fg.vmac}\",\n+    var __match = i\"eth.dst == ${fg.vmac}\",\n     var actions = \"fwd_group(\" ++\n                   if (fg.liveness) { \"liveness=\\\"true\\\",\" } else { \"\" } ++\n                   \"childports=\" ++ escape_child_ports(fg.child_port) ++ \");\".\n@@ -1952,12 +1956,12 @@ for (&Switch(._uuid =ls_uuid)) {\n /* stateless filters always take precedence over stateful ACLs. */\n for (&SwitchACL(.sw = sw@&Switch{._uuid = ls_uuid}, .acl = acl, .has_fair_meter = fair_meter)) {\n     if (sw.has_stateful_acl) {\n-        if (acl.action == \"allow-stateless\") {\n-            if (acl.direction == \"from-lport\") {\n+        if (acl.action == i\"allow-stateless\") {\n+            if (acl.direction == i\"from-lport\") {\n                 Flow(.logical_datapath = ls_uuid,\n                      .stage            = s_SWITCH_IN_PRE_ACL(),\n                      .priority         = acl.priority + oVN_ACL_PRI_OFFSET(),\n-                     .__match          = acl.__match.intern(),\n+                     .__match          = acl.__match,\n                      .actions          = i\"next;\",\n                      .stage_hint       = stage_hint(acl._uuid),\n                      .io_port          = None,\n@@ -1966,7 +1970,7 @@ for (&SwitchACL(.sw = sw@&Switch{._uuid = ls_uuid}, .acl = acl, .has_fair_meter\n                 Flow(.logical_datapath = ls_uuid,\n                      .stage            = s_SWITCH_OUT_PRE_ACL(),\n                      .priority         = acl.priority + oVN_ACL_PRI_OFFSET(),\n-                     .__match          = acl.__match.intern(),\n+                     .__match          = acl.__match,\n                      .actions          = i\"next;\",\n                      .stage_hint       = stage_hint(acl._uuid),\n                      .io_port          = None,\n@@ -1980,7 +1984,7 @@ for (&SwitchACL(.sw = sw@&Switch{._uuid = ls_uuid}, .acl = acl, .has_fair_meter\n  * send all IP packets through the conntrack action, which handles\n  * defragmentation, in order to match L4 headers. */\n \n-for (&SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = \"router\"},\n+for (&SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = i\"router\"},\n                  .json_name = lsp_name,\n                  .sw = &Switch{._uuid = ls_uuid, .has_stateful_acl = true})) {\n     /* Can't use ct() for router ports. Consider the\n@@ -2013,7 +2017,7 @@ for (&SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = \"router\"},\n          .controller_meter = None)\n }\n \n-for (&SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = \"localnet\"},\n+for (&SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = i\"localnet\"},\n                  .json_name = lsp_name,\n                  .sw = &Switch{._uuid = ls_uuid, .has_stateful_acl = true})) {\n     Flow(.logical_datapath = ls_uuid,\n@@ -2144,7 +2148,7 @@ for (&Switch(._uuid = ls_uuid)) {\n }\n \n for (&SwitchPort(.lsp = lsp, .json_name = lsp_name, .sw = &Switch{._uuid = ls_uuid}))\n-if (lsp.__type == \"router\" or lsp.__type == \"localnet\") {\n+if (lsp.__type == i\"router\" or lsp.__type == i\"localnet\") {\n     Flow(.logical_datapath = ls_uuid,\n          .stage            = s_SWITCH_IN_PRE_LB(),\n          .priority         = 110,\n@@ -2164,16 +2168,13 @@ if (lsp.__type == \"router\" or lsp.__type == \"localnet\") {\n }\n \n /* Empty LoadBalancer Controller event */\n-function build_empty_lb_event_flow(key: string, lb: Intern<nb::Load_Balancer>): Option<(istring, istring)> {\n-    (var ip, var port) = match (ip_address_and_port_from_lb_key(key)) {\n+function build_empty_lb_event_flow(key: istring, lb: Intern<nb::Load_Balancer>): Option<(istring, istring)> {\n+    (var ip, var port) = match (ip_address_and_port_from_lb_key(key.ival())) {\n         Some{(ip, port)} -> (ip, port),\n         _ -> return None\n     };\n \n-    var protocol = match (lb.protocol) {\n-        Some{\"tcp\"} -> \"tcp\",\n-        _ -> \"udp\"\n-    };\n+    var protocol = if (lb.protocol == Some{i\"tcp\"}) { \"tcp\" } else { \"udp\" };\n     var vip = match (port) {\n         0 -> \"${ip}\",\n         _ -> \"${ip.to_bracketed_string()}:${port}\"\n@@ -2206,9 +2207,9 @@ function build_empty_lb_event_flow(key: string, lb: Intern<nb::Load_Balancer>):\n relation LoadBalancerEmptyEvents(lb: Intern<nb::Load_Balancer>)\n LoadBalancerEmptyEvents(lb) :-\n     nb::NB_Global(.options = global_options),\n-    var global_events = global_options.get_bool_def(\"controller_event\", false),\n+    var global_events = global_options.get_bool_def(i\"controller_event\", false),\n     lb in &nb::Load_Balancer(.options = local_options),\n-    var local_events = local_options.get_bool_def(\"event\", false),\n+    var local_events = local_options.get_bool_def(i\"event\", false),\n     global_events or local_events.\n \n Flow(.logical_datapath = sw._uuid,\n@@ -2221,9 +2222,9 @@ Flow(.logical_datapath = sw._uuid,\n      .stage_hint       = stage_hint(lb._uuid)) :-\n     SwitchLBVIP(.sw_uuid = sw_uuid, .lb = lb, .vip = vip, .backends = backends),\n     LoadBalancerEmptyEvents(lb),\n-    not lb.options.get_bool_def(\"reject\", false),\n+    not lb.options.get_bool_def(i\"reject\", false),\n     sw in &Switch(._uuid = sw_uuid),\n-    backends == \"\",\n+    backends == i\"\",\n     Some {(var __match, var __action)} = build_empty_lb_event_flow(vip, lb).\n \n /* 'REGBIT_CONNTRACK_NAT' is set to let the pre-stateful table send\n@@ -2368,9 +2369,9 @@ for (&Switch(._uuid = ls_uuid)) {\n          .controller_meter = None)\n }\n \n-function acl_log_meter_name(meter_name: string, acl_uuid: uuid): string =\n+function acl_log_meter_name(meter_name: istring, acl_uuid: uuid): string =\n {\n-    meter_name ++ \"__\" ++ uuid2str(acl_uuid)\n+    \"${meter_name}__${uuid2str(acl_uuid)}\"\n }\n \n function build_acl_log(acl: Intern<nb::ACL>, fair_meter: bool): string =\n@@ -2381,14 +2382,14 @@ function build_acl_log(acl: Intern<nb::ACL>, fair_meter: bool): string =\n         var strs = vec_empty();\n         match (acl.name) {\n             None -> (),\n-            Some{name} -> strs.push(\"name=${json_string_escape(name)}\")\n+            Some{name} -> strs.push(\"name=${json_escape(name)}\")\n         };\n         /* If a severity level isn't specified, default to \"info\". */\n         match (acl.severity) {\n             None -> strs.push(\"severity=info\"),\n             Some{severity} -> strs.push(\"severity=${severity}\")\n         };\n-        match (acl.action) {\n+        match (acl.action.ival()) {\n             \"drop\" -> {\n                 strs.push(\"verdict=drop\")\n             },\n@@ -2410,9 +2411,9 @@ function build_acl_log(acl: Intern<nb::ACL>, fair_meter: bool): string =\n             Some{meter} -> {\n                 var name = match (fair_meter) {\n                     true -> acl_log_meter_name(meter, acl._uuid),\n-                    false -> meter\n+                    false -> meter.ival()\n                 };\n-                strs.push(\"meter=${json_string_escape(name)}\")\n+                strs.push(\"meter=${json_escape(name)}\")\n             },\n             None -> ()\n         };\n@@ -2435,9 +2436,9 @@ relation Reject(\n     stage: Intern<Stage>,\n     acl: Intern<nb::ACL>,\n     fair_meter: bool,\n-    controller_meter: Option<string>,\n-    extra_match: string,\n-    extra_actions: string)\n+    controller_meter: Option<istring>,\n+    extra_match: istring,\n+    extra_actions: istring)\n \n /* build_reject_acl_rules() */\n function next_to_stage(stage: Intern<Stage>): string {\n@@ -2449,14 +2450,8 @@ function next_to_stage(stage: Intern<Stage>): string {\n }\n for (Reject(lsuuid, pipeline, stage, acl, fair_meter, controller_meter,\n             extra_match_, extra_actions_)) {\n-    var extra_match = match (extra_match_) {\n-        \"\" -> \"\",\n-        s -> \"(${s}) && \"\n-    } in\n-    var extra_actions = match (extra_actions_) {\n-        \"\" -> \"\",\n-        s -> \"${s} \"\n-    } in\n+    var extra_match = if (extra_match_ == i\"\") { \"\" } else { \"(${extra_match_}) && \" } in\n+    var extra_actions = if (extra_actions_ == i\"\") { \"\" } else { \"${extra_actions_} \" } in\n     var next_stage = match (pipeline) {\n         Ingress  -> s_SWITCH_OUT_QOS_MARK(),\n         Egress -> s_SWITCH_IN_L2_LKUP()\n@@ -2786,13 +2781,13 @@ for (sw in &Switch(._uuid = ls_uuid)) {\n for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) {\n     /* consider_acl */\n     var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in\n-    var ingress = acl.direction == \"from-lport\" in\n+    var ingress = acl.direction == i\"from-lport\" in\n     var stage = if (ingress) { s_SWITCH_IN_ACL() } else { s_SWITCH_OUT_ACL() } in\n     var pipeline = if ingress Ingress else Egress in\n     var stage_hint = stage_hint(acl._uuid) in\n     var acl_log = build_acl_log(acl, fair_meter) in\n     var acl_match = acl.__match.intern() in\n-    if (acl.action == \"allow\" or acl.action == \"allow-related\") {\n+    if (acl.action == i\"allow\" or acl.action == i\"allow-related\") {\n         /* If there are any stateful flows, we must even commit \"allow\"\n          * actions.  This is because, while the initiater's\n          * direction may not have any stateful rules, the server's\n@@ -2802,7 +2797,7 @@ for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) {\n             Flow(.logical_datapath = sw._uuid,\n                  .stage            = stage,\n                  .priority         = acl.priority + oVN_ACL_PRI_OFFSET(),\n-                 .__match          = acl.__match.intern(),\n+                 .__match          = acl.__match,\n                  .actions          = i\"${acl_log}next;\",\n                  .stage_hint       = stage_hint,\n                  .io_port          = None,\n@@ -2859,16 +2854,16 @@ for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) {\n                       .io_port          = None,\n                       .controller_meter = None)\n         }\n-    } else if (acl.action == \"allow-stateless\") {\n+    } else if (acl.action == i\"allow-stateless\") {\n         Flow(.logical_datapath = sw._uuid,\n              .stage            = stage,\n              .priority         = acl.priority + oVN_ACL_PRI_OFFSET(),\n-             .__match          = acl.__match.intern(),\n+             .__match          = acl.__match,\n              .actions          = i\"${acl_log}next;\",\n              .stage_hint       = stage_hint,\n              .io_port          = None,\n              .controller_meter = None)\n-    } else if (acl.action == \"drop\" or acl.action == \"reject\") {\n+    } else if (acl.action == i\"drop\" or acl.action == i\"reject\") {\n         /* The implementation of \"drop\" differs if stateful ACLs are in\n          * use for this datapath.  In that case, the actions differ\n          * depending on whether the connection was previously committed\n@@ -2878,8 +2873,8 @@ for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) {\n             /* If the packet is not tracked or not part of an established\n              * connection, then we can simply reject/drop it. */\n             var __match = \"${rEGBIT_ACL_HINT_DROP()} == 1\" in\n-            if (acl.action == \"reject\") {\n-                Reject(sw._uuid, pipeline, stage, acl, fair_meter, controller_meter, __match, \"\")\n+            if (acl.action == i\"reject\") {\n+                Reject(sw._uuid, pipeline, stage, acl, fair_meter, controller_meter, __match.intern(), i\"\")\n             } else {\n                 Flow(.logical_datapath = sw._uuid,\n                      .stage            = stage,\n@@ -2903,8 +2898,8 @@ for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) {\n              */\n             var __match = \"${rEGBIT_ACL_HINT_BLOCK()} == 1\" in\n             var actions = \"ct_commit { ct_label.blocked = 1; }; \" in\n-            if (acl.action == \"reject\") {\n-                Reject(sw._uuid, pipeline, stage, acl, fair_meter, controller_meter, __match, actions)\n+            if (acl.action == i\"reject\") {\n+                Reject(sw._uuid, pipeline, stage, acl, fair_meter, controller_meter, __match.intern(), actions.intern())\n             } else {\n                 Flow(.logical_datapath = sw._uuid,\n                      .stage            = stage,\n@@ -2919,13 +2914,13 @@ for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) {\n             /* There are no stateful ACLs in use on this datapath,\n              * so a \"reject/drop\" ACL is simply the \"reject/drop\"\n              * logical flow action in all cases. */\n-            if (acl.action == \"reject\") {\n-                Reject(sw._uuid, pipeline, stage, acl, fair_meter, controller_meter, \"\", \"\")\n+            if (acl.action == i\"reject\") {\n+                Reject(sw._uuid, pipeline, stage, acl, fair_meter, controller_meter, i\"\", i\"\")\n             } else {\n                 Flow(.logical_datapath = sw._uuid,\n                      .stage            = stage,\n                      .priority         = acl.priority + oVN_ACL_PRI_OFFSET(),\n-                     .__match          = acl.__match.intern(),\n+                     .__match          = acl.__match,\n                      .actions          = i\"${acl_log}/* drop */\",\n                      .stage_hint       = stage_hint,\n                      .io_port          = None,\n@@ -2940,14 +2935,14 @@ for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) {\n  * */\n for (SwitchPortDHCPv4Options(.port = &SwitchPort{.lsp = lsp, .sw = sw},\n                              .dhcpv4_options = dhcpv4_options@&nb::DHCP_Options{.options = options})\n-     if lsp.__type != \"external\") {\n+     if lsp.__type != i\"external\") {\n     (Some{var server_id}, Some{var server_mac}, Some{var lease_time}) =\n-        (options.get(\"server_id\"), options.get(\"server_mac\"), options.get(\"lease_time\")) in\n+        (options.get(i\"server_id\"), options.get(i\"server_mac\"), options.get(i\"lease_time\")) in\n     var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in\n     Flow(.logical_datapath = sw._uuid,\n          .stage            = s_SWITCH_OUT_ACL(),\n          .priority         = 34000,\n-         .__match          = i\"outport == ${json_string_escape(lsp.name)} \"\n+         .__match          = i\"outport == ${json_escape(lsp.name)} \"\n                              \"&& eth.src == ${server_mac} \"\n                              \"&& ip4.src == ${server_id} && udp && udp.src == 67 \"\n                              \"&& udp.dst == 68\",\n@@ -2959,9 +2954,9 @@ for (SwitchPortDHCPv4Options(.port = &SwitchPort{.lsp = lsp, .sw = sw},\n \n for (SwitchPortDHCPv6Options(.port = &SwitchPort{.lsp = lsp, .sw = sw},\n                              .dhcpv6_options = dhcpv6_options@&nb::DHCP_Options{.options=options} )\n-     if lsp.__type != \"external\") {\n-    Some{var server_mac} = options.get(\"server_id\") in\n-    Some{var ea} = eth_addr_from_string(server_mac) in\n+     if lsp.__type != i\"external\") {\n+    Some{var server_mac} = options.get(i\"server_id\") in\n+    Some{var ea} = eth_addr_from_string(server_mac.ival()) in\n     var server_ip = ea.to_ipv6_lla() in\n     /* Get the link local IP of the DHCPv6 server from the\n      * server MAC. */\n@@ -2969,7 +2964,7 @@ for (SwitchPortDHCPv6Options(.port = &SwitchPort{.lsp = lsp, .sw = sw},\n     Flow(.logical_datapath = sw._uuid,\n          .stage            = s_SWITCH_OUT_ACL(),\n          .priority         = 34000,\n-         .__match          = i\"outport == ${json_string_escape(lsp.name)} \"\n+         .__match          = i\"outport == ${json_escape(lsp.name)} \"\n                              \"&& eth.src == ${server_mac} \"\n                              \"&& ip6.src == ${server_ip} && udp && udp.src == 547 \"\n                              \"&& udp.dst == 546\",\n@@ -2979,12 +2974,11 @@ for (SwitchPortDHCPv6Options(.port = &SwitchPort{.lsp = lsp, .sw = sw},\n          .controller_meter = None)\n }\n \n-relation QoSAction(qos: uuid, key_action: string, value_action: integer)\n+relation QoSAction(qos: uuid, key_action: istring, value_action: integer)\n \n QoSAction(qos, k, v) :-\n     &nb::QoS(._uuid = qos, .action = actions),\n-    var action = FlatMap(actions),\n-    (var k, var v) = action.\n+    (var k, var v) = FlatMap(actions).\n \n /* QoS rules */\n for (&Switch(._uuid = ls_uuid)) {\n@@ -3023,16 +3017,16 @@ for (&Switch(._uuid = ls_uuid)) {\n }\n \n for (SwitchQoS(.sw = sw, .qos = qos)) {\n-    var ingress = if (qos.direction == \"from-lport\") true else false in\n+    var ingress = if (qos.direction == i\"from-lport\") true else false in\n     var pipeline = if ingress \"ingress\" else \"egress\" in {\n         var stage = if (ingress) { s_SWITCH_IN_QOS_MARK() } else { s_SWITCH_OUT_QOS_MARK() } in\n         /* FIXME: Can value_action be negative? */\n         for (QoSAction(qos._uuid, key_action, value_action)) {\n-            if (key_action == \"dscp\") {\n+            if (key_action == i\"dscp\") {\n                 Flow(.logical_datapath = sw._uuid,\n                      .stage            = stage,\n                      .priority         = qos.priority,\n-                     .__match          = qos.__match.intern(),\n+                     .__match          = qos.__match,\n                      .actions          = i\"ip.dscp = ${value_action}; next;\",\n                      .stage_hint       = stage_hint(qos._uuid),\n                      .io_port          = None,\n@@ -3043,12 +3037,11 @@ for (SwitchQoS(.sw = sw, .qos = qos)) {\n         (var burst, var rate) = {\n             var rate = 0;\n             var burst = 0;\n-            for (bw in qos.bandwidth) {\n+            for ((key_bandwidth, value_bandwidth) in qos.bandwidth) {\n                 /* FIXME: Can value_bandwidth be negative? */\n-                (var key_bandwidth, var value_bandwidth) = bw;\n-                if (key_bandwidth == \"rate\") {\n+                if (key_bandwidth == i\"rate\") {\n                     rate = value_bandwidth\n-                } else if (key_bandwidth == \"burst\") {\n+                } else if (key_bandwidth == i\"burst\") {\n                     burst = value_bandwidth\n                 } else ()\n             };\n@@ -3068,7 +3061,7 @@ for (SwitchQoS(.sw = sw, .qos = qos)) {\n             Flow(.logical_datapath = sw._uuid,\n                  .stage            = stage,\n                  .priority         = qos.priority,\n-                 .__match          = qos.__match.intern(),\n+                 .__match          = qos.__match,\n                  .actions          = meter_action,\n                  .stage_hint       = stage_hint(qos._uuid),\n                  .io_port          = None,\n@@ -3150,12 +3143,12 @@ for (&Switch(._uuid = ls_uuid)) {\n  * REGBIT_CONNTRACK_COMMIT. */\n function get_match_for_lb_key(ip_address: v46_ip,\n                               port: bit<16>,\n-                              protocol: Option<string>,\n+                              protocol: Option<istring>,\n                               redundancy: bool,\n                               use_nexthop_reg: bool,\n                               use_dest_tp_reg: bool): string = {\n     var port_match = if (port != 0) {\n-        var proto = if (protocol == Some{\"udp\"}) {\n+        var proto = if (protocol == Some{i\"udp\"}) {\n             \"udp\"\n         } else {\n             \"tcp\"\n@@ -3195,21 +3188,22 @@ function get_match_for_lb_key(ip_address: v46_ip,\n /* New connections in Ingress table. */\n \n function ct_lb(backends: string,\n-               selection_fields: Set<string>, protocol: Option<string>): string {\n+               selection_fields: Set<istring>, protocol: Option<istring>): string {\n     var args = vec_with_capacity(2);\n     args.push(\"backends=${backends}\");\n \n     if (not selection_fields.is_empty()) {\n         var hash_fields = vec_with_capacity(selection_fields.size());\n         for (sf in selection_fields) {\n-            var hf = match ((sf, protocol)) {\n+            var hf = match ((sf.ival(), protocol)) {\n                 (\"tp_src\", Some{p}) -> \"${p}_src\",\n                 (\"tp_dst\", Some{p}) -> \"${p}_dst\",\n-                _ -> sf\n+                _ -> sf.ival()\n             };\n             hash_fields.push(hf);\n         };\n-        args.push(\"hash_fields=\" ++ json_string_escape(hash_fields.join(\",\")));\n+        hash_fields.sort();\n+        args.push(\"hash_fields=\" ++ json_escape(hash_fields.join(\",\")));\n     };\n \n     \"ct_lb(\" ++ args.join(\"; \") ++ \");\"\n@@ -3217,28 +3211,27 @@ function ct_lb(backends: string,\n function build_lb_vip_actions(lbvip: Intern<LBVIPWithStatus>,\n                               stage: Intern<Stage>,\n                               actions0: string): (string, bool) {\n-    var up_backends = set_empty();\n+    var up_backends = vec_with_capacity(lbvip.backends.size());\n     for (pair in lbvip.backends) {\n         (var backend, var up) = pair;\n         if (up) {\n-            if (backend.port != 0) {\n-                up_backends.insert(\"${backend.ip.to_bracketed_string()}:${backend.port}\")\n-            } else {\n-                up_backends.insert(\"${backend.ip.to_bracketed_string()}\")\n-            }\n+            up_backends.push((backend.ip, backend.port))\n         }\n     };\n \n     if (up_backends.is_empty()) {\n-        if (lbvip.lb.options.get_bool_def(\"reject\", false)) {\n+        if (lbvip.lb.options.get_bool_def(i\"reject\", false)) {\n             return (\"reg0 = 0; reject { outport <-> inport; ${next_to_stage(stage)};};\", true)\n         } else if (lbvip.health_check.is_some()) {\n             return (\"drop;\", false)\n         } // else fall through\n     };\n \n-    var actions = ct_lb(up_backends.to_vec().join(\",\"), lbvip.lb.selection_fields,\n-                        lbvip.lb.protocol);\n+    var up_backends_s = up_backends.sort_imm().map(|x| match (x) {\n+        (ip, 0) -> \"${ip.to_bracketed_string()}\",\n+        (ip, port) -> \"${ip.to_bracketed_string()}:${port}\"\n+    }).join(\",\");\n+    var actions = ct_lb(up_backends_s, lbvip.lb.selection_fields, lbvip.lb.protocol);\n     (actions0 ++ actions, false)\n }\n Flow(.logical_datapath = sw._uuid,\n@@ -3363,14 +3356,14 @@ for (&Switch(._uuid = ls_uuid, .has_lb_vip = true)) {\n                   ingress table PORT_SEC_IP: ingress port security - IP (priority 90 and 80)\n                   ingress table PORT_SEC_ND: ingress port security - ND (priority 90 and 80) */\n for (&SwitchPort(.lsp = lsp, .sw = sw, .json_name = json_name, .ps_eth_addresses = ps_eth_addresses)\n-     if lsp.is_enabled() and lsp.__type != \"external\") {\n+     if lsp.is_enabled() and lsp.__type != i\"external\") {\n      for (pbinding in sb::Out_Port_Binding(.logical_port = lsp.name)) {\n         var __match = if (ps_eth_addresses.is_empty()) {\n                 i\"inport == ${json_name}\"\n             } else {\n                 i\"inport == ${json_name} && eth.src == {${ps_eth_addresses.join(\\\" \\\")}}\"\n             } in\n-        var actions = match (pbinding.options.get(\"qdisc_queue_id\")) {\n+        var actions = match (pbinding.options.get(i\"qdisc_queue_id\")) {\n                 None -> i\"next;\",\n                 Some{id} -> i\"set_queue(${id}); next;\"\n             } in\n@@ -3403,7 +3396,7 @@ for (&SwitchPort(.lsp = lsp, .sw = sw, .json_name = json_name, .ps_eth_addresses\n for (SwitchPortPSAddresses(.port = port@&SwitchPort{.sw = sw}, .ps_addrs = ps)\n      if port.is_enabled() and\n         (ps.ipv4_addrs.len() > 0 or ps.ipv6_addrs.len() > 0) and\n-        port.lsp.__type != \"external\")\n+        port.lsp.__type != i\"external\")\n {\n     if (ps.ipv4_addrs.len() > 0) {\n         var dhcp_match = i\"inport == ${port.json_name}\"\n@@ -3510,7 +3503,7 @@ for (SwitchPortPSAddresses(.port = port@&SwitchPort{.sw = sw}, .ps_addrs = ps)\n  *   - Priority 80 flow to drop ARP and IPv6 ND packets.\n  */\n for (SwitchPortPSAddresses(.port = port@&SwitchPort{.sw = sw}, .ps_addrs = ps)\n-     if port.is_enabled() and port.lsp.__type != \"external\")\n+     if port.is_enabled() and port.lsp.__type != i\"external\")\n {\n     var no_ip = ps.ipv4_addrs.is_empty() and ps.ipv6_addrs.is_empty() in\n     {\n@@ -3588,7 +3581,7 @@ for (&Switch(._uuid = ls_uuid)) {\n  * rationale. */\n for (&SwitchPort(.lsp = lsp, .sw = sw, .json_name = json_name)\n      if lsp.is_enabled() and\n-        (lsp.__type == \"localnet\" or lsp.__type == \"vtep\"))\n+        (lsp.__type == i\"localnet\" or lsp.__type == i\"vtep\"))\n {\n     Flow(.logical_datapath = sw._uuid,\n          .stage            = s_SWITCH_IN_ARP_ND_RSP(),\n@@ -3623,12 +3616,12 @@ function lsp_is_up(lsp: Intern<nb::Logical_Switch_Port>): bool = {\n       .stage_hint       = stage_hint(lsp._uuid),\n       .io_port          = Some{vp.lsp.name},\n       .controller_meter = None) :-\n-    sp in &SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = \"virtual\"}),\n-    Some{var virtual_ip} = lsp.options.get(\"virtual-ip\"),\n-    Some{var virtual_parents} = lsp.options.get(\"virtual-parents\"),\n-    Some{var ip} = ip_parse(virtual_ip),\n-    var vparent = FlatMap(string_split(virtual_parents, \",\")),\n-    vp in &SwitchPort(.lsp = &nb::Logical_Switch_Port{.name = vparent}),\n+    sp in &SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = i\"virtual\"}),\n+    Some{var virtual_ip} = lsp.options.get(i\"virtual-ip\"),\n+    Some{var virtual_parents} = lsp.options.get(i\"virtual-parents\"),\n+    Some{var ip} = ip_parse(virtual_ip.ival()),\n+    var vparent = FlatMap(virtual_parents.split(\",\")),\n+    vp in &SwitchPort(.lsp = &nb::Logical_Switch_Port{.name = vparent.intern()}),\n     vp.sw == sp.sw.\n \n /*\n@@ -3642,9 +3635,9 @@ for (CheckLspIsUp[check_lsp_is_up]) {\n                                .ea = ea, .addr = addr)\n          if lsp.is_enabled() and\n             ((lsp_is_up(lsp) or not check_lsp_is_up)\n-             or lsp.__type == \"router\" or lsp.__type == \"localport\") and\n-            lsp.__type != \"external\" and lsp.__type != \"virtual\" and\n-            not lsp.addresses.contains(\"unknown\") and\n+             or lsp.__type == i\"router\" or lsp.__type == i\"localport\") and\n+            lsp.__type != i\"external\" and lsp.__type != i\"virtual\" and\n+            not lsp.addresses.contains(i\"unknown\") and\n             not sw.is_vlan_transparent)\n     {\n         var __match = \"arp.tpa == ${addr.addr} && arp.op == 1\" in\n@@ -3704,10 +3697,10 @@ Flow(.logical_datapath = sw._uuid,\n     sp in &SwitchPort(.sw = sw, .peer = Some{rp}),\n     rp.is_enabled(),\n     var proxy_ips = {\n-        match (sp.lsp.options.get(\"arp_proxy\")) {\n+        match (sp.lsp.options.get(i\"arp_proxy\")) {\n             None -> \"\",\n             Some {addresses} -> {\n-                match (extract_ip_addresses(addresses)) {\n+                match (extract_ip_addresses(addresses.ival())) {\n                     None -> \"\",\n                     Some{addr} -> {\n                         var ip4_addrs = vec_empty();\n@@ -3738,12 +3731,12 @@ Flow(.logical_datapath = sw._uuid,\n for (SwitchPortIPv6Address(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = sw},\n                            .ea = ea, .addr = addr)\n      if lsp.is_enabled() and\n-        (lsp_is_up(lsp) or lsp.__type == \"router\" or lsp.__type == \"localport\") and\n-        lsp.__type != \"external\" and lsp.__type != \"virtual\" and\n+        (lsp_is_up(lsp) or lsp.__type == i\"router\" or lsp.__type == i\"localport\") and\n+        lsp.__type != i\"external\" and lsp.__type != i\"virtual\" and\n         not sw.is_vlan_transparent)\n {\n     var __match = \"nd_ns && ip6.dst == {${addr.addr}, ${addr.solicited_node()}} && nd.target == ${addr.addr}\" in\n-    var actions = i\"${if (lsp.__type == \\\"router\\\") \\\"nd_na_router\\\" else \\\"nd_na\\\"} { \"\n+    var actions = i\"${if (lsp.__type == i\\\"router\\\") \\\"nd_na_router\\\" else \\\"nd_na\\\"} { \"\n                   \"eth.src = ${ea}; \"\n                   \"ip6.src = ${addr.addr}; \"\n                   \"nd.target = ${addr.addr}; \"\n@@ -3819,9 +3812,9 @@ function build_dhcpv4_action(\n     lsp_json_key: string,\n     dhcpv4_options: Intern<nb::DHCP_Options>,\n     offer_ip: in_addr,\n-    lsp_options: Map<string,string>) : Option<(istring, istring, string)> =\n+    lsp_options: Map<istring,istring>) : Option<(istring, istring, string)> =\n {\n-    match (ip_parse_masked(dhcpv4_options.cidr)) {\n+    match (ip_parse_masked(dhcpv4_options.cidr.ival())) {\n         Left{err} -> {\n             /* cidr defined is invalid */\n             None\n@@ -3833,29 +3826,28 @@ function build_dhcpv4_action(\n                 */\n                 None\n             } else {\n-                match ((dhcpv4_options.options.get(\"server_id\"),\n-                        dhcpv4_options.options.get(\"server_mac\"),\n-                        dhcpv4_options.options.get(\"lease_time\")))\n+                match ((dhcpv4_options.options.get(i\"server_id\"),\n+                        dhcpv4_options.options.get(i\"server_mac\"),\n+                        dhcpv4_options.options.get(i\"lease_time\")))\n                 {\n                     (Some{var server_ip}, Some{var server_mac}, Some{var lease_time}) -> {\n                         var options_map = dhcpv4_options.options;\n \n                         /* server_mac is not DHCPv4 option, delete it from the smap. */\n-                        options_map.remove(\"server_mac\");\n-                        options_map.insert(\"netmask\", \"${mask}\");\n+                        options_map.remove(i\"server_mac\");\n+                        options_map.insert(i\"netmask\", i\"${mask}\");\n \n-                        match (lsp_options.get(\"hostname\")) {\n+                        match (lsp_options.get(i\"hostname\")) {\n                             None -> (),\n-                            Some{port_hostname} -> options_map.insert(\"hostname\", \"${port_hostname}\")\n+                            Some{port_hostname} -> options_map.insert(i\"hostname\", port_hostname)\n                         };\n \n-                        /* We're not using SMAP_FOR_EACH because we want a consistent order of the\n-                         * options on different architectures (big or little endian, SSE4.2) */\n                         var options = vec_empty();\n                         for (node in options_map) {\n                             (var k, var v) = node;\n                             options.push(\"${k} = ${v}\")\n                         };\n+                        options.sort();\n                         var options_action = \"${rEGBIT_DHCP_OPTS_RESULT()} = put_dhcp_opts(offerip = ${offer_ip}, \" ++\n                                              options.join(\", \") ++ \"); next;\";\n                         var response_action = i\"eth.dst = eth.src; eth.src = ${server_mac}; \"\n@@ -3884,7 +3876,7 @@ function build_dhcpv6_action(\n     dhcpv6_options: Intern<nb::DHCP_Options>,\n     offer_ip: in6_addr): Option<(istring, istring)> =\n {\n-    match (ipv6_parse_masked(dhcpv6_options.cidr)) {\n+    match (ipv6_parse_masked(dhcpv6_options.cidr.ival())) {\n         Left{err} -> {\n             /* cidr defined is invalid */\n             //warn(\"cidr is invalid - ${err}\");\n@@ -3898,13 +3890,13 @@ function build_dhcpv6_action(\n                 None\n             } else {\n                 /* \"server_id\" should be the MAC address. */\n-                match (dhcpv6_options.options.get(\"server_id\")) {\n+                match (dhcpv6_options.options.get(i\"server_id\")) {\n                     None -> {\n                         warn(\"server_id not present in the DHCPv6 options for lport ${lsp_json_key}\");\n                         None\n                     },\n                     Some{server_mac} -> {\n-                        match (eth_addr_from_string(server_mac)) {\n+                        match (eth_addr_from_string(server_mac.ival())) {\n                             None -> {\n                                 warn(\"server_id not present in the DHCPv6 options for lport ${lsp_json_key}\");\n                                 None\n@@ -3917,19 +3909,16 @@ function build_dhcpv6_action(\n \n                                 /* Check whether the dhcpv6 options should be configured as stateful.\n                                  * Only reply with ia_addr option for dhcpv6 stateful address mode. */\n-                                if (not dhcpv6_options.options.get_bool_def(\"dhcpv6_stateless\", false)) {\n+                                if (not dhcpv6_options.options.get_bool_def(i\"dhcpv6_stateless\", false)) {\n                                     options.push(\"ia_addr = ${ia_addr}\")\n                                 } else ();\n \n-                                /* We're not using SMAP_FOR_EACH because we want a consistent order of the\n-                                 * options on different architectures (big or little endian, SSE4.2) */\n-                                // FIXME: enumerate map in ascending order of keys. Is this good enough?\n-                                for (node in dhcpv6_options.options) {\n-                                    (var k, var v) = node;\n-                                    if (k != \"dhcpv6_stateless\") {\n+                                for ((k, v) in dhcpv6_options.options) {\n+                                    if (k != i\"dhcpv6_stateless\") {\n                                         options.push(\"${k} = ${v}\")\n                                     } else ()\n                                 };\n+                                options.sort();\n \n                                 var options_action = \"${rEGBIT_DHCP_OPTS_RESULT()} = put_dhcpv6_opts(\" ++\n                                                      options.join(\", \") ++\n@@ -3948,17 +3937,17 @@ function build_dhcpv6_action(\n     }\n }\n \n-/* If 'names' has one element, returns json_string_escape() for it.\n- * Otherwise, returns json_string_escape() of all of its elements inside \"{...}\".\n+/* If 'names' has one element, returns json_escape() for it.\n+ * Otherwise, returns json_escape() of all of its elements inside \"{...}\".\n  */\n-function json_string_escape_vec(names: Vec<string>): string\n+function json_escape_vec(names: Vec<string>): string\n {\n     match ((names.len(), names.nth(0))) {\n-        (1, Some{name}) -> json_string_escape(name),\n+        (1, Some{name}) -> json_escape(name),\n         _ -> {\n             var json_names = vec_with_capacity(names.len());\n             for (name in names) {\n-                json_names.push(json_string_escape(name));\n+                json_names.push(json_escape(name));\n             };\n             \"{\" ++ json_names.join(\", \") ++ \"}\"\n         }\n@@ -3981,8 +3970,8 @@ function json_string_escape_vec(names: Vec<string>): string\n  */\n function match_dhcp_input(lsp: Intern<SwitchPort>): (string, string) =\n {\n-    if (lsp.lsp.__type == \"external\" and not lsp.sw.localnet_ports.is_empty()) {\n-        (\"inport == \" ++ json_string_escape_vec(lsp.sw.localnet_ports.map(|x| x.1)) ++ \" && \",\n+    if (lsp.lsp.__type == i\"external\" and not lsp.sw.localnet_ports.is_empty()) {\n+        (\"inport == \" ++ json_escape_vec(lsp.sw.localnet_ports.map(|x| x.1.ival())) ++ \" && \",\n          \" && is_chassis_resident(${lsp.json_name})\")\n     } else {\n         (\"inport == ${lsp.json_name} && \", \"\")\n@@ -3994,15 +3983,15 @@ function match_dhcp_input(lsp: Intern<SwitchPort>): (string, string) =\n for (lsp in &SwitchPort\n          /* Don't add the DHCP flows if the port is not enabled or if the\n           * port is a router port. */\n-         if (lsp.is_enabled() and lsp.lsp.__type != \"router\")\n+         if (lsp.is_enabled() and lsp.lsp.__type != i\"router\")\n          /* If it's an external port and there is no localnet port\n           * and if it doesn't belong to an HA chassis group ignore it. */\n-         and (lsp.lsp.__type != \"external\"\n+         and (lsp.lsp.__type != i\"external\"\n               or (not lsp.sw.localnet_ports.is_empty()\n                   and lsp.lsp.ha_chassis_group.is_some())))\n {\n     for (lps in LogicalSwitchPort(.lport = lsp.lsp._uuid, .lswitch = lsuuid)) {\n-        var json_key = json_string_escape(lsp.lsp.name) in\n+        var json_key = json_escape(lsp.lsp.name) in\n         (var pfx, var sfx) = match_dhcp_input(lsp) in\n         {\n             /* DHCPv4 options enabled for this port */\n@@ -4227,7 +4216,7 @@ for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = mcast_cfg)\n                 var flood_static = not flood_ports.is_empty() in\n                 var igmp_act = {\n                     if (flood_reports) {\n-                        var mrouter_static = json_string_escape(mC_MROUTER_STATIC().0);\n+                        var mrouter_static = json_escape(mC_MROUTER_STATIC().0);\n                         i\"clone { \"\n                             \"outport = ${mrouter_static}; \"\n                             \"output; \"\n@@ -4259,7 +4248,7 @@ for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = mcast_cfg)\n                     /* Flood all IP multicast traffic destined to 224.0.0.X to\n                      * all ports - RFC 4541, section 2.1.2, item 2.\n                      */\n-                    var flood = json_string_escape(mC_FLOOD().0) in\n+                    var flood = json_escape(mC_FLOOD().0) in\n                     Flow(.logical_datapath = ls_uuid,\n                          .stage            = s_SWITCH_IN_L2_LKUP(),\n                          .priority         = 85,\n@@ -4272,7 +4261,7 @@ for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = mcast_cfg)\n                     /* Flood all IPv6 multicast traffic destined to reserved\n                      * multicast IPs (RFC 4291, 2.7.1).\n                      */\n-                    var flood = json_string_escape(mC_FLOOD().0) in\n+                    var flood = json_escape(mC_FLOOD().0) in\n                     Flow(.logical_datapath = ls_uuid,\n                          .stage            = s_SWITCH_IN_L2_LKUP(),\n                          .priority         = 85,\n@@ -4290,7 +4279,7 @@ for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = mcast_cfg)\n                     if (not mcast_cfg.flood_unreg) {\n                         var relay_act = {\n                             if (flood_relay) {\n-                                var rtr_flood = json_string_escape(mC_MROUTER_FLOOD().0);\n+                                var rtr_flood = json_escape(mC_MROUTER_FLOOD().0);\n                                 \"clone { \"\n                                     \"outport = ${rtr_flood}; \"\n                                     \"output; \"\n@@ -4301,7 +4290,7 @@ for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = mcast_cfg)\n                         } in\n                         var static_act = {\n                             if (flood_static) {\n-                                var mc_static = json_string_escape(mC_STATIC().0);\n+                                var mc_static = json_escape(mC_STATIC().0);\n                                 \"outport =${mc_static}; output;\"\n                             } else {\n                                 \"\"\n@@ -4338,7 +4327,7 @@ for (IgmpSwitchMulticastGroup(.address = address, .switch = sw)) {\n      * RFC 4291, section 2.7.1: Skip groups that correspond to all\n      * hosts.\n      */\n-    Some{var ip} = ip46_parse(address) in\n+    Some{var ip} = ip46_parse(address.ival()) in\n     (var skip_address) = match (ip) {\n         IPv4{ipv4} -> ipv4.is_local_multicast(),\n         IPv6{ipv6} -> ipv6.is_all_hosts()\n@@ -4348,8 +4337,8 @@ for (IgmpSwitchMulticastGroup(.address = address, .switch = sw)) {\n         for (SwitchMcastFloodPorts(sw, flood_ports)) {\n             var flood_relay = not relay_ports.is_empty() in\n             var flood_static = not flood_ports.is_empty() in\n-            var mc_rtr_flood = json_string_escape(mC_MROUTER_FLOOD().0) in\n-            var mc_static = json_string_escape(mC_STATIC().0) in\n+            var mc_rtr_flood = json_escape(mC_MROUTER_FLOOD().0) in\n+            var mc_static = json_escape(mC_STATIC().0) in\n             var relay_act = {\n                 if (flood_relay) {\n                     \"clone { \"\n@@ -4394,7 +4383,7 @@ for (IgmpSwitchMulticastGroup(.address = address, .switch = sw)) {\n Flow(.logical_datapath = sp.sw._uuid,\n      .stage            = s_SWITCH_IN_EXTERNAL_PORT(),\n      .priority         = 100,\n-     .__match          = (i\"inport == ${json_string_escape(localnet_port.1)} && \"\n+     .__match          = (i\"inport == ${json_escape(localnet_port.1)} && \"\n                           \"eth.src == ${lp_addr.ea} && \"\n                           \"!is_chassis_resident(${sp.json_name}) && \"\n                           \"arp.tpa == ${rp_addr.addr} && arp.op == 1\"),\n@@ -4403,16 +4392,16 @@ Flow(.logical_datapath = sp.sw._uuid,\n      .io_port          = Some{localnet_port.1},\n      .controller_meter = None) :-\n     sp in &SwitchPort(),\n-    sp.lsp.__type == \"external\",\n+    sp.lsp.__type == i\"external\",\n     var localnet_port = FlatMap(sp.sw.localnet_ports),\n     var lp_addr = FlatMap(sp.static_addresses),\n     rp in &SwitchPort(.sw = sp.sw),\n-    rp.lsp.__type == \"router\",\n+    rp.lsp.__type == i\"router\",\n     SwitchPortIPv4Address(.port = rp, .addr = rp_addr).\n Flow(.logical_datapath = sp.sw._uuid,\n      .stage            = s_SWITCH_IN_EXTERNAL_PORT(),\n      .priority         = 100,\n-     .__match          = (i\"inport == ${json_string_escape(localnet_port.1)} && \"\n+     .__match          = (i\"inport == ${json_escape(localnet_port.1)} && \"\n                           \"eth.src == ${lp_addr.ea} && \"\n                           \"!is_chassis_resident(${sp.json_name}) && \"\n                           \"nd_ns && ip6.dst == {${rp_addr.addr}, ${rp_addr.solicited_node()}} && \"\n@@ -4422,16 +4411,16 @@ Flow(.logical_datapath = sp.sw._uuid,\n      .io_port          = Some{localnet_port.1},\n      .controller_meter = None) :-\n     sp in &SwitchPort(),\n-    sp.lsp.__type == \"external\",\n+    sp.lsp.__type == i\"external\",\n     var localnet_port = FlatMap(sp.sw.localnet_ports),\n     var lp_addr = FlatMap(sp.static_addresses),\n     rp in &SwitchPort(.sw = sp.sw),\n-    rp.lsp.__type == \"router\",\n+    rp.lsp.__type == i\"router\",\n     SwitchPortIPv6Address(.port = rp, .addr = rp_addr).\n Flow(.logical_datapath = sp.sw._uuid,\n      .stage            = s_SWITCH_IN_EXTERNAL_PORT(),\n      .priority         = 100,\n-     .__match          = (i\"inport == ${json_string_escape(localnet_port.1)} && \"\n+     .__match          = (i\"inport == ${json_escape(localnet_port.1)} && \"\n                           \"eth.src == ${lp_addr.ea} && \"\n                           \"eth.dst == ${ea} && \"\n                           \"!is_chassis_resident(${sp.json_name})\"),\n@@ -4440,17 +4429,17 @@ Flow(.logical_datapath = sp.sw._uuid,\n      .io_port          = Some{localnet_port.1},\n      .controller_meter = None) :-\n     sp in &SwitchPort(),\n-    sp.lsp.__type == \"external\",\n+    sp.lsp.__type == i\"external\",\n     var localnet_port = FlatMap(sp.sw.localnet_ports),\n     var lp_addr = FlatMap(sp.static_addresses),\n     rp in &SwitchPort(.sw = sp.sw),\n-    rp.lsp.__type == \"router\",\n+    rp.lsp.__type == i\"router\",\n     SwitchPortAddresses(.port = rp, .addrs = LPortAddress{.ea = ea}).\n \n /* Ingress table L2_LKUP: Destination lookup, broadcast and multicast handling\n  * (priority 100). */\n for (ls in &nb::Logical_Switch) {\n-    var mc_flood = json_string_escape(mC_FLOOD().0) in\n+    var mc_flood = json_escape(mC_FLOOD().0) in\n     Flow(.logical_datapath = ls._uuid,\n          .stage            = s_SWITCH_IN_L2_LKUP(),\n          .priority         = 70,\n@@ -4465,7 +4454,7 @@ for (ls in &nb::Logical_Switch) {\n */\n for (SwitchPortStaticAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = sw},\n                                .addrs = addrs)\n-     if lsp.__type != \"external\") {\n+     if lsp.__type != i\"external\") {\n     Flow(.logical_datapath = sw._uuid,\n          .stage            = s_SWITCH_IN_L2_LKUP(),\n          .priority         = 50,\n@@ -4520,7 +4509,7 @@ Flow(.logical_datapath = sw._uuid,\n     sp in &SwitchPort(.sw = sw@&Switch{.has_non_router_port = true}, .peer = Some{rp}),\n     rp.is_enabled(),\n     var eth_src_set = {\n-        var eth_src_set = set_singleton(\"${rp.networks.ea}\");\n+        var eth_src_set = set_singleton(i\"${rp.networks.ea}\");\n         for (nat in rp.router.nats) {\n             match (nat.nat.external_mac) {\n                 Some{mac} ->\n@@ -4534,7 +4523,7 @@ Flow(.logical_datapath = sw._uuid,\n     },\n     var eth_src = \"{\" ++ eth_src_set.to_vec().join(\", \") ++ \"}\",\n     var __match = i\"eth.src == ${eth_src} && (arp.op == 1 || nd_ns)\",\n-    var mc_flood_l2 = json_string_escape(mC_FLOOD_L2().0),\n+    var mc_flood_l2 = json_escape(mC_FLOOD_L2().0),\n     var actions = i\"outport = ${mc_flood_l2}; output;\".\n \n /* Forward ARP requests for owned IP addresses (L3, VIP, NAT) only to this\n@@ -4542,7 +4531,7 @@ Flow(.logical_datapath = sw._uuid,\n  * Priority: 80.\n  */\n function get_arp_forward_ips(rp: Intern<RouterPort>):\n-    (Set<string>, Set<string>, Set<string>, Set<string>) =\n+    (Set<istring>, Set<istring>, Set<istring>, Set<istring>) =\n {\n     var reachable_ips_v4 = set_empty();\n     var reachable_ips_v6 = set_empty();\n@@ -4555,7 +4544,7 @@ function get_arp_forward_ips(rp: Intern<RouterPort>):\n         /* Check if the ovn port has a network configured on which we could\n          * expect ARP requests for the LB VIP.\n          */\n-        match (ip_parse(a)) {\n+        match (ip_parse(a.ival())) {\n             Some{ipv4} -> if (lrouter_port_ip_reachable(rp, IPv4{ipv4})) {\n                 reachable_ips_v4.insert(a)\n             } else {\n@@ -4568,7 +4557,7 @@ function get_arp_forward_ips(rp: Intern<RouterPort>):\n         /* Check if the ovn port has a network configured on which we could\n          * expect NS requests for the LB VIP.\n          */\n-        match (ipv6_parse(a)) {\n+        match (ipv6_parse(a.ival())) {\n             Some{ipv6} -> if (lrouter_port_ip_reachable(rp, IPv6{ipv6})) {\n                 reachable_ips_v6.insert(a)\n             } else {\n@@ -4579,7 +4568,7 @@ function get_arp_forward_ips(rp: Intern<RouterPort>):\n     };\n \n     for (nat in rp.router.nats) {\n-        if (nat.nat.__type != \"snat\") {\n+        if (nat.nat.__type != i\"snat\") {\n             /* Check if the ovn port has a network configured on which we could\n              * expect ARP requests/NS for the DNAT external_ip.\n              */\n@@ -4598,10 +4587,10 @@ function get_arp_forward_ips(rp: Intern<RouterPort>):\n     };\n \n     for (a in rp.networks.ipv4_addrs) {\n-        reachable_ips_v4.insert(\"${a.addr}\")\n+        reachable_ips_v4.insert(i\"${a.addr}\")\n     };\n     for (a in rp.networks.ipv6_addrs) {\n-        reachable_ips_v6.insert(\"${a.addr}\")\n+        reachable_ips_v6.insert(i\"${a.addr}\")\n     };\n \n     (reachable_ips_v4, reachable_ips_v6, unreachable_ips_v4, unreachable_ips_v6)\n@@ -4609,10 +4598,10 @@ function get_arp_forward_ips(rp: Intern<RouterPort>):\n \n relation &SwitchPortARPForwards(\n     port: Intern<SwitchPort>,\n-    reachable_ips_v4: Set<string>,\n-    reachable_ips_v6: Set<string>,\n-    unreachable_ips_v4: Set<string>,\n-    unreachable_ips_v6: Set<string>\n+    reachable_ips_v4: Set<istring>,\n+    reachable_ips_v6: Set<istring>,\n+    unreachable_ips_v4: Set<istring>,\n+    unreachable_ips_v6: Set<istring>\n )\n \n &SwitchPortARPForwards(.port = port,\n@@ -4647,7 +4636,7 @@ Flow(.logical_datapath = sw._uuid,\n     rp.is_enabled(),\n     &SwitchPortARPForwards(.port = sp, .reachable_ips_v4 = ips_v4),\n     var ipv4 = FlatMap(ips_v4),\n-    var mc_flood_l2 = json_string_escape(mC_FLOOD_L2().0).\n+    var mc_flood_l2 = json_escape(mC_FLOOD_L2().0).\n Flow(.logical_datapath = sw._uuid,\n      .stage            = s_SWITCH_IN_L2_LKUP(),\n      .priority         = 80,\n@@ -4665,7 +4654,7 @@ Flow(.logical_datapath = sw._uuid,\n     rp.is_enabled(),\n     &SwitchPortARPForwards(.port = sp, .reachable_ips_v6 = ips_v6),\n     var ipv6 = FlatMap(ips_v6),\n-    var mc_flood_l2 = json_string_escape(mC_FLOOD_L2().0).\n+    var mc_flood_l2 = json_escape(mC_FLOOD_L2().0).\n \n Flow(.logical_datapath = sw._uuid,\n      .stage            = s_SWITCH_IN_L2_LKUP(),\n@@ -4679,7 +4668,7 @@ Flow(.logical_datapath = sw._uuid,\n     rp.is_enabled(),\n     &SwitchPortARPForwards(.port = sp, .unreachable_ips_v4 = ips_v4),\n     var ipv4 = FlatMap(ips_v4),\n-    var flood = json_string_escape(mC_FLOOD().0).\n+    var flood = json_escape(mC_FLOOD().0).\n \n Flow(.logical_datapath = sw._uuid,\n      .stage            = s_SWITCH_IN_L2_LKUP(),\n@@ -4693,11 +4682,11 @@ Flow(.logical_datapath = sw._uuid,\n     rp.is_enabled(),\n     &SwitchPortARPForwards(.port = sp, .unreachable_ips_v6 = ips_v6),\n     var ipv6 = FlatMap(ips_v6),\n-    var flood = json_string_escape(mC_FLOOD().0).\n+    var flood = json_escape(mC_FLOOD().0).\n \n for (SwitchPortNewDynamicAddress(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = sw},\n                                  .address = Some{addrs})\n-     if lsp.__type != \"external\") {\n+     if lsp.__type != i\"external\") {\n     Flow(.logical_datapath = sw._uuid,\n          .stage            = s_SWITCH_IN_L2_LKUP(),\n          .priority         = 50,\n@@ -4715,9 +4704,9 @@ for (&SwitchPort(.lsp = lsp,\n                                           .is_redirect = is_redirect,\n                                           .router = &Router{._uuid = lr_uuid,\n                                                             .l3dgw_ports = l3dgw_ports}}})\n-     if (lsp.addresses.contains(\"router\") and lsp.__type != \"external\"))\n+     if (lsp.addresses.contains(i\"router\") and lsp.__type != i\"external\"))\n {\n-    Some{var mac} = scan_eth_addr(lrp.mac) in {\n+    Some{var mac} = scan_eth_addr(lrp.mac.ival()) in {\n         var add_chassis_resident_check =\n             not sw.localnet_ports.is_empty() and\n             (/* The peer of this port represents a distributed\n@@ -4732,13 +4721,13 @@ for (&SwitchPort(.lsp = lsp,\n               * this logical switch should be run on the chassis\n               * hosting the gateway port.\n               */\n-              lrp.options.get_bool_def(\"reside-on-redirect-chassis\", false)) in\n+              lrp.options.get_bool_def(i\"reside-on-redirect-chassis\", false)) in\n         var __match = if (add_chassis_resident_check) {\n             var redirect_port_name = if (is_redirect) {\n-                json_string_escape(chassis_redirect_name(lrp.name))\n+                json_escape(chassis_redirect_name(lrp.name))\n             } else {\n                 match (l3dgw_ports.nth(0)) {\n-                    Some {var gw_port} -> json_string_escape(chassis_redirect_name(gw_port.name)),\n+                    Some {var gw_port} -> json_escape(chassis_redirect_name(gw_port.name)),\n                     None -> \"\"\n                 }\n             };\n@@ -4762,11 +4751,11 @@ for (&SwitchPort(.lsp = lsp,\n          * distributed logical routers. */\n         if (is_redirect) {\n             for (LogicalRouterNAT(.lr = lr_uuid, .nat = nat)) {\n-                if (nat.nat.__type == \"dnat_and_snat\") {\n+                if (nat.nat.__type == i\"dnat_and_snat\") {\n                     Some{var lport} = nat.nat.logical_port in\n                     Some{var emac} = nat.nat.external_mac in\n-                    Some{var nat_mac} = eth_addr_from_string(emac) in\n-                    var __match = i\"eth.dst == ${nat_mac} && is_chassis_resident(${json_string_escape(lport)})\" in\n+                    Some{var nat_mac} = eth_addr_from_string(emac.ival()) in\n+                    var __match = i\"eth.dst == ${nat_mac} && is_chassis_resident(${json_escape(lport)})\" in\n                     Flow(.logical_datapath = sw._uuid,\n                          .stage            = s_SWITCH_IN_L2_LKUP(),\n                          .priority         = 50,\n@@ -4805,7 +4794,7 @@ for (sw in &Switch(._uuid = ls_uuid)) {\n          .priority         = 50,\n          .__match          = i\"outport == \\\"none\\\"\",\n          .actions          = if (sw.has_unknown_ports) {\n-                                 var mc_unknown = json_string_escape(mC_UNKNOWN().0);\n+                                 var mc_unknown = json_escape(mC_UNKNOWN().0);\n                                  i\"outport = ${mc_unknown}; output;\"\n                              } else {\n                                  i\"drop;\"\n@@ -4862,7 +4851,7 @@ Flow(.logical_datapath = ls_uuid,\n      .io_port = Some{sp.lsp.name},\n      .controller_meter = None) :-\n     LogicalSwitchPortWithUnknownAddress(ls_uuid, lsp_uuid),\n-    sp in &SwitchPort(.lsp = &nb::Logical_Switch_Port{._uuid = lsp_uuid, .__type = \"\"},\n+    sp in &SwitchPort(.lsp = &nb::Logical_Switch_Port{._uuid = lsp_uuid, .__type = i\"\"},\n                       .ps_addresses = vec_empty()).\n \n Flow(.logical_datapath = ls_uuid,\n@@ -4902,21 +4891,21 @@ Flow(.logical_datapath = sw._uuid,\n      .controller_meter = None) :-\n     &SwitchPort(.sw = sw, .lsp = lsp, .json_name = json_name, .ps_eth_addresses = ps_eth_addresses),\n     lsp.is_enabled(),\n-    lsp.__type != \"external\",\n+    lsp.__type != i\"external\",\n     var __match = if (ps_eth_addresses.is_empty()) {\n             i\"outport == ${json_name}\"\n         } else {\n             i\"outport == ${json_name} && eth.dst == {${ps_eth_addresses.join(\\\" \\\")}}\"\n         },\n     pbinding in sb::Out_Port_Binding(.logical_port = lsp.name),\n-    var queue_action = match ((lsp.__type,\n-                               pbinding.options.get(\"qdisc_queue_id\"))) {\n+    var queue_action = match ((lsp.__type.ival(),\n+                               pbinding.options.get(i\"qdisc_queue_id\"))) {\n         (\"localnet\", Some{queue_id}) -> \"set_queue(${queue_id});\",\n         _ -> \"\"\n     }.\n \n for (&SwitchPort(.lsp = lsp, .json_name = json_name, .sw = sw)) {\n-    if (not lsp.is_enabled() and lsp.__type != \"external\") {\n+    if (not lsp.is_enabled() and lsp.__type != i\"external\") {\n         Flow(.logical_datapath = sw._uuid,\n              .stage            = s_SWITCH_OUT_PORT_SEC_L2(),\n              .priority         = 150,\n@@ -4931,7 +4920,7 @@ for (&SwitchPort(.lsp = lsp, .json_name = json_name, .sw = sw)) {\n for (SwitchPortPSAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = sw},\n                            .ps_addrs = ps)\n      if (ps.ipv4_addrs.len() > 0 or ps.ipv6_addrs.len() > 0)\n-         and lsp.__type != \"external\")\n+         and lsp.__type != i\"external\")\n {\n     if (ps.ipv4_addrs.len() > 0) {\n         var addrs = {\n@@ -5018,7 +5007,7 @@ for (&RouterPort(.lrp = lrp,\n      * This will save us from having to match on inport further down in\n      * the pipeline.\n      */\n-    var gw_mtu = lrp.options.get_int_def(\"gateway_mtu\", 0) in\n+    var gw_mtu = lrp.options.get_int_def(i\"gateway_mtu\", 0) in\n     var mtu = gw_mtu + vLAN_ETH_HEADER_LEN() in\n     var actions = if (gw_mtu > 0) {\n         \"${rEGBIT_PKT_LARGER()} = check_pkt_larger(${mtu}); \"\n@@ -5039,7 +5028,7 @@ for (&RouterPort(.lrp = lrp,\n             if is_redirect {\n                 /* Traffic with eth.dst = l3dgw_port->lrp_networks.ea\n                  * should only be received on the \"redirect-chassis\". */\n-                \" && is_chassis_resident(${json_string_escape(chassis_redirect_name(lrp.name))})\"\n+                \" && is_chassis_resident(${json_escape(chassis_redirect_name(lrp.name))})\"\n             } else { \"\" } in\n         Flow(.logical_datapath = router._uuid,\n              .stage            = s_ROUTER_IN_ADMISSION(),\n@@ -5183,7 +5172,7 @@ var rLNIR = rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() in\n /* Check if we need to learn mac-binding from ARP requests. */\n for (RouterPortNetworksIPv4Addr(rp@&RouterPort{.router = router}, addr)) {\n     var chassis_residence = match (rp.is_redirect) {\n-        true -> \" && is_chassis_resident(${json_string_escape(chassis_redirect_name(rp.lrp.name))})\",\n+        true -> \" && is_chassis_resident(${json_escape(chassis_redirect_name(rp.lrp.name))})\",\n         false -> \"\"\n     } in\n     var rLNR = rEGBIT_LOOKUP_NEIGHBOR_RESULT() in\n@@ -5381,7 +5370,7 @@ AddChassisResidentCheck_(lrp._uuid, res) :-\n          * hosting the gateway port and it should reply to the\n          * ARP requests for the router port IPs.\n          */\n-        lrp.options.get_bool_def(\"reside-on-redirect-chassis\", false)\n+        lrp.options.get_bool_def(i\"reside-on-redirect-chassis\", false)\n     }.\n \n \n@@ -5450,7 +5439,7 @@ LogicalRouterNatArpNdFlow(router, nat) :-\n     /* Skip SNAT entries for now, we handle unique SNAT IPs separately\n      * below.\n      */\n-    __type != \"snat\".\n+    __type != i\"snat\".\n /* Now handle SNAT entries too, one per unique SNAT IP. */\n LogicalRouterNatArpNdFlow(router, nat) :-\n     router in &Router(.snat_ips = snat_ips),\n@@ -5478,7 +5467,7 @@ LogicalRouterPortNatArpNdFlow(router, nat, l3dgw_port) :-\n     /* Skip SNAT entries for now, we handle unique SNAT IPs separately\n      * below.\n      */\n-    nat.nat.__type != \"snat\".\n+    nat.nat.__type != i\"snat\".\n /* Now handle SNAT entries too, one per unique SNAT IP. */\n LogicalRouterPortNatArpNdFlow(router, nat, l3dgw_port) :-\n     router in &Router(.l3dgw_ports = l3dgw_ports, .snat_ips = snat_ips),\n@@ -5497,13 +5486,13 @@ LogicalRouterArpNdFlow(router, nat, Some{lrp}, mac, None, true, 91) :-\n     (var mac, var extra_match) = match ((nat.external_mac, nat.nat.logical_port)) {\n         (Some{external_mac}, Some{logical_port}) -> (\n             /* distributed NAT case, use nat->external_mac */\n-            external_mac.to_string(),\n+            external_mac.to_string().intern(),\n             /* Traffic with eth.src = nat->external_mac should only be\n              * sent from the chassis where nat->logical_port is\n              * resident, so that upstream MAC learning points to the\n              * correct chassis.  Also need to avoid generation of\n              * multiple ARP responses from different chassis. */\n-            \"is_chassis_resident(${json_string_escape(logical_port)})\"\n+            i\"is_chassis_resident(${json_escape(logical_port)})\"\n         ),\n         _ -> (\n             rEG_INPORT_ETH_ADDR(),\n@@ -5513,8 +5502,8 @@ LogicalRouterArpNdFlow(router, nat, Some{lrp}, mac, None, true, 91) :-\n              * Also need to avoid generation of multiple ARP responses\n              * from different chassis. */\n             match (router.l3dgw_ports.nth(0)) {\n-                None -> \"\",\n-                Some {var gw_port} -> \"is_chassis_resident(${json_string_escape(chassis_redirect_name(gw_port.name))})\"\n+                None -> i\"\",\n+                Some {var gw_port} -> i\"is_chassis_resident(${json_escape(chassis_redirect_name(gw_port.name))})\"\n             }\n         )\n     }.\n@@ -5524,15 +5513,15 @@ relation LogicalRouterArpNdFlow(\n     router: Intern<Router>,\n     nat: NAT,\n     lrp: Option<Intern<nb::Logical_Router_Port>>,\n-    mac: string,\n-    extra_match: Option<string>,\n+    mac: istring,\n+    extra_match: Option<istring>,\n     drop: bool,\n     priority: integer)\n-LogicalRouterArpFlow(router, lrp, \"${ipv4}\", mac, extra_match, drop, priority,\n+LogicalRouterArpFlow(router, lrp, i\"${ipv4}\", mac, extra_match, drop, priority,\n                      stage_hint(nat.nat._uuid)) :-\n     LogicalRouterArpNdFlow(router, nat@NAT{.external_ip = IPv4{ipv4}}, lrp,\n                            mac, extra_match, drop, priority).\n-LogicalRouterNdFlow(router, lrp, \"nd_na\", ipv6, true, mac, extra_match, drop, priority,\n+LogicalRouterNdFlow(router, lrp, i\"nd_na\", ipv6, true, mac, extra_match, drop, priority,\n                     stage_hint(nat.nat._uuid)) :-\n     LogicalRouterArpNdFlow(router, nat@NAT{.external_ip = IPv6{ipv6}}, lrp,\n                            mac, extra_match, drop, priority).\n@@ -5540,9 +5529,9 @@ LogicalRouterNdFlow(router, lrp, \"nd_na\", ipv6, true, mac, extra_match, drop, pr\n relation LogicalRouterArpFlow(\n     lr: Intern<Router>,\n     lrp: Option<Intern<nb::Logical_Router_Port>>,\n-    ip: string,\n-    mac: string,\n-    extra_match: Option<string>,\n+    ip: istring,\n+    mac: istring,\n+    extra_match: Option<istring>,\n     drop: bool,\n     priority: integer,\n     stage_hint: bit<32>)\n@@ -5560,10 +5549,10 @@ Flow(.logical_datapath = lr._uuid,\n     var __match = {\n         var clauses = vec_with_capacity(3);\n         match (lrp) {\n-            Some{p} -> clauses.push(\"inport == ${json_string_escape(p.name)}\"),\n+            Some{p} -> clauses.push(i\"inport == ${json_escape(p.name)}\"),\n             None -> ()\n         };\n-        clauses.push(\"arp.op == 1 && arp.tpa == ${ip}\");\n+        clauses.push(i\"arp.op == 1 && arp.tpa == ${ip}\");\n         clauses.append(extra_match.to_vec());\n         clauses.join(\" && \")\n     },\n@@ -5584,11 +5573,11 @@ Flow(.logical_datapath = lr._uuid,\n relation LogicalRouterNdFlow(\n     lr: Intern<Router>,\n     lrp: Option<Intern<nb::Logical_Router_Port>>,\n-    action: string,\n+    action: istring,\n     ip: in6_addr,\n     sn_ip: bool,\n-    mac: string,\n-    extra_match: Option<string>,\n+    mac: istring,\n+    extra_match: Option<istring>,\n     drop: bool,\n     priority: integer,\n     stage_hint: bit<32>)\n@@ -5607,13 +5596,13 @@ Flow(.logical_datapath = lr._uuid,\n     var __match = {\n         var clauses = vec_with_capacity(4);\n         match (lrp) {\n-            Some{p} -> clauses.push(\"inport == ${json_string_escape(p.name)}\"),\n+            Some{p} -> clauses.push(i\"inport == ${json_escape(p.name)}\"),\n             None -> ()\n         };\n         if (sn_ip) {\n-            clauses.push(\"ip6.dst == {${ip}, ${ip.solicited_node()}}\")\n+            clauses.push(i\"ip6.dst == {${ip}, ${ip.solicited_node()}}\")\n         };\n-        clauses.push(\"nd_ns && nd.target == ${ip}\");\n+        clauses.push(i\"nd_ns && nd.target == ${ip}\");\n         clauses.append(extra_match.to_vec());\n         clauses.join(\" && \")\n     },\n@@ -5664,20 +5653,20 @@ for (RouterPortNetworksIPv4Addr(.port = &RouterPort{.lrp = lrp,\n             \"arp.spa == ${addr.match_network()}\" ++\n             if (add_chassis_resident_check) {\n                 var redirect_port_name = if (is_redirect) {\n-                    json_string_escape(chassis_redirect_name(lrp.name))\n+                    json_escape(chassis_redirect_name(lrp.name))\n                 } else {\n                     match (router.l3dgw_ports.nth(0)) {\n                         None -> \"\",\n-                        Some {var gw_port} -> json_string_escape(chassis_redirect_name(gw_port.name))\n+                        Some {var gw_port} -> json_escape(chassis_redirect_name(gw_port.name))\n                     }\n                 };\n                 \" && is_chassis_resident(${redirect_port_name})\"\n             } else \"\" in\n         LogicalRouterArpFlow(.lr = router,\n                              .lrp = Some{lrp},\n-                             .ip = \"${addr.addr}\",\n+                             .ip = i\"${addr.addr}\",\n                              .mac = rEG_INPORT_ETH_ADDR(),\n-                             .extra_match = Some{__match},\n+                             .extra_match = Some{__match.intern()},\n                              .drop = false,\n                              .priority = 90,\n                              .stage_hint = stage_hint(lrp._uuid))\n@@ -5690,14 +5679,14 @@ for (&RouterPort(.lrp = lrp,\n                  .networks = networks,\n                  .is_redirect = is_redirect))\n var residence_check = match (is_redirect) {\n-    true -> Some{\"is_chassis_resident(${json_string_escape(chassis_redirect_name(lrp.name))})\"},\n+    true -> Some{i\"is_chassis_resident(${json_escape(chassis_redirect_name(lrp.name))})\"},\n     false -> None\n } in {\n     (var all_ips_v4, _) = get_router_load_balancer_ips(router, false) in {\n         if (not all_ips_v4.is_empty()) {\n             LogicalRouterArpFlow(.lr = router,\n                                  .lrp = Some{lrp},\n-                                 .ip = \"{ \" ++ all_ips_v4.join(\", \") ++ \" }\",\n+                                 .ip = i\"{ ${all_ips_v4.map(ival).to_vec().join(\\\", \\\")} }\",\n                                  .mac = rEG_INPORT_ETH_ADDR(),\n                                  .extra_match = residence_check,\n                                  .drop = false,\n@@ -5706,11 +5695,11 @@ var residence_check = match (is_redirect) {\n         }\n     };\n     for (RouterLBVIP(.router = &Router{._uuid= lr_uuid}, .vip = vip)) {\n-        Some{(var ip_address, _)} = ip_address_and_port_from_lb_key(vip) in {\n+        Some{(var ip_address, _)} = ip_address_and_port_from_lb_key(vip.ival()) in {\n             IPv6{var ipv6} = ip_address in\n             LogicalRouterNdFlow(.lr = router,\n                                 .lrp = Some{lrp},\n-                                .action = \"nd_na\",\n+                                .action = i\"nd_na\",\n                                 .ip = ipv6,\n                                 .sn_ip = false,\n                                 .mac = rEG_INPORT_ETH_ADDR(),\n@@ -5887,11 +5876,11 @@ for (RouterPortNetworksIPv6Addr(.port = &RouterPort{.lrp = lrp,\n          * upstream MAC learning points to the gateway chassis.\n          * Also need to avoid generation of multiple ND replies\n          * from different chassis. */\n-        Some{\"is_chassis_resident(${json_string_escape(chassis_redirect_name(lrp.name))})\"}\n+        Some{i\"is_chassis_resident(${json_escape(chassis_redirect_name(lrp.name))})\"}\n     } else None in\n     LogicalRouterNdFlow(.lr = router,\n                         .lrp = Some{lrp},\n-                        .action = \"nd_na_router\",\n+                        .action = i\"nd_na_router\",\n                         .ip = addr.addr,\n                         .sn_ip = true,\n                         .mac = rEG_INPORT_ETH_ADDR(),\n@@ -6078,11 +6067,11 @@ Flow(.logical_datapath = lr,\n      .io_port          = None,\n      .controller_meter = None) :-\n     LogicalRouterLB(lr, lb),\n-    lb.options.get_bool_def(\"skip_snat\", false)\n+    lb.options.get_bool_def(i\"skip_snat\", false)\n     .\n \n function lrouter_nat_is_stateless(nat: NAT): bool = {\n-    Some{\"true\"} == nat.nat.options.get(\"stateless\")\n+    Some{i\"true\"} == nat.nat.options.get(i\"stateless\")\n }\n \n /* Handles the match criteria and actions in logical flow\n@@ -6240,9 +6229,9 @@ for (rp in &RouterPort(.router = &Router{._uuid = lr_uuid, .options = lr_options\n     }\n }\n \n-relation VirtualLogicalPort(logical_port: Option<string>)\n+relation VirtualLogicalPort(logical_port: Option<istring>)\n VirtualLogicalPort(Some{logical_port}) :-\n-    lsp in &nb::Logical_Switch_Port(.name = logical_port, .__type = \"virtual\").\n+    lsp in &nb::Logical_Switch_Port(.name = logical_port, .__type = i\"virtual\").\n \n /* NAT rules are only valid on Gateway routers and routers with\n  * l3dgw_port (router has a port with \"redirect-chassis\"\n@@ -6257,8 +6246,8 @@ for (r in &Router(._uuid = lr_uuid,\n         var xx = nat.external_ip.xxreg() in\n         /* Check the validity of nat->logical_ip. 'logical_ip' can\n          * be a subnet when the type is \"snat\". */\n-        Some{(_, var mask)} = ip46_parse_masked(nat.nat.logical_ip) in\n-        true == match ((mask.is_all_ones(), nat.nat.__type)) {\n+        Some{(_, var mask)} = ip46_parse_masked(nat.nat.logical_ip.ival()) in\n+        true == match ((mask.is_all_ones(), nat.nat.__type.ival())) {\n             (_, \"snat\") -> true,\n             (false, _) -> {\n                 warn(\"bad ip ${nat.nat.logical_ip} for dnat in router ${uuid2str(lr_uuid)}\");\n@@ -6268,13 +6257,13 @@ for (r in &Router(._uuid = lr_uuid,\n         } in\n         /* For distributed router NAT, determine whether this NAT rule\n          * satisfies the conditions for distributed NAT processing. */\n-        var mac = match ((not l3dgw_ports.is_empty() and nat.nat.__type == \"dnat_and_snat\",\n+        var mac = match ((not l3dgw_ports.is_empty() and nat.nat.__type == i\"dnat_and_snat\",\n                           nat.nat.logical_port, nat.external_mac)) {\n             (true, Some{_}, Some{mac}) -> Some{mac},\n             _ -> None\n         } in\n         var stateless = (lrouter_nat_is_stateless(nat)\n-                         and nat.nat.__type == \"dnat_and_snat\") in\n+                         and nat.nat.__type == i\"dnat_and_snat\") in\n         {\n             /* Ingress UNSNAT table: It is for already established connections'\n              * reverse traffic. i.e., SNAT has already been done in egress\n@@ -6285,7 +6274,7 @@ for (r in &Router(._uuid = lr_uuid,\n              * because when the packet was DNATed in ingress pipeline, it did\n              * not know about the possibility of eventual additional SNAT in\n              * egress pipeline. */\n-            if (nat.nat.__type == \"snat\" or nat.nat.__type == \"dnat_and_snat\") {\n+            if (nat.nat.__type == i\"snat\" or nat.nat.__type == i\"dnat_and_snat\") {\n                 if (l3dgw_ports.is_empty()) {\n                     /* Gateway router. */\n                     var actions = if (stateless) {\n@@ -6308,11 +6297,11 @@ for (r in &Router(._uuid = lr_uuid,\n                     /* Traffic received on l3dgw_port is subject to NAT. */\n                     var __match =\n                         \"ip && ${ipX}.dst == ${nat.nat.external_ip}\"\n-                        \" && inport == ${json_string_escape(gwport.name)}\" ++\n+                        \" && inport == ${json_escape(gwport.name)}\" ++\n                         if (mac == None) {\n                             /* Flows for NAT rules that are centralized are only\n                              * programmed on the \"redirect-chassis\". */\n-                            \" && is_chassis_resident(${json_string_escape(chassis_redirect_name(gwport.name))})\"\n+                            \" && is_chassis_resident(${json_escape(chassis_redirect_name(gwport.name))})\"\n                         } else { \"\" } in\n                     var actions = if (stateless) {\n                         i\"${ipX}.dst=${nat.nat.logical_ip}; next;\"\n@@ -6334,12 +6323,12 @@ for (r in &Router(._uuid = lr_uuid,\n              * IP address that needs to be DNATted from a external IP address\n              * to a logical IP address. */\n             var ip_and_ports = \"${nat.nat.logical_ip}\" ++\n-                               if (nat.nat.external_port_range != \"\") {\n+                               if (nat.nat.external_port_range != i\"\") {\n                                    \" ${nat.nat.external_port_range}\"\n                                } else {\n                                    \"\"\n                                } in\n-            if (nat.nat.__type == \"dnat\" or nat.nat.__type == \"dnat_and_snat\") {\n+            if (nat.nat.__type == i\"dnat\" or nat.nat.__type == i\"dnat_and_snat\") {\n                 l3dgw_ports.is_empty() in\n                 var __match = \"ip && ${ipX}.dst == ${nat.nat.external_ip}\" in\n                 (var ext_ip_match, var ext_flow) = lrouter_nat_add_ext_ip_match(\n@@ -6352,7 +6341,7 @@ for (r in &Router(._uuid = lr_uuid,\n                     Some{var f} = ext_flow in Flow[f];\n \n                     var flag_action =\n-                        if (has_force_snat_ip(r.options, \"dnat\")) {\n+                        if (has_force_snat_ip(r.options, i\"dnat\")) {\n                             /* Indicate to the future tables that a DNAT has taken\n                              * place and a force SNAT needs to be done in the\n                              * Egress SNAT table. */\n@@ -6377,11 +6366,11 @@ for (r in &Router(._uuid = lr_uuid,\n                 Some {var gwport} = l3dgw_ports.nth(0) in\n                 var __match =\n                     \"ip && ${ipX}.dst == ${nat.nat.external_ip}\"\n-                    \" && inport == ${json_string_escape(gwport.name)}\" ++\n+                    \" && inport == ${json_escape(gwport.name)}\" ++\n                     if (mac == None) {\n                         /* Flows for NAT rules that are centralized are only\n                          * programmed on the \"redirect-chassis\". */\n-                        \" && is_chassis_resident(${json_string_escape(chassis_redirect_name(gwport.name))})\"\n+                        \" && is_chassis_resident(${json_escape(chassis_redirect_name(gwport.name))})\"\n                     } else { \"\" } in\n                 (var ext_ip_match, var ext_flow) = lrouter_nat_add_ext_ip_match(\n                     r, nat, __match, ipX, true, mask) in\n@@ -6408,8 +6397,8 @@ for (r in &Router(._uuid = lr_uuid,\n \n             /* ARP resolve for NAT IPs. */\n             Some {var gwport} = l3dgw_ports.nth(0) in {\n-            var gwport_name = json_string_escape(gwport.name) in {\n-                if (nat.nat.__type == \"snat\") {\n+            var gwport_name = json_escape(gwport.name) in {\n+                if (nat.nat.__type == i\"snat\") {\n                     var __match = i\"inport == ${gwport_name} && \"\n                                   \"${ipX}.src == ${nat.nat.external_ip}\" in\n                     Flow(.logical_datapath = lr_uuid,\n@@ -6426,7 +6415,7 @@ for (r in &Router(._uuid = lr_uuid,\n                 var __match = i\"outport == ${gwport_name} && \"\n                               \"${nexthop_reg} == ${nat.nat.external_ip}\" in\n                 var dst_mac = match (mac) {\n-                    Some{value} -> \"${value}\",\n+                    Some{value} -> i\"${value}\",\n                     None -> gwport.mac\n                 } in\n                 Flow(.logical_datapath = lr_uuid,\n@@ -6447,15 +6436,15 @@ for (r in &Router(._uuid = lr_uuid,\n              *\n              * Note that this only applies for NAT on a distributed router.\n              */\n-            if ((nat.nat.__type == \"dnat\" or nat.nat.__type == \"dnat_and_snat\")) {\n+            if ((nat.nat.__type == i\"dnat\" or nat.nat.__type == i\"dnat_and_snat\")) {\n                 Some {var gwport} = l3dgw_ports.nth(0) in\n                 var __match =\n                     \"ip && ${ipX}.src == ${nat.nat.logical_ip}\"\n-                    \" && outport == ${json_string_escape(gwport.name)}\" ++\n+                    \" && outport == ${json_escape(gwport.name)}\" ++\n                     if (mac == None) {\n                         /* Flows for NAT rules that are centralized are only\n                          * programmed on the \"redirect-chassis\". */\n-                        \" && is_chassis_resident(${json_string_escape(chassis_redirect_name(gwport.name))})\"\n+                        \" && is_chassis_resident(${json_escape(chassis_redirect_name(gwport.name))})\"\n                     } else { \"\" } in\n                 var actions =\n                     match (mac) {\n@@ -6481,12 +6470,12 @@ for (r in &Router(._uuid = lr_uuid,\n              * source ip address that needs to be SNATted to a external ip\n              * address. */\n             var ip_and_ports = \"${nat.nat.external_ip}\" ++\n-                               if (nat.nat.external_port_range != \"\") {\n+                               if (nat.nat.external_port_range != i\"\") {\n                                    \" ${nat.nat.external_port_range}\"\n                                } else {\n                                    \"\"\n                                } in\n-            if (nat.nat.__type == \"snat\" or nat.nat.__type == \"dnat_and_snat\") {\n+            if (nat.nat.__type == i\"snat\" or nat.nat.__type == i\"dnat_and_snat\") {\n                 l3dgw_ports.is_empty() in\n                 var __match = \"ip && ${ipX}.src == ${nat.nat.logical_ip}\" in\n                 (var ext_ip_match, var ext_flow) = lrouter_nat_add_ext_ip_match(\n@@ -6517,11 +6506,11 @@ for (r in &Router(._uuid = lr_uuid,\n                 Some {var gwport} = l3dgw_ports.nth(0) in\n                 var __match =\n                     \"ip && ${ipX}.src == ${nat.nat.logical_ip}\"\n-                    \" && outport == ${json_string_escape(gwport.name)}\" ++\n+                    \" && outport == ${json_escape(gwport.name)}\" ++\n                     if (mac == None) {\n                         /* Flows for NAT rules that are centralized are only\n                          * programmed on the \"redirect-chassis\". */\n-                        \" && is_chassis_resident(${json_string_escape(chassis_redirect_name(gwport.name))})\"\n+                        \" && is_chassis_resident(${json_escape(chassis_redirect_name(gwport.name))})\"\n                     } else { \"\" } in\n                 (var ext_ip_match, var ext_flow) = lrouter_nat_add_ext_ip_match(\n                     r, nat, __match, ipX, false, mask) in\n@@ -6564,8 +6553,8 @@ for (r in &Router(._uuid = lr_uuid,\n             Some{var gwport} = l3dgw_ports.nth(0) in\n             Some{var logical_port} = nat.nat.logical_port in\n             var __match =\n-                i\"eth.dst == ${mac_addr} && inport == ${json_string_escape(gwport.name)}\"\n-                \" && is_chassis_resident(${json_string_escape(logical_port)})\" in\n+                i\"eth.dst == ${mac_addr} && inport == ${json_escape(gwport.name)}\"\n+                \" && is_chassis_resident(${json_escape(logical_port)})\" in\n             /* Store the ethernet address of the port receiving the packet.\n              * This will save us from having to match on inport further\n              * down in the pipeline.\n@@ -6594,8 +6583,8 @@ for (r in &Router(._uuid = lr_uuid,\n             Some{var external_mac} = nat.nat.external_mac in\n             var __match =\n                 i\"${ipX}.src == ${nat.nat.logical_ip} && \"\n-                \"outport == ${json_string_escape(gwport.name)} && \"\n-                \"is_chassis_resident(${json_string_escape(logical_port)})\" in\n+                \"outport == ${json_escape(gwport.name)} && \"\n+                \"is_chassis_resident(${json_escape(logical_port)})\" in\n             var actions =\n                 i\"eth.src = ${external_mac}; \"\n                 \"${xx}${rEG_SRC()} = ${nat.nat.external_ip}; \"\n@@ -6615,7 +6604,7 @@ for (r in &Router(._uuid = lr_uuid,\n                      .stage            = s_ROUTER_IN_GW_REDIRECT(),\n                     .priority         = 80,\n                     .__match          = i\"${ipX}.src == ${nat.nat.logical_ip} && \"\n-                                        \"outport == ${json_string_escape(gwport.name)}\",\n+                                        \"outport == ${json_escape(gwport.name)}\",\n                     .actions          = i\"drop;\",\n                     .stage_hint       = stage_hint(nat.nat._uuid),\n                     .io_port          = None,\n@@ -6631,12 +6620,12 @@ for (r in &Router(._uuid = lr_uuid,\n             /* Distributed router. */\n             Some{var port} = match (mac) {\n                 Some{_} -> match (nat.nat.logical_port) {\n-                               Some{name} -> Some{json_string_escape(name)},\n+                               Some{name} -> Some{json_escape(name)},\n                                None -> None: Option<string>\n                            },\n-                None -> Some{json_string_escape(chassis_redirect_name(gwport.name))}\n+                None -> Some{json_escape(chassis_redirect_name(gwport.name))}\n             } in\n-            var __match = i\"${ipX}.dst == ${nat.nat.external_ip} && outport == ${json_string_escape(gwport.name)} && is_chassis_resident(${port})\" in\n+            var __match = i\"${ipX}.dst == ${nat.nat.external_ip} && outport == ${json_escape(gwport.name)} && is_chassis_resident(${port})\" in\n             var regs = {\n                 var regs = vec_empty();\n                 for (j in range_vec(0, mFF_N_LOG_REGS(), 01)) {\n@@ -6665,13 +6654,13 @@ for (r in &Router(._uuid = lr_uuid,\n \n     /* Handle force SNAT options set in the gateway router. */\n     if (l3dgw_ports.is_empty()) {\n-        var dnat_force_snat_ips = get_force_snat_ip(r.options, \"dnat\") in\n+        var dnat_force_snat_ips = get_force_snat_ip(r.options, i\"dnat\") in\n         if (not dnat_force_snat_ips.is_empty())\n         LogicalRouterForceSnatFlows(.logical_router = lr_uuid,\n                                     .ips = dnat_force_snat_ips,\n                                     .context = \"dnat\");\n \n-        var lb_force_snat_ips = get_force_snat_ip(r.options, \"lb\") in\n+        var lb_force_snat_ips = get_force_snat_ip(r.options, i\"lb\") in\n         if (not lb_force_snat_ips.is_empty())\n         LogicalRouterForceSnatFlows(.logical_router = lr_uuid,\n                                     .ips = lb_force_snat_ips,\n@@ -6700,7 +6689,7 @@ for (RouterLBVIP(\n         .backends = backends)\n      if not l3dgw_ports.is_empty() or is_gateway)\n {\n-    if (backends == \"\" and not lb.options.get_bool_def(\"reject\", false)) {\n+    if (backends == i\"\" and not lb.options.get_bool_def(i\"reject\", false)) {\n         for (LoadBalancerEmptyEvents(lb)) {\n             Some {(var __match, var __action)} =\n                 build_empty_lb_event_flow(vip, lb) in\n@@ -6718,11 +6707,11 @@ for (RouterLBVIP(\n     /* A set to hold all ips that need defragmentation and tracking. */\n \n     /* vip contains IP:port or just IP. */\n-    Some{(var ip_address, var port)} = ip_address_and_port_from_lb_key(vip) in\n+    Some{(var ip_address, var port)} = ip_address_and_port_from_lb_key(vip.ival()) in\n     var ipX = ip_address.ipX() in\n     var proto = match (lb.protocol) {\n         Some{proto} -> proto,\n-        _ -> \"tcp\"\n+        _ -> i\"tcp\"\n     } in {\n         /* If there are any load balancing rules, we should send\n          * the packet to conntrack for defragmentation and\n@@ -6776,15 +6765,15 @@ for (RouterLBVIP(\n                 (110, \"\")\n             } in\n         var __match = match1 ++ match2 ++\n-            match ((l3dgw_ports.nth(0), backends != \"\" or lb.options.get_bool_def(\"reject\", false))) {\n-                (Some{gw_port}, true) -> \" && is_chassis_resident(${json_string_escape(chassis_redirect_name(gw_port.name))})\",\n+            match ((l3dgw_ports.nth(0), backends != i\"\" or lb.options.get_bool_def(i\"reject\", false))) {\n+                (Some{gw_port}, true) -> \" && is_chassis_resident(${json_escape(chassis_redirect_name(gw_port.name))})\",\n                 _ -> \"\"\n             } in\n         var snat_for_lb = snat_for_lb(r.options, lb) in\n         {\n             /* A match and actions for established connections. */\n             var est_match = \"ct.est && \" ++ match1 ++ match2 ++ \" && ct_label.natted == 1\" ++\n-                match ((l3dgw_ports.nth(0), backends != \"\" or lb.options.get_bool_def(\"reject\", false))) {\n+                match ((l3dgw_ports.nth(0), backends != i\"\" or lb.options.get_bool_def(i\"reject\", false))) {\n                     (Some {var gw_port}, true) -> \" && is_chassis_resident(${json_string_escape(chassis_redirect_name(gw_port.name))})\",\n                     _ -> \"\"\n                 } in\n@@ -6835,7 +6824,7 @@ for (RouterLBVIP(\n              */\n             var conds = {\n                 var conds = vec_empty();\n-                for (ip_str in string_split(backends, \",\")) {\n+                for (ip_str in backends.split(\",\")) {\n                     match (ip_address_and_port_from_lb_key(ip_str)) {\n                         None -> () /* FIXME: put a break here */,\n                         Some{(ip_address_, port_)} -> conds.push(\n@@ -6852,8 +6841,8 @@ for (RouterLBVIP(\n             not conds.is_empty() in\n             var undnat_match =\n                 \"${ip_address.ipX()} && (\" ++ conds.join(\" || \") ++\n-                \") && outport == ${json_string_escape(gwport.name)} && \"\n-                \"is_chassis_resident(${json_string_escape(chassis_redirect_name(gwport.name))})\" in\n+                \") && outport == ${json_escape(gwport.name)} && \"\n+                \"is_chassis_resident(${json_escape(chassis_redirect_name(gwport.name))})\" in\n             var action =\n                 match (snat_for_lb) {\n                     SkipSNAT -> i\"flags.skip_snat_for_lb = 1; ct_dnat;\",\n@@ -6893,7 +6882,7 @@ Flow(.logical_datapath = r._uuid,\n         = \"ct.new && \" ++\n           get_match_for_lb_key(lbvip.vip_addr, lbvip.vip_port, lb.protocol, true, true, true) ++\n           match (r.l3dgw_ports.nth(0)) {\n-              Some{gw_port} -> \" && is_chassis_resident(${json_string_escape(chassis_redirect_name(gw_port.name))})\",\n+              Some{gw_port} -> \" && is_chassis_resident(${json_escape(chassis_redirect_name(gw_port.name))})\",\n               _ -> \"\"\n           },\n     var priority = if (lbvip.vip_port != 0) 120 else 110,\n@@ -6925,64 +6914,64 @@ function nD_RA_MIN_INTERVAL_RANGE(max: integer): (integer, integer) = (3, ((max\n \n function nD_MTU_DEFAULT(): integer = 0\n \n-function copy_ra_to_sb(port: RouterPort, address_mode: string): Map<string, string> =\n+function copy_ra_to_sb(port: RouterPort, address_mode: istring): Map<istring, istring> =\n {\n     var options = port.sb_options;\n \n-    options.insert(\"ipv6_ra_send_periodic\", \"true\");\n-    options.insert(\"ipv6_ra_address_mode\", address_mode);\n+    options.insert(i\"ipv6_ra_send_periodic\", i\"true\");\n+    options.insert(i\"ipv6_ra_address_mode\", address_mode);\n \n     var max_interval = port.lrp.ipv6_ra_configs\n-        .get_int_def(\"max_interval\", nD_RA_MAX_INTERVAL_DEFAULT())\n+        .get_int_def(i\"max_interval\", nD_RA_MAX_INTERVAL_DEFAULT())\n         .clamp(nD_RA_MAX_INTERVAL_RANGE());\n-    options.insert(\"ipv6_ra_max_interval\", \"${max_interval}\");\n+    options.insert(i\"ipv6_ra_max_interval\", i\"${max_interval}\");\n \n     var min_interval = port.lrp.ipv6_ra_configs\n-        .get_int_def(\"min_interval\", nd_ra_min_interval_default(max_interval))\n+        .get_int_def(i\"min_interval\", nd_ra_min_interval_default(max_interval))\n         .clamp(nD_RA_MIN_INTERVAL_RANGE(max_interval));\n-    options.insert(\"ipv6_ra_min_interval\", \"${min_interval}\");\n+    options.insert(i\"ipv6_ra_min_interval\", i\"${min_interval}\");\n \n-    var mtu = port.lrp.ipv6_ra_configs.get_int_def(\"mtu\", nD_MTU_DEFAULT());\n+    var mtu = port.lrp.ipv6_ra_configs.get_int_def(i\"mtu\", nD_MTU_DEFAULT());\n \n     /* RFC 2460 requires the MTU for IPv6 to be at least 1280 */\n     if (mtu != 0 and mtu >= 1280) {\n-        options.insert(\"ipv6_ra_mtu\", \"${mtu}\")\n+        options.insert(i\"ipv6_ra_mtu\", i\"${mtu}\")\n     };\n \n     var prefixes = vec_empty();\n     for (addr in port.networks.ipv6_addrs) {\n         if (addr.is_lla()) {\n-            options.insert(\"ipv6_ra_src_addr\", \"${addr.addr}\")\n+            options.insert(i\"ipv6_ra_src_addr\", i\"${addr.addr}\")\n         } else {\n             prefixes.push(addr.match_network())\n         }\n     };\n-    match (port.sb_options.get(\"ipv6_ra_pd_list\")) {\n-        Some{value} -> prefixes.push(value),\n+    match (port.sb_options.get(i\"ipv6_ra_pd_list\")) {\n+        Some{value} -> prefixes.push(value.ival()),\n         _ -> ()\n     };\n-    options.insert(\"ipv6_ra_prefixes\", prefixes.join(\" \"));\n+    options.insert(i\"ipv6_ra_prefixes\", prefixes.join(\" \").intern());\n \n-    match (port.lrp.ipv6_ra_configs.get(\"rdnss\")) {\n-        Some{value} -> options.insert(\"ipv6_ra_rdnss\", value),\n+    match (port.lrp.ipv6_ra_configs.get(i\"rdnss\")) {\n+        Some{value} -> options.insert(i\"ipv6_ra_rdnss\", value),\n         _ -> ()\n     };\n \n-    match (port.lrp.ipv6_ra_configs.get(\"dnssl\")) {\n-        Some{value} -> options.insert(\"ipv6_ra_dnssl\", value),\n+    match (port.lrp.ipv6_ra_configs.get(i\"dnssl\")) {\n+        Some{value} -> options.insert(i\"ipv6_ra_dnssl\", value),\n         _ -> ()\n     };\n \n-    options.insert(\"ipv6_ra_src_eth\", \"${port.networks.ea}\");\n+    options.insert(i\"ipv6_ra_src_eth\", i\"${port.networks.ea}\");\n \n-    var prf = match (port.lrp.ipv6_ra_configs.get(\"router_preference\")) {\n-        Some{prf} -> if (prf == \"HIGH\" or prf == \"LOW\") prf else \"MEDIUM\",\n-        _ -> \"MEDIUM\"\n+    var prf = match (port.lrp.ipv6_ra_configs.get(i\"router_preference\")) {\n+        Some{prf} -> if (prf == i\"HIGH\" or prf == i\"LOW\") prf else i\"MEDIUM\",\n+        _ -> i\"MEDIUM\"\n     };\n-    options.insert(\"ipv6_ra_prf\", prf);\n+    options.insert(i\"ipv6_ra_prf\", prf);\n \n-    match (port.lrp.ipv6_ra_configs.get(\"route_info\")) {\n-        Some{s} -> options.insert(\"ipv6_ra_route_info\", s),\n+    match (port.lrp.ipv6_ra_configs.get(i\"route_info\")) {\n+        Some{s} -> options.insert(i\"ipv6_ra_route_info\", s),\n         _ -> ()\n     };\n \n@@ -6999,17 +6988,17 @@ for (&RouterPort[port@RouterPort{.lrp = lrp@&nb::Logical_Router_Port{.peer = Non\n                                  .peer = PeerSwitch{}}]\n      if (not networks.ipv6_addrs.is_empty()))\n {\n-    Some{var address_mode} = lrp.ipv6_ra_configs.get(\"address_mode\") in\n+    Some{var address_mode} = lrp.ipv6_ra_configs.get(i\"address_mode\") in\n     /* FIXME: we need a nicer wat to write this */\n     true ==\n-        if ((address_mode != \"slaac\") and\n-            (address_mode != \"dhcpv6_stateful\") and\n-            (address_mode != \"dhcpv6_stateless\")) {\n+        if ((address_mode != i\"slaac\") and\n+            (address_mode != i\"dhcpv6_stateful\") and\n+            (address_mode != i\"dhcpv6_stateless\")) {\n             warn(\"Invalid address mode [${address_mode}] defined\");\n             false\n         } else { true } in\n     {\n-        if (lrp.ipv6_ra_configs.get_bool_def(\"send_periodic\", false)) {\n+        if (lrp.ipv6_ra_configs.get_bool_def(i\"send_periodic\", false)) {\n             RouterPortRAOptions(lrp._uuid, copy_ra_to_sb(port, address_mode))\n         };\n \n@@ -7028,7 +7017,7 @@ for (&RouterPort[port@RouterPort{.lrp = lrp@&nb::Logical_Router_Port{.peer = Non\n         {\n             var __match = i\"inport == ${json_name} && ip6.dst == ff02::2 && nd_rs\" in\n             /* As per RFC 2460, 1280 is minimum IPv6 MTU. */\n-            var mtu = match(lrp.ipv6_ra_configs.get(\"mtu\")) {\n+            var mtu = match(lrp.ipv6_ra_configs.get(i\"mtu\")) {\n                     Some{mtu_s} -> {\n                         match (parse_dec_u64(mtu_s)) {\n                             None -> 0,\n@@ -7039,13 +7028,12 @@ for (&RouterPort[port@RouterPort{.lrp = lrp@&nb::Logical_Router_Port{.peer = Non\n                 } in\n             var actions0 =\n                 \"${rEGBIT_ND_RA_OPTS_RESULT()} = put_nd_ra_opts(\"\n-                \"addr_mode = ${json_string_escape(address_mode)}, \"\n+                \"addr_mode = ${json_escape(address_mode)}, \"\n                 \"slla = ${networks.ea}\" ++\n                 if (mtu > 0) { \", mtu = ${mtu}\" } else { \"\" } in\n-            var router_preference = match (lrp.ipv6_ra_configs.get(\"router_preference\")) {\n-                    Some{\"MEDIUM\"} -> \"\",\n-                    None -> \"\",\n-                    Some{prf} -> \", router_preference = \\\"${prf}\\\"\"\n+            var router_preference = match (lrp.ipv6_ra_configs.get(i\"router_preference\")) {\n+                    Some{prf} -> if (prf == i\"MEDIUM\") { \"\" } else { \", router_preference = \\\"${prf}\\\"\" },\n+                    None -> \"\"\n                 } in\n             var actions = actions0 ++ router_preference ++ prefix ++ \"); next;\" in\n             Flow(.logical_datapath = router._uuid,\n@@ -7269,7 +7257,7 @@ relation RouterPortRoutableAddresses(\n     addresses: Set<lport_addresses>)\n RouterPortRoutableAddresses(port.lrp._uuid, addresses) :-\n     port in &RouterPort(.is_redirect = true),\n-    var addresses = get_nat_addresses(port, true).filter_map(extract_addresses),\n+    var addresses = get_nat_addresses(port, true).filter_map(|addrs| addrs.ival().extract_addresses()),\n     addresses != set_empty().\n \n /* Return a vector of pairs (1, set[0]), ... (n, set[n - 1]). */\n@@ -7445,7 +7433,7 @@ Flow(.logical_datapath = router._uuid,\n for (IgmpRouterMulticastGroup(address, rtr, ports)) {\n     for (RouterMcastFloodPorts(rtr, flood_ports) if rtr.mcast_cfg.relay) {\n         var flood_static = not flood_ports.is_empty() in\n-        var mc_static = json_string_escape(mC_STATIC().0) in\n+        var mc_static = json_escape(mC_STATIC().0) in\n         var static_act = {\n             if (flood_static) {\n                 \"clone { \"\n@@ -7457,14 +7445,14 @@ for (IgmpRouterMulticastGroup(address, rtr, ports)) {\n                 \"\"\n             }\n         } in\n-        Some{var ip} = ip46_parse(address) in\n+        Some{var ip} = ip46_parse(address.ival()) in\n         var ipX = ip.ipX() in\n         Flow(.logical_datapath = rtr._uuid,\n              .stage            = s_ROUTER_IN_IP_ROUTING(),\n              .priority         = 500,\n              .__match          = i\"${ipX} && ${ipX}.dst == ${address} \",\n              .actions          =\n-                i\"${static_act}outport = ${json_string_escape(address)}; \"\n+                i\"${static_act}outport = ${json_escape(address)}; \"\n                 \"ip.ttl--; next;\",\n              .stage_hint       = 0,\n              .io_port          = None,\n@@ -7476,7 +7464,7 @@ for (IgmpRouterMulticastGroup(address, rtr, ports)) {\n  * Priority 450. Otherwise drop any multicast traffic.\n  */\n for (RouterMcastFloodPorts(rtr, flood_ports) if rtr.mcast_cfg.relay) {\n-    var mc_static = json_string_escape(mC_STATIC().0) in\n+    var mc_static = json_escape(mC_STATIC().0) in\n     var flood_static = not flood_ports.is_empty() in\n     var actions = if (flood_static) {\n         i\"clone { \"\n@@ -7529,8 +7517,8 @@ for (&Router(._uuid = lr_uuid)) {\n }\n \n /* Convert routing policies to flows. */\n-function pkt_mark_policy(options: Map<string,string>): string {\n-    var pkt_mark = options.get(\"pkt_mark\").and_then(parse_dec_u64).unwrap_or(0);\n+function pkt_mark_policy(options: Map<istring,istring>): string {\n+    var pkt_mark = options.get(i\"pkt_mark\").and_then(parse_dec_u64).unwrap_or(0);\n     if (pkt_mark > 0 and pkt_mark < (1 << 32)) {\n         \"pkt.mark = ${pkt_mark}; \"\n     } else {\n@@ -7540,7 +7528,7 @@ function pkt_mark_policy(options: Map<string,string>): string {\n Flow(.logical_datapath = r._uuid,\n      .stage            = s_ROUTER_IN_POLICY(),\n      .priority         = policy.priority,\n-     .__match          = policy.__match.intern(),\n+     .__match          = policy.__match,\n      .actions          = actions.intern(),\n      .stage_hint       = stage_hint(policy._uuid),\n      .io_port          = None,\n@@ -7548,13 +7536,13 @@ Flow(.logical_datapath = r._uuid,\n     r in &Router(),\n     var policy_uuid = FlatMap(r.policies),\n     policy in nb::Logical_Router_Policy(._uuid = policy_uuid),\n-    policy.action == \"reroute\",\n+    policy.action == i\"reroute\",\n     Some{var nexthop_s} = match (policy.nexthops.size()) {\n         0 -> policy.nexthop,\n         1 -> policy.nexthops.nth(0),\n         _ -> None       /* >1 nexthops handled separately as ECMP. */\n     },\n-    Some{var nexthop} = ip46_parse(nexthop_s),\n+    Some{var nexthop} = ip46_parse(nexthop_s.ival()),\n     out_port in &RouterPort(.router = r),\n     Some{var src_ip} = find_lrp_member_ip(out_port.networks, nexthop),\n     /*\n@@ -7575,7 +7563,7 @@ Flow(.logical_datapath = r._uuid,\n \n /* Returns true if the addresses in 'addrs' are all IPv4 or all IPv6,\n    false if they are a mix. */\n-function all_same_addr_family(addrs: Set<string>): bool {\n+function all_same_addr_family(addrs: Set<istring>): bool {\n     var addr_families = set_empty();\n     for (a in addrs) {\n         addr_families.insert(a.contains(\".\"))\n@@ -7592,9 +7580,9 @@ EcmpReroutePolicy(r, policy, ecmp_group_id) :-\n     r in &Router(),\n     var policy_uuid = FlatMap(r.policies),\n     policy in nb::Logical_Router_Policy(._uuid = policy_uuid),\n-    policy.action == \"reroute\",\n+    policy.action == i\"reroute\",\n     policy.nexthops.size() > 1,\n-    var policies = policy.group_by(r).to_vec(),\n+    var policies = policy.group_by(r).to_vec().map(|x| (x.nexthop, x)).sort_imm().map(|x| x.1),\n     var ecmp_group_ids = range_vec(1, policies.len() + 1, 1),\n     var numbered_policies = policies.zip(ecmp_group_ids),\n     var pair = FlatMap(numbered_policies),\n@@ -7610,7 +7598,7 @@ Flow(.logical_datapath = r._uuid,\n      .controller_meter = None) :-\n     EcmpReroutePolicy(r, policy, ecmp_group_id),\n     var member_ids = range_vec(1, policy.nexthops.size() + 1, 1),\n-    var numbered_nexthops = policy.nexthops.to_vec().zip(member_ids),\n+    var numbered_nexthops = policy.nexthops.map(ival).to_vec().zip(member_ids),\n     var pair = FlatMap(numbered_nexthops),\n     (var nexthop_s, var member_id) = pair,\n     Some{var nexthop} = ip46_parse(nexthop_s),\n@@ -7629,7 +7617,7 @@ Flow(.logical_datapath = r._uuid,\n Flow(.logical_datapath = r._uuid,\n      .stage            = s_ROUTER_IN_POLICY(),\n      .priority         = policy.priority,\n-     .__match          = policy.__match.intern(),\n+     .__match          = policy.__match,\n      .actions          = actions,\n      .stage_hint       = stage_hint(policy._uuid),\n      .io_port          = None,\n@@ -7649,7 +7637,7 @@ Flow(.logical_datapath = r._uuid,\n Flow(.logical_datapath = r._uuid,\n      .stage            = s_ROUTER_IN_POLICY(),\n      .priority         = policy.priority,\n-     .__match          = policy.__match.intern(),\n+     .__match          = policy.__match,\n      .actions          = i\"drop;\",\n      .stage_hint       = stage_hint(policy._uuid),\n      .io_port          = None,\n@@ -7657,11 +7645,11 @@ Flow(.logical_datapath = r._uuid,\n     r in &Router(),\n     var policy_uuid = FlatMap(r.policies),\n     policy in nb::Logical_Router_Policy(._uuid = policy_uuid),\n-    policy.action == \"drop\".\n+    policy.action == i\"drop\".\n Flow(.logical_datapath = r._uuid,\n      .stage            = s_ROUTER_IN_POLICY(),\n      .priority         = policy.priority,\n-     .__match          = policy.__match.intern(),\n+     .__match          = policy.__match,\n      .actions          = (pkt_mark_policy(policy.options) ++ \"${rEG_ECMP_GROUP_ID()} = 0; next;\").intern(),\n      .stage_hint       = stage_hint(policy._uuid),\n      .io_port          = None,\n@@ -7669,7 +7657,7 @@ Flow(.logical_datapath = r._uuid,\n     r in &Router(),\n     var policy_uuid = FlatMap(r.policies),\n     policy in nb::Logical_Router_Policy(._uuid = policy_uuid),\n-    policy.action == \"allow\".\n+    policy.action == i\"allow\".\n \n \n /* XXX destination unreachable */\n@@ -7753,14 +7741,14 @@ Flow(.logical_datapath = router._uuid,\n      .stage            = s_ROUTER_IN_ARP_RESOLVE(),\n      .priority         = 50,\n      .__match          = i\"outport == ${rp.json_name} && \"\n-                         \"!is_chassis_resident(${json_string_escape(chassis_redirect_name(l3dgw_port.name))})\",\n+                         \"!is_chassis_resident(${json_escape(chassis_redirect_name(l3dgw_port.name))})\",\n      .actions          = i\"eth.dst = ${rp.networks.ea}; next;\",\n      .stage_hint       = stage_hint(lrp._uuid),\n      .io_port          = None,\n      .controller_meter = None) :-\n     rp in &RouterPort(.lrp = lrp, .router = router),\n     Some{var l3dgw_port} = router.l3dgw_ports.nth(0),\n-    Some{\"bridged\"} = lrp.options.get(\"redirect-type\").\n+    Some{i\"bridged\"} == lrp.options.get(i\"redirect-type\").\n \n \n /* Drop IP traffic destined to router owned IPs. Part of it is dropped\n@@ -7815,7 +7803,7 @@ Flow(.logical_datapath = peer.router._uuid,\n      FirstHopRouterPortRoutableAddresses(port, peer_uuid),\n      peer in &RouterPort(.lrp = lrp),\n      lrp._uuid == peer_uuid,\n-     not peer.router.options.get_bool_def(\"dynamic_neigh_routers\", false),\n+     not peer.router.options.get_bool_def(i\"dynamic_neigh_routers\", false),\n      var addr = FlatMap(addresses),\n      var ips = addr.ipv4_addrs.map(|a| a.addr.to_string()).join(\", \").\n \n@@ -7828,7 +7816,7 @@ for (SwitchPortIPv4Address(\n         .port = &SwitchPort{.lsp = lsp, .sw = sw},\n         .ea = ea,\n         .addr = addr)\n-     if lsp.__type != \"router\" and lsp.__type != \"virtual\" and lsp.is_enabled())\n+     if lsp.__type != i\"router\" and lsp.__type != i\"virtual\" and lsp.is_enabled())\n {\n     for (&SwitchPort(.sw = &Switch{._uuid = sw._uuid},\n                      .peer = Some{peer@&RouterPort{.router = peer_router}}))\n@@ -7850,7 +7838,7 @@ for (SwitchPortIPv6Address(\n         .port = &SwitchPort{.lsp = lsp, .sw = sw},\n         .ea = ea,\n         .addr = addr)\n-     if lsp.__type != \"router\" and lsp.__type != \"virtual\" and lsp.is_enabled())\n+     if lsp.__type != i\"router\" and lsp.__type != i\"virtual\" and lsp.is_enabled())\n {\n     for (&SwitchPort(.sw = &Switch{._uuid = sw._uuid},\n                      .peer = Some{peer@&RouterPort{.router = peer_router}}))\n@@ -7873,11 +7861,10 @@ for (SwitchPortIPv6Address(\n  *\n  * This is meant for sets of 0 or 1 elements, like the OVSDB integration\n  * with DDlog uses. */\n-function is_empty_set_or_string(s: Option<string>): bool = {\n+function is_empty_set_or_string(s: Option<istring>): bool = {\n     match (s) {\n         None -> true,\n-        Some{\"\"} -> true,\n-        _ -> false\n+        Some{s} -> s == i\"\"\n     }\n }\n \n@@ -7897,10 +7884,10 @@ Flow(.logical_datapath = peer.router._uuid,\n      .stage_hint       = stage_hint(sp.lsp._uuid),\n      .io_port          = None,\n      .controller_meter = None) :-\n-    sp in &SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = \"virtual\"}),\n-    Some{var virtual_ip_s} = lsp.options.get(\"virtual-ip\"),\n-    Some{var virtual_parents} = lsp.options.get(\"virtual-parents\"),\n-    Some{var virtual_ip} = ip_parse(virtual_ip_s),\n+    sp in &SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = i\"virtual\"}),\n+    Some{var virtual_ip_s} = lsp.options.get(i\"virtual-ip\"),\n+    Some{var virtual_parents} = lsp.options.get(i\"virtual-parents\"),\n+    Some{var virtual_ip} = ip_parse(virtual_ip_s.ival()),\n     pb in sb::Port_Binding(.logical_port = sp.lsp.name),\n     is_empty_set_or_string(pb.virtual_parent) or pb.chassis == None,\n     sp2 in &SwitchPort(.sw = sp.sw, .peer = Some{peer}),\n@@ -7914,10 +7901,10 @@ Flow(.logical_datapath = peer.router._uuid,\n      .stage_hint       = stage_hint(sp.lsp._uuid),\n      .io_port          = None,\n      .controller_meter = None) :-\n-    sp in &SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = \"virtual\"}),\n-    Some{var virtual_ip_s} = lsp.options.get(\"virtual-ip\"),\n-    Some{var virtual_parents} = lsp.options.get(\"virtual-parents\"),\n-    Some{var virtual_ip} = ip_parse(virtual_ip_s),\n+    sp in &SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = i\"virtual\"}),\n+    Some{var virtual_ip_s} = lsp.options.get(i\"virtual-ip\"),\n+    Some{var virtual_parents} = lsp.options.get(i\"virtual-parents\"),\n+    Some{var virtual_ip} = ip_parse(virtual_ip_s.ival()),\n     pb in sb::Port_Binding(.logical_port = sp.lsp.name),\n     not (is_empty_set_or_string(pb.virtual_parent) or pb.chassis == None),\n     Some{var virtual_parent} = pb.virtual_parent,\n@@ -7936,7 +7923,7 @@ for (&SwitchPort(.lsp = lsp1,\n                  .peer = Some{peer1@&RouterPort{.router = peer_router}},\n                  .sw = sw)\n      if lsp1.is_enabled() and\n-        not peer_router.options.get_bool_def(\"dynamic_neigh_routers\", false))\n+        not peer_router.options.get_bool_def(i\"dynamic_neigh_routers\", false))\n {\n     for (&SwitchPort(.lsp = lsp2, .peer = Some{peer2},\n                      .sw = &Switch{._uuid = sw._uuid})\n@@ -8031,7 +8018,7 @@ Flow(.logical_datapath = lr_uuid,\n      .controller_meter = None) :-\n     r in &Router(._uuid = lr_uuid),\n     gw_mtu_rp in &RouterPort(.router = r),\n-    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def(\"gateway_mtu\", 0),\n+    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def(i\"gateway_mtu\", 0),\n     gw_mtu > 0,\n     var mtu = gw_mtu + vLAN_ETH_HEADER_LEN().\n Flow(.logical_datapath = lr_uuid,\n@@ -8057,7 +8044,7 @@ Flow(.logical_datapath = lr_uuid,\n      .stage_hint       = stage_hint(rp.lrp._uuid)) :-\n     r in &Router(._uuid = lr_uuid),\n     gw_mtu_rp in &RouterPort(.router = r),\n-    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def(\"gateway_mtu\", 0),\n+    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def(i\"gateway_mtu\", 0),\n     gw_mtu > 0,\n     var mtu = gw_mtu + vLAN_ETH_HEADER_LEN(),\n     rp in &RouterPort(.router = r),\n@@ -8087,7 +8074,7 @@ Flow(.logical_datapath = lr_uuid,\n      .stage_hint       = stage_hint(rp.lrp._uuid)) :-\n     r in &Router(._uuid = lr_uuid),\n     gw_mtu_rp in &RouterPort(.router = r),\n-    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def(\"gateway_mtu\", 0),\n+    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def(i\"gateway_mtu\", 0),\n     gw_mtu > 0,\n     var mtu = gw_mtu + vLAN_ETH_HEADER_LEN(),\n     rp in &RouterPort(.router = r),\n@@ -8117,7 +8104,7 @@ Flow(.logical_datapath = lr_uuid,\n      .stage_hint       = stage_hint(rp.lrp._uuid)) :-\n     r in &Router(._uuid = lr_uuid),\n     gw_mtu_rp in &RouterPort(.router = r),\n-    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def(\"gateway_mtu\", 0),\n+    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def(i\"gateway_mtu\", 0),\n     gw_mtu > 0,\n     var mtu = gw_mtu + vLAN_ETH_HEADER_LEN(),\n     rp in &RouterPort(.router = r),\n@@ -8147,7 +8134,7 @@ Flow(.logical_datapath = lr_uuid,\n      .stage_hint       = stage_hint(rp.lrp._uuid)) :-\n     r in &Router(._uuid = lr_uuid),\n     gw_mtu_rp in &RouterPort(.router = r),\n-    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def(\"gateway_mtu\", 0),\n+    var gw_mtu = gw_mtu_rp.lrp.options.get_int_def(i\"gateway_mtu\", 0),\n     gw_mtu > 0,\n     var mtu = gw_mtu + vLAN_ETH_HEADER_LEN(),\n     rp in &RouterPort(.router = r),\n@@ -8171,8 +8158,8 @@ for (&Router(._uuid = lr_uuid))\n         Flow(.logical_datapath = lr_uuid,\n              .stage            = s_ROUTER_IN_GW_REDIRECT(),\n              .priority         = 50,\n-             .__match          = i\"outport == ${json_string_escape(lrp.name)}\",\n-             .actions          = i\"outport = ${json_string_escape(chassis_redirect_name(lrp.name))}; next;\",\n+             .__match          = i\"outport == ${json_escape(lrp.name)}\",\n+             .actions          = i\"outport = ${json_escape(chassis_redirect_name(lrp.name))}; next;\",\n              .stage_hint       = stage_hint(lrp._uuid),\n              .io_port          = None,\n              .controller_meter = None)\n@@ -8319,7 +8306,7 @@ relation IsVxlanMode0()\n IsVxlanMode0() :-\n     sb::Chassis(.encaps = encaps),\n     var encap_uuid = FlatMap(encaps),\n-    sb::Encap(._uuid = encap_uuid, .__type = \"vxlan\").\n+    sb::Encap(._uuid = encap_uuid, .__type = i\"vxlan\").\n \n relation IsVxlanMode[bool]\n IsVxlanMode[true] :-\n@@ -8334,7 +8321,7 @@ relation OvnMaxDpKeyLocal[integer]\n OvnMaxDpKeyLocal[oVN_MAX_DP_VXLAN_KEY()] :- IsVxlanMode[true].\n OvnMaxDpKeyLocal[oVN_MAX_DP_KEY() - oVN_MAX_DP_GLOBAL_NUM()] :- IsVxlanMode[false].\n \n-function get_dp_tunkey(map: Map<string,string>, key: string): Option<integer> {\n+function get_dp_tunkey(map: Map<istring,istring>, key: istring): Option<integer> {\n     map.get(key)\n        .and_then(parse_dec_u64)\n        .and_then(|x| if (x > 0 and x < (2<<24)) {\n@@ -8348,10 +8335,10 @@ function get_dp_tunkey(map: Map<string,string>, key: string): Option<integer> {\n relation RequestedTunKey(datapath: uuid, tunkey: integer)\n RequestedTunKey(uuid, tunkey) :-\n     ls in &nb::Logical_Switch(._uuid = uuid),\n-    Some{var tunkey} = get_dp_tunkey(ls.other_config, \"requested-tnl-key\").\n+    Some{var tunkey} = get_dp_tunkey(ls.other_config, i\"requested-tnl-key\").\n RequestedTunKey(uuid, tunkey) :-\n     lr in nb::Logical_Router(._uuid = uuid),\n-    Some{var tunkey} = get_dp_tunkey(lr.options, \"requested-tnl-key\").\n+    Some{var tunkey} = get_dp_tunkey(lr.options, i\"requested-tnl-key\").\n Warning[message] :-\n     RequestedTunKey(datapath, tunkey),\n     var count = datapath.group_by((tunkey)).size(),\n@@ -8416,7 +8403,7 @@ TunKeyAllocation(datapath, tunkey) :-\n  * Port IDs in a per-datapath space in the range 1...2**15-1\n  */\n \n-function get_port_tunkey(map: Map<string,string>, key: string): Option<integer> {\n+function get_port_tunkey(map: Map<istring,istring>, key: istring): Option<integer> {\n     map.get(key)\n        .and_then(parse_dec_u64)\n        .and_then(|x| if (x > 0 and x < (2<<15)) {\n@@ -8432,12 +8419,12 @@ RequestedPortTunKey(datapath, port, tunkey) :-\n     sp in &SwitchPort(),\n     var datapath = sp.sw._uuid,\n     var port = sp.lsp._uuid,\n-    Some{var tunkey} = get_port_tunkey(sp.lsp.options, \"requested-tnl-key\").\n+    Some{var tunkey} = get_port_tunkey(sp.lsp.options, i\"requested-tnl-key\").\n RequestedPortTunKey(datapath, port, tunkey) :-\n     rp in &RouterPort(),\n     var datapath = rp.router._uuid,\n     var port = rp.lrp._uuid,\n-    Some{var tunkey} = get_port_tunkey(rp.lrp.options, \"requested-tnl-key\").\n+    Some{var tunkey} = get_port_tunkey(rp.lrp.options, i\"requested-tnl-key\").\n Warning[message] :-\n     RequestedPortTunKey(datapath, port, tunkey),\n     var count = port.group_by((datapath, tunkey)).size(),\n@@ -8514,7 +8501,7 @@ AllocatedMulticastGroupTunKeys(datapath_uuid, keys) :-\n \n // Multicast_Group's not yet in the Realized table.\n relation NotYetAllocatedMulticastGroupTunKeys(datapath_uuid: uuid,\n-                                              all_logical_ids: Vec<string>)\n+                                              all_logical_ids: Vec<istring>)\n \n NotYetAllocatedMulticastGroupTunKeys(datapath_uuid, all_names) :-\n     OutProxy_Multicast_Group(.name = name, .datapath = datapath_uuid),\n@@ -8522,7 +8509,7 @@ NotYetAllocatedMulticastGroupTunKeys(datapath_uuid, all_names) :-\n     var all_names = name.group_by(datapath_uuid).to_vec().\n \n // Perform the allocation\n-relation MulticastGroupTunKeyAllocation(datapath_uuid: uuid, group: string, tunkey: integer)\n+relation MulticastGroupTunKeyAllocation(datapath_uuid: uuid, group: istring, tunkey: integer)\n \n // transfer existing allocations from the realized table\n MulticastGroupTunKeyAllocation(datapath_uuid, group, tunkey) :-\n@@ -8567,8 +8554,8 @@ MulticastGroupTunKeyAllocation(datapath_uuid, group, tunkey) :-\n  * have a queue ID.  For those we use the port's own UUID as the chassis UUID.\n  */\n \n-function port_has_qos_params(opts: Map<string, string>): bool = {\n-    opts.contains_key(\"qos_max_rate\") or opts.contains_key(\"qos_burst\")\n+function port_has_qos_params(opts: Map<istring, istring>): bool = {\n+    opts.contains_key(i\"qos_max_rate\") or opts.contains_key(i\"qos_burst\")\n }\n \n \n@@ -8577,13 +8564,13 @@ relation PortRequiresQID(port: uuid, chassis: uuid)\n \n PortRequiresQID(pb._uuid, chassis) :-\n     pb in OutProxy_Port_Binding(),\n-    pb.__type != \"localnet\",\n+    pb.__type != i\"localnet\",\n     port_has_qos_params(pb.options),\n     sb::Port_Binding(._uuid = pb._uuid, .chassis = chassis_set),\n     Some{var chassis} = chassis_set.\n PortRequiresQID(pb._uuid, pb._uuid) :-\n     pb in OutProxy_Port_Binding(),\n-    pb.__type == \"localnet\",\n+    pb.__type == i\"localnet\",\n     port_has_qos_params(pb.options),\n     sb::Port_Binding(._uuid = pb._uuid).\n \n@@ -8597,16 +8584,16 @@ relation AllocatedQIDs(chassis: uuid, allocated_ids: Map<uuid, integer>)\n \n AllocatedQIDs(chassis, allocated_ids) :-\n     pb in sb::Port_Binding(),\n-    pb.__type != \"localnet\",\n+    pb.__type != i\"localnet\",\n     Some{var chassis} = pb.chassis,\n-    Some{var qid_str} = pb.options.get(\"qdisc_queue_id\"),\n+    Some{var qid_str} = pb.options.get(i\"qdisc_queue_id\"),\n     Some{var qid} = parse_dec_u64(qid_str),\n     var allocated_ids = (pb._uuid, qid).group_by(chassis).to_map().\n AllocatedQIDs(chassis, allocated_ids) :-\n     pb in sb::Port_Binding(),\n-    pb.__type == \"localnet\",\n+    pb.__type == i\"localnet\",\n     var chassis = pb._uuid,\n-    Some{var qid_str} = pb.options.get(\"qdisc_queue_id\"),\n+    Some{var qid_str} = pb.options.get(i\"qdisc_queue_id\"),\n     Some{var qid} = parse_dec_u64(qid_str),\n     var allocated_ids = (pb._uuid, qid).group_by(chassis).to_map().\n \n@@ -8634,10 +8621,10 @@ QueueIDAllocation(port, Some{qid}) :-\n  * This allows ovn-northd to preserve options:ipv6_ra_pd_list, which is set by\n  * ovn-controller.\n  */\n-relation PreserveIPv6RAPDList(lrp_uuid: uuid, ipv6_ra_pd_list: Option<string>)\n+relation PreserveIPv6RAPDList(lrp_uuid: uuid, ipv6_ra_pd_list: Option<istring>)\n PreserveIPv6RAPDList(lrp_uuid, ipv6_ra_pd_list) :-\n     sb::Port_Binding(._uuid = lrp_uuid, .options = options),\n-    var ipv6_ra_pd_list = options.get(\"ipv6_ra_pd_list\").\n+    var ipv6_ra_pd_list = options.get(i\"ipv6_ra_pd_list\").\n PreserveIPv6RAPDList(lrp_uuid, None) :-\n     &nb::Logical_Router_Port(._uuid = lrp_uuid),\n     not sb::Port_Binding(._uuid = lrp_uuid).\n@@ -8653,7 +8640,7 @@ PreserveIPv6RAPDList(lrp_uuid, None) :-\n  * 3. For ports that do not have a tag_request, but have a tag statically assigned\n  *    by directly setting the `tag` field, use this value.\n  */\n-relation SwitchPortReservedTag(parent_name: string, tags: integer)\n+relation SwitchPortReservedTag(parent_name: istring, tags: integer)\n \n SwitchPortReservedTag(parent_name, tag) :-\n     &SwitchPort(.lsp = lsp, .needs_dynamic_tag = needs_dynamic_tag, .parent_name = Some{parent_name}),\n@@ -8666,7 +8653,7 @@ SwitchPortReservedTag(parent_name, tag) :-\n         }\n     }.\n \n-relation SwitchPortReservedTags(parent_name: string, tags: Set<integer>)\n+relation SwitchPortReservedTags(parent_name: istring, tags: Set<integer>)\n \n SwitchPortReservedTags(parent_name, tags) :-\n     SwitchPortReservedTag(parent_name, tag),\n@@ -8734,7 +8721,7 @@ sb::Out_IP_Multicast(._uuid = cfg.datapath,\n     McastSwitchCfg[cfg].\n \n \n-relation PortExists(name: string)\n+relation PortExists(name: istring)\n PortExists(name) :- &nb::Logical_Switch_Port(.name = name).\n PortExists(name) :- &nb::Logical_Router_Port(.name = name).\n \n@@ -8743,7 +8730,7 @@ sb::Out_Load_Balancer(._uuid = lb._uuid,\n                       .vips = lb.vips,\n                       .protocol = lb.protocol,\n                       .datapaths = datapaths,\n-                      .external_ids = [\"lb_id\" -> uuid2str(lb_uuid)],\n+                      .external_ids = [i\"lb_id\" -> uuid2str(lb_uuid).intern()],\n                       .options = options) :-\n     nb in &nb::Logical_Switch(._uuid = ls_uuid, .load_balancer = lb_uuids),\n     var lb_uuid = FlatMap(lb_uuids),\n@@ -8752,14 +8739,14 @@ sb::Out_Load_Balancer(._uuid = lb._uuid,\n     /* Store the fact that northd provides the original (destination IP +\n      * transport port) tuple.\n      */\n-    var options = lb.options.insert_imm(\"hairpin_orig_tuple\", \"true\").\n+    var options = lb.options.insert_imm(i\"hairpin_orig_tuple\", i\"true\").\n \n sb::Out_Service_Monitor(._uuid = hash128((svc_monitor.port_name, lbvipbackend.ip, lbvipbackend.port, protocol)),\n-                       .ip = \"${lbvipbackend.ip}\",\n+                       .ip = i\"${lbvipbackend.ip}\",\n                        .protocol = Some{protocol},\n                        .port = lbvipbackend.port as integer,\n                        .logical_port = svc_monitor.port_name,\n-                       .src_mac = to_string(svc_monitor_mac),\n+                       .src_mac = i\"${svc_monitor_mac}\",\n                        .src_ip = svc_monitor.src_ip,\n                        .options = health_check.options,\n                        .external_ids = map_empty()) :-\n@@ -8770,13 +8757,13 @@ sb::Out_Service_Monitor(._uuid = hash128((svc_monitor.port_name, lbvipbackend.ip\n     Some{var svc_monitor} = lbvipbackend.svc_monitor,\n     PortExists(svc_monitor.port_name),\n     var protocol = default_protocol(lb.protocol),\n-    protocol != \"sctp\".\n+    protocol != i\"sctp\".\n \n Warning[\"SCTP load balancers do not currently support \"\n         \"health checks. Not creating health checks for \"\n         \"load balancer ${uuid2str(lb._uuid)}\"] :-\n     LBVIP[lbvip@&LBVIP{.lb = lb}],\n-    default_protocol(lb.protocol) == \"sctp\",\n+    default_protocol(lb.protocol) == i\"sctp\",\n     Some{var health_check} = lbvip.health_check,\n     var lbvipbackend = FlatMap(lbvip.backends),\n     Some{var svc_monitor} = lbvipbackend.svc_monitor.\n@@ -8803,8 +8790,8 @@ function bFD_UDP_SRC_PORT_MAX(): integer { 65535 }\n // Get already assigned BFD source ports.\n // If there's a conflict, make an arbitrary choice.\n relation AssignedSrcPort(\n-    logical_port: string,\n-    dst_ip: string,\n+    logical_port: istring,\n+    dst_ip: istring,\n     src_port: integer)\n AssignedSrcPort(logical_port, dst_ip, src_port) :-\n     sb::BFD(.logical_port = logical_port, .dst_ip = dst_ip, .src_port = src_port),\n@@ -8822,7 +8809,7 @@ AllocatedSrcPorts(src_ports) :- AllocatedSrcPorts0(src_ports).\n AllocatedSrcPorts(set_empty()) :- Unit(), not AllocatedSrcPorts0(_).\n \n // (logical_port, dst_ip) pairs not yet in the Realized table\n-relation NotYetAllocatedSrcPorts(pairs: Vec<(string, string)>)\n+relation NotYetAllocatedSrcPorts(pairs: Vec<(istring, istring)>)\n NotYetAllocatedSrcPorts(pairs) :-\n     nb::BFD(.logical_port = logical_port, .dst_ip = dst_ip),\n     not AssignedSrcPort(logical_port, dst_ip, _),\n@@ -8830,8 +8817,8 @@ NotYetAllocatedSrcPorts(pairs) :-\n \n // Perform the allocation\n relation SrcPortAllocation(\n-    logical_port: string,\n-    dst_ip: string,\n+    logical_port: istring,\n+    dst_ip: istring,\n     src_port: integer)\n SrcPortAllocation(logical_port, dst_ip, src_port) :- AssignedSrcPort(logical_port, dst_ip, src_port).\n SrcPortAllocation(logical_port, dst_ip, src_port) :-\n@@ -8842,9 +8829,9 @@ SrcPortAllocation(logical_port, dst_ip, src_port) :-\n     ((var logical_port, var dst_ip), var src_port) = allocation.\n \n relation SouthboundBFDStatus(\n-    logical_port: string,\n-    dst_ip: string,\n-    status: Option<string>\n+    logical_port: istring,\n+    dst_ip: istring,\n+    status: Option<istring>\n )\n SouthboundBFDStatus(bfd.logical_port, bfd.dst_ip, Some{bfd.status}) :- bfd in sb::BFD().\n SouthboundBFDStatus(logical_port, dst_ip, None) :-\n@@ -8864,9 +8851,9 @@ sb::Out_BFD(._uuid = hash,\n             .detect_mult = nb.detect_mult.unwrap_or(bFD_DEF_DETECT_MULT()),\n             .status = status,\n             .external_ids = map_empty(),\n-            .options = [\"nb_status\" -> nb.status.unwrap_or(\"\"),\n-                        \"sb_status\" -> sb_status.unwrap_or(\"\"),\n-                        \"referenced\" -> referenced.to_string()]) :-\n+            .options = [i\"nb_status\" -> nb.status.unwrap_or(i\"\"),\n+                        i\"sb_status\" -> sb_status.unwrap_or(i\"\"),\n+                        i\"referenced\" -> i\"${referenced}\"]) :-\n     nb in nb::BFD(),\n     SrcPortAllocation(nb.logical_port, nb.dst_ip, src_port),\n     SouthboundBFDStatus(nb.logical_port, nb.dst_ip, sb_status),\n@@ -8891,22 +8878,22 @@ BFDReferenced(bfd_uuid, false) :-\n //    - 'sb_status0': 'status' in the existing sb::BFD record (None, if none exists yet)\n // computes and returns (nb_status, sb_status), which are the values to use next in these records\n function bfd_new_status(referenced: bool,\n-                        nb_status0: Option<string>,\n-                        sb_status0: Option<string>): (string, string) {\n-    var nb_status = nb_status0.unwrap_or(\"admin_down\");\n+                        nb_status0: Option<istring>,\n+                        sb_status0: Option<istring>): (istring, istring) {\n+    var nb_status = nb_status0.unwrap_or(i\"admin_down\");\n     match (sb_status0) {\n-        Some{sb_status} -> if (nb_status != \"admin_down\" and sb_status != \"admin_down\") {\n+        Some{sb_status} -> if (nb_status != i\"admin_down\" and sb_status != i\"admin_down\") {\n                                nb_status = sb_status\n                            },\n         _ -> ()\n     };\n     var sb_status = nb_status;\n     if (referenced) {\n-        if (nb_status == \"admin_down\") {\n-            nb_status = \"down\"\n+        if (nb_status == i\"admin_down\") {\n+            nb_status = i\"down\"\n         }\n     } else {\n-        nb_status = \"admin_down\"\n+        nb_status = i\"admin_down\"\n     };\n     warn(\"nb_status=${nb_status} sb_status=${sb_status} referenced=${referenced}\");\n     (nb_status, sb_status)\n@@ -8925,7 +8912,7 @@ function lrouter_bfd_flows(lr_uuid: uuid,\n                            lrp_uuid: uuid,\n                            ipX: string,\n                            networks: string,\n-                           controller_meter: Option<string>)\n+                           controller_meter: Option<istring>)\n     : (Flow, Flow)\n {\n     (Flow{.logical_datapath = lr_uuid,\ndiff --git a/northd/ovsdb2ddlog2c b/northd/ovsdb2ddlog2c\nindex e489c3c76..fa994c99e 100755\n--- a/northd/ovsdb2ddlog2c\n+++ b/northd/ovsdb2ddlog2c\n@@ -37,6 +37,7 @@ The following ovsdb2ddlog options are supported:\n   --ro=TABLE.COLUMN          Ignored.\n   --rw=TABLE.COLUMN          Ignored.\n   --intern-table=TABLE       Ignored.\n+  --intern-strings           Ignored.\n   --output-file=FILE.inc     Write output to FILE.inc. If this option is not specified, output will be written to stdout.\n \n The following options are also available:\n@@ -56,7 +57,8 @@ if __name__ == \"__main__\":\n                                                'intern-table=',\n                                                'ro=',\n                                                'rw=',\n-                                               'output-file='])\n+                                               'output-file=',\n+                                               'intern-strings'])\n         except getopt.GetoptError as geo:\n             sys.stderr.write(\"%s: %s\\n\" % (argv0, geo.msg))\n             sys.exit(1)\n@@ -79,7 +81,7 @@ if __name__ == \"__main__\":\n                 output_tables.add(value)\n             elif key == '--output-only-table':\n                 output_only_tables.add(value)\n-            elif key in ['--ro', '--rw', '--intern-table']:\n+            elif key in ['--ro', '--rw', '--intern-table', '--intern-strings']:\n                 pass\n             elif key == '--output-file':\n                 output_file = value\ndiff --git a/tests/ovn-ic.at b/tests/ovn-ic.at\nindex 32f4e9d02..7601ebb45 100644\n--- a/tests/ovn-ic.at\n+++ b/tests/ovn-ic.at\n@@ -223,7 +223,13 @@ OVS_WAIT_WHILE([ovn_as az2 ovn-sbctl show | grep lsp-ts1-lr1])\n \n ovn-nbctl set logical_router_port lrp-lr1-ts1 mac=\"\\\"aa:aa:aa:aa:aa:02\\\"\" \\\n               networks=\"169.254.100.2/24 169.254.200.3/24\"\n-OVS_WAIT_UNTIL([ovn_as az2 ovn-nbctl show | grep \"aa:aa:aa:aa:aa:02 169.254.100.2/24 169.254.200.3/24\"])\n+OVS_WAIT_FOR_OUTPUT([ovn_as az2 ovn-nbctl show | uuidfilt], [0], [dnl\n+switch <0> (ts1)\n+    port lsp-ts1-lr1\n+        type: remote\n+        addresses: [[\"aa:aa:aa:aa:aa:02 169.254.100.2/24 169.254.200.3/24\"]]\n+])\n+\n \n # Delete the router port from az1, the remote port in az2 should still remain\n # but just lost address.\ndiff --git a/tests/ovn.at b/tests/ovn.at\nindex 5104a6895..bf1a3b119 100644\n--- a/tests/ovn.at\n+++ b/tests/ovn.at\n@@ -6150,10 +6150,12 @@ test_dhcp() {\n compare_dhcp_packets() {\n     received=$($PYTHON \"$ovs_srcdir/utilities/ovs-pcap.in\" hv1/vif$1-tx.pcap)\n     expected=$(cat $1.expected)\n+    echo \"received=$received\"\n+    echo \"expected=$expected\"\n \n     if test \"$received\" != \"$expected\"; then\n-        AT_CHECK_UNQUOTED([echo \"$received\"; tcpdump_hex \"$received\"], [0],\n-            [$(echo \"$expected\"; tcpdump_hex \"$expected\")])\n+        (echo \"$expected\"; tcpdump_hex \"$expected\") > expout\n+        AT_CHECK([echo \"$received\"; tcpdump_hex \"$received\"], [0], [expout])\n     fi\n }\n \n",
    "prefixes": [
        "ovs-dev",
        "v2",
        "01/10"
    ]
}