diff --git a/.ovn2.13.metadata b/.ovn2.13.metadata new file mode 100644 index 0000000..543429b --- /dev/null +++ b/.ovn2.13.metadata @@ -0,0 +1,5 @@ +002450621b33c5690060345b0aac25bc2426d675 SOURCES/docutils-0.12.tar.gz +b5734e2bdf09d15d8950b3423dbecec9825d129a SOURCES/openvswitch-2.13.0.tar.gz +3fac0d814f52e9744195042bb9a5e93561eec9bc SOURCES/ovn-2.13.0.tar.gz +d34f96421a86004aa5d26ecf975edefd09f948b1 SOURCES/Pygments-1.4.tar.gz +6beb30f18ffac3de7689b7fd63e9a8a7d9c8df3a SOURCES/Sphinx-1.1.3.tar.gz diff --git a/SOURCES/0001-Add-SCTP-support-to-load-balancers.patch b/SOURCES/0001-Add-SCTP-support-to-load-balancers.patch new file mode 100644 index 0000000..2c966fa --- /dev/null +++ b/SOURCES/0001-Add-SCTP-support-to-load-balancers.patch @@ -0,0 +1,364 @@ +From 080b77af805d1c48f48c617c1fab095edcebaffd Mon Sep 17 00:00:00 2001 +From: Mark Michelson +Date: Mon, 9 Mar 2020 17:09:15 -0400 +Subject: [PATCH] Add SCTP support to load balancers. + +This allows for load balancers to use SCTP as a supported protocol in +addition to the already-supported UDP and TCP. + +With this patch, health checks are not supported for SCTP load +balancers. A test has been added to ensure that this is the case. Health +checks should be added for SCTP load balancers in the near future. When +that's done, the existing test can be updated to ensure that the SCTP +health check works properly. + +Signed-off-by: Mark Michelson +Acked-by: Numan Siddique +(cherry picked from upstream commit c4700eed17da8615107553aec82852a37d401821) + +Change-Id: Iecbc4a2329716aaa0f37a5f53acd5b5cfa74d133 +--- + lib/actions.c | 8 ++-- + northd/ovn-northd.c | 55 ++++++++++++++--------- + ovn-nb.ovsschema | 6 +-- + ovn-nb.xml | 10 ++--- + tests/ovn.at | 121 +++++++++++++++++++++++++++++++++++++++++++++++++- + utilities/ovn-nbctl.c | 8 ++-- + 6 files changed, 170 insertions(+), 38 deletions(-) + +diff --git a/lib/actions.c b/lib/actions.c +index f22acdd..6351db7 100644 +--- a/lib/actions.c ++++ b/lib/actions.c +@@ -1957,10 +1957,12 @@ validate_empty_lb_backends(struct action_context *ctx, + } + break; + case EMPTY_LB_PROTOCOL: +- if (strcmp(c->string, "tcp") && strcmp(c->string, "udp")) { ++ if (strcmp(c->string, "tcp") && ++ strcmp(c->string, "udp") && ++ strcmp(c->string, "sctp")) { + lexer_error(ctx->lexer, +- "Load balancer protocol '%s' is not 'tcp' or 'udp'", +- c->string); ++ "Load balancer protocol '%s' is not 'tcp', 'udp', " ++ "or 'sctp'", c->string); + return; + } + break; +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 75c19df..bb68b8f 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -3173,10 +3173,21 @@ ovn_lb_create(struct northd_context *ctx, struct hmap *lbs, + lb->vips[n_vips].backend_ips = xstrdup(node->value); + + struct nbrec_load_balancer_health_check *lb_health_check = NULL; +- for (size_t i = 0; i < nbrec_lb->n_health_check; i++) { +- if (!strcmp(nbrec_lb->health_check[i]->vip, node->key)) { +- lb_health_check = nbrec_lb->health_check[i]; +- break; ++ if (nbrec_lb->protocol && !strcmp(nbrec_lb->protocol, "sctp")) { ++ if (nbrec_lb->n_health_check > 0) { ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); ++ VLOG_WARN_RL(&rl, ++ "SCTP load balancers do not currently support " ++ "health checks. Not creating health checks for " ++ "load balancer " UUID_FMT, ++ UUID_ARGS(&nbrec_lb->header_.uuid)); ++ } ++ } else { ++ for (size_t i = 0; i < nbrec_lb->n_health_check; i++) { ++ if (!strcmp(nbrec_lb->health_check[i]->vip, node->key)) { ++ lb_health_check = nbrec_lb->health_check[i]; ++ break; ++ } + } + } + +@@ -5558,10 +5569,13 @@ build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, struct ovn_lb *lb) + + const char *proto = NULL; + if (lb_vip->vip_port) { +- if (lb->nlb->protocol && !strcmp(lb->nlb->protocol, "udp")) { +- proto = "udp"; +- } else { +- proto = "tcp"; ++ proto = "tcp"; ++ if (lb->nlb->protocol) { ++ if (!strcmp(lb->nlb->protocol, "udp")) { ++ proto = "udp"; ++ } else if (!strcmp(lb->nlb->protocol, "sctp")) { ++ proto = "sctp"; ++ } + } + } + +@@ -7569,7 +7583,7 @@ static void + add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, + struct ds *match, struct ds *actions, int priority, + const char *lb_force_snat_ip, struct lb_vip *lb_vip, +- bool is_udp, struct nbrec_load_balancer *lb, ++ const char *proto, struct nbrec_load_balancer *lb, + struct shash *meter_groups, struct sset *nat_entries) + { + build_empty_lb_event_flow(od, lflows, lb_vip, lb, S_ROUTER_IN_DNAT, +@@ -7624,11 +7638,10 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, + * S_ROUTER_IN_DNAT stage. */ + struct ds unsnat_match = DS_EMPTY_INITIALIZER; + ds_put_format(&unsnat_match, "%s && %s.dst == %s && %s", +- ip_match, ip_match, lb_vip->vip, +- is_udp ? "udp" : "tcp"); ++ ip_match, ip_match, lb_vip->vip, proto); + if (lb_vip->vip_port) { +- ds_put_format(&unsnat_match, " && %s.dst == %d", +- is_udp ? "udp" : "tcp", lb_vip->vip_port); ++ ds_put_format(&unsnat_match, " && %s.dst == %d", proto, ++ lb_vip->vip_port); + } + + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, 120, +@@ -7654,7 +7667,7 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, + + if (backend->port) { + ds_put_format(&undnat_match, " && %s.src == %d) || ", +- is_udp ? "udp" : "tcp", backend->port); ++ proto, backend->port); + } else { + ds_put_cstr(&undnat_match, ") || "); + } +@@ -9203,15 +9216,13 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + + int prio = 110; + bool is_udp = nullable_string_is_equal(nb_lb->protocol, "udp"); ++ bool is_sctp = nullable_string_is_equal(nb_lb->protocol, ++ "sctp"); ++ const char *proto = is_udp ? "udp" : is_sctp ? "sctp" : "tcp"; + + if (lb_vip->vip_port) { +- if (is_udp) { +- ds_put_format(&match, " && udp && udp.dst == %d", +- lb_vip->vip_port); +- } else { +- ds_put_format(&match, " && tcp && tcp.dst == %d", +- lb_vip->vip_port); +- } ++ ds_put_format(&match, " && %s && %s.dst == %d", proto, ++ proto, lb_vip->vip_port); + prio = 120; + } + +@@ -9220,7 +9231,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + od->l3redirect_port->json_key); + } + add_router_lb_flow(lflows, od, &match, &actions, prio, +- lb_force_snat_ip, lb_vip, is_udp, ++ lb_force_snat_ip, lb_vip, proto, + nb_lb, meter_groups, &nat_entries); + } + } +diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema +index 843e979..ea6f4e3 100644 +--- a/ovn-nb.ovsschema ++++ b/ovn-nb.ovsschema +@@ -1,7 +1,7 @@ + { + "name": "OVN_Northbound", +- "version": "5.20.0", +- "cksum": "2846067333 25243", ++ "version": "5.20.1", ++ "cksum": "721375950 25251", + "tables": { + "NB_Global": { + "columns": { +@@ -168,7 +168,7 @@ + "min": 0, "max": "unlimited"}}, + "protocol": { + "type": {"key": {"type": "string", +- "enum": ["set", ["tcp", "udp"]]}, ++ "enum": ["set", ["tcp", "udp", "sctp"]]}, + "min": 0, "max": 1}}, + "health_check": {"type": { + "key": {"type": "uuid", +diff --git a/ovn-nb.xml b/ovn-nb.xml +index 4a422bb..f7ba9c3 100644 +--- a/ovn-nb.xml ++++ b/ovn-nb.xml +@@ -1458,11 +1458,11 @@ + + +

+- Valid protocols are tcp or udp. This column +- is useful when a port number is provided as part of the +- vips column. If this column is empty and a port number +- is provided as part of vips column, OVN assumes the +- protocol to be tcp. ++ Valid protocols are tcp, udp, or ++ sctp. This column is useful when a port number is ++ provided as part of the vips column. If this column is ++ empty and a port number is provided as part of vips ++ column, OVN assumes the protocol to be tcp. +

+
+ +diff --git a/tests/ovn.at b/tests/ovn.at +index 1402fae..9f3d9d3 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -1423,8 +1423,8 @@ trigger_event(event = "empty_lb_backends", meter="event-elb" vip = "10.0.0.1:80" + encodes as controller(userdata=00.00.00.0f.00.00.00.00.00.00.00.00.00.01.00.0b.31.30.2e.30.2e.30.2e.31.3a.38.30.00.02.00.03.74.63.70.00.03.00.24.31.32.33.34.35.36.37.38.2d.61.62.63.64.2d.39.38.37.36.2d.66.65.64.63.2d.31.31.31.31.39.66.38.65.37.64.36.63,meter_id=5) + + # Testing invalid vip results in extra error messages from socket-util.c +-trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "sctp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c"); +- Load balancer protocol 'sctp' is not 'tcp' or 'udp' ++trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "aarp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c"); ++ Load balancer protocol 'aarp' is not 'tcp', 'udp', or 'sctp' + trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "tcp", load_balancer = "bacon"); + Load balancer 'bacon' is not a UUID + +@@ -17894,6 +17894,123 @@ AT_CHECK([cat lflows.txt], [0], [dnl + OVN_CLEANUP([hv1], [hv2]) + AT_CLEANUP + ++AT_SETUP([ovn -- SCTP Load balancer health checks]) ++AT_KEYWORDS([lb sctp]) ++ ++# Currently this test just ensures that no service monitors get created when ++# An SCTP load balancer is configured to use health checks. Once SCTP load ++# balancers are modified to allow health checks, this test should be altered ++# to ensure the health check succeeds. ++ ++ovn_start ++ ++# Set up same network as previous health check test. As long as health checks ++# aren't allowed for SCTP load balancers, the network will not be used for ++# much. However, having the network in place will make it easy to alter when ++# health checks are allowed. ++ ++net_add n1 ++ ++sim_add hv1 ++as hv1 ++ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++ovs-vsctl -- add-port br-int hv1-vif1 -- \ ++ set interface hv1-vif1 external-ids:iface-id=sw0-p1 \ ++ options:tx_pcap=hv1/vif1-tx.pcap \ ++ options:rxq_pcap=hv1/vif1-rx.pcap \ ++ ofport-request=1 ++ovs-vsctl -- add-port br-int hv1-vif2 -- \ ++ set interface hv1-vif2 external-ids:iface-id=sw0-p2 \ ++ options:tx_pcap=hv1/vif2-tx.pcap \ ++ options:rxq_pcap=hv1/vif2-rx.pcap \ ++ ofport-request=2 ++ ++sim_add hv2 ++as hv2 ++ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.2 ++ovs-vsctl -- add-port br-int hv2-vif1 -- \ ++ set interface hv2-vif1 external-ids:iface-id=sw1-p1 \ ++ options:tx_pcap=hv2/vif1-tx.pcap \ ++ options:rxq_pcap=hv2/vif1-rx.pcap \ ++ ofport-request=1 ++ ++ovn-nbctl ls-add sw0 ++ ++ovn-nbctl lsp-add sw0 sw0-p1 ++ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3" ++ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3" ++ ++ovn-nbctl lsp-add sw0 sw0-p2 ++ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4" ++ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4" ++ ++# Create the second logical switch with one port ++ovn-nbctl ls-add sw1 ++ovn-nbctl lsp-add sw1 sw1-p1 ++ovn-nbctl lsp-set-addresses sw1-p1 "40:54:00:00:00:03 20.0.0.3" ++ovn-nbctl lsp-set-port-security sw1-p1 "40:54:00:00:00:03 20.0.0.3" ++ ++# Create a logical router and attach both logical switches ++ovn-nbctl lr-add lr0 ++ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 ++ovn-nbctl lsp-add sw0 sw0-lr0 ++ovn-nbctl lsp-set-type sw0-lr0 router ++ovn-nbctl lsp-set-addresses sw0-lr0 router ++ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 ++ ++ovn-nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 20.0.0.1/24 ++ovn-nbctl lsp-add sw1 sw1-lr0 ++ovn-nbctl lsp-set-type sw1-lr0 router ++ovn-nbctl lsp-set-addresses sw1-lr0 router ++ovn-nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1 ++ ++ovn-nbctl lb-add lb1 10.0.0.10:80 10.0.0.3:80,20.0.0.3:80 sctp ++ ++ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:10.0.0.3=sw0-p1:10.0.0.2 ++ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:20.0.0.3=sw1-p1:10.0.0.2 ++ ++ovn-nbctl --wait=sb -- --id=@hc create \ ++Load_Balancer_Health_Check vip="10.0.0.10\:80" -- add Load_Balancer . \ ++health_check @hc ++ ++ovn-nbctl --wait=sb ls-lb-add sw0 lb1 ++ovn-nbctl --wait=sb ls-lb-add sw1 lb1 ++ovn-nbctl --wait=sb lr-lb-add lr0 lb1 ++ ++ovn-nbctl ls-add public ++ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 172.168.0.100/24 ++ovn-nbctl lsp-add public public-lr0 ++ovn-nbctl lsp-set-type public-lr0 router ++ovn-nbctl lsp-set-addresses public-lr0 router ++ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public ++ ++# localnet port ++ovn-nbctl lsp-add public ln-public ++ovn-nbctl lsp-set-type ln-public localnet ++ovn-nbctl lsp-set-addresses ln-public unknown ++ovn-nbctl lsp-set-options ln-public network_name=public ++ ++# schedule the gw router port to a chassis. Change the name of the chassis ++ovn-nbctl --wait=hv lrp-set-gateway-chassis lr0-public hv1 20 ++ ++OVN_POPULATE_ARP ++ovn-nbctl --wait=hv sync ++ ++# And now for the anticlimax. We need to ensure that there is no ++# service monitor in the southbound db. ++ ++AT_CHECK([test 0 = `ovn-sbctl --bare --columns _uuid find \ ++service_monitor | sed '/^$/d' | wc -l`]) ++ ++# Let's also be sure the warning message about SCTP load balancers is ++# is in the ovn-northd log ++ ++AT_CHECK([test 1 = `grep -c "SCTP load balancers do not currently support health checks" northd/ovn-northd.log`]) ++ ++AT_CLEANUP ++ + AT_SETUP([ovn -- ARP/ND request broadcast limiting]) + ovn_start + +diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c +index e80058e..59abe00 100644 +--- a/utilities/ovn-nbctl.c ++++ b/utilities/ovn-nbctl.c +@@ -2734,9 +2734,11 @@ nbctl_lb_add(struct ctl_context *ctx) + /* Validate protocol. */ + lb_proto = ctx->argv[4]; + is_update_proto = true; +- if (strcmp(lb_proto, "tcp") && strcmp(lb_proto, "udp")) { +- ctl_error(ctx, "%s: protocol must be one of \"tcp\", \"udp\".", +- lb_proto); ++ if (strcmp(lb_proto, "tcp") && ++ strcmp(lb_proto, "udp") && ++ strcmp(lb_proto, "sctp")) { ++ ctl_error(ctx, "%s: protocol must be one of \"tcp\", \"udp\", " ++ " or \"sctp\".", lb_proto); + return; + } + } +-- +1.8.3.1 + diff --git a/SOURCES/0001-Add-external_ids-column-for-tables-in-nb-schema.patch b/SOURCES/0001-Add-external_ids-column-for-tables-in-nb-schema.patch new file mode 100644 index 0000000..928a1f1 --- /dev/null +++ b/SOURCES/0001-Add-external_ids-column-for-tables-in-nb-schema.patch @@ -0,0 +1,93 @@ +From aff9c19d5fb9bb2cfba220d32ec68111d1adb1c5 Mon Sep 17 00:00:00 2001 +From: Tao YunXiang +Date: Wed, 11 Mar 2020 11:37:53 +0800 +Subject: [PATCH] Add external_ids column for tables in nb schema + +"Logical_Router_Policy" and "Forwarding_Group" tables doesn't have +"external_ids" column. I think it is better to add it, so CMS could +fill it with useful information. + +Author: Tao YunXiang +Co-authored-by: Liu Chang +Co-authored-by: Rong Yin +Signed-off-by: Tao YunXiang +Signed-off-by: Liu Chang +Signed-off-by: Rong Yin +Acked-by: Numan Siddique +Signed-off-by: Numan Siddique +(cherry picked from upstream commit 45de84bff0224e61847ff52d480c6500153ce699) + +Change-Id: I85671ce34238dd8989756b395d85785c25c8842c +--- + ovn-nb.ovsschema | 10 ++++++++-- + ovn-nb.xml | 12 ++++++++++++ + 2 files changed, 20 insertions(+), 2 deletions(-) + +diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema +index bbd6c25..843e979 100644 +--- a/ovn-nb.ovsschema ++++ b/ovn-nb.ovsschema +@@ -1,7 +1,7 @@ + { + "name": "OVN_Northbound", + "version": "5.20.0", +- "cksum": "987891875 24923", ++ "cksum": "2846067333 25243", + "tables": { + "NB_Global": { + "columns": { +@@ -125,6 +125,9 @@ + "vip": {"type": "string"}, + "vmac": {"type": "string"}, + "liveness": {"type": "boolean"}, ++ "external_ids": { ++ "type": {"key": "string", "value": "string", ++ "min": 0, "max": "unlimited"}}, + "child_port": {"type": {"key": "string", + "min": 1, "max": "unlimited"}}}, + "isRoot": false}, +@@ -366,7 +369,10 @@ + "action": {"type": { + "key": {"type": "string", + "enum": ["set", ["allow", "drop", "reroute"]]}}}, +- "nexthop": {"type": {"key": "string", "min": 0, "max": 1}}}, ++ "nexthop": {"type": {"key": "string", "min": 0, "max": 1}}, ++ "external_ids": { ++ "type": {"key": "string", "value": "string", ++ "min": 0, "max": "unlimited"}}}, + "isRoot": false}, + "NAT": { + "columns": { +diff --git a/ovn-nb.xml b/ovn-nb.xml +index f30cc9e..4a422bb 100644 +--- a/ovn-nb.xml ++++ b/ovn-nb.xml +@@ -1313,6 +1313,12 @@ + + List of child ports in the forwarding group. + ++ ++ ++ ++ See External IDs at the beginning of this document. ++ ++ + + + +@@ -2498,6 +2504,12 @@ + address of a connected router port or the IP address of a logical port. +

+ ++ ++ ++ ++ See External IDs at the beginning of this document. ++ ++ +
+ + +-- +1.8.3.1 + diff --git a/SOURCES/0001-DNS-Make-DNS-lookups-case-insensitive.patch b/SOURCES/0001-DNS-Make-DNS-lookups-case-insensitive.patch new file mode 100644 index 0000000..f4c91ae --- /dev/null +++ b/SOURCES/0001-DNS-Make-DNS-lookups-case-insensitive.patch @@ -0,0 +1,269 @@ +From a60b2826bd4eb0144d2dc9b25b63b3a6ca5106c7 Mon Sep 17 00:00:00 2001 +From: Mark Michelson +Date: Mon, 20 Apr 2020 09:25:09 -0400 +Subject: [PATCH 1/2] DNS: Make DNS lookups case insensitive. + +From RFC 1035 Section 2.3.3: + +"For all parts of the DNS that are part of the official protocol, all +comparisons between character strings (e.g., labels, domain names, etc.) +are done in a case-insensitive manner." + +OVN was using case-sensitive lookups and therefore was not complying. +This change makes lookups case insensitive by storing lowercase record +names in the southbound database and converting incoming query names to +lowercase. + +Signed-off-by: Mark Michelson +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1819069 +Reported-by: Jianlin Shi +Acked-by: Numan Siddique +--- + controller/pinctrl.c | 7 ++++- + lib/ovn-util.c | 15 +++++++++++ + lib/ovn-util.h | 5 ++++ + northd/ovn-northd.c | 15 ++++++++++- + ovn-sb.xml | 3 ++- + tests/ovn.at | 61 ++++++++++++++++++++++++++++++++------------ + 6 files changed, 87 insertions(+), 19 deletions(-) + +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index 8703641c2..8592d4e3f 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -2368,7 +2368,12 @@ pinctrl_handle_dns_lookup( + struct dns_data *d = iter->data; + for (size_t i = 0; i < d->n_dps; i++) { + if (d->dps[i] == dp_key) { +- answer_ips = smap_get(&d->records, ds_cstr(&query_name)); ++ /* DNS records in SBDB are stored in lowercase. Convert to ++ * lowercase to perform case insensitive lookup ++ */ ++ char *query_name_lower = str_tolower(ds_cstr(&query_name)); ++ answer_ips = smap_get(&d->records, query_name_lower); ++ free(query_name_lower); + if (answer_ips) { + break; + } +diff --git a/lib/ovn-util.c b/lib/ovn-util.c +index 514e2489f..1b30c2e9a 100644 +--- a/lib/ovn-util.c ++++ b/lib/ovn-util.c +@@ -21,6 +21,7 @@ + #include "openvswitch/ofp-parse.h" + #include "ovn-nb-idl.h" + #include "ovn-sb-idl.h" ++#include + + VLOG_DEFINE_THIS_MODULE(ovn_util); + +@@ -550,3 +551,17 @@ ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2) + (addr1->family == AF_INET ? addr1->ipv4 == addr2->ipv4 : + IN6_ARE_ADDR_EQUAL(&addr1->ipv6, &addr2->ipv6))); + } ++ ++char * ++str_tolower(const char *orig) ++{ ++ char *copy = xmalloc(strlen(orig) + 1); ++ char *p = copy; ++ ++ while (*orig) { ++ *p++ = tolower(*orig++); ++ } ++ *p = '\0'; ++ ++ return copy; ++} +diff --git a/lib/ovn-util.h b/lib/ovn-util.h +index 11238f61c..4076e8b9a 100644 +--- a/lib/ovn-util.h ++++ b/lib/ovn-util.h +@@ -124,4 +124,9 @@ struct v46_ip { + bool ip46_parse_cidr(const char *str, struct v46_ip *prefix, + unsigned int *plen); + bool ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2); ++ ++/* Returns a lowercase copy of orig. ++ * Caller must free the returned string. ++ */ ++char *str_tolower(const char *orig); + #endif +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index f7d3988d7..515722c5d 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -10698,7 +10698,20 @@ sync_dns_entries(struct northd_context *ctx, struct hmap *datapaths) + dns_info->sb_dns, + (struct sbrec_datapath_binding **)dns_info->sbs, + dns_info->n_sbs); +- sbrec_dns_set_records(dns_info->sb_dns, &dns_info->nb_dns->records); ++ ++ /* DNS lookups are case-insensitive. Convert records to lowercase so ++ * we can do consistent lookups when DNS requests arrive ++ */ ++ struct smap lower_records = SMAP_INITIALIZER(&lower_records); ++ struct smap_node *node; ++ SMAP_FOR_EACH (node, &dns_info->nb_dns->records) { ++ smap_add_nocopy(&lower_records, xstrdup(node->key), ++ str_tolower(node->value)); ++ } ++ ++ sbrec_dns_set_records(dns_info->sb_dns, &lower_records); ++ ++ smap_destroy(&lower_records); + free(dns_info->sbs); + free(dns_info); + } +diff --git a/ovn-sb.xml b/ovn-sb.xml +index 72466b97e..5f8da534c 100644 +--- a/ovn-sb.xml ++++ b/ovn-sb.xml +@@ -3597,7 +3597,8 @@ tcp.flags = RST; + + Key-value pair of DNS records with DNS query name as the key + and a string of IP address(es) separated by comma or space as the +- value. ++ value. ovn-northd stores the DNS query name in all lowercase in order to ++ facilitate case-insensitive lookups. + +

Example: "vm1.ovn.org" = "10.0.0.4 aef0::4"

+
+diff --git a/tests/ovn.at b/tests/ovn.at +index 0f02e8144..b78637044 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -8328,6 +8328,12 @@ set_dns_params() { + # IPv4 address - 10.0.0.4 + expected_dns_answer=${query_name}00010001${ttl}00040a000004 + ;; ++ VM1) ++ # VM1.OVN.ORG ++ query_name=03564d31034f564e034f524700 ++ # IPv4 address - 10.0.0.4 ++ expected_dns_answer=${query_name}00010001${ttl}00040a000004 ++ ;; + vm2) + # vm2.ovn.org + query_name=03766d32036f766e036f726700 +@@ -8490,6 +8496,29 @@ reset_pcap_file hv1-vif2 hv1/vif2 + rm -f 1.expected + rm -f 2.expected + ++# Try vm1 again but an all-caps query name ++ ++set_dns_params VM1 ++src_ip=`ip_to_hex 10 0 0 6` ++dst_ip=`ip_to_hex 10 0 0 1` ++dns_reply=1 ++test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data ++ ++# NXT_RESUMEs should be 3. ++OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) ++ ++$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets ++cat 2.expected | cut -c -48 > expout ++AT_CHECK([cat 2.packets | cut -c -48], [0], [expout]) ++# Skipping the IPv4 checksum. ++cat 2.expected | cut -c 53- > expout ++AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout]) ++ ++reset_pcap_file hv1-vif1 hv1/vif1 ++reset_pcap_file hv1-vif2 hv1/vif2 ++rm -f 1.expected ++rm -f 2.expected ++ + # Clear the query name options for ls1-lp2 + ovn-nbctl --wait=hv remove DNS $DNS1 records vm2.ovn.org + +@@ -8499,8 +8528,8 @@ dst_ip=`ip_to_hex 10 0 0 1` + dns_reply=0 + test_dns 1 f00000000001 f00000000002 $src_ip $dst_ip $dns_reply $dns_req_data + +-# NXT_RESUMEs should be 3. +-OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) ++# NXT_RESUMEs should be 4. ++OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets + AT_CHECK([cat 1.packets], [0], []) +@@ -8521,8 +8550,8 @@ dst_ip=`ip_to_hex 10 0 0 1` + dns_reply=0 + test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data + +-# NXT_RESUMEs should be 3 only. +-OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) ++# NXT_RESUMEs should be 4 only. ++OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets + AT_CHECK([cat 2.packets], [0], []) +@@ -8542,8 +8571,8 @@ dst_ip=`ip_to_hex 10 0 0 1` + dns_reply=1 + test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data + +-# NXT_RESUMEs should be 4. +-OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) ++# NXT_RESUMEs should be 5. ++OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets + cat 2.expected | cut -c -48 > expout +@@ -8564,8 +8593,8 @@ dst_ip=`ip_to_hex 10 0 0 1` + dns_reply=1 + test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data + +-# NXT_RESUMEs should be 5. +-OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) ++# NXT_RESUMEs should be 6. ++OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets + cat 2.expected | cut -c -48 > expout +@@ -8586,8 +8615,8 @@ dst_ip=`ip_to_hex 10 0 0 1` + dns_reply=0 + test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data + +-# NXT_RESUMEs should be 6. +-OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) ++# NXT_RESUMEs should be 7. ++OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets + AT_CHECK([cat 2.packets], [0], []) +@@ -8604,8 +8633,8 @@ dst_ip=`ip_to_hex 10 0 0 1` + dns_reply=0 + test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data + +-# NXT_RESUMEs should be 7. +-OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) ++# NXT_RESUMEs should be 8. ++OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets + AT_CHECK([cat 2.packets], [0], []) +@@ -8624,8 +8653,8 @@ dst_ip=`ip_to_hex 10 0 0 1` + dns_reply=1 + test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data + +-# NXT_RESUMEs should be 8. +-OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) ++# NXT_RESUMEs should be 9. ++OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets + cat 1.expected | cut -c -48 > expout +@@ -8646,8 +8675,8 @@ dst_ip=aef00000000000000000000000000001 + dns_reply=1 + test_dns6 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data + +-# NXT_RESUMEs should be 9. +-OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) ++# NXT_RESUMEs should be 10 ++OVS_WAIT_UNTIL([test 10 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets + # Skipping the UDP checksum. +-- +2.25.1 + diff --git a/SOURCES/0001-Disable-IPv6-prefix-reporting-if-IPv6-PD-is-disabled.patch b/SOURCES/0001-Disable-IPv6-prefix-reporting-if-IPv6-PD-is-disabled.patch new file mode 100644 index 0000000..5168b84 --- /dev/null +++ b/SOURCES/0001-Disable-IPv6-prefix-reporting-if-IPv6-PD-is-disabled.patch @@ -0,0 +1,88 @@ +From 0b9d16670d5561d8300d2448cbd4686a3acdc57e Mon Sep 17 00:00:00 2001 +Message-Id: <0b9d16670d5561d8300d2448cbd4686a3acdc57e.1588608928.git.lorenzo.bianconi@redhat.com> +From: Lorenzo Bianconi +Date: Wed, 22 Apr 2020 16:13:03 +0200 +Subject: [PATCH 1/3] Disable IPv6 prefix reporting if IPv6 PD is disabled + +Disable IPv6 prefix delegation reporting in Logical_Router_Port table if +IPv6 prefix delegation state machine has been disabled for the related +logical router port + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique +--- + northd/ovn-northd.c | 28 ++++++++++++++++------------ + tests/system-ovn.at | 7 +++++++ + 2 files changed, 23 insertions(+), 12 deletions(-) + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index bc1ea0bd3..431c511c3 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -2703,6 +2703,10 @@ ovn_update_ipv6_prefix(struct hmap *ports) + continue; + } + ++ if (!smap_get_bool(&op->nbrp->options, "prefix", false)) { ++ continue; ++ } ++ + char prefix[IPV6_SCAN_LEN + 6]; + unsigned aid; + const char *ipv6_pd_list = smap_get(&op->sb->options, +@@ -9364,22 +9368,22 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + } + + struct smap options; ++ smap_clone(&options, &op->sb->options); ++ + /* enable IPv6 prefix delegation */ + bool prefix_delegation = smap_get_bool(&op->nbrp->options, + "prefix_delegation", false); +- if (prefix_delegation) { +- smap_clone(&options, &op->sb->options); +- smap_add(&options, "ipv6_prefix_delegation", "true"); +- sbrec_port_binding_set_options(op->sb, &options); +- smap_destroy(&options); +- } ++ smap_add(&options, "ipv6_prefix_delegation", ++ prefix_delegation ? "true" : "false"); ++ sbrec_port_binding_set_options(op->sb, &options); + +- if (smap_get_bool(&op->nbrp->options, "prefix", false)) { +- smap_clone(&options, &op->sb->options); +- smap_add(&options, "ipv6_prefix", "true"); +- sbrec_port_binding_set_options(op->sb, &options); +- smap_destroy(&options); +- } ++ bool ipv6_prefix = smap_get_bool(&op->nbrp->options, ++ "prefix", false); ++ smap_add(&options, "ipv6_prefix", ++ ipv6_prefix ? "true" : "false"); ++ sbrec_port_binding_set_options(op->sb, &options); ++ ++ smap_destroy(&options); + + const char *address_mode = smap_get( + &op->nbrp->ipv6_ra_configs, "address_mode"); +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index 3b11cf92b..fa3b83cb1 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -3946,6 +3946,13 @@ OVS_WAIT_UNTIL([ + test "${total_pkts}" = "1" + ]) + ++ovn-nbctl set logical_router_port rp-sw0 options:prefix=false ++ovn-nbctl clear logical_router_port rp-sw0 ipv6_prefix ++OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16)" = "[2001:1db8:3333]"]) ++AT_CHECK([ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16], [0], [dnl ++[] ++]) ++ + kill $(pidof tcpdump) + kill $(pidof ovn-controller) + +-- +2.26.2 + diff --git a/SOURCES/0001-Fix-ACL-reject-action-for-UDP-packets.patch b/SOURCES/0001-Fix-ACL-reject-action-for-UDP-packets.patch new file mode 100644 index 0000000..c32d975 --- /dev/null +++ b/SOURCES/0001-Fix-ACL-reject-action-for-UDP-packets.patch @@ -0,0 +1,525 @@ +From cfb0f49b644f2a253cc1365c219d1bb78c2cacac Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Fri, 24 Apr 2020 12:19:09 +0530 +Subject: [PATCH] Fix ACL reject action for UDP packets. + +The icmp packet generated by ovn-controller for reject ACL action +for non TCP packets is not getting delivered to the sender of +the original packet. This is because the icmp packets are skipped +from out_pre_lb/out_pre_acl logical switch egress pipeline and this +results in these icmp packets getting dropped in the ACL stage because +of invalid ct flags. This patch fixes this issue by removing those logical +flows. The IP checksum generated by ovn-controller is invalid. This patch +fixes this issue as well. + +Tested-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique + +(cherry-picked from upstream commit f792b1a00b439a949e3b7aae4951f8513340c1a1) + +Change-Id: I9837991cf0981f57dc92d1309f0f453c800d7937 +--- + controller/pinctrl.c | 102 ++++++++++++++++++++++++++++--------------- + northd/ovn-northd.c | 22 +++++----- + tests/ovn.at | 46 +++++++++---------- + tests/system-ovn.at | 95 ++++++++++++++++++++++++++++++++-------- + 4 files changed, 177 insertions(+), 88 deletions(-) + +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index f0d63b9a6..9d5b7c3c0 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -1465,7 +1465,7 @@ static void + pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow, + struct dp_packet *pkt_in, + const struct match *md, struct ofpbuf *userdata, +- bool include_orig_ip_datagram) ++ bool set_icmp_code) + { + /* This action only works for IP packets, and the switch should only send + * us IP packets this way, but check here just to be sure. */ +@@ -1512,46 +1512,51 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow, + packet_set_ipv4(&packet, ip_flow->nw_src, ip_flow->nw_dst, + ip_flow->nw_tos, 255); + ++ uint8_t icmp_code = 1; ++ if (set_icmp_code && in_ip->ip_proto == IPPROTO_UDP) { ++ icmp_code = 3; ++ } ++ + struct icmp_header *ih = dp_packet_put_zeros(&packet, sizeof *ih); + dp_packet_set_l4(&packet, ih); +- packet_set_icmp(&packet, ICMP4_DST_UNREACH, 1); +- +- if (include_orig_ip_datagram) { +- /* RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes +- * of header. MAY send more. +- * RFC says return as much as we can without exceeding 576 +- * bytes. +- * So, lets return as much as we can. */ +- +- /* Calculate available room to include the original IP + data. */ +- nh = dp_packet_l3(&packet); +- uint16_t room = 576 - (sizeof *eh + ntohs(nh->ip_tot_len)); +- if (in_ip_len > room) { +- in_ip_len = room; +- } +- dp_packet_put(&packet, in_ip, in_ip_len); +- +- /* dp_packet_put may reallocate the buffer. Get the l3 and l4 +- * header pointers again. */ +- nh = dp_packet_l3(&packet); +- ih = dp_packet_l4(&packet); +- uint16_t ip_total_len = ntohs(nh->ip_tot_len) + in_ip_len; +- nh->ip_tot_len = htons(ip_total_len); +- ih->icmp_csum = 0; +- ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len); +- nh->ip_csum = 0; +- nh->ip_csum = csum(nh, sizeof *nh); +- } ++ packet_set_icmp(&packet, ICMP4_DST_UNREACH, icmp_code); ++ ++ /* RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes ++ * of header. MAY send more. ++ * RFC says return as much as we can without exceeding 576 ++ * bytes. ++ * So, lets return as much as we can. */ ++ ++ /* Calculate available room to include the original IP + data. */ ++ nh = dp_packet_l3(&packet); ++ uint16_t room = 576 - (sizeof *eh + ntohs(nh->ip_tot_len)); ++ if (in_ip_len > room) { ++ in_ip_len = room; ++ } ++ dp_packet_put(&packet, in_ip, in_ip_len); ++ ++ /* dp_packet_put may reallocate the buffer. Get the l3 and l4 ++ * header pointers again. */ ++ nh = dp_packet_l3(&packet); ++ ih = dp_packet_l4(&packet); ++ uint16_t ip_total_len = ntohs(nh->ip_tot_len) + in_ip_len; ++ nh->ip_tot_len = htons(ip_total_len); ++ ih->icmp_csum = 0; ++ ih->icmp_csum = csum(ih, sizeof *ih + in_ip_len); ++ nh->ip_csum = 0; ++ nh->ip_csum = csum(nh, sizeof *nh); ++ + } else { + struct ip6_hdr *nh = dp_packet_put_zeros(&packet, sizeof *nh); + struct icmp6_data_header *ih; + uint32_t icmpv6_csum; ++ struct ip6_hdr *in_ip = dp_packet_l3(pkt_in); + + eh->eth_type = htons(ETH_TYPE_IPV6); + dp_packet_set_l3(&packet, nh); + nh->ip6_vfc = 0x60; + nh->ip6_nxt = IPPROTO_ICMPV6; +- nh->ip6_plen = htons(sizeof(*nh) + ICMP6_DATA_HEADER_LEN); ++ nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN); + packet_set_ipv6(&packet, &ip_flow->ipv6_src, &ip_flow->ipv6_dst, + ip_flow->nw_tos, ip_flow->ipv6_label, 255); + +@@ -1559,15 +1564,42 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow, + dp_packet_set_l4(&packet, ih); + ih->icmp6_base.icmp6_type = ICMP6_DST_UNREACH; + ih->icmp6_base.icmp6_code = 1; ++ ++ if (set_icmp_code && in_ip->ip6_nxt == IPPROTO_UDP) { ++ ih->icmp6_base.icmp6_code = ICMP6_DST_UNREACH_NOPORT; ++ } + ih->icmp6_base.icmp6_cksum = 0; + +- uint8_t *data = dp_packet_put_zeros(&packet, sizeof *nh); +- memcpy(data, dp_packet_l3(pkt_in), sizeof(*nh)); ++ nh = dp_packet_l3(&packet); ++ ++ /* RFC 4443: 3.1. ++ * ++ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Type | Code | Checksum | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Unused | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | As much of invoking packet | ++ * + as possible without the ICMPv6 packet + ++ * | exceeding the minimum IPv6 MTU [IPv6] | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ */ ++ ++ uint16_t room = 1280 - (sizeof *eh + sizeof *nh + ++ ICMP6_DATA_HEADER_LEN); ++ uint16_t in_ip_len = (uint16_t) sizeof *in_ip + ntohs(in_ip->ip6_plen); ++ if (in_ip_len > room) { ++ in_ip_len = room; ++ } ++ ++ dp_packet_put(&packet, in_ip, in_ip_len); ++ nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN + in_ip_len); + + icmpv6_csum = packet_csum_pseudoheader6(dp_packet_l3(&packet)); + ih->icmp6_base.icmp6_cksum = csum_finish( + csum_continue(icmpv6_csum, ih, +- sizeof(*nh) + ICMP6_DATA_HEADER_LEN)); ++ in_ip_len + ICMP6_DATA_HEADER_LEN)); + } + + if (ip_flow->vlans[0].tci & htons(VLAN_CFI)) { +@@ -2658,12 +2690,12 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg) + + case ACTION_OPCODE_ICMP: + pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata, +- &userdata, false); ++ &userdata, true); + break; + + case ACTION_OPCODE_ICMP4_ERROR: + pinctrl_handle_icmp(swconn, &headers, &packet, &pin.flow_metadata, +- &userdata, true); ++ &userdata, false); + break; + + case ACTION_OPCODE_TCP_RESET: +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 4efe4a0c3..ec77ae1a8 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -4736,12 +4736,10 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) + * Not to do conntrack on ND and ICMP destination + * unreachable packets. */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, +- "nd || nd_rs || nd_ra || icmp4.type == 3 || " +- "icmp6.type == 1 || " ++ "nd || nd_rs || nd_ra || " + "(udp && udp.src == 546 && udp.dst == 547)", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, +- "nd || nd_rs || nd_ra || icmp4.type == 3 || " +- "icmp6.type == 1 || " ++ "nd || nd_rs || nd_ra || " + "(udp && udp.src == 546 && udp.dst == 547)", "next;"); + + /* Ingress and Egress Pre-ACL Table (Priority 100). +@@ -4853,12 +4851,10 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows, + { + /* Do not send ND packets to conntrack */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, +- "nd || nd_rs || nd_ra || icmp4.type == 3 ||" +- "icmp6.type == 1", ++ "nd || nd_rs || nd_ra", + "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, +- "nd || nd_rs || nd_ra || icmp4.type == 3 ||" +- "icmp6.type == 1", ++ "nd || nd_rs || nd_ra", + "next;"); + + /* Do not send service monitor packets to conntrack. */ +@@ -5037,9 +5033,10 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, + ds_put_format(&actions, "%s ", extra_actions->string); + } + ds_put_format(&actions, "reg0 = 0; " +- "eth.dst <-> eth.src; ip4.dst <-> ip4.src; " +- "icmp4 { outport <-> inport; %s };", +- ingress ? "output;" : "next(pipeline=ingress,table=0);"); ++ "icmp4 { eth.dst <-> eth.src; ip4.dst <-> ip4.src; " ++ "outport <-> inport; %s };", ++ ingress ? "next(pipeline=egress,table=5);" ++ : "next(pipeline=ingress,table=19);"); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET, + ds_cstr(&match), ds_cstr(&actions), stage_hint); +@@ -5056,7 +5053,8 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, + ds_put_format(&actions, "reg0 = 0; icmp6 { " + "eth.dst <-> eth.src; ip6.dst <-> ip6.src; " + "outport <-> inport; %s };", +- ingress ? "output;" : "next(pipeline=ingress,table=0);"); ++ ingress ? "next(pipeline=egress,table=5);" ++ : "next(pipeline=ingress,table=19);"); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET, + ds_cstr(&match), ds_cstr(&actions), stage_hint); +diff --git a/tests/ovn.at b/tests/ovn.at +index defe00a40..35415f2b6 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -11737,13 +11737,13 @@ test_ip_packet() { + + local ip_ttl=ff + local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst} +- ++ local orig_pkt_in_reply=4500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst} + local reply_icmp_ttl=ff + local icmp_type_code_response=0301 + local icmp_data=00000000 + local reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data} +- local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ipv4_dst}${ipv4_src}${reply_icmp_payload} +- echo $reply >> vif$inport.expected ++ local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ipv4_dst}${ipv4_src}${reply_icmp_payload} ++ echo $reply$orig_pkt_in_reply >> vif$inport.expected + + as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet + } +@@ -11760,7 +11760,7 @@ test_ipv6_packet() { + local ip6_hdr=6000000000083aff${ipv6_src}${ipv6_dst} + local packet=${eth_dst}${eth_src}86dd${ip6_hdr}0000000000000000 + +- local reply=${eth_src}${eth_dst}86dd6000000000303aff${ipv6_dst}${ipv6_src}0101${exp_icmp_chksum}00000000${ip6_hdr} ++ local reply=${eth_src}${eth_dst}86dd6000000000383aff${ipv6_dst}${ipv6_src}0101${exp_icmp_chksum}00000000${ip6_hdr}0000000000000000 + echo $reply >> vif$inport.expected + + as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet +@@ -11838,11 +11838,11 @@ ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p21\"" reject + # Allow some time for ovn-northd and ovn-controller to catch up. + ovn-nbctl --timeout=3 --wait=hv sync + +-test_ip_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 7d8d fcfe +-test_ip_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 7d8d fcfe +-test_ip_packet 31 3 000000000031 000000000012 $(ip_to_hex 192 168 1 31) $(ip_to_hex 192 168 1 12) 0000 7d82 fcfe ++test_ip_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 f85b f576 ++test_ip_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 f85b f576 ++test_ip_packet 31 3 000000000031 000000000012 $(ip_to_hex 192 168 1 31) $(ip_to_hex 192 168 1 12) 0000 f850 f56b + +-test_ipv6_packet 11 1 000000000011 000000000021 fe80000000000000020001fffe000001 fe80000000000000020001fffe000002 6183 ++test_ipv6_packet 11 1 000000000011 000000000021 fe80000000000000020001fffe000001 fe80000000000000020001fffe000002 617b + + test_tcp_syn_packet 11 1 000000000011 000000000021 $(ip_to_hex 192 168 1 11) $(ip_to_hex 192 168 1 21) 0000 8b40 3039 0000 b85f 70e4 + test_tcp_syn_packet 21 2 000000000021 000000000011 $(ip_to_hex 192 168 1 21) $(ip_to_hex 192 168 1 11) 0000 8b40 3039 0000 b85f 70e4 +@@ -12795,13 +12795,13 @@ test_ip_packet() { + + local ip_ttl=01 + local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst} +- ++ local orig_pkt_in_reply=4500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst} + local reply_icmp_ttl=fe + local icmp_type_code_response=0b00 + local icmp_data=00000000 + local reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data} +- local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload} +- echo $reply >> vif$inport.expected ++ local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload} ++ echo $reply$orig_pkt_in_reply >> vif$inport.expected + + as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet + } +@@ -12819,7 +12819,7 @@ test_ip6_packet() { + local ip6_hdr=6000000000151101${ipv6_src}${ipv6_dst} + local packet=${eth_dst}${eth_src}86dd${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a + +- local reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr} ++ local reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a + echo $reply >> vif$inport.expected + + as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet +@@ -12861,8 +12861,8 @@ OVN_POPULATE_ARP + # allow some time for ovn-northd and ovn-controller to catch up. + ovn-nbctl --wait=hv sync + +-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 7dae f4ff +-test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 d461 ++test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 f87c ea96 ++test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 1c22 + OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected]) + + OVN_CLEANUP([hv1], [hv2]) +@@ -12891,12 +12891,12 @@ test_ip_packet() { + + local ip_ttl=ff + local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router} +- ++ local orig_pkt_in_reply=4500001400004000${ip_ttl}${l4_proto}${ip_chksum}${ipv4_src}${ip_router} + local reply_icmp_ttl=fe + local icmp_data=00000000 + local reply_icmp_payload=${exp_icmp_code}${exp_icmp_chksum}${icmp_data} +- local reply=${eth_src}${eth_dst}08004500001c00004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload} +- echo $reply >> vif$inport.expected ++ local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload} ++ echo $reply$orig_pkt_in_reply >> vif$inport.expected + + as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet + } +@@ -12962,7 +12962,9 @@ test_ip6_packet() { + local ip6_hdr=60000000${ipv6_len}${ipv6_proto}ff${ipv6_src}${ipv6_dst} + local packet=${eth_dst}${eth_src}86dd${ip6_hdr}${data} + +- local reply=${eth_src}${eth_dst}86dd6000000000303afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr} ++ local reply_ip_len=`expr 48 + ${#data} / 2` ++ reply_ip_len=$(printf "%x" $reply_ip_len) ++ local reply=${eth_src}${eth_dst}86dd6000000000${reply_ip_len}3afe${ipv6_dst}${ipv6_src}${exp_icmp_code}${exp_icmp_chksum}00000000${ip6_hdr}${data} + echo $reply >> vif$inport.expected + + as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet +@@ -13004,13 +13006,13 @@ OVN_POPULATE_ARP + # allow some time for ovn-northd and ovn-controller to catch up. + ovn-nbctl --wait=hv sync + +-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 11 0000 7dae fcfc 0303 +-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 84 0000 7dae fcfd 0302 +-test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015 dbb8303900155bac6b646f65206676676e6d66720a 0104 d570 ++test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 11 0000 f87c f485 0303 ++test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 1 254) 84 0000 f87c f413 0302 ++test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000100000000000000000001 11 0015 dbb8303900155bac6b646f65206676676e6d66720a 0104 1d31 + OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected]) + + test_tcp_syn_packet 2 2 000000000002 00000000ff02 $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 2 254) 0000 8b40 3039 0000 b680 6e05 +-test_ip6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004 01020304 0103 627e ++test_ip6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 84 0004 01020304 0103 5e74 + test_tcp6_packet 2 2 000000000002 00000000ff02 20010db8000200000000000000000011 20010db8000200000000000000000001 8b40 3039 0000 98cd + OVN_CHECK_PACKETS([hv2/vif2-tx.pcap], [vif2.expected]) + +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index fa3b83cb1..117f1e835 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -3697,7 +3697,7 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d + AT_CLEANUP + + +-AT_SETUP([ovn -- ACL reject - TCP reset]) ++AT_SETUP([ovn -- ACL reject]) + AT_SKIP_IF([test $HAVE_NC = no]) + AT_KEYWORDS([lb]) + +@@ -3736,13 +3736,14 @@ ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop + ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop + + ovn-nbctl pg-add pg0 sw0-p1-rej sw0-p2-rej +-ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related ++ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip" allow-related + ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 80" reject ++ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip && udp && udp.dst == 90" reject + +-ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related + ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 82" allow-related + ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 82" allow-related + ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 84" reject ++ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && udp && udp.dst == 94" reject + + OVN_POPULATE_ARP + ovn-nbctl --wait=hv sync +@@ -3758,33 +3759,38 @@ ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \ + NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0]) + NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0]) + +-# Capture packets in sw0-p1-rej. +-NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 2 -i sw0-p1-rej tcp port 80 > sw0-p1-rej-ip4.pcap &], [0]) + sleep 1 + +-NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 80], [1], [], +-[dnl +-Ncat: Connection refused. +-]) ++# Capture packets in sw0-p1-rej. ++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 4 -i sw0-p1-rej tcp > sw0-p1-rej-ip4.pcap &], [0]) ++ ++sleep 1 + + OVS_WAIT_UNTIL([ +- total=`cat sw0-p1-rej-ip4.pcap | wc -l` +- echo "total = $total" +- test "${total}" = "2" ++ ip netns exec sw0-p1-rej nc 10.0.0.4 80 2> r ++ res=$(cat r) ++ test "$res" = "Ncat: Connection refused." + ]) + + # Now send traffic to port 84 +-NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 84], [1], [], +-[dnl +-Ncat: Connection refused. ++OVS_WAIT_UNTIL([ ++ ip netns exec sw0-p1-rej nc 10.0.0.4 84 2> r ++ res=$(cat r) ++ test "$res" = "Ncat: Connection refused." + ]) + +-AT_CHECK([ ++OVS_WAIT_UNTIL([ + n_pkt=$(ovs-ofctl dump-flows br-int table=44 | grep -v n_packets=0 | \ + grep controller | grep tp_dst=84 -c) + test $n_pkt -eq 1 + ]) + ++OVS_WAIT_UNTIL([ ++ total=`cat sw0-p1-rej-ip4.pcap | wc -l` ++ echo "total = $total" ++ test "${total}" = "4" ++]) ++ + # Without this sleep, test case fails intermittently. + sleep 3 + +@@ -3792,17 +3798,68 @@ NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 2 -i sw0-p2-rej tcp port 80 > sw0-p2- + + sleep 1 + +-NS_CHECK_EXEC([sw0-p2-rej], [nc -6 aef0::3 80], [1], [], +-[dnl +-Ncat: Connection refused. ++OVS_WAIT_UNTIL([ ++ ip netns exec sw0-p2-rej nc -6 aef0::3 80 2> r ++ res=$(cat r) ++ test "$res" = "Ncat: Connection refused." + ]) + ++ + OVS_WAIT_UNTIL([ + total=`cat sw0-p2-rej-ip6.pcap | wc -l` + echo "total = $total" + test "${total}" = "2" + ]) + ++# Now test for IPv4 UDP. ++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 90 > sw0-p1-rej-udp.pcap &], [0]) ++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0]) ++ ++echo "foo" > foo ++OVS_WAIT_UNTIL([ ++ ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo ++ c=$(cat sw0-p1-rej-icmp.pcap | grep \ ++"10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port dnsix unreachable" | uniq | wc -l) ++ test $c -eq 1 ++]) ++ ++rm -f *.pcap ++ ++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 94 > sw0-p1-rej-udp.pcap &], [0]) ++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0]) ++ ++OVS_WAIT_UNTIL([ ++ ip netns exec sw0-p1-rej nc -u 10.0.0.4 94 < foo ++ c=$(cat sw0-p1-rej-icmp.pcap | grep \ ++"10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port objcall unreachable" | uniq | wc -l) ++ test $c -eq 1 ++]) ++ ++# Now test for IPv6 UDP. ++NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej udp port 90 > sw0-p2-rej-ip6-udp.pcap &], [0]) ++NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0]) ++ ++OVS_WAIT_UNTIL([ ++ ip netns exec sw0-p2-rej nc -u -6 aef0::3 90 < foo ++ c=$(cat sw0-p2-rej-icmp6.pcap | grep \ ++"IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \ ++aef0::3 udp port dnsix" | uniq | wc -l) ++ test $c -eq 1 ++]) ++ ++rm -f *.pcap ++ ++NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej udp port 94 > sw0-p2-rej-ip6-udp.pcap &], [0]) ++NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 1 -i sw0-p2-rej icmp6 > sw0-p2-rej-icmp6.pcap &], [0]) ++ ++OVS_WAIT_UNTIL([ ++ ip netns exec sw0-p2-rej nc -u -6 aef0::3 94 < foo ++ c=$(cat sw0-p2-rej-icmp6.pcap | grep \ ++"IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \ ++aef0::3 udp port objcall" | uniq | wc -l) ++ test $c -eq 1 ++]) ++ + OVS_APP_EXIT_AND_WAIT([ovn-controller]) + + as ovn-sb +-- +2.26.2 + diff --git a/SOURCES/0001-Fix-conntrack-entry-leaks-because-of-TCP-RST-packets.patch b/SOURCES/0001-Fix-conntrack-entry-leaks-because-of-TCP-RST-packets.patch new file mode 100644 index 0000000..2ec0cb6 --- /dev/null +++ b/SOURCES/0001-Fix-conntrack-entry-leaks-because-of-TCP-RST-packets.patch @@ -0,0 +1,473 @@ +From 685c685b0070731524869459f96b7b690e12ae74 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Thu, 23 Apr 2020 18:08:48 +0530 +Subject: [PATCH] Fix conntrack entry leaks because of TCP RST packets not sent + to conntrack. + +The commit [1] - 28097d5adb95("Fix tcp_reset action handling") fixed an issue +with tcp_reset OVN action. In order to fix that issue, this commit added +logical flows to skip all the TCP RST packets from conntrack. +Ideally it should have skipped only the TCP RST packets generated by +ovn-controller from conntrack. Since all the TCP RST packets are +skipped from conntrack, the connections in conntrack remain in +ESTABLISHED state even if the client/server sends TCP RST to close the +connection. And these entries live for a long time and this is +causing performance issues as reported in the BZ. + +This patch reverts the logical flows added in [1] and modifies the inner +actions of tcp_reset in the ingress logical switch pipeline +from - "tcp_reset { outport <-> inport; output; }" +to "tcp_reset { output <-> inport; next(pipeline=egress,table=5); }". +This causes the packet to resubmit to the egress table ls_out_qos_mark +skipping the egress ACL stage. Prior to this packet, next action was +not allowing a resubmit from ingress to egress pipeline. This patch +relaxes this limitation. + +For the tcp_reset action in the egress logical switch pipeline, this patch +modifies the inner action +from - "tcp_reset { outport <-> inport; next(pipeline=ingress,table=0); }" +to - "tcp_reset { outport <-> inport; next(pipeline=ingress,table=19); }". +This causes the packet to enter the ingress table ls_in_l2_lkup. + +We don't see similar conntrack leaks with UDP. Although there is an issue +with the acl reject action for UDP packets. When ovn-controller generates icmp +destination unreachable packet, it doesn't get delivered. And the IP checksum is +incorrect in this packet. A follow up patch will fix these issues. + +[1] - 28097d5adb95("Fix tcp_reset action handling") + +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1819785 +Co-Authored-by: Tim Rozet +Signed-off-by: Tim Rozet +Acked-by: Dumitru Ceara +Acked-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique +--- + AUTHORS.rst | 1 + + lib/actions.c | 6 +- + northd/ovn-northd.8.xml | 8 ++ + northd/ovn-northd.c | 14 ++-- + ovn-sb.xml | 10 ++- + tests/automake.mk | 3 +- + tests/ovn.at | 6 +- + tests/system-ovn.at | 170 +++++++++++++++++++++++++++++++++++----- + tests/test-tcp-rst.py | 37 +++++++++ + 9 files changed, 217 insertions(+), 38 deletions(-) + create mode 100644 tests/test-tcp-rst.py + +diff --git a/AUTHORS.rst b/AUTHORS.rst +index 230e487f0..c80fc1bae 100644 +--- a/AUTHORS.rst ++++ b/AUTHORS.rst +@@ -355,6 +355,7 @@ Thomas F. Herbert thomasfherbert@gmail.com + Thomas Goirand zigo@debian.org + Thomas Graf tgraf@noironetworks.com + Thomas Lacroix thomas.lacroix@citrix.com ++Tim Rozet trozet@redhat.com + Timo Puha timox.puha@intel.com + Timothy Redaelli tredaelli@redhat.com + Todd Deshane deshantm@gmail.com +diff --git a/lib/actions.c b/lib/actions.c +index 02141af30..41a742064 100644 +--- a/lib/actions.c ++++ b/lib/actions.c +@@ -319,11 +319,7 @@ parse_NEXT(struct action_context *ctx) + } + } + +- if (pipeline == OVNACT_P_EGRESS && ctx->pp->pipeline == OVNACT_P_INGRESS) { +- lexer_error(ctx->lexer, +- "\"next\" action cannot advance from ingress to egress " +- "pipeline (use \"output\" action instead)"); +- } else if (table >= ctx->pp->n_tables) { ++ if (table >= ctx->pp->n_tables) { + lexer_error(ctx->lexer, + "\"next\" action cannot advance beyond table %d.", + ctx->pp->n_tables - 1); +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index efcc4b7fc..d39e259f6 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -373,6 +373,14 @@ + for new connections and reg0[1] = 1; next; for existing + connections. + ++
  • ++ reject ACLs translate into logical ++ flows with the ++ tcp_reset { output <-> inport; ++ next(pipeline=egress,table=5);} ++ action for TCP connections and icmp4/icmp6 action ++ for UDP connections. ++
  • +
  • + Other ACLs translate to drop; for new or untracked + connections and ct_commit(ct_label=1/1); for known +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index d3d481ab8..0082e2e8b 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -4717,11 +4717,11 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) + * unreachable packets. */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, + "nd || nd_rs || nd_ra || icmp4.type == 3 || " +- "icmp6.type == 1 || (tcp && tcp.flags == 20) || " ++ "icmp6.type == 1 || " + "(udp && udp.src == 546 && udp.dst == 547)", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, + "nd || nd_rs || nd_ra || icmp4.type == 3 || " +- "icmp6.type == 1 || (tcp && tcp.flags == 20) ||" ++ "icmp6.type == 1 || " + "(udp && udp.src == 546 && udp.dst == 547)", "next;"); + + /* Ingress and Egress Pre-ACL Table (Priority 100). +@@ -4834,11 +4834,11 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows, + /* Do not send ND packets to conntrack */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, + "nd || nd_rs || nd_ra || icmp4.type == 3 ||" +- "icmp6.type == 1 || (tcp && tcp.flags == 20)", ++ "icmp6.type == 1", + "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, + "nd || nd_rs || nd_ra || icmp4.type == 3 ||" +- "icmp6.type == 1 || (tcp && tcp.flags == 20)", ++ "icmp6.type == 1", + "next;"); + + /* Do not send service monitor packets to conntrack. */ +@@ -4984,7 +4984,8 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, + ds_put_format(&actions, "reg0 = 0; " + "eth.dst <-> eth.src; ip4.dst <-> ip4.src; " + "tcp_reset { outport <-> inport; %s };", +- ingress ? "output;" : "next(pipeline=ingress,table=0);"); ++ ingress ? "next(pipeline=egress,table=5);" ++ : "next(pipeline=ingress,table=19);"); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET + 10, + ds_cstr(&match), ds_cstr(&actions), stage_hint); +@@ -4998,7 +4999,8 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, + ds_put_format(&actions, "reg0 = 0; " + "eth.dst <-> eth.src; ip6.dst <-> ip6.src; " + "tcp_reset { outport <-> inport; %s };", +- ingress ? "output;" : "next(pipeline=ingress,table=0);"); ++ ingress ? "next(pipeline=egress,table=5);" ++ : "next(pipeline=ingress,table=19);"); + ovn_lflow_add_with_hint(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET + 10, + ds_cstr(&match), ds_cstr(&actions), stage_hint); +diff --git a/ovn-sb.xml b/ovn-sb.xml +index 5f8da534c..3aa7cd4da 100644 +--- a/ovn-sb.xml ++++ b/ovn-sb.xml +@@ -1112,10 +1112,12 @@ + pipeline as a subroutine. The default table is + just after the current one. If pipeline is specified, it + may be ingress or egress; the default +- pipeline is the one currently executing. Actions in the +- ingress pipeline may not use next to jump into the +- egress pipeline (use the output instead), but +- transitions in the opposite direction are allowed. ++ pipeline is the one currently executing. Actions in the ++ both ingress and egress pipeline can use next to jump ++ across the other pipeline. Actions in the ingress pipeline should ++ use next to jump into the specific table of egress ++ pipeline only if it is certain that the packets are local and not ++ tunnelled and wants to skip certain stages in the packet processing. + + +
    field = constant;
    +diff --git a/tests/automake.mk b/tests/automake.mk +index 215fb432b..ed530dd77 100644 +--- a/tests/automake.mk ++++ b/tests/automake.mk +@@ -205,7 +205,8 @@ tests_ovstest_LDADD = $(OVS_LIBDIR)/libopenvswitch.la lib/libovn.la + # Python tests. + CHECK_PYFILES = \ + tests/test-l7.py \ +- tests/uuidfilt.py ++ tests/uuidfilt.py \ ++ tests/test-tcp-rst.py + + EXTRA_DIST += $(CHECK_PYFILES) + PYCOV_CLEAN_FILES += $(CHECK_PYFILES:.py=.py,cover) .coverage +diff --git a/tests/ovn.at b/tests/ovn.at +index b78637044..6da975554 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -850,7 +850,11 @@ next(pipeline=ingress, table=11); + encodes as resubmit(,19) + + next(pipeline=egress); +- "next" action cannot advance from ingress to egress pipeline (use "output" action instead) ++ formats as next(pipeline=egress, table=11); ++ encodes as resubmit(,51) ++ ++next(pipeline=egress, table=5); ++ encodes as resubmit(,45) + + next(table=10); + formats as next(10); +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index bdb9768d2..3b11cf92b 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -3719,60 +3719,86 @@ start_daemon ovn-controller + + ovn-nbctl ls-add sw0 + +-ovn-nbctl lsp-add sw0 sw0-p1 +-ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3 aef0::3" +-ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3 aef0::3" ++ovn-nbctl lsp-add sw0 sw0-p1-rej ++ovn-nbctl lsp-set-addresses sw0-p1-rej "50:54:00:00:00:03 10.0.0.3 aef0::3" ++ovn-nbctl lsp-set-port-security sw0-p1-rej "50:54:00:00:00:03 10.0.0.3 aef0::3" + +-ovn-nbctl lsp-add sw0 sw0-p2 +-ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4 aef0::4" +-ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4 aef0::4" ++ovn-nbctl lsp-add sw0 sw0-p2-rej ++ovn-nbctl lsp-set-addresses sw0-p2-rej "50:54:00:00:00:04 10.0.0.4 aef0::4" ++ovn-nbctl lsp-set-port-security sw0-p2-rej "50:54:00:00:00:04 10.0.0.4 aef0::4" ++ ++#ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p1\" && tcp && tcp.dst == 80" reject ++#ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p2\" && ip6 && tcp && tcp.dst == 80" reject ++ ++# Create port group and ACLs for sw0 ports. ++ovn-nbctl pg-add pg0_drop sw0-p1-rej sw0-p2-rej ++ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop ++ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop ++ ++ovn-nbctl pg-add pg0 sw0-p1-rej sw0-p2-rej ++ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related ++ovn-nbctl --log acl-add pg0 from-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 80" reject + +-ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p1\" && tcp && tcp.dst == 80" reject +-ovn-nbctl --log acl-add sw0 from-lport 1000 "inport == \"sw0-p2\" && ip6 && tcp && tcp.dst == 80" reject ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 82" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 82" allow-related ++ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 84" reject + + OVN_POPULATE_ARP + ovn-nbctl --wait=hv sync + +-ADD_NAMESPACES(sw0-p1) +-ADD_VETH(sw0-p1, sw0-p1, br-int, "10.0.0.3/24", "50:54:00:00:00:03", \ ++ADD_NAMESPACES(sw0-p1-rej) ++ADD_VETH(sw0-p1-rej, sw0-p1-rej, br-int, "10.0.0.3/24", "50:54:00:00:00:03", \ + "10.0.0.1") + +-ADD_NAMESPACES(sw0-p2) +-ADD_VETH(sw0-p2, sw0-p2, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \ ++ADD_NAMESPACES(sw0-p2-rej) ++ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \ + "10.0.0.1") + +-NS_CHECK_EXEC([sw0-p1], [ip a a aef0::3/64 dev sw0-p1], [0]) +-NS_CHECK_EXEC([sw0-p2], [ip a a aef0::4/64 dev sw0-p2], [0]) ++NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0]) ++NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0]) + +-# Capture packets in sw0-p1. +-NS_CHECK_EXEC([sw0-p1], [tcpdump -n -c 2 -i sw0-p1 tcp port 80 > sw0-p1-ip4.pcap &], [0]) ++# Capture packets in sw0-p1-rej. ++NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 2 -i sw0-p1-rej tcp port 80 > sw0-p1-rej-ip4.pcap &], [0]) + sleep 1 + +-NS_CHECK_EXEC([sw0-p1], [nc 10.0.0.4 80], [1], [], ++NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 80], [1], [], + [dnl + Ncat: Connection refused. + ]) + + OVS_WAIT_UNTIL([ +- total=`cat sw0-p1-ip4.pcap | wc -l` ++ total=`cat sw0-p1-rej-ip4.pcap | wc -l` + echo "total = $total" + test "${total}" = "2" + ]) + ++# Now send traffic to port 84 ++NS_CHECK_EXEC([sw0-p1-rej], [nc 10.0.0.4 84], [1], [], ++[dnl ++Ncat: Connection refused. ++]) ++ ++AT_CHECK([ ++ n_pkt=$(ovs-ofctl dump-flows br-int table=44 | grep -v n_packets=0 | \ ++grep controller | grep tp_dst=84 -c) ++ test $n_pkt -eq 1 ++]) ++ + # Without this sleep, test case fails intermittently. + sleep 3 + +-NS_CHECK_EXEC([sw0-p2], [tcpdump -n -c 2 -i sw0-p2 tcp port 80 > sw0-p2-ip6.pcap &], [0]) ++NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -n -c 2 -i sw0-p2-rej tcp port 80 > sw0-p2-rej-ip6.pcap &], [0]) + + sleep 1 + +-NS_CHECK_EXEC([sw0-p2], [nc -6 aef0::3 80], [1], [], ++NS_CHECK_EXEC([sw0-p2-rej], [nc -6 aef0::3 80], [1], [], + [dnl + Ncat: Connection refused. + ]) + + OVS_WAIT_UNTIL([ +- total=`cat sw0-p2-ip6.pcap | wc -l` ++ total=`cat sw0-p2-rej-ip6.pcap | wc -l` + echo "total = $total" + test "${total}" = "2" + ]) +@@ -3936,3 +3962,105 @@ as + OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d + /.*terminating with signal 15.*/d"]) + AT_CLEANUP ++ ++# Tests that when an established connection sends TCP reset, ++# the conntrack entry is not in established state. ++AT_SETUP([ovn -- conntrack TCP reset]) ++AT_KEYWORDS([conntrack]) ++ovn_start ++ ++OVS_TRAFFIC_VSWITCHD_START() ++ADD_BR([br-int]) ++ ++# Set external-ids in br-int needed for ovn-controller ++ovs-vsctl \ ++ -- set Open_vSwitch . external-ids:system-id=hv1 \ ++ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ ++ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ ++ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ ++ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true ++ ++# Start ovn-controller ++start_daemon ovn-controller ++ ++ovn-nbctl ls-add sw0 ++ ++ovn-nbctl lsp-add sw0 rst-p1 ++ovn-nbctl lsp-set-addresses rst-p1 "50:54:00:00:00:03" ++ovn-nbctl lsp-set-port-security rst-p1 "50:54:00:00:00:03" ++ ++ovn-nbctl lsp-add sw0 rst-p2 ++ovn-nbctl lsp-set-addresses rst-p2 "50:54:00:00:00:04 10.0.0.4" ++ovn-nbctl lsp-set-port-security rst-p2 "50:54:00:00:00:04 10.0.0.4" ++ ++# Create port group and ACLs for sw0 ports. ++ovn-nbctl pg-add pg0_drop rst-p1 rst-p2 ++ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop ++ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop ++ ++ovn-nbctl pg-add pg0 rst-p1 rst-p2 ++ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 80" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 80" allow-related ++ ++# Create a logical router and attach to logical switch. ++ovn-nbctl lr-add lr0 ++ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 ++ovn-nbctl lsp-add sw0 sw0-lr0 ++ovn-nbctl lsp-set-type sw0-lr0 router ++ovn-nbctl lsp-set-addresses sw0-lr0 router ++ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 ++ ++ovn-nbctl lb-add lb1 10.0.0.10:80 10.0.0.3:80 ++ovn-nbctl --wait=sb ls-lb-add sw0 lb1 ++ovn-nbctl --wait=sb lr-lb-add lr0 lb1 ++ ++OVN_POPULATE_ARP ++ovn-nbctl --wait=hv sync ++ ++ADD_NAMESPACES(rst-p1) ++ADD_VETH(rst-p1, rst-p1, br-int, "10.0.0.3/24", "50:54:00:00:00:03", \ ++ "10.0.0.1") ++ ++ADD_NAMESPACES(rst-p2) ++ADD_VETH(rst-p2, rst-p2, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \ ++ "10.0.0.1") ++ ++OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up rst-p1) = xup]) ++OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up rst-p2) = xup]) ++ ++# Start webservers in 'rst-p1'. ++OVS_START_L7([rst-p1], [http]) ++ ++NS_CHECK_EXEC([rst-p2], [$PYTHON $srcdir/test-tcp-rst.py --dst-port 80 --dst-ip 10.0.0.10]) ++ ++# When tcp reset is sent, conntrack entry should be in the state - CLOSED or CLOSING. ++# But there is a bug where tcp reset packet was not sent to the conntrack. ++# This test case checks that the tcp reset packet is sent to conntrack ++# and the state is not in established state. ++AT_CHECK([ ++ ct_est_count=$(ovs-appctl dpctl/dump-conntrack | grep 10.0.0.10 | grep state=ESTABLISHED -c) ++ test $ct_est_count -eq 0 ++ ++ ct_est_count=$(ovs-appctl dpctl/dump-conntrack | grep 10.0.0.10 | grep state=CLOS -c) ++ test $ct_est_count -eq 1 ++]) ++ ++OVS_APP_EXIT_AND_WAIT([ovn-controller]) ++ ++as ovn-sb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as ovn-nb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as northd ++OVS_APP_EXIT_AND_WAIT([ovn-northd]) ++ ++as ++OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d ++/connection dropped.*/d ++/Service monitor not found.*/d"]) ++ ++AT_CLEANUP +diff --git a/tests/test-tcp-rst.py b/tests/test-tcp-rst.py +new file mode 100644 +index 000000000..6f96c5706 +--- /dev/null ++++ b/tests/test-tcp-rst.py +@@ -0,0 +1,37 @@ ++#!/usr/bin/env python3 ++# Copyright (c) 2020 Red Hat, Inc. ++# ++# Licensed under the Apache License, Version 2.0 (the "License"); ++# you may not use this file except in compliance with the License. ++# You may obtain a copy of the License at: ++# ++# http://www.apache.org/licenses/LICENSE-2.0 ++# ++# Unless required by applicable law or agreed to in writing, software ++# distributed under the License is distributed on an "AS IS" BASIS, ++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++# See the License for the specific language governing permissions and ++# limitations under the License. ++ ++# Simple python script which connects to tcp server and then ++# resets the connection. ++import argparse ++import socket ++import sys ++import struct ++import time ++ ++parser = argparse.ArgumentParser(description='') ++parser.add_argument("--src-port", type=int, default=11337, help="source port to use") ++parser.add_argument("--dst-port", type=int, help="dst port to use") ++parser.add_argument("--dst-ip", help="server ip to use") ++args = parser.parse_args() ++sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ++server_address = (args.dst_ip, args.dst_port) ++sock.bind(('0.0.0.0', args.src_port)) ++sock.connect(server_address) ++l_onoff = 1 ++l_linger = 0 ++time.sleep(1) ++sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', l_onoff, l_linger)) ++sock.close() +-- +2.25.1 + diff --git a/SOURCES/0001-Fix-ovn-controller-generated-packets-from-getting-dr.patch b/SOURCES/0001-Fix-ovn-controller-generated-packets-from-getting-dr.patch new file mode 100644 index 0000000..1aadd22 --- /dev/null +++ b/SOURCES/0001-Fix-ovn-controller-generated-packets-from-getting-dr.patch @@ -0,0 +1,152 @@ +From 14f9bf6ba4bfa459f2e924dbf273a6337aab4107 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Sun, 14 Jun 2020 18:40:07 +0530 +Subject: [PATCH 1/3] Fix ovn-controller generated packets from getting dropped + for reject ACL action. + +TCP reset/ICMP packet generated by ovn-controller for the ACL reject action +gets dropped by ovs-vswithd with the below messages in ovs-vswitchd log +even though ovn-controller sets the in_port as OFPP_CONTROLLER. + +---- +ofproto_dpif_upcall(handler1)|INFO|received packet on unassociated datapath port 4294967295 +ofproto_dpif_upcall(revalidator37)|WARN|Failed to acquire udpif_key corresponding to +unexpected flow (Invalid argument): ufid:0daac824-bda7-44d8-ad38-cdd9c5f0fc97 +---- + +ovs-vswitchd drops the packet because the in_port is 0. + +The below OF flow sets the in_port to 0 if 'MLF_ALLOW_LOOPBACK_BIT' is set in the REG0 +in table 64. + +priority=100,reg10=0x1/0x1,reg15=0x2,metadata=0x2 actions=push:NXM_OF_IN_PORT[],load:0->NXM_OF_IN_PORT[],resubmit(,65),pop:NXM_OF_IN_PORT[] + +This patch fixes this issue by setting the in_port to OFPP_NONE so that ovs-vswitchd +doesn't drop the packet. + +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1832176 +Acked-by: Mark Michelson +Signed-off-by: Numan Siddique + +(cherry-picked from upstream master commit cfa5478211318b686ad0981e7b0620f96edd7168) + +Change-Id: Ia8e134013c30a6865322083c8054fa45b57c9353 +--- + controller/physical.c | 18 ++++++++++++------ + tests/system-ovn.at | 32 ++++++++++++++++++++++++++++++++ + 2 files changed, 44 insertions(+), 6 deletions(-) + +diff --git a/controller/physical.c b/controller/physical.c +index 144aeb7bd..3c5bbe027 100644 +--- a/controller/physical.c ++++ b/controller/physical.c +@@ -765,12 +765,18 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key, + * - or if the destination is a nested container + * - or if "nested_container" flag is set and the destination is the + * parent port, +- * temporarily set the in_port to zero, resubmit to ++ * temporarily set the in_port to OFPP_NONE, resubmit to + * table 65 for logical-to-physical translation, then restore + * the port number. + * + * If 'parent_port_key' is set, then the 'port_key' represents a nested +- * container. */ ++ * container. ++ * ++ * Note:We can set in_port to 0 too. But if recirculation happens ++ * later (eg. clone action to enter peer pipeline and a subsequent ++ * ct action), ovs-vswitchd will drop the packet if the frozen metadata ++ * in_port is 0. ++ * */ + + bool nested_container = parent_port_key ? true: false; + match_init_catchall(&match); +@@ -783,7 +789,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key, + } + + put_stack(MFF_IN_PORT, ofpact_put_STACK_PUSH(ofpacts_p)); +- put_load(0, MFF_IN_PORT, 0, 16, ofpacts_p); ++ put_load(ofp_to_u16(OFPP_NONE), MFF_IN_PORT, 0, 16, ofpacts_p); + put_resubmit(OFTABLE_LOG_TO_PHY, ofpacts_p); + put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p)); + ofctrl_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100, 0, +@@ -792,8 +798,8 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key, + if (nested_container) { + /* It's a nested container and when the packet from the nested + * container is to be sent to the parent port, "nested_container" +- * flag will be set. We need to temporarily set the in_port to zero +- * as mentioned in the comment above. ++ * flag will be set. We need to temporarily set the in_port to ++ * OFPP_NONE as mentioned in the comment above. + * + * If a parent port has multiple child ports, then this if condition + * will be hit multiple times, but we want to add only one flow. +@@ -814,7 +820,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key, + MLF_NESTED_CONTAINER, MLF_NESTED_CONTAINER); + + put_stack(MFF_IN_PORT, ofpact_put_STACK_PUSH(ofpacts_p)); +- put_load(0, MFF_IN_PORT, 0, 16, ofpacts_p); ++ put_load(ofp_to_u16(OFPP_NONE), MFF_IN_PORT, 0, 16, ofpacts_p); + put_resubmit(OFTABLE_LOG_TO_PHY, ofpacts_p); + put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p)); + ofctrl_check_and_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100, 0, +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index 9dfe6a4ad..52f05f07e 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -3927,6 +3927,24 @@ ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0. + ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && tcp && tcp.dst == 84" reject + ovn-nbctl --log acl-add pg0 to-lport 1004 "inport == @pg0 && ip && udp && udp.dst == 94" reject + ++ovn-nbctl ls-add sw1 ++ovn-nbctl lsp-add sw1 sw1-p1-rej ++ovn-nbctl lsp-set-addresses sw1-p1-rej "40:54:00:00:00:03 20.0.0.3" ++ovn-nbctl lsp-set-port-security sw1-p1-rej "40:54:00:00:00:03 20.0.0.3" ++ ++ovn-nbctl lr-add lr0 ++ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 ++ovn-nbctl lsp-add sw0 sw0-lr0 ++ovn-nbctl lsp-set-type sw0-lr0 router ++ovn-nbctl lsp-set-addresses sw0-lr0 router ++ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 ++ ++ovn-nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 20.0.0.1/24 ++ovn-nbctl lsp-add sw1 sw1-lr0 ++ovn-nbctl lsp-set-type sw1-lr0 router ++ovn-nbctl lsp-set-addresses sw1-lr0 router ++ovn-nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1 ++ + OVN_POPULATE_ARP + ovn-nbctl --wait=hv sync + +@@ -3941,6 +3959,10 @@ ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \ + NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0]) + NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0]) + ++ADD_NAMESPACES(sw1-p1-rej) ++ADD_VETH(sw1-p1-rej, sw1-p1-rej, br-int, "20.0.0.3/24", "40:54:00:00:00:03", \ ++ "20.0.0.1") ++ + sleep 1 + + # Capture packets in sw0-p1-rej. +@@ -3993,6 +4015,16 @@ OVS_WAIT_UNTIL([ + test "${total}" = "2" + ]) + ++ovn-nbctl acl-add sw1 from-lport 1004 "ip" allow-related ++ovn-nbctl acl-add sw1 to-lport 1004 "ip" allow-related ++ovn-nbctl --log acl-add pg0 to-lport 1004 "outport == @pg0 && ip && tcp && tcp.dst == 84" reject ++ ++OVS_WAIT_UNTIL([ ++ ip netns exec sw1-p1-rej nc 10.0.0.4 84 2> r ++ res=$(cat r) ++ test "$res" = "Ncat: Connection refused." ++]) ++ + # Now test for IPv4 UDP. + NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 90 > sw0-p1-rej-udp.pcap &], [0]) + NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0]) +-- +2.26.2 + diff --git a/SOURCES/0001-IPv6-PD-assume-status-to-be-Success-if-not-present.patch b/SOURCES/0001-IPv6-PD-assume-status-to-be-Success-if-not-present.patch new file mode 100644 index 0000000..2ef8f34 --- /dev/null +++ b/SOURCES/0001-IPv6-PD-assume-status-to-be-Success-if-not-present.patch @@ -0,0 +1,36 @@ +From f3f604a41e44a17b1953ebd3d2162c1fc046f49f Mon Sep 17 00:00:00 2001 +Message-Id: +From: Lorenzo Bianconi +Date: Sat, 25 Apr 2020 12:18:12 +0200 +Subject: [PATCH] IPv6 PD: assume status to be Success if not present + +According to the RFC3315 (section 22.13. Status Code Option), +if status code option is not present in the delegation server +reply, it will be assumed to be Success. In this particular case, +do not stop IPv6 PD state machine + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique +--- + controller/pinctrl.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -835,12 +835,15 @@ pinctrl_parse_dhcpv6_reply(struct dp_pac + plife_time = ntohl(ia_hdr->plife_time); + vlife_time = ntohl(ia_hdr->vlife_time); + memcpy(&ipv6, &ia_hdr->ipv6, sizeof (struct in6_addr)); ++ status = true; + } + if (ntohs(in_opt->code) == DHCPV6_OPT_STATUS_CODE) { + struct dhcpv6_opt_status *status_hdr; + + status_hdr = (struct dhcpv6_opt_status *)in_opt; +- status = ntohs(status_hdr->status_code) == 0; ++ if (ntohs(status_hdr->status_code)) { ++ status = false; ++ } + } + size += sizeof *in_opt + ntohs(in_opt->len); + in_opt = (struct dhcpv6_opt_header *)(in_dhcpv6_data + size); diff --git a/SOURCES/0001-IPv6-PD-time-parameter-checks.patch b/SOURCES/0001-IPv6-PD-time-parameter-checks.patch new file mode 100644 index 0000000..1221fb8 --- /dev/null +++ b/SOURCES/0001-IPv6-PD-time-parameter-checks.patch @@ -0,0 +1,68 @@ +From 942f7b2b9e3acfc7b1d6ea5c48fc22171b14549a Mon Sep 17 00:00:00 2001 +Message-Id: <942f7b2b9e3acfc7b1d6ea5c48fc22171b14549a.1588586761.git.lorenzo.bianconi@redhat.com> +From: Lorenzo Bianconi +Date: Thu, 23 Apr 2020 18:25:20 +0200 +Subject: [PATCH] IPv6 PD: time parameter checks + +RFC3633 imposes the following constraints for IPv6 pd time parameters: + +Identity Association for Prefix Delegation Option: +-------------------------------------------------- +t1 must not be greater than t2 if both of them are greater than 0 + +IA_PD Prefix option: +-------------------- +preferred lifetime must not be greater than valid lifetime + +Add checks for previous constraints in ovn implementation + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique +--- + controller/pinctrl.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -653,6 +653,11 @@ pinctrl_parse_dhcpv6_advt(struct rconn * + case DHCPV6_OPT_IA_PD: { + struct dhcpv6_opt_ia_na *ia_na = (struct dhcpv6_opt_ia_na *)in_opt; + int orig_len = len, hdr_len = 0, size = sizeof *in_opt + 12; ++ uint32_t t1 = ntohl(ia_na->t1), t2 = ntohl(ia_na->t2); ++ ++ if (t1 > t2 && t2 > 0) { ++ goto out; ++ } + + aid = ntohl(ia_na->iaid); + memcpy(&data[len], in_opt, size); +@@ -667,6 +672,15 @@ pinctrl_parse_dhcpv6_advt(struct rconn * + } + + if (ntohs(in_opt->code) == DHCPV6_OPT_IA_PREFIX) { ++ struct dhcpv6_opt_ia_prefix *ia_hdr = ++ (struct dhcpv6_opt_ia_prefix *)in_opt; ++ uint32_t plife_time = ntohl(ia_hdr->plife_time); ++ uint32_t vlife_time = ntohl(ia_hdr->vlife_time); ++ ++ if (plife_time > vlife_time) { ++ goto out; ++ } ++ + memcpy(&data[len], in_opt, flen); + hdr_len += flen; + len += flen; +@@ -831,9 +845,12 @@ pinctrl_parse_dhcpv6_reply(struct dp_pac + struct dhcpv6_opt_ia_prefix *ia_hdr = + (struct dhcpv6_opt_ia_prefix *)(in_dhcpv6_data + size); + +- prefix_len = ia_hdr->plen; + plife_time = ntohl(ia_hdr->plife_time); + vlife_time = ntohl(ia_hdr->vlife_time); ++ if (plife_time > vlife_time) { ++ break; ++ } ++ prefix_len = ia_hdr->plen; + memcpy(&ipv6, &ia_hdr->ipv6, sizeof (struct in6_addr)); + status = true; + } diff --git a/SOURCES/0001-Make-the-notify-calls-work-with-IPv6-in-the-OCF-reso.patch b/SOURCES/0001-Make-the-notify-calls-work-with-IPv6-in-the-OCF-reso.patch new file mode 100644 index 0000000..262e59b --- /dev/null +++ b/SOURCES/0001-Make-the-notify-calls-work-with-IPv6-in-the-OCF-reso.patch @@ -0,0 +1,44 @@ +From 5d47f08c60600708aae354b021da9779a9c8e5e6 Mon Sep 17 00:00:00 2001 +From: Michele Baldessari +Date: Wed, 3 Jun 2020 14:43:47 +0200 +Subject: [PATCH] Make the notify() calls work with IPv6 in the OCF + resource-agent + +When the VIP is an IPv6 address we get the following error in the +resource agent: +ovndb_servers_notify_0:355:stderr [ + ovn-sbctl -- --id=@conn_uuid create Connection 'target=ptcp\:6642\:[fd00:fd00:fd00:2000::a2]' inactivity_probe=180000 -- set SB_Global . connections=@conn_uuid ] +ovndb_servers_notify_0:355:stderr [ ovn-sbctl: ptcp\:6642\:[fd00:fd00:fd00:2000::a2]: unexpected "[" parsing string ] + +This is because MASTER_IP is an IPv6 address and is being passed to +ovn-[ns]bctl without being escaped and the command errors out with +unexpected parsing string errors. The rest of the create Connection +command was already escaping the columns, we are just missing the ip +address bits in case of IPv6. + +Let's make sure we escape the '[]:' characters and avoid this problem. +Tested this on an OpenStack environment on both IPv6 and IPv4. + +Signed-off-by: Michele Baldessari +Signed-off-by: Numan Siddique +--- + utilities/ovndb-servers.ocf | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/utilities/ovndb-servers.ocf b/utilities/ovndb-servers.ocf +index 56c2bc322..7351c7d64 100755 +--- a/utilities/ovndb-servers.ocf ++++ b/utilities/ovndb-servers.ocf +@@ -249,7 +249,9 @@ ovsdb_server_notify() { + if [ "x${LISTEN_ON_MASTER_IP_ONLY}" = xno ]; then + LISTEN_ON_IP="0.0.0.0" + else +- LISTEN_ON_IP=${MASTER_IP} ++ # ovn-[sn]bctl want ':[]' characters to be escaped. We do so in ++ # order to make this work when MASTER_IP is an IPv6 address. ++ LISTEN_ON_IP=$(sed -e 's/\(\[\|\]\|:\)/\\\1/g' <<< ${MASTER_IP}) + fi + conn=`ovn-nbctl get NB_global . connections` + if [ "$conn" == "[]" ] +-- +2.26.2 + diff --git a/SOURCES/0001-Rely-on-unique-name-for-ovn-qos-meters.patch b/SOURCES/0001-Rely-on-unique-name-for-ovn-qos-meters.patch new file mode 100644 index 0000000..04bf3fd --- /dev/null +++ b/SOURCES/0001-Rely-on-unique-name-for-ovn-qos-meters.patch @@ -0,0 +1,73 @@ +From ab7a370f24ec88a019f1aa4da76f1a050bf398c6 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Lorenzo Bianconi +Date: Mon, 27 Apr 2020 17:45:20 +0200 +Subject: [PATCH] Rely on unique name for ovn qos meters + +ovn currently identifies qos meters according to the rate and burst values +configured. Doing so 2 meters on the same hv assigned to 2 different logical +switch ports and configured with the same values for rate and burst will be +mapped to the same ovs kernel mater and will share the bandwidth. +Fix this behavior making qos meter name unique + +Tested-By: Maciej Jozefczyk +Acked-by: Han Zhou +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique +--- + controller/ofctrl.c | 2 +- + lib/actions.c | 11 ++++++----- + tests/ovn.at | 10 ++++++++++ + 3 files changed, 17 insertions(+), 6 deletions(-) + +--- a/controller/ofctrl.c ++++ b/controller/ofctrl.c +@@ -970,7 +970,7 @@ add_meter_string(struct ovn_extend_table + enum ofputil_protocol usable_protocols; + char *meter_string = xasprintf("meter=%"PRIu32",%s", + m_desired->table_id, +- &m_desired->name[9]); ++ &m_desired->name[52]); + char *error = parse_ofp_meter_mod_str(&mm, meter_string, OFPMC13_ADD, + &usable_protocols); + if (!error) { +--- a/lib/actions.c ++++ b/lib/actions.c +@@ -2796,12 +2796,13 @@ encode_SET_METER(const struct ovnact_set + * describes the meter itself. */ + char *name; + if (cl->burst) { +- name = xasprintf("__string: kbps burst stats bands=type=drop " +- "rate=%"PRId64" burst_size=%"PRId64"", cl->rate, +- cl->burst); ++ name = xasprintf("__string: uuid "UUID_FMT" kbps burst stats " ++ "bands=type=drop rate=%"PRId64" burst_size=%"PRId64, ++ UUID_ARGS(&ep->lflow_uuid), cl->rate, cl->burst); + } else { +- name = xasprintf("__string: kbps stats bands=type=drop " +- "rate=%"PRId64"", cl->rate); ++ name = xasprintf("__string: uuid "UUID_FMT" kbps stats " ++ "bands=type=drop rate=%"PRId64, ++ UUID_ARGS(&ep->lflow_uuid), cl->rate); + } + + table_id = ovn_extend_table_assign_id(ep->meter_table, name, +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -7653,6 +7653,16 @@ AT_CHECK([as hv ovs-ofctl dump-flows br- + AT_CHECK([as hv ovs-ofctl dump-meters br-int -O OpenFlow13 | grep rate=11123 | wc -l], [0], [0 + ]) + ++# Check multiple qos meters ++ovn-nbctl qos-del lsw0 ++ovn-nbctl qos-add lsw0 to-lport 1001 'inport=="lp1" && is_chassis_resident("lp1")' rate=100000 burst=100000 ++ovn-nbctl qos-add lsw0 to-lport 1001 'inport=="lp2" && is_chassis_resident("lp2")' rate=100000 burst=100000 ++ovn-nbctl qos-add lsw0 to-lport 1002 'inport=="lp1" && is_chassis_resident("lp1")' rate=100001 burst=100001 ++ovn-nbctl qos-add lsw0 to-lport 1002 'inport=="lp2" && is_chassis_resident("lp2")' rate=100001 burst=100001 ++ ++AT_CHECK([as hv ovs-ofctl dump-meters br-int -O OpenFlow13 | grep meter | wc -l], [0], [4 ++]) ++ + OVN_CLEANUP([hv]) + AT_CLEANUP + diff --git a/SOURCES/0001-Revert-ovsdb-idl-Avoid-sending-redundant-conditional.patch b/SOURCES/0001-Revert-ovsdb-idl-Avoid-sending-redundant-conditional.patch new file mode 100644 index 0000000..8cb059a --- /dev/null +++ b/SOURCES/0001-Revert-ovsdb-idl-Avoid-sending-redundant-conditional.patch @@ -0,0 +1,67 @@ +From 7d3fe4b24896304bc1d832f95a425fa62c48f7f8 Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Wed, 25 Mar 2020 21:15:23 +0100 +Subject: [PATCH] Revert "ovsdb-idl: Avoid sending redundant conditional + monitoring updates" + +This reverts commit 5351980b047f4dd40be7a59a1e4b910df21eca0a. + +If the ovsdb-server reply to "monitor_cond_since" requests has +"found" == false then ovsdb_idl_db_parse_monitor_reply() calls +ovsdb_idl_db_clear() which iterates through all tables and +unconditionally sets table->cond_changed to false. + +However, if the client had already set a new condition for some of the +tables, this new condition request will never be sent to ovsdb-server +until the condition is reset to a different value. This is due to the +check in ovsdb_idl_db_set_condition(). + +One way to replicate the issue is described in the bugzilla reporting +the bug, when ovn-controller is configured to use "ovn-monitor-all": +https://bugzilla.redhat.com/show_bug.cgi?id=1808125#c6 + +Commit 5351980b047f tried to optimize sending redundant conditional +monitoring updates but the chances that this scenario happens with the +latest code is quite low since commit 403a6a0cb003 ("ovsdb-idl: Fast +resync from server when connection reset.") changed the behavior of +ovsdb_idl_db_parse_monitor_reply() to avoid calling ovsdb_idl_db_clear() +in most cases. + +Reported-by: Dan Williams +Reported-at: https://bugzilla.redhat.com/1808125 +CC: Andy Zhou +Fixes: 5351980b047f ("ovsdb-idl: Avoid sending redundant conditional monitoring updates") +Acked-by: Han Zhou +Acked-by: Ilya Maximets +Signed-off-by: Dumitru Ceara +Signed-off-by: Ilya Maximets +(cherry picked from upstream OVS commit 2b7e536fa5e20be10e620b959e05557f88862d2c) + +Change-Id: Iaa24bc949d648e8fa29abea1fe8fb5878ba45864 +--- + openvswitch-2.13.0/lib/ovsdb-idl.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/openvswitch-2.13.0/lib/ovsdb-idl.c b/openvswitch-2.13.0/lib/ovsdb-idl.c +index 190143f..1535ad7 100644 +--- a/openvswitch-2.13.0/lib/ovsdb-idl.c ++++ b/openvswitch-2.13.0/lib/ovsdb-idl.c +@@ -610,7 +610,6 @@ ovsdb_idl_db_clear(struct ovsdb_idl_db *db) + struct ovsdb_idl_table *table = &db->tables[i]; + struct ovsdb_idl_row *row, *next_row; + +- table->cond_changed = false; + if (hmap_is_empty(&table->rows)) { + continue; + } +@@ -634,7 +633,6 @@ ovsdb_idl_db_clear(struct ovsdb_idl_db *db) + } + ovsdb_idl_row_destroy_postprocess(db); + +- db->cond_changed = false; + db->cond_seqno = 0; + ovsdb_idl_db_track_clear(db); + +-- +1.8.3.1 + diff --git a/SOURCES/0001-Split-SB-Port_Group-per-datapath.patch b/SOURCES/0001-Split-SB-Port_Group-per-datapath.patch new file mode 100644 index 0000000..695a0fe --- /dev/null +++ b/SOURCES/0001-Split-SB-Port_Group-per-datapath.patch @@ -0,0 +1,556 @@ +From 3cdc2f9cdd9b4911a236c731dfa76535e3af38e6 Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Mon, 29 Jun 2020 17:24:41 +0200 +Subject: [PATCH] Split SB Port_Group per datapath. + +In order to avoid ovn-controller reinstalling all logical flows that +refer a port_group when some ports are added/removed from the port group +we now change the way ovn-northd populates the Southbound DB Port_Group +table. + +Instead of copying NB.Port_Group.name to SB.Port_Group.name we now +create one SB.Port_Group record for every datapath that has ports +referenced by the NB.Port_Group.ports field. In order to maintain the +SB.Port_Group.name uniqueness constraint, ovn-northd populates the field +with the value: _. + +In specific scenarios we see significant improvements in time to +install/remove all logical flows to/from OVS. One such scenario, in the +BZ referenced below has: + +$ ovn-nbctl acl-list pg + from-lport 1001 (inport == @pg && ip) drop + to-lport 1001 (outport == @pg && ip) drop + +Then, incrementally, creates new logical ports on different logical +switches, binds them to OVS interfaces and adds them to the port_group. + +Measuring the total time to perform the above steps 500 times (for 500 +new ports attached to 100 switches, 5 per switch) on a test setup +we observe an improvement of 50% in time it takes to install all +openflow rules when port_groups are split in the SB database. + +Suggested-by: Numan Siddique +Reported-by: Venkata Anil +Reported-at: https://bugzilla.redhat.com/1818128 +Signed-off-by: Dumitru Ceara +Acked-by: Numan Siddique +Signed-off-by: Mark Michelson + +Conflicts: + TODO.rst + lib/ovn-util.h + +Change-Id: Ibb8ffc5dbf4deb33a46e94b3f7b57c248d669073 +--- + TODO.rst | 8 ++++++ + controller/lflow.c | 4 ++- + include/ovn/expr.h | 4 ++- + lib/actions.c | 2 +- + lib/expr.c | 48 ++++++++++++++++++++++++------- + lib/ovn-util.h | 7 +++++ + northd/ovn-northd.c | 79 ++++++++++++++++++++++++++++++++++----------------- + tests/ovn-northd.at | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ + tests/test-ovn.c | 10 +++---- + utilities/ovn-trace.c | 3 +- + 10 files changed, 198 insertions(+), 46 deletions(-) + +diff --git a/TODO.rst b/TODO.rst +index 809d1c9..cfd33be 100644 +--- a/TODO.rst ++++ b/TODO.rst +@@ -149,3 +149,11 @@ OVN To-do List + * OVN Interconnection + + * Packaging for RHEL, Debian, etc. ++ ++* ovn-controller: Remove backwards compatibility for Southbound DB Port_Group ++ names in expr.c a few releases after the 20.09 version. Right now ++ ovn-controller maintains backwards compatibility when connecting to a ++ SB database that doesn't store Port_Group.name as ++ . This causes an additional ++ hashtable lookup in parse_port_group() which can be avoided when we are sure ++ that the Southbound DB uses the new format. +diff --git a/controller/lflow.c b/controller/lflow.c +index 01214a3..0e57327 100644 +--- a/controller/lflow.c ++++ b/controller/lflow.c +@@ -552,7 +552,9 @@ consider_logical_flow(const struct sbrec_logical_flow *lflow, + struct sset port_groups_ref = SSET_INITIALIZER(&port_groups_ref); + expr = expr_parse_string(lflow->match, &symtab, l_ctx_in->addr_sets, + l_ctx_in->port_groups, +- &addr_sets_ref, &port_groups_ref, &error); ++ &addr_sets_ref, &port_groups_ref, ++ lflow->logical_datapath->tunnel_key, ++ &error); + const char *addr_set_name; + SSET_FOR_EACH (addr_set_name, &addr_sets_ref) { + lflow_resource_add(l_ctx_out->lfrr, REF_TYPE_ADDRSET, addr_set_name, +diff --git a/include/ovn/expr.h b/include/ovn/expr.h +index 21bf51c..9838251 100644 +--- a/include/ovn/expr.h ++++ b/include/ovn/expr.h +@@ -391,12 +391,14 @@ struct expr *expr_parse(struct lexer *, const struct shash *symtab, + const struct shash *addr_sets, + const struct shash *port_groups, + struct sset *addr_sets_ref, +- struct sset *port_groups_ref); ++ struct sset *port_groups_ref, ++ int64_t dp_id); + struct expr *expr_parse_string(const char *, const struct shash *symtab, + const struct shash *addr_sets, + const struct shash *port_groups, + struct sset *addr_sets_ref, + struct sset *port_groups_ref, ++ int64_t dp_id, + char **errorp); + + struct expr *expr_clone(struct expr *); +diff --git a/lib/actions.c b/lib/actions.c +index 3181126..d107871 100644 +--- a/lib/actions.c ++++ b/lib/actions.c +@@ -242,7 +242,7 @@ add_prerequisite(struct action_context *ctx, const char *prerequisite) + char *error; + + expr = expr_parse_string(prerequisite, ctx->pp->symtab, NULL, NULL, +- NULL, NULL, &error); ++ NULL, NULL, 0, &error); + ovs_assert(!error); + ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr); + } +diff --git a/lib/expr.c b/lib/expr.c +index 078d178..497b2ac 100644 +--- a/lib/expr.c ++++ b/lib/expr.c +@@ -29,6 +29,7 @@ + #include "simap.h" + #include "sset.h" + #include "util.h" ++#include "ovn-util.h" + + VLOG_DEFINE_THIS_MODULE(expr); + +@@ -482,6 +483,10 @@ struct expr_context { + const struct shash *port_groups; /* Port group table. */ + struct sset *addr_sets_ref; /* The set of address set referenced. */ + struct sset *port_groups_ref; /* The set of port groups referenced. */ ++ int64_t dp_id; /* The tunnel_key of the datapath for ++ which we're parsing the current ++ expression. */ ++ + bool not; /* True inside odd number of NOT operators. */ + unsigned int paren_depth; /* Depth of nested parentheses. */ + }; +@@ -783,14 +788,32 @@ static bool + parse_port_group(struct expr_context *ctx, struct expr_constant_set *cs, + size_t *allocated_values) + { ++ struct ds sb_name = DS_EMPTY_INITIALIZER; ++ ++ get_sb_port_group_name(ctx->lexer->token.s, ctx->dp_id, &sb_name); + if (ctx->port_groups_ref) { +- sset_add(ctx->port_groups_ref, ctx->lexer->token.s); ++ sset_add(ctx->port_groups_ref, ds_cstr(&sb_name)); ++ } ++ ++ struct expr_constant_set *port_group = NULL; ++ ++ if (ctx->port_groups) { ++ port_group = shash_find_data(ctx->port_groups, ds_cstr(&sb_name)); ++ if (!port_group) { ++ /* For backwards compatibility (e.g., ovn-controller was ++ * upgraded but ovn-northd not yet), perform an additional ++ * lookup because the NB Port_Group.name might have been ++ * stored as is in the SB Port_Group.name field. ++ */ ++ port_group = shash_find_data(ctx->port_groups, ++ ctx->lexer->token.s); ++ if (ctx->port_groups_ref) { ++ sset_add(ctx->port_groups_ref, ctx->lexer->token.s); ++ } ++ } + } ++ ds_destroy(&sb_name); + +- struct expr_constant_set *port_group +- = (ctx->port_groups +- ? shash_find_data(ctx->port_groups, ctx->lexer->token.s) +- : NULL); + if (!port_group) { + lexer_syntax_error(ctx->lexer, "expecting port group name"); + return false; +@@ -1302,14 +1325,16 @@ expr_parse(struct lexer *lexer, const struct shash *symtab, + const struct shash *addr_sets, + const struct shash *port_groups, + struct sset *addr_sets_ref, +- struct sset *port_groups_ref) ++ struct sset *port_groups_ref, ++ int64_t dp_id) + { + struct expr_context ctx = { .lexer = lexer, + .symtab = symtab, + .addr_sets = addr_sets, + .port_groups = port_groups, + .addr_sets_ref = addr_sets_ref, +- .port_groups_ref = port_groups_ref }; ++ .port_groups_ref = port_groups_ref, ++ .dp_id = dp_id }; + return lexer->error ? NULL : expr_parse__(&ctx); + } + +@@ -1325,6 +1350,7 @@ expr_parse_string(const char *s, const struct shash *symtab, + const struct shash *port_groups, + struct sset *addr_sets_ref, + struct sset *port_groups_ref, ++ int64_t dp_id, + char **errorp) + { + struct lexer lexer; +@@ -1332,7 +1358,7 @@ expr_parse_string(const char *s, const struct shash *symtab, + lexer_init(&lexer, s); + lexer_get(&lexer); + struct expr *expr = expr_parse(&lexer, symtab, addr_sets, port_groups, +- addr_sets_ref, port_groups_ref); ++ addr_sets_ref, port_groups_ref, dp_id); + lexer_force_end(&lexer); + *errorp = lexer_steal_error(&lexer); + if (*errorp) { +@@ -1558,7 +1584,7 @@ expr_get_level(const struct expr *expr) + static enum expr_level + expr_parse_level(const char *s, const struct shash *symtab, char **errorp) + { +- struct expr *expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, ++ struct expr *expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, 0, + errorp); + enum expr_level level = expr ? expr_get_level(expr) : EXPR_L_NOMINAL; + expr_destroy(expr); +@@ -1730,7 +1756,7 @@ parse_and_annotate(const char *s, const struct shash *symtab, + char *error; + struct expr *expr; + +- expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, &error); ++ expr = expr_parse_string(s, symtab, NULL, NULL, NULL, NULL, 0, &error); + if (expr) { + expr = expr_annotate_(expr, symtab, nesting, &error); + } +@@ -3456,7 +3482,7 @@ expr_parse_microflow(const char *s, const struct shash *symtab, + lexer_get(&lexer); + + struct expr *e = expr_parse(&lexer, symtab, addr_sets, port_groups, +- NULL, NULL); ++ NULL, NULL, 0); + lexer_force_end(&lexer); + + if (e) { +diff --git a/lib/ovn-util.h b/lib/ovn-util.h +index ec5f2cf..9c6d357 100644 +--- a/lib/ovn-util.h ++++ b/lib/ovn-util.h +@@ -111,6 +111,13 @@ bool ovn_tnlid_in_use(const struct hmap *set, uint32_t tnlid); + uint32_t ovn_allocate_tnlid(struct hmap *set, const char *name, uint32_t min, + uint32_t max, uint32_t *hint); + ++static inline void ++get_sb_port_group_name(const char *nb_pg_name, int64_t dp_tunnel_key, ++ struct ds *sb_pg_name) ++{ ++ ds_put_format(sb_pg_name, "%"PRId64"_%s", dp_tunnel_key, nb_pg_name); ++} ++ + char *ovn_chassis_redirect_name(const char *port_name); + void ovn_set_pidfile(const char *name); + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index fc25031..8a809d0 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -4457,7 +4457,11 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip, + struct ovn_port_group_ls { + struct hmap_node key_node; /* Index on 'key'. */ + struct uuid key; /* nb_ls->header_.uuid. */ +- const struct nbrec_logical_switch *nb_ls; ++ struct ovn_datapath *od; ++ ++ struct ovn_port **ports; /* Ports in 'od' referrenced by the PG. */ ++ size_t n_ports; ++ size_t n_allocated_ports; + }; + + struct ovn_port_group { +@@ -4467,14 +4471,14 @@ struct ovn_port_group { + struct hmap nb_lswitches; /* NB lswitches related to the port group */ + }; + +-static void +-ovn_port_group_ls_add(struct ovn_port_group *pg, +- const struct nbrec_logical_switch *nb_ls) ++static struct ovn_port_group_ls * ++ovn_port_group_ls_add(struct ovn_port_group *pg, struct ovn_datapath *od) + { + struct ovn_port_group_ls *pg_ls = xzalloc(sizeof *pg_ls); +- pg_ls->key = nb_ls->header_.uuid; +- pg_ls->nb_ls = nb_ls; ++ pg_ls->key = od->nbs->header_.uuid; ++ pg_ls->od = od; + hmap_insert(&pg->nb_lswitches, &pg_ls->key_node, uuid_hash(&pg_ls->key)); ++ return pg_ls; + } + + static struct ovn_port_group_ls * +@@ -4491,6 +4495,18 @@ ovn_port_group_ls_find(struct ovn_port_group *pg, const struct uuid *ls_uuid) + return NULL; + } + ++static void ++ovn_port_group_ls_add_port(struct ovn_port_group_ls *pg_ls, ++ struct ovn_port *op) ++{ ++ if (pg_ls->n_ports == pg_ls->n_allocated_ports) { ++ pg_ls->ports = x2nrealloc(pg_ls->ports, ++ &pg_ls->n_allocated_ports, ++ sizeof *pg_ls->ports); ++ } ++ pg_ls->ports[pg_ls->n_ports++] = op; ++} ++ + struct ovn_ls_port_group { + struct hmap_node key_node; /* Index on 'key'. */ + struct uuid key; /* nb_pg->header_.uuid. */ +@@ -5250,6 +5266,7 @@ ovn_port_group_destroy(struct hmap *pgs, struct ovn_port_group *pg) + hmap_remove(pgs, &pg->key_node); + struct ovn_port_group_ls *ls; + HMAP_FOR_EACH_POP (ls, key_node, &pg->nb_lswitches) { ++ free(ls->ports); + free(ls); + } + hmap_destroy(&pg->nb_lswitches); +@@ -5287,9 +5304,10 @@ build_port_group_lswitches(struct northd_context *ctx, struct hmap *pgs, + struct ovn_port_group_ls *pg_ls = + ovn_port_group_ls_find(pg, &op->od->nbs->header_.uuid); + if (!pg_ls) { +- ovn_port_group_ls_add(pg, op->od->nbs); ++ pg_ls = ovn_port_group_ls_add(pg, op->od); + ovn_ls_port_group_add(&op->od->nb_pgs, nb_pg); + } ++ ovn_port_group_ls_add_port(pg_ls, op); + } + } + } +@@ -10454,7 +10472,7 @@ sync_address_sets(struct northd_context *ctx) + * contains lport uuids, while in OVN_Southbound we store the lport names. + */ + static void +-sync_port_groups(struct northd_context *ctx) ++sync_port_groups(struct northd_context *ctx, struct hmap *pgs) + { + struct shash sb_port_groups = SHASH_INITIALIZER(&sb_port_groups); + +@@ -10463,26 +10481,35 @@ sync_port_groups(struct northd_context *ctx) + shash_add(&sb_port_groups, sb_port_group->name, sb_port_group); + } + +- const struct nbrec_port_group *nb_port_group; +- NBREC_PORT_GROUP_FOR_EACH (nb_port_group, ctx->ovnnb_idl) { +- sb_port_group = shash_find_and_delete(&sb_port_groups, +- nb_port_group->name); +- if (!sb_port_group) { +- sb_port_group = sbrec_port_group_insert(ctx->ovnsb_txn); +- sbrec_port_group_set_name(sb_port_group, nb_port_group->name); +- } ++ struct ds sb_name = DS_EMPTY_INITIALIZER; + +- const char **nb_port_names = xcalloc(nb_port_group->n_ports, +- sizeof *nb_port_names); +- int i; +- for (i = 0; i < nb_port_group->n_ports; i++) { +- nb_port_names[i] = nb_port_group->ports[i]->name; ++ struct ovn_port_group *pg; ++ HMAP_FOR_EACH (pg, key_node, pgs) { ++ ++ struct ovn_port_group_ls *pg_ls; ++ HMAP_FOR_EACH (pg_ls, key_node, &pg->nb_lswitches) { ++ ds_clear(&sb_name); ++ get_sb_port_group_name(pg->nb_pg->name, pg_ls->od->sb->tunnel_key, ++ &sb_name); ++ sb_port_group = shash_find_and_delete(&sb_port_groups, ++ ds_cstr(&sb_name)); ++ if (!sb_port_group) { ++ sb_port_group = sbrec_port_group_insert(ctx->ovnsb_txn); ++ sbrec_port_group_set_name(sb_port_group, ds_cstr(&sb_name)); ++ } ++ ++ const char **nb_port_names = xcalloc(pg_ls->n_ports, ++ sizeof *nb_port_names); ++ for (size_t i = 0; i < pg_ls->n_ports; i++) { ++ nb_port_names[i] = pg_ls->ports[i]->nbsp->name; ++ } ++ sbrec_port_group_set_ports(sb_port_group, ++ nb_port_names, ++ pg_ls->n_ports); ++ free(nb_port_names); + } +- sbrec_port_group_set_ports(sb_port_group, +- nb_port_names, +- nb_port_group->n_ports); +- free(nb_port_names); + } ++ ds_destroy(&sb_name); + + struct shash_node *node, *next; + SHASH_FOR_EACH_SAFE (node, next, &sb_port_groups) { +@@ -11081,7 +11108,7 @@ ovnnb_db_run(struct northd_context *ctx, + ovn_update_ipv6_prefix(ports); + + sync_address_sets(ctx); +- sync_port_groups(ctx); ++ sync_port_groups(ctx, &port_groups); + sync_meters(ctx); + sync_dns_entries(ctx, datapaths); + destroy_ovn_lbs(&lbs); +diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at +index e6a8c04..37805d3 100644 +--- a/tests/ovn-northd.at ++++ b/tests/ovn-northd.at +@@ -1406,3 +1406,82 @@ AT_CHECK([ovn-nbctl --wait=sb sync], [0]) + AT_CHECK([test 0 = $(ovn-sbctl list Ha_Chassis_Group | wc -l)]) + + AT_CLEANUP ++ ++AT_SETUP([ovn -- check NB/SB Port_Group translation (lsp add/del)]) ++ovn_start ++ ++ovn-nbctl ls-add ls1 ++ovn-nbctl ls-add ls2 ++ovn-nbctl lsp-add ls1 lsp1 ++ovn-nbctl lsp-add ls2 lsp2 ++ovn-nbct --wait=sb sync ++ls1_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls1) ++ls2_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls2) ++ ++# Add an empty port group. This should generate no entry in the SB. ++ovn-nbctl --wait=sb pg-add pg_test ++AT_CHECK([test 0 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)]) ++ ++# Add lsp1 to the port group. This should generate an entry in the SB only ++# for ls1. ++ovn-nbctl --wait=sb pg-set-ports pg_test lsp1 ++AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)]) ++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls1_key}_pg_test], [0], [dnl ++lsp1 ++]) ++ ++# Add lsp2 to the port group. This should generate a new entry in the SB, for ++# ls2. ++ovn-nbctl --wait=sb pg-set-ports pg_test lsp1 lsp2 ++AT_CHECK([test 2 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)]) ++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls1_key}_pg_test], [0], [dnl ++lsp1 ++]) ++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl ++lsp2 ++]) ++ ++# Remove lsp1 from the port group. The SB Port_Group for ls1 should be ++# removed. ++ovn-nbctl --wait=sb pg-set-ports pg_test lsp2 ++AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)]) ++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl ++lsp2 ++]) ++ ++# Remove lsp2 from the port group. All SB Port_Groups should be purged. ++ovn-nbctl --wait=sb clear Port_Group pg_test ports ++AT_CHECK([test 0 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)]) ++ ++AT_CLEANUP ++ ++AT_SETUP([ovn -- check NB/SB Port_Group translation (ls del)]) ++ovn_start ++ ++ovn-nbctl ls-add ls1 ++ovn-nbctl ls-add ls2 ++ovn-nbctl lsp-add ls1 lsp1 ++ovn-nbctl lsp-add ls2 lsp2 ++ovn-nbct --wait=sb sync ++ls1_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls1) ++ls2_key=$(ovn-sbctl --columns tunnel_key --bare list Datapath_Binding ls2) ++ ++# Add lsp1 & lsp2 to a port group. This should generate two entries in the ++# SB (one per logical switch). ++ovn-nbctl --wait=sb pg-add pg_test lsp1 lsp2 ++AT_CHECK([test 2 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)]) ++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls1_key}_pg_test], [0], [dnl ++lsp1 ++]) ++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl ++lsp2 ++]) ++ ++# Delete logical switch ls1. This should remove the associated SB Port_Group. ++ovn-nbctl --wait=sb ls-del ls1 ++AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Port_Group | grep uuid -c)]) ++AT_CHECK([ovn-sbctl --columns ports --bare find Port_Group name=${ls2_key}_pg_test], [0], [dnl ++lsp2 ++]) ++ ++AT_CLEANUP +diff --git a/tests/test-ovn.c b/tests/test-ovn.c +index 11697eb..9f74c5c 100644 +--- a/tests/test-ovn.c ++++ b/tests/test-ovn.c +@@ -235,8 +235,8 @@ create_port_groups(struct shash *port_groups) + }; + static const char *const pg2[] = { NULL }; + +- expr_const_sets_add(port_groups, "pg1", pg1, 3, false); +- expr_const_sets_add(port_groups, "pg_empty", pg2, 0, false); ++ expr_const_sets_add(port_groups, "0_pg1", pg1, 3, false); ++ expr_const_sets_add(port_groups, "0_pg_empty", pg2, 0, false); + } + + static bool +@@ -302,7 +302,7 @@ test_parse_expr__(int steps) + char *error; + + expr = expr_parse_string(ds_cstr(&input), &symtab, &addr_sets, +- &port_groups, NULL, NULL, &error); ++ &port_groups, NULL, NULL, 0, &error); + if (!error && steps > 0) { + expr = expr_annotate(expr, &symtab, &error); + } +@@ -428,7 +428,7 @@ test_evaluate_expr(struct ovs_cmdl_context *ctx) + struct expr *expr; + + expr = expr_parse_string(ds_cstr(&input), &symtab, NULL, NULL, +- NULL, NULL, &error); ++ NULL, NULL, 0, &error); + if (!error) { + expr = expr_annotate(expr, &symtab, &error); + } +@@ -903,7 +903,7 @@ test_tree_shape_exhaustively(struct expr *expr, struct shash *symtab, + + char *error; + modified = expr_parse_string(ds_cstr(&s), symtab, NULL, +- NULL, NULL, NULL, &error); ++ NULL, NULL, NULL, 0, &error); + if (error) { + fprintf(stderr, "%s fails to parse (%s)\n", + ds_cstr(&s), error); +diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c +index d7251e7..2666c10 100644 +--- a/utilities/ovn-trace.c ++++ b/utilities/ovn-trace.c +@@ -889,7 +889,8 @@ read_flows(void) + char *error; + struct expr *match; + match = expr_parse_string(sblf->match, &symtab, &address_sets, +- &port_groups, NULL, NULL, &error); ++ &port_groups, NULL, NULL, dp->tunnel_key, ++ &error); + if (error) { + VLOG_WARN("%s: parsing expression failed (%s)", + sblf->match, error); +-- +1.8.3.1 + diff --git a/SOURCES/0001-controller-Use-OpenFlow-version-1.5.patch b/SOURCES/0001-controller-Use-OpenFlow-version-1.5.patch new file mode 100644 index 0000000..b979eea --- /dev/null +++ b/SOURCES/0001-controller-Use-OpenFlow-version-1.5.patch @@ -0,0 +1,259 @@ +From a8fcc8cc07ff9acbf9ff328e6ac2e781d73d3f8b Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Tue, 21 Apr 2020 19:28:23 +0530 +Subject: [PATCH 1/4] controller: Use OpenFlow version 1.5 + +When adding flows to the group table, we need to use OFP15_VERSION to +set the selection_method. Right now ovn-controller is setting +select_method=dp_hash for OVN load balancers, but when encoding the +group mod, it is ignored. + +Acked-by: Han Zhou +Signed-off-by: Numan Siddique +--- + NEWS | 1 + + controller/ofctrl.c | 14 +++++++------- + controller/ovn-controller.c | 2 +- + controller/pinctrl.c | 2 +- + lib/actions.c | 10 +++++----- + lib/expr.c | 2 +- + tests/ovn.at | 6 +++--- + utilities/ovn-sbctl.c | 4 ++-- + utilities/ovn-trace.c | 4 ++-- + 9 files changed, 23 insertions(+), 22 deletions(-) + +diff --git a/NEWS b/NEWS +index 21c80f0dc..e77343c89 100644 +--- a/NEWS ++++ b/NEWS +@@ -8,6 +8,7 @@ OVN v20.03.0 - 28 Feb 2020 + - Added support for MLD Snooping and MLD Querier. + - Added support for ECMP routes in OVN router. + - Added IPv6 Prefix Delegation support in OVN. ++ - OVN now uses OpenFlow 1.5. + + - OVN Interconnection: + * Support for L3 interconnection of multiple OVN deployments with tunnels +diff --git a/controller/ofctrl.c b/controller/ofctrl.c +index 485a857d1..4b51cd86e 100644 +--- a/controller/ofctrl.c ++++ b/controller/ofctrl.c +@@ -178,7 +178,7 @@ ofctrl_init(struct ovn_extend_table *group_table, + int inactivity_probe_interval) + { + swconn = rconn_create(inactivity_probe_interval, 0, +- DSCP_DEFAULT, 1 << OFP13_VERSION); ++ DSCP_DEFAULT, 1 << OFP15_VERSION); + tx_counter = rconn_packet_counter_create(); + hmap_init(&installed_flows); + ovs_list_init(&flow_updates); +@@ -282,8 +282,8 @@ process_tlv_table_reply(const struct ofputil_tlv_table_reply *reply) + ovs_list_init(&ttm.mappings); + ovs_list_push_back(&ttm.mappings, &tm.list_node); + +- xid = queue_msg(ofputil_encode_tlv_table_mod(OFP13_VERSION, &ttm)); +- xid2 = queue_msg(ofputil_encode_barrier_request(OFP13_VERSION)); ++ xid = queue_msg(ofputil_encode_tlv_table_mod(OFP15_VERSION, &ttm)); ++ xid2 = queue_msg(ofputil_encode_barrier_request(OFP15_VERSION)); + state = S_TLV_TABLE_MOD_SENT; + + return true; +@@ -911,7 +911,7 @@ encode_flow_mod(struct ofputil_flow_mod *fm) + fm->buffer_id = UINT32_MAX; + fm->out_port = OFPP_ANY; + fm->out_group = OFPG_ANY; +- return ofputil_encode_flow_mod(fm, OFPUTIL_P_OF13_OXM); ++ return ofputil_encode_flow_mod(fm, OFPUTIL_P_OF15_OXM); + } + + static void +@@ -926,7 +926,7 @@ add_flow_mod(struct ofputil_flow_mod *fm, struct ovs_list *msgs) + static struct ofpbuf * + encode_group_mod(const struct ofputil_group_mod *gm) + { +- return ofputil_encode_group_mod(OFP13_VERSION, gm, NULL, -1); ++ return ofputil_encode_group_mod(OFP15_VERSION, gm, NULL, -1); + } + + static void +@@ -940,7 +940,7 @@ add_group_mod(const struct ofputil_group_mod *gm, struct ovs_list *msgs) + static struct ofpbuf * + encode_meter_mod(const struct ofputil_meter_mod *mm) + { +- return ofputil_encode_meter_mod(OFP13_VERSION, mm); ++ return ofputil_encode_meter_mod(OFP15_VERSION, mm); + } + + static void +@@ -1281,7 +1281,7 @@ ofctrl_put(struct ovn_desired_flow_table *flow_table, + + if (!ovs_list_is_empty(&msgs)) { + /* Add a barrier to the list of messages. */ +- struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP13_VERSION); ++ struct ofpbuf *barrier = ofputil_encode_barrier_request(OFP15_VERSION); + const struct ofp_header *oh = barrier->data; + ovs_be32 xid_ = oh->xid; + ovs_list_push_back(&msgs, &barrier->list_node); +diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c +index 6ff897325..a2d92429c 100644 +--- a/controller/ovn-controller.c ++++ b/controller/ovn-controller.c +@@ -2297,7 +2297,7 @@ parse_options(int argc, char *argv[]) + usage(); + + case 'V': +- ovs_print_version(OFP13_VERSION, OFP13_VERSION); ++ ovs_print_version(OFP15_VERSION, OFP15_VERSION); + exit(EXIT_SUCCESS); + + VLOG_OPTION_HANDLERS +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index 9d5b7c3c0..6b0ac3483 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -2805,7 +2805,7 @@ pinctrl_handler(void *arg_) + static long long int svc_monitors_next_run_time = LLONG_MAX; + static long long int send_prefixd_time = LLONG_MAX; + +- swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION); ++ swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP15_VERSION); + + while (!latch_is_set(&pctrl->pinctrl_thread_exit)) { + if (pctrl->br_int_name) { +diff --git a/lib/actions.c b/lib/actions.c +index 2dba9a922..605dbffe4 100644 +--- a/lib/actions.c ++++ b/lib/actions.c +@@ -1457,7 +1457,7 @@ encode_nested_actions(const struct ovnact_nest *on, + size_t oc_offset = encode_start_controller_op(opcode, false, + NX_CTLR_NO_METER, ofpacts); + ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size, +- ofpacts, OFP13_VERSION); ++ ofpacts, OFP15_VERSION); + encode_finish_controller_op(oc_offset, ofpacts); + + /* Free memory. */ +@@ -2260,7 +2260,7 @@ encode_PUT_DHCPV4_OPTS(const struct ovnact_put_opts *pdo, + size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_PUT_DHCP_OPTS, + true, NX_CTLR_NO_METER, + ofpacts); +- nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ++ nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false); + ovs_be32 ofs = htonl(dst.ofs); + ofpbuf_put(ofpacts, &ofs, sizeof ofs); + +@@ -2291,7 +2291,7 @@ encode_PUT_DHCPV6_OPTS(const struct ovnact_put_opts *pdo, + + size_t oc_offset = encode_start_controller_op( + ACTION_OPCODE_PUT_DHCPV6_OPTS, true, NX_CTLR_NO_METER, ofpacts); +- nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ++ nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false); + ovs_be32 ofs = htonl(dst.ofs); + ofpbuf_put(ofpacts, &ofs, sizeof ofs); + +@@ -2401,7 +2401,7 @@ encode_DNS_LOOKUP(const struct ovnact_dns_lookup *dl, + size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_DNS_LOOKUP, + true, NX_CTLR_NO_METER, + ofpacts); +- nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ++ nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false); + ovs_be32 ofs = htonl(dst.ofs); + ofpbuf_put(ofpacts, &ofs, sizeof ofs); + encode_finish_controller_op(oc_offset, ofpacts); +@@ -2565,7 +2565,7 @@ encode_PUT_ND_RA_OPTS(const struct ovnact_put_opts *po, + + size_t oc_offset = encode_start_controller_op( + ACTION_OPCODE_PUT_ND_RA_OPTS, true, NX_CTLR_NO_METER, ofpacts); +- nx_put_header(ofpacts, dst.field->id, OFP13_VERSION, false); ++ nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false); + ovs_be32 ofs = htonl(dst.ofs); + ofpbuf_put(ofpacts, &ofs, sizeof ofs); + +diff --git a/lib/expr.c b/lib/expr.c +index 78646a1af..078d17840 100644 +--- a/lib/expr.c ++++ b/lib/expr.c +@@ -1414,7 +1414,7 @@ expr_symbol_format(const struct expr_symbol *symbol, struct ds *s) + } else if (symbol->ovn_field) { + ds_put_cstr(s, symbol->name); + } else { +- nx_format_field_name(symbol->field->id, OFP13_VERSION, s); ++ nx_format_field_name(symbol->field->id, OFP15_VERSION, s); + } + } + +diff --git a/tests/ovn.at b/tests/ovn.at +index 35415f2b6..5fb100ad4 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -1186,7 +1186,7 @@ reg1[0] = put_dhcp_opts(offerip=1.2.3.4, domain_name=1.2.3.4); + + # nd_ns + nd_ns { nd.target = xxreg0; output; }; +- encodes as controller(userdata=00.00.00.09.00.00.00.00.ff.ff.00.18.00.00.23.20.00.06.00.80.00.00.00.00.00.01.de.10.00.01.2e.10.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00) ++ encodes as controller(userdata=00.00.00.09.00.00.00.00.00.1c.00.18.00.80.00.00.00.00.00.00.00.01.de.10.80.00.3e.10.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00) + has prereqs ip6 + + nd_ns { }; +@@ -1197,12 +1197,12 @@ nd_ns { }; + # nd_na + nd_na { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; /* Allow sending out inport. */ output; }; + formats as nd_na { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; output; }; +- encodes as controller(userdata=00.00.00.03.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.ff.ff.00.18.00.00.23.20.00.06.00.20.00.00.00.00.00.01.1c.04.00.01.1e.04.00.19.00.10.00.01.1c.04.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00) ++ encodes as controller(userdata=00.00.00.03.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.00.1c.00.18.00.20.00.00.00.00.00.00.00.01.1c.04.00.01.1e.04.00.00.00.00.00.19.00.10.00.01.1c.04.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00) + has prereqs nd_ns + # nd_na_router + nd_na_router { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; /* Allow sending out inport. */ output; }; + formats as nd_na_router { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; output; }; +- encodes as controller(userdata=00.00.00.0c.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.ff.ff.00.18.00.00.23.20.00.06.00.20.00.00.00.00.00.01.1c.04.00.01.1e.04.00.19.00.10.00.01.1c.04.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00) ++ encodes as controller(userdata=00.00.00.0c.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.00.1c.00.18.00.20.00.00.00.00.00.00.00.01.1c.04.00.01.1e.04.00.00.00.00.00.19.00.10.00.01.1c.04.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00) + has prereqs nd_ns + + # get_nd +diff --git a/utilities/ovn-sbctl.c b/utilities/ovn-sbctl.c +index d8bb3dcbc..04e082c70 100644 +--- a/utilities/ovn-sbctl.c ++++ b/utilities/ovn-sbctl.c +@@ -795,7 +795,7 @@ sbctl_open_vconn(struct shash *options) + + char *remote = ovs->data ? xstrdup(ovs->data) : default_ovs(); + struct vconn *vconn; +- int retval = vconn_open_block(remote, 1 << OFP13_VERSION, 0, -1, &vconn); ++ int retval = vconn_open_block(remote, 1 << OFP15_VERSION, 0, -1, &vconn); + if (retval) { + VLOG_WARN("%s: connection failed (%s)", remote, ovs_strerror(retval)); + } +@@ -816,7 +816,7 @@ sbctl_dump_openflow(struct vconn *vconn, const struct uuid *uuid, bool stats) + + struct ofputil_flow_stats *fses; + size_t n_fses; +- int error = vconn_dump_flows(vconn, &fsr, OFPUTIL_P_OF13_OXM, ++ int error = vconn_dump_flows(vconn, &fsr, OFPUTIL_P_OF15_OXM, + &fses, &n_fses); + if (error) { + VLOG_WARN("%s: error obtaining flow stats (%s)", +diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c +index c9d72285c..d7251e7ed 100644 +--- a/utilities/ovn-trace.c ++++ b/utilities/ovn-trace.c +@@ -2326,7 +2326,7 @@ trace_openflow(const struct ovntrace_flow *f, struct ovs_list *super) + + struct ofputil_flow_stats *fses; + size_t n_fses; +- int error = vconn_dump_flows(vconn, &fsr, OFPUTIL_P_OF13_OXM, ++ int error = vconn_dump_flows(vconn, &fsr, OFPUTIL_P_OF15_OXM, + &fses, &n_fses); + if (error) { + ovntrace_node_append(super, OVNTRACE_NODE_ERROR, +@@ -2435,7 +2435,7 @@ trace(const char *dp_s, const char *flow_s) + ds_put_char(&output, '\n'); + + if (ovs) { +- int retval = vconn_open_block(ovs, 1 << OFP13_VERSION, 0, -1, &vconn); ++ int retval = vconn_open_block(ovs, 1 << OFP15_VERSION, 0, -1, &vconn); + if (retval) { + VLOG_WARN("%s: connection failed (%s)", ovs, ovs_strerror(retval)); + } +-- +2.26.2 + diff --git a/SOURCES/0001-controller-use-LLA-IPv6-address-as-NS-source-address.patch b/SOURCES/0001-controller-use-LLA-IPv6-address-as-NS-source-address.patch new file mode 100644 index 0000000..091ee2d --- /dev/null +++ b/SOURCES/0001-controller-use-LLA-IPv6-address-as-NS-source-address.patch @@ -0,0 +1,105 @@ +From 7f60417ae6c7438565a21d5aee0bb8ae0b3a9b68 Mon Sep 17 00:00:00 2001 +Message-Id: <7f60417ae6c7438565a21d5aee0bb8ae0b3a9b68.1585835882.git.me@lorenzobianconi.net> +From: Lorenzo Bianconi +Date: Tue, 24 Mar 2020 20:33:27 +0100 +Subject: [PATCH] controller: use LLA IPv6 address as NS source address + +Use router LLA IPv6 address as IPv6 source address for Neighbor +Solicitation packets + +Fixes: c0bf32d72 ("Manage ARP process locally in a DVR scenario") +Change-Id: Iafa26f4b3c20e181bd5b54a357d468ce61b589b6 +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique +Signed-off-by: Lorenzo Bianconi +--- + controller/pinctrl.c | 4 +++- + tests/ovn.at | 15 +++++++++------ + 2 files changed, 12 insertions(+), 7 deletions(-) + +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -4563,9 +4563,11 @@ pinctrl_handle_nd_ns(struct rconn *swcon + + uint64_t packet_stub[128 / 8]; + struct dp_packet packet; ++ struct in6_addr ipv6_src; + dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); + +- compose_nd_ns(&packet, ip_flow->dl_src, &ip_flow->ipv6_src, ++ in6_generate_lla(ip_flow->dl_src, &ipv6_src); ++ compose_nd_ns(&packet, ip_flow->dl_src, &ipv6_src, + &ip_flow->ipv6_dst); + + /* Reload previous packet metadata and set actions from userdata. */ +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -11280,13 +11280,13 @@ options:rxq_pcap=${pcap_file}-rx.pcap + # This function sends ipv6 packet + test_ipv6() { + local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 +- local dst_mcast_mac=$6 mcast_node_ip=$7 nd_target=$8 ++ local dst_mcast_mac=$6 mcast_node_ip=$7 nd_target=$8 nd_src_ip=$9 + + local packet=${dst_mac}${src_mac}86dd6000000000083aff${src_ip}${dst_ip} + packet=${packet}8000000000000000 + + src_mac=000002010204 +- expected_packet=${dst_mcast_mac}${src_mac}86dd6000000000203aff${src_ip} ++ expected_packet=${dst_mcast_mac}${src_mac}86dd6000000000203aff${nd_src_ip} + expected_packet=${expected_packet}${mcast_node_ip}8700XXXX00000000 + expected_packet=${expected_packet}${nd_target}0101${src_mac} + +@@ -11298,6 +11298,7 @@ test_ipv6() { + src_mac=506400000002 + dst_mac=00000000af01 + src_ip=aef0000000000000526400fffe000002 ++nd_src_ip=fe80000000000000020002fffe010204 + dst_ip=20010db800010000020002fffe010205 + dst_mcast_mac=3333ff010205 + mcast_node_ip=ff0200000000000000000001ff010205 +@@ -11305,7 +11306,7 @@ nd_target=20010db800010000020002fffe0102 + # Send an IPv6 packet. Generated IPv6 Neighbor solicitation packet + # should be received by the ports attached to br-phys. + test_ipv6 1 $src_mac $dst_mac $src_ip $dst_ip $dst_mcast_mac \ +-$mcast_node_ip $nd_target ++$mcast_node_ip $nd_target $nd_src_ip + + OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys_n1-tx.pcap | cut -d " " -f1)]) + OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys-tx.pcap | cut -d " " -f1)]) +@@ -11338,7 +11339,7 @@ dst_mcast_mac=3333ff011305 + mcast_node_ip=ff0200000000000000000001ff011305 + nd_target=20010db800010000020002fffe011305 + test_ipv6 1 $src_mac $dst_mac $src_ip $dst_ip $dst_mcast_mac \ +-$mcast_node_ip $nd_target ++$mcast_node_ip $nd_target $nd_src_ip + + OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys_n1-tx.pcap | cut -d " " -f1)]) + OVS_WAIT_WHILE([test 24 = $(wc -c hv1/br-phys-tx.pcap | cut -d " " -f1)]) +@@ -14262,7 +14263,7 @@ send_na() { + get_nd() { + local eth_src=$1 src_ip=$2 dst_ip=$3 ta=$4 + local ip6_hdr=6000000000203aff${src_ip}${dst_ip} +- request=3333ff000010${eth_src}86dd${ip6_hdr}8700357600000000${ta}0101${eth_src} ++ request=3333ff000010${eth_src}86dd${ip6_hdr}870051f400000000${ta}0101${eth_src} + + echo $request + } +@@ -14325,6 +14326,8 @@ router_mac1=000002010203 + router_ip=$(ip_to_hex 172 16 1 1) + router_ip6=20020000000000000000000000000001 + ++nd_src_ip6=fe80000000000000020002fffe010203 ++ + dst_mac=001122334455 + dst_ip=$(ip_to_hex 172 16 1 10) + dst_ip6=20020000000000000000000000000010 +@@ -14342,7 +14345,7 @@ nd_ip=ff0200000000000000000001ff000010 + ip6_hdr=6000000000083afe${src_ip6}${dst_ip6} + + send_icmp6_packet 1 1 $src_mac $router_mac0 $src_ip6 $dst_ip6 +-echo $(get_nd $router_mac1 $src_ip6 $nd_ip $dst_ip6) >> expected ++echo $(get_nd $router_mac1 $nd_src_ip6 $nd_ip $dst_ip6) >> expected + echo "${dst_mac}${router_mac1}86dd${ip6_hdr}8000dcb662f00001" >> expected + send_na 2 1 $dst_mac $router_mac1 $dst_ip6 $router_ip6 + diff --git a/SOURCES/0001-northd-By-pass-IPv6-Router-Adv-and-Router-Solicitati.patch b/SOURCES/0001-northd-By-pass-IPv6-Router-Adv-and-Router-Solicitati.patch new file mode 100644 index 0000000..2352aab --- /dev/null +++ b/SOURCES/0001-northd-By-pass-IPv6-Router-Adv-and-Router-Solicitati.patch @@ -0,0 +1,65 @@ +From d64f501d787571a50eb2e5380947d1d0a3e2ca74 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Thu, 11 Jun 2020 18:44:41 +0530 +Subject: [PATCH] northd: By pass IPv6 Router Adv and Router Solicitation + packets from ACL stages. + +We already add below logical flows to by pass IPv6 Neighbor discovery packets +from in/out ACL stage. + +table=6 (ls_in_acl ), priority=65535, match=(nd), action=(next;) +table=4 (ls_out_acl ), priority=65535, match=(nd), action=(next;) + +This patch also adds nd_rs and nd_ra to these logical flows. Without these +the IPv6 Router Adv packets generated by ovn-controller are dropped if +CMS has configured ACLs. + +Reported-by: Jakub Libosvar +Signed-off-by: Numan Siddique +Acked-by: Mark Michelson + +(cherry-picked from upstream master commit 90e5971018277ab0f383a56f59ffcfe17466a2c6) + +Change-Id: I33fcb3032fe946f2b2333a8cf2791af75dceaf44 +--- + northd/ovn-northd.8.xml | 6 ++++++ + northd/ovn-northd.c | 6 ++++-- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index dc56de273..081536ab4 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -439,6 +439,12 @@ + ACL re-allow this connection. +
  • + ++
  • ++ A priority-65535 flow that allows IPv6 Neighbor solicitation, ++ Neighbor discover, Router solicitation and Router advertisement ++ packets. ++
  • ++ +
  • + A priority 34000 logical flow is added for each logical switch datapath + with the match eth.dst = E to allow the service +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index cffe3de17..fc250318f 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -5390,8 +5390,10 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, + /* Ingress and Egress ACL Table (Priority 65535). + * + * Not to do conntrack on ND packets. */ +- ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, "nd", "next;"); +- ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, "nd", "next;"); ++ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX, ++ "nd || nd_ra || nd_rs", "next;"); ++ ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX, ++ "nd || nd_ra || nd_rs", "next;"); + } + + /* Ingress or Egress ACL Table (Various priorities). */ +-- +2.26.2 + diff --git a/SOURCES/0001-northd-do-not-insert-identical-lflows-in-S_ROUTER_IN.patch b/SOURCES/0001-northd-do-not-insert-identical-lflows-in-S_ROUTER_IN.patch new file mode 100644 index 0000000..d000815 --- /dev/null +++ b/SOURCES/0001-northd-do-not-insert-identical-lflows-in-S_ROUTER_IN.patch @@ -0,0 +1,85 @@ +From 5f3e15c3d5809134d70892b4f65031e5bd110c8f Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Wed, 11 Mar 2020 17:41:59 +0100 +Subject: [PATCH 1/2] northd: do not insert identical lflows in + S_ROUTER_IN_ARP_RESOLVE + +Avoid to configure multiple identical logical flows in +S_ROUTER_IN_ARP_RESOLVE stage. This can happen adding L2 destination +address info about snat since multiple nat entries will use the same +external_ip + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique + +(cherry picked from upstream OVS branch20.03 commit 20aa8c3c5a1930805a32ec8121affa07b2ac7dff) + +Change-Id: Ic5c1df529363469092a55454fdfbcae31a06ccf5 +--- + northd/ovn-northd.c | 36 ++++++++++++++++++++++-------------- + 1 file changed, 22 insertions(+), 14 deletions(-) + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 787ca2f80..cdaeff401 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -8630,6 +8630,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + continue; + } + ++ struct sset nat_entries = SSET_INITIALIZER(&nat_entries); ++ + struct v46_ip snat_ip, lb_snat_ip; + const char *dnat_force_snat_ip = get_force_snat_ip(od, "dnat", + &snat_ip); +@@ -8855,20 +8857,24 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + &nat->header_); + } + +- ds_clear(&match); +- ds_put_format( +- &match, "outport == %s && %s == %s", +- od->l3dgw_port->json_key, +- is_v6 ? "xxreg0" : "reg0", nat->external_ip); +- ds_clear(&actions); +- ds_put_format( +- &actions, "eth.dst = %s; next;", +- distributed ? nat->external_mac : +- od->l3dgw_port->lrp_networks.ea_s); +- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_RESOLVE, +- 100, ds_cstr(&match), +- ds_cstr(&actions), +- &nat->header_); ++ if (!sset_contains(&nat_entries, nat->external_ip)) { ++ ds_clear(&match); ++ ds_put_format( ++ &match, "outport == %s && %s == %s", ++ od->l3dgw_port->json_key, ++ is_v6 ? "xxreg0" : "reg0", nat->external_ip); ++ ds_clear(&actions); ++ ds_put_format( ++ &actions, "eth.dst = %s; next;", ++ distributed ? nat->external_mac : ++ od->l3dgw_port->lrp_networks.ea_s); ++ ovn_lflow_add_with_hint(lflows, od, ++ S_ROUTER_IN_ARP_RESOLVE, ++ 100, ds_cstr(&match), ++ ds_cstr(&actions), ++ &nat->header_); ++ sset_add(&nat_entries, nat->external_ip); ++ } + } + + /* Egress UNDNAT table: It is for already established connections' +@@ -9049,6 +9055,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + } + } + ++ sset_destroy(&nat_entries); ++ + /* Handle force SNAT options set in the gateway router. */ + if (dnat_force_snat_ip && !od->l3dgw_port) { + /* If a packet with destination IP address as that of the +-- +2.25.1 + diff --git a/SOURCES/0001-ofctrl-Split-large-group_mod-messages-up.patch b/SOURCES/0001-ofctrl-Split-large-group_mod-messages-up.patch new file mode 100644 index 0000000..6f7f2ec --- /dev/null +++ b/SOURCES/0001-ofctrl-Split-large-group_mod-messages-up.patch @@ -0,0 +1,161 @@ +From 88056d15bffe67c033322de16c01a013e7bc7c7c Mon Sep 17 00:00:00 2001 +From: Mark Michelson +Date: Wed, 6 May 2020 09:49:55 -0400 +Subject: [PATCH] ofctrl: Split large group_mod messages up. + +Group mod messages have the possibility of growing very large if OVN +installs a load balancer with a great many backends. The current +approach is to send a single ADD message with the entire group contents. +If the size of this message exceeds UINT16_MAX, then OpenFlow cannot +properly express the length of the message since the OpenFlow header's +length is limited to 16 bits. + +This patch solves the problem by breaking the message into pieces. The +first piece is an ADD, and subsequent messages are INSERT_BUCKET +messages. This way, we end up being able to express the entire size of +the group through multiple OpenFlow messages. + +Signed-off-by: Mark Michelson +Acked-by: Numan Siddique +--- + controller/ofctrl.c | 70 ++++++++++++++++++++++++++++++++++++++++++--- + tests/ovn.at | 29 +++++++++++++++++++ + 2 files changed, 95 insertions(+), 4 deletions(-) + +diff --git a/controller/ofctrl.c b/controller/ofctrl.c +index 4b51cd86e..073e076c7 100644 +--- a/controller/ofctrl.c ++++ b/controller/ofctrl.c +@@ -930,10 +930,72 @@ encode_group_mod(const struct ofputil_group_mod *gm) + } + + static void +-add_group_mod(const struct ofputil_group_mod *gm, struct ovs_list *msgs) ++add_group_mod(struct ofputil_group_mod *gm, struct ovs_list *msgs) + { + struct ofpbuf *msg = encode_group_mod(gm); +- ovs_list_push_back(msgs, &msg->list_node); ++ if (msg->size <= UINT16_MAX) { ++ ovs_list_push_back(msgs, &msg->list_node); ++ return; ++ } ++ /* This group mod request is too large to fit in a single OF message ++ * since the header can only specify a 16-bit size. We need to break ++ * this into multiple group_mod requests. ++ */ ++ ++ /* Pull the first bucket. All buckets are approximately the same length ++ * since they contain near-identical actions. Using its length can give ++ * us a good approximation of how many buckets we can fit in a single ++ * OF message. ++ */ ++ ofpraw_pull_assert(msg); ++ struct ofp15_group_mod *ogm = ofpbuf_pull(msg, sizeof(*ogm)); ++ struct ofp15_bucket *of_bucket = ofpbuf_pull(msg, sizeof(*of_bucket)); ++ uint16_t bucket_size = ntohs(of_bucket->len); ++ ++ ofpbuf_delete(msg); ++ ++ /* Dividing by 2 here ensures that just in case there are variations in ++ * the size of the buckets, we will not put too many in our new group_mod ++ * message. ++ */ ++ size_t max_buckets = ((UINT16_MAX - sizeof *ogm) / bucket_size) / 2; ++ ++ ovs_assert(max_buckets < ovs_list_size(&gm->buckets)); ++ ++ uint16_t command = OFPGC15_INSERT_BUCKET; ++ if (gm->command == OFPGC15_DELETE || ++ gm->command == OFPGC15_REMOVE_BUCKET) { ++ command = OFPGC15_REMOVE_BUCKET; ++ } ++ struct ofputil_group_mod split = { ++ .command = command, ++ .type = gm->type, ++ .group_id = gm->group_id, ++ .command_bucket_id = OFPG15_BUCKET_LAST, ++ }; ++ ovs_list_init(&split.buckets); ++ ++ size_t i = 0; ++ struct ofputil_bucket *bucket; ++ LIST_FOR_EACH (bucket, list_node, &gm->buckets) { ++ if (i++ < max_buckets) { ++ continue; ++ } ++ break; ++ } ++ ++ ovs_list_splice(&split.buckets, &bucket->list_node, &gm->buckets); ++ ++ struct ofpbuf *orig = encode_group_mod(gm); ++ ovs_list_push_back(msgs, &orig->list_node); ++ ++ /* We call this recursively just in case our new ++ * INSERT_BUCKET/REMOVE_BUCKET group_mod is still too ++ * large for an OF message. This will allow for it to ++ * be broken into pieces, too. ++ */ ++ add_group_mod(&split, msgs); ++ ofputil_uninit_group_mod(&split); + } + + +@@ -1124,7 +1186,7 @@ ofctrl_put(struct ovn_desired_flow_table *flow_table, + char *group_string = xasprintf("group_id=%"PRIu32",%s", + desired->table_id, + desired->name); +- char *error = parse_ofp_group_mod_str(&gm, OFPGC11_ADD, group_string, ++ char *error = parse_ofp_group_mod_str(&gm, OFPGC15_ADD, group_string, + NULL, NULL, &usable_protocols); + if (!error) { + add_group_mod(&gm, &msgs); +@@ -1243,7 +1305,7 @@ ofctrl_put(struct ovn_desired_flow_table *flow_table, + enum ofputil_protocol usable_protocols; + char *group_string = xasprintf("group_id=%"PRIu32"", + installed->table_id); +- char *error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE, ++ char *error = parse_ofp_group_mod_str(&gm, OFPGC15_DELETE, + group_string, NULL, NULL, + &usable_protocols); + if (!error) { +diff --git a/tests/ovn.at b/tests/ovn.at +index 52d994972..f39fda2e4 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -19179,3 +19179,32 @@ OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [expected]) + + OVN_CLEANUP([hv1]) + AT_CLEANUP ++ ++AT_SETUP([ovn -- Big Load Balancer]) ++ovn_start ++ ++ovn-nbctl ls-add ls1 ++ovn-nbctl lsp-add ls1 lsp1 ++ ++net_add n1 ++sim_add hv1 ++ ++as hv1 ++ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++ovs-vsctl add-port br-int p1 -- set Interface p1 external-ids:iface-id=lsp1 ++ ++IPS=192.169.0.1:80 ++for i in `seq 1 9` ; do ++ for j in `seq 1 254` ; do ++ IPS=${IPS},192.169.$i.$j:80 ++ done ++done ++ ++ovn-nbctl lb-add lb0 172.172.0.1:8080 "${IPS}" ++ovn-nbctl --wait=hv ls-lb-add ls1 lb0 ++ ++AT_CHECK([test 2287 = `ovs-ofctl dump-group-stats br-int | grep -o bucket | wc -l`]) ++ ++OVN_CLEANUP([hv1]) ++AT_CLEANUP +-- +2.25.4 + diff --git a/SOURCES/0001-ovn-controller-Fix-potential-segfault-with-virtual-p.patch b/SOURCES/0001-ovn-controller-Fix-potential-segfault-with-virtual-p.patch new file mode 100644 index 0000000..34b4c29 --- /dev/null +++ b/SOURCES/0001-ovn-controller-Fix-potential-segfault-with-virtual-p.patch @@ -0,0 +1,104 @@ +From 08dfddbe4b1559dd91747cee435eb8945555b348 Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Tue, 31 Mar 2020 13:47:04 +0200 +Subject: [PATCH] ovn-controller: Fix potential segfault with "virtual" port + bindings. + +Even though ovn-controller tries to set port_binding->chassis to NULL +every time port_binding->virtual_parent is set to NULL for bindings of +type="virtual", there's no way to enforce that an operator doesn't +manually clear the "virtual_parent" column in the Southbound database. + +In such scenario ovn-controller would crash because of trying to +dereference the NULL port_binding->virtual_parent column. + +Add an extra check and release "virtual" port bindings that have +"virtual_parent" NULL. + +Reported-at: https://bugzilla.redhat.com/1818844 +CC: Numan Siddique +Fixes: 054f4c85c413 ("Add a new logical switch port type - 'virtual'") +Signed-off-by: Dumitru Ceara +Signed-off-by: Numan Siddique +(cherry picked from upstream commit 5b3e9879be2b6c9b07ed5c9e073f1c24080a49f7) + +Change-Id: I10c2a8dd3731b34f606c4fa2db42711c81f431cc +--- + controller/binding.c | 26 +++++++++++++++----------- + tests/ovn.at | 18 ++++++++++++++++++ + 2 files changed, 33 insertions(+), 11 deletions(-) + +diff --git a/controller/binding.c b/controller/binding.c +index c3376e2..5ea12a8 100644 +--- a/controller/binding.c ++++ b/controller/binding.c +@@ -625,22 +625,26 @@ consider_local_virtual_port(struct ovsdb_idl_index *sbrec_port_binding_by_name, + const struct sbrec_chassis *chassis_rec, + const struct sbrec_port_binding *binding_rec) + { ++ if (binding_rec->virtual_parent) { ++ const struct sbrec_port_binding *parent = ++ lport_lookup_by_name(sbrec_port_binding_by_name, ++ binding_rec->virtual_parent); ++ if (parent && parent->chassis == chassis_rec) { ++ return; ++ } ++ } ++ + /* pinctrl module takes care of binding the ports of type 'virtual'. + * Release such ports if their virtual parents are no longer claimed by + * this chassis. + */ +- const struct sbrec_port_binding *parent = +- lport_lookup_by_name(sbrec_port_binding_by_name, +- binding_rec->virtual_parent); +- if (!parent || parent->chassis != chassis_rec) { +- VLOG_INFO("Releasing lport %s from this chassis.", +- binding_rec->logical_port); +- if (binding_rec->encap) { +- sbrec_port_binding_set_encap(binding_rec, NULL); +- } +- sbrec_port_binding_set_chassis(binding_rec, NULL); +- sbrec_port_binding_set_virtual_parent(binding_rec, NULL); ++ VLOG_INFO("Releasing lport %s from this chassis.", ++ binding_rec->logical_port); ++ if (binding_rec->encap) { ++ sbrec_port_binding_set_encap(binding_rec, NULL); + } ++ sbrec_port_binding_set_chassis(binding_rec, NULL); ++ sbrec_port_binding_set_virtual_parent(binding_rec, NULL); + } + + static void +diff --git a/tests/ovn.at b/tests/ovn.at +index 9a44f0a..1402fae 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -15007,6 +15007,24 @@ AT_CHECK([cat lflows.txt], [0], [dnl + table=12(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-sw0" && reg0 == 10.0.0.10), action=(eth.dst = 50:54:00:00:00:03; next;) + ]) + ++# Forcibly clear virtual_parent. ovn-controller should release the binding ++# gracefully. ++pb_uuid=$(ovn-sbctl --bare --columns _uuid find port_binding logical_port=sw0-vir) ++ovn-sbctl clear port_binding $pb_uuid virtual_parent ++ ++OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \ ++logical_port=sw0-vir) = x]) ++ ++# From sw0-p0 resend GARP for 10.0.0.10. hv1 should reclaim sw0-vir ++# and sw0-p1 should be its virtual_parent. ++send_garp 1 1 $eth_src $eth_dst $spa $tpa ++ ++OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \ ++logical_port=sw0-vir) = x$hv1_ch_uuid], [0], []) ++ ++AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \ ++logical_port=sw0-vir) = xsw0-p1]) ++ + # From sw0-p3 send GARP for 10.0.0.10. hv1 should claim sw0-vir + # and sw0-p3 should be its virtual_parent. + eth_src=505400000005 +-- +1.8.3.1 + diff --git a/SOURCES/0001-ovn-controller-Skip-vport-bindings-done-through-OVS-.patch b/SOURCES/0001-ovn-controller-Skip-vport-bindings-done-through-OVS-.patch new file mode 100644 index 0000000..85088c5 --- /dev/null +++ b/SOURCES/0001-ovn-controller-Skip-vport-bindings-done-through-OVS-.patch @@ -0,0 +1,90 @@ +From a8acc52e37d5a74487b0a787bf8a519debc3a031 Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Thu, 2 Apr 2020 10:35:32 +0200 +Subject: [PATCH] ovn-controller: Skip vport bindings done through OVS + external_ids:iface-id. + +Port bindings of type "virtual" should not have an associated OVS port +in the integration bridge. If this is the case, it's a misconfig and +ovn-controller should ignore it. + +If such a situation is detected, ovn-controller will also log a warning +message to inform the user about the wrong configuration. + +Reported-at: https://bugzilla.redhat.com/1818844 +CC: Numan Siddique +Fixes: 054f4c85c413 ("Add a new logical switch port type - 'virtual'") +Signed-off-by: Dumitru Ceara +Signed-off-by: Numan Siddique +(cherry picked from upstream commit 523b1f5f45682bd6dd454281a97a09c3f429c457) + +Change-Id: Ie35818921a6e67c637feaea3be41c59880bb1b96 +--- + controller/binding.c | 12 ++++++++++++ + tests/ovn.at | 20 ++++++++++++++++++++ + 2 files changed, 32 insertions(+) + +diff --git a/controller/binding.c b/controller/binding.c +index 5ea12a8..20a89d0 100644 +--- a/controller/binding.c ++++ b/controller/binding.c +@@ -447,6 +447,18 @@ is_our_chassis(const struct sbrec_chassis *chassis_rec, + const struct ovsrec_interface *iface_rec + = shash_find_data(lport_to_iface, binding_rec->logical_port); + ++ /* Ports of type "virtual" should never be explicitly bound to an OVS ++ * port in the integration bridge. If that's the case, ignore the binding ++ * and log a warning. ++ */ ++ if (iface_rec && !strcmp(binding_rec->type, "virtual")) { ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); ++ VLOG_WARN_RL(&rl, ++ "Virtual port %s should not be bound to OVS port %s", ++ binding_rec->logical_port, iface_rec->name); ++ return false; ++ } ++ + bool our_chassis = false; + if (iface_rec + || (binding_rec->parent_port && binding_rec->parent_port[0] && +diff --git a/tests/ovn.at b/tests/ovn.at +index 0135838..e8554f6 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -14894,6 +14894,11 @@ ovs-vsctl -- add-port br-int hv1-vif2 -- \ + options:tx_pcap=hv1/vif2-tx.pcap \ + options:rxq_pcap=hv1/vif2-rx.pcap \ + ofport-request=2 ++ovs-vsctl -- add-port br-int hv1-vif3 -- \ ++ set interface hv1-vif3 \ ++ options:tx_pcap=hv1/vif3-tx.pcap \ ++ options:rxq_pcap=hv1/vif3-rx.pcap \ ++ ofport-request=3 + + sim_add hv2 + as hv2 +@@ -14987,6 +14992,21 @@ logical_port=sw0-vir) = x], [0], []) + AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \ + logical_port=sw0-vir) = x]) + ++# Try to bind sw0-vir directly to an OVS port. This should be ignored by ++# ovn-controller. ++as hv1 ++ovs-vsctl set interface hv1-vif3 external-ids:iface-id=sw0-vir ++ ++AT_CHECK([test x$(ovn-sbctl --bare --columns chassis find port_binding \ ++logical_port=sw0-vir) = x], [0], []) ++ ++# Cleanup hv1-vif3. ++as hv1 ++ovs-vsctl del-port hv1-vif3 ++ ++AT_CHECK([test x$(ovn-sbctl --bare --columns chassis find port_binding \ ++logical_port=sw0-vir) = x], [0], []) ++ + # From sw0-p0 send GARP for 10.0.0.10. hv1 should claim sw0-vir + # and sw0-p1 should be its virtual_parent. + eth_src=505400000003 +-- +1.8.3.1 + diff --git a/SOURCES/0001-ovn-ctl-Provide-the-option-to-configure-inactive-pro.patch b/SOURCES/0001-ovn-ctl-Provide-the-option-to-configure-inactive-pro.patch new file mode 100644 index 0000000..8f7266e --- /dev/null +++ b/SOURCES/0001-ovn-ctl-Provide-the-option-to-configure-inactive-pro.patch @@ -0,0 +1,182 @@ +From 1a34ed1dee90ad3ae82d91725bf8f5e86cf007c6 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Mon, 17 Feb 2020 11:23:45 +0530 +Subject: [PATCH] ovn-ctl: Provide the option to configure inactive probe from + standby to active. + +Recently ovsdb-server supported an unixctl command - +ovsdb-server/set-active-ovsdb-server-probe-interval to configure inactive probe +interval from standby connection to the active. This patch provides the +option to configure this from ovn-ctl and the pacemaker OVN OCF script. + +Signed-off-by: Numan Siddique +Acked-by: Han Zhou +--- + utilities/ovn-ctl | 14 +++++++++++--- + utilities/ovn-ctl.8.xml | 8 ++++++-- + utilities/ovndb-servers.ocf | 23 +++++++++++++++++++---- + 3 files changed, 36 insertions(+), 9 deletions(-) + +diff --git a/utilities/ovn-ctl b/utilities/ovn-ctl +index c7cb42bc1..2a337ae27 100755 +--- a/utilities/ovn-ctl ++++ b/utilities/ovn-ctl +@@ -82,7 +82,8 @@ demote_xx_ovsdb () { + local sync_from_proto=$2 + local sync_from_port=$3 + local active_conf_file=$4 +- local ctl_file=$5 ++ local inactive_probe_to_active=$5 ++ local ctl_file=$6 + + if test ! -z "$sync_from_addr"; then + echo "$sync_from_proto:$sync_from_addr:$sync_from_port" > $active_conf_file +@@ -91,6 +92,7 @@ demote_xx_ovsdb () { + if test -e $active_conf_file; then + ovn-appctl -t $OVN_RUNDIR/$ctl_file ovsdb-server/set-active-ovsdb-server `cat $active_conf_file` + ovn-appctl -t $OVN_RUNDIR/$ctl_file ovsdb-server/connect-active-ovsdb-server ++ ovn-appctl -t $OVN_RUNDIR/$ctl_file ovsdb-server/set-active-ovsdb-server-probe-interval $inactive_probe_to_active + else + echo >&2 "$0: active server details not set" + exit 1 +@@ -99,12 +101,14 @@ demote_xx_ovsdb () { + + demote_ovnnb() { + demote_xx_ovsdb $DB_NB_SYNC_FROM_ADDR $DB_NB_SYNC_FROM_PROTO \ +- $DB_NB_SYNC_FROM_PORT $ovnnb_active_conf_file ovnnb_db.ctl ++ $DB_NB_SYNC_FROM_PORT $ovnnb_active_conf_file \ ++ $DB_NB_PROBE_INTERVAL_TO_ACTIVE ovnnb_db.ctl + } + + demote_ovnsb() { + demote_xx_ovsdb $DB_SB_SYNC_FROM_ADDR $DB_SB_SYNC_FROM_PROTO \ +- $DB_SB_SYNC_FROM_PORT $ovnsb_active_conf_file ovnsb_db.ctl ++ $DB_SB_SYNC_FROM_PORT $ovnsb_active_conf_file \ ++ $DB_SB_PROBE_INTERVAL_TO_ACTIVE ovnsb_db.ctl + } + + demote_ic_nb() { +@@ -642,6 +646,7 @@ set_defaults () { + DB_NB_SYNC_FROM_PROTO=tcp + DB_NB_SYNC_FROM_ADDR= + DB_NB_SYNC_FROM_PORT=6641 ++ DB_NB_PROBE_INTERVAL_TO_ACTIVE=60000 + + DB_SB_SOCK=$OVN_RUNDIR/ovnsb_db.sock + DB_SB_PID=$OVN_RUNDIR/ovnsb_db.pid +@@ -652,6 +657,7 @@ set_defaults () { + DB_SB_SYNC_FROM_PROTO=tcp + DB_SB_SYNC_FROM_ADDR= + DB_SB_SYNC_FROM_PORT=6642 ++ DB_SB_PROBE_INTERVAL_TO_ACTIVE=60000 + + DB_IC_NB_SOCK=$OVN_RUNDIR/ovn_ic_nb_db.sock + DB_IC_NB_PID=$OVN_RUNDIR/ovn_ic_nb_db.pid +@@ -923,10 +929,12 @@ File location options: + --db-nb-sync-from-port=PORT OVN Northbound active db tcp port (default: $DB_NB_SYNC_FROM_PORT) + --db-nb-sync-from-proto=PROTO OVN Northbound active db transport (default: $DB_NB_SYNC_FROM_PROTO) + --db-nb-create-insecure-remote=yes|no Create ptcp OVN Northbound remote (default: $DB_NB_CREATE_INSECURE_REMOTE) ++ --db-nb-probe-interval-to-active Active probe interval from standby to active ovsdb-server remote (default: $DB_NB_PROBE_INTERVAL_TO_ACTIVE) + --db-sb-sync-from-addr=ADDR OVN Southbound active db tcp address (default: $DB_SB_SYNC_FROM_ADDR) + --db-sb-sync-from-port=ADDR OVN Southbound active db tcp port (default: $DB_SB_SYNC_FROM_PORT) + --db-sb-sync-from-proto=PROTO OVN Southbound active db transport (default: $DB_SB_SYNC_FROM_PROTO) + --db-sb-create-insecure-remote=yes|no Create ptcp OVN Southbound remote (default: $DB_SB_CREATE_INSECURE_REMOTE) ++ --db-sb-probe-interval-to-active Active probe interval from standby to active ovsdb-server remote (default: $DB_SB_PROBE_INTERVAL_TO_ACTIVE) + --db-nb-cluster-local-addr=ADDR OVN_Northbound cluster local address \ + (default: $DB_NB_CLUSTER_LOCAL_ADDR) + --db-nb-cluster-local-port=PORT OVN_Northbound cluster local tcp port \ +diff --git a/utilities/ovn-ctl.8.xml b/utilities/ovn-ctl.8.xml +index 816701379..f5b7f7aeb 100644 +--- a/utilities/ovn-ctl.8.xml ++++ b/utilities/ovn-ctl.8.xml +@@ -150,6 +150,10 @@ +

    --db-ic-sb-cluster-remote-port=PORT NUMBER

    +

    --db-ic-sb-cluster-remote-proto=PROTO (tcp/ssl)

    + ++

    Probe interval options

    ++

    --db-nb-probe-interval-to-active=Time in milliseconds

    ++

    --db-sb-probe-interval-to-active=Time in milliseconds

    ++ +

    Configuration files

    +

    Following are the optional configuration files. If present, it should be located in the etc dir

    + +@@ -241,8 +245,8 @@ +

    Promote and demote ovsdb servers

    +

    # ovn-ctl promote_ovnnb

    +

    # ovn-ctl promote_ovnsb

    +-

    # ovn-ctl --db-nb-sync-from-addr=x.x.x.x --db-nb-sync-from-port=6641 demote_ovnnb

    +-

    # ovn-ctl --db-sb-sync-from-addr=x.x.x.x --db-sb-sync-from-port=6642 demote_ovnsb

    ++

    # ovn-ctl --db-nb-sync-from-addr=x.x.x.x --db-nb-sync-from-port=6641 --db-nb-probe-interval-to-active=60000 demote_ovnnb

    ++

    # ovn-ctl --db-sb-sync-from-addr=x.x.x.x --db-sb-sync-from-port=6642 --db-sb-probe-interval-to-active=60000 demote_ovnsb

    + +

    Creating a clustered db on 3 nodes with IPs x.x.x.x, y.y.y.y and z.z.z.z

    +

    Starting OVN ovsdb servers and ovn-northd on the node with IP x.x.x.x

    +diff --git a/utilities/ovndb-servers.ocf b/utilities/ovndb-servers.ocf +index 42e0412ad..56c2bc322 100755 +--- a/utilities/ovndb-servers.ocf ++++ b/utilities/ovndb-servers.ocf +@@ -9,6 +9,7 @@ + : ${SB_MASTER_PROTO_DEFAULT="tcp"} + : ${MANAGE_NORTHD_DEFAULT="no"} + : ${INACTIVE_PROBE_DEFAULT="5000"} ++: ${INACTIVE_PROBE_TO_MASTER_DEFAULT="60000"} + : ${LISTEN_ON_MASTER_IP_ONLY_DEFAULT="yes"} + : ${NB_SSL_KEY_DEFAULT="/etc/openvswitch/ovnnb-privkey.pem"} + : ${NB_SSL_CERT_DEFAULT="/etc/openvswitch/ovnnb-cert.pem"} +@@ -27,6 +28,7 @@ SB_MASTER_PORT=${OCF_RESKEY_sb_master_port:-${SB_MASTER_PORT_DEFAULT}} + SB_MASTER_PROTO=${OCF_RESKEY_sb_master_protocol:-${SB_MASTER_PROTO_DEFAULT}} + MANAGE_NORTHD=${OCF_RESKEY_manage_northd:-${MANAGE_NORTHD_DEFAULT}} + INACTIVE_PROBE=${OCF_RESKEY_inactive_probe_interval:-${INACTIVE_PROBE_DEFAULT}} ++INACTIVE_PROBE_TO_MASTER=${OCF_RESKEY_inactive_probe_interval_to_master:-${INACTIVE_PROBE_TO_MASTER_DEFAULT}} + NB_PRIVKEY=${OCF_RESKEY_ovn_nb_db_privkey:-${NB_SSL_KEY_DEFAULT}} + NB_CERT=${OCF_RESKEY_ovn_nb_db_cert:-${NB_SSL_CERT_DEFAULT}} + NB_CACERT=${OCF_RESKEY_ovn_nb_db_cacert:-${NB_SSL_CACERT_DEFAULT}} +@@ -135,6 +137,15 @@ ovsdb_server_metadata() { + + + ++ ++ ++ Inactive probe interval to use for the connection from standby ++ ovsdb-server to master ovsdb-server. ++ ++ Set inactive probe interval to master ++ ++ ++ + + + If set to yes, the OVNDBs will listen on master IP. Otherwise, it will +@@ -266,10 +277,12 @@ inactivity_probe=$INACTIVE_PROBE -- set SB_Global . connections=@conn_uuid + ocf_log debug "ovndb_server: Connecting to the new master ${OCF_RESKEY_CRM_meta_notify_promote_uname}" + ${OVN_CTL} demote_ovnnb --db-nb-sync-from-addr=${MASTER_IP} \ + --db-nb-sync-from-port=${NB_MASTER_PORT} \ +- --db-nb-sync-from-proto=${NB_MASTER_PROTO} ++ --db-nb-sync-from-proto=${NB_MASTER_PROTO} \ ++ --db-nb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER} + ${OVN_CTL} demote_ovnsb --db-sb-sync-from-addr=${MASTER_IP} \ + --db-sb-sync-from-port=${SB_MASTER_PORT} \ +- --db-sb-sync-from-proto=${SB_MASTER_PROTO} ++ --db-sb-sync-from-proto=${SB_MASTER_PROTO} \ ++ --db-sb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER} + fi + } + +@@ -596,10 +609,12 @@ ovsdb_server_demote() { + # being demoted. Sync to the surviving one + ${OVN_CTL} demote_ovnnb --db-nb-sync-from-addr=${MASTER_IP} \ + --db-nb-sync-from-port=${NB_MASTER_PORT} \ +- --db-nb-sync-from-proto=${NB_MASTER_PROTO} ++ --db-nb-sync-from-proto=${NB_MASTER_PROTO} \ ++ --db-nb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER} + ${OVN_CTL} demote_ovnsb --db-sb-sync-from-addr=${MASTER_IP} \ + --db-sb-sync-from-port=${SB_MASTER_PORT} \ +- --db-sb-sync-from-proto=${SB_MASTER_PROTO} ++ --db-sb-sync-from-proto=${SB_MASTER_PROTO} \ ++ --db-sb-probe-interval-to-active=${INACTIVE_PROBE_TO_MASTER} + + else + # For completeness, should never be called +-- +2.25.1 + diff --git a/SOURCES/0001-ovn-nbctl-Create-daemon-control-socket-in-ovn-run-di.patch b/SOURCES/0001-ovn-nbctl-Create-daemon-control-socket-in-ovn-run-di.patch new file mode 100644 index 0000000..999a5dc --- /dev/null +++ b/SOURCES/0001-ovn-nbctl-Create-daemon-control-socket-in-ovn-run-di.patch @@ -0,0 +1,180 @@ +From 0319176e1d1fa741868d822100d0dde89a585ca3 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Wed, 8 Apr 2020 20:16:49 +0530 +Subject: [PATCH] ovn-nbctl: Create daemon control socket in ovn run dir + +ovn-nbctl when run as a daemon is creating the ctl socket in +the ovs rundir. This patch fixes this issue by creating it in +the ovn rundir. + +When an ovn service is run with -u option (which specifies the +ctl socket path) and if this path is not absolute, the ovn +ctl socket path is created in the ovs run dir. This patch +also fixes this issue by creating it in the ovn run dir. + +Reported-by: Dan Williams +Acked-by: Dumitru Ceara +Signed-off-by: Numan Siddique + +(cherry-picked from upstream branch-20.03 commit 29927708242044696a49051c77c3d4b38ba02392) + +Change-Id: I17b3ab45f591fa9793ae8d95cf78c2113a1e4d65 +--- + controller-vtep/ovn-controller-vtep.c | 5 ++++- + controller/ovn-controller.c | 2 +- + ic/ovn-ic.c | 10 +++------- + lib/ovn-util.c | 9 +++++---- + lib/ovn-util.h | 2 +- + northd/ovn-northd.c | 10 +++------- + utilities/ovn-nbctl.c | 6 +++++- + utilities/ovn-trace.c | 6 +++++- + 8 files changed, 27 insertions(+), 23 deletions(-) + +diff --git a/controller-vtep/ovn-controller-vtep.c b/controller-vtep/ovn-controller-vtep.c +index b30a731d4..253a709ab 100644 +--- a/controller-vtep/ovn-controller-vtep.c ++++ b/controller-vtep/ovn-controller-vtep.c +@@ -67,7 +67,10 @@ main(int argc, char *argv[]) + + daemonize_start(false); + +- retval = unixctl_server_create(NULL, &unixctl); ++ char *abs_unixctl_path = get_abs_unix_ctl_path(NULL); ++ retval = unixctl_server_create(abs_unixctl_path, &unixctl); ++ free(abs_unixctl_path); ++ + if (retval) { + exit(EXIT_FAILURE); + } +diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c +index 2893eaac1..4d21ba0fd 100644 +--- a/controller/ovn-controller.c ++++ b/controller/ovn-controller.c +@@ -1729,7 +1729,7 @@ main(int argc, char *argv[]) + + daemonize_start(true); + +- char *abs_unixctl_path = get_abs_unix_ctl_path(); ++ char *abs_unixctl_path = get_abs_unix_ctl_path(NULL); + retval = unixctl_server_create(abs_unixctl_path, &unixctl); + free(abs_unixctl_path); + if (retval) { +diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c +index bf8205de2..d931ca50f 100644 +--- a/ic/ovn-ic.c ++++ b/ic/ovn-ic.c +@@ -1575,13 +1575,9 @@ main(int argc, char *argv[]) + + daemonize_start(false); + +- if (!unixctl_path) { +- char *abs_unixctl_path = get_abs_unix_ctl_path(); +- retval = unixctl_server_create(abs_unixctl_path, &unixctl); +- free(abs_unixctl_path); +- } else { +- retval = unixctl_server_create(unixctl_path, &unixctl); +- } ++ char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path); ++ retval = unixctl_server_create(abs_unixctl_path, &unixctl); ++ free(abs_unixctl_path); + + if (retval) { + exit(EXIT_FAILURE); +diff --git a/lib/ovn-util.c b/lib/ovn-util.c +index df18fda89..514e2489f 100644 +--- a/lib/ovn-util.c ++++ b/lib/ovn-util.c +@@ -377,7 +377,7 @@ default_ic_sb_db(void) + } + + char * +-get_abs_unix_ctl_path(void) ++get_abs_unix_ctl_path(const char *path) + { + #ifdef _WIN32 + enum { WINDOWS = 1 }; +@@ -386,9 +386,10 @@ get_abs_unix_ctl_path(void) + #endif + + long int pid = getpid(); +- char *abs_path = +- WINDOWS ? xasprintf("%s/%s.ctl", ovn_rundir(), program_name) +- : xasprintf("%s/%s.%ld.ctl", ovn_rundir(), program_name, pid); ++ char *abs_path ++ = (path ? abs_file_name(ovn_rundir(), path) ++ : WINDOWS ? xasprintf("%s/%s.ctl", ovn_rundir(), program_name) ++ : xasprintf("%s/%s.%ld.ctl", ovn_rundir(), program_name, pid)); + return abs_path; + } + +diff --git a/lib/ovn-util.h b/lib/ovn-util.h +index 32c8334b0..11238f61c 100644 +--- a/lib/ovn-util.h ++++ b/lib/ovn-util.h +@@ -82,7 +82,7 @@ const char *default_nb_db(void); + const char *default_sb_db(void); + const char *default_ic_nb_db(void); + const char *default_ic_sb_db(void); +-char *get_abs_unix_ctl_path(void); ++char *get_abs_unix_ctl_path(const char *path); + + struct ovsdb_idl_table_class; + const char *db_table_usage(struct ds *tables, +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index fd1be5b27..1f1238d23 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -11673,13 +11673,9 @@ main(int argc, char *argv[]) + + daemonize_start(false); + +- if (!unixctl_path) { +- char *abs_unixctl_path = get_abs_unix_ctl_path(); +- retval = unixctl_server_create(abs_unixctl_path, &unixctl); +- free(abs_unixctl_path); +- } else { +- retval = unixctl_server_create(unixctl_path, &unixctl); +- } ++ char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path); ++ retval = unixctl_server_create(abs_unixctl_path, &unixctl); ++ free(abs_unixctl_path); + + if (retval) { + exit(EXIT_FAILURE); +diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c +index 59abe0051..a88c1ddc2 100644 +--- a/utilities/ovn-nbctl.c ++++ b/utilities/ovn-nbctl.c +@@ -6436,7 +6436,11 @@ server_loop(struct ovsdb_idl *idl, int argc, char *argv[]) + + service_start(&argc, &argv); + daemonize_start(false); +- int error = unixctl_server_create(unixctl_path, &server); ++ ++ char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path); ++ int error = unixctl_server_create(abs_unixctl_path, &server); ++ free(abs_unixctl_path); ++ + if (error) { + ctl_fatal("failed to create unixctl server (%s)", + ovs_retval_to_string(error)); +diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c +index e59698ec4..eae9622d3 100644 +--- a/utilities/ovn-trace.c ++++ b/utilities/ovn-trace.c +@@ -125,7 +125,11 @@ main(int argc, char *argv[]) + bool exiting = false; + if (get_detach()) { + daemonize_start(false); +- int error = unixctl_server_create(unixctl_path, &server); ++ ++ char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path); ++ int error = unixctl_server_create(abs_unixctl_path, &server); ++ free(abs_unixctl_path); ++ + if (error) { + ovs_fatal(error, "failed to create unixctl server"); + } +-- +2.25.1 + diff --git a/SOURCES/0001-ovn-northd-Add-lflows-to-by-pass-the-svc-monitor-pac.patch b/SOURCES/0001-ovn-northd-Add-lflows-to-by-pass-the-svc-monitor-pac.patch new file mode 100644 index 0000000..5e35cab --- /dev/null +++ b/SOURCES/0001-ovn-northd-Add-lflows-to-by-pass-the-svc-monitor-pac.patch @@ -0,0 +1,197 @@ +From 8e0b2c54726c666db7163dd18673683dfd06d89c Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Thu, 12 Mar 2020 15:58:38 +0530 +Subject: [PATCH] ovn-northd: Add lflows to by pass the svc monitor packets + from conntrack. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The commit [1] added lflows to by pass the service monitor health check +packets from conntrack. But it missed out adding in the ingress pre_acl +and egress pre_acl of logical switch pipeline. + +This patch adds these missing lflows. It also enhanced the system lb health +check tests to add the acls to test this scenario. + +[1] - bb9f2b9ce56c("ovn-northd: Consider load balancer active backends in router pipeline) +Fixes: bb9f2b9ce56c("ovn-northd: Consider load balancer active backends in router pipeline) + +Reported-by: Maciej Józefczyk +Acked-by: Dumitru Ceara +Acked-by: Maciej Jozefczyk +Signed-off-by: Numan Siddique + +(cherry-picked from upstream branch-20.03 commit f70a0f7c485f13cbbae8bc6f8d78225238c308b9) + +Change-Id: I8980d306ea67c2aaa3bfa8f907a0f71a55fe0f9d +--- + northd/ovn-northd.8.xml | 22 +++++++++++++++++++++- + northd/ovn-northd.c | 15 ++++++++++++++- + tests/ovn.at | 22 ++++++++++++++++++++++ + tests/system-ovn.at | 22 ++++++++++++++++++++++ + 4 files changed, 79 insertions(+), 2 deletions(-) + +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index b6cfa3e90..9b44720d1 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -293,6 +293,16 @@ + priority-110 flow is added to skip over stateful ACLs. +

    + ++

    ++ This table also has a priority-110 flow with the match ++ eth.dst == E for all logical switch ++ datapaths to move traffic to the next table. Where E ++ is the service monitor mac defined in the ++ colum of table. ++

    ++ +

    Ingress Table 4: Pre-LB

    + +

    +@@ -320,7 +330,7 @@ + +

    + This table also has a priority-110 flow with the match +- eth.src == E for all logical switch ++ eth.dst == E for all logical switch + datapaths to move traffic to the next table. Where E + is the service monitor mac defined in the + to-lport traffic. +

    + ++

    ++ This table also has a priority-110 flow with the match ++ eth.src == E for all logical switch ++ datapaths to move traffic to the next table. Where E ++ is the service monitor mac defined in the ++ colum of table. ++

    ++ +

    Egress Table 2: Pre-stateful

    + +

    +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 217a8c894..3a77f2e3a 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -4601,6 +4601,16 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 0, "1", "next;"); + ++ char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac); ++ ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, svc_check_match, ++ "next;"); ++ free(svc_check_match); ++ ++ svc_check_match = xasprintf("eth.src == %s", svc_monitor_mac); ++ ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, svc_check_match, ++ "next;"); ++ free(svc_check_match); ++ + /* If there are any stateful ACL rules in this datapath, we must + * send all IP packets through the conntrack action, which handles + * defragmentation, in order to match L4 headers. */ +@@ -4784,9 +4794,12 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows, + "next;"); + + /* Do not send service monitor packets to conntrack. */ +- char *svc_check_match = xasprintf("eth.src == %s", svc_monitor_mac); ++ char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac); + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 110, + svc_check_match, "next;"); ++ free(svc_check_match); ++ ++ svc_check_match = xasprintf("eth.src == %s", svc_monitor_mac); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 110, + svc_check_match, "next;"); + free(svc_check_match); +diff --git a/tests/ovn.at b/tests/ovn.at +index 8de4b5ceb..8cdbad743 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -17739,12 +17739,34 @@ ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3" + ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4" + ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4" + ++# Create port group and ACLs for sw0 ports. ++ovn-nbctl pg-add pg0_drop sw0-p1 sw0-p2 ++ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop ++ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop ++ ++ovn-nbctl pg-add pg0 sw0-p1 sw0-p2 ++ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 80" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 80" allow-related ++ + # Create the second logical switch with one port + ovn-nbctl ls-add sw1 + ovn-nbctl lsp-add sw1 sw1-p1 + ovn-nbctl lsp-set-addresses sw1-p1 "40:54:00:00:00:03 20.0.0.3" + ovn-nbctl lsp-set-port-security sw1-p1 "40:54:00:00:00:03 20.0.0.3" + ++# Create port group and ACLs for sw1 ports. ++ovn-nbctl pg-add pg1_drop sw1-p1 ++ovn-nbctl acl-add pg1_drop from-lport 1001 "inport == @pg1_drop && ip" drop ++ovn-nbctl acl-add pg1_drop to-lport 1001 "outport == @pg1_drop && ip" drop ++ ++ovn-nbctl pg-add pg1 sw1-p1 ++ovn-nbctl acl-add pg1 from-lport 1002 "inport == @pg1 && ip4" allow-related ++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related ++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 80" allow-related ++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 80" allow-related ++ + # Create a logical router and attach both logical switches + ovn-nbctl lr-add lr0 + ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index 9ed3df754..3b3379840 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -3314,12 +3314,34 @@ ovn-nbctl lsp-add sw0 sw0-p2 + ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4" + ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4" + ++# Create port group and ACLs for sw0 ports. ++ovn-nbctl pg-add pg0_drop sw0-p1 sw0-p2 ++ovn-nbctl acl-add pg0_drop from-lport 1001 "inport == @pg0_drop && ip" drop ++ovn-nbctl acl-add pg0_drop to-lport 1001 "outport == @pg0_drop && ip" drop ++ ++ovn-nbctl pg-add pg0 sw0-p1 sw0-p2 ++ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 80" allow-related ++ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 80" allow-related ++ + # Create the second logical switch with one port + ovn-nbctl ls-add sw1 + ovn-nbctl lsp-add sw1 sw1-p1 + ovn-nbctl lsp-set-addresses sw1-p1 "40:54:00:00:00:03 20.0.0.3" + ovn-nbctl lsp-set-port-security sw1-p1 "40:54:00:00:00:03 20.0.0.3" + ++# Create port group and ACLs for sw1 ports. ++ovn-nbctl pg-add pg1_drop sw1-p1 ++ovn-nbctl acl-add pg1_drop from-lport 1001 "inport == @pg1_drop && ip" drop ++ovn-nbctl acl-add pg1_drop to-lport 1001 "outport == @pg1_drop && ip" drop ++ ++ovn-nbctl pg-add pg1 sw1-p1 ++ovn-nbctl acl-add pg1 from-lport 1002 "inport == @pg1 && ip4" allow-related ++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && icmp4" allow-related ++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && tcp && tcp.dst == 80" allow-related ++ovn-nbctl acl-add pg1 to-lport 1002 "outport == @pg1 && ip4 && ip4.src == 0.0.0.0/0 && udp && udp.dst == 80" allow-related ++ + # Create a logical router and attach both logical switches + ovn-nbctl lr-add lr0 + ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 +-- +2.24.1 + diff --git a/SOURCES/0001-ovn-northd-Clear-SB-records-depending-on-stale-datap.patch b/SOURCES/0001-ovn-northd-Clear-SB-records-depending-on-stale-datap.patch new file mode 100644 index 0000000..3538655 --- /dev/null +++ b/SOURCES/0001-ovn-northd-Clear-SB-records-depending-on-stale-datap.patch @@ -0,0 +1,189 @@ +From e5b87cf915c0061355f9c4cdea0df1fe1c26cd38 Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Thu, 30 Apr 2020 20:32:17 +0200 +Subject: [PATCH 1/2] ovn-northd: Clear SB records depending on stale + datapaths. + +When purging stale SB Datapath_Binding records ovn-northd doesn't +properly clean records from other tables that might refer the +datapaths being deleted. + +One way to reproduce the issue is: +$ ovn-nbctl lr-add lr +$ ovn-nbctl lrp-add lr p 00:00:00:00:00:01 1.1.1.1/24 +$ ovn-nbctl --wait=sb sync +$ dp=$(ovn-sbctl --bare --columns _uuid list datapath .) +$ ovn-sbctl create mac_binding logical_port="p" ip="1.1.1.2" datapath="$dp" +$ ovn-nbctl lrp-del p -- lr-del lr -- \ + lr-add lr -- lrp-add lr p 00:00:00:00:00:01 1.1.1.1/24 + +Reported-by: Dan Williams +Reported-at: https://bugzilla.redhat.com/1828637 +Signed-off-by: Dumitru Ceara +Acked-by: Numan Siddique +Signed-off-by: Han Zhou +(cherry picked from upstream commit 6856adc616a7181723ce5201110cc95de1aba92b) + +Change-Id: I1cbcb5fc34927368e6655420126b2492c4fce9df +--- + northd/ovn-northd.c | 45 ++++++++++++++++++++++++++++++++------------- + tests/ovn-northd.at | 24 ++++++++++++++++++++++++ + 2 files changed, 56 insertions(+), 13 deletions(-) + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 5ada3ae..5e649d0 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -634,6 +634,12 @@ ovn_datapath_find(struct hmap *datapaths, const struct uuid *uuid) + return NULL; + } + ++static bool ++ovn_datapath_is_stale(const struct ovn_datapath *od) ++{ ++ return !od->nbr && !od->nbs; ++} ++ + static struct ovn_datapath * + ovn_datapath_from_sbrec(struct hmap *datapaths, + const struct sbrec_datapath_binding *sb) +@@ -3067,11 +3073,16 @@ ovn_port_update_sbrec(struct northd_context *ctx, + /* Remove mac_binding entries that refer to logical_ports which are + * deleted. */ + static void +-cleanup_mac_bindings(struct northd_context *ctx, struct hmap *ports) ++cleanup_mac_bindings(struct northd_context *ctx, struct hmap *datapaths, ++ struct hmap *ports) + { + const struct sbrec_mac_binding *b, *n; + SBREC_MAC_BINDING_FOR_EACH_SAFE (b, n, ctx->ovnsb_idl) { +- if (!ovn_port_find(ports, b->logical_port)) { ++ const struct ovn_datapath *od = ++ ovn_datapath_from_sbrec(datapaths, b->datapath); ++ ++ if (!od || ovn_datapath_is_stale(od) || ++ !ovn_port_find(ports, b->logical_port)) { + sbrec_mac_binding_delete(b); + } + } +@@ -3439,6 +3450,9 @@ build_ports(struct northd_context *ctx, + join_logical_ports(ctx, datapaths, ports, &chassis_qdisc_queues, + &tag_alloc_table, &sb_only, &nb_only, &both); + ++ /* Purge stale Mac_Bindings if ports are deleted. */ ++ bool remove_mac_bindings = !ovs_list_is_empty(&sb_only); ++ + struct ovn_port *op, *next; + /* For logical ports that are in both databases, index the in-use + * tunnel_keys. */ +@@ -3453,6 +3467,12 @@ build_ports(struct northd_context *ctx, + * For logical ports that are in NB database, do any tag allocation + * needed. */ + LIST_FOR_EACH_SAFE (op, next, list, &both) { ++ /* When reusing stale Port_Bindings, make sure that stale ++ * Mac_Bindings are purged. ++ */ ++ if (op->od->sb != op->sb->datapath) { ++ remove_mac_bindings = true; ++ } + if (op->nbsp) { + tag_alloc_create_new_tag(&tag_alloc_table, op->nbsp); + } +@@ -3488,19 +3508,15 @@ build_ports(struct northd_context *ctx, + sbrec_port_binding_set_tunnel_key(op->sb, tunnel_key); + } + +- bool remove_mac_bindings = false; +- if (!ovs_list_is_empty(&sb_only)) { +- remove_mac_bindings = true; +- } +- + /* Delete southbound records without northbound matches. */ + LIST_FOR_EACH_SAFE(op, next, list, &sb_only) { + ovs_list_remove(&op->list); + sbrec_port_binding_delete(op->sb); + ovn_port_destroy(ports, op); + } ++ + if (remove_mac_bindings) { +- cleanup_mac_bindings(ctx, ports); ++ cleanup_mac_bindings(ctx, datapaths, ports); + } + + tag_alloc_destroy(&tag_alloc_table); +@@ -10258,7 +10274,8 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths, + SBREC_LOGICAL_FLOW_FOR_EACH_SAFE (sbflow, next_sbflow, ctx->ovnsb_idl) { + struct ovn_datapath *od + = ovn_datapath_from_sbrec(datapaths, sbflow->logical_datapath); +- if (!od) { ++ ++ if (!od || ovn_datapath_is_stale(od)) { + sbrec_logical_flow_delete(sbflow); + continue; + } +@@ -10318,7 +10335,8 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths, + SBREC_MULTICAST_GROUP_FOR_EACH_SAFE (sbmc, next_sbmc, ctx->ovnsb_idl) { + struct ovn_datapath *od = ovn_datapath_from_sbrec(datapaths, + sbmc->datapath); +- if (!od) { ++ ++ if (!od || ovn_datapath_is_stale(od)) { + sbrec_multicast_group_delete(sbmc); + continue; + } +@@ -10800,8 +10818,8 @@ build_ip_mcast(struct northd_context *ctx, struct hmap *datapaths) + const struct sbrec_ip_multicast *sb, *sb_next; + + SBREC_IP_MULTICAST_FOR_EACH_SAFE (sb, sb_next, ctx->ovnsb_idl) { +- if (!sb->datapath || +- !ovn_datapath_from_sbrec(datapaths, sb->datapath)) { ++ od = ovn_datapath_from_sbrec(datapaths, sb->datapath); ++ if (!od || ovn_datapath_is_stale(od)) { + sbrec_ip_multicast_delete(sb); + } + } +@@ -10870,7 +10888,8 @@ build_mcast_groups(struct northd_context *ctx, + /* If the datapath value is stale, purge the group. */ + struct ovn_datapath *od = + ovn_datapath_from_sbrec(datapaths, sb_igmp->datapath); +- if (!od) { ++ ++ if (!od || ovn_datapath_is_stale(od)) { + sbrec_igmp_group_delete(sb_igmp); + continue; + } +diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at +index d127152..94f892b 100644 +--- a/tests/ovn-northd.at ++++ b/tests/ovn-northd.at +@@ -1326,3 +1326,27 @@ AT_CHECK([test 0 = $(ovn-sbctl dump-flows lr0 | grep lr_in_unsnat | \ + grep "ip4 && ip4.dst == 192.168.2.6 && tcp && tcp.dst == 8080" -c) ]) + + AT_CLEANUP ++ ++AT_SETUP([ovn -- check reconcile stale Datapath_Binding]) ++ovn_start ++ ++ovn-nbctl lr-add lr ++ovn-nbctl lrp-add lr p 00:00:00:00:00:01 1.1.1.1/24 ++ ++AT_CHECK([ovn-nbctl --wait=sb sync], [0]) ++ ++# Create a MAC_Binding referring the router datapath. ++dp=$(ovn-sbctl --bare --columns _uuid list datapath .) ++ovn-sbctl create mac_binding logical_port="p" ip="1.1.1.2" datapath="$dp" ++ ++ovn-nbctl lrp-del p -- lr-del lr -- \ ++ lr-add lr -- lrp-add lr p 00:00:00:00:00:01 1.1.1.1/24 ++AT_CHECK([ovn-nbctl --wait=sb sync], [0]) ++ ++AT_CHECK([test 1 = $(ovn-sbctl --columns _uuid list Datapath_Binding | wc -l)]) ++ ++nb_uuid=$(ovn-sbctl get Datapath_Binding . external_ids:logical-router) ++lr_uuid=$(ovn-nbctl --columns _uuid list Logical_Router .) ++AT_CHECK[test ${nb_uuid} = ${lr_uuid}] ++ ++AT_CLEANUP +-- +1.8.3.1 + diff --git a/SOURCES/0001-ovn-northd-Don-t-add-arp-responder-flows-for-lports-.patch b/SOURCES/0001-ovn-northd-Don-t-add-arp-responder-flows-for-lports-.patch new file mode 100644 index 0000000..da692e0 --- /dev/null +++ b/SOURCES/0001-ovn-northd-Don-t-add-arp-responder-flows-for-lports-.patch @@ -0,0 +1,126 @@ +From 5521da70830446373265999b6d994d986a02ce01 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Thu, 19 Mar 2020 16:52:17 +0530 +Subject: [PATCH] ovn-northd: Don't add arp responder flows for lports with + 'unknown' address. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If a logical port has 'unknown' address, it means it can send and receive +packet with any IP and MAC and generally port security is not set for +such logical ports. If an lport has addresses set to - ["MAC1 IP1", unknown], +right now we add arp responder flows for IP1 and respond MAC1 in the arp +response. But it's possible that the VIF of the logical port can use the IP1 +with a different MAC. This patch supports this usecase. When another logical port +sends ARP request for IP1, the VIF of the logical port will anyway respond. + +Reported-by: Maciej Józefczyk +Acked-by: Han Zhou +Signed-off-by: Numan Siddique +--- + northd/ovn-northd.8.xml | 5 +++-- + northd/ovn-northd.c | 13 ++++++++----- + tests/ovn.at | 16 ++++++++++++---- + 3 files changed, 23 insertions(+), 11 deletions(-) + +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index 9b44720d1..7d03cbc83 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -699,8 +699,9 @@ output; + +

    + These flows are omitted for logical ports (other than router ports or +- localport ports) that are down and for logical ports of +- type virtual. ++ localport ports) that are down, for logical ports of ++ type virtual and for logical ports with 'unknown' ++ address set. +

    +
  • + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 3a77f2e3a..356c5436c 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -1148,7 +1148,7 @@ struct ovn_port { + + bool derived; /* Indicates whether this is an additional port + * derived from nbsp or nbrp. */ +- ++ bool has_unknown; /* If the addresses have 'unknown' defined. */ + /* The port's peer: + * + * - A switch port S of type "router" has a router port R as a peer, +@@ -2055,8 +2055,11 @@ join_logical_ports(struct northd_context *ctx, + op->lsp_addrs + = xmalloc(sizeof *op->lsp_addrs * nbsp->n_addresses); + for (size_t j = 0; j < nbsp->n_addresses; j++) { +- if (!strcmp(nbsp->addresses[j], "unknown") +- || !strcmp(nbsp->addresses[j], "router")) { ++ if (!strcmp(nbsp->addresses[j], "unknown")) { ++ op->has_unknown = true; ++ continue; ++ } ++ if (!strcmp(nbsp->addresses[j], "router")) { + continue; + } + if (is_dynamic_lsp_address(nbsp->addresses[j])) { +@@ -6123,7 +6126,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, + } else { + /* + * Add ARP/ND reply flows if either the +- * - port is up or ++ * - port is up and it doesn't have 'unknown' address defined or + * - port type is router or + * - port type is localport + */ +@@ -6132,7 +6135,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, + continue; + } + +- if (lsp_is_external(op->nbsp)) { ++ if (lsp_is_external(op->nbsp) || op->has_unknown) { + continue; + } + +diff --git a/tests/ovn.at b/tests/ovn.at +index 8cdbad743..1b6073ff0 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -1758,11 +1758,13 @@ for is in 1 2 3; do + sip=`ip_to_hex 192 168 0 $is$js` + tip=`ip_to_hex 192 168 0 $id$jd` + tip_unknown=`ip_to_hex 11 11 11 11` ++ reply_ha=; + if test $d != $s; then +- reply_ha=f000000000$d +- else +- reply_ha= ++ if test $jd != 1; then ++ reply_ha=f000000000$d ++ fi + fi ++ + test_arp $s f000000000$s $sip $tip $reply_ha #9 + test_arp $s f000000000$s $sip $tip_unknown #10 + +@@ -2199,7 +2201,13 @@ for s in 1 2 3; do + sip=192.168.0.$s + tip=192.168.0.$d + tip_unknown=11.11.11.11 +- if test $d != $s; then reply_ha=f0:00:00:00:00:0$d; else reply_ha=; fi ++ reply_ha=; ++ if test $d != $s; then ++ if test $d != 1; then ++ reply_ha=f0:00:00:00:00:0$d; ++ fi ++ fi ++ + test_arp $s f0:00:00:00:00:0$s $sip $tip $reply_ha #9 + test_arp $s f0:00:00:00:00:0$s $sip $tip_unknown #10 + +-- +2.24.1 + diff --git a/SOURCES/0001-ovn-northd-Fix-leak-of-lport-addresses-during-DHCPv6.patch b/SOURCES/0001-ovn-northd-Fix-leak-of-lport-addresses-during-DHCPv6.patch new file mode 100644 index 0000000..7d1d91b --- /dev/null +++ b/SOURCES/0001-ovn-northd-Fix-leak-of-lport-addresses-during-DHCPv6.patch @@ -0,0 +1,62 @@ +From c0d305f985cb1a8533950d4f17107d9a71635644 Mon Sep 17 00:00:00 2001 +From: Ilya Maximets +Date: Tue, 12 May 2020 12:44:06 +0200 +Subject: [PATCH 1/2] ovn-northd: Fix leak of lport addresses during DHCPv6 + reply handling. + +'lrp_networks' never destroyed but constantly overwritten in a loop that +handles DHCPv6 replies. In some cases this point leaks several MB per +minute making ovn-northd to constantly growing its memory consumption: + + 399,820,764 bytes in 1,885,947 blocks are definitely lost in loss record 182 of 182 + at 0x4839748: malloc (vg_replace_malloc.c:308) + by 0x483BD63: realloc (vg_replace_malloc.c:836) + by 0x1E7BF8: xrealloc (util.c:149) + by 0x152723: add_ipv6_netaddr.isra.0 (ovn-util.c:55) + by 0x152F1C: extract_lrp_networks (ovn-util.c:275) + by 0x142EE2: build_lrouter_flows (ovn-northd.c:8607) + by 0x142EE2: build_lflows.isra.0 (ovn-northd.c:10296) + by 0x14E4F8: ovnnb_db_run (ovn-northd.c:11128) + by 0x14E4F8: ovn_db_run (ovn-northd.c:11672) + by 0x13304D: main (ovn-northd.c:12035) + +In fact, there is no need to allocate this memory at all, since all the +required information is already available in 'op->lrp_networks'. + +Reported-by: Joe Talerico +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1827769 +Fixes: 5c1d2d230773 ("northd: Add logical flows for dhcpv6 pfd parsing") +Signed-off-by: Ilya Maximets +Acked-by: Mark Michelson +Signed-off-by: Numan Siddique +--- + northd/ovn-northd.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index b07e68cfa..c1cdb2280 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -8603,17 +8603,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + continue; + } + +- struct lport_addresses lrp_networks; +- if (!extract_lrp_networks(op->nbrp, &lrp_networks)) { +- continue; +- } +- +- for (size_t i = 0; i < lrp_networks.n_ipv6_addrs; i++) { ++ for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + ds_clear(&actions); + ds_clear(&match); + ds_put_format(&match, "ip6.dst == %s && udp.src == 547 &&" + " udp.dst == 546", +- lrp_networks.ipv6_addrs[i].addr_s); ++ op->lrp_networks.ipv6_addrs[i].addr_s); + ds_put_format(&actions, "reg0 = 0; handle_dhcpv6_reply;"); + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, + ds_cstr(&match), ds_cstr(&actions)); +-- +2.26.2 + diff --git a/SOURCES/0001-ovn-northd-Fix-the-missing-lflow-issue-in-LS_OUT_PRE.patch b/SOURCES/0001-ovn-northd-Fix-the-missing-lflow-issue-in-LS_OUT_PRE.patch new file mode 100644 index 0000000..3d0d04c --- /dev/null +++ b/SOURCES/0001-ovn-northd-Fix-the-missing-lflow-issue-in-LS_OUT_PRE.patch @@ -0,0 +1,131 @@ +From 7aa75981dfc17eb7f0ac9ee7300e346f3b6a0c8e Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Tue, 7 Jul 2020 18:30:20 +0530 +Subject: [PATCH 1/5] ovn-northd: Fix the missing lflow issue in LS_OUT_PRE_LB. + +When load balancer(s) configured with VIPs are associated to a logical switch, +then ovn-northd adds the below logical flow so that the packets in the egress +switch pipeline enter the conntrack. + +table=0 (ls_out_pre_lb ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) + +ovn-northd maintains a local boolean variable 'vip_configured' in +build_pre_lb() and adds the above lflow if this is true at the end. +But this variable is overriden as -> vip_configured = !!lb->n_vips; +when it loops through every load balancer associated with the logical switch. + +This is wrong and this patch fixes this issue. + +A test case is addd to test this scenario and the test case fails without the +fix in this patch. + +Fixes: bb9f2b9ce56c("ovn-northd: Consider load balancer active backends in router pipeline") + +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1849162 +Reported-by: Tim Rozet +Acked-by: Dumitru Ceara +Signed-off-by: Numan Siddique + +(cherry-picked from master commit 59af6f9048946e16813ad7ad4e453b85989670e4) +--- + northd/ovn-northd.c | 2 +- + tests/ovn-northd.at | 73 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 74 insertions(+), 1 deletion(-) + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 8a809d020..2b891c68f 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -4932,7 +4932,7 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows, + * table, we will eventually look at L4 information. */ + } + +- vip_configured = !!lb->n_vips; ++ vip_configured = (vip_configured || lb->n_vips); + } + + /* 'REGBIT_CONNTRACK_DEFRAG' is set to let the pre-stateful table send +diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at +index 37805d3d8..842800b90 100644 +--- a/tests/ovn-northd.at ++++ b/tests/ovn-northd.at +@@ -1485,3 +1485,76 @@ lsp2 + ]) + + AT_CLEANUP ++ ++# This test case tests that when a logical switch has load balancers associated ++# (with VIPs configured), the below logical flow is added by ovn-northd. ++# table=0 (ls_out_pre_lb ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) ++# This test case is added for the BZ - ++# https://bugzilla.redhat.com/show_bug.cgi?id=1849162 ++# ++# ovn-northd was not adding the above lflow if the last load balancer associated ++# to the logical switch doesn't have the VIP configured even if other load ++# balancers before the last one in the last have VIPs configured. ++# So make sure that the above lflow is added even if one load balancer has VIP ++# associated. ++ ++AT_SETUP([ovn -- Load balancer - missing ls_out_pre_lb flows]) ++ovn_start ++ ++ovn-nbctl ls-add sw0 ++ovn-nbctl lsp-add sw0 sw0-p1 ++ ++ovn-nbctl lb-add lb1 "10.0.0.10" "10.0.0.3" ++ovn-nbctl lb-add lb2 "10.0.0.11" "10.0.0.4" ++ ++ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl ++]) ++ ++ovn-nbctl ls-lb-add sw0 lb1 ++ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl ++ table=0 (ls_out_pre_lb ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) ++]) ++ ++ovn-nbctl ls-lb-add sw0 lb2 ++ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl ++ table=0 (ls_out_pre_lb ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) ++]) ++ ++lb1_uuid=$(ovn-nbctl --bare --columns _uuid find load_balancer name=lb1) ++lb2_uuid=$(ovn-nbctl --bare --columns _uuid find load_balancer name=lb2) ++ ++ovn-nbctl clear load_balancer $lb1_uuid vips ++ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl ++ table=0 (ls_out_pre_lb ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) ++]) ++ ++ovn-nbctl clear load_balancer $lb2_uuid vips ++ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl ++]) ++ ++ovn-nbctl set load_balancer $lb1_uuid vips:"10.0.0.10"="10.0.0.3" ++ovn-nbctl set load_balancer $lb2_uuid vips:"10.0.0.11"="10.0.0.4" ++ ++ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl ++ table=0 (ls_out_pre_lb ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) ++]) ++ ++# Now reverse the order of clearing the vip. ++ovn-nbctl clear load_balancer $lb2_uuid vips ++ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl ++ table=0 (ls_out_pre_lb ), priority=100 , match=(ip), action=(reg0[[0]] = 1; next;) ++]) ++ ++ovn-nbctl clear load_balancer $lb1_uuid vips ++ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep "ls_out_pre_lb.*priority=100" | grep reg0 | sort], [0], [dnl ++]) ++ ++AT_CLEANUP +-- +2.26.2 + diff --git a/SOURCES/0001-ovn-northd-Forward-ARP-requests-on-localnet-ports.patch b/SOURCES/0001-ovn-northd-Forward-ARP-requests-on-localnet-ports.patch new file mode 100644 index 0000000..742c212 --- /dev/null +++ b/SOURCES/0001-ovn-northd-Forward-ARP-requests-on-localnet-ports.patch @@ -0,0 +1,321 @@ +From 20bf8b836703f3ad984e6679510ea215655479a5 Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Tue, 24 Mar 2020 11:03:29 +0100 +Subject: [PATCH ovn] ovn-northd: Forward ARP requests on localnet ports. + +Commit 32f5ebb06226 limited the ARP/ND broadcast domain but in scenarios +where ARP responder flows are installed only on chassis that own the +associated logical ports ARP requests should still be forwarded on +localnet ports because the router pipeline should be executed on the +chassis that owns the logical port. Only that chassis will reply to the +ARP/ND request. + +Reported-by: Michael Plato +Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2020-March/049856.html +Fixes: 32f5ebb06226 ("ovn-northd: Limit ARP/ND broadcast domain whenever possible.") +Signed-off-by: Dumitru Ceara +Signed-off-by: Numan Siddique +(cherry picked from upstream commit 9f13732ae232aa0c872527d948435125b3a6cbce) + +Change-Id: I86b18043821f24bf491c9b85381c5d008f7f2307 +--- + northd/ovn-northd.8.xml | 3 +- + northd/ovn-northd.c | 6 +- + tests/ovn.at | 169 ++++++++++++++++++++++++++++++++++++++++++++---- + 3 files changed, 162 insertions(+), 16 deletions(-) + +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index 7d03cbc..1e0993e 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -1194,7 +1194,8 @@ output; + Priority-75 flows for each IP address/VIP/NAT address owned by a + router port connected to the switch. These flows match ARP requests + and ND packets for the specific IP addresses. Matched packets are +- forwarded only to the router that owns the IP address. ++ forwarded only to the router that owns the IP address and, if ++ present, to the localnet port of the logical switch. + + +
  • +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 356c543..787ca2f 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -5899,8 +5899,12 @@ build_lswitch_rport_arp_req_flow_for_ip(struct sset *ips, + ds_put_cstr(&match, "}"); + + /* Send a the packet only to the router pipeline and skip flooding it +- * in the broadcast domain. ++ * in the broadcast domain (except for the localnet port). + */ ++ if (od->localnet_port) { ++ ds_put_format(&actions, "clone { outport = %s; output; }; ", ++ od->localnet_port->json_key); ++ } + ds_put_format(&actions, "outport = %s; output;", patch_op->json_key); + ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_L2_LKUP, priority, + ds_cstr(&match), ds_cstr(&actions), stage_hint); +diff --git a/tests/ovn.at b/tests/ovn.at +index 1b6073f..4baf2e9 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -17928,13 +17928,14 @@ net_add n1 + sim_add hv1 + as hv1 + ovs-vsctl add-br br-phys ++ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys + ovn_attach n1 br-phys 192.168.0.1 + +-ovs-vsctl -- add-port br-int hv1-vif1 -- \ +- set interface hv1-vif1 external-ids:iface-id=sw-agg-ext \ +- options:tx_pcap=hv1/vif1-tx.pcap \ +- options:rxq_pcap=hv1/vif1-rx.pcap \ +- ofport-request=1 ++sim_add hv2 ++as hv2 ++ovs-vsctl add-br br-phys ++ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys ++ovn_attach n1 br-phys 192.168.0.2 + + # One Aggregation Switch connected to two Logical networks (routers). + ovn-nbctl ls-add sw-agg +@@ -17950,18 +17951,66 @@ ovn-nbctl lsp-add sw-agg sw-rtr2 \ + -- lsp-set-addresses sw-rtr2 00:00:00:00:02:00 \ + -- lsp-set-options sw-rtr2 router-port=rtr2-sw + +-# Configure L3 interface IPv4 & IPv6 on both routers ++# Localnet port on the Aggregation Switch. ++ovn-nbctl lsp-add sw-agg sw-agg-ln ++ovn-nbctl lsp-set-addresses sw-agg-ln unknown ++ovn-nbctl lsp-set-type sw-agg-ln localnet ++ovn-nbctl lsp-set-options sw-agg-ln network_name=phys ++ ++# Configure L3 interface IPv4 & IPv6 on both routers. + ovn-nbctl lr-add rtr1 + ovn-nbctl lrp-add rtr1 rtr1-sw 00:00:00:00:01:00 10.0.0.1/24 10::1/64 + ++ovn-nbctl lrp-add rtr1 rtr1-sw1 00:00:01:00:00:00 20.0.0.1/24 20::1/64 ++ + ovn-nbctl lr-add rtr2 + ovn-nbctl lrp-add rtr2 rtr2-sw 00:00:00:00:02:00 10.0.0.2/24 10::2/64 + ++# Configure router gateway ports. ++ovn-nbctl lrp-set-gateway-chassis rtr1-sw hv1 20 ++ovn-nbctl lrp-set-gateway-chassis rtr2-sw hv1 20 ++ ++# One private network behind rtr1 with two VMs. ++ovn-nbctl ls-add sw1 ++ovn-nbctl lsp-add sw1 sw1-p1 \ ++ -- lsp-set-addresses sw1-p1 00:00:00:01:00:00 ++ovn-nbctl lsp-add sw1 sw1-p2 \ ++ -- lsp-set-addresses sw1-p2 00:00:00:02:00:00 ++ovn-nbctl lsp-add sw1 sw1-rtr1 \ ++ -- lsp-set-type sw1-rtr1 router \ ++ -- lsp-set-addresses sw1-rtr1 00:00:01:00:00:00 \ ++ -- lsp-set-options sw1-rtr1 router-port=rtr1-sw1 ++ ++# Bind a "VM" connected to sw-agg on hv1. ++as hv1 ++ovs-vsctl -- add-port br-int hv1-vif0 -- \ ++ set interface hv1-vif0 external-ids:iface-id=sw-agg-ext \ ++ options:tx_pcap=hv1/vif0-tx.pcap \ ++ options:rxq_pcap=hv1/vif0-rx.pcap \ ++ ofport-request=1 ++ ++# Bind a "VM" connected to sw1 on hv1. ++as hv1 ++ovs-vsctl -- add-port br-int hv1-vif1 -- \ ++ set interface hv1-vif1 external-ids:iface-id=sw1-p1 \ ++ options:tx_pcap=hv1/vif1-tx.pcap \ ++ options:rxq_pcap=hv1/vif1-rx.pcap \ ++ ofport-request=2 ++ ++# Bind a "VM" connected to sw1 on hv2. ++as hv2 ++ovs-vsctl -- add-port br-int hv1-vif2 -- \ ++ set interface hv1-vif2 external-ids:iface-id=sw1-p2 \ ++ options:tx_pcap=hv1/vif2-tx.pcap \ ++ options:rxq_pcap=hv1/vif2-rx.pcap \ ++ ofport-request=3 ++ + OVN_POPULATE_ARP + ovn-nbctl --wait=hv sync + + sw_dp_uuid=$(ovn-sbctl --bare --columns _uuid list datapath_binding sw-agg) + sw_dp_key=$(ovn-sbctl --bare --columns tunnel_key list datapath_binding sw-agg) ++r1_dp_key=$(ovn-sbctl --bare --columns tunnel_key list datapath_binding rtr1) + + r1_tnl_key=$(ovn-sbctl --bare --columns tunnel_key list port_binding sw-rtr1) + r2_tnl_key=$(ovn-sbctl --bare --columns tunnel_key list port_binding sw-rtr2) +@@ -17970,9 +18019,10 @@ mc_key=$(ovn-sbctl --bare --columns tunnel_key find multicast_group datapath=${s + mc_key=$(printf "%04x" $mc_key) + + match_sw_metadata="metadata=0x${sw_dp_key}" ++match_r1_metadata="metadata=0x${r1_dp_key}" + + # Inject ARP request for first router owned IP address. +-send_arp_request 1 1 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 1) ++send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 1) + + # Verify that the ARP request is sent only to rtr1. + match_arp_req="priority=75.*${match_sw_metadata}.*arp_tpa=10.0.0.1,arp_op=1" +@@ -18001,7 +18051,7 @@ OVS_WAIT_UNTIL([ + # Inject ND_NS for ofirst router owned IP address. + src_ipv6=00100000000000000000000000000254 + dst_ipv6=00100000000000000000000000000001 +-send_nd_ns 1 1 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d ++send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d + + # Verify that the ND_NS is sent only to rtr1. + match_nd_ns="priority=75.*${match_sw_metadata}.*icmp_type=135.*nd_target=10::1" +@@ -18038,7 +18088,7 @@ ovn-nbctl lr-lb-add rtr2 lb2-v6 + ovn-nbctl --wait=hv sync + + # Inject ARP request for first router owned VIP address. +-send_arp_request 1 1 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 11) ++send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 11) + + # Verify that the ARP request is sent only to rtr1. + match_arp_req="priority=75.*${match_sw_metadata}.*arp_tpa=10.0.0.11,arp_op=1" +@@ -18067,7 +18117,7 @@ OVS_WAIT_UNTIL([ + # Inject ND_NS for first router owned VIP address. + src_ipv6=00100000000000000000000000000254 + dst_ipv6=00100000000000000000000000000011 +-send_nd_ns 1 1 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d ++send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d + + # Verify that the ND_NS is sent only to rtr1. + match_nd_ns="priority=75.*${match_sw_metadata}.*icmp_type=135.*nd_target=10::11" +@@ -18091,14 +18141,21 @@ OVS_WAIT_UNTIL([ + test "0" = "${pkts_flooded}" + ]) + +-# Configure NAT on both routers ++# Configure NAT on both routers. + ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.111 42.42.42.1 + ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10::111 42::1 + ovn-nbctl lr-nat-add rtr2 dnat_and_snat 10.0.0.222 42.42.42.2 + ovn-nbctl lr-nat-add rtr2 dnat_and_snat 10::222 42::2 + ++# Configure FIP1 and FIP2 on rtr1 for sw1-p1 and sw1-p2. ++ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.121 20.0.0.11 sw1-p1 00:00:00:01:00:00 ++ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10::121 20::11 sw1-p1 00:00:00:01:00:00 ++ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.122 20.0.0.12 sw1-p2 00:00:00:02:00:00 ++ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10::122 20::12 sw1-p2 00:00:00:02:00:00 ++ovn-nbctl --wait=hv sync ++ + # Inject ARP request for first router owned NAT address. +-send_arp_request 1 1 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 111) ++send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 111) + + # Verify that the ARP request is sent only to rtr1. + match_arp_req="priority=75.*${match_sw_metadata}.*arp_tpa=10.0.0.111,arp_op=1" +@@ -18124,10 +18181,50 @@ OVS_WAIT_UNTIL([ + test "0" = "${pkts_flooded}" + ]) + ++# Inject ARP request for FIP1. ++send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 121) ++ ++# Verify that the ARP request is replied to from hv1 and not hv2. ++match_arp_req="priority=90.*${match_r1_metadata}.*arp_tpa=10.0.0.121,arp_op=1" ++ ++as hv1 ++OVS_WAIT_UNTIL([ ++ pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \ ++ grep -E "${match_arp_req}" | grep n_packets=1 -c) ++ test "1" = "${pkts_on_rtr1}" ++]) ++ ++as hv2 ++OVS_WAIT_UNTIL([ ++ pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \ ++ grep -E "${match_arp_req}" | grep n_packets=1 -c) ++ test "0" = "${pkts_on_rtr1}" ++]) ++ ++# Inject ARP request for FIP2. ++send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 122) ++ ++# Verify that the ARP request is replied to from hv2 and not hv1. ++match_arp_req="priority=90.*${match_r1_metadata}.*arp_tpa=10.0.0.122,arp_op=1" ++ ++as hv2 ++OVS_WAIT_UNTIL([ ++ pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \ ++ grep -E "${match_arp_req}" | grep n_packets=1 -c) ++ test "1" = "${pkts_on_rtr1}" ++]) ++ ++as hv1 ++OVS_WAIT_UNTIL([ ++ pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \ ++ grep -E "${match_arp_req}" | grep n_packets=1 -c) ++ test "0" = "${pkts_on_rtr1}" ++]) ++ + # Inject ND_NS for first router owned IP address. + src_ipv6=00100000000000000000000000000254 + dst_ipv6=00100000000000000000000000000111 +-send_nd_ns 1 1 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d ++send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 751d + + # Verify that the ND_NS is sent only to rtr1. + match_nd_ns="priority=75.*${match_sw_metadata}.*icmp_type=135.*nd_target=10::111" +@@ -18151,7 +18248,51 @@ OVS_WAIT_UNTIL([ + test "0" = "${pkts_flooded}" + ]) + +-OVN_CLEANUP([hv1]) ++# Inject ND_NS for FIP1. ++src_ipv6=00100000000000000000000000000254 ++dst_ipv6=00100000000000000000000000000121 ++send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 72dd ++ ++# Verify that the ND_NS is replied to from hv1 and not hv2. ++match_nd_ns="priority=90.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::121" ++ ++as hv1 ++OVS_WAIT_UNTIL([ ++ pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \ ++ grep -E "${match_nd_ns}" | grep n_packets=1 -c) ++ test "1" = "${pkts_on_rtr1}" ++]) ++ ++as hv2 ++OVS_WAIT_UNTIL([ ++ pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \ ++ grep -E "${match_nd_ns}" | grep n_packets=1 -c) ++ test "0" = "${pkts_on_rtr1}" ++]) ++ ++# Inject ND_NS for FIP2. ++src_ipv6=00100000000000000000000000000254 ++dst_ipv6=00100000000000000000000000000122 ++send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 72db ++ ++# Verify that the ND_NS is replied to from hv2 and not hv1. ++match_nd_ns="priority=90.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::122" ++ ++as hv2 ++OVS_WAIT_UNTIL([ ++ pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \ ++ grep -E "${match_nd_ns}" | grep n_packets=1 -c) ++ test "1" = "${pkts_on_rtr1}" ++]) ++ ++as hv1 ++OVS_WAIT_UNTIL([ ++ pkts_on_rtr1=$(ovs-ofctl dump-flows br-int | \ ++ grep -E "${match_nd_ns}" | grep n_packets=1 -c) ++ test "0" = "${pkts_on_rtr1}" ++]) ++ ++OVN_CLEANUP([hv1], [hv2]) + AT_CLEANUP + + AT_SETUP([ovn -- trace when flow cookie updated]) +-- +1.8.3.1 + diff --git a/SOURCES/0001-ovn-northd-Limit-IPv6-ND-NS-RA-RS-to-the-local-netwo.patch b/SOURCES/0001-ovn-northd-Limit-IPv6-ND-NS-RA-RS-to-the-local-netwo.patch new file mode 100644 index 0000000..9ef0d78 --- /dev/null +++ b/SOURCES/0001-ovn-northd-Limit-IPv6-ND-NS-RA-RS-to-the-local-netwo.patch @@ -0,0 +1,205 @@ +From d46b2e1f3b31509849441cde28475a8d48a6624f Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Fri, 17 Apr 2020 23:54:25 +0200 +Subject: [PATCH] ovn-northd: Limit IPv6 ND NS/RA/RS to the local network. + +Neighbor solicitation packets for router owned IPs are replied to in +table IN_IP_INPUT at a higher priority than flows relay IPv6 multicast +traffic when needed. All other NS/NA packets received at this point can +be safely dropped. + +However, router advertisement and router solicitation packets are +processed at a later stage, in ND_RA_OPTIONS/ND_RA_RESPONSE. These +packets need to be allowed in table IN_IP_INPUT. + +Commit 677a3ba4d66b incorrectly allowed all IPv6 multicast traffic +destined to all-nodes in table IN_IP_INPUT. Instead, only ND_RA and +ND_RS packets should be allowed. All others were either already +processed or should be dropped. If multicast relay is enabled then IPv6 +multicast traffic that's not destined to reserved groups should also be +allowed. + +Furthermore, router solicitation and advertisement packets that don't +get processed in tables ND_RA_OPTIONS/ND_RA_RESPONSE should be dropped +in IN_IP_ROUTING because they should never be routed. + +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1825334 +Reported-by: Jakub Libosvar +Fixes: 677a3ba4d66b ("ovn: Add MLD support.") +Signed-off-by: Dumitru Ceara +Signed-off-by: Numan Siddique + +(cherry-picked from upstream branch-20.03 commit 0924bcb07ef25f93fde683fe8f15d376eca005ec) + +Change-Id: I1d060e5d40f344b890974e6ad0c0960ea280f050 +--- + northd/ovn-northd.8.xml | 49 +++++++++++++++++++++++++++-------------- + northd/ovn-northd.c | 43 +++++++++++++++++++++++++----------- + 2 files changed, 62 insertions(+), 30 deletions(-) + +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index 82c86f636..efcc4b7fc 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -1668,22 +1668,6 @@ next; + router. +
  • + +-
  • +-

    +- A priority-87 flow explicitly allows IPv6 multicast traffic that is +- supposed to reach the router pipeline (e.g., neighbor solicitations +- and traffic destined to the All-Routers multicast group). +-

    +-
  • +- +-
  • +-

    +- A priority-86 flow allows IP multicast traffic if +- :mcast_relay='true', +- otherwise drops it. +-

    +-
  • +- +
  • +

    + ICMP echo reply. These flows reply to ICMP echo requests received +@@ -1944,6 +1928,29 @@ nd.tll = external_mac; + packets. +

  • + ++
  • ++

    ++ A priority-84 flow explicitly allows IPv6 multicast traffic that is ++ supposed to reach the router pipeline (i.e., router solicitation ++ and router advertisement packets). ++

    ++
  • ++ ++
  • ++

    ++ A priority-83 flow explicitly drops IPv6 multicast traffic that is ++ destined to reserved multicast groups. ++

    ++
  • ++ ++
  • ++

    ++ A priority-82 flow allows IP multicast traffic if ++ :mcast_relay='true', ++ otherwise drops it. ++

    ++
  • ++ +
  • +

    + UDP port unreachable. Priority-80 flows generate ICMP port +@@ -2440,6 +2447,13 @@ output; +

    + +
      ++
    • ++

      ++ Priority-550 flow that drops IPv6 Router Solicitation/Advertisement ++ packets that were not processed in previous tables. ++

      ++
    • ++ +
    • +

      + Priority-500 flows that match IP multicast traffic destined to +@@ -2457,7 +2471,8 @@ output; + multicast group, which ovn-northd populates with the + logical ports that have + +- :mcast_flood='true'. ++ :mcast_flood='true'. If no router ports are configured ++ to flood multicast traffic the packets are dropped. +

      +
    • + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 1f1238d23..f7d3988d7 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -8002,17 +8002,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + + /* Priority-90 flows reply to ARP requests and ND packets. */ + +- /* Allow IPv6 multicast traffic that's supposed to reach the +- * router pipeline (e.g., neighbor solicitations). +- */ +- ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 87, "ip6.mcast_flood", +- "next;"); +- +- /* Allow multicast if relay enabled (priority 86). */ +- ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 86, +- "ip4.mcast || ip6.mcast", +- od->mcast_info.rtr.relay ? "next;" : "drop;"); +- + /* Drop ARP packets (priority 85). ARP request packets for router's own + * IPs are handled with priority-90 flows. + * Drop IPv6 ND packets (priority 85). ND NA packets for router's own +@@ -8021,6 +8010,21 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 85, + "arp || nd", "drop;"); + ++ /* Allow IPv6 multicast traffic that's supposed to reach the ++ * router pipeline (e.g., router solicitations). ++ */ ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 84, "nd_rs || nd_ra", ++ "next;"); ++ ++ /* Drop other reserved multicast. */ ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 83, ++ "ip6.mcast_rsvd", "drop;"); ++ ++ /* Allow other multicast if relay enabled (priority 82). */ ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 82, ++ "ip4.mcast || ip6.mcast", ++ od->mcast_info.rtr.relay ? "next;" : "drop;"); ++ + /* Drop Ethernet local broadcast. By definition this traffic should + * not be forwarded.*/ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50, +@@ -9520,7 +9524,17 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + * advance to next table (priority 500). + */ + HMAP_FOR_EACH (od, key_node, datapaths) { +- if (!od->nbr || !od->mcast_info.rtr.relay) { ++ if (!od->nbr) { ++ continue; ++ } ++ ++ /* Drop IPv6 multicast traffic that shouldn't be forwarded, ++ * i.e., router solicitation and router advertisement. ++ */ ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 550, ++ "nd_rs || nd_ra", "drop;"); ++ ++ if (!od->mcast_info.rtr.relay) { + continue; + } + +@@ -9551,7 +9565,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + } + + /* If needed, flood unregistered multicast on statically configured +- * ports. ++ * ports. Otherwise drop any multicast traffic. + */ + if (od->mcast_info.rtr.flood_static) { + ds_clear(&actions); +@@ -9562,6 +9576,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + "ip.ttl--; " + "next; " + "};"); ++ } else { ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 450, ++ "ip4.mcast || ip6.mcast", "drop;"); + } + } + +-- +2.25.1 + diff --git a/SOURCES/0001-ovn-northd-Optimize-flows-for-LB-Hairpin-traffic.patch b/SOURCES/0001-ovn-northd-Optimize-flows-for-LB-Hairpin-traffic.patch new file mode 100644 index 0000000..6299b4e --- /dev/null +++ b/SOURCES/0001-ovn-northd-Optimize-flows-for-LB-Hairpin-traffic.patch @@ -0,0 +1,185 @@ +From 74e1bf4dd0f6c62602ab708eabb5534a274a4d75 Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Tue, 28 Apr 2020 12:39:26 +0200 +Subject: [PATCH] ovn-northd: Optimize flows for LB Hairpin traffic. + +In order to detect that traffic was hairpinned due to logical switch load +balancers we need to match on source and destination IPs of packets (and +protocol ports potentially) in table ls_in_pre_hairpin. + +For this, until now, we created 2 logical flows for each backend of a load +balancer VIP. However, in scenarios where large load balancers (i.e., +with large numbers of backends) are applied to multiple logical +switches, this might generate logical flow count explosion. + +One optimization is to generate a single logical flow per VIP that +combines all conditions generated for each backend. This reduces load on +the SB DB because of lower number of logical flows and also reduces +overall DB size because of less overhead due to other fields on the +logical_flow records. + +Comparison of various performance aspects when running OVN with the NB +database attached to the bug report on a deployment with all VIFs bound +to a single node (62 load balancer VIPs with 513 load balancer +backends, applied on 106 logical switches): + +Without this patch: +- SB database size: 60MB +- # of pre-hairpin logical flows: 109074 +- # of logical flows: 159414 +- ovn-controller max loop iteration time when processing SB DB: 8803ms +- ovn-northd max loop iteration time: 3988ms + +With this patch: +- SB database size: 29MB (~50% decrease) +- # of pre-hairpin logical flows: 13250 (~88% decrease) +- # of logical flows: 63590 (~60% decrease) +- ovn-controller max loop iteration time when processing SB DB: 5585ms +- ovn-northd max loop iteration time: 1594ms + +Reported-by: Aniket Bhat +Reported-at: https://bugzilla.redhat.com/1827403 +Fixes: 1be8ac65bc60 ("ovn-northd: Support hairpinning for logical switch load balancing.") +Signed-off-by: Dumitru Ceara +Signed-off-by: Numan Siddique +(cherry picked from upstream commit 97e82ae5f135a088c9e95b49122d8217718d23f4) + +Change-Id: Id713209f8bd159e8ad924e91681bab784606faff +--- + northd/ovn-northd.8.xml | 4 +-- + northd/ovn-northd.c | 79 ++++++++++++++++++++++++++++++++----------------- + 2 files changed, 54 insertions(+), 29 deletions(-) + +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index d39e259..1f81742 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -559,14 +559,14 @@ +

      Ingress Table 11: Pre-Hairpin

      +
        +
      • +- For all configured load balancer backends a priority-2 flow that ++ For all configured load balancer VIPs a priority-2 flow that + matches on traffic that needs to be hairpinned, i.e., after load + balancing the destination IP matches the source IP, which sets + reg0[6] = 1 and executes ct_snat(VIP) + to force replies to these packets to come back through OVN. +
      • +
      • +- For all configured load balancer backends a priority-1 flow that ++ For all configured load balancer VIPs a priority-1 flow that + matches on replies to hairpinned traffic, i.e., destination IP is VIP, + source IP is the backend IP and source L4 port is backend port, which + sets reg0[6] = 1 and executes ct_snat;. +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 0082e2e..5ada3ae 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -5542,52 +5542,77 @@ build_lb_hairpin_rules(struct ovn_datapath *od, struct hmap *lflows, + struct ovn_lb *lb, struct lb_vip *lb_vip, + const char *ip_match, const char *proto) + { ++ if (lb_vip->n_backends == 0) { ++ return; ++ } ++ ++ struct ds action = DS_EMPTY_INITIALIZER; ++ struct ds match_initiator = DS_EMPTY_INITIALIZER; ++ struct ds match_reply = DS_EMPTY_INITIALIZER; ++ struct ds proto_match = DS_EMPTY_INITIALIZER; ++ + /* Ingress Pre-Hairpin table. +- * - Priority 2: SNAT load balanced traffic that needs to be hairpinned. ++ * - Priority 2: SNAT load balanced traffic that needs to be hairpinned: ++ * - Both SRC and DST IP match backend->ip and destination port ++ * matches backend->port. + * - Priority 1: unSNAT replies to hairpinned load balanced traffic. ++ * - SRC IP matches backend->ip, DST IP matches LB VIP and source port ++ * matches backend->port. + */ ++ ds_put_char(&match_reply, '('); + for (size_t i = 0; i < lb_vip->n_backends; i++) { + struct lb_vip_backend *backend = &lb_vip->backends[i]; +- struct ds action = DS_EMPTY_INITIALIZER; +- struct ds match = DS_EMPTY_INITIALIZER; +- struct ds proto_match = DS_EMPTY_INITIALIZER; + + /* Packets that after load balancing have equal source and +- * destination IPs should be hairpinned. SNAT them so that the reply +- * traffic is directed also through OVN. ++ * destination IPs should be hairpinned. + */ + if (lb_vip->vip_port) { +- ds_put_format(&proto_match, " && %s && %s.dst == %"PRIu16, +- proto, proto, backend->port); ++ ds_put_format(&proto_match, " && %s.dst == %"PRIu16, ++ proto, backend->port); + } +- ds_put_format(&match, "%s.src == %s && %s.dst == %s%s", ++ ds_put_format(&match_initiator, "(%s.src == %s && %s.dst == %s%s)", + ip_match, backend->ip, ip_match, backend->ip, + ds_cstr(&proto_match)); +- ds_put_format(&action, REGBIT_HAIRPIN " = 1; ct_snat(%s);", +- lb_vip->vip); +- ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 2, +- ds_cstr(&match), ds_cstr(&action), +- &lb->nlb->header_); + +- /* If the packets are replies for hairpinned traffic, UNSNAT them. */ ++ /* Replies to hairpinned traffic are originated by backend->ip:port. */ + ds_clear(&proto_match); +- ds_clear(&match); + if (lb_vip->vip_port) { +- ds_put_format(&proto_match, " && %s && %s.src == %"PRIu16, +- proto, proto, backend->port); ++ ds_put_format(&proto_match, " && %s.src == %"PRIu16, proto, ++ backend->port); + } +- ds_put_format(&match, "%s.src == %s && %s.dst == %s%s", +- ip_match, backend->ip, ip_match, lb_vip->vip, ++ ds_put_format(&match_reply, "(%s.src == %s%s)", ip_match, backend->ip, + ds_cstr(&proto_match)); +- ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 1, +- ds_cstr(&match), +- REGBIT_HAIRPIN " = 1; ct_snat;", +- &lb->nlb->header_); ++ ds_clear(&proto_match); + +- ds_destroy(&action); +- ds_destroy(&match); +- ds_destroy(&proto_match); ++ if (i < lb_vip->n_backends - 1) { ++ ds_put_cstr(&match_initiator, " || "); ++ ds_put_cstr(&match_reply, " || "); ++ } + } ++ ds_put_char(&match_reply, ')'); ++ ++ /* SNAT hairpinned initiator traffic so that the reply traffic is ++ * also directed through OVN. ++ */ ++ ds_put_format(&action, REGBIT_HAIRPIN " = 1; ct_snat(%s);", ++ lb_vip->vip); ++ ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 2, ++ ds_cstr(&match_initiator), ds_cstr(&action), ++ &lb->nlb->header_); ++ ++ /* Replies to hairpinned traffic are destined to the LB VIP. */ ++ ds_put_format(&match_reply, " && %s.dst == %s", ip_match, lb_vip->vip); ++ ++ /* UNSNAT replies for hairpinned traffic. */ ++ ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 1, ++ ds_cstr(&match_reply), ++ REGBIT_HAIRPIN " = 1; ct_snat;", ++ &lb->nlb->header_); ++ ++ ds_destroy(&action); ++ ds_destroy(&match_initiator); ++ ds_destroy(&match_reply); ++ ds_destroy(&proto_match); + } + + static void +-- +1.8.3.1 + diff --git a/SOURCES/0001-ovn-northd-Remove-useless-flow-for-GW_REDIRECT.patch b/SOURCES/0001-ovn-northd-Remove-useless-flow-for-GW_REDIRECT.patch new file mode 100644 index 0000000..89b38d8 --- /dev/null +++ b/SOURCES/0001-ovn-northd-Remove-useless-flow-for-GW_REDIRECT.patch @@ -0,0 +1,74 @@ +From 32972260b50f39d493cc42a78d9648ed668c2aec Mon Sep 17 00:00:00 2001 +Message-Id: <32972260b50f39d493cc42a78d9648ed668c2aec.1590584789.git.lorenzo.bianconi@redhat.com> +From: Han Zhou +Date: Tue, 5 May 2020 23:16:09 -0700 +Subject: [PATCH ovn] ovn-northd: Remove useless flow for GW_REDIRECT. + +Remove the flow in lr_in_gw_redirect stage: + + A priority-150 logical flow with match + outport == GW && + eth.dst == 00:00:00:00:00:00 has actions + outport = CR; next;, where + GW is the logical router distributed gateway + port and CR is the chassisredirect + port representing the instance of the logical router + distributed gateway port on the + redirect-chassis. + +The commit c0bf32d ("Manage ARP process locally in a DVR scenario") updated +the priority-100 flow in this stage to priority 200, which makes this +priority-150 flow useless, because whatever packets matching this flow +would also match the priority-50 flow. + +Cc: Lorenzo Bianconi +Tested-by: Lorenzo Bianconi +Acked-by: Numan Siddique +Signed-off-by: Han Zhou +Signed-off-by: Lorenzo Bianconi +--- + northd/ovn-northd.8.xml | 12 ------------ + northd/ovn-northd.c | 11 ----------- + 2 files changed, 23 deletions(-) + +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -2909,18 +2909,6 @@ icmp4 { + +
          +
        • +- A priority-150 logical flow with match +- outport == GW && +- eth.dst == 00:00:00:00:00:00 has actions +- outport = CR; next;, where +- GW is the logical router distributed gateway +- port and CR is the chassisredirect +- port representing the instance of the logical router +- distributed gateway port on the +- redirect-chassis. +-
        • +- +-
        • + For each NAT rule in the OVN Northbound database that can + be handled in a distributed manner, a priority-200 logical + flow with match ip4.src == B && +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -10143,17 +10143,6 @@ build_lrouter_flows(struct hmap *datapat + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50, + ds_cstr(&match), ds_cstr(&actions), + stage_hint); +- +- /* If the Ethernet destination has not been resolved, +- * redirect to the central instance of the l3dgw_port. +- * Such traffic will be replaced by an ARP request or ND +- * Neighbor Solicitation in the ARP request ingress +- * table, before being redirected to the central instance. +- */ +- ds_put_format(&match, " && eth.dst == 00:00:00:00:00:00"); +- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 150, +- ds_cstr(&match), ds_cstr(&actions), +- stage_hint); + } + + /* Packets are allowed by default. */ diff --git a/SOURCES/0001-ovn.at-Fix-ARP-test-that-fails-due-to-timing.patch b/SOURCES/0001-ovn.at-Fix-ARP-test-that-fails-due-to-timing.patch new file mode 100644 index 0000000..ffc9db8 --- /dev/null +++ b/SOURCES/0001-ovn.at-Fix-ARP-test-that-fails-due-to-timing.patch @@ -0,0 +1,113 @@ +From 356501f3246ddb99aef8cd6016467b7c1861b3ff Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Tue, 24 Mar 2020 14:35:41 +0100 +Subject: [PATCH ovn] ovn.at: Fix ARP test that fails due to timing. + +The test for "ARP/ND request broadcast limiting" checks that injected +ARP packets are not flooded using the MC_FLOOD multicast group. However, +this introduces a race condition in the test because GARPs generated by +OVN would also hit the same openflow rules. + +Remove the checks that use the MC_FLOOD group. They are also redundant +as the rest of the test checks that packets are forwarded according to +the newly added, higher priority rules. + +Fixes: 32f5ebb06226 ("ovn-northd: Limit ARP/ND broadcast domain whenever possible.") +Signed-off-by: Dumitru Ceara +Signed-off-by: Numan Siddique +(cherry picked from upstream commit 598a07cd240d7d01de3d7f04ca7abc58a33977a1) + +Change-Id: I4519f441245a5f1ecf7da73257f97aff0c7bc967 +--- + tests/ovn.at | 33 --------------------------------- + 1 file changed, 33 deletions(-) + +diff --git a/tests/ovn.at b/tests/ovn.at +index 4baf2e9..9a44f0a 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -18015,9 +18015,6 @@ r1_dp_key=$(ovn-sbctl --bare --columns tunnel_key list datapath_binding rtr1) + r1_tnl_key=$(ovn-sbctl --bare --columns tunnel_key list port_binding sw-rtr1) + r2_tnl_key=$(ovn-sbctl --bare --columns tunnel_key list port_binding sw-rtr2) + +-mc_key=$(ovn-sbctl --bare --columns tunnel_key find multicast_group datapath=${sw_dp_uuid} name="_MC_flood") +-mc_key=$(printf "%04x" $mc_key) +- + match_sw_metadata="metadata=0x${sw_dp_key}" + match_r1_metadata="metadata=0x${r1_dp_key}" + +@@ -18042,11 +18039,6 @@ OVS_WAIT_UNTIL([ + grep n_packets=1 -c) + test "0" = "${pkts_to_rtr2}" + ]) +-OVS_WAIT_UNTIL([ +- pkts_flooded=$(ovs-ofctl dump-flows br-int | \ +- grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c) +- test "0" = "${pkts_flooded}" +-]) + + # Inject ND_NS for ofirst router owned IP address. + src_ipv6=00100000000000000000000000000254 +@@ -18069,11 +18061,6 @@ OVS_WAIT_UNTIL([ + grep n_packets=1 -c) + test "0" = "${pkts_to_rtr2}" + ]) +-OVS_WAIT_UNTIL([ +- pkts_flooded=$(ovs-ofctl dump-flows br-int | \ +- grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c) +- test "0" = "${pkts_flooded}" +-]) + + # Configure load balancing on both routers. + ovn-nbctl lb-add lb1-v4 10.0.0.11 42.42.42.1 +@@ -18108,11 +18095,6 @@ OVS_WAIT_UNTIL([ + grep n_packets=1 -c) + test "0" = "${pkts_to_rtr2}" + ]) +-OVS_WAIT_UNTIL([ +- pkts_flooded=$(ovs-ofctl dump-flows br-int | \ +- grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c) +- test "0" = "${pkts_flooded}" +-]) + + # Inject ND_NS for first router owned VIP address. + src_ipv6=00100000000000000000000000000254 +@@ -18135,11 +18117,6 @@ OVS_WAIT_UNTIL([ + grep n_packets=1 -c) + test "0" = "${pkts_to_rtr2}" + ]) +-OVS_WAIT_UNTIL([ +- pkts_flooded=$(ovs-ofctl dump-flows br-int | \ +- grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c) +- test "0" = "${pkts_flooded}" +-]) + + # Configure NAT on both routers. + ovn-nbctl lr-nat-add rtr1 dnat_and_snat 10.0.0.111 42.42.42.1 +@@ -18175,11 +18152,6 @@ OVS_WAIT_UNTIL([ + grep n_packets=1 -c) + test "0" = "${pkts_to_rtr2}" + ]) +-OVS_WAIT_UNTIL([ +- pkts_flooded=$(ovs-ofctl dump-flows br-int | \ +- grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c) +- test "0" = "${pkts_flooded}" +-]) + + # Inject ARP request for FIP1. + send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0 0 121) +@@ -18242,11 +18214,6 @@ OVS_WAIT_UNTIL([ + grep n_packets=1 -c) + test "0" = "${pkts_to_rtr2}" + ]) +-OVS_WAIT_UNTIL([ +- pkts_flooded=$(ovs-ofctl dump-flows br-int | \ +- grep -E "${match_sw_metadata}" | grep ${mc_key} | grep -v n_packets=0 -c) +- test "0" = "${pkts_flooded}" +-]) + + # Inject ND_NS for FIP1. + src_ipv6=00100000000000000000000000000254 +-- +1.8.3.1 + diff --git a/SOURCES/0001-ovsdb-idl-Avoid-inconsistent-IDL-state-with-OVSDB_MO.patch b/SOURCES/0001-ovsdb-idl-Avoid-inconsistent-IDL-state-with-OVSDB_MO.patch new file mode 100644 index 0000000..5df4118 --- /dev/null +++ b/SOURCES/0001-ovsdb-idl-Avoid-inconsistent-IDL-state-with-OVSDB_MO.patch @@ -0,0 +1,460 @@ +From 966dd7bc7fb7931d7616ca886dc24ecb1f34cced Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Thu, 28 May 2020 14:32:31 +0200 +Subject: [PATCH] ovsdb-idl: Avoid inconsistent IDL state with + OVSDB_MONITOR_V3. + +Assuming an ovsdb client connected to a database using OVSDB_MONITOR_V3 +(i.e., "monitor_cond_since" method) with the initial monitor condition +MC1. + +Assuming the following two transactions are executed on the +ovsdb-server: +TXN1: "insert record R1 in table T1" +TXN2: "insert record R2 in table T2" + +If the client's monitor condition MC1 for table T2 matches R2 then the +client will receive the following update3 message: +method="update3", "insert record R2 in table T2", last-txn-id=TXN2 + +At this point, if the presence of the new record R2 in the IDL triggers +the client to update its monitor condition to MC2 and add a clause for +table T1 which matches R1, a monitor_cond_change message is sent to the +server: +method="monitor_cond_change", "clauses from MC2" + +In normal operation the ovsdb-server will reply with a new update3 +message of the form: +method="update3", "insert record R1 in table T1", last-txn-id=TXN2 + +However, if the connection drops in the meantime, this last update might +get lost. + +It might happen that during the reconnect a new transaction happens +that modifies the original record R1: +TXN3: "modify record R1 in table T1" + +When the client reconnects, it will try to perform a fast resync by +sending: +method="monitor_cond_since", "clauses from MC2", last-txn-id=TXN2 + +Because TXN2 is still in the ovsdb-server transaction history, the +server replies with the changes from the most recent transactions only, +i.e., TXN3: +result="true", last-txbb-id=TXN3, "modify record R1 in table T1" + +This causes the IDL on the client in to end up in an inconsistent +state because it has never seen the update that created R1. + +Such a scenario is described in: +https://bugzilla.redhat.com/show_bug.cgi?id=1808580#c22 + +To avoid this issue, the IDL will now maintain (up to) 3 different +types of conditions for each DB table: +- new_cond: condition that has been set by the IDL client but has + not yet been sent to the server through monitor_cond_change. +- req_cond: condition that has been sent to the server but the reply + acknowledging the change hasn't been received yet. +- ack_cond: condition that has been acknowledged by the server. + +Whenever the IDL FSM is restarted (e.g., voluntary or involuntary +disconnect): +- if there is a known last_id txn-id the code ensures that new_cond + will contain the most recent condition set by the IDL client + (either req_cond if there was a request in flight, or new_cond + if the IDL client set a condition while the IDL was disconnected) +- if there is no known last_id txn-id the code ensures that ack_cond will + contain the most recent conditions set by the IDL client regardless + whether they were acked by the server or not. + +When monitor_cond_since/monitor_cond requests are sent they will +always include ack_cond and if new_cond is not NULL a follow up +monitor_cond_change will be generated afterwards. + +On the other hand ovsdb_idl_db_set_condition() will always modify new_cond. + +This ensures that updates of type "insert" that happened before the last +transaction known by the IDL but didn't match old monitor conditions are +sent upon reconnect if the monitor condition has changed to include them +in the meantime. + +Fixes: 403a6a0cb003 ("ovsdb-idl: Fast resync from server when connection reset.") +Signed-off-by: Dumitru Ceara +Acked-by: Han Zhou +Signed-off-by: Ilya Maximets +(cherry picked from upstream OVS commit ae25f8c8fff80a58cd0a15e2d3ae7ab1b4994e48) + +Change-Id: I4f3cd43cf69dfe76eb65c9709b759e5062c29e89 +--- + openvswitch-2.13.0/lib/ovsdb-idl-provider.h | 8 +- + openvswitch-2.13.0/lib/ovsdb-idl.c | 167 ++++++++++++++++++++++++---- + openvswitch-2.13.0/tests/ovsdb-idl.at | 56 ++++++++++ + 3 files changed, 206 insertions(+), 25 deletions(-) + +diff --git a/openvswitch-2.13.0/lib/ovsdb-idl-provider.h b/openvswitch-2.13.0/lib/ovsdb-idl-provider.h +index 30d1d08..00497d9 100644 +--- a/openvswitch-2.13.0/lib/ovsdb-idl-provider.h ++++ b/openvswitch-2.13.0/lib/ovsdb-idl-provider.h +@@ -122,8 +122,12 @@ struct ovsdb_idl_table { + unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX]; + struct ovs_list indexes; /* Contains "struct ovsdb_idl_index"s */ + struct ovs_list track_list; /* Tracked rows (ovsdb_idl_row.track_node). */ +- struct ovsdb_idl_condition condition; +- bool cond_changed; ++ struct ovsdb_idl_condition *ack_cond; /* Last condition acked by the ++ * server. */ ++ struct ovsdb_idl_condition *req_cond; /* Last condition requested to the ++ * server. */ ++ struct ovsdb_idl_condition *new_cond; /* Latest condition set by the IDL ++ * client. */ + }; + + struct ovsdb_idl_class { +diff --git a/openvswitch-2.13.0/lib/ovsdb-idl.c b/openvswitch-2.13.0/lib/ovsdb-idl.c +index 2d35179..8eb4213 100644 +--- a/openvswitch-2.13.0/lib/ovsdb-idl.c ++++ b/openvswitch-2.13.0/lib/ovsdb-idl.c +@@ -240,6 +240,10 @@ static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *, + struct ovsdb_idl_db *, + enum ovsdb_idl_monitor_method); + static void ovsdb_idl_db_clear(struct ovsdb_idl_db *db); ++static void ovsdb_idl_db_ack_condition(struct ovsdb_idl_db *db); ++static void ovsdb_idl_db_sync_condition(struct ovsdb_idl_db *db); ++static void ovsdb_idl_condition_move(struct ovsdb_idl_condition **dst, ++ struct ovsdb_idl_condition **src); + + struct ovsdb_idl { + struct ovsdb_idl_db server; +@@ -424,9 +428,11 @@ ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class, + = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY] + = table->change_seqno[OVSDB_IDL_CHANGE_DELETE] = 0; + table->db = db; +- ovsdb_idl_condition_init(&table->condition); +- ovsdb_idl_condition_add_clause_true(&table->condition); +- table->cond_changed = false; ++ table->ack_cond = NULL; ++ table->req_cond = NULL; ++ table->new_cond = xmalloc(sizeof *table->new_cond); ++ ovsdb_idl_condition_init(table->new_cond); ++ ovsdb_idl_condition_add_clause_true(table->new_cond); + } + db->monitor_id = json_array_create_2(json_string_create("monid"), + json_string_create(class->database)); +@@ -558,12 +564,15 @@ ovsdb_idl_set_shuffle_remotes(struct ovsdb_idl *idl, bool shuffle) + static void + ovsdb_idl_db_destroy(struct ovsdb_idl_db *db) + { ++ struct ovsdb_idl_condition *null_cond = NULL; + ovs_assert(!db->txn); + ovsdb_idl_db_txn_abort_all(db); + ovsdb_idl_db_clear(db); + for (size_t i = 0; i < db->class_->n_tables; i++) { + struct ovsdb_idl_table *table = &db->tables[i]; +- ovsdb_idl_condition_destroy(&table->condition); ++ ovsdb_idl_condition_move(&table->ack_cond, &null_cond); ++ ovsdb_idl_condition_move(&table->req_cond, &null_cond); ++ ovsdb_idl_condition_move(&table->new_cond, &null_cond); + ovsdb_idl_destroy_indexes(table); + shash_destroy(&table->columns); + hmap_destroy(&table->rows); +@@ -692,6 +701,12 @@ ovsdb_idl_send_request(struct ovsdb_idl *idl, struct jsonrpc_msg *request) + static void + ovsdb_idl_restart_fsm(struct ovsdb_idl *idl) + { ++ /* Resync data DB table conditions to avoid missing updates due to ++ * conditions that were in flight or changed locally while the connection ++ * was down. ++ */ ++ ovsdb_idl_db_sync_condition(&idl->data); ++ + ovsdb_idl_send_schema_request(idl, &idl->server); + ovsdb_idl_transition(idl, IDL_S_SERVER_SCHEMA_REQUESTED); + idl->data.monitoring = OVSDB_IDL_NOT_MONITORING; +@@ -799,7 +814,9 @@ ovsdb_idl_process_response(struct ovsdb_idl *idl, struct jsonrpc_msg *msg) + * do, it's a "monitor_cond_change", which means that the conditional + * monitor clauses were updated. + * +- * If further condition changes were pending, send them now. */ ++ * Mark the last requested conditions as acked and if further ++ * condition changes were pending, send them now. */ ++ ovsdb_idl_db_ack_condition(&idl->data); + ovsdb_idl_send_cond_change(idl); + idl->data.cond_seqno++; + break; +@@ -1495,30 +1512,60 @@ ovsdb_idl_condition_equals(const struct ovsdb_idl_condition *a, + } + + static void +-ovsdb_idl_condition_clone(struct ovsdb_idl_condition *dst, ++ovsdb_idl_condition_clone(struct ovsdb_idl_condition **dst, + const struct ovsdb_idl_condition *src) + { +- ovsdb_idl_condition_init(dst); ++ if (*dst) { ++ ovsdb_idl_condition_destroy(*dst); ++ } else { ++ *dst = xmalloc(sizeof **dst); ++ } ++ ovsdb_idl_condition_init(*dst); + +- dst->is_true = src->is_true; ++ (*dst)->is_true = src->is_true; + + const struct ovsdb_idl_clause *clause; + HMAP_FOR_EACH (clause, hmap_node, &src->clauses) { +- ovsdb_idl_condition_add_clause__(dst, clause, clause->hmap_node.hash); ++ ovsdb_idl_condition_add_clause__(*dst, clause, clause->hmap_node.hash); + } + } + ++static void ++ovsdb_idl_condition_move(struct ovsdb_idl_condition **dst, ++ struct ovsdb_idl_condition **src) ++{ ++ if (*dst) { ++ ovsdb_idl_condition_destroy(*dst); ++ free(*dst); ++ } ++ *dst = *src; ++ *src = NULL; ++} ++ + static unsigned int + ovsdb_idl_db_set_condition(struct ovsdb_idl_db *db, + const struct ovsdb_idl_table_class *tc, + const struct ovsdb_idl_condition *condition) + { ++ struct ovsdb_idl_condition *table_cond; + struct ovsdb_idl_table *table = ovsdb_idl_db_table_from_class(db, tc); + unsigned int seqno = db->cond_seqno; +- if (!ovsdb_idl_condition_equals(condition, &table->condition)) { +- ovsdb_idl_condition_destroy(&table->condition); +- ovsdb_idl_condition_clone(&table->condition, condition); +- db->cond_changed = table->cond_changed = true; ++ ++ /* Compare the new condition to the last known condition which can be ++ * either "new" (not sent yet), "requested" or "acked", in this order. ++ */ ++ if (table->new_cond) { ++ table_cond = table->new_cond; ++ } else if (table->req_cond) { ++ table_cond = table->req_cond; ++ } else { ++ table_cond = table->ack_cond; ++ } ++ ovs_assert(table_cond); ++ ++ if (!ovsdb_idl_condition_equals(condition, table_cond)) { ++ ovsdb_idl_condition_clone(&table->new_cond, condition); ++ db->cond_changed = true; + poll_immediate_wake(); + return seqno + 1; + } +@@ -1563,9 +1610,8 @@ ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd) + } + + static struct json * +-ovsdb_idl_create_cond_change_req(struct ovsdb_idl_table *table) ++ovsdb_idl_create_cond_change_req(const struct ovsdb_idl_condition *cond) + { +- const struct ovsdb_idl_condition *cond = &table->condition; + struct json *monitor_cond_change_request = json_object_create(); + struct json *cond_json = ovsdb_idl_condition_to_json(cond); + +@@ -1585,8 +1631,12 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db) + for (size_t i = 0; i < db->class_->n_tables; i++) { + struct ovsdb_idl_table *table = &db->tables[i]; + +- if (table->cond_changed) { +- struct json *req = ovsdb_idl_create_cond_change_req(table); ++ /* Always use the most recent conditions set by the IDL client when ++ * requesting monitor_cond_change, i.e., table->new_cond. ++ */ ++ if (table->new_cond) { ++ struct json *req = ++ ovsdb_idl_create_cond_change_req(table->new_cond); + if (req) { + if (!monitor_cond_change_requests) { + monitor_cond_change_requests = json_object_create(); +@@ -1595,7 +1645,11 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db) + table->class_->name, + json_array_create_1(req)); + } +- table->cond_changed = false; ++ /* Mark the new condition as requested by moving it to req_cond. ++ * If there's already requested condition that's a bug. ++ */ ++ ovs_assert(table->req_cond == NULL); ++ ovsdb_idl_condition_move(&table->req_cond, &table->new_cond); + } + } + +@@ -1610,6 +1664,73 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db) + return jsonrpc_create_request("monitor_cond_change", params, NULL); + } + ++/* Marks all requested table conditions in 'db' as acked by the server. ++ * It should be called when the server replies to monitor_cond_change ++ * requests. ++ */ ++static void ++ovsdb_idl_db_ack_condition(struct ovsdb_idl_db *db) ++{ ++ for (size_t i = 0; i < db->class_->n_tables; i++) { ++ struct ovsdb_idl_table *table = &db->tables[i]; ++ ++ if (table->req_cond) { ++ ovsdb_idl_condition_move(&table->ack_cond, &table->req_cond); ++ } ++ } ++} ++ ++/* Should be called when the IDL fsm is restarted and resyncs table conditions ++ * based on the state the DB is in: ++ * - if a non-zero last_id is available for the DB then upon reconnect ++ * the IDL should first request acked conditions to avoid missing updates ++ * about records that were added before the transaction with ++ * txn-id == last_id. If there were requested condition changes in flight ++ * (i.e., req_cond not NULL) and the IDL client didn't set new conditions ++ * (i.e., new_cond is NULL) then move req_cond to new_cond to trigger a ++ * follow up monitor_cond_change request. ++ * - if there's no last_id available for the DB then it's safe to use the ++ * latest conditions set by the IDL client even if they weren't acked yet. ++ */ ++static void ++ovsdb_idl_db_sync_condition(struct ovsdb_idl_db *db) ++{ ++ bool ack_all = uuid_is_zero(&db->last_id); ++ ++ db->cond_changed = false; ++ for (size_t i = 0; i < db->class_->n_tables; i++) { ++ struct ovsdb_idl_table *table = &db->tables[i]; ++ ++ /* When monitor_cond_since requests will be issued, the ++ * table->ack_cond condition will be added to the "where" clause". ++ * Follow up monitor_cond_change requests will use table->new_cond. ++ */ ++ if (ack_all) { ++ if (table->new_cond) { ++ ovsdb_idl_condition_move(&table->req_cond, &table->new_cond); ++ } ++ ++ if (table->req_cond) { ++ ovsdb_idl_condition_move(&table->ack_cond, &table->req_cond); ++ } ++ } else { ++ /* If there was no "unsent" condition but instead a ++ * monitor_cond_change request was in flight, move table->req_cond ++ * to table->new_cond and set db->cond_changed to trigger a new ++ * monitor_cond_change request. ++ * ++ * However, if a new condition has been set by the IDL client, ++ * monitor_cond_change will be sent anyway and will use the most ++ * recent table->new_cond so there's no need to update it here. ++ */ ++ if (table->req_cond && !table->new_cond) { ++ ovsdb_idl_condition_move(&table->new_cond, &table->req_cond); ++ db->cond_changed = true; ++ } ++ } ++ } ++} ++ + static void + ovsdb_idl_send_cond_change(struct ovsdb_idl *idl) + { +@@ -2064,13 +2185,15 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db, + monitor_request = json_object_create(); + json_object_put(monitor_request, "columns", columns); + +- const struct ovsdb_idl_condition *cond = &table->condition; ++ /* Always use acked conditions when requesting ++ * monitor_cond/monitor_cond_since. ++ */ ++ const struct ovsdb_idl_condition *cond = table->ack_cond; + if ((monitor_method == OVSDB_IDL_MM_MONITOR_COND || + monitor_method == OVSDB_IDL_MM_MONITOR_COND_SINCE) && +- !ovsdb_idl_condition_is_true(cond)) { ++ cond && !ovsdb_idl_condition_is_true(cond)) { + json_object_put(monitor_request, "where", + ovsdb_idl_condition_to_json(cond)); +- table->cond_changed = false; + } + json_object_put(monitor_requests, tc->name, + json_array_create_1(monitor_request)); +@@ -2078,8 +2201,6 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db, + } + free_schema(schema); + +- db->cond_changed = false; +- + struct json *params = json_array_create_3( + json_string_create(db->class_->database), + json_clone(db->monitor_id), +diff --git a/openvswitch-2.13.0/tests/ovsdb-idl.at b/openvswitch-2.13.0/tests/ovsdb-idl.at +index cc38d69..a5ca966 100644 +--- a/openvswitch-2.13.0/tests/ovsdb-idl.at ++++ b/openvswitch-2.13.0/tests/ovsdb-idl.at +@@ -1814,3 +1814,59 @@ m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY], + + OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL connects to leader], 3, ['remote']) + OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL reconnects to leader], 3, ['remote' '+remotestop' 'remote']) ++ ++# same as OVSDB_CHECK_IDL but uses C IDL implementation with tcp ++# with multiple remotes. ++m4_define([OVSDB_CHECK_CLUSTER_IDL_C], ++ [AT_SETUP([$1 - C - tcp]) ++ AT_KEYWORDS([ovsdb server idl positive tcp socket $5]) ++ m4_define([LPBK],[127.0.0.1]) ++ AT_CHECK([ovsdb_cluster_start_idltest $2 "ptcp:0:"LPBK]) ++ PARSE_LISTENING_PORT([s1.log], [TCP_PORT_1]) ++ PARSE_LISTENING_PORT([s2.log], [TCP_PORT_2]) ++ PARSE_LISTENING_PORT([s3.log], [TCP_PORT_3]) ++ remotes=tcp:LPBK:$TCP_PORT_1,tcp:LPBK:$TCP_PORT_2,tcp:LPBK:$TCP_PORT_3 ++ ++ m4_if([$3], [], [], ++ [AT_CHECK([ovsdb-client transact $remotes $3], [0], [ignore], [ignore])]) ++ AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl tcp:LPBK:$TCP_PORT_1 $4], ++ [0], [stdout], [ignore]) ++ AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]), ++ [0], [$5]) ++ AT_CLEANUP]) ++ ++# Checks that monitor_cond_since works fine when disconnects happen ++# with cond_change requests in flight (i.e., IDL is properly updated). ++OVSDB_CHECK_CLUSTER_IDL_C([simple idl, monitor_cond_since, cluster disconnect], ++ 3, ++ [['["idltest", ++ {"op": "insert", ++ "table": "simple", ++ "row": {"i": 1, ++ "r": 1.0, ++ "b": true}}, ++ {"op": "insert", ++ "table": "simple", ++ "row": {"i": 2, ++ "r": 1.0, ++ "b": true}}]']], ++ [['condition simple []' \ ++ 'condition simple [["i","==",2]]' \ ++ 'condition simple [["i","==",1]]' \ ++ '+reconnect' \ ++ '["idltest", ++ {"op": "update", ++ "table": "simple", ++ "where": [["i", "==", 1]], ++ "row": {"r": 2.0 }}]']], ++ [[000: change conditions ++001: empty ++002: change conditions ++003: i=2 r=1 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1> ++004: change conditions ++005: reconnect ++006: i=2 r=1 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1> ++007: {"error":null,"result":[{"count":1}]} ++008: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2> ++009: done ++]]) +-- +1.8.3.1 + diff --git a/SOURCES/0001-pinctrl-Fix-icmp6-packet-corruption-issue.patch b/SOURCES/0001-pinctrl-Fix-icmp6-packet-corruption-issue.patch new file mode 100644 index 0000000..adc0e60 --- /dev/null +++ b/SOURCES/0001-pinctrl-Fix-icmp6-packet-corruption-issue.patch @@ -0,0 +1,62 @@ +From a069dc4106bc641cbc8596e90b95308950b0bffa Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Tue, 12 May 2020 14:21:33 +0530 +Subject: [PATCH] pinctrl: Fix icmp6 packet corruption issue + +The commit f792b1a00b43("Fix ACL reject action for UDP packets.") +didn't updated the 'struct ip6_hdr' pointer after calling +dp_packet_put(), as dp_packet_put() can reallocate memory making the +old references to packet pointers invalid. + +This patch fixes this issue. + +Fixes: f792b1a00b43("Fix ACL reject action for UDP packets.") +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1834655 +Acked-by: Dumitru Ceara +Signed-off-by: Numan Siddique +--- + controller/pinctrl.c | 4 ++-- + tests/system-ovn.at | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index 6b0ac3483..d976ec82b 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -1570,8 +1570,6 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow, + } + ih->icmp6_base.icmp6_cksum = 0; + +- nh = dp_packet_l3(&packet); +- + /* RFC 4443: 3.1. + * + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +@@ -1594,9 +1592,11 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow, + } + + dp_packet_put(&packet, in_ip, in_ip_len); ++ nh = dp_packet_l3(&packet); + nh->ip6_plen = htons(ICMP6_DATA_HEADER_LEN + in_ip_len); + + icmpv6_csum = packet_csum_pseudoheader6(dp_packet_l3(&packet)); ++ ih = dp_packet_l4(&packet); + ih->icmp6_base.icmp6_cksum = csum_finish( + csum_continue(icmpv6_csum, ih, + in_ip_len + ICMP6_DATA_HEADER_LEN)); +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index 9a5ef1ec3..9ae6c6b1f 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -3967,7 +3967,7 @@ OVS_WAIT_UNTIL([ + NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej udp port 90 > sw0-p1-rej-udp.pcap &], [0]) + NS_CHECK_EXEC([sw0-p1-rej], [tcpdump -n -c 1 -i sw0-p1-rej icmp > sw0-p1-rej-icmp.pcap &], [0]) + +-echo "foo" > foo ++printf '.%.0s' {1..100} > foo + OVS_WAIT_UNTIL([ + ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo + c=$(cat sw0-p1-rej-icmp.pcap | grep \ +-- +2.26.2 + diff --git a/SOURCES/0001-pinctrl-Handle-service-monitors-even-if-the-lport-do.patch b/SOURCES/0001-pinctrl-Handle-service-monitors-even-if-the-lport-do.patch new file mode 100644 index 0000000..5932a4f --- /dev/null +++ b/SOURCES/0001-pinctrl-Handle-service-monitors-even-if-the-lport-do.patch @@ -0,0 +1,95 @@ +From 88677e5c2051a1880db61cbb22e4ab48659bc1a8 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Fri, 17 Apr 2020 11:45:56 +0530 +Subject: [PATCH] pinctrl: Handle service monitors even if the lport doesn't + have IPv4 addresses set. + +If a logical port is only configured with MAC address(es) in the +Logical_Switch_Port.addresses, pinctrl is ignoring the service monitors +configured for that logical port. This patch allows that. + +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1801058 +Acked-by: Mark Michelson +Signed-off-by: Numan Siddique +--- + controller/pinctrl.c | 5 +++++ + tests/ovn.at | 31 +++++++++++++++++++++++++++++++ + tests/system-ovn.at | 4 ++-- + 3 files changed, 38 insertions(+), 2 deletions(-) + +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index a053938ec..8703641c2 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -5786,6 +5786,11 @@ sync_svc_monitors(struct ovsdb_idl_txn *ovnsb_idl_txn, + + if (mac_found) { + break; ++ } else if (!laddrs.n_ipv4_addrs) { ++ /* IPv4 address(es) are not configured. Use the first mac. */ ++ ea = laddrs.ea; ++ mac_found = true; ++ break; + } + } + +diff --git a/tests/ovn.at b/tests/ovn.at +index 3bc435e6d..0f02e8144 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -17918,6 +17918,37 @@ AT_CHECK([cat lflows.txt], [0], [dnl + table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;) + ]) + ++# Delete sw0-p1 ++ovn-nbctl lsp-del sw0-p1 ++ ++OVS_WAIT_UNTIL([test 1 = $(ovn-sbctl --bare --columns _uuid find \ ++service_monitor | sed '/^$/d' | wc -l)]) ++ ++# Add back sw0-p1 but without any IP address. ++ovn-nbctl lsp-add sw0 sw0-p1 ++ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03" -- \ ++lsp-set-port-security sw0-p1 "50:54:00:00:00:03" ++ ++OVS_WAIT_UNTIL([test 2 = $(ovn-sbctl --bare --columns status find \ ++service_monitor | grep offline | wc -l)]) ++ ++ovn-nbctl lsp-del sw0-p1 ++ovn-nbctl lsp-del sw1-p1 ++OVS_WAIT_UNTIL([test 0 = $(ovn-sbctl --bare --columns _uuid find \ ++service_monitor | sed '/^$/d' | wc -l)]) ++ ++# Add back sw0-p1 but without any address set. ++ovn-nbctl lsp-add sw0 sw0-p1 ++ ++OVS_WAIT_UNTIL([test 1 = $(ovn-sbctl --bare --columns _uuid find \ ++service_monitor | sed '/^$/d' | wc -l)]) ++ ++OVS_WAIT_UNTIL([test 0 = $(ovn-sbctl --bare --columns status find \ ++service_monitor | grep offline | wc -l)]) ++ ++OVS_WAIT_UNTIL([test 0 = $(ovn-sbctl --bare --columns status find \ ++service_monitor | grep online | wc -l)]) ++ + OVN_CLEANUP([hv1], [hv2]) + AT_CLEANUP + +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index 000b3f13b..bdb9768d2 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -3356,8 +3356,8 @@ start_daemon ovn-controller + ovn-nbctl ls-add sw0 + + ovn-nbctl lsp-add sw0 sw0-p1 +-ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3" +-ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3" ++ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03" ++ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03" + + ovn-nbctl lsp-add sw0 sw0-p2 + ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4" +-- +2.25.1 + diff --git a/SOURCES/0001-system-tests-Fix-occasional-failure-of-the-test-Load.patch b/SOURCES/0001-system-tests-Fix-occasional-failure-of-the-test-Load.patch new file mode 100644 index 0000000..335fe6d --- /dev/null +++ b/SOURCES/0001-system-tests-Fix-occasional-failure-of-the-test-Load.patch @@ -0,0 +1,35 @@ +From b1a0a1aecc5e49e465f7ff42b179f6c5ce683397 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Fri, 28 Feb 2020 22:09:43 +0530 +Subject: [PATCH 1/3] system tests: Fix occasional failure of the test - "Load + balancer health checks". + +Due to some timing issues, ovn-controller logs the warning message - +"handle service check: Service monitor not found". This can happen +if the service monitor is created in SB DB before the port for +the service is bound. This patch adds this warning message to the +WHITELIST of OVS_TRAFFIC_VSWITCHD_STOP. + +Signed-off-by: Numan Siddique +Acked-by: Dumitru Ceara +--- + tests/system-ovn.at | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index 53da910cb..9ed3df754 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -3462,7 +3462,8 @@ OVS_APP_EXIT_AND_WAIT([ovn-northd]) + + as + OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +-/connection dropped.*/d"]) ++/connection dropped.*/d ++/Service monitor not found.*/d"]) + + AT_CLEANUP + +-- +2.24.1 + diff --git a/SOURCES/0001-tests-Wait-up-to-OVS_CTL_TIMEOUT-seconds.patch b/SOURCES/0001-tests-Wait-up-to-OVS_CTL_TIMEOUT-seconds.patch new file mode 100644 index 0000000..bedc1da --- /dev/null +++ b/SOURCES/0001-tests-Wait-up-to-OVS_CTL_TIMEOUT-seconds.patch @@ -0,0 +1,45 @@ +From 2e84aada0b45d2f8739c2fdbc351098fc1c09c26 Mon Sep 17 00:00:00 2001 +Message-Id: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com> +From: Ilya Maximets +Date: Wed, 6 Nov 2019 17:29:58 +0100 +Subject: [PATCH 1/3] tests: Wait up to OVS_CTL_TIMEOUT seconds. + +While running tests under valgrind, it could take more than 10 seconds +for process to disappear after successful 'ovs-appctl exit' command. + +Same applies to some other events that tests are waiting for with +OVS_WAIT macro. This makes tests to fail frequently under valgrind. + +Using OVS_CTL_TIMEOUT variable instead of constant 10 seconds seems +reasonable to avoid this issue because it controls timeouts of all +control utilities and needs to be adjusted while running under valgrind +anyway. + +Signed-off-by: Ilya Maximets +Acked-by: Aaron Conole +Signed-off-by: William Tu +Signed-off-by: Numan Siddique +Signed-off-by: Lorenzo Bianconi +--- + tests/ovs-macros.at | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/ovs-macros.at b/tests/ovs-macros.at +index b2e619f76..3dcf8f96d 100644 +--- a/tests/ovs-macros.at ++++ b/tests/ovs-macros.at +@@ -208,9 +208,9 @@ ovs_wait () { + sleep 0.1 + if ovs_wait_cond; then echo "$1: wait succeeded quickly" >&AS_MESSAGE_LOG_FD; return 0; fi + +- # Then wait up to 10 seconds. ++ # Then wait up to OVS_CTL_TIMEOUT seconds. + local d +- for d in 1 2 3 4 5 6 7 8 9 10; do ++ for d in `seq 1 "$OVS_CTL_TIMEOUT"`; do + sleep 1 + if ovs_wait_cond; then echo "$1: wait succeeded after $d seconds" >&AS_MESSAGE_LOG_FD; return 0; fi + done +-- +2.25.2 + diff --git a/SOURCES/0002-Broadcast-DHCPREPLY-when-BROADCAST-flag-is-set.patch b/SOURCES/0002-Broadcast-DHCPREPLY-when-BROADCAST-flag-is-set.patch new file mode 100644 index 0000000..f11664d --- /dev/null +++ b/SOURCES/0002-Broadcast-DHCPREPLY-when-BROADCAST-flag-is-set.patch @@ -0,0 +1,400 @@ +From e982e99e5ee4eb9b65e0d3fe59d0975505ea625b Mon Sep 17 00:00:00 2001 +From: Ihar Hrachyshka +Date: Thu, 5 Mar 2020 20:44:24 -0500 +Subject: [PATCH 2/3] Broadcast DHCPREPLY when BROADCAST flag is set + +As per RFC2131, section 4.1: + A server or relay agent sending or relaying a DHCP message directly + to a DHCP client (i.e., not to a relay agent specified in the + 'giaddr' field) SHOULD examine the BROADCAST bit in the 'flags' + field. If this bit is set to 1, the DHCP message SHOULD be sent as + an IP broadcast using an IP broadcast address (preferably 0xffffffff) + as the IP destination address and the link-layer broadcast address as + the link-layer destination address. + +This patch changes destination IP address to 255.255.255.255 when client +set BROADCAST flag in their DHCPREQUEST. Note: the offered IP address is +still part of the DHCP payload. + +While the new DHCP response is sent as a broadcast IP frame, it's +handled locally, as any other DHCP reply by the native responder. +Meaning, the reply is sent to the client port that initiated the DHCP +session only. + +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1801006 + +Signed-off-by: Ihar Hrachyshka +Signed-off-by: Numan Siddique + +(cherry-picked from upstream commit 4f8045b3b5f2c3376f86f5edc4e3f7507c2b1148) +--- + controller/pinctrl.c | 15 +++++++ + lib/ovn-l7.h | 2 + + northd/ovn-northd.8.xml | 5 +-- + northd/ovn-northd.c | 7 ++- + tests/ovn.at | 98 +++++++++++++++++++++++++++++------------ + 5 files changed, 93 insertions(+), 34 deletions(-) + +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index dc8d3fd28..8bf19776c 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -966,6 +966,12 @@ pinctrl_handle_tcp_reset(struct rconn *swconn, const struct flow *ip_flow, + dp_packet_uninit(&packet); + } + ++static bool ++is_dhcp_flags_broadcast(ovs_be16 flags) ++{ ++ return flags & htons(DHCP_BROADCAST_FLAG); ++} ++ + /* Called with in the pinctrl_handler thread context. */ + static void + pinctrl_handle_put_dhcp_opts( +@@ -1190,7 +1196,16 @@ pinctrl_handle_put_dhcp_opts( + + udp->udp_len = htons(new_l4_size); + ++ /* Send a broadcast IP frame when BROADCAST flag is set. */ + struct ip_header *out_ip = dp_packet_l3(&pkt_out); ++ ovs_be32 ip_dst; ++ if (!is_dhcp_flags_broadcast(dhcp_data->flags)) { ++ ip_dst = *offer_ip; ++ } else { ++ ip_dst = htonl(0xffffffff); ++ } ++ put_16aligned_be32(&out_ip->ip_dst, ip_dst); ++ + out_ip->ip_tot_len = htons(pkt_out.l4_ofs - pkt_out.l3_ofs + new_l4_size); + udp->udp_csum = 0; + /* Checksum needs to be initialized to zero. */ +diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h +index f20d86c39..931e6ffcf 100644 +--- a/lib/ovn-l7.h ++++ b/lib/ovn-l7.h +@@ -34,6 +34,8 @@ struct gen_opts_map { + size_t code; + }; + ++#define DHCP_BROADCAST_FLAG 0x8000 ++ + #define DHCP_OPTION(NAME, CODE, TYPE) \ + {.name = NAME, .code = CODE, .type = TYPE} + +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index d80f8cf8d..b6cfa3e90 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -937,7 +937,6 @@ next; +
          + eth.dst = eth.src;
          + eth.src = E;
          +-ip4.dst = A;
          + ip4.src = S;
          + udp.src = 67;
          + udp.dst = 68;
          +@@ -948,8 +947,8 @@ output;
          + 
          +         

          + where E is the server MAC address and S is the +- server IPv4 address defined in the DHCPv4 options and A is +- the IPv4 address defined in the logical port's addresses column. ++ server IPv4 address defined in the DHCPv4 options. Note that ++ ip4.dst field is handled by put_dhcp_opts. +

          + +

          +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 0d43322cf..217a8c894 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -4276,10 +4276,9 @@ build_dhcpv4_action(struct ovn_port *op, ovs_be32 offer_ip, + ds_put_cstr(options_action, "); next;"); + + ds_put_format(response_action, "eth.dst = eth.src; eth.src = %s; " +- "ip4.dst = "IP_FMT"; ip4.src = %s; udp.src = 67; " +- "udp.dst = 68; outport = inport; flags.loopback = 1; " +- "output;", +- server_mac, IP_ARGS(offer_ip), server_ip); ++ "ip4.src = %s; udp.src = 67; udp.dst = 68; " ++ "outport = inport; flags.loopback = 1; output;", ++ server_mac, server_ip); + + ds_put_format(ipv4_addr_match, + "ip4.src == "IP_FMT" && ip4.dst == {%s, 255.255.255.255}", +diff --git a/tests/ovn.at b/tests/ovn.at +index a04f22c4c..8de4b5ceb 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -4595,10 +4595,11 @@ sleep 2 + as hv1 ovs-vsctl show + + # This shell function sends a DHCP request packet +-# test_dhcp INPORT SRC_MAC DHCP_TYPE OFFER_IP REQUEST_IP ... ++# test_dhcp INPORT SRC_MAC DHCP_TYPE BROADCAST CIADDR OFFER_IP REQUEST_IP USE_IP ... + test_dhcp() { +- local inport=$1 src_mac=$2 dhcp_type=$3 ciaddr=$4 offer_ip=$5 request_ip=$6 use_ip=$7 +- shift; shift; shift; shift; shift; shift; shift; ++ local inport=$1 src_mac=$2 dhcp_type=$3 broadcast=$4 ciaddr=$5 offer_ip=$6 request_ip=$7 use_ip=$8 ++ shift; shift; shift; shift; shift; shift; shift; shift; ++ + if test $use_ip != 0; then + src_ip=$1 + dst_ip=$2 +@@ -4607,6 +4608,7 @@ test_dhcp() { + src_ip=`ip_to_hex 0 0 0 0` + dst_ip=`ip_to_hex 255 255 255 255` + fi ++ + if test $request_ip != 0; then + ip_len=0120 + udp_len=010b +@@ -4614,10 +4616,19 @@ test_dhcp() { + ip_len=011a + udp_len=0106 + fi ++ ++ if test $broadcast != 0; then ++ flags=8000 ++ reply_dst_ip=`ip_to_hex 255 255 255 255` ++ else ++ flags=0000 ++ reply_dst_ip=${offer_ip} ++ fi ++ + local request=ffffffffffff${src_mac}08004510${ip_len}0000000080110000${src_ip}${dst_ip} + # udp header and dhcp header + request=${request}00440043${udp_len}0000 +- request=${request}010106006359aa7600000000${ciaddr}000000000000000000000000${src_mac} ++ request=${request}010106006359aa760000${flags}${ciaddr}000000000000000000000000${src_mac} + # client hardware padding + request=${request}00000000000000000000 + # server hostname +@@ -4655,10 +4666,10 @@ test_dhcp() { + ip_len=$(printf "%x" $ip_len) + udp_len=$(printf "%x" $udp_len) + # $ip_len var will be in 3 digits i.e 134. So adding a '0' before $ip_len +- local reply=${src_mac}${srv_mac}080045100${ip_len}000000008011XXXX${srv_ip}${offer_ip} ++ local reply=${src_mac}${srv_mac}080045100${ip_len}000000008011XXXX${srv_ip}${reply_dst_ip} + # udp header and dhcp header. + # $udp_len var will be in 3 digits. So adding a '0' before $udp_len +- reply=${reply}004300440${udp_len}0000020106006359aa7600000000${ciaddr} ++ reply=${reply}004300440${udp_len}0000020106006359aa760000${flags}${ciaddr} + # your ip address; 0 for NAK + if test $dhcp_reply_type = 06; then + reply=${reply}00000000 +@@ -4729,7 +4740,7 @@ server_ip=`ip_to_hex 10 0 0 1` + ciaddr=`ip_to_hex 0 0 0 0` + request_ip=0 + expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001 +-test_dhcp 1 f00000000001 01 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts ++test_dhcp 1 f00000000001 01 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts + + # NXT_RESUMEs should be 1. + OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) +@@ -4755,7 +4766,7 @@ server_ip=`ip_to_hex 10 0 0 1` + ciaddr=`ip_to_hex 0 0 0 0` + request_ip=$offer_ip + expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001 +-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 05 $expected_dhcp_opts ++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 05 $expected_dhcp_opts + + # NXT_RESUMEs should be 2. + OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) +@@ -4779,7 +4790,7 @@ server_ip=`ip_to_hex 10 0 0 1` + ciaddr=`ip_to_hex 0 0 0 0` + request_ip=`ip_to_hex 10 0 0 7` + expected_dhcp_opts="" +-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 06 $expected_dhcp_opts ++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 06 $expected_dhcp_opts + + # NXT_RESUMEs should be 3. + OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) +@@ -4803,7 +4814,7 @@ rm -f 2.expected + ciaddr=`ip_to_hex 0 0 0 0` + offer_ip=0 + request_ip=0 +-test_dhcp 2 f00000000002 08 $ciaddr $offer_ip $request_ip 0 1 1 ++test_dhcp 2 f00000000002 08 0 $ciaddr $offer_ip $request_ip 0 1 1 + + # NXT_RESUMEs should be 4. + OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) +@@ -4820,12 +4831,12 @@ rm -f 2.expected + # ls2-lp2 (vif4-tx.pcap) should receive the DHCPv4 request packet once. + + ciaddr=`ip_to_hex 0 0 0 0` +-test_dhcp 3 f00000000003 01 $ciaddr 0 0 4 0 ++test_dhcp 3 f00000000003 01 0 $ciaddr 0 0 4 0 + + # Send DHCPv4 packet on ls2-lp2. "router" DHCPv4 option is not defined for + # this lport. + ciaddr=`ip_to_hex 0 0 0 0` +-test_dhcp 4 f00000000004 01 $ciaddr 0 0 3 0 ++test_dhcp 4 f00000000004 01 0 $ciaddr 0 0 3 0 + + # NXT_RESUMEs should be 4. + OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) +@@ -4842,7 +4853,7 @@ request_ip=0 + src_ip=$offer_ip + dst_ip=$server_ip + expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001 +-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts ++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts + + # NXT_RESUMEs should be 5. + OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) +@@ -4868,7 +4879,7 @@ request_ip=0 + src_ip=$offer_ip + dst_ip=`ip_to_hex 255 255 255 255` + expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001 +-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts ++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts + + # NXT_RESUMEs should be 6. + OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) +@@ -4894,7 +4905,7 @@ request_ip=0 + src_ip=$offer_ip + dst_ip=`ip_to_hex 255 255 255 255` + expected_dhcp_opts="" +-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts ++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts + + # NXT_RESUMEs should be 7. + OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) +@@ -4920,7 +4931,7 @@ request_ip=0 + src_ip=$offer_ip + dst_ip=`ip_to_hex 255 255 255 255` + expected_dhcp_opts="" +-test_dhcp 2 f00000000002 03 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts ++test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts + + # NXT_RESUMEs should be 8. + OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) +@@ -4942,7 +4953,7 @@ rm -f 2.expected + ciaddr=`ip_to_hex 0 0 0 0` + src_ip=`ip_to_hex 10 0 0 6` + dst_ip=`ip_to_hex 10 0 0 4` +-test_dhcp 2 f00000000002 03 $ciaddr 0 0 1 $src_ip $dst_ip 1 ++test_dhcp 2 f00000000002 03 0 $ciaddr 0 0 1 $src_ip $dst_ip 1 + + # NXT_RESUMEs should be 8. + OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) +@@ -4950,6 +4961,29 @@ OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + # vif1-tx.pcap should have received the DHCPv4 request packet + OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected]) + ++reset_pcap_file hv1-vif1 hv1/vif1 ++reset_pcap_file hv1-vif2 hv1/vif2 ++rm -f 1.expected ++rm -f 2.expected ++ ++# Send DHCPDISCOVER with BROADCAST flag on. ++offer_ip=`ip_to_hex 10 0 0 4` ++server_ip=`ip_to_hex 10 0 0 1` ++ciaddr=`ip_to_hex 0 0 0 0` ++request_ip=0 ++expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001 ++test_dhcp 1 f00000000001 01 1 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts ++ ++# NXT_RESUMEs should be 9. ++OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) ++ ++$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets ++cat 1.expected | cut -c -48 > expout ++AT_CHECK([cat 1.packets | cut -c -48], [0], [expout]) ++# Skipping the IPv4 checksum. ++cat 1.expected | cut -c 53- > expout ++AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout]) ++ + OVN_CLEANUP([hv1]) + + AT_CLEANUP +@@ -13220,10 +13254,11 @@ as hv1 + ovs-vsctl show + + # This shell function sends a DHCP request packet +-# test_dhcp INPORT SRC_MAC DHCP_TYPE OFFER_IP ... ++# test_dhcp INPORT SRC_MAC DHCP_TYPE BROADCAST OFFER_IP ... + test_dhcp() { +- local inport=$1 src_mac=$2 dhcp_type=$3 offer_ip=$4 use_ip=$5 +- shift; shift; shift; shift; shift; ++ local inport=$1 src_mac=$2 dhcp_type=$3 broadcast=$4 offer_ip=$5 use_ip=$6 ++ shift; shift; shift; shift; shift; shift; ++ + if test $use_ip != 0; then + src_ip=$1 + dst_ip=$2 +@@ -13232,10 +13267,19 @@ test_dhcp() { + src_ip=`ip_to_hex 0 0 0 0` + dst_ip=`ip_to_hex 255 255 255 255` + fi ++ ++ if test $broadcast != 0; then ++ flags=8000 ++ reply_dst_ip=`ip_to_hex 255 255 255 255` ++ else ++ flags=0000 ++ reply_dst_ip=${offer_ip} ++ fi ++ + local request=ffffffffffff${src_mac}0800451001100000000080110000${src_ip}${dst_ip} + # udp header and dhcp header + request=${request}0044004300fc0000 +- request=${request}010106006359aa760000000000000000000000000000000000000000${src_mac} ++ request=${request}010106006359aa760000${flags}00000000000000000000000000000000${src_mac} + # client hardware padding + request=${request}00000000000000000000 + # server hostname +@@ -13259,10 +13303,10 @@ test_dhcp() { + ip_len=$(printf "%x" $ip_len) + udp_len=$(printf "%x" $udp_len) + # $ip_len var will be in 3 digits i.e 134. So adding a '0' before $ip_len +- local reply=${src_mac}${srv_mac}080045100${ip_len}000000008011XXXX${srv_ip}${offer_ip} ++ local reply=${src_mac}${srv_mac}080045100${ip_len}000000008011XXXX${srv_ip}${reply_dst_ip} + # udp header and dhcp header. + # $udp_len var will be in 3 digits. So adding a '0' before $udp_len +- reply=${reply}004300440${udp_len}0000020106006359aa760000000000000000 ++ reply=${reply}004300440${udp_len}0000020106006359aa760000${flags}00000000 + # your ip address + reply=${reply}${offer_ip} + # next server ip address, relay agent ip address, client mac address +@@ -13381,7 +13425,7 @@ offer_ip=`ip_to_hex 10 0 0 6` + server_ip=`ip_to_hex 10 0 0 1` + server_mac=ff1000000001 + expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001 +-test_dhcp 1 f00000000003 01 $offer_ip 0 $server_mac $server_ip \ ++test_dhcp 1 f00000000003 01 0 $offer_ip 0 $server_mac $server_ip \ + $expected_dhcp_opts + + # NXT_RESUMEs should be 1 in hv1. +@@ -13479,7 +13523,7 @@ offer_ip=`ip_to_hex 10 0 0 6` + server_ip=`ip_to_hex 10 0 0 1` + server_mac=ff1000000001 + expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001 +-test_dhcp 1 f00000000003 01 $offer_ip 0 $server_mac $server_ip \ ++test_dhcp 1 f00000000003 01 0 $offer_ip 0 $server_mac $server_ip \ + $expected_dhcp_opts + + # NXT_RESUMEs should be 2 in hv1. +@@ -13589,7 +13633,7 @@ offer_ip=`ip_to_hex 10 0 0 6` + server_ip=`ip_to_hex 10 0 0 1` + server_mac=ff1000000001 + expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001 +-test_dhcp 1 f00000000003 01 $offer_ip 0 $server_mac $server_ip \ ++test_dhcp 1 f00000000003 01 0 $offer_ip 0 $server_mac $server_ip \ + $expected_dhcp_opts + + # NXT_RESUMEs should be 3 in hv1. +@@ -13669,7 +13713,7 @@ offer_ip=`ip_to_hex 10 0 0 6` + server_ip=`ip_to_hex 10 0 0 1` + server_mac=ff1000000001 + expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001 +-test_dhcp 1 f00000000003 01 $offer_ip 0 $server_mac $server_ip \ ++test_dhcp 1 f00000000003 01 0 $offer_ip 0 $server_mac $server_ip \ + $expected_dhcp_opts + + # NXT_RESUMEs should be 4 in hv1. +-- +2.24.1 + diff --git a/SOURCES/0002-Create-daemon-pidfiles-in-ovn-run-dir.patch b/SOURCES/0002-Create-daemon-pidfiles-in-ovn-run-dir.patch new file mode 100644 index 0000000..45129b5 --- /dev/null +++ b/SOURCES/0002-Create-daemon-pidfiles-in-ovn-run-dir.patch @@ -0,0 +1,351 @@ +From d80be07ca318603524508402e044474571c1f642 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Thu, 23 Apr 2020 12:53:23 +0530 +Subject: [PATCH 2/2] Create daemon pidfiles in ovn run dir. + +If an OVN service is started with --pidfile option, the pidfile +is created in the ovs rundir. This patch fixes it by using the ovn rundir +if either the pidfile is not specified or if specified, it is not +absolute path. + +Signed-off-by: Numan Siddique +Acked-by: Dumitru Ceara +Signed-off-by: Mark Michelson +--- + controller-vtep/ovn-controller-vtep.c | 6 +-- + controller/ovn-controller.c | 6 +-- + ic/ovn-ic.c | 6 +-- + lib/ovn-util.c | 26 ++++++++++++ + lib/ovn-util.h | 60 +++++++++++++++++++++++++++ + northd/ovn-northd.c | 6 +-- + utilities/ovn-nbctl.c | 10 ++--- + utilities/ovn-trace.c | 6 +-- + 8 files changed, 106 insertions(+), 20 deletions(-) + +diff --git a/controller-vtep/ovn-controller-vtep.c b/controller-vtep/ovn-controller-vtep.c +index 253a709ab..c13280bc0 100644 +--- a/controller-vtep/ovn-controller-vtep.c ++++ b/controller-vtep/ovn-controller-vtep.c +@@ -169,7 +169,7 @@ parse_options(int argc, char *argv[]) + OPT_PEER_CA_CERT = UCHAR_MAX + 1, + OPT_BOOTSTRAP_CA_CERT, + VLOG_OPTION_ENUMS, +- DAEMON_OPTION_ENUMS, ++ OVN_DAEMON_OPTION_ENUMS, + SSL_OPTION_ENUMS, + }; + +@@ -179,7 +179,7 @@ parse_options(int argc, char *argv[]) + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + VLOG_LONG_OPTIONS, +- DAEMON_LONG_OPTIONS, ++ OVN_DAEMON_LONG_OPTIONS, + STREAM_SSL_LONG_OPTIONS, + {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT}, + {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT}, +@@ -212,7 +212,7 @@ parse_options(int argc, char *argv[]) + exit(EXIT_SUCCESS); + + VLOG_OPTION_HANDLERS +- DAEMON_OPTION_HANDLERS ++ OVN_DAEMON_OPTION_HANDLERS + STREAM_SSL_OPTION_HANDLERS + + case OPT_PEER_CA_CERT: +diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c +index 4d21ba0fd..6ff897325 100644 +--- a/controller/ovn-controller.c ++++ b/controller/ovn-controller.c +@@ -2268,7 +2268,7 @@ parse_options(int argc, char *argv[]) + OPT_PEER_CA_CERT = UCHAR_MAX + 1, + OPT_BOOTSTRAP_CA_CERT, + VLOG_OPTION_ENUMS, +- DAEMON_OPTION_ENUMS, ++ OVN_DAEMON_OPTION_ENUMS, + SSL_OPTION_ENUMS, + }; + +@@ -2276,7 +2276,7 @@ parse_options(int argc, char *argv[]) + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + VLOG_LONG_OPTIONS, +- DAEMON_LONG_OPTIONS, ++ OVN_DAEMON_LONG_OPTIONS, + STREAM_SSL_LONG_OPTIONS, + {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT}, + {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT}, +@@ -2301,7 +2301,7 @@ parse_options(int argc, char *argv[]) + exit(EXIT_SUCCESS); + + VLOG_OPTION_HANDLERS +- DAEMON_OPTION_HANDLERS ++ OVN_DAEMON_OPTION_HANDLERS + STREAM_SSL_OPTION_HANDLERS + + case OPT_PEER_CA_CERT: +diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c +index d931ca50f..a1ed25623 100644 +--- a/ic/ovn-ic.c ++++ b/ic/ovn-ic.c +@@ -1461,7 +1461,7 @@ static void + parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) + { + enum { +- DAEMON_OPTION_ENUMS, ++ OVN_DAEMON_OPTION_ENUMS, + VLOG_OPTION_ENUMS, + SSL_OPTION_ENUMS, + }; +@@ -1474,7 +1474,7 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) + {"help", no_argument, NULL, 'h'}, + {"options", no_argument, NULL, 'o'}, + {"version", no_argument, NULL, 'V'}, +- DAEMON_LONG_OPTIONS, ++ OVN_DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, + STREAM_SSL_LONG_OPTIONS, + {NULL, 0, NULL, 0}, +@@ -1490,7 +1490,7 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) + } + + switch (c) { +- DAEMON_OPTION_HANDLERS; ++ OVN_DAEMON_OPTION_HANDLERS; + VLOG_OPTION_HANDLERS; + STREAM_SSL_OPTION_HANDLERS; + +diff --git a/lib/ovn-util.c b/lib/ovn-util.c +index 1b30c2e9a..3482edb8d 100644 +--- a/lib/ovn-util.c ++++ b/lib/ovn-util.c +@@ -15,6 +15,7 @@ + #include + #include + ++#include "daemon.h" + #include "ovn-util.h" + #include "ovn-dirs.h" + #include "openvswitch/vlog.h" +@@ -394,6 +395,31 @@ get_abs_unix_ctl_path(const char *path) + return abs_path; + } + ++void ++ovn_set_pidfile(const char *name) ++{ ++ char *pidfile_name = NULL; ++ ++#ifndef _WIN32 ++ pidfile_name = name ? abs_file_name(ovn_rundir(), name) ++ : xasprintf("%s/%s.pid", ovn_rundir(), program_name); ++#else ++ if (name) { ++ if (strchr(name, ':')) { ++ pidfile_name = xstrdup(name); ++ } else { ++ pidfile_name = xasprintf("%s/%s", ovn_rundir(), name); ++ } ++ } else { ++ pidfile_name = xasprintf("%s/%s.pid", ovn_rundir(), program_name); ++ } ++#endif ++ ++ /* Call openvswitch lib function. */ ++ set_pidfile(pidfile_name); ++ free(pidfile_name); ++} ++ + /* l3gateway, chassisredirect, and patch + * are not in this list since they are + * only set in the SB DB by northd +diff --git a/lib/ovn-util.h b/lib/ovn-util.h +index 4076e8b9a..ec5f2cf5a 100644 +--- a/lib/ovn-util.h ++++ b/lib/ovn-util.h +@@ -112,6 +112,7 @@ uint32_t ovn_allocate_tnlid(struct hmap *set, const char *name, uint32_t min, + uint32_t max, uint32_t *hint); + + char *ovn_chassis_redirect_name(const char *port_name); ++void ovn_set_pidfile(const char *name); + + /* An IPv4 or IPv6 address */ + struct v46_ip { +@@ -129,4 +130,63 @@ bool ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2); + * Caller must free the returned string. + */ + char *str_tolower(const char *orig); ++ ++/* OVN daemon options. Taken from ovs/lib/daemon.h. */ ++#define OVN_DAEMON_OPTION_ENUMS \ ++ OVN_OPT_DETACH, \ ++ OVN_OPT_NO_SELF_CONFINEMENT, \ ++ OVN_OPT_NO_CHDIR, \ ++ OVN_OPT_OVERWRITE_PIDFILE, \ ++ OVN_OPT_PIDFILE, \ ++ OVN_OPT_MONITOR, \ ++ OVN_OPT_USER_GROUP ++ ++#define OVN_DAEMON_LONG_OPTIONS \ ++ {"detach", no_argument, NULL, OVN_OPT_DETACH}, \ ++ {"no-self-confinement", no_argument, NULL, \ ++ OVN_OPT_NO_SELF_CONFINEMENT}, \ ++ {"no-chdir", no_argument, NULL, OVN_OPT_NO_CHDIR}, \ ++ {"pidfile", optional_argument, NULL, OVN_OPT_PIDFILE}, \ ++ {"overwrite-pidfile", no_argument, NULL, OVN_OPT_OVERWRITE_PIDFILE}, \ ++ {"monitor", no_argument, NULL, OVN_OPT_MONITOR}, \ ++ {"user", required_argument, NULL, OVN_OPT_USER_GROUP} ++ ++#define OVN_DAEMON_OPTION_HANDLERS \ ++ case OVN_OPT_DETACH: \ ++ set_detach(); \ ++ break; \ ++ \ ++ case OVN_OPT_NO_SELF_CONFINEMENT: \ ++ daemon_disable_self_confinement(); \ ++ break; \ ++ \ ++ case OVN_OPT_NO_CHDIR: \ ++ set_no_chdir(); \ ++ break; \ ++ \ ++ case OVN_OPT_PIDFILE: \ ++ ovn_set_pidfile(optarg); \ ++ break; \ ++ \ ++ case OVN_OPT_OVERWRITE_PIDFILE: \ ++ ignore_existing_pidfile(); \ ++ break; \ ++ \ ++ case OVN_OPT_MONITOR: \ ++ daemon_set_monitor(); \ ++ break; \ ++ \ ++ case OVN_OPT_USER_GROUP: \ ++ daemon_set_new_user(optarg); \ ++ break; ++ ++#define OVN_DAEMON_OPTION_CASES \ ++ case OVN_OPT_DETACH: \ ++ case OVN_OPT_NO_SELF_CONFINEMENT: \ ++ case OVN_OPT_NO_CHDIR: \ ++ case OVN_OPT_PIDFILE: \ ++ case OVN_OPT_OVERWRITE_PIDFILE: \ ++ case OVN_OPT_MONITOR: \ ++ case OVN_OPT_USER_GROUP: ++ + #endif +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 515722c5d..d3d481ab8 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -11607,7 +11607,7 @@ static void + parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) + { + enum { +- DAEMON_OPTION_ENUMS, ++ OVN_DAEMON_OPTION_ENUMS, + VLOG_OPTION_ENUMS, + SSL_OPTION_ENUMS, + }; +@@ -11618,7 +11618,7 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) + {"help", no_argument, NULL, 'h'}, + {"options", no_argument, NULL, 'o'}, + {"version", no_argument, NULL, 'V'}, +- DAEMON_LONG_OPTIONS, ++ OVN_DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, + STREAM_SSL_LONG_OPTIONS, + {NULL, 0, NULL, 0}, +@@ -11634,7 +11634,7 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) + } + + switch (c) { +- DAEMON_OPTION_HANDLERS; ++ OVN_DAEMON_OPTION_HANDLERS; + VLOG_OPTION_HANDLERS; + STREAM_SSL_OPTION_HANDLERS; + +diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c +index a88c1ddc2..3f4731d40 100644 +--- a/utilities/ovn-nbctl.c ++++ b/utilities/ovn-nbctl.c +@@ -324,7 +324,7 @@ enum { + OPT_NO_SHUFFLE_REMOTES, + OPT_BOOTSTRAP_CA_CERT, + MAIN_LOOP_OPTION_ENUMS, +- DAEMON_OPTION_ENUMS, ++ OVN_DAEMON_OPTION_ENUMS, + VLOG_OPTION_ENUMS, + TABLE_OPTION_ENUMS, + SSL_OPTION_ENUMS, +@@ -428,7 +428,7 @@ get_all_options(void) + {"version", no_argument, NULL, 'V'}, + {"unixctl", required_argument, NULL, 'u'}, + MAIN_LOOP_LONG_OPTIONS, +- DAEMON_LONG_OPTIONS, ++ OVN_DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, + STREAM_SSL_LONG_OPTIONS, + {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT}, +@@ -460,7 +460,7 @@ has_option(const struct ovs_cmdl_parsed_option *parsed_options, size_t n, + static bool + will_detach(const struct ovs_cmdl_parsed_option *parsed_options, size_t n) + { +- return has_option(parsed_options, n, OPT_DETACH); ++ return has_option(parsed_options, n, OVN_OPT_DETACH); + } + + static char * OVS_WARN_UNUSED_RESULT +@@ -547,7 +547,7 @@ apply_options_direct(const struct ovs_cmdl_parsed_option *parsed_options, + printf("DB Schema %s\n", nbrec_get_db_version()); + exit(EXIT_SUCCESS); + +- DAEMON_OPTION_HANDLERS ++ OVN_DAEMON_OPTION_HANDLERS + VLOG_OPTION_HANDLERS + TABLE_OPTION_HANDLERS(&table_style) + STREAM_SSL_OPTION_HANDLERS +@@ -6512,7 +6512,7 @@ nbctl_client(const char *socket_name, + case OPT_NO_SHUFFLE_REMOTES: + case OPT_BOOTSTRAP_CA_CERT: + STREAM_SSL_CASES +- DAEMON_OPTION_CASES ++ OVN_DAEMON_OPTION_CASES + VLOG_INFO("using ovn-nbctl daemon, ignoring %s option", + po->o->name); + break; +diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c +index eae9622d3..c9d72285c 100644 +--- a/utilities/ovn-trace.c ++++ b/utilities/ovn-trace.c +@@ -239,7 +239,7 @@ parse_options(int argc, char *argv[]) + OPT_CT, + OPT_FRIENDLY_NAMES, + OPT_NO_FRIENDLY_NAMES, +- DAEMON_OPTION_ENUMS, ++ OVN_DAEMON_OPTION_ENUMS, + SSL_OPTION_ENUMS, + VLOG_OPTION_ENUMS, + OPT_LB_DST, +@@ -260,7 +260,7 @@ parse_options(int argc, char *argv[]) + {"version", no_argument, NULL, 'V'}, + {"lb-dst", required_argument, NULL, OPT_LB_DST}, + {"select-id", required_argument, NULL, OPT_SELECT_ID}, +- DAEMON_LONG_OPTIONS, ++ OVN_DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, + STREAM_SSL_LONG_OPTIONS, + {NULL, 0, NULL, 0}, +@@ -333,7 +333,7 @@ parse_options(int argc, char *argv[]) + printf("DB Schema %s\n", sbrec_get_db_version()); + exit(EXIT_SUCCESS); + +- DAEMON_OPTION_HANDLERS ++ OVN_DAEMON_OPTION_HANDLERS + VLOG_OPTION_HANDLERS + STREAM_SSL_OPTION_HANDLERS + +-- +2.25.1 + diff --git a/SOURCES/0002-Honour-router_preference-for-solicited-RA.patch b/SOURCES/0002-Honour-router_preference-for-solicited-RA.patch new file mode 100644 index 0000000..a73b677 --- /dev/null +++ b/SOURCES/0002-Honour-router_preference-for-solicited-RA.patch @@ -0,0 +1,209 @@ +From 17d3f4f18878ef706008575cd1565745c5936819 Mon Sep 17 00:00:00 2001 +From: Gabriele Cerami +Date: Sat, 13 Jun 2020 10:20:23 +0100 +Subject: [PATCH 2/3] Honour router_preference for solicited RA + +Replies to router solicitation follow a different flow than periodic RA. +This flow currently does not honour the router_preference configuration. + +This patch modifies the flow to honour the flag, and send +router-preference indications in the reply RA following RFC4191 +specifications + +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1804576 +Signed-off-by: Gabriele Cerami +Signed-off-by: Numan Siddique +--- + AUTHORS.rst | 1 + + lib/actions.c | 29 +++++++++++++++++++++++++++-- + lib/ovn-l7.h | 5 +++++ + northd/ovn-northd.c | 6 ++++++ + tests/ovn.at | 26 ++++++++++++++++---------- + 5 files changed, 55 insertions(+), 12 deletions(-) + +diff --git a/AUTHORS.rst b/AUTHORS.rst +index c80fc1bae..bba0d1d6f 100644 +--- a/AUTHORS.rst ++++ b/AUTHORS.rst +@@ -145,6 +145,7 @@ Frédéric Tobias Christ fchrist@live.de + Frode Nordahl frode.nordahl@gmail.com + FUJITA Tomonori fujita.tomonori@lab.ntt.co.jp + Gabe Beged-Dov gabe@begeddov.com ++Gabriele Cerami gcerami@redhat.com + Gaetano Catalli gaetano.catalli@gmail.com + Gal Sagie gal.sagie@gmail.com + Genevieve LEsperance glesperance@pivotal.io +diff --git a/lib/actions.c b/lib/actions.c +index ee7ccae0d..3181126e6 100644 +--- a/lib/actions.c ++++ b/lib/actions.c +@@ -2484,6 +2484,12 @@ parse_put_nd_ra_opts(struct action_context *ctx, const struct expr_field *dst, + } + break; + ++ case ND_RA_FLAG_PRF: ++ ok = (c->string && (!strcmp(c->string, "MEDIUM") || ++ !strcmp(c->string, "HIGH") || ++ !strcmp(c->string, "LOW"))); ++ break; ++ + case ND_OPT_SOURCE_LINKADDR: + ok = c->format == LEX_F_ETHERNET; + slla_present = true; +@@ -2538,9 +2544,22 @@ encode_put_nd_ra_option(const struct ovnact_gen_option *o, + { + struct ovs_ra_msg *ra = ofpbuf_at(ofpacts, ra_offset, sizeof *ra); + if (!strcmp(c->string, "dhcpv6_stateful")) { +- ra->mo_flags = IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG; ++ ra->mo_flags |= IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG; + } else if (!strcmp(c->string, "dhcpv6_stateless")) { +- ra->mo_flags = IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG; ++ ra->mo_flags |= IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG; ++ } ++ break; ++ } ++ ++ case ND_RA_FLAG_PRF: ++ { ++ struct ovs_ra_msg *ra = ofpbuf_at(ofpacts, ra_offset, sizeof *ra); ++ if (!strcmp(c->string, "LOW")) { ++ ra->mo_flags |= IPV6_ND_RA_OPT_PRF_LOW; ++ } else if (!strcmp(c->string, "HIGH")) { ++ ra->mo_flags |= IPV6_ND_RA_OPT_PRF_HIGH; ++ } else { ++ ra->mo_flags |= IPV6_ND_RA_OPT_PRF_NORMAL; + } + break; + } +@@ -2621,6 +2640,12 @@ encode_PUT_ND_RA_OPTS(const struct ovnact_put_opts *po, + encode_put_nd_ra_option(o, ofpacts, ra_offset); + } + ++ /* RFC4191 section 2.2 */ ++ struct ovs_ra_msg *new_ra = ofpbuf_at(ofpacts, ra_offset, sizeof *new_ra); ++ if (ntohs(new_ra->router_lifetime) == 0) { ++ new_ra->mo_flags &= IPV6_ND_RA_OPT_PRF_RESET_MASK; ++ } ++ + encode_finish_controller_op(oc_offset, ofpacts); + } + +diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h +index cbea2a0c8..2da38fb65 100644 +--- a/lib/ovn-l7.h ++++ b/lib/ovn-l7.h +@@ -304,6 +304,9 @@ nd_ra_opts_destroy(struct hmap *nd_ra_opts) + + + #define ND_RA_FLAG_ADDR_MODE 0 ++/* all small numbers seems to be all already taken but nothing guarantees this ++ * code will not be assigned by IANA to another option */ ++#define ND_RA_FLAG_PRF 255 + + + /* Default values of various IPv6 Neighbor Discovery protocol options and +@@ -325,11 +328,13 @@ nd_ra_opts_destroy(struct hmap *nd_ra_opts) + #define IPV6_ND_RA_OPT_PRF_NORMAL 0x00 + #define IPV6_ND_RA_OPT_PRF_HIGH 0x08 + #define IPV6_ND_RA_OPT_PRF_LOW 0x18 ++#define IPV6_ND_RA_OPT_PRF_RESET_MASK 0xe7 + + static inline void + nd_ra_opts_init(struct hmap *nd_ra_opts) + { + nd_ra_opt_add(nd_ra_opts, "addr_mode", ND_RA_FLAG_ADDR_MODE, "str"); ++ nd_ra_opt_add(nd_ra_opts, "router_preference", ND_RA_FLAG_PRF, "str"); + nd_ra_opt_add(nd_ra_opts, "slla", ND_OPT_SOURCE_LINKADDR, "mac"); + nd_ra_opt_add(nd_ra_opts, "prefix", ND_OPT_PREFIX_INFORMATION, "ipv6"); + nd_ra_opt_add(nd_ra_opts, "mtu", ND_OPT_MTU, "uint32"); +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index c1b4c13b7..cffe3de17 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -9408,6 +9408,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + ds_put_format(&actions, ", mtu = %u", mtu); + } + ++ const char *prf = smap_get_def( ++ &op->nbrp->ipv6_ra_configs, "router_preference", "MEDIUM"); ++ if (strcmp(prf, "MEDIUM")) { ++ ds_put_format(&actions, ", router_preference = \"%s\"", prf); ++ } ++ + bool add_rs_response_flow = false; + + for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { +diff --git a/tests/ovn.at b/tests/ovn.at +index 57c1d90e4..d9df393d5 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -1346,14 +1346,14 @@ log(severity=notice); + Syntax error at `;' expecting verdict. + + # put_nd_ra_opts +-reg1[0] = put_nd_ra_opts(addr_mode = "slaac", mtu = 1500, prefix = aef0::/64, slla = ae:01:02:03:04:05); +- encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.00.ff.ff.00.00.00.00.00.00.00.00.05.01.00.00.00.00.05.dc.03.04.40.c0.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.05,pause) ++reg1[0] = put_nd_ra_opts(addr_mode = "slaac", mtu = 1500, router_preference = "HIGH", prefix = aef0::/64, slla = ae:01:02:03:04:05); ++ encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.08.ff.ff.00.00.00.00.00.00.00.00.05.01.00.00.00.00.05.dc.03.04.40.c0.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.05,pause) + has prereqs ip6 +-reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateful", slla = ae:01:02:03:04:10, mtu = 1450); ++reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateful", router_preference = "MEDIUM", slla = ae:01:02:03:04:10, mtu = 1450); + encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.80.ff.ff.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.10.05.01.00.00.00.00.05.aa,pause) + has prereqs ip6 +-reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateless", slla = ae:01:02:03:04:06, prefix = aef0::/64); +- encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.40.ff.ff.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.06.03.04.40.c0.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00,pause) ++reg1[0] = put_nd_ra_opts(addr_mode = "dhcpv6_stateless", router_preference = "LOW", slla = ae:01:02:03:04:06, prefix = aef0::/64); ++ encodes as controller(userdata=00.00.00.08.00.00.00.00.00.01.de.10.00.00.00.40.86.00.00.00.ff.58.ff.ff.00.00.00.00.00.00.00.00.01.01.ae.01.02.03.04.06.03.04.40.c0.ff.ff.ff.ff.ff.ff.ff.ff.00.00.00.00.ae.f0.00.00.00.00.00.00.00.00.00.00.00.00.00.00,pause) + has prereqs ip6 + reg1[0] = put_nd_ra_opts(addr_mode = "slaac", mtu = 1500, prefix = aef0::/64); + slla option not present +@@ -10083,13 +10083,16 @@ reset_pcap_file hv1-vif1 hv1/vif1 + reset_pcap_file hv1-vif2 hv1/vif2 + reset_pcap_file hv1-vif3 hv1/vif3 + +-# Set the MTU to 1500 ++# Set the MTU to 1500, send_periodic to false, preference to LOW + ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:mtu=1500 ++ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:send_periodic="false" ++ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:router_preference="LOW" + + # Make sure that ovn-controller has installed the corresponding OF Flow. + OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) + +-addr_mode=00 ++# addr_mode byte also includes router preference information ++addr_mode=18 + default_prefix_option_config=030440c0ffffffffffffffff00000000 + src_mac=fa163e000003 + src_lla=fe80000000000000f8163efffe000003 +@@ -10114,12 +10117,14 @@ reset_pcap_file hv1-vif1 hv1/vif1 + reset_pcap_file hv1-vif2 hv1/vif2 + reset_pcap_file hv1-vif3 hv1/vif3 + +-# Set the address mode to dhcpv6_stateful ++# Set the address mode to dhcpv6_stateful, router_preference to HIGH + ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=dhcpv6_stateful ++ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:router_preference="HIGH" + # Make sure that ovn-controller has installed the corresponding OF Flow. + OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) + +-addr_mode=80 ++# addr_mode byte also includes router preference information ++addr_mode=88 + default_prefix_option_config=03044080ffffffffffffffff00000000 + src_mac=fa163e000004 + src_lla=fe80000000000000f8163efffe000004 +@@ -10144,8 +10149,9 @@ reset_pcap_file hv1-vif1 hv1/vif1 + reset_pcap_file hv1-vif2 hv1/vif2 + reset_pcap_file hv1-vif3 hv1/vif3 + +-# Set the address mode to dhcpv6_stateless ++# Set the address mode to dhcpv6_stateless, reset router preference to default + ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=dhcpv6_stateless ++ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:router_preference="MEDIUM" + # Make sure that ovn-controller has installed the corresponding OF Flow. + OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) + +-- +2.26.2 + diff --git a/SOURCES/0002-Revert-Manage-ARP-process-locally-in-a-DVR-scenario.patch b/SOURCES/0002-Revert-Manage-ARP-process-locally-in-a-DVR-scenario.patch new file mode 100644 index 0000000..d6bd9d1 --- /dev/null +++ b/SOURCES/0002-Revert-Manage-ARP-process-locally-in-a-DVR-scenario.patch @@ -0,0 +1,186 @@ +From d9ed450713eda62af1bec5009694b2d206c9f435 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Lorenzo Bianconi +Date: Mon, 25 May 2020 23:55:06 +0200 +Subject: [PATCH ovn 1/3] Revert "Manage ARP process locally in a DVR scenario" + +This reverts commit c0bf32d72f8b893bbe3cb64912b0fd259d71555f. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Han Zhou +--- + northd/ovn-northd.8.xml | 37 ++-------------------------- + northd/ovn-northd.c | 53 +---------------------------------------- + tests/ovn.at | 14 ----------- + 3 files changed, 3 insertions(+), 101 deletions(-) + +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -2486,44 +2486,11 @@ output; + +

        • +

          +- For distributed logical routers where one of the logical router ports +- specifies a redirect-chassis, a priority-400 logical +- flow for each dnat_and_snat NAT rules configured. +- These flows will allow to properly forward traffic to the external +- connections if available and avoid sending it through the tunnel. +- Assuming the following NAT rule has been configured: +-

          +- +-
          +-external_ip = A;
          +-external_mac = B;
          +-logical_ip = C;
          +-        
          +- +-

          +- the following action will be applied: +-

          +- +-
          +-ip.ttl--;
          +-reg0 = ip.dst;
          +-reg1 = A;
          +-eth.src = B;
          +-outport = router-port;
          +-next;
          +-        
          +- +-
        • +- +-
        • +-

          + IPv4 routing table. For each route to IPv4 network N with + netmask M, on router port P with IP address + A and Ethernet + address E, a logical flow with match ip4.dst == +- N/M, whose priority is 400 +- + the number of 1-bits in M if the router port is not a +- distributed gateway port, else the priority is the number of ++ N/M, whose priority is the number of + 1-bits in M, has the following actions: +

          + +@@ -2910,7 +2877,7 @@ icmp4 { +
            +
          • + For each NAT rule in the OVN Northbound database that can +- be handled in a distributed manner, a priority-200 logical ++ be handled in a distributed manner, a priority-100 logical + flow with match ip4.src == B && + outport == GW, where GW is + the logical router distributed gateway port, with actions +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -7102,8 +7102,6 @@ build_routing_policy_flow(struct hmap *l + ds_destroy(&actions); + } + +-/* default logical flow prioriry for distributed routes */ +-#define DROUTE_PRIO 400 + struct parsed_route { + struct ovs_list list_node; + struct v46_ip prefix; +@@ -7492,40 +7490,6 @@ build_ecmp_route_flow(struct hmap *lflow + } + + static void +-add_distributed_routes(struct hmap *lflows, struct ovn_datapath *od) +-{ +- struct ds actions = DS_EMPTY_INITIALIZER; +- struct ds match = DS_EMPTY_INITIALIZER; +- +- for (size_t i = 0; i < od->nbr->n_nat; i++) { +- const struct nbrec_nat *nat = od->nbr->nat[i]; +- +- if (strcmp(nat->type, "dnat_and_snat") || +- !nat->external_mac) { +- continue; +- } +- +- bool is_ipv4 = strchr(nat->logical_ip, '.') ? true : false; +- ds_put_format(&match, "ip%s.src == %s && is_chassis_resident(\"%s\")", +- is_ipv4 ? "4" : "6", nat->logical_ip, +- nat->logical_port); +- char *prefix = is_ipv4 ? "" : "xx"; +- ds_put_format(&actions, "outport = %s; eth.src = %s; " +- "%sreg0 = ip%s.dst; %sreg1 = %s; next;", +- od->l3dgw_port->json_key, nat->external_mac, +- prefix, is_ipv4 ? "4" : "6", +- prefix, nat->external_ip); +- ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, DROUTE_PRIO, +- ds_cstr(&match), ds_cstr(&actions)); +- ds_clear(&match); +- ds_clear(&actions); +- } +- +- ds_destroy(&actions); +- ds_destroy(&match); +-} +- +-static void + add_route(struct hmap *lflows, const struct ovn_port *op, + const char *lrp_addr_s, const char *network_s, int plen, + const char *gateway, bool is_src_route, +@@ -7546,12 +7510,6 @@ add_route(struct hmap *lflows, const str + } + build_route_match(op_inport, network_s, plen, is_src_route, is_ipv4, + &match, &priority); +- /* traffic for internal IPs of logical switch ports must be sent to +- * the gw controller through the overlay tunnels +- */ +- if (op->nbrp && !op->nbrp->n_gateway_chassis) { +- priority += DROUTE_PRIO; +- } + + struct ds actions = DS_EMPTY_INITIALIZER; + ds_put_format(&actions, "ip.ttl--; "REG_ECMP_GROUP_ID" = 0; %sreg0 = ", +@@ -9187,7 +9145,7 @@ build_lrouter_flows(struct hmap *datapat + nat->logical_ip, + od->l3dgw_port->json_key); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, +- 200, ds_cstr(&match), "next;", ++ 100, ds_cstr(&match), "next;", + &nat->header_); + } + +@@ -9493,15 +9451,6 @@ build_lrouter_flows(struct hmap *datapat + ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, "1", "next;"); + } + +- /* Logical router ingress table IP_ROUTING - IP routing for distributed +- * logical router +- */ +- HMAP_FOR_EACH (od, key_node, datapaths) { +- if (od->nbr && od->l3dgw_port) { +- add_distributed_routes(lflows, od); +- } +- } +- + /* Logical router ingress table IP_ROUTING & IP_ROUTING_ECMP: IP Routing. + * + * A packet that arrives at this table is an IP packet that should be +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -9605,20 +9605,6 @@ AT_CHECK([as hv3 ovs-vsctl set Open_vSwi + OVS_WAIT_UNTIL([test 1 = `as hv3 ovs-vsctl show | \ + grep "Port patch-br-int-to-ln_port" | wc -l`]) + +-AT_CHECK([test 1 = `ovn-sbctl dump-flows lr0 | grep lr_in_ip_routing | \ +-grep "ip4.src == 10.0.0.3 && is_chassis_resident(\"foo1\")" -c`]) +-AT_CHECK([test 1 = `ovn-sbctl dump-flows lr0 | grep lr_in_ip_routing | \ +-grep "ip4.src == 10.0.0.4 && is_chassis_resident(\"foo2\")" -c`]) +- +-key=`ovn-sbctl --bare --columns tunnel_key list datapath_Binding lr0` +-# Check that the OVS flows appear for the dnat_and_snat entries in +-# lr_in_ip_routing table. +-OVS_WAIT_UNTIL([test 1 = `as hv3 ovs-ofctl dump-flows br-int table=17 | \ +-grep "priority=400,ip,metadata=0x$key,nw_src=10.0.0.3" -c`]) +- +-OVS_WAIT_UNTIL([test 1 = `as hv3 ovs-ofctl dump-flows br-int table=17 | \ +-grep "priority=400,ip,metadata=0x$key,nw_src=10.0.0.4" -c`]) +- + # Re-add nat-addresses option + ovn-nbctl lsp-set-options lrp0-rp router-port=lrp0 nat-addresses="router" + diff --git a/SOURCES/0002-controller-Add-garbage-collector-for-ipv6_prefixd.patch b/SOURCES/0002-controller-Add-garbage-collector-for-ipv6_prefixd.patch new file mode 100644 index 0000000..7b48c56 --- /dev/null +++ b/SOURCES/0002-controller-Add-garbage-collector-for-ipv6_prefixd.patch @@ -0,0 +1,65 @@ +From 85b13870020facf5f4441df51df64ee647c6abd9 Mon Sep 17 00:00:00 2001 +Message-Id: <85b13870020facf5f4441df51df64ee647c6abd9.1588608928.git.lorenzo.bianconi@redhat.com> +In-Reply-To: <0b9d16670d5561d8300d2448cbd4686a3acdc57e.1588608928.git.lorenzo.bianconi@redhat.com> +References: <0b9d16670d5561d8300d2448cbd4686a3acdc57e.1588608928.git.lorenzo.bianconi@redhat.com> +From: Lorenzo Bianconi +Date: Wed, 29 Apr 2020 18:05:30 +0200 +Subject: [PATCH 2/3] controller: Add garbage collector for ipv6_prefixd. + +Introduce a garbage collector for stale entries in ipv6_prefixd that are +no longer managed by the controller (e.g. if the processing has been +disabled setting ipv6_prefix_delegation to false on all logical router +ports). + +Tested-by: Jianlin Shi +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique +--- + controller/pinctrl.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index 3230bb386..f0d63b9a6 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -578,6 +578,7 @@ enum { + + struct ipv6_prefixd_state { + long long int next_announce; ++ long long int last_used; + struct in6_addr ipv6_addr; + struct eth_addr ea; + struct eth_addr cmac; +@@ -1128,11 +1129,13 @@ fill_ipv6_prefix_state(struct ovsdb_idl_txn *ovnsb_idl_txn, + sbrec_port_binding_set_options(pb, &options); + smap_destroy(&options); + } ++ pfd->last_used = time_msec(); + } + + return changed; + } + ++#define IPV6_PREFIXD_STALE_TIMEOUT 180000LL + static void + prepare_ipv6_prefixd(struct ovsdb_idl_txn *ovnsb_idl_txn, + struct ovsdb_idl_index *sbrec_port_binding_by_name, +@@ -1210,6 +1213,15 @@ prepare_ipv6_prefixd(struct ovsdb_idl_txn *ovnsb_idl_txn, + } + } + ++ struct shash_node *iter, *next; ++ SHASH_FOR_EACH_SAFE (iter, next, &ipv6_prefixd) { ++ struct ipv6_prefixd_state *pfd = iter->data; ++ if (pfd->last_used + IPV6_PREFIXD_STALE_TIMEOUT < time_msec()) { ++ free(pfd); ++ shash_delete(&ipv6_prefixd, iter); ++ } ++ } ++ + if (changed) { + notify_pinctrl_handler(); + } +-- +2.26.2 + diff --git a/SOURCES/0002-controller-Add-ipv6-prefix-delegation-state-machine.patch b/SOURCES/0002-controller-Add-ipv6-prefix-delegation-state-machine.patch new file mode 100644 index 0000000..b715219 --- /dev/null +++ b/SOURCES/0002-controller-Add-ipv6-prefix-delegation-state-machine.patch @@ -0,0 +1,934 @@ +From aa0139f28628bb869866e4c35cb31f8005b99994 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com> +References: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com> +From: Lorenzo Bianconi +Date: Wed, 1 Apr 2020 18:37:30 +0200 +Subject: [PATCH 2/3] controller: Add ipv6 prefix delegation state machine + +Introduce IPv6 Prefix delegation state machine according to RFC 3633 +https://tools.ietf.org/html/rfc3633. +Add handle_dhcpv6_reply controller action to parse advertise/reply from +IPv6 delegation server. Advertise/reply are parsed running respectively: +- pinctrl_parse_dhcv6_advt +- pinctrl_parse_dhcv6_reply +The IPv6 requesting router starts sending dhcpv6 solicit through the logical +router port marked with ipv6_prefix_delegation set to true. +An IPv6 prefix will be requested for each logical router port marked +with "prefix" set to true in option column of logical router port table. +Save IPv6 prefix received by IPv6 delegation router in the options columns of +SB port binding table in order to be reused by Router Advertisement framework +run by ovn logical router pipeline. +IPv6 Prefix delegation state machine is enabled on Gateway Router or on +a Gateway Router Port + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique +--- + controller/pinctrl.c | 651 ++++++++++++++++++++++++++++++++++++++++++ + include/ovn/actions.h | 8 +- + lib/actions.c | 16 ++ + lib/ovn-l7.h | 19 ++ + ovn-sb.xml | 18 ++ + tests/ovn.at | 4 + + utilities/ovn-trace.c | 2 + + 7 files changed, 717 insertions(+), 1 deletion(-) + +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index 3fa8923e7..a053938ec 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -270,6 +270,8 @@ static void pinctrl_ip_mcast_handle( + const struct match *md, + struct ofpbuf *userdata); + ++static void init_ipv6_prefixd(void); ++ + static bool may_inject_pkts(void); + + static void init_put_vport_bindings(void); +@@ -313,6 +315,13 @@ static void pinctrl_compose_ipv6(struct dp_packet *packet, + uint8_t ip_proto, uint8_t ttl, + uint16_t ip_payload_len); + ++static void ++put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits, ++ struct ofpbuf *ofpacts); ++ ++static void notify_pinctrl_main(void); ++static void notify_pinctrl_handler(void); ++ + COVERAGE_DEFINE(pinctrl_drop_put_mac_binding); + COVERAGE_DEFINE(pinctrl_drop_buffered_packets_map); + COVERAGE_DEFINE(pinctrl_drop_controller_event); +@@ -470,6 +479,7 @@ pinctrl_init(void) + init_put_mac_bindings(); + init_send_garps_rarps(); + init_ipv6_ras(); ++ init_ipv6_prefixd(); + init_buffered_packets_map(); + init_event_table(); + ip_mcast_snoop_init(); +@@ -557,6 +567,634 @@ set_actions_and_enqueue_msg(struct rconn *swconn, + ofpbuf_uninit(&ofpacts); + } + ++static struct shash ipv6_prefixd; ++ ++enum { ++ PREFIX_SOLICIT, ++ PREFIX_REQUEST, ++ PREFIX_PENDING, ++ PREFIX_DONE, ++}; ++ ++struct ipv6_prefixd_state { ++ long long int next_announce; ++ struct in6_addr ipv6_addr; ++ struct eth_addr ea; ++ struct eth_addr cmac; ++ int64_t port_key; ++ int64_t metadata; ++ struct in6_addr prefix; ++ uint32_t plife_time; ++ uint32_t vlife_time; ++ uint32_t aid; ++ uint32_t t1; ++ uint32_t t2; ++ uint32_t plen; ++ int state; ++}; ++ ++static void ++init_ipv6_prefixd(void) ++{ ++ shash_init(&ipv6_prefixd); ++} ++ ++static void ++destroy_ipv6_prefixd(void) ++{ ++ struct shash_node *iter, *next; ++ SHASH_FOR_EACH_SAFE (iter, next, &ipv6_prefixd) { ++ struct ipv6_prefixd_state *pfd = iter->data; ++ free(pfd); ++ shash_delete(&ipv6_prefixd, iter); ++ } ++ shash_destroy(&ipv6_prefixd); ++} ++ ++static struct ipv6_prefixd_state * ++pinctrl_find_prefixd_state(const struct flow *ip_flow, unsigned aid) ++{ ++ struct shash_node *iter; ++ ++ SHASH_FOR_EACH (iter, &ipv6_prefixd) { ++ struct ipv6_prefixd_state *pfd = iter->data; ++ if (IN6_ARE_ADDR_EQUAL(&pfd->ipv6_addr, &ip_flow->ipv6_dst) && ++ eth_addr_equals(pfd->ea, ip_flow->dl_dst) && ++ pfd->aid == aid) { ++ return pfd; ++ } ++ } ++ return NULL; ++} ++ ++static void ++pinctrl_parse_dhcpv6_advt(struct rconn *swconn, const struct flow *ip_flow, ++ struct dp_packet *pkt_in, const struct match *md) ++{ ++ struct udp_header *udp_in = dp_packet_l4(pkt_in); ++ size_t dlen = MIN(ntohs(udp_in->udp_len), dp_packet_l4_size(pkt_in)); ++ unsigned char *in_dhcpv6_data = (unsigned char *)(udp_in + 1); ++ uint8_t *data, *end = (uint8_t *)udp_in + dlen; ++ int len = 0, aid = 0; ++ ++ data = xmalloc(dlen); ++ /* skip DHCPv6 common header */ ++ in_dhcpv6_data += 4; ++ while (in_dhcpv6_data < end) { ++ struct dhcpv6_opt_header *in_opt = ++ (struct dhcpv6_opt_header *)in_dhcpv6_data; ++ int opt_len = sizeof *in_opt + ntohs(in_opt->len); ++ ++ if (dlen < opt_len + len) { ++ goto out; ++ } ++ ++ switch (ntohs(in_opt->code)) { ++ case DHCPV6_OPT_IA_PD: { ++ struct dhcpv6_opt_ia_na *ia_na = (struct dhcpv6_opt_ia_na *)in_opt; ++ int orig_len = len, hdr_len = 0, size = sizeof *in_opt + 12; ++ ++ aid = ntohl(ia_na->iaid); ++ memcpy(&data[len], in_opt, size); ++ in_opt = (struct dhcpv6_opt_header *)(in_dhcpv6_data + size); ++ len += size; ++ ++ while (size < opt_len) { ++ int flen = sizeof *in_opt + ntohs(in_opt->len); ++ ++ if (dlen < flen + len) { ++ goto out; ++ } ++ ++ if (ntohs(in_opt->code) == DHCPV6_OPT_IA_PREFIX) { ++ memcpy(&data[len], in_opt, flen); ++ hdr_len += flen; ++ len += flen; ++ } ++ if (ntohs(in_opt->code) == DHCPV6_OPT_STATUS_CODE) { ++ struct dhcpv6_opt_status *status; ++ ++ status = (struct dhcpv6_opt_status *)in_opt; ++ if (ntohs(status->status_code)) { ++ goto out; ++ } ++ } ++ size += flen; ++ in_opt = (struct dhcpv6_opt_header *)(in_dhcpv6_data + size); ++ } ++ in_opt = (struct dhcpv6_opt_header *)&data[orig_len]; ++ in_opt->len = htons(hdr_len + 12); ++ break; ++ } ++ case DHCPV6_OPT_SERVER_ID_CODE: ++ case DHCPV6_OPT_CLIENT_ID_CODE: ++ memcpy(&data[len], in_opt, opt_len); ++ len += opt_len; ++ break; ++ default: ++ break; ++ } ++ in_dhcpv6_data += opt_len; ++ } ++ ++ struct ipv6_prefixd_state *pfd = pinctrl_find_prefixd_state(ip_flow, aid); ++ if (!pfd) { ++ goto out; ++ } ++ ++ pfd->state = PREFIX_REQUEST; ++ ++ uint64_t packet_stub[256 / 8]; ++ struct dp_packet packet; ++ ++ dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); ++ eth_compose(&packet, ip_flow->dl_src, ip_flow->dl_dst, ETH_TYPE_IPV6, ++ IPV6_HEADER_LEN); ++ ++ struct udp_header *udp_h = compose_ipv6(&packet, IPPROTO_UDP, ++ &ip_flow->ipv6_dst, ++ &ip_flow->ipv6_src, 0, 0, 255, ++ len + UDP_HEADER_LEN + 4); ++ udp_h->udp_len = htons(len + UDP_HEADER_LEN + 4); ++ udp_h->udp_csum = 0; ++ packet_set_udp_port(&packet, htons(546), htons(547)); ++ ++ unsigned char *dhcp_hdr = (unsigned char *)(udp_h + 1); ++ *dhcp_hdr = DHCPV6_MSG_TYPE_REQUEST; ++ memcpy(dhcp_hdr + 4, data, len); ++ ++ uint32_t csum = packet_csum_pseudoheader6(dp_packet_l3(&packet)); ++ csum = csum_continue(csum, udp_h, dp_packet_size(&packet) - ++ ((const unsigned char *)udp_h - ++ (const unsigned char *)dp_packet_eth(&packet))); ++ udp_h->udp_csum = csum_finish(csum); ++ if (!udp_h->udp_csum) { ++ udp_h->udp_csum = htons(0xffff); ++ } ++ ++ if (ip_flow->vlans[0].tci & htons(VLAN_CFI)) { ++ eth_push_vlan(&packet, htons(ETH_TYPE_VLAN_8021Q), ++ ip_flow->vlans[0].tci); ++ } ++ ++ uint64_t ofpacts_stub[4096 / 8]; ++ struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); ++ enum ofp_version version = rconn_get_version(swconn); ++ put_load(ntohll(md->flow.metadata), MFF_LOG_DATAPATH, 0, 64, &ofpacts); ++ put_load(md->flow.regs[MFF_LOG_INPORT - MFF_REG0], MFF_LOG_OUTPORT, ++ 0, 32, &ofpacts); ++ struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts); ++ resubmit->in_port = OFPP_CONTROLLER; ++ resubmit->table_id = OFTABLE_REMOTE_OUTPUT; ++ ++ struct ofputil_packet_out po = { ++ .packet = dp_packet_data(&packet), ++ .packet_len = dp_packet_size(&packet), ++ .buffer_id = UINT32_MAX, ++ .ofpacts = ofpacts.data, ++ .ofpacts_len = ofpacts.size, ++ }; ++ match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER); ++ enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version); ++ queue_msg(swconn, ofputil_encode_packet_out(&po, proto)); ++ dp_packet_uninit(&packet); ++ ofpbuf_uninit(&ofpacts); ++ ++out: ++ free(data); ++} ++ ++static void ++pinctrl_prefixd_state_handler(const struct flow *ip_flow, ++ struct in6_addr addr, unsigned aid, ++ char prefix_len, unsigned t1, unsigned t2, ++ unsigned plife_time, unsigned vlife_time) ++{ ++ struct ipv6_prefixd_state *pfd; ++ ++ pfd = pinctrl_find_prefixd_state(ip_flow, aid); ++ if (pfd) { ++ pfd->state = PREFIX_PENDING; ++ pfd->plife_time = plife_time; ++ pfd->vlife_time = vlife_time; ++ pfd->plen = prefix_len; ++ pfd->prefix = addr; ++ pfd->t1 = t1; ++ pfd->t2 = t2; ++ notify_pinctrl_main(); ++ } ++} ++ ++static void ++pinctrl_parse_dhcpv6_reply(struct dp_packet *pkt_in, ++ const struct flow *ip_flow) ++ OVS_REQUIRES(pinctrl_mutex) ++{ ++ struct udp_header *udp_in = dp_packet_l4(pkt_in); ++ unsigned char *in_dhcpv6_data = (unsigned char *)(udp_in + 1); ++ size_t dlen = MIN(ntohs(udp_in->udp_len), dp_packet_l4_size(pkt_in)); ++ unsigned t1 = 0, t2 = 0, vlife_time = 0, plife_time = 0; ++ uint8_t *end = (uint8_t *)udp_in + dlen; ++ uint8_t prefix_len = 0; ++ struct in6_addr ipv6; ++ bool status = false; ++ unsigned aid = 0; ++ ++ memset(&ipv6, 0, sizeof (struct in6_addr)); ++ /* skip DHCPv6 common header */ ++ in_dhcpv6_data += 4; ++ while (in_dhcpv6_data < end) { ++ struct dhcpv6_opt_header *in_opt = ++ (struct dhcpv6_opt_header *)in_dhcpv6_data; ++ int opt_len = sizeof *in_opt + ntohs(in_opt->len); ++ ++ if (in_dhcpv6_data + opt_len > end) { ++ break; ++ } ++ ++ switch (ntohs(in_opt->code)) { ++ case DHCPV6_OPT_IA_PD: { ++ int size = sizeof *in_opt + 12; ++ in_opt = (struct dhcpv6_opt_header *)(in_dhcpv6_data + size); ++ struct dhcpv6_opt_ia_na *ia_na = ++ (struct dhcpv6_opt_ia_na *)in_dhcpv6_data; ++ ++ aid = ntohl(ia_na->iaid); ++ t1 = ntohl(ia_na->t1); ++ t2 = ntohl(ia_na->t2); ++ if (t1 > t2 && t2 > 0) { ++ break; ++ } ++ ++ while (size < opt_len) { ++ if (ntohs(in_opt->code) == DHCPV6_OPT_IA_PREFIX) { ++ struct dhcpv6_opt_ia_prefix *ia_hdr = ++ (struct dhcpv6_opt_ia_prefix *)(in_dhcpv6_data + size); ++ ++ prefix_len = ia_hdr->plen; ++ plife_time = ntohl(ia_hdr->plife_time); ++ vlife_time = ntohl(ia_hdr->vlife_time); ++ memcpy(&ipv6, &ia_hdr->ipv6, sizeof (struct in6_addr)); ++ } ++ if (ntohs(in_opt->code) == DHCPV6_OPT_STATUS_CODE) { ++ struct dhcpv6_opt_status *status_hdr; ++ ++ status_hdr = (struct dhcpv6_opt_status *)in_opt; ++ status = ntohs(status_hdr->status_code) == 0; ++ } ++ size += sizeof *in_opt + ntohs(in_opt->len); ++ in_opt = (struct dhcpv6_opt_header *)(in_dhcpv6_data + size); ++ } ++ break; ++ } ++ default: ++ break; ++ } ++ in_dhcpv6_data += opt_len; ++ } ++ if (status) { ++ pinctrl_prefixd_state_handler(ip_flow, ipv6, aid, prefix_len, ++ t1, t2, plife_time, vlife_time); ++ } ++} ++ ++static void ++pinctrl_handle_dhcp6_server(struct rconn *swconn, const struct flow *ip_flow, ++ struct dp_packet *pkt_in, const struct match *md) ++ OVS_REQUIRES(pinctrl_mutex) ++{ ++ if (ip_flow->dl_type != htons(ETH_TYPE_IPV6) || ++ ip_flow->nw_proto != IPPROTO_UDP) { ++ return; ++ } ++ ++ struct udp_header *udp_in = dp_packet_l4(pkt_in); ++ unsigned char *dhcp_hdr = (unsigned char *)(udp_in + 1); ++ ++ switch (*dhcp_hdr) { ++ case DHCPV6_MSG_TYPE_ADVT: ++ pinctrl_parse_dhcpv6_advt(swconn, ip_flow, pkt_in, md); ++ break; ++ case DHCPV6_MSG_TYPE_REPLY: ++ pinctrl_parse_dhcpv6_reply(pkt_in, ip_flow); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void ++compose_prefixd_solicit(struct dp_packet *b, ++ struct ipv6_prefixd_state *pfd, ++ const struct eth_addr eth_dst, ++ const struct in6_addr *ipv6_dst) ++{ ++ eth_compose(b, eth_dst, pfd->ea, ETH_TYPE_IPV6, IPV6_HEADER_LEN); ++ ++ int payload = sizeof(struct dhcpv6_opt_server_id) + ++ sizeof(struct dhcpv6_opt_ia_na); ++ if (ipv6_addr_is_set(&pfd->prefix)) { ++ payload += sizeof(struct dhcpv6_opt_ia_prefix); ++ } ++ int len = UDP_HEADER_LEN + 4 + payload; ++ struct udp_header *udp_h = compose_ipv6(b, IPPROTO_UDP, &pfd->ipv6_addr, ++ ipv6_dst, 0, 0, 255, len); ++ udp_h->udp_len = htons(len); ++ udp_h->udp_csum = 0; ++ packet_set_udp_port(b, htons(546), htons(547)); ++ ++ unsigned char *dhcp_hdr = (unsigned char *)(udp_h + 1); ++ *dhcp_hdr = DHCPV6_MSG_TYPE_SOLICIT; ++ ++ struct dhcpv6_opt_server_id *opt_client_id = ++ (struct dhcpv6_opt_server_id *)(dhcp_hdr + 4); ++ opt_client_id->opt.code = htons(DHCPV6_OPT_CLIENT_ID_CODE); ++ opt_client_id->opt.len = htons(sizeof(struct dhcpv6_opt_server_id) - ++ sizeof(struct dhcpv6_opt_header)); ++ opt_client_id->duid_type = htons(DHCPV6_DUID_LL); ++ opt_client_id->hw_type = htons(DHCPV6_HW_TYPE_ETH); ++ opt_client_id->mac = pfd->cmac; ++ ++ if (!ipv6_addr_is_set(&pfd->prefix)) { ++ pfd->aid = random_uint16(); ++ } ++ struct dhcpv6_opt_ia_na *ia_pd = ++ (struct dhcpv6_opt_ia_na *)(opt_client_id + 1); ++ ia_pd->opt.code = htons(DHCPV6_OPT_IA_PD); ++ int opt_len = sizeof(struct dhcpv6_opt_ia_na) - ++ sizeof(struct dhcpv6_opt_header); ++ if (ipv6_addr_is_set(&pfd->prefix)) { ++ opt_len += sizeof(struct dhcpv6_opt_ia_prefix); ++ } ++ ia_pd->opt.len = htons(opt_len); ++ ia_pd->iaid = htonl(pfd->aid); ++ ia_pd->t1 = OVS_BE32_MAX; ++ ia_pd->t2 = OVS_BE32_MAX; ++ if (ipv6_addr_is_set(&pfd->prefix)) { ++ struct dhcpv6_opt_ia_prefix *ia_prefix = ++ (struct dhcpv6_opt_ia_prefix *)(ia_pd + 1); ++ ia_prefix->opt.code = htons(DHCPV6_OPT_IA_PREFIX); ++ ia_prefix->opt.len = htons(sizeof(struct dhcpv6_opt_ia_prefix) - ++ sizeof(struct dhcpv6_opt_header)); ++ ia_prefix->plife_time = OVS_BE32_MAX; ++ ia_prefix->vlife_time = OVS_BE32_MAX; ++ ia_prefix->plen = pfd->plen; ++ ia_prefix->ipv6 = pfd->prefix; ++ } ++ ++ uint32_t csum = packet_csum_pseudoheader6(dp_packet_l3(b)); ++ csum = csum_continue(csum, udp_h, dp_packet_size(b) - ++ ((const unsigned char *)udp_h - ++ (const unsigned char *)dp_packet_eth(b))); ++ udp_h->udp_csum = csum_finish(csum); ++ if (!udp_h->udp_csum) { ++ udp_h->udp_csum = htons(0xffff); ++ } ++} ++ ++#define IPV6_PREFIXD_TIMEOUT 3000LL ++static long long int ++ipv6_prefixd_send(struct rconn *swconn, struct ipv6_prefixd_state *pfd) ++{ ++ long long int cur_time = time_msec(); ++ if (cur_time < pfd->next_announce) { ++ return pfd->next_announce; ++ } ++ ++ uint64_t packet_stub[256 / 8]; ++ struct dp_packet packet; ++ ++ struct eth_addr eth_dst; ++ eth_dst = (struct eth_addr) ETH_ADDR_C(33,33,00,01,00,02); ++ struct in6_addr ipv6_dst; ++ ipv6_parse("ff02::1:2", &ipv6_dst); ++ ++ dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); ++ compose_prefixd_solicit(&packet, pfd, eth_dst, &ipv6_dst); ++ ++ uint64_t ofpacts_stub[4096 / 8]; ++ struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); ++ ++ /* Set MFF_LOG_DATAPATH and MFF_LOG_INPORT. */ ++ uint32_t dp_key = pfd->metadata; ++ uint32_t port_key = pfd->port_key; ++ put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts); ++ put_load(port_key, MFF_LOG_INPORT, 0, 32, &ofpacts); ++ put_load(1, MFF_LOG_FLAGS, MLF_LOCAL_ONLY_BIT, 1, &ofpacts); ++ struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts); ++ resubmit->in_port = OFPP_CONTROLLER; ++ resubmit->table_id = OFTABLE_LOG_INGRESS_PIPELINE; ++ ++ struct ofputil_packet_out po = { ++ .packet = dp_packet_data(&packet), ++ .packet_len = dp_packet_size(&packet), ++ .buffer_id = UINT32_MAX, ++ .ofpacts = ofpacts.data, ++ .ofpacts_len = ofpacts.size, ++ }; ++ ++ match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER); ++ enum ofp_version version = rconn_get_version(swconn); ++ enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version); ++ queue_msg(swconn, ofputil_encode_packet_out(&po, proto)); ++ dp_packet_uninit(&packet); ++ ofpbuf_uninit(&ofpacts); ++ pfd->next_announce = cur_time + random_range(IPV6_PREFIXD_TIMEOUT); ++ pfd->state = PREFIX_SOLICIT; ++ ++ return pfd->next_announce; ++} ++ ++static bool ipv6_prefixd_should_inject(void) ++{ ++ struct shash_node *iter; ++ ++ SHASH_FOR_EACH (iter, &ipv6_prefixd) { ++ struct ipv6_prefixd_state *pfd = iter->data; ++ if (pfd->state == PREFIX_SOLICIT) { ++ return true; ++ } ++ if (pfd->state && pfd->next_announce < time_msec()) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++static void ++ipv6_prefixd_wait(long long int timeout) ++{ ++ if (ipv6_prefixd_should_inject()) { ++ poll_timer_wait_until(timeout); ++ } ++} ++ ++static void ++send_ipv6_prefixd(struct rconn *swconn, long long int *send_prefixd_time) ++ OVS_REQUIRES(pinctrl_mutex) ++{ ++ struct shash_node *iter; ++ ++ *send_prefixd_time = LLONG_MAX; ++ SHASH_FOR_EACH (iter, &ipv6_prefixd) { ++ struct ipv6_prefixd_state *pfd = iter->data; ++ long long int next_msg = ipv6_prefixd_send(swconn, pfd); ++ if (*send_prefixd_time > next_msg) { ++ *send_prefixd_time = next_msg; ++ } ++ } ++} ++ ++static bool ++fill_ipv6_prefix_state(struct ovsdb_idl_txn *ovnsb_idl_txn, ++ const struct local_datapath *ld, ++ struct eth_addr ea, struct in6_addr ipv6_addr, ++ int64_t tunnel_key, int64_t dp_tunnel_key) ++ OVS_REQUIRES(pinctrl_mutex) ++{ ++ bool changed = false; ++ ++ for (size_t i = 0; i < ld->n_peer_ports; i++) { ++ const struct sbrec_port_binding *pb = ld->peer_ports[i].local; ++ struct ipv6_prefixd_state *pfd; ++ ++ if (!smap_get_bool(&pb->options, "ipv6_prefix", false)) { ++ pfd = shash_find_and_delete(&ipv6_prefixd, pb->logical_port); ++ if (pfd) { ++ free(pfd); ++ } ++ continue; ++ } ++ ++ struct lport_addresses c_addrs; ++ for (size_t j = 0; j < pb->n_mac; j++) { ++ if (extract_lsp_addresses(pb->mac[j], &c_addrs)) { ++ break; ++ } ++ } ++ ++ pfd = shash_find_data(&ipv6_prefixd, pb->logical_port); ++ if (!pfd) { ++ pfd = xzalloc(sizeof *pfd); ++ pfd->ipv6_addr = ipv6_addr; ++ pfd->ea = ea; ++ pfd->cmac = c_addrs.ea; ++ pfd->metadata = dp_tunnel_key; ++ pfd->port_key = tunnel_key; ++ shash_add(&ipv6_prefixd, pb->logical_port, pfd); ++ pfd->next_announce = time_msec() + ++ random_range(IPV6_PREFIXD_TIMEOUT); ++ changed = true; ++ ++ char prefix_s[IPV6_SCAN_LEN + 6]; ++ const char *ipv6_pd_list = smap_get(&pb->options, ++ "ipv6_ra_pd_list"); ++ if (!ipv6_pd_list || ++ !ovs_scan(ipv6_pd_list, "%u:"IPV6_SCAN_FMT"/%d", ++ &pfd->aid, prefix_s, &pfd->plen) || ++ !ipv6_parse(prefix_s, &pfd->prefix)) { ++ pfd->prefix = in6addr_any; ++ } ++ } else if (pfd->state == PREFIX_PENDING && ovnsb_idl_txn) { ++ char prefix_str[INET6_ADDRSTRLEN + 1] = {}; ++ struct smap options; ++ ++ pfd->state = PREFIX_DONE; ++ pfd->next_announce = time_msec() + pfd->t1 * 1000; ++ ipv6_string_mapped(prefix_str, &pfd->prefix); ++ smap_clone(&options, &pb->options); ++ smap_add_format(&options, "ipv6_ra_pd_list", "%d:%s/%d", ++ pfd->aid, prefix_str, pfd->plen); ++ sbrec_port_binding_set_options(pb, &options); ++ smap_destroy(&options); ++ } ++ } ++ ++ return changed; ++} ++ ++static void ++prepare_ipv6_prefixd(struct ovsdb_idl_txn *ovnsb_idl_txn, ++ struct ovsdb_idl_index *sbrec_port_binding_by_name, ++ const struct hmap *local_datapaths, ++ const struct sbrec_chassis *chassis, ++ const struct sset *active_tunnels) ++ OVS_REQUIRES(pinctrl_mutex) ++{ ++ const struct local_datapath *ld; ++ bool changed = false; ++ ++ HMAP_FOR_EACH (ld, hmap_node, local_datapaths) { ++ if (datapath_is_switch(ld->datapath)) { ++ /* logical switch */ ++ continue; ++ } ++ ++ for (size_t i = 0; i < ld->n_peer_ports; i++) { ++ const struct sbrec_port_binding *pb = ld->peer_ports[i].local; ++ int j; ++ ++ if (!smap_get_bool(&pb->options, "ipv6_prefix_delegation", ++ false)) { ++ continue; ++ } ++ ++ const char *peer_s = smap_get(&pb->options, "peer"); ++ if (!peer_s) { ++ continue; ++ } ++ ++ const struct sbrec_port_binding *peer ++ = lport_lookup_by_name(sbrec_port_binding_by_name, peer_s); ++ if (!peer) { ++ continue; ++ } ++ ++ char *redirect_name = xasprintf("cr-%s", pb->logical_port); ++ bool resident = lport_is_chassis_resident( ++ sbrec_port_binding_by_name, chassis, active_tunnels, ++ redirect_name); ++ free(redirect_name); ++ if (!resident && strcmp(pb->type, "l3gateway")) { ++ continue; ++ } ++ ++ struct in6_addr ip6_addr; ++ struct eth_addr ea; ++ for (j = 0; j < pb->n_mac; j++) { ++ struct lport_addresses laddrs; ++ ++ if (!extract_lsp_addresses(pb->mac[j], &laddrs)) { ++ continue; ++ } ++ ++ ea = laddrs.ea; ++ if (laddrs.n_ipv6_addrs > 0) { ++ ip6_addr = laddrs.ipv6_addrs[0].addr; ++ break; ++ } ++ } ++ ++ if (eth_addr_is_zero(ea)) { ++ continue; ++ } ++ ++ if (j == pb->n_mac) { ++ in6_generate_lla(ea, &ip6_addr); ++ } ++ ++ changed |= fill_ipv6_prefix_state(ovnsb_idl_txn, ld, ++ ea, ip6_addr, ++ peer->tunnel_key, ++ peer->datapath->tunnel_key); ++ } ++ } ++ ++ if (changed) { ++ notify_pinctrl_handler(); ++ } ++} ++ + struct buffer_info { + struct ofpbuf ofpacts; + ofp_port_t ofp_port; +@@ -2012,6 +2650,12 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg) + pinctrl_handle_bind_vport(&pin.flow_metadata.flow, &userdata); + ovs_mutex_unlock(&pinctrl_mutex); + break; ++ case ACTION_OPCODE_DHCP6_SERVER: ++ ovs_mutex_lock(&pinctrl_mutex); ++ pinctrl_handle_dhcp6_server(swconn, &headers, &packet, ++ &pin.flow_metadata); ++ ovs_mutex_unlock(&pinctrl_mutex); ++ break; + + case ACTION_OPCODE_HANDLE_SVC_CHECK: + ovs_mutex_lock(&pinctrl_mutex); +@@ -2090,6 +2734,7 @@ pinctrl_handler(void *arg_) + /* Next multicast query (IGMP) in ms. */ + static long long int send_mcast_query_time = LLONG_MAX; + static long long int svc_monitors_next_run_time = LLONG_MAX; ++ static long long int send_prefixd_time = LLONG_MAX; + + swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION); + +@@ -2143,6 +2788,7 @@ pinctrl_handler(void *arg_) + ovs_mutex_lock(&pinctrl_mutex); + send_garp_rarp_run(swconn, &send_garp_rarp_time); + send_ipv6_ras(swconn, &send_ipv6_ra_time); ++ send_ipv6_prefixd(swconn, &send_prefixd_time); + send_mac_binding_buffered_pkts(swconn); + ovs_mutex_unlock(&pinctrl_mutex); + +@@ -2160,6 +2806,7 @@ pinctrl_handler(void *arg_) + ipv6_ra_wait(send_ipv6_ra_time); + ip_mcast_querier_wait(send_mcast_query_time); + svc_monitors_wait(svc_monitors_next_run_time); ++ ipv6_prefixd_wait(send_prefixd_time); + + new_seq = seq_read(pinctrl_handler_seq); + seq_wait(pinctrl_handler_seq, new_seq); +@@ -2211,6 +2858,8 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, + sbrec_port_binding_by_name, br_int, chassis, + local_datapaths, active_tunnels); + prepare_ipv6_ras(local_datapaths); ++ prepare_ipv6_prefixd(ovnsb_idl_txn, sbrec_port_binding_by_name, ++ local_datapaths, chassis, active_tunnels); + sync_dns_cache(dns_table); + controller_event_run(ovnsb_idl_txn, ce_table, chassis); + ip_mcast_sync(ovnsb_idl_txn, chassis, local_datapaths, +@@ -2757,6 +3406,7 @@ pinctrl_destroy(void) + free(pinctrl.br_int_name); + destroy_send_garps_rarps(); + destroy_ipv6_ras(); ++ destroy_ipv6_prefixd(); + destroy_buffered_packets_map(); + event_table_destroy(); + destroy_put_mac_bindings(); +@@ -4471,6 +5121,7 @@ may_inject_pkts(void) + { + return (!shash_is_empty(&ipv6_ras) || + !shash_is_empty(&send_garp_rarp_data) || ++ ipv6_prefixd_should_inject() || + !ovs_list_is_empty(&mcast_query_list) || + !ovs_list_is_empty(&buffered_mac_bindings)); + } +diff --git a/include/ovn/actions.h b/include/ovn/actions.h +index 9b014925b..e3dec99b2 100644 +--- a/include/ovn/actions.h ++++ b/include/ovn/actions.h +@@ -91,7 +91,8 @@ struct ovn_extend_table; + OVNACT(TRIGGER_EVENT, ovnact_controller_event) \ + OVNACT(BIND_VPORT, ovnact_bind_vport) \ + OVNACT(HANDLE_SVC_CHECK, ovnact_handle_svc_check) \ +- OVNACT(FWD_GROUP, ovnact_fwd_group) ++ OVNACT(FWD_GROUP, ovnact_fwd_group) \ ++ OVNACT(DHCP6_REPLY, ovnact_null) + + /* enum ovnact_type, with a member OVNACT_ for each action. */ + enum OVS_PACKED_ENUM ovnact_type { +@@ -577,6 +578,11 @@ enum action_opcode { + * MFF_LOG_INPORT = port + */ + ACTION_OPCODE_HANDLE_SVC_CHECK, ++ /* handle_dhcpv6_reply { ...actions ...}." ++ * ++ * The actions, in OpenFlow 1.3 format, follow the action_header. ++ */ ++ ACTION_OPCODE_DHCP6_SERVER, + }; + + /* Header. */ +diff --git a/lib/actions.c b/lib/actions.c +index 6351db765..02141af30 100644 +--- a/lib/actions.c ++++ b/lib/actions.c +@@ -2313,6 +2313,20 @@ ovnact_put_opts_free(struct ovnact_put_opts *pdo) + free_gen_options(pdo->options, pdo->n_options); + } + ++static void ++format_DHCP6_REPLY(const struct ovnact_null *a OVS_UNUSED, struct ds *s) ++{ ++ ds_put_cstr(s, "handle_dhcpv6_reply;"); ++} ++ ++static void ++encode_DHCP6_REPLY(const struct ovnact_null *a OVS_UNUSED, ++ const struct ovnact_encode_params *ep OVS_UNUSED, ++ struct ofpbuf *ofpacts) ++{ ++ encode_controller_op(ACTION_OPCODE_DHCP6_SERVER, ofpacts); ++} ++ + static void + parse_SET_QUEUE(struct action_context *ctx) + { +@@ -3260,6 +3274,8 @@ parse_action(struct action_context *ctx) + parse_handle_svc_check(ctx); + } else if (lexer_match_id(ctx->lexer, "fwd_group")) { + parse_fwd_group_action(ctx); ++ } else if (lexer_match_id(ctx->lexer, "handle_dhcpv6_reply")) { ++ ovnact_put_DHCP6_REPLY(ctx->ovnacts); + } else { + lexer_syntax_error(ctx->lexer, "expecting action"); + } +diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h +index 931e6ffcf..cbea2a0c8 100644 +--- a/lib/ovn-l7.h ++++ b/lib/ovn-l7.h +@@ -178,8 +178,11 @@ struct dhcp_opt6_header { + #define DHCPV6_OPT_SERVER_ID_CODE 2 + #define DHCPV6_OPT_IA_NA_CODE 3 + #define DHCPV6_OPT_IA_ADDR_CODE 5 ++#define DHCPV6_OPT_STATUS_CODE 13 + #define DHCPV6_OPT_DNS_SERVER_CODE 23 + #define DHCPV6_OPT_DOMAIN_SEARCH_CODE 24 ++#define DHCPV6_OPT_IA_PD 25 ++#define DHCPV6_OPT_IA_PREFIX 26 + + #define DHCPV6_OPT_SERVER_ID \ + DHCP_OPTION("server_id", DHCPV6_OPT_SERVER_ID_CODE, "mac") +@@ -258,6 +261,22 @@ struct ovs_nd_route_info { + }; + BUILD_ASSERT_DECL(ND_ROUTE_INFO_OPT_LEN == sizeof(struct ovs_nd_route_info)); + ++OVS_PACKED( ++struct dhcpv6_opt_ia_prefix { ++ struct dhcpv6_opt_header opt; ++ ovs_be32 plife_time; ++ ovs_be32 vlife_time; ++ uint8_t plen; ++ struct in6_addr ipv6; ++}); ++ ++OVS_PACKED( ++struct dhcpv6_opt_status { ++ struct dhcpv6_opt_header opt; ++ ovs_be16 status_code; ++ uint8_t msg[]; ++}); ++ + #define DHCPV6_DUID_LL 3 + #define DHCPV6_HW_TYPE_ETH 1 + +diff --git a/ovn-sb.xml b/ovn-sb.xml +index 3ae9d4f92..72466b97e 100644 +--- a/ovn-sb.xml ++++ b/ovn-sb.xml +@@ -2149,6 +2149,17 @@ tcp.flags = RST; +

            Example: handle_svc_check(inport);

            + + ++
            handle_dhcpv6_reply;
            ++
            ++

            ++ Handle DHCPv6 prefix delegation advertisements/replies from ++ a IPv6 delegation server. ovn-controller will ++ add an entry ipv6_ra_pd_list in the ++ table for each ++ prefix received from the delegation server ++

            ++
            ++ +
            R = select(N1[=W1], N2[=W2], ...);
            +
            +

            +@@ -2182,6 +2193,13 @@ tcp.flags = RST; +

            +
            + ++
            handle_dhcpv6_reply;
            ++
            ++

            ++ This action is used to parse DHCPv6 replies from IPv6 ++ Delegation Router and managed IPv6 Prefix delegation state machine ++

            ++
            + + + +diff --git a/tests/ovn.at b/tests/ovn.at +index e8554f60d..3bc435e6d 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -1525,6 +1525,10 @@ fwd_group(); + fwd_group(liveness="false", childports="eth0", "lsp1"); + Syntax error at `"false"' expecting `,'. + ++# prefix delegation ++handle_dhcpv6_reply; ++ encodes as controller(userdata=00.00.00.13.00.00.00.00) ++ + # Miscellaneous negative tests. + ; + Syntax error at `;'. +diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c +index 84e5f2b5c..e59698ec4 100644 +--- a/utilities/ovn-trace.c ++++ b/utilities/ovn-trace.c +@@ -2292,6 +2292,8 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, + + case OVNACT_FWD_GROUP: + break; ++ case OVNACT_DHCP6_REPLY: ++ break; + } + } + ds_destroy(&s); +-- +2.25.2 + diff --git a/SOURCES/0002-ovn-northd-Fix-memory-leak-and-incorrect-limiting-of.patch b/SOURCES/0002-ovn-northd-Fix-memory-leak-and-incorrect-limiting-of.patch new file mode 100644 index 0000000..b82edf3 --- /dev/null +++ b/SOURCES/0002-ovn-northd-Fix-memory-leak-and-incorrect-limiting-of.patch @@ -0,0 +1,47 @@ +From ccaeae4261bc7d35d48a511f71cfc25728786b24 Mon Sep 17 00:00:00 2001 +From: Ilya Maximets +Date: Tue, 5 May 2020 13:08:50 +0200 +Subject: [PATCH 2/4] ovn-northd: Fix memory leak and incorrect limiting of + ECMP routes. + +If route count reaches UINT16_MAX, ecmp_groups_add_route() will leak the +allocated route structure. Also, since group->route_count incremented +unconditionally, next attempt to add new route will succeed, because the +value of 'route_count' is zero now and out of sync with the real number +of routes. + +Fixes: 4e53974bdc4e ("ovn-northd: Support ECMP routes.") +Signed-off-by: Ilya Maximets +Acked-by: Mark Michelson +Signed-off-by: Han Zhou +--- + northd/ovn-northd.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index ec77ae1a8..dc647d7c5 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -7188,15 +7188,15 @@ static void + ecmp_groups_add_route(struct ecmp_groups_node *group, + const struct parsed_route *route) + { +- struct ecmp_route_list_node *er = xmalloc(sizeof *er); +- er->route = route; +- er->id = ++group->route_count; +- if (er->id == 0) { ++ if (group->route_count == UINT16_MAX) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "too many routes in a single ecmp group."); + return; + } + ++ struct ecmp_route_list_node *er = xmalloc(sizeof *er); ++ er->route = route; ++ er->id = ++group->route_count; + ovs_list_insert(&group->route_list, &er->list_node); + } + +-- +2.26.2 + diff --git a/SOURCES/0002-ovn-northd-Fix-memory-leak-in-case-of-duplicate-logi.patch b/SOURCES/0002-ovn-northd-Fix-memory-leak-in-case-of-duplicate-logi.patch new file mode 100644 index 0000000..3c0eb4c --- /dev/null +++ b/SOURCES/0002-ovn-northd-Fix-memory-leak-in-case-of-duplicate-logi.patch @@ -0,0 +1,30 @@ +From 2fdce8ec0e631b759bb03a35457b17060605d887 Mon Sep 17 00:00:00 2001 +From: Ilya Maximets +Date: Tue, 12 May 2020 12:46:18 +0200 +Subject: [PATCH 2/2] ovn-northd: Fix memory leak in case of duplicate logical + router port. + +'lrp_networks' must be destroyed on error path. + +Fixes: 8e83e561879a ("ovn: Support multiple addresses on a single logical router port.") +Signed-off-by: Ilya Maximets +Signed-off-by: Numan Siddique +--- + northd/ovn-northd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index c1cdb2280..a41e3d46e 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -2125,6 +2125,7 @@ join_logical_ports(struct northd_context *ctx, + = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "duplicate logical router port %s", + nbrp->name); ++ destroy_lport_addresses(&lrp_networks); + continue; + } + ovn_port_set_nb(op, NULL, nbrp); +-- +2.26.2 + diff --git a/SOURCES/0002-ovn-northd-Fix-tunnel_key-allocation-for-SB-Port_Bin.patch b/SOURCES/0002-ovn-northd-Fix-tunnel_key-allocation-for-SB-Port_Bin.patch new file mode 100644 index 0000000..0da2b8f --- /dev/null +++ b/SOURCES/0002-ovn-northd-Fix-tunnel_key-allocation-for-SB-Port_Bin.patch @@ -0,0 +1,146 @@ +From 0cda584a6ee05830c0611650fe22c642cb39b09f Mon Sep 17 00:00:00 2001 +From: Dumitru Ceara +Date: Thu, 30 Apr 2020 20:32:35 +0200 +Subject: [PATCH 2/2] ovn-northd: Fix tunnel_key allocation for SB + Port_Bindings. + +When generating Port_Binding records ovn-northd tries to reuse the +tunnel_key value from the original SB record, if any available. + +However, there's no check for tunnel_keys that would conflict with +newly allocated keys for new records. In order to avoid that, we +don't reuse stale Port_Binding entries, i.e., their "datapath" field +doesn't match the Datapath_Binding record associated with the +logical switch/router they're part of. + +One way to reproduce the issue is: +$ ovn-nbctl ls-add ls1 +$ ovn-nbctl ls-add ls2 +$ ovn-nbctl lsp-add ls1 lsp1 +$ ovn-nbctl lsp-add ls2 lsp2 +$ ovn-nbctl --wait=sb sync +$ ovn-nbctl lsp-del lsp2 -- lsp-add ls1 lsp2 + +Another option to reproduce the issue is with HA_Chassis_Group: +$ ovn-nbctl ls-add ls1 +$ ovn-nbctl ls-add ls2 +$ ovn-nbctl lsp-add ls1 lsp1 +$ ovn-nbctl lsp-add ls2 lsp2 +$ ovn-nbctl lsp-set-type lsp2 external +$ ovn-nbctl ha-chassis-group-add chg1 +$ ovn-nbctl ha-chassis-group-add-chassis chg1 chassis-1 30 +$ chg1_uuid=$(ovn-nbctl --bare --columns _uuid list ha_Chassis_Group .) +$ ovn-nbctl set logical_switch_port lsp2 ha_chassis_group=${chg1_uuid} +$ ovn-nbctl lsp-del lsp2 -- lsp-add ls1 lsp2 + +Reported-by: Dan Williams +Reported-at: https://bugzilla.redhat.com/1828637 +Signed-off-by: Dumitru Ceara +Acked-by: Numan Siddique +Signed-off-by: Han Zhou +(cherry picked from upstream commit 8bf9075968ac8b26f1d4d32697f4b117a61a2c49) + +Change-Id: I03146f0778ff50375c3f843c0e650e76008bba94 +--- + northd/ovn-northd.c | 6 +++--- + tests/ovn-northd.at | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 59 insertions(+), 3 deletions(-) + +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 5e649d0..bc1ea0b 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -2025,7 +2025,7 @@ join_logical_ports(struct northd_context *ctx, + const struct nbrec_logical_switch_port *nbsp + = od->nbs->ports[i]; + struct ovn_port *op = ovn_port_find(ports, nbsp->name); +- if (op) { ++ if (op && op->sb->datapath == od->sb) { + if (op->nbsp || op->nbrp) { + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(5, 1); +@@ -2119,7 +2119,7 @@ join_logical_ports(struct northd_context *ctx, + } + + struct ovn_port *op = ovn_port_find(ports, nbrp->name); +- if (op) { ++ if (op && op->sb->datapath == od->sb) { + if (op->nbsp || op->nbrp) { + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(5, 1); +@@ -2171,7 +2171,7 @@ join_logical_ports(struct northd_context *ctx, + char *redirect_name = + ovn_chassis_redirect_name(nbrp->name); + struct ovn_port *crp = ovn_port_find(ports, redirect_name); +- if (crp) { ++ if (crp && crp->sb->datapath == od->sb) { + crp->derived = true; + ovn_port_set_nb(crp, NULL, nbrp); + ovs_list_remove(&crp->list); +diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at +index 94f892b..569390c 100644 +--- a/tests/ovn-northd.at ++++ b/tests/ovn-northd.at +@@ -1350,3 +1350,59 @@ lr_uuid=$(ovn-nbctl --columns _uuid list Logical_Router .) + AT_CHECK[test ${nb_uuid} = ${lr_uuid}] + + AT_CLEANUP ++ ++AT_SETUP([ovn -- check reconcile stale tunnel keys]) ++ovn_start ++ ++ovn-nbctl ls-add ls1 ++ovn-nbctl ls-add ls2 ++ovn-nbctl lsp-add ls1 lsp1 ++ovn-nbctl lsp-add ls2 lsp2 ++AT_CHECK([ovn-nbctl --wait=sb sync], [0]) ++ ++# Ports are bound on different datapaths so it's expected that they both ++# get tunnel_key == 1. ++AT_CHECK([test 1 = $(ovn-sbctl --bare --columns tunnel_key find \ ++port_binding logical_port=lsp1)]) ++AT_CHECK([test 1 = $(ovn-sbctl --bare --columns tunnel_key find \ ++port_binding logical_port=lsp2)]) ++ ++ovn-nbctl lsp-del lsp2 -- lsp-add ls1 lsp2 ++AT_CHECK([ovn-nbctl --wait=sb sync], [0]) ++ ++AT_CHECK([test 1 = $(ovn-sbctl --bare --columns tunnel_key find \ ++port_binding logical_port=lsp1)]) ++AT_CHECK([test 2 = $(ovn-sbctl --bare --columns tunnel_key find \ ++port_binding logical_port=lsp2)]) ++ ++# ovn-northd should allocate a new tunnel_key for lsp1 or lsp2 to maintain ++# unique DB indices. ++AT_CHECK([test ${pb1_key} != ${pb2_key}]) ++ ++AT_CLEANUP ++ ++AT_SETUP([ovn -- check reconcile stale Ha_Chassis_Group]) ++ovn_start ++ ++ovn-nbctl ls-add ls1 ++ovn-nbctl ls-add ls2 ++ovn-nbctl lsp-add ls1 lsp1 ++ovn-nbctl lsp-add ls2 lsp2 ++ ++ovn-nbctl lsp-set-type lsp2 external ++ ++ovn-nbctl ha-chassis-group-add chg1 ++ovn-nbctl ha-chassis-group-add-chassis chg1 chassis-1 30 ++ ++chg1_uuid=$(ovn-nbctl --bare --columns _uuid list Ha_Chassis_Group .) ++ovn-nbctl set logical_switch_port lsp2 ha_chassis_group=${chg1_uuid} ++AT_CHECK([ovn-nbctl --wait=sb sync], [0]) ++ ++# Move lsp2 from ls2 to ls1. This should also remove the SB HA_Chassis_Group ++# record. ++ovn-nbctl lsp-del lsp2 -- lsp-add ls1 lsp2 ++AT_CHECK([ovn-nbctl --wait=sb sync], [0]) ++ ++AT_CHECK([test 0 = $(ovn-sbctl list Ha_Chassis_Group | wc -l)]) ++ ++AT_CLEANUP +-- +1.8.3.1 + diff --git a/SOURCES/0002-ovn-northd-Skip-unsnat-flows-for-load-balancer-vips-.patch b/SOURCES/0002-ovn-northd-Skip-unsnat-flows-for-load-balancer-vips-.patch new file mode 100644 index 0000000..c64e616 --- /dev/null +++ b/SOURCES/0002-ovn-northd-Skip-unsnat-flows-for-load-balancer-vips-.patch @@ -0,0 +1,340 @@ +From f075920452dbcaab7c185efd4f63a02bd6e384ce Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Thu, 26 Mar 2020 20:19:12 +0530 +Subject: [PATCH 2/2] ovn-northd: Skip unsnat flows for load balancer vips in + router ingress pipeline + +Suppose there is below NAT entry with external_ip = 172.168.0.100 + +nat + external ip: "172.168.0.100" + logical ip: "10.0.0.0/24" + type: "snat" + +And a load balancer with the VIP - 172.168.0.100 + +_uuid : +external_ids : {} +name : lb1 +protocol : tcp +vips : {"172.168.0.100:8080"="10.0.0.4:8080"} + +And if these are associated to a gateway logical router + +Then we will see the below lflows in the router pipeline + +... +table=5 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_snat;) +... +table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8080), action=(ct_lb(10.0.0.4:8080);) +table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8080), action=(ct_dnat;) + +When a new connection packet destinated for the lb vip 172.168.0.100 and tcp.dst = 8080 +is received, the ct.new flow in the lr_in_dnat is hit and the packet's ip4.dst is +dnatted to 10.0.0.4 in the dnat conntrack zone. + +But for the subsequent packet destined to the vip, the ct.est lflow in the lr_in_dnat +stage doesn't get hit. In this case, the packet first hits the lr_in_unsnat pri 90 flow +as mentioned above with the action ct_snat. Even though ct_snat should have no effect, +looks like it is resetting the ct flags. + +In the case of tcp, the ct.new flow is hit instead of ct.est. In the the case of sctp, neither of the above +lflows in lr_in_dnat stage hit. + +This needs to be investigated further. But we can avoid this scenario in OVN +by adding the below lflow. + +table=5 (lr_in_unsnat ), priority=120 , match=(ip4 && ip4.dst == 172.168.0.100 && tcp.dst == 8080), action=(next;) + +This patch adds the above lflow if the lb vip also has an entry in the NAT table. + +This patch is also required to support sctp load balancers in OVN. + +Reported-by: Tim Rozet +Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1815217 +Signed-off-by: Numan Siddique +Acked-by: Mark Michelson +(cherry picked from upstream OVS branch20.03 commit 3cf40e8b35c5d6a4e593b42b96c284a8742235d5) + +Change-Id: Ibf609537189e80a9e69e6c968b8e4041ecc9cc40 +--- + northd/ovn-northd.8.xml | 27 +++++++++++++++++++ + northd/ovn-northd.c | 59 +++++++++++++++++++++++++++++++---------- + tests/ovn-northd.at | 38 ++++++++++++++++++++++++++ + tests/system-ovn.at | 51 ++++++++++++++++++++++++++++++++++- + 4 files changed, 160 insertions(+), 15 deletions(-) + +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index 1e0993e07..b5e4d6d84 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -2075,6 +2075,33 @@ icmp6 { + unSNATted here. +

            + ++

            Ingress Table 5: UNSNAT on Gateway and Distributed Routers

            ++
              ++
            • ++

              ++ If the Router (Gateway or Distributed) is configured with ++ load balancers, then below lflows are added: ++

              ++ ++

              ++ For each IPv4 address A defined as load balancer ++ VIP with the protocol P (and the protocol port ++ T if defined) is also present as an ++ external_ip in the NAT table, ++ a priority-120 logical flow is added with the match ++ ip4 && ip4.dst == A && ++ P with the action next; to ++ advance the packet to the next table. If the load balancer ++ has protocol port B defined, then the match also has ++ P.dst == B. ++

              ++ ++

              ++ The above flows are also added for IPv6 load balancers. ++

              ++
            • ++
            ++ +

            Ingress Table 5: UNSNAT on Gateway Routers

            + +
              +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index cdaeff401..75c19df62 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -7570,7 +7570,7 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, + struct ds *match, struct ds *actions, int priority, + const char *lb_force_snat_ip, struct lb_vip *lb_vip, + bool is_udp, struct nbrec_load_balancer *lb, +- struct shash *meter_groups) ++ struct shash *meter_groups, struct sset *nat_entries) + { + build_empty_lb_event_flow(od, lflows, lb_vip, lb, S_ROUTER_IN_DNAT, + meter_groups); +@@ -7603,6 +7603,40 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, + free(new_match); + free(est_match); + ++ const char *ip_match = NULL; ++ if (lb_vip->addr_family == AF_INET) { ++ ip_match = "ip4"; ++ } else { ++ ip_match = "ip6"; ++ } ++ ++ if (sset_contains(nat_entries, lb_vip->vip)) { ++ /* The load balancer vip is also present in the NAT entries. ++ * So add a high priority lflow to advance the the packet ++ * destined to the vip (and the vip port if defined) ++ * in the S_ROUTER_IN_UNSNAT stage. ++ * There seems to be an issue with ovs-vswitchd. When the new ++ * connection packet destined for the lb vip is received, ++ * it is dnat'ed in the S_ROUTER_IN_DNAT stage in the dnat ++ * conntrack zone. For the next packet, if it goes through ++ * unsnat stage, the conntrack flags are not set properly, and ++ * it doesn't hit the established state flows in ++ * S_ROUTER_IN_DNAT stage. */ ++ struct ds unsnat_match = DS_EMPTY_INITIALIZER; ++ ds_put_format(&unsnat_match, "%s && %s.dst == %s && %s", ++ ip_match, ip_match, lb_vip->vip, ++ is_udp ? "udp" : "tcp"); ++ if (lb_vip->vip_port) { ++ ds_put_format(&unsnat_match, " && %s.dst == %d", ++ is_udp ? "udp" : "tcp", lb_vip->vip_port); ++ } ++ ++ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, 120, ++ ds_cstr(&unsnat_match), "next;", &lb->header_); ++ ++ ds_destroy(&unsnat_match); ++ } ++ + if (!od->l3dgw_port || !od->l3redirect_port || !lb_vip->n_backends) { + return; + } +@@ -7612,19 +7646,11 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, + * router has a gateway router port associated. + */ + struct ds undnat_match = DS_EMPTY_INITIALIZER; +- if (lb_vip->addr_family == AF_INET) { +- ds_put_cstr(&undnat_match, "ip4 && ("); +- } else { +- ds_put_cstr(&undnat_match, "ip6 && ("); +- } ++ ds_put_format(&undnat_match, "%s && (", ip_match); + + for (size_t i = 0; i < lb_vip->n_backends; i++) { + struct lb_vip_backend *backend = &lb_vip->backends[i]; +- if (backend->addr_family == AF_INET) { +- ds_put_format(&undnat_match, "(ip4.src == %s", backend->ip); +- } else { +- ds_put_format(&undnat_match, "(ip6.src == %s", backend->ip); +- } ++ ds_put_format(&undnat_match, "(%s.src == %s", ip_match, backend->ip); + + if (backend->port) { + ds_put_format(&undnat_match, " && %s.src == %d) || ", +@@ -8875,6 +8901,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + &nat->header_); + sset_add(&nat_entries, nat->external_ip); + } ++ } else { ++ /* Add the NAT external_ip to the nat_entries even for ++ * gateway routers. This is required for adding load balancer ++ * flows.*/ ++ sset_add(&nat_entries, nat->external_ip); + } + + /* Egress UNDNAT table: It is for already established connections' +@@ -9055,8 +9086,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + } + } + +- sset_destroy(&nat_entries); +- + /* Handle force SNAT options set in the gateway router. */ + if (dnat_force_snat_ip && !od->l3dgw_port) { + /* If a packet with destination IP address as that of the +@@ -9117,6 +9146,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + /* Load balancing and packet defrag are only valid on + * Gateway routers or router with gateway port. */ + if (!smap_get(&od->nbr->options, "chassis") && !od->l3dgw_port) { ++ sset_destroy(&nat_entries); + continue; + } + +@@ -9191,10 +9221,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + } + add_router_lb_flow(lflows, od, &match, &actions, prio, + lb_force_snat_ip, lb_vip, is_udp, +- nb_lb, meter_groups); ++ nb_lb, meter_groups, &nat_entries); + } + } + sset_destroy(&all_ips); ++ sset_destroy(&nat_entries); + } + + /* Logical router ingress table ND_RA_OPTIONS & ND_RA_RESPONSE: IPv6 Router +diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at +index a2989e78e..d127152f5 100644 +--- a/tests/ovn-northd.at ++++ b/tests/ovn-northd.at +@@ -1288,3 +1288,41 @@ ovn-nbctl --wait=sb lb-del lb2 + OVS_WAIT_UNTIL([test 0 = `ovn-sbctl list service_monitor | wc -l`]) + + AT_CLEANUP ++ ++AT_SETUP([ovn -- Load balancer VIP in NAT entries]) ++AT_SKIP_IF([test $HAVE_PYTHON = no]) ++ovn_start ++ ++ovn-nbctl lr-add lr0 ++ovn-nbctl lrp-add lr0 lr0-public 00:00:01:01:02:04 192.168.2.1/24 ++ovn-nbctl lrp-add lr0 lr0-join 00:00:01:01:02:04 10.10.0.1/24 ++ ++ovn-nbctl set logical_router lr0 options:chassis=ch1 ++ ++ovn-nbctl lb-add lb1 "192.168.2.1:8080" "10.0.0.4:8080" ++ovn-nbctl lb-add lb2 "192.168.2.4:8080" "10.0.0.5:8080" udp ++ovn-nbctl lb-add lb3 "192.168.2.5:8080" "10.0.0.6:8080" ++ovn-nbctl lb-add lb4 "192.168.2.6:8080" "10.0.0.7:8080" ++ ++ovn-nbctl lr-lb-add lr0 lb1 ++ovn-nbctl lr-lb-add lr0 lb2 ++ovn-nbctl lr-lb-add lr0 lb3 ++ovn-nbctl lr-lb-add lr0 lb4 ++ ++ovn-nbctl lr-nat-add lr0 snat 192.168.2.1 10.0.0.0/24 ++ovn-nbctl lr-nat-add lr0 dnat_and_snat 192.168.2.4 10.0.0.4 ++ovn-nbctl lr-nat-add lr0 dnat 192.168.2.5 10.0.0.5 ++ ++OVS_WAIT_UNTIL([test 1 = $(ovn-sbctl dump-flows lr0 | grep lr_in_unsnat | \ ++grep "ip4 && ip4.dst == 192.168.2.1 && tcp && tcp.dst == 8080" -c) ]) ++ ++AT_CHECK([test 1 = $(ovn-sbctl dump-flows lr0 | grep lr_in_unsnat | \ ++grep "ip4 && ip4.dst == 192.168.2.4 && udp && udp.dst == 8080" -c) ]) ++ ++AT_CHECK([test 1 = $(ovn-sbctl dump-flows lr0 | grep lr_in_unsnat | \ ++grep "ip4 && ip4.dst == 192.168.2.5 && tcp && tcp.dst == 8080" -c) ]) ++ ++AT_CHECK([test 0 = $(ovn-sbctl dump-flows lr0 | grep lr_in_unsnat | \ ++grep "ip4 && ip4.dst == 192.168.2.6 && tcp && tcp.dst == 8080" -c) ]) ++ ++AT_CLEANUP +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index 3b3379840..f1ae69b20 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -1635,7 +1635,6 @@ ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.16 + ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=192.168.2.2 \ + external_ip=30.0.0.2 -- add logical_router R2 nat @nat + +- + # Wait for ovn-controller to catch up. + ovn-nbctl --wait=hv sync + OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \ +@@ -1671,6 +1670,56 @@ tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(sr + tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,protoinfo=(state=) + ]) + ++check_est_flows () { ++ n=$(ovs-ofctl dump-flows br-int table=14 | grep \ ++"priority=120,ct_state=+est+trk,tcp,metadata=0x2,nw_dst=30.0.0.2,tp_dst=8000" \ ++| grep nat | sed -n 's/.*n_packets=\([[0-9]]\{1,\}\).*/\1/p') ++ ++ echo "n_packets=$n" ++ test "$n" != 0 ++} ++ ++OVS_WAIT_UNTIL([check_est_flows], [check established flows]) ++ ++ ++ovn-nbctl set logical_router R2 options:lb_force_snat_ip="20.0.0.2" ++ ++# Destroy the load balancer and create again. ovn-controller will ++# clear the OF flows and re add again and clears the n_packets ++# for these flows. ++ovn-nbctl destroy load_balancer $uuid ++uuid=`ovn-nbctl create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"` ++ovn-nbctl set logical_router R2 load_balancer=$uuid ++ ++# Config OVN load-balancer with another VIP (this time with ports). ++ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.168.2.2:80"' ++ ++ovn-nbctl list load_balancer ++ovn-sbctl dump-flows R2 ++OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=41 | \ ++grep 'nat(src=20.0.0.2)']) ++ ++dnl Test load-balancing that includes L4 ports in NAT. ++for i in `seq 1 20`; do ++ echo Request $i ++ NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) ++done ++ ++dnl Each server should have at least one connection. ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | ++sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,protoinfo=(state=) ++]) ++ ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) | ++sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++tcp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) ++]) ++ ++OVS_WAIT_UNTIL([check_est_flows], [check established flows]) ++ + OVS_APP_EXIT_AND_WAIT([ovn-controller]) + + as ovn-sb +-- +2.25.1 + diff --git a/SOURCES/0003-IPv6-PD-Disable-pd-processing-if-the-router-port-is-.patch b/SOURCES/0003-IPv6-PD-Disable-pd-processing-if-the-router-port-is-.patch new file mode 100644 index 0000000..57864aa --- /dev/null +++ b/SOURCES/0003-IPv6-PD-Disable-pd-processing-if-the-router-port-is-.patch @@ -0,0 +1,37 @@ +From fe499ffd96efda2ffd3f7f066faebe6ec41a83f4 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <0b9d16670d5561d8300d2448cbd4686a3acdc57e.1588608928.git.lorenzo.bianconi@redhat.com> +References: <0b9d16670d5561d8300d2448cbd4686a3acdc57e.1588608928.git.lorenzo.bianconi@redhat.com> +From: Lorenzo Bianconi +Date: Wed, 29 Apr 2020 18:05:31 +0200 +Subject: [PATCH 3/3] IPv6 PD: Disable pd processing if the router port is + disabled. + +Tested-by: Jianlin Shi +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique +--- + northd/ovn-northd.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -9373,12 +9373,18 @@ build_lrouter_flows(struct hmap *datapat + /* enable IPv6 prefix delegation */ + bool prefix_delegation = smap_get_bool(&op->nbrp->options, + "prefix_delegation", false); ++ if (!lrport_is_enabled(op->nbrp)) { ++ prefix_delegation = false; ++ } + smap_add(&options, "ipv6_prefix_delegation", + prefix_delegation ? "true" : "false"); + sbrec_port_binding_set_options(op->sb, &options); + + bool ipv6_prefix = smap_get_bool(&op->nbrp->options, + "prefix", false); ++ if (!lrport_is_enabled(op->nbrp)) { ++ ipv6_prefix = false; ++ } + smap_add(&options, "ipv6_prefix", + ipv6_prefix ? "true" : "false"); + sbrec_port_binding_set_options(op->sb, &options); diff --git a/SOURCES/0003-Support-selection-fields-in-load-balancer.patch b/SOURCES/0003-Support-selection-fields-in-load-balancer.patch new file mode 100644 index 0000000..97a7296 --- /dev/null +++ b/SOURCES/0003-Support-selection-fields-in-load-balancer.patch @@ -0,0 +1,741 @@ +From 2ee7fb81b5f396972ce279547456fd6d57891180 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Wed, 22 Apr 2020 18:03:57 +0530 +Subject: [PATCH 3/4] Support selection fields in load balancer. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch add a new column 'selection_fields' in Load_Balancer +table in NB DB. CMS can define a set of packet headers to use +while selecting a backend. If this column is set, OVN will add the +flow in group table with selection method as 'hash' with the set fields. +Otherwise it will use the default 'dp_hash' selection method. + +If a load balancer is configured with the selection_fields as +selection_fields : [ip_dst, ip_src, tp_dst, tp_src] + +then with this patch, the modified ct_lb action will look like + - ct_lb(backends=IP1:P1,IP2:P1; hash_fields="ip_dst,ip_src,tp_dst,tp_src"); + +And the OF flow will look like + - group_id=2,type=select,selection_method=hash, + fields(ip_src,ip_dst,tcp_src,tcp_dst),bucket=bucket_id:0,weight:100,actions=ct(.... + +Change-Id: Iac595d50d77783fd28bcb1af7b63e9274b94f622 +Tested-by: Maciej Józefczyk +Acked-by: Maciej Józefczyk +Acked-by: Han Zhou +Acked-by: Mark Michelson +Signed-off-by: Numan Siddique +--- + NEWS | 6 ++ + include/ovn/actions.h | 1 + + lib/actions.c | 45 +++++++++-- + northd/ovn-northd.c | 30 ++++++-- + ovn-nb.ovsschema | 10 ++- + ovn-nb.xml | 27 +++++++ + tests/ovn-northd.at | 24 +++--- + tests/ovn.at | 49 +++++++----- + tests/system-ovn.at | 172 +++++++++++++++++++++++++++++++++++++++--- + 9 files changed, 311 insertions(+), 53 deletions(-) + +diff --git a/NEWS b/NEWS +index e77343c89..15c3453f8 100644 +--- a/NEWS ++++ b/NEWS +@@ -9,6 +9,12 @@ OVN v20.03.0 - 28 Feb 2020 + - Added support for ECMP routes in OVN router. + - Added IPv6 Prefix Delegation support in OVN. + - OVN now uses OpenFlow 1.5. ++ - Added support to choose selection methods - dp_hash or ++ hash (with specified hash fields) for OVN load balancer ++ backend selection. This is incompatible with older versions. ++ Care should be taken while upgrading as the existing ++ load balancer traffic will be affected if ovn-controllers ++ are not stopped before uprading northd services. + + - OVN Interconnection: + * Support for L3 interconnection of multiple OVN deployments with tunnels +diff --git a/include/ovn/actions.h b/include/ovn/actions.h +index e3dec99b2..df11a5713 100644 +--- a/include/ovn/actions.h ++++ b/include/ovn/actions.h +@@ -252,6 +252,7 @@ struct ovnact_ct_lb { + struct ovnact_ct_lb_dst *dsts; + size_t n_dsts; + uint8_t ltable; /* Logical table ID of next table. */ ++ char *hash_fields; + }; + + struct ovnact_select_dst { +diff --git a/lib/actions.c b/lib/actions.c +index 605dbffe4..ee7ccae0d 100644 +--- a/lib/actions.c ++++ b/lib/actions.c +@@ -900,9 +900,18 @@ parse_ct_lb_action(struct action_context *ctx) + struct ovnact_ct_lb_dst *dsts = NULL; + size_t allocated_dsts = 0; + size_t n_dsts = 0; ++ char *hash_fields = NULL; + +- if (lexer_match(ctx->lexer, LEX_T_LPAREN)) { +- while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) { ++ if (lexer_match(ctx->lexer, LEX_T_LPAREN) && ++ !lexer_match(ctx->lexer, LEX_T_RPAREN)) { ++ if (!lexer_match_id(ctx->lexer, "backends") || ++ !lexer_force_match(ctx->lexer, LEX_T_EQUALS)) { ++ lexer_syntax_error(ctx->lexer, "expecting backends"); ++ return; ++ } ++ ++ while (!lexer_match(ctx->lexer, LEX_T_SEMICOLON) && ++ !lexer_match(ctx->lexer, LEX_T_RPAREN)) { + struct ovnact_ct_lb_dst dst; + if (lexer_match(ctx->lexer, LEX_T_LSQUARE)) { + /* IPv6 address and port */ +@@ -969,12 +978,27 @@ parse_ct_lb_action(struct action_context *ctx) + } + dsts[n_dsts++] = dst; + } ++ ++ if (lexer_match_id(ctx->lexer, "hash_fields")) { ++ if (!lexer_match(ctx->lexer, LEX_T_EQUALS) || ++ ctx->lexer->token.type != LEX_T_STRING || ++ lexer_lookahead(ctx->lexer) != LEX_T_RPAREN) { ++ lexer_syntax_error(ctx->lexer, "invalid hash_fields"); ++ free(dsts); ++ return; ++ } ++ ++ hash_fields = xstrdup(ctx->lexer->token.s); ++ lexer_get(ctx->lexer); ++ lexer_get(ctx->lexer); ++ } + } + + struct ovnact_ct_lb *cl = ovnact_put_CT_LB(ctx->ovnacts); + cl->ltable = ctx->pp->cur_ltable + 1; + cl->dsts = dsts; + cl->n_dsts = n_dsts; ++ cl->hash_fields = hash_fields; + } + + static void +@@ -982,10 +1006,10 @@ format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s) + { + ds_put_cstr(s, "ct_lb"); + if (cl->n_dsts) { +- ds_put_char(s, '('); ++ ds_put_cstr(s, "(backends="); + for (size_t i = 0; i < cl->n_dsts; i++) { + if (i) { +- ds_put_cstr(s, ", "); ++ ds_put_char(s, ','); + } + + const struct ovnact_ct_lb_dst *dst = &cl->dsts[i]; +@@ -1005,7 +1029,13 @@ format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s) + } + } + ds_put_char(s, ')'); ++ ++ if (cl->hash_fields) { ++ ds_chomp(s, ')'); ++ ds_put_format(s, "; hash_fields=\"%s\")", cl->hash_fields); ++ } + } ++ + ds_put_char(s, ';'); + } + +@@ -1052,7 +1082,11 @@ encode_CT_LB(const struct ovnact_ct_lb *cl, + : MFF_LOG_DNAT_ZONE - MFF_REG0; + + struct ds ds = DS_EMPTY_INITIALIZER; +- ds_put_format(&ds, "type=select,selection_method=dp_hash"); ++ ds_put_format(&ds, "type=select,selection_method=%s", ++ cl->hash_fields ? "hash": "dp_hash"); ++ if (cl->hash_fields) { ++ ds_put_format(&ds, ",fields(%s)", cl->hash_fields); ++ } + + BUILD_ASSERT(MFF_LOG_CT_ZONE >= MFF_REG0); + BUILD_ASSERT(MFF_LOG_CT_ZONE < MFF_REG0 + FLOW_N_REGS); +@@ -1094,6 +1128,7 @@ static void + ovnact_ct_lb_free(struct ovnact_ct_lb *ct_lb) + { + free(ct_lb->dsts); ++ free(ct_lb->hash_fields); + } + + static void +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index dc647d7c5..b07e68cfa 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -3108,7 +3108,7 @@ struct ovn_lb { + struct hmap_node hmap_node; + + const struct nbrec_load_balancer *nlb; /* May be NULL. */ +- ++ char *selection_fields; + struct lb_vip *vips; + size_t n_vips; + }; +@@ -3336,6 +3336,15 @@ ovn_lb_create(struct northd_context *ctx, struct hmap *lbs, + n_vips++; + } + ++ if (lb->nlb->n_selection_fields) { ++ struct ds sel_fields = DS_EMPTY_INITIALIZER; ++ for (size_t i = 0; i < lb->nlb->n_selection_fields; i++) { ++ ds_put_format(&sel_fields, "%s,", lb->nlb->selection_fields[i]); ++ } ++ ds_chomp(&sel_fields, ','); ++ lb->selection_fields = ds_steal_cstr(&sel_fields); ++ } ++ + return lb; + } + +@@ -3354,13 +3363,15 @@ ovn_lb_destroy(struct ovn_lb *lb) + free(lb->vips[i].backends); + } + free(lb->vips); ++ free(lb->selection_fields); + } + + static void build_lb_vip_ct_lb_actions(struct lb_vip *lb_vip, +- struct ds *action) ++ struct ds *action, ++ char *selection_fields) + { + if (lb_vip->health_check) { +- ds_put_cstr(action, "ct_lb("); ++ ds_put_cstr(action, "ct_lb(backends="); + + size_t n_active_backends = 0; + for (size_t k = 0; k < lb_vip->n_backends; k++) { +@@ -3384,7 +3395,13 @@ static void build_lb_vip_ct_lb_actions(struct lb_vip *lb_vip, + ds_put_cstr(action, ");"); + } + } else { +- ds_put_format(action, "ct_lb(%s);", lb_vip->backend_ips); ++ ds_put_format(action, "ct_lb(backends=%s);", lb_vip->backend_ips); ++ } ++ ++ if (selection_fields && selection_fields[0]) { ++ ds_chomp(action, ';'); ++ ds_chomp(action, ')'); ++ ds_put_format(action, "; hash_fields=\"%s\");", selection_fields); + } + } + +@@ -5660,7 +5677,7 @@ build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, struct ovn_lb *lb) + + /* New connections in Ingress table. */ + struct ds action = DS_EMPTY_INITIALIZER; +- build_lb_vip_ct_lb_actions(lb_vip, &action); ++ build_lb_vip_ct_lb_actions(lb_vip, &action, lb->selection_fields); + + struct ds match = DS_EMPTY_INITIALIZER; + ds_put_format(&match, "ct.new && %s.dst == %s", ip_match, lb_vip->vip); +@@ -9290,7 +9307,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + for (size_t j = 0; j < lb->n_vips; j++) { + struct lb_vip *lb_vip = &lb->vips[j]; + ds_clear(&actions); +- build_lb_vip_ct_lb_actions(lb_vip, &actions); ++ build_lb_vip_ct_lb_actions(lb_vip, &actions, ++ lb->selection_fields); + + if (!sset_contains(&all_ips, lb_vip->vip)) { + sset_add(&all_ips, lb_vip->vip); +diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema +index 949f6258b..359201c26 100644 +--- a/ovn-nb.ovsschema ++++ b/ovn-nb.ovsschema +@@ -1,7 +1,7 @@ + { + "name": "OVN_Northbound", +- "version": "5.22.0", +- "cksum": "170077561 25417", ++ "version": "5.23.0", ++ "cksum": "3367447924 25747", + "tables": { + "NB_Global": { + "columns": { +@@ -179,6 +179,12 @@ + "ip_port_mappings": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}, ++ "selection_fields": { ++ "type": {"key": {"type": "string", ++ "enum": ["set", ++ ["eth_src", "eth_dst", "ip_src", "ip_dst", ++ "tp_src", "tp_dst"]]}, ++ "min": 0, "max": "unlimited"}}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, +diff --git a/ovn-nb.xml b/ovn-nb.xml +index 045c63fb0..55f0ef9f6 100644 +--- a/ovn-nb.xml ++++ b/ovn-nb.xml +@@ -1497,6 +1497,33 @@ +

              + + ++ ++

              ++ OVN native load balancers are supported using the OpenFlow groups ++ of type select. OVS supports two selection methods: ++ dp_hash and hash (with optional fields ++ specified) in selecting the buckets of a group. ++ Please see the OVS documentation (man ovs-ofctl) ++ for more details on the selection methods. Each endpoint IP (and port ++ if set) is mapped to a bucket in the group flow. ++

              ++ ++

              ++ CMS can choose the hash selection method by setting the ++ selection fields in this column. ovs-vswitchd uses the ++ specified fields in generating the hash. ++

              ++ ++

              ++ dp_hash selection method uses the assistance of ++ datapath to calculate the hash and it is expected to be ++ faster than hash selection method. So CMS should take ++ this into consideration before using the hash method. ++ Please consult the OVS documentation and OVS sources for the ++ implementation details. ++

              ++
              ++ + + + See External IDs at the beginning of this document. +diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at +index 569390cee..e6a8c04da 100644 +--- a/tests/ovn-northd.at ++++ b/tests/ovn-northd.at +@@ -1119,7 +1119,7 @@ ovn-nbctl --wait=sb ls-lb-add sw0 lb1 + + ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) + ]) + + # Delete the Load_Balancer_Health_Check +@@ -1128,7 +1128,7 @@ OVS_WAIT_UNTIL([test 0 = `ovn-sbctl list service_monitor | wc -l`]) + + ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) + ]) + + # Create the Load_Balancer_Health_Check again. +@@ -1141,7 +1141,7 @@ service_monitor | sed '/^$/d' | wc -l`]) + + ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) + ]) + + # Get the uuid of both the service_monitor +@@ -1157,7 +1157,7 @@ OVS_WAIT_UNTIL([ + + ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80);) + ]) + + # Set the service monitor for sw0-p1 to offline +@@ -1187,7 +1187,7 @@ OVS_WAIT_UNTIL([ + + ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) + ]) + + # Set the service monitor for sw1-p1 to error +@@ -1199,7 +1199,7 @@ OVS_WAIT_UNTIL([ + ovn-sbctl dump-flows sw0 | grep "ip4.dst == 10.0.0.10 && tcp.dst == 80" \ + | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80);) + ]) + + # Add one more vip to lb1 +@@ -1229,8 +1229,8 @@ service_monitor port=1000 | sed '/^$/d' | wc -l`]) + + ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80);) +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(10.0.0.3:1000);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(backends=10.0.0.3:1000);) + ]) + + # Set the service monitor for sw1-p1 to online +@@ -1242,16 +1242,16 @@ OVS_WAIT_UNTIL([ + + ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);) +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(10.0.0.3:1000,20.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(backends=10.0.0.3:1000,20.0.0.3:80);) + ]) + + # Associate lb1 to sw1 + ovn-nbctl --wait=sb ls-lb-add sw1 lb1 + ovn-sbctl dump-flows sw1 | grep ct_lb | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);) +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(10.0.0.3:1000,20.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(ct_lb(backends=10.0.0.3:1000,20.0.0.3:80);) + ]) + + # Now create lb2 same as lb1 but udp protocol. +diff --git a/tests/ovn.at b/tests/ovn.at +index 5fb100ad4..ae3b44cb3 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -968,29 +968,42 @@ ct_lb(); + encodes as ct(table=19,zone=NXM_NX_REG13[0..15],nat) + has prereqs ip + ct_lb(192.168.1.2:80, 192.168.1.3:80); ++ Syntax error at `192.168.1.2' expecting backends. ++ct_lb(backends=192.168.1.2:80,192.168.1.3:80); + encodes as group:1 + uses group: id(1), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=192.168.1.2:80),commit,table=19,zone=NXM_NX_REG13[0..15]),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=192.168.1.3:80),commit,table=19,zone=NXM_NX_REG13[0..15])) + has prereqs ip +-ct_lb(192.168.1.2, 192.168.1.3, ); +- formats as ct_lb(192.168.1.2, 192.168.1.3); ++ct_lb(backends=192.168.1.2, 192.168.1.3, ); ++ formats as ct_lb(backends=192.168.1.2,192.168.1.3); + encodes as group:2 + uses group: id(2), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=192.168.1.2),commit,table=19,zone=NXM_NX_REG13[0..15]),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=192.168.1.3),commit,table=19,zone=NXM_NX_REG13[0..15])) + has prereqs ip +-ct_lb(fd0f::2, fd0f::3, ); +- formats as ct_lb(fd0f::2, fd0f::3); ++ct_lb(backends=fd0f::2, fd0f::3, ); ++ formats as ct_lb(backends=fd0f::2,fd0f::3); + encodes as group:3 + uses group: id(3), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=fd0f::2),commit,table=19,zone=NXM_NX_REG13[0..15]),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=fd0f::3),commit,table=19,zone=NXM_NX_REG13[0..15])) + has prereqs ip + +-ct_lb(192.168.1.2:); ++ct_lb(backends=192.168.1.2:); + Syntax error at `)' expecting port number. +-ct_lb(192.168.1.2:123456); ++ct_lb(backends=192.168.1.2:123456); + Syntax error at `123456' expecting port number. +-ct_lb(foo); ++ct_lb(backends=foo); + Syntax error at `foo' expecting IP address. +-ct_lb([192.168.1.2]); ++ct_lb(backends=[192.168.1.2]); + Syntax error at `192.168.1.2' expecting IPv6 address. + ++ct_lb(backends=192.168.1.2:80,192.168.1.3:80; hash_fields=eth_src,eth_dst,ip_src); ++ Syntax error at `eth_src' invalid hash_fields. ++ct_lb(backends=192.168.1.2:80,192.168.1.3:80; hash_fields="eth_src,eth_dst,ip_src"); ++ encodes as group:4 ++ uses group: id(4), name(type=select,selection_method=hash,fields(eth_src,eth_dst,ip_src),bucket=bucket_id=0,weight:100,actions=ct(nat(dst=192.168.1.2:80),commit,table=19,zone=NXM_NX_REG13[0..15]),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=192.168.1.3:80),commit,table=19,zone=NXM_NX_REG13[0..15])) ++ has prereqs ip ++ct_lb(backends=fd0f::2,fd0f::3; hash_fields="eth_src,eth_dst,ip_src,ip_dst,tp_src,tp_dst"); ++ encodes as group:5 ++ uses group: id(5), name(type=select,selection_method=hash,fields(eth_src,eth_dst,ip_src,ip_dst,tp_src,tp_dst),bucket=bucket_id=0,weight:100,actions=ct(nat(dst=fd0f::2),commit,table=19,zone=NXM_NX_REG13[0..15]),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=fd0f::3),commit,table=19,zone=NXM_NX_REG13[0..15])) ++ has prereqs ip ++ + # ct_next + ct_next; + encodes as ct(table=19,zone=NXM_NX_REG13[0..15]) +@@ -1491,13 +1504,13 @@ handle_svc_check(reg0); + # select + reg9[16..31] = select(1=50, 2=100, 3, ); + formats as reg9[16..31] = select(1=50, 2=100, 3=100); +- encodes as group:4 +- uses group: id(4), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:50,actions=load:1->xreg4[16..31],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xreg4[16..31],resubmit(,19),bucket=bucket_id=2,weight:100,actions=load:3->xreg4[16..31],resubmit(,19)) ++ encodes as group:6 ++ uses group: id(6), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:50,actions=load:1->xreg4[16..31],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xreg4[16..31],resubmit(,19),bucket=bucket_id=2,weight:100,actions=load:3->xreg4[16..31],resubmit(,19)) + + reg0 = select(1, 2); + formats as reg0 = select(1=100, 2=100); +- encodes as group:5 +- uses group: id(5), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=load:1->xxreg0[96..127],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xxreg0[96..127],resubmit(,19)) ++ encodes as group:7 ++ uses group: id(7), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=load:1->xxreg0[96..127],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xxreg0[96..127],resubmit(,19)) + + reg0 = select(1=, 2); + Syntax error at `,' expecting weight. +@@ -1513,12 +1526,12 @@ reg0[0..14] = select(1, 2, 3); + cannot use 15-bit field reg0[0..14] for "select", which requires at least 16 bits. + + fwd_group(liveness="true", childports="eth0", "lsp1"); +- encodes as group:6 +- uses group: id(6), name(type=select,selection_method=dp_hash,bucket=watch_port:5,load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=watch_port:17,load=0x17->NXM_NX_REG15[0..15],resubmit(,64)) ++ encodes as group:8 ++ uses group: id(8), name(type=select,selection_method=dp_hash,bucket=watch_port:5,load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=watch_port:17,load=0x17->NXM_NX_REG15[0..15],resubmit(,64)) + + fwd_group(childports="eth0", "lsp1"); +- encodes as group:7 +- uses group: id(7), name(type=select,selection_method=dp_hash,bucket=load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=load=0x17->NXM_NX_REG15[0..15],resubmit(,64)) ++ encodes as group:9 ++ uses group: id(9), name(type=select,selection_method=dp_hash,bucket=load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=load=0x17->NXM_NX_REG15[0..15],resubmit(,64)) + + fwd_group(childports=eth0); + Syntax error at `eth0' expecting logical switch port. +@@ -17916,12 +17929,12 @@ service_monitor | sed '/^$/d' | wc -l`]) + + ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);) ++ table=10(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) + ]) + + ovn-sbctl dump-flows lr0 | grep ct_lb | grep priority=120 > lflows.txt + AT_CHECK([cat lflows.txt], [0], [dnl +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(10.0.0.3:80,20.0.0.3:80);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) + ]) + + # get the svc monitor mac. +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index 117f1e835..9a5ef1ec3 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -1095,15 +1095,15 @@ ovn-nbctl lsp-add bar bar3 \ + -- lsp-set-addresses bar3 "f0:00:0f:01:02:05 172.16.1.4" + + # Config OVN load-balancer with a VIP. +-uuid=`ovn-nbctl create load_balancer vips:30.0.0.1="172.16.1.2,172.16.1.3,172.16.1.4"` +-ovn-nbctl set logical_switch foo load_balancer=$uuid ++ovn-nbctl lb-add lb1 30.0.0.1 "172.16.1.2,172.16.1.3,172.16.1.4" ++ovn-nbctl ls-lb-add foo lb1 + + # Create another load-balancer with another VIP. +-uuid=`ovn-nbctl create load_balancer vips:30.0.0.3="172.16.1.2,172.16.1.3,172.16.1.4"` +-ovn-nbctl add logical_switch foo load_balancer $uuid ++lb2_uuid=`ovn-nbctl create load_balancer name=lb2 vips:30.0.0.3="172.16.1.2,172.16.1.3,172.16.1.4"` ++ovn-nbctl ls-lb-add foo lb2 + + # Config OVN load-balancer with another VIP (this time with ports). +-ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"172.16.1.2:80,172.16.1.3:80,172.16.1.4:80"' ++ovn-nbctl set load_balancer $lb2_uuid vips:'"30.0.0.2:8000"'='"172.16.1.2:80,172.16.1.3:80,172.16.1.4:80"' + + # Wait for ovn-controller to catch up. + ovn-nbctl --wait=hv sync +@@ -1157,6 +1157,82 @@ tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(s + tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,protoinfo=(state=) + ]) + ++# Configure selection_fields. ++ovn-nbctl set load_balancer $lb2_uuid selection_fields="ip_src,ip_dst,tp_src,tp_dst" ++OVS_WAIT_UNTIL([ ++ test $(ovs-ofctl dump-groups br-int | \ ++ grep "selection_method=hash,fields(ip_src,ip_dst,tcp_src,tcp_dst)" -c) -eq 2 ++]) ++ ++AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++ ++dnl Test load-balancing that includes L4 ports in NAT. ++for i in `seq 1 20`; do ++ echo Request $i ++ NS_CHECK_EXEC([foo1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) ++done ++ ++dnl Each server should have at least one connection. ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \ ++sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,protoinfo=(state=) ++]) ++ ++AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++ ++echo "foo" > foo ++for i in `seq 1 20`; do ++ echo Request $i ++ ip netns exec foo1 nc -p 30000 30.0.0.2 8000 < foo ++done ++ ++dnl Only one backend should be chosen. ++AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 -c) -eq 1]) ++ ++ovn-nbctl set load_balancer $lb2_uuid selection_fields="ip_src" ++OVS_WAIT_UNTIL([ ++ test $(ovs-ofctl dump-groups br-int | \ ++ grep "selection_method=hash,fields=ip_src" -c) -eq 2 ++]) ++ ++AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++for i in `seq 1 20`; do ++ echo Request $i ++ ip netns exec foo1 nc 30.0.0.2 8000 < foo ++done ++ ++dnl Only one backend should be chosen as eth_src and ip_src is fixed. ++bar1_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1.2 -c) ++bar2_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1.3 -c) ++bar3_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1.4 -c) ++ ++AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1 -c) -ne 0]) ++ ++if [[ "$bar1_ct" == "20" ]]; then ++ AT_CHECK([test $bar1_ct -eq 20]) ++ AT_CHECK([test $bar2_ct -eq 0]) ++ AT_CHECK([test $bar3_ct -eq 0]) ++else ++ AT_CHECK([test $bar1_ct -eq 0]) ++fi ++ ++if [[ "$bar2_ct" == "20" ]]; then ++ AT_CHECK([test $bar1_ct -eq 20]) ++ AT_CHECK([test $bar2_ct -eq 0]) ++ AT_CHECK([test $bar3_ct -eq 0]) ++else ++ AT_CHECK([test $bar2_ct -eq 0]) ++fi ++ ++if [[ "$bar3_ct" == "20" ]]; then ++ AT_CHECK([test $bar1_ct -eq 20]) ++ AT_CHECK([test $bar2_ct -eq 0]) ++ AT_CHECK([test $bar3_ct -eq 0]) ++else ++ AT_CHECK([test $bar3_ct -eq 0]) ++fi + + OVS_APP_EXIT_AND_WAIT([ovn-controller]) + +@@ -1246,11 +1322,11 @@ uuid=`ovn-nbctl create load_balancer vips:\"fd03::1\"=\"fd02::2,fd02::3,fd02::4 + ovn-nbctl set logical_switch foo load_balancer=$uuid + + # Create another load-balancer with another VIP. +-uuid=`ovn-nbctl create load_balancer vips:\"fd03::3\"=\"fd02::2,fd02::3,fd02::4\"` +-ovn-nbctl add logical_switch foo load_balancer $uuid ++lb2_uuid=`ovn-nbctl create load_balancer vips:\"fd03::3\"=\"fd02::2,fd02::3,fd02::4\"` ++ovn-nbctl add logical_switch foo load_balancer $lb2_uuid + + # Config OVN load-balancer with another VIP (this time with ports). +-ovn-nbctl set load_balancer $uuid vips:'"[[fd03::2]]:8000"'='"@<:@fd02::2@:>@:80,@<:@fd02::3@:>@:80,@<:@fd02::4@:>@:80"' ++ovn-nbctl set load_balancer $lb2_uuid vips:'"[[fd03::2]]:8000"'='"@<:@fd02::2@:>@:80,@<:@fd02::3@:>@:80,@<:@fd02::4@:>@:80"' + + # Wait for ovn-controller to catch up. + ovn-nbctl --wait=hv sync +@@ -1304,7 +1380,83 @@ tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd + tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::4,dst=fd01::2,sport=,dport=),zone=,protoinfo=(state=) + ]) + ++# Configure selection_fields. ++ovn-nbctl set load_balancer $lb2_uuid selection_fields="ip_src,ip_dst,tp_src,tp_dst" ++OVS_WAIT_UNTIL([ ++ test $(ovs-ofctl dump-groups br-int | \ ++ grep "selection_method=hash,fields(ip_src,ip_dst,tcp_src,tcp_dst)" -c) -eq 2 ++]) ++ ++AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++ ++dnl Test load-balancing that includes L4 ports in NAT. ++for i in `seq 1 20`; do ++ echo Request $i ++ NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) ++done ++ ++dnl Each server should have at least one connection. ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \ ++sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::2,dst=fd01::2,sport=,dport=),zone=,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::3,dst=fd01::2,sport=,dport=),zone=,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::4,dst=fd01::2,sport=,dport=),zone=,protoinfo=(state=) ++]) ++ ++AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++ ++echo "foo" > foo ++for i in `seq 1 20`; do ++ echo Request $i ++ ip netns exec foo1 nc -6 -p 30000 fd03::2 8000 < foo ++done ++ ++# Only one backend should be chosen. Since the source port is fixed, ++# there should be only one conntrack entry. ++AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep fd03::2 -c) -eq 1]) ++ ++ovn-nbctl set load_balancer $lb2_uuid selection_fields="eth_src,ip_src" ++OVS_WAIT_UNTIL([ ++ test $(ovs-ofctl dump-groups br-int | \ ++ grep "selection_method=hash,fields(eth_src,ip_src)" -c) -eq 2 ++]) ++ ++AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++for i in `seq 1 20`; do ++ echo Request $i ++ ip netns exec foo1 nc -6 fd03::2 8000 < foo ++done + ++dnl Only one backend should be chosen as eth_src and ip_src is fixed. ++bar1_ct=$(ovs-appctl dpctl/dump-conntrack | grep fd03::2 | grep fd02::2 -c) ++bar2_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep fd02::3 -c) ++bar3_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep fd02::4 -c) ++ ++AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep fd03::2 | grep fd02 -c) -ne 0]) ++ ++if [[ "$bar1_ct" == "20" ]]; then ++ AT_CHECK([test $bar1_ct -eq 20]) ++ AT_CHECK([test $bar2_ct -eq 0]) ++ AT_CHECK([test $bar3_ct -eq 0]) ++else ++ AT_CHECK([test $bar1_ct -eq 0]) ++fi ++ ++if [[ "$bar2_ct" == "20" ]]; then ++ AT_CHECK([test $bar1_ct -eq 20]) ++ AT_CHECK([test $bar2_ct -eq 0]) ++ AT_CHECK([test $bar3_ct -eq 0]) ++else ++ AT_CHECK([test $bar2_ct -eq 0]) ++fi ++ ++if [[ "$bar3_ct" == "20" ]]; then ++ AT_CHECK([test $bar1_ct -eq 20]) ++ AT_CHECK([test $bar2_ct -eq 0]) ++ AT_CHECK([test $bar3_ct -eq 0]) ++else ++ AT_CHECK([test $bar3_ct -eq 0]) ++fi + OVS_APP_EXIT_AND_WAIT([ovn-controller]) + + as ovn-sb +@@ -3448,7 +3600,7 @@ service_monitor | sed '/^$/d' | grep online | wc -l`]) + + OVS_WAIT_UNTIL( + [ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 | grep "ip4.dst == 10.0.0.10" > lflows.txt +- test 1 = `cat lflows.txt | grep "ct_lb(10.0.0.3:80,20.0.0.3:80)" | wc -l`] ++ test 1 = `cat lflows.txt | grep "ct_lb(backends=10.0.0.3:80,20.0.0.3:80)" | wc -l`] + ) + + # From sw0-p2 send traffic to vip - 10.0.0.10 +@@ -3474,7 +3626,7 @@ service_monitor logical_port=sw0-p1 | sed '/^$/d' | grep offline | wc -l`]) + + OVS_WAIT_UNTIL( + [ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 | grep "ip4.dst == 10.0.0.10" > lflows.txt +- test 1 = `cat lflows.txt | grep "ct_lb(20.0.0.3:80)" | wc -l`] ++ test 1 = `cat lflows.txt | grep "ct_lb(backends=20.0.0.3:80)" | wc -l`] + ) + + ovs-appctl dpctl/flush-conntrack +-- +2.26.2 + diff --git a/SOURCES/0003-controller-fix-ip-buffering-with-static-routes.patch b/SOURCES/0003-controller-fix-ip-buffering-with-static-routes.patch new file mode 100644 index 0000000..9f3209d --- /dev/null +++ b/SOURCES/0003-controller-fix-ip-buffering-with-static-routes.patch @@ -0,0 +1,61 @@ +From 754d5581fa9d5de97f7c2acf8c2900e105f588c9 Mon Sep 17 00:00:00 2001 +Message-Id: <754d5581fa9d5de97f7c2acf8c2900e105f588c9.1590585469.git.lorenzo.bianconi@redhat.com> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Wed, 20 May 2020 22:01:16 +0200 +Subject: [PATCH ovn 2/3] controller: fix ip buffering with static routes + +When the arp request is sent to a gw router and not to the final +destination of the packet buffered_packets_map needs to be updated using +next-hop ip address and not the destionation one. + +Fixes: 2e5cdb4b1392 ("OVN: add buffering support for ip packets") +Signed-off-by: Lorenzo Bianconi +--- + controller/pinctrl.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -1378,8 +1378,7 @@ pinctrl_find_buffered_packets(const stru + + /* Called with in the pinctrl_handler thread context. */ + static int +-pinctrl_handle_buffered_packets(const struct flow *ip_flow, +- struct dp_packet *pkt_in, ++pinctrl_handle_buffered_packets(struct dp_packet *pkt_in, + const struct match *md, bool is_arp) + OVS_REQUIRES(pinctrl_mutex) + { +@@ -1388,9 +1387,10 @@ pinctrl_handle_buffered_packets(const st + struct in6_addr addr; + + if (is_arp) { +- addr = in6_addr_mapped_ipv4(ip_flow->nw_dst); ++ addr = in6_addr_mapped_ipv4(htonl(md->flow.regs[0])); + } else { +- addr = ip_flow->ipv6_dst; ++ ovs_be128 ip6 = hton128(flow_get_xxreg(&md->flow, 0)); ++ memcpy(&addr, &ip6, sizeof addr); + } + + uint32_t hash = hash_bytes(&addr, sizeof addr, 0); +@@ -1431,7 +1431,7 @@ pinctrl_handle_arp(struct rconn *swconn, + } + + ovs_mutex_lock(&pinctrl_mutex); +- pinctrl_handle_buffered_packets(ip_flow, pkt_in, md, true); ++ pinctrl_handle_buffered_packets(pkt_in, md, true); + ovs_mutex_unlock(&pinctrl_mutex); + + /* Compose an ARP packet. */ +@@ -5278,7 +5278,7 @@ pinctrl_handle_nd_ns(struct rconn *swcon + } + + ovs_mutex_lock(&pinctrl_mutex); +- pinctrl_handle_buffered_packets(ip_flow, pkt_in, md, false); ++ pinctrl_handle_buffered_packets(pkt_in, md, false); + ovs_mutex_unlock(&pinctrl_mutex); + + uint64_t packet_stub[128 / 8]; diff --git a/SOURCES/0003-logical-fields-fix-memory-leak-caused-by-initialize-.patch b/SOURCES/0003-logical-fields-fix-memory-leak-caused-by-initialize-.patch new file mode 100644 index 0000000..26e8773 --- /dev/null +++ b/SOURCES/0003-logical-fields-fix-memory-leak-caused-by-initialize-.patch @@ -0,0 +1,120 @@ +From e6b687cc23212e0c007d9f69dfa89536c8f92306 Mon Sep 17 00:00:00 2001 +From: Damijan Skvarc +Date: Thu, 5 Mar 2020 07:21:41 +0100 +Subject: [PATCH 3/3] logical-fields: fix memory leak caused by initialize + ovnfield_by_name twice + +ovnfield_by_name is hash of strings which is used to quickly find +field by name. This hash is initialized from ovn_init_symtab(). In case +the latter function is called multiple times then also ovnfield_by_name is +initialized multiple times but without freeing previously allocated +memory resources what cause memory leaks. This actually happens in +ovn-controller which calls ovn_init_symtab() function twice, once from +ofctrl.c and the other time from lflow.c files. + +Problem was solved by initializing ovnfield_by_name entity only once +and using design pattern from stopwatch.c or meta_flow.c files (ovs). + +Problem was reported by valgrind with flood of messages (190) while executing +ovn test suite: + + ==5999== 47 (32 direct, 15 indirect) bytes in 1 blocks are definitely lost in loss record 86 of 102 + ==5999== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) + ==5999== by 0x50635D: xmalloc (util.c:138) + ==5999== by 0x4F6513: shash_add_nocopy__ (shash.c:109) + ==5999== by 0x4F6585: shash_add_nocopy (shash.c:121) + ==5999== by 0x4F65BD: shash_add (shash.c:129) + ==5999== by 0x4F6602: shash_add_once (shash.c:136) + ==5999== by 0x4395B7: ovn_init_symtab (logical-fields.c:261) + ==5999== by 0x406C91: main (ovn-controller.c:1750) + +Signed-off-by: Damijan Skvarc +Signed-off-by: Ben Pfaff +--- + controller/lflow.c | 1 - + include/ovn/logical-fields.h | 1 - + lib/logical-fields.c | 39 +++++++++++++++++++++++++----------- + 3 files changed, 27 insertions(+), 14 deletions(-) + +diff --git a/controller/lflow.c b/controller/lflow.c +index ee11fc617..01214a3a6 100644 +--- a/controller/lflow.c ++++ b/controller/lflow.c +@@ -846,5 +846,4 @@ lflow_destroy(void) + { + expr_symtab_destroy(&symtab); + shash_destroy(&symtab); +- ovn_destroy_ovnfields(); + } +diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h +index 9b7c34fb7..c7bd2dba9 100644 +--- a/include/ovn/logical-fields.h ++++ b/include/ovn/logical-fields.h +@@ -130,5 +130,4 @@ ovn_field_from_id(enum ovn_field_id id) + const char *event_to_string(enum ovn_controller_event event); + int string_to_event(const char *s); + const struct ovn_field *ovn_field_from_name(const char *name); +-void ovn_destroy_ovnfields(void); + #endif /* ovn/lib/logical-fields.h */ +diff --git a/lib/logical-fields.c b/lib/logical-fields.c +index 25ace5840..a007085b3 100644 +--- a/lib/logical-fields.c ++++ b/lib/logical-fields.c +@@ -254,12 +254,6 @@ ovn_init_symtab(struct shash *symtab) + expr_symtab_add_field(symtab, "sctp.src", MFF_SCTP_SRC, "sctp", false); + expr_symtab_add_field(symtab, "sctp.dst", MFF_SCTP_DST, "sctp", false); + +- shash_init(&ovnfield_by_name); +- for (int i = 0; i < OVN_FIELD_N_IDS; i++) { +- const struct ovn_field *of = &ovn_fields[i]; +- ovs_assert(of->id == i); /* Fields must be in the enum order. */ +- shash_add_once(&ovnfield_by_name, of->name, of); +- } + expr_symtab_add_ovn_field(symtab, "icmp4.frag_mtu", OVN_ICMP4_FRAG_MTU); + } + +@@ -284,14 +278,35 @@ string_to_event(const char *s) + return -1; + } + +-const struct ovn_field * +-ovn_field_from_name(const char *name) ++static void ++ovn_destroy_ovnfields(void) + { +- return shash_find_data(&ovnfield_by_name, name); ++ shash_destroy(&ovnfield_by_name); + } + +-void +-ovn_destroy_ovnfields(void) ++static void ++ovn_do_init_ovnfields(void) + { +- shash_destroy(&ovnfield_by_name); ++ shash_init(&ovnfield_by_name); ++ for (int i = 0; i < OVN_FIELD_N_IDS; i++) { ++ const struct ovn_field *of = &ovn_fields[i]; ++ ovs_assert(of->id == i); /* Fields must be in the enum order. */ ++ shash_add_once(&ovnfield_by_name, of->name, of); ++ } ++ atexit(ovn_destroy_ovnfields); ++} ++ ++static void ++ovn_init_ovnfields(void) ++{ ++ static pthread_once_t once = PTHREAD_ONCE_INIT; ++ pthread_once(&once, ovn_do_init_ovnfields); ++} ++ ++const struct ovn_field * ++ovn_field_from_name(const char *name) ++{ ++ ovn_init_ovnfields(); ++ ++ return shash_find_data(&ovnfield_by_name, name); + } +-- +2.24.1 + diff --git a/SOURCES/0003-northd-Add-logical-flows-for-dhcpv6-pfd-parsing.patch b/SOURCES/0003-northd-Add-logical-flows-for-dhcpv6-pfd-parsing.patch new file mode 100644 index 0000000..79d5a4f --- /dev/null +++ b/SOURCES/0003-northd-Add-logical-flows-for-dhcpv6-pfd-parsing.patch @@ -0,0 +1,449 @@ +From 643d4be1b3f40c3075af584d0cbc83e34a5e51ca Mon Sep 17 00:00:00 2001 +Message-Id: <643d4be1b3f40c3075af584d0cbc83e34a5e51ca.1586727203.git.lorenzo.bianconi@redhat.com> +In-Reply-To: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com> +References: <2e84aada0b45d2f8739c2fdbc351098fc1c09c26.1586727203.git.lorenzo.bianconi@redhat.com> +From: Lorenzo Bianconi +Date: Wed, 1 Apr 2020 18:37:31 +0200 +Subject: [PATCH 3/3] northd: Add logical flows for dhcpv6 pfd parsing + +Introduce logical flows in ovn router pipeline in order to parse dhcpv6 +advertise/reply from IPv6 prefix delegation router. +Do not overwrite ipv6_ra_pd_list info in options column of SB port_binding +table written by ovn-controller +Introduce ipv6_prefix column in NB Logical_router_port table to report +IPv6 prefix received from delegation router to the CMS + +Change-Id: Ibc1bd83bf3d9d4671f70610df5635e6266580a18 +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Numan Siddique +--- + NEWS | 1 + + northd/ovn-northd.8.xml | 8 +++ + northd/ovn-northd.c | 95 ++++++++++++++++++++++++-- + ovn-nb.ovsschema | 7 +- + ovn-nb.xml | 21 ++++++ + tests/atlocal.in | 5 +- + tests/system-ovn.at | 143 ++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 272 insertions(+), 8 deletions(-) + +diff --git a/NEWS b/NEWS +index 9b36bfd17..21c80f0dc 100644 +--- a/NEWS ++++ b/NEWS +@@ -7,6 +7,7 @@ OVN v20.03.0 - 28 Feb 2020 + - Added Forwarding Group support in OVN. + - Added support for MLD Snooping and MLD Querier. + - Added support for ECMP routes in OVN router. ++ - Added IPv6 Prefix Delegation support in OVN. + + - OVN Interconnection: + * Support for L3 interconnection of multiple OVN deployments with tunnels +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index b5e4d6d84..82c86f636 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -1660,6 +1660,14 @@ next; +
            +
          • + ++
          • ++ A priority-100 flow parses DHCPv6 replies from IPv6 prefix ++ delegation routers (udp.src == 547 && ++ udp.dst == 546). The handle_dhcpv6_reply ++ is used to send IPv6 prefix delegation messages to the delegation ++ router. ++
          • ++ +
          • +

            + A priority-87 flow explicitly allows IPv6 multicast traffic that is +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index bb68b8fe9..fd1be5b27 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -2688,6 +2688,33 @@ op_get_name(const struct ovn_port *op) + return name; + } + ++static void ++ovn_update_ipv6_prefix(struct hmap *ports) ++{ ++ const struct ovn_port *op; ++ HMAP_FOR_EACH (op, key_node, ports) { ++ if (!op->nbrp) { ++ continue; ++ } ++ ++ char prefix[IPV6_SCAN_LEN + 6]; ++ unsigned aid; ++ const char *ipv6_pd_list = smap_get(&op->sb->options, ++ "ipv6_ra_pd_list"); ++ if (!ipv6_pd_list || ++ !ovs_scan(ipv6_pd_list, "%u:%s", &aid, prefix)) { ++ continue; ++ } ++ ++ struct sset ipv6_prefix_set = SSET_INITIALIZER(&ipv6_prefix_set); ++ sset_add(&ipv6_prefix_set, prefix); ++ nbrec_logical_router_port_set_ipv6_prefix(op->nbrp, ++ sset_array(&ipv6_prefix_set), ++ sset_count(&ipv6_prefix_set)); ++ sset_destroy(&ipv6_prefix_set); ++ } ++} ++ + static void + ovn_port_update_sbrec(struct northd_context *ctx, + struct ovsdb_idl_index *sbrec_chassis_by_name, +@@ -2818,6 +2845,13 @@ ovn_port_update_sbrec(struct northd_context *ctx, + smap_add(&new, "l3gateway-chassis", chassis_name); + } + } ++ ++ const char *ipv6_pd_list = smap_get(&op->sb->options, ++ "ipv6_ra_pd_list"); ++ if (ipv6_pd_list) { ++ smap_add(&new, "ipv6_ra_pd_list", ipv6_pd_list); ++ } ++ + sbrec_port_binding_set_options(op->sb, &new); + smap_destroy(&new); + +@@ -4683,12 +4717,12 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows) + * unreachable packets. */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, + "nd || nd_rs || nd_ra || icmp4.type == 3 || " +- "icmp6.type == 1 || (tcp && tcp.flags == 20)", +- "next;"); ++ "icmp6.type == 1 || (tcp && tcp.flags == 20) || " ++ "(udp && udp.src == 546 && udp.dst == 547)", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, + "nd || nd_rs || nd_ra || icmp4.type == 3 || " +- "icmp6.type == 1 || (tcp && tcp.flags == 20)", +- "next;"); ++ "icmp6.type == 1 || (tcp && tcp.flags == 20) ||" ++ "(udp && udp.src == 546 && udp.dst == 547)", "next;"); + + /* Ingress and Egress Pre-ACL Table (Priority 100). + * +@@ -7744,6 +7778,11 @@ copy_ra_to_sb(struct ovn_port *op, const char *address_mode) + } + ds_put_format(&s, "%s/%u ", addrs->network_s, addrs->plen); + } ++ ++ const char *ra_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list"); ++ if (ra_pd_list) { ++ ds_put_cstr(&s, ra_pd_list); ++ } + /* Remove trailing space */ + ds_chomp(&s, ' '); + smap_add(&options, "ipv6_ra_prefixes", ds_cstr(&s)); +@@ -8488,7 +8527,34 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + free(snat_ips); + } + +- /* Logical router ingress table 3: IP Input for IPv6. */ ++ /* DHCPv6 reply handling */ ++ HMAP_FOR_EACH (op, key_node, ports) { ++ if (!op->nbrp) { ++ continue; ++ } ++ ++ if (op->derived) { ++ continue; ++ } ++ ++ struct lport_addresses lrp_networks; ++ if (!extract_lrp_networks(op->nbrp, &lrp_networks)) { ++ continue; ++ } ++ ++ for (size_t i = 0; i < lrp_networks.n_ipv6_addrs; i++) { ++ ds_clear(&actions); ++ ds_clear(&match); ++ ds_put_format(&match, "ip6.dst == %s && udp.src == 547 &&" ++ " udp.dst == 546", ++ lrp_networks.ipv6_addrs[i].addr_s); ++ ds_put_format(&actions, "reg0 = 0; handle_dhcpv6_reply;"); ++ ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, ++ ds_cstr(&match), ds_cstr(&actions)); ++ } ++ } ++ ++ /* Logical router ingress table 1: IP Input for IPv6. */ + HMAP_FOR_EACH (op, key_node, ports) { + if (!op->nbrp) { + continue; +@@ -9250,6 +9316,24 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, + continue; + } + ++ struct smap options; ++ /* enable IPv6 prefix delegation */ ++ bool prefix_delegation = smap_get_bool(&op->nbrp->options, ++ "prefix_delegation", false); ++ if (prefix_delegation) { ++ smap_clone(&options, &op->sb->options); ++ smap_add(&options, "ipv6_prefix_delegation", "true"); ++ sbrec_port_binding_set_options(op->sb, &options); ++ smap_destroy(&options); ++ } ++ ++ if (smap_get_bool(&op->nbrp->options, "prefix", false)) { ++ smap_clone(&options, &op->sb->options); ++ smap_add(&options, "ipv6_prefix", "true"); ++ sbrec_port_binding_set_options(op->sb, &options); ++ smap_destroy(&options); ++ } ++ + const char *address_mode = smap_get( + &op->nbrp->ipv6_ra_configs, "address_mode"); + +@@ -10941,6 +11025,7 @@ ovnnb_db_run(struct northd_context *ctx, + build_meter_groups(ctx, &meter_groups); + build_lflows(ctx, datapaths, ports, &port_groups, &mcast_groups, + &igmp_groups, &meter_groups, &lbs); ++ ovn_update_ipv6_prefix(ports); + + sync_address_sets(ctx); + sync_port_groups(ctx); +diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema +index ea6f4e354..949f6258b 100644 +--- a/ovn-nb.ovsschema ++++ b/ovn-nb.ovsschema +@@ -1,7 +1,7 @@ + { + "name": "OVN_Northbound", +- "version": "5.20.1", +- "cksum": "721375950 25251", ++ "version": "5.22.0", ++ "cksum": "170077561 25417", + "tables": { + "NB_Global": { + "columns": { +@@ -342,6 +342,9 @@ + "ipv6_ra_configs": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}, ++ "ipv6_prefix": {"type": {"key": "string", ++ "min": 0, ++ "max": "unlimited"}}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, +diff --git a/ovn-nb.xml b/ovn-nb.xml +index f7ba9c334..045c63fb0 100644 +--- a/ovn-nb.xml ++++ b/ovn-nb.xml +@@ -2065,6 +2065,11 @@ + port has all ingress and egress traffic dropped. + + ++ ++ This column contains IPv6 prefix obtained by prefix delegation ++ router according to RFC 3633 ++ ++ + +

            + This column defines the IPv6 ND RA address mode and ND MTU Option to be +@@ -2320,6 +2325,22 @@ + ovn-northd honors the configured value. + + ++ ++

            ++ If set to true, enable IPv6 prefix delegation state ++ machine on this logical router port (RFC3633). IPv6 prefix ++ delegation is available just on a gateway router or on a gateway ++ router port. ++

            ++ ++ ++ ++

            ++ If set to true, this interface will receive an IPv6 ++ prefix according to RFC3663 ++

            ++
            + + + +diff --git a/tests/atlocal.in b/tests/atlocal.in +index 5f14c3da0..8f3ff03b9 100644 +--- a/tests/atlocal.in ++++ b/tests/atlocal.in +@@ -157,7 +157,7 @@ find_command() + { + which $1 > /dev/null 2>&1 + status=$? +- var=HAVE_`echo "$1" | tr '[a-z]' '[A-Z]'` ++ var=HAVE_`echo "$1" | tr '-' '_' | tr '[a-z]' '[A-Z]'` + if test "$status" = "0"; then + eval ${var}="yes" + else +@@ -192,6 +192,9 @@ else + DIFF_SUPPORTS_NORMAL_FORMAT=no + fi + ++# Set HAVE_DIBBLER-SERVER ++find_command dibbler-server ++ + # Turn off proxies. + unset http_proxy + unset https_proxy +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index f1ae69b20..000b3f13b 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -3793,3 +3793,146 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d + /connection dropped.*/d"]) + + AT_CLEANUP ++ ++AT_SETUP([ovn -- IPv6 prefix delegation]) ++AT_SKIP_IF([test $HAVE_DIBBLER_SERVER = no]) ++AT_SKIP_IF([test $HAVE_TCPDUMP = no]) ++AT_KEYWORDS([ovn-ipv6-prefix_d]) ++ ++ovn_start ++OVS_TRAFFIC_VSWITCHD_START() ++ ++ADD_BR([br-int]) ++ADD_BR([br-ext]) ++ ++ovs-ofctl add-flow br-ext action=normal ++# Set external-ids in br-int needed for ovn-controller ++ovs-vsctl \ ++ -- set Open_vSwitch . external-ids:system-id=hv1 \ ++ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ ++ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ ++ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ ++ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true ++ ++# Start ovn-controller ++start_daemon ovn-controller ++ ++ovn-nbctl lr-add R1 ++ ++ovn-nbctl ls-add sw0 ++ovn-nbctl ls-add sw1 ++ovn-nbctl ls-add public ++ ++ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24 ++ovn-nbctl lrp-add R1 rp-sw1 00:00:03:01:02:03 192.168.2.1/24 ++ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 \ ++ -- set Logical_Router_Port rp-public options:redirect-chassis=hv1 ++ ++ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ ++ type=router options:router-port=rp-sw0 \ ++ -- lsp-set-addresses sw0-rp router ++ovn-nbctl lsp-add sw1 sw1-rp -- set Logical_Switch_Port sw1-rp \ ++ type=router options:router-port=rp-sw1 \ ++ -- lsp-set-addresses sw1-rp router ++ ++ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \ ++ type=router options:router-port=rp-public \ ++ -- lsp-set-addresses public-rp router ++ ++ADD_NAMESPACES(sw01) ++ADD_VETH(sw01, sw01, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \ ++ "192.168.1.1") ++ovn-nbctl lsp-add sw0 sw01 \ ++ -- lsp-set-addresses sw01 "f0:00:00:01:02:03 192.168.1.2" ++ ++ADD_NAMESPACES(sw11) ++ADD_VETH(sw11, sw11, br-int, "192.168.2.2/24", "f0:00:00:02:02:03", \ ++ "192.168.2.1") ++ovn-nbctl lsp-add sw1 sw11 \ ++ -- lsp-set-addresses sw11 "f0:00:00:02:02:03 192.168.2.2" ++ ++ADD_NAMESPACES(server) ++ADD_VETH(s1, server, br-ext, "2001:1db8:3333::2/64", "f0:00:00:01:02:05", \ ++ "2001:1db8:3333::1") ++ ++OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep 2001:1db8:3333::2 | grep tentative)" = ""]) ++OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep fe80 | grep tentative)" = ""]) ++ ++AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext]) ++ovn-nbctl lsp-add public public1 \ ++ -- lsp-set-addresses public1 unknown \ ++ -- lsp-set-type public1 localnet \ ++ -- lsp-set-options public1 network_name=phynet ++ ++ovn-nbctl set logical_router_port rp-public options:prefix_delegation=true ++ovn-nbctl set logical_router_port rp-public options:prefix=true ++ovn-nbctl set logical_router_port rp-sw0 options:prefix=true ++ovn-nbctl set logical_router_port rp-sw1 options:prefix=true ++ ++# reset dibbler state ++sed s/^iface.*/"iface \"s1\" {"/g -i /etc/dibbler/server.conf ++sed s/pd-pool.*/"pd-pool 2001:1db8:3333::\/80"/g -i /etc/dibbler/server.conf ++sed s/t1.*/"t1 10"/g -i /etc/dibbler/server.conf ++sed s/t2.*/"t2 15"/g -i /etc/dibbler/server.conf ++cat > /var/lib/dibbler/server-AddrMgr.xml < ++ 1575481348 ++ 0 ++ ++EOF ++cat > /var/lib/dibbler/server-CfgMgr.xml < ++ /var/lib/dibbler ++ Server ++ 8 ++ 0 ++ 0 ++ ++EOF ++ ++NS_CHECK_EXEC([server], [dibbler-server run > dibbler.log &]) ++ovn-nbctl --wait=hv sync ++ ++OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-public ipv6_prefix | cut -c4-15)" = ""]) ++OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c4-15)" = ""]) ++OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw1 ipv6_prefix | cut -c4-15)" = ""]) ++ ++AT_CHECK([ovn-nbctl get logical_router_port rp-public ipv6_prefix | cut -c3-16], [0], [dnl ++[2001:1db8:3333] ++]) ++AT_CHECK([ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16], [0], [dnl ++[2001:1db8:3333] ++]) ++AT_CHECK([ovn-nbctl get logical_router_port rp-sw1 ipv6_prefix | cut -c3-16], [0], [dnl ++[2001:1db8:3333] ++]) ++ ++kill $(pidof dibbler-server) ++ ++prefix=$(ovn-nbctl list logical_router_port rp-public | awk -F/ '/ipv6_prefix/{print substr($1,25,9)}' | sed 's/://g') ++ovn-nbctl set logical_router_port rp-sw0 options:prefix=false ++ovn-nbctl set logical_router_port rp-sw1 options:prefix=false ++ ++NS_CHECK_EXEC([server], [tcpdump -c 1 -nni s1 ip6[[95:4]]=0x${prefix} > public.pcap &]) ++ ++OVS_WAIT_UNTIL([ ++ total_pkts=$(cat public.pcap | wc -l) ++ test "${total_pkts}" = "1" ++]) ++ ++kill $(pidof tcpdump) ++kill $(pidof ovn-controller) ++ ++as ovn-sb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as ovn-nb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as northd ++OVS_APP_EXIT_AND_WAIT([ovn-northd]) ++ ++as ++OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d ++/.*terminating with signal 15.*/d"]) ++AT_CLEANUP +-- +2.25.2 + diff --git a/SOURCES/0003-ovsdb-idl-Try-committing-the-pending-txn-in-ovsdb_id.patch b/SOURCES/0003-ovsdb-idl-Try-committing-the-pending-txn-in-ovsdb_id.patch new file mode 100644 index 0000000..64e808e --- /dev/null +++ b/SOURCES/0003-ovsdb-idl-Try-committing-the-pending-txn-in-ovsdb_id.patch @@ -0,0 +1,217 @@ +From 22a9d1b20218d2467f30c9a87205344ff787bcf8 Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Fri, 5 Jun 2020 14:00:29 +0530 +Subject: [PATCH 3/3] ovsdb idl: Try committing the pending txn in + ovsdb_idl_loop_run. + +The function ovsdb_idl_loop_run(), after calling ovsdb_idl_run(), +returns a transaction object (of type 'struct ovsdb_idl_txn'). +The returned transaction object can be NULL if there is a pending +transaction (loop->committing_txn) in the idl loop object. + +Normally the clients of idl library, first call ovsdb_idl_loop_run(), +then do their own processing and create any idl transactions during +this processing and then finally call ovsdb_idl_loop_commit_and_wait(). + +If ovsdb_idl_loop_run() returns NULL transaction object, then much +of the processing done by the client gets wasted as in the case +of ovn-controller. + +The client (in this case ovn-controller), can skip the processing +and instead call ovsdb_idl_loop_commit_and_wait() if the transaction +oject is NULL. But ovn-controller uses IDL tracking and it may +loose the tracked changes in that run. + +This patch tries to improve this scenario, by checking if the +pending transaction can be committed in the ovsdb_idl_loop_run() +itself and if the pending transaction is cleared (because of the +response messages from ovsdb-server due to a transaction message +in the previous run), ovsdb_idl_loop_run() can return a valid +transaction object. + +CC: Han Zhou +Signed-off-by: Numan Siddique +Signed-off-by: Ben Pfaff +--- + openvswitch-2.13.0/lib/ovsdb-idl.c | 143 +++++++++++++++++++---------- + 1 file changed, 93 insertions(+), 50 deletions(-) + +diff --git a/openvswitch-2.13.0/lib/ovsdb-idl.c b/openvswitch-2.13.0/lib/ovsdb-idl.c +index 1535ad7b5..2d351791f 100644 +--- a/openvswitch-2.13.0/lib/ovsdb-idl.c ++++ b/openvswitch-2.13.0/lib/ovsdb-idl.c +@@ -385,6 +385,8 @@ static void ovsdb_idl_send_cond_change(struct ovsdb_idl *idl); + static void ovsdb_idl_destroy_indexes(struct ovsdb_idl_table *); + static void ovsdb_idl_add_to_indexes(const struct ovsdb_idl_row *); + static void ovsdb_idl_remove_from_indexes(const struct ovsdb_idl_row *); ++static int ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop, ++ bool *may_need_wakeup); + + static void + ovsdb_idl_db_init(struct ovsdb_idl_db *db, const struct ovsdb_idl_class *class, +@@ -5329,6 +5331,12 @@ struct ovsdb_idl_txn * + ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop) + { + ovsdb_idl_run(loop->idl); ++ ++ /* See if we can commit the loop->committing_txn. */ ++ if (loop->committing_txn) { ++ ovsdb_idl_try_commit_loop_txn(loop, NULL); ++ } ++ + loop->open_txn = (loop->committing_txn + || ovsdb_idl_get_seqno(loop->idl) == loop->skip_seqno + ? NULL +@@ -5336,6 +5344,87 @@ ovsdb_idl_loop_run(struct ovsdb_idl_loop *loop) + return loop->open_txn; + } + ++/* Attempts to commit the current transaction, if one is open. ++ * ++ * If a transaction was open, in this or a previous iteration of the main loop, ++ * and had not before finished committing (successfully or unsuccessfully), the ++ * return value is one of: ++ * ++ * 1: The transaction committed successfully (or it did not change anything in ++ * the database). ++ * 0: The transaction failed. ++ * -1: The commit is still in progress. ++ * ++ * Thus, the return value is -1 if the transaction is in progress and otherwise ++ * true for success, false for failure. ++ * ++ * (In the corner case where the IDL sends a transaction to the database and ++ * the database commits it, and the connection between the IDL and the database ++ * drops before the IDL receives the message confirming the commit, this ++ * function can return 0 even though the transaction succeeded.) ++ */ ++static int ++ovsdb_idl_try_commit_loop_txn(struct ovsdb_idl_loop *loop, ++ bool *may_need_wakeup) ++{ ++ if (!loop->committing_txn) { ++ /* Not a meaningful return value: no transaction was in progress. */ ++ return 1; ++ } ++ ++ int retval; ++ struct ovsdb_idl_txn *txn = loop->committing_txn; ++ ++ enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn); ++ if (status != TXN_INCOMPLETE) { ++ switch (status) { ++ case TXN_TRY_AGAIN: ++ /* We want to re-evaluate the database when it's changed from ++ * the contents that it had when we started the commit. (That ++ * might have already happened.) */ ++ loop->skip_seqno = loop->precommit_seqno; ++ if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno ++ && may_need_wakeup) { ++ *may_need_wakeup = true; ++ } ++ retval = 0; ++ break; ++ ++ case TXN_SUCCESS: ++ /* Possibly some work on the database was deferred because no ++ * further transaction could proceed. Wake up again. */ ++ retval = 1; ++ loop->cur_cfg = loop->next_cfg; ++ if (may_need_wakeup) { ++ *may_need_wakeup = true; ++ } ++ break; ++ ++ case TXN_UNCHANGED: ++ retval = 1; ++ loop->cur_cfg = loop->next_cfg; ++ break; ++ ++ case TXN_ABORTED: ++ case TXN_NOT_LOCKED: ++ case TXN_ERROR: ++ retval = 0; ++ break; ++ ++ case TXN_UNCOMMITTED: ++ case TXN_INCOMPLETE: ++ default: ++ OVS_NOT_REACHED(); ++ } ++ ovsdb_idl_txn_destroy(txn); ++ loop->committing_txn = NULL; ++ } else { ++ retval = -1; ++ } ++ ++ return retval; ++} ++ + /* Attempts to commit the current transaction, if one is open, and sets up the + * poll loop to wake up when some more work might be needed. + * +@@ -5366,57 +5455,11 @@ ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *loop) + loop->precommit_seqno = ovsdb_idl_get_seqno(loop->idl); + } + +- struct ovsdb_idl_txn *txn = loop->committing_txn; +- int retval; +- if (txn) { +- enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn); +- if (status != TXN_INCOMPLETE) { +- switch (status) { +- case TXN_TRY_AGAIN: +- /* We want to re-evaluate the database when it's changed from +- * the contents that it had when we started the commit. (That +- * might have already happened.) */ +- loop->skip_seqno = loop->precommit_seqno; +- if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) { +- poll_immediate_wake(); +- } +- retval = 0; +- break; +- +- case TXN_SUCCESS: +- /* Possibly some work on the database was deferred because no +- * further transaction could proceed. Wake up again. */ +- retval = 1; +- loop->cur_cfg = loop->next_cfg; +- poll_immediate_wake(); +- break; +- +- case TXN_UNCHANGED: +- retval = 1; +- loop->cur_cfg = loop->next_cfg; +- break; +- +- case TXN_ABORTED: +- case TXN_NOT_LOCKED: +- case TXN_ERROR: +- retval = 0; +- break; +- +- case TXN_UNCOMMITTED: +- case TXN_INCOMPLETE: +- default: +- OVS_NOT_REACHED(); +- } +- ovsdb_idl_txn_destroy(txn); +- loop->committing_txn = NULL; +- } else { +- retval = -1; +- } +- } else { +- /* Not a meaningful return value: no transaction was in progress. */ +- retval = 1; ++ bool may_need_wakeup = false; ++ int retval = ovsdb_idl_try_commit_loop_txn(loop, &may_need_wakeup); ++ if (may_need_wakeup) { ++ poll_immediate_wake(); + } +- + ovsdb_idl_wait(loop->idl); + + return retval; +-- +2.26.2 + diff --git a/SOURCES/0004-northd-manage-ARP-request-locally-for-FIP-traffic.patch b/SOURCES/0004-northd-manage-ARP-request-locally-for-FIP-traffic.patch new file mode 100644 index 0000000..de2a192 --- /dev/null +++ b/SOURCES/0004-northd-manage-ARP-request-locally-for-FIP-traffic.patch @@ -0,0 +1,187 @@ +From 92f6a2f668708c677a8b10b0ac861bfd712f6a20 Mon Sep 17 00:00:00 2001 +Message-Id: <92f6a2f668708c677a8b10b0ac861bfd712f6a20.1590585469.git.lorenzo.bianconi@redhat.com> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Mon, 25 May 2020 18:31:27 +0200 +Subject: [PATCH ovn 3/3] northd: manage ARP request locally for FIP traffic + +Modify 100-priority logical flows in Gateway Redirect table of +logical router ingress pipeline (table 15) in order to manage ARP +request locally for FIP traffic. In particular set reg1 and eth.src +to NAT external ip and NAT external mac respectively and do not +distribute ARP traffic using FIP + +Signed-off-by: Lorenzo Bianconi +--- + northd/ovn-northd.8.xml | 10 +++++++--- + northd/ovn-northd.c | 23 ++++++++++++++++------- + tests/ovn.at | 28 +++++++++++++++++++++++++--- + tests/system-ovn.at | 30 ++++++++++++++++++++++++++++++ + 4 files changed, 78 insertions(+), 13 deletions(-) + +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -2879,9 +2879,13 @@ icmp4 { + For each NAT rule in the OVN Northbound database that can + be handled in a distributed manner, a priority-100 logical + flow with match ip4.src == B && +- outport == GW, where GW is +- the logical router distributed gateway port, with actions +- next;. ++ outport == GW && ++ is_chassis_resident(P), where GW is ++ the logical router distributed gateway port and P ++ is the NAT logical port. IP traffic matching the above rule ++ will be managed locally setting reg1 to C ++ and eth.src to D, where C is NAT ++ external ip and D is NAT external mac. +
          • + +
          • +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -9137,16 +9137,25 @@ build_lrouter_flows(struct hmap *datapat + /* Ingress Gateway Redirect Table: For NAT on a distributed + * router, add flows that are specific to a NAT rule. These + * flows indicate the presence of an applicable NAT rule that +- * can be applied in a distributed manner. */ ++ * can be applied in a distributed manner. ++ * In particulr reg1 and eth.src are set to NAT external IP and ++ * NAT external mac so the ARP request generated in the following ++ * stage is sent out with proper IP/MAC src addresses ++ */ + if (distributed) { + ds_clear(&match); +- ds_put_format(&match, "ip%s.src == %s && outport == %s", +- is_v6 ? "6" : "4", +- nat->logical_ip, +- od->l3dgw_port->json_key); ++ ds_clear(&actions); ++ ds_put_format(&match, ++ "ip%s.src == %s && outport == %s && " ++ "is_chassis_resident(\"%s\")", ++ is_v6 ? "6" : "4", nat->logical_ip, ++ od->l3dgw_port->json_key, nat->logical_port); ++ ds_put_format(&actions, "eth.src = %s; %sreg1 = %s; next;", ++ nat->external_mac, is_v6 ? "xx" : "", ++ nat->external_ip); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, +- 100, ds_cstr(&match), "next;", +- &nat->header_); ++ 100, ds_cstr(&match), ++ ds_cstr(&actions), &nat->header_); + } + + /* Egress Loopback table: For NAT on a distributed router. +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -14353,9 +14353,14 @@ ovs-vsctl -- add-port br-int hv2-vif1 -- + set interface hv2-vif1 external-ids:iface-id=sw1-p0 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ +- ofport-request=1 ++ ofport-request=2 ++ovs-vsctl -- add-port br-int hv2-vif2 -- \ ++ set interface hv2-vif2 external-ids:iface-id=sw0-p1 \ ++ options:tx_pcap=hv2/vif2-tx.pcap \ ++ options:rxq_pcap=hv2/vif2-rx.pcap \ ++ ofport-request=3 + +-ovn-nbctl create Logical_Router name=lr0 options:chassis=hv1 ++ovn-nbctl create Logical_Router name=lr0 + ovn-nbctl ls-add sw0 + ovn-nbctl ls-add sw1 + +@@ -14364,13 +14369,16 @@ ovn-nbctl lsp-add sw0 rp-sw0 -- set Logi + type=router options:router-port=sw0 \ + -- lsp-set-addresses rp-sw0 router + +-ovn-nbctl lrp-add lr0 sw1 00:00:02:01:02:03 172.16.1.1/24 2002:0:0:0:0:0:0:1/64 ++ovn-nbctl lrp-add lr0 sw1 00:00:02:01:02:03 172.16.1.1/24 2002:0:0:0:0:0:0:1/64 \ ++ -- set Logical_Router_Port sw1 options:redirect-chassis="hv2" + ovn-nbctl lsp-add sw1 rp-sw1 -- set Logical_Switch_Port rp-sw1 \ + type=router options:router-port=sw1 \ + -- lsp-set-addresses rp-sw1 router + + ovn-nbctl lsp-add sw0 sw0-p0 \ + -- lsp-set-addresses sw0-p0 "f0:00:00:01:02:03 192.168.1.2 2001::2" ++ovn-nbctl lsp-add sw0 sw0-p1 \ ++ -- lsp-set-addresses sw0-p1 "f0:00:00:11:02:03 192.168.1.3 2001::3" + + ovn-nbctl lsp-add sw1 sw1-p0 \ + -- lsp-set-addresses sw1-p0 unknown +@@ -14416,6 +14424,20 @@ send_na 2 1 $dst_mac $router_mac1 $dst_i + + OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + ++# Create FIP on sw0-p0, add a route on logical router pipeline and ++# ARP request for a unkwon destination is sent using FIP MAC/IP ++ovn-nbctl lr-nat-add lr0 dnat_and_snat 172.16.1.2 192.168.1.3 sw0-p1 f0:00:00:01:02:04 ++ovn-nbctl lr-route-add lr0 172.16.2.0/24 172.16.1.11 ++ ++dst_ip=$(ip_to_hex 172 16 2 10) ++fip_ip=$(ip_to_hex 172 16 1 2) ++src_ip=$(ip_to_hex 192 168 1 3) ++gw_router=$(ip_to_hex 172 16 1 11) ++send_icmp_packet 2 2 f00000110203 $router_mac0 $src_ip $dst_ip 0000 $data ++echo $(get_arp_req f00000010204 $fip_ip $gw_router) >> expected ++ ++OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) ++ + OVN_CLEANUP([hv1],[hv2]) + AT_CLEANUP + +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -2747,6 +2747,19 @@ ADD_VETH(alice1, alice1, br-int, "172.16 + ovn-nbctl lsp-add alice alice1 \ + -- lsp-set-addresses alice1 "f0:00:00:01:02:05 172.16.1.2" + ++# Add external network ++ADD_NAMESPACES(ext-net) ++AT_CHECK([ip link add alice-ext netns alice1 type veth peer name ext-veth netns ext-net]) ++NS_CHECK_EXEC([ext-net], [ip link set dev ext-veth up], [0], []) ++NS_CHECK_EXEC([ext-net], [ip addr add 10.0.0.1/24 dev ext-veth], [0], []) ++NS_CHECK_EXEC([ext-net], [ip route add default via 10.0.0.2], [0], []) ++ ++NS_CHECK_EXEC([alice1], [ip link set dev alice-ext up], [0], []) ++NS_CHECK_EXEC([alice1], [ip addr add 10.0.0.2/24 dev alice-ext], [0], []) ++NS_CHECK_EXEC([alice1], [sysctl -w net.ipv4.conf.all.forwarding=1],[0], [dnl ++net.ipv4.conf.all.forwarding = 1 ++]) ++ + # Add DNAT rules + AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.3 192.168.1.2 foo1 00:00:02:02:03:04]) + AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.4 192.168.1.3 foo2 00:00:02:02:03:05]) +@@ -2754,6 +2767,9 @@ AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_a + # Add a SNAT rule + AT_CHECK([ovn-nbctl lr-nat-add R1 snat 172.16.1.1 192.168.0.0/16]) + ++# Add default route to ext-net ++AT_CHECK([ovn-nbctl lr-route-add R1 10.0.0.0/24 172.16.1.2]) ++ + ovn-nbctl --wait=hv sync + OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=172.16.1.1)']) + +@@ -2797,6 +2813,20 @@ sed -e 's/zone=[[0-9]]*/zone=/' + icmp,orig=(src=192.168.2.2,dst=172.16.1.2,id=,type=8,code=0),reply=(src=172.16.1.2,dst=172.16.1.1,id=,type=0,code=0),zone= + ]) + ++# Try to ping external network ++NS_CHECK_EXEC([ext-net], [tcpdump -n -c 3 -i ext-veth dst 172.16.1.3 and icmp > ext-net.pcap &]) ++sleep 1 ++AT_CHECK([ovn-nbctl lr-nat-del R1 snat]) ++NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.1 | FORMAT_PING], \ ++[0], [dnl ++3 packets transmitted, 3 received, 0% packet loss, time 0ms ++]) ++ ++OVS_WAIT_UNTIL([ ++ total_pkts=$(cat ext-net.pcap | wc -l) ++ test "${total_pkts}" = "3" ++]) ++ + OVS_APP_EXIT_AND_WAIT([ovn-controller]) + + as ovn-sb diff --git a/SOURCES/0004-tests-Fix-occasional-failures-for-test-85.patch b/SOURCES/0004-tests-Fix-occasional-failures-for-test-85.patch new file mode 100644 index 0000000..eaaf3c0 --- /dev/null +++ b/SOURCES/0004-tests-Fix-occasional-failures-for-test-85.patch @@ -0,0 +1,69 @@ +From 9735eeff2b736145fe7ab444eb77686a595a9c8e Mon Sep 17 00:00:00 2001 +From: Numan Siddique +Date: Fri, 17 Apr 2020 20:09:24 +0530 +Subject: [PATCH 4/4] tests: Fix occasional failures for test 85. + +The test case "85: ovn -- send gratuitous ARP for NAT rules on HA distributed router" +fails occaionally. On faster systems, chances of failure are higher. + +This patch fixes this. + +Tested-by: Flavio Fernandes +Signed-off-by: Numan Siddique +--- + tests/ovn.at | 21 +++++++++++++++++++-- + 1 file changed, 19 insertions(+), 2 deletions(-) + +diff --git a/tests/ovn.at b/tests/ovn.at +index ae3b44cb3..91d0a8fec 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -11062,6 +11062,12 @@ only_broadcast_from_lrp1() { + garp="fffffffffffff0000000000108060001080006040001f00000000001c0a80064000000000000c0a80064" + echo $garp > expout + ++OVS_WAIT_UNTIL( ++ [$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap > rcv_text ++ exp_rcvd=$(cat rcv_text | grep $garp | wc -l) ++ echo "expected received = $exp_rcvd" ++ test $exp_rcvd -ge 1]) ++ + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv1_snoop_tx + echo "packets on hv1-snoopvif:" + cat hv1_snoop_tx +@@ -11090,12 +11096,17 @@ as hv1 reset_pcap_file snoopvif hv1/snoopvif + as hv2 reset_pcap_file br-phys_n1 hv2/br-phys_n1 + as hv3 reset_pcap_file br-phys_n1 hv3/br-phys_n1 + +-# Wait for packets to be received. +-OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 100]) + trim_zeros() { + sed 's/\(00\)\{1,\}$//' + } + ++# Wait for packets to be received. ++OVS_WAIT_UNTIL( ++ [$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap > rcv_text ++ exp_rcvd=$(cat rcv_text | grep $garp | wc -l) ++ echo "expected received = $exp_rcvd" ++ test $exp_rcvd -ge 1]) ++ + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv1_snoopvif_tx + AT_CHECK([sort hv1_snoopvif_tx], [0], [expout]) + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/br-phys_n1-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv3_br_phys_tx +@@ -11141,6 +11152,12 @@ trim_zeros() { + garp="fffffffffffff00000000001810007de08060001080006040001f00000000001c0a80064000000000000c0a80064" + echo $garp > expout + ++OVS_WAIT_UNTIL( ++ [$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap > rcv_text ++ exp_rcvd=$(cat rcv_text | grep $garp | wc -l) ++ echo "expected received = $exp_rcvd" ++ test $exp_rcvd -ge 1]) ++ + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv1_snoopvif_tx + AT_CHECK([sort hv1_snoopvif_tx], [0], [expout]) + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/br-phys_n1-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv3_br_phys_tx +-- +2.26.2 + diff --git a/SOURCES/arm64-armv8a-linuxapp-gcc-config b/SOURCES/arm64-armv8a-linuxapp-gcc-config new file mode 100644 index 0000000..5813d7a --- /dev/null +++ b/SOURCES/arm64-armv8a-linuxapp-gcc-config @@ -0,0 +1,540 @@ +# -*- cfg-sha: 9fc8b53ccd53cc8b64391f6252e1dba558ae660a73a72f10dcadff2ca5462243 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2015 Cavium, Inc +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2017 Cavium, Inc +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2016 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2017 Intel Corporation +# RTE_EXEC_ENV values are the directories in mk/exec-env/ +CONFIG_RTE_EXEC_ENV="linuxapp" +# RTE_ARCH values are architecture we compile for. directories in mk/arch/ +CONFIG_RTE_ARCH="arm64" +# machine can define specific variables or action for a specific board +# RTE_MACHINE values are architecture we compile for. directories in mk/machine/ +CONFIG_RTE_MACHINE="armv8a" +# The compiler we use. +# RTE_TOOLCHAIN values are architecture we compile for. directories in mk/toolchain/ +CONFIG_RTE_TOOLCHAIN="gcc" +# Use intrinsics or assembly code for key routines +CONFIG_RTE_FORCE_INTRINSICS=y +# Machine forces strict alignment constraints. +CONFIG_RTE_ARCH_STRICT_ALIGN=n +# Compile to share library +CONFIG_RTE_BUILD_SHARED_LIB=n +# Use newest code breaking previous ABI +CONFIG_RTE_NEXT_ABI=n +# Major ABI to overwrite library specific LIBABIVER +CONFIG_RTE_MAJOR_ABI= +# Machine's cache line size +CONFIG_RTE_CACHE_LINE_SIZE=128 +# Memory model +CONFIG_RTE_USE_C11_MEM_MODEL=y +# Compile Environment Abstraction Layer +CONFIG_RTE_LIBRTE_EAL=y +CONFIG_RTE_MAX_LCORE=256 +CONFIG_RTE_MAX_NUMA_NODES=8 +CONFIG_RTE_MAX_HEAPS=32 +CONFIG_RTE_MAX_MEMSEG_LISTS=64 +# each memseg list will be limited to either RTE_MAX_MEMSEG_PER_LIST pages +# or RTE_MAX_MEM_MB_PER_LIST megabytes worth of memory, whichever is smaller +CONFIG_RTE_MAX_MEMSEG_PER_LIST=8192 +CONFIG_RTE_MAX_MEM_MB_PER_LIST=32768 +# a "type" is a combination of page size and NUMA node. total number of memseg +# lists per type will be limited to either RTE_MAX_MEMSEG_PER_TYPE pages (split +# over multiple lists of RTE_MAX_MEMSEG_PER_LIST pages), or +# RTE_MAX_MEM_MB_PER_TYPE megabytes of memory (split over multiple lists of +# RTE_MAX_MEM_MB_PER_LIST), whichever is smaller +CONFIG_RTE_MAX_MEMSEG_PER_TYPE=32768 +CONFIG_RTE_MAX_MEM_MB_PER_TYPE=131072 +# global maximum usable amount of VA, in megabytes +CONFIG_RTE_MAX_MEM_MB=524288 +CONFIG_RTE_MAX_MEMZONE=2560 +CONFIG_RTE_MAX_TAILQ=32 +CONFIG_RTE_ENABLE_ASSERT=n +CONFIG_RTE_LOG_DP_LEVEL=RTE_LOG_INFO +CONFIG_RTE_LOG_HISTORY=256 +CONFIG_RTE_BACKTRACE=y +CONFIG_RTE_LIBEAL_USE_HPET=n +CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID=n +CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n +CONFIG_RTE_EAL_IGB_UIO=n +CONFIG_RTE_EAL_VFIO=y +CONFIG_RTE_MAX_VFIO_GROUPS=64 +CONFIG_RTE_MAX_VFIO_CONTAINERS=64 +CONFIG_RTE_MALLOC_DEBUG=n +CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=y +CONFIG_RTE_USE_LIBBSD=n +# Recognize/ignore architecture we compile for. AVX/AVX512 CPU flags for performance/power testing. +# AVX512 is marked as experimental for now, will enable it after enough +# field test and possible optimization. +CONFIG_RTE_ENABLE_AVX=y +CONFIG_RTE_ENABLE_AVX512=n +# Default driver path (or "" to disable) +CONFIG_RTE_EAL_PMD_PATH="" +# Compile Environment Abstraction Layer to support Vmware TSC map +CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y +# Compile architecture we compile for. PCI library +CONFIG_RTE_LIBRTE_PCI=y +# Compile architecture we compile for. argument parser library +CONFIG_RTE_LIBRTE_KVARGS=y +# Compile generic ethernet library +CONFIG_RTE_LIBRTE_ETHER=y +CONFIG_RTE_LIBRTE_ETHDEV_DEBUG=n +CONFIG_RTE_MAX_ETHPORTS=32 +CONFIG_RTE_MAX_QUEUES_PER_PORT=1024 +CONFIG_RTE_LIBRTE_IEEE1588=n +CONFIG_RTE_ETHDEV_QUEUE_STAT_CNTRS=16 +CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y +CONFIG_RTE_ETHDEV_PROFILE_WITH_VTUNE=n +# Turn off Tx preparation stage +# Warning: rte_eth_tx_prepare() can be safely disabled only if using a +# driver which do not implement any Tx preparation. +CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n +# Common libraries, before Bus/PMDs +CONFIG_RTE_LIBRTE_COMMON_DPAAX=n +# Compile architecture we compile for. Intel FPGA bus +CONFIG_RTE_LIBRTE_IFPGA_BUS=n +# Compile PCI bus driver +CONFIG_RTE_LIBRTE_PCI_BUS=y +# Compile architecture we compile for. vdev bus +CONFIG_RTE_LIBRTE_VDEV_BUS=y +# Compile ARK PMD +CONFIG_RTE_LIBRTE_ARK_PMD=n +CONFIG_RTE_LIBRTE_ARK_PAD_TX=y +CONFIG_RTE_LIBRTE_ARK_DEBUG_RX=n +CONFIG_RTE_LIBRTE_ARK_DEBUG_TX=n +CONFIG_RTE_LIBRTE_ARK_DEBUG_STATS=n +CONFIG_RTE_LIBRTE_ARK_DEBUG_TRACE=n +# Compile Aquantia Atlantic PMD driver +CONFIG_RTE_LIBRTE_ATLANTIC_PMD=n +# Compile AMD PMD +CONFIG_RTE_LIBRTE_AXGBE_PMD=n +CONFIG_RTE_LIBRTE_AXGBE_PMD_DEBUG=n +# Compile burst-oriented Broadcom PMD driver +CONFIG_RTE_LIBRTE_BNX2X_PMD=n +CONFIG_RTE_LIBRTE_BNX2X_DEBUG_RX=n +CONFIG_RTE_LIBRTE_BNX2X_DEBUG_TX=n +CONFIG_RTE_LIBRTE_BNX2X_MF_SUPPORT=n +CONFIG_RTE_LIBRTE_BNX2X_DEBUG_PERIODIC=n +# Compile burst-oriented Broadcom BNXT PMD driver +CONFIG_RTE_LIBRTE_BNXT_PMD=n +# Compile burst-oriented Chelsio Terminator (CXGBE) PMD +CONFIG_RTE_LIBRTE_CXGBE_PMD=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_REG=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_MBOX=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_TX=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_RX=n +CONFIG_RTE_LIBRTE_CXGBE_TPUT=y +# NXP DPAA Bus +CONFIG_RTE_LIBRTE_DPAA_BUS=n +CONFIG_RTE_LIBRTE_DPAA_MEMPOOL=n +CONFIG_RTE_LIBRTE_DPAA_PMD=n +CONFIG_RTE_LIBRTE_DPAA_HWDEBUG=n +# Compile NXP DPAA2 FSL-MC Bus +CONFIG_RTE_LIBRTE_FSLMC_BUS=n +# Compile Support Libraries for NXP DPAA2 +CONFIG_RTE_LIBRTE_DPAA2_MEMPOOL=n +CONFIG_RTE_LIBRTE_DPAA2_USE_PHYS_IOVA=y +# Compile burst-oriented NXP DPAA2 PMD driver +CONFIG_RTE_LIBRTE_DPAA2_PMD=n +CONFIG_RTE_LIBRTE_DPAA2_DEBUG_DRIVER=n +# Compile NXP ENETC PMD Driver +CONFIG_RTE_LIBRTE_ENETC_PMD=n +# Compile burst-oriented Amazon ENA PMD driver +CONFIG_RTE_LIBRTE_ENA_PMD=n +CONFIG_RTE_LIBRTE_ENA_DEBUG_RX=n +CONFIG_RTE_LIBRTE_ENA_DEBUG_TX=n +CONFIG_RTE_LIBRTE_ENA_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_ENA_COM_DEBUG=n +# Compile burst-oriented Cisco ENIC PMD driver +CONFIG_RTE_LIBRTE_ENIC_PMD=n +# Compile burst-oriented IGB & EM PMD drivers +CONFIG_RTE_LIBRTE_EM_PMD=n +CONFIG_RTE_LIBRTE_IGB_PMD=y +CONFIG_RTE_LIBRTE_E1000_DEBUG_RX=n +CONFIG_RTE_LIBRTE_E1000_DEBUG_TX=n +CONFIG_RTE_LIBRTE_E1000_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC=n +# Compile burst-oriented IXGBE PMD driver +CONFIG_RTE_LIBRTE_IXGBE_PMD=y +CONFIG_RTE_LIBRTE_IXGBE_DEBUG_RX=n +CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX=n +CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_IXGBE_PF_DISABLE_STRIP_CRC=n +CONFIG_RTE_IXGBE_INC_VECTOR=y +CONFIG_RTE_LIBRTE_IXGBE_BYPASS=n +# Compile burst-oriented I40E PMD driver +CONFIG_RTE_LIBRTE_I40E_PMD=y +CONFIG_RTE_LIBRTE_I40E_DEBUG_RX=n +CONFIG_RTE_LIBRTE_I40E_DEBUG_TX=n +CONFIG_RTE_LIBRTE_I40E_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC=y +CONFIG_RTE_LIBRTE_I40E_INC_VECTOR=y +CONFIG_RTE_LIBRTE_I40E_16BYTE_RX_DESC=n +CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_PF=64 +CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM=4 +# Compile burst-oriented FM10K PMD +CONFIG_RTE_LIBRTE_FM10K_PMD=n +CONFIG_RTE_LIBRTE_FM10K_DEBUG_RX=n +CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX=n +CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE=y +CONFIG_RTE_LIBRTE_FM10K_INC_VECTOR=y +# Compile burst-oriented AVF PMD driver +CONFIG_RTE_LIBRTE_AVF_PMD=n +CONFIG_RTE_LIBRTE_AVF_INC_VECTOR=y +CONFIG_RTE_LIBRTE_AVF_DEBUG_TX=n +CONFIG_RTE_LIBRTE_AVF_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_AVF_DEBUG_RX=n +CONFIG_RTE_LIBRTE_AVF_16BYTE_RX_DESC=n +# Compile burst-oriented Mellanox ConnectX-3 (MLX4) PMD +CONFIG_RTE_LIBRTE_MLX4_PMD=n +CONFIG_RTE_LIBRTE_MLX4_DEBUG=n +CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS=n +# Compile burst-oriented Mellanox ConnectX-4, ConnectX-5 & Bluefield +# (MLX5) PMD +CONFIG_RTE_LIBRTE_MLX5_PMD=n +CONFIG_RTE_LIBRTE_MLX5_DEBUG=n +CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS=n +# Compile burst-oriented Netronome NFP PMD driver +CONFIG_RTE_LIBRTE_NFP_PMD=n +CONFIG_RTE_LIBRTE_NFP_DEBUG_TX=n +CONFIG_RTE_LIBRTE_NFP_DEBUG_RX=n +# QLogic 10G/25G/40G/50G/100G PMD +CONFIG_RTE_LIBRTE_QEDE_PMD=n +CONFIG_RTE_LIBRTE_QEDE_DEBUG_TX=n +CONFIG_RTE_LIBRTE_QEDE_DEBUG_RX=n +#Provides abs path/name of architecture we compile for. firmware file. +#Empty string denotes driver will use default firmware +CONFIG_RTE_LIBRTE_QEDE_FW="" +# Compile burst-oriented Solarflare libefx-based PMD +CONFIG_RTE_LIBRTE_SFC_EFX_PMD=n +CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n +# Compile software PMD backed by SZEDATA2 device +CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n +# Compile burst-oriented Cavium Thunderx NICVF PMD driver +CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD=n +CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_RX=n +CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_TX=n +# Compile burst-oriented Cavium LiquidIO PMD driver +CONFIG_RTE_LIBRTE_LIO_PMD=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_RX=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_TX=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_MBOX=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_REGS=n +# Compile burst-oriented Cavium OCTEONTX network PMD driver +CONFIG_RTE_LIBRTE_OCTEONTX_PMD=n +# Compile WRS accelerated virtual port (AVP) guest PMD driver +CONFIG_RTE_LIBRTE_AVP_PMD=n +CONFIG_RTE_LIBRTE_AVP_DEBUG_RX=n +CONFIG_RTE_LIBRTE_AVP_DEBUG_TX=n +CONFIG_RTE_LIBRTE_AVP_DEBUG_BUFFERS=n +# Compile burst-oriented VIRTIO PMD driver +CONFIG_RTE_LIBRTE_VIRTIO_PMD=y +CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_RX=n +CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_TX=n +CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_DUMP=n +# Compile virtio device emulation inside virtio PMD driver +CONFIG_RTE_VIRTIO_USER=n +# Compile burst-oriented VMXNET3 PMD driver +CONFIG_RTE_LIBRTE_VMXNET3_PMD=n +CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_RX=n +CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX=n +CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX_FREE=n +# Compile software PMD backed by AF_PACKET sockets (Linux only) +CONFIG_RTE_LIBRTE_PMD_AF_PACKET=n +# Compile link bonding PMD library +CONFIG_RTE_LIBRTE_PMD_BOND=n +CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n +CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n +# Compile fail-safe PMD +CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y +# Compile Marvell PMD driver +CONFIG_RTE_LIBRTE_MVPP2_PMD=n +# Compile Marvell MVNETA PMD driver +CONFIG_RTE_LIBRTE_MVNETA_PMD=n +# Compile support for VMBus library +CONFIG_RTE_LIBRTE_VMBUS=n +# Compile native PMD for Hyper-V/Azure +CONFIG_RTE_LIBRTE_NETVSC_PMD=n +CONFIG_RTE_LIBRTE_NETVSC_DEBUG_RX=n +CONFIG_RTE_LIBRTE_NETVSC_DEBUG_TX=n +CONFIG_RTE_LIBRTE_NETVSC_DEBUG_DUMP=n +# Compile virtual device driver for NetVSC on Hyper-V/Azure +CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD=n +# Compile null PMD +CONFIG_RTE_LIBRTE_PMD_NULL=n +# Compile software PMD backed by PCAP files +CONFIG_RTE_LIBRTE_PMD_PCAP=n +# Compile example software rings based PMD +CONFIG_RTE_LIBRTE_PMD_RING=y +CONFIG_RTE_PMD_RING_MAX_RX_RINGS=16 +CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16 +# Compile SOFTNIC PMD +CONFIG_RTE_LIBRTE_PMD_SOFTNIC=n +# Compile architecture we compile for. TAP PMD +# It is enabled by default for Linux only. +CONFIG_RTE_LIBRTE_PMD_TAP=y +# Do prefetch of packet data within PMD driver receive function +CONFIG_RTE_PMD_PACKET_PREFETCH=y +# Compile generic wireless base band device library +# EXPERIMENTAL: API may change without prior notice +CONFIG_RTE_LIBRTE_BBDEV=n +CONFIG_RTE_BBDEV_MAX_DEVS=128 +CONFIG_RTE_BBDEV_OFFLOAD_COST=n +# Compile PMD for NULL bbdev device +CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL=y +# Compile PMD for turbo software bbdev device +CONFIG_RTE_LIBRTE_PMD_BBDEV_TURBO_SW=n +# Compile generic crypto device library +CONFIG_RTE_LIBRTE_CRYPTODEV=n +CONFIG_RTE_CRYPTO_MAX_DEVS=64 +# Compile PMD for ARMv8 Crypto device +CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO=n +CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO_DEBUG=n +# Compile NXP CAAM JR crypto Driver +CONFIG_RTE_LIBRTE_PMD_CAAM_JR=n +CONFIG_RTE_LIBRTE_PMD_CAAM_JR_BE=n +# Compile NXP DPAA2 crypto sec driver for CAAM HW +CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC=n +# NXP DPAA caam - crypto driver +CONFIG_RTE_LIBRTE_PMD_DPAA_SEC=n +CONFIG_RTE_LIBRTE_DPAA_MAX_CRYPTODEV=4 +# Compile PMD for Cavium OCTEON TX crypto device +CONFIG_RTE_LIBRTE_PMD_OCTEONTX_CRYPTO=y +# Compile PMD for QuickAssist based devices - see docs for details +CONFIG_RTE_LIBRTE_PMD_QAT=n +CONFIG_RTE_LIBRTE_PMD_QAT_SYM=n +# Max. number of QuickAssist devices, which can be detected and attached +CONFIG_RTE_PMD_QAT_MAX_PCI_DEVICES=48 +CONFIG_RTE_PMD_QAT_COMP_SGL_MAX_SEGMENTS=16 +CONFIG_RTE_PMD_QAT_COMP_IM_BUFFER_SIZE=65536 +# Compile PMD for virtio crypto devices +CONFIG_RTE_LIBRTE_PMD_VIRTIO_CRYPTO=n +# Number of maximum virtio crypto devices +CONFIG_RTE_MAX_VIRTIO_CRYPTO=32 +# Compile PMD for AESNI backed device +CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n +# Compile PMD for Software backed device +CONFIG_RTE_LIBRTE_PMD_OPENSSL=n +# Compile PMD for AESNI GCM device +CONFIG_RTE_LIBRTE_PMD_AESNI_GCM=n +# Compile PMD for SNOW 3G device +CONFIG_RTE_LIBRTE_PMD_SNOW3G=n +CONFIG_RTE_LIBRTE_PMD_SNOW3G_DEBUG=n +# Compile PMD for KASUMI device +CONFIG_RTE_LIBRTE_PMD_KASUMI=n +# Compile PMD for ZUC device +CONFIG_RTE_LIBRTE_PMD_ZUC=n +# Compile PMD for Crypto Scheduler device +CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER=n +# Compile PMD for NULL Crypto device +CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=n +# Compile PMD for AMD CCP crypto device +CONFIG_RTE_LIBRTE_PMD_CCP=n +# Compile PMD for Marvell Crypto device +CONFIG_RTE_LIBRTE_PMD_MVSAM_CRYPTO=n +# Compile generic security library +CONFIG_RTE_LIBRTE_SECURITY=n +# Compile generic compression device library +CONFIG_RTE_LIBRTE_COMPRESSDEV=n +CONFIG_RTE_COMPRESS_MAX_DEVS=64 +# Compile compressdev unit test +CONFIG_RTE_COMPRESSDEV_TEST=n +# Compile PMD for Octeontx ZIPVF compression device +CONFIG_RTE_LIBRTE_PMD_OCTEONTX_ZIPVF=n +# Compile PMD for ISA-L compression device +CONFIG_RTE_LIBRTE_PMD_ISAL=n +# Compile PMD for ZLIB compression device +CONFIG_RTE_LIBRTE_PMD_ZLIB=n +# Compile generic event device library +CONFIG_RTE_LIBRTE_EVENTDEV=n +CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n +CONFIG_RTE_EVENT_MAX_DEVS=16 +CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64 +CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32 +CONFIG_RTE_EVENT_ETH_INTR_RING_SIZE=1024 +CONFIG_RTE_EVENT_CRYPTO_ADAPTER_MAX_INSTANCE=32 +CONFIG_RTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE=32 +# Compile PMD for skeleton event device +CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV=n +CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV_DEBUG=n +# Compile PMD for software event device +CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV=n +# Compile PMD for distributed software event device +CONFIG_RTE_LIBRTE_PMD_DSW_EVENTDEV=n +# Compile PMD for octeontx sso event device +CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF=n +# Compile PMD for OPDL event device +CONFIG_RTE_LIBRTE_PMD_OPDL_EVENTDEV=n +# Compile PMD for NXP DPAA event device +CONFIG_RTE_LIBRTE_PMD_DPAA_EVENTDEV=n +# Compile PMD for NXP DPAA2 event device +CONFIG_RTE_LIBRTE_PMD_DPAA2_EVENTDEV=n +# Compile raw device support +# EXPERIMENTAL: API may change without prior notice +CONFIG_RTE_LIBRTE_RAWDEV=n +CONFIG_RTE_RAWDEV_MAX_DEVS=10 +CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV=n +# Compile PMD for NXP DPAA2 CMDIF raw device +CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n +# Compile PMD for NXP DPAA2 QDMA raw device +CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n +# Compile PMD for Intel FPGA raw device +CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=n +# Compile librte_ring +CONFIG_RTE_LIBRTE_RING=y +# Compile librte_mempool +CONFIG_RTE_LIBRTE_MEMPOOL=y +CONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE=512 +CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG=n +# Compile Mempool drivers +CONFIG_RTE_DRIVER_MEMPOOL_BUCKET=y +CONFIG_RTE_DRIVER_MEMPOOL_BUCKET_SIZE_KB=64 +CONFIG_RTE_DRIVER_MEMPOOL_RING=y +CONFIG_RTE_DRIVER_MEMPOOL_STACK=y +# Compile PMD for octeontx fpa mempool device +CONFIG_RTE_LIBRTE_OCTEONTX_MEMPOOL=n +# Compile librte_mbuf +CONFIG_RTE_LIBRTE_MBUF=y +CONFIG_RTE_LIBRTE_MBUF_DEBUG=n +CONFIG_RTE_MBUF_DEFAULT_MEMPOOL_OPS="ring_mp_mc" +CONFIG_RTE_MBUF_REFCNT_ATOMIC=y +CONFIG_RTE_PKTMBUF_HEADROOM=128 +# Compile librte_timer +CONFIG_RTE_LIBRTE_TIMER=n +CONFIG_RTE_LIBRTE_TIMER_DEBUG=n +# Compile librte_cfgfile +CONFIG_RTE_LIBRTE_CFGFILE=n +# Compile librte_cmdline +CONFIG_RTE_LIBRTE_CMDLINE=y +CONFIG_RTE_LIBRTE_CMDLINE_DEBUG=n +# Compile librte_hash +CONFIG_RTE_LIBRTE_HASH=y +CONFIG_RTE_LIBRTE_HASH_DEBUG=n +# Compile librte_efd +CONFIG_RTE_LIBRTE_EFD=n +# Compile librte_member +CONFIG_RTE_LIBRTE_MEMBER=y +# Compile librte_jobstats +CONFIG_RTE_LIBRTE_JOBSTATS=n +# Compile architecture we compile for. device metrics library +CONFIG_RTE_LIBRTE_METRICS=y +# Compile architecture we compile for. bitrate statistics library +CONFIG_RTE_LIBRTE_BITRATE=y +# Compile architecture we compile for. latency statistics library +CONFIG_RTE_LIBRTE_LATENCY_STATS=y +# Compile librte_telemetry +CONFIG_RTE_LIBRTE_TELEMETRY=n +# Compile librte_lpm +CONFIG_RTE_LIBRTE_LPM=n +CONFIG_RTE_LIBRTE_LPM_DEBUG=n +# Compile librte_acl +CONFIG_RTE_LIBRTE_ACL=n +CONFIG_RTE_LIBRTE_ACL_DEBUG=n +# Compile librte_power +CONFIG_RTE_LIBRTE_POWER=n +CONFIG_RTE_LIBRTE_POWER_DEBUG=n +CONFIG_RTE_MAX_LCORE_FREQS=64 +# Compile librte_net +CONFIG_RTE_LIBRTE_NET=y +# Compile librte_ip_frag +CONFIG_RTE_LIBRTE_IP_FRAG=y +CONFIG_RTE_LIBRTE_IP_FRAG_DEBUG=n +CONFIG_RTE_LIBRTE_IP_FRAG_MAX_FRAG=4 +CONFIG_RTE_LIBRTE_IP_FRAG_TBL_STAT=n +# Compile GRO library +CONFIG_RTE_LIBRTE_GRO=y +# Compile GSO library +CONFIG_RTE_LIBRTE_GSO=y +# Compile librte_meter +CONFIG_RTE_LIBRTE_METER=y +# Compile librte_classify +CONFIG_RTE_LIBRTE_FLOW_CLASSIFY=n +# Compile librte_sched +CONFIG_RTE_LIBRTE_SCHED=n +CONFIG_RTE_SCHED_DEBUG=n +CONFIG_RTE_SCHED_RED=n +CONFIG_RTE_SCHED_COLLECT_STATS=n +CONFIG_RTE_SCHED_SUBPORT_TC_OV=n +CONFIG_RTE_SCHED_PORT_N_GRINDERS=8 +CONFIG_RTE_SCHED_VECTOR=n +# Compile architecture we compile for. distributor library +CONFIG_RTE_LIBRTE_DISTRIBUTOR=n +# Compile architecture we compile for. reorder library +CONFIG_RTE_LIBRTE_REORDER=n +# Compile librte_port +CONFIG_RTE_LIBRTE_PORT=n +CONFIG_RTE_PORT_STATS_COLLECT=n +CONFIG_RTE_PORT_PCAP=n +# Compile librte_table +CONFIG_RTE_LIBRTE_TABLE=n +CONFIG_RTE_TABLE_STATS_COLLECT=n +# Compile librte_pipeline +CONFIG_RTE_LIBRTE_PIPELINE=n +CONFIG_RTE_PIPELINE_STATS_COLLECT=n +# Compile librte_kni +CONFIG_RTE_LIBRTE_KNI=n +CONFIG_RTE_LIBRTE_PMD_KNI=n +CONFIG_RTE_KNI_KMOD=n +CONFIG_RTE_KNI_KMOD_ETHTOOL=n +CONFIG_RTE_KNI_PREEMPT_DEFAULT=y +# Compile architecture we compile for. pdump library +CONFIG_RTE_LIBRTE_PDUMP=y +# Compile vhost user library +CONFIG_RTE_LIBRTE_VHOST=y +CONFIG_RTE_LIBRTE_VHOST_NUMA=y +CONFIG_RTE_LIBRTE_VHOST_DEBUG=n +# Compile vhost PMD +# To compile, CONFIG_RTE_LIBRTE_VHOST should be enabled. +CONFIG_RTE_LIBRTE_PMD_VHOST=y +# Compile IFC driver +# To compile, CONFIG_RTE_LIBRTE_VHOST and CONFIG_RTE_EAL_VFIO +# should be enabled. +CONFIG_RTE_LIBRTE_IFC_PMD=n +# Compile librte_bpf +CONFIG_RTE_LIBRTE_BPF=n +# allow load BPF from ELF files (requires libelf) +CONFIG_RTE_LIBRTE_BPF_ELF=n +# Compile architecture we compile for. test application +CONFIG_RTE_APP_TEST=y +CONFIG_RTE_APP_TEST_RESOURCE_TAR=n +# Compile architecture we compile for. procinfo application +CONFIG_RTE_PROC_INFO=y +# Compile architecture we compile for. PMD test application +CONFIG_RTE_TEST_PMD=n +CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n +CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n +# Compile architecture we compile for. bbdev test application +CONFIG_RTE_TEST_BBDEV=n +# Compile architecture we compile for. crypto performance application +CONFIG_RTE_APP_CRYPTO_PERF=n +# Compile architecture we compile for. eventdev application +CONFIG_RTE_APP_EVENTDEV=n +CONFIG_RTE_EXEC_ENV_LINUXAPP=y +CONFIG_RTE_LIBRTE_VHOST_POSTCOPY=n +# Common libraries, before Bus/PMDs +# NXP DPAA BUS and drivers +# NXP FSLMC BUS and DPAA2 drivers +# NXP ENETC PMD Driver +CONFIG_RTE_ARCH_ARM64=y +CONFIG_RTE_ARCH_64=y +# Maximum available cache line size in arm64 implementations. +# Setting to maximum available cache line size in generic config +# to address minimum DMA alignment across all arm64 implementations. +# Accelarate rte_memcpy. Be sure to run unit test (memcpy_perf_autotest) +# to determine architecture we compile for. best threshold in code. Refer to notes in source file +# (lib/librte_eal/common/include/arch/arm/rte_memcpy_64.h) for more info. +CONFIG_RTE_ARCH_ARM64_MEMCPY=n +#CONFIG_RTE_ARM64_MEMCPY_ALIGNED_THRESHOLD=2048 +#CONFIG_RTE_ARM64_MEMCPY_UNALIGNED_THRESHOLD=512 +# Leave below RTE_ARM64_MEMCPY_xxx options commented out, unless there're +# strong reasons. +#CONFIG_RTE_ARM64_MEMCPY_SKIP_GCC_VER_CHECK=n +#CONFIG_RTE_ARM64_MEMCPY_ALIGN_MASK=0xF +#CONFIG_RTE_ARM64_MEMCPY_STRICT_ALIGN=n +CONFIG_RTE_TOOLCHAIN_GCC=y +CONFIG_RTE_LIBRTE_PMD_XENVIRT=n diff --git a/SOURCES/configlib.sh b/SOURCES/configlib.sh new file mode 100644 index 0000000..a1049b3 --- /dev/null +++ b/SOURCES/configlib.sh @@ -0,0 +1,105 @@ +# Copyright (C) 2017, Red Hat, Inc. +# +# Core configuration file library. + +# Configurations are determined by sha values. The way to determine is by +# the special text: +# $FILE_COMMENT_TYPE -*- cfg-sha: $SHA256 -*- + +export LC_ALL=C + +# check required binaries +__check_reqd_binaries() { + local BIN __binaries=("egrep" "sort" "sha256sum" "sed") + for BIN in $__binaries; do + if ! type -P $BIN >/dev/null 2>&1; then + echo "Binary $BIN not found. Please install." + exit 1 + fi + done +} + +# Calculates a sha from a file +# The algorithm for generating a sha from a config is thus: +# +# 1. Remove all comment lines and blank lines +# 2. Sort the content +# 3. generate the sha-256 sum +# +# From a script perspective, this means: +# egrep -v ^\# %file% | egrep -v ^$ | sort -u | sha256sum +# +# Params: +# $1 = output variable +# $2 = file to use to calculate the shasum +# $3 = file comment type (defaults to # if unspecified) +calc_sha() { + __check_reqd_binaries + + if [ "$1" == "" ]; then + echo "Please pass in a storage variable." + return 1 + fi + + local __resultvar=$1 + __retval=1 + shift + + local __file=$1 + local cmnt=${2:-#} + + if [ -f "$__file" ]; then + local __shasum=$(egrep -v ^"$cmnt" "$__file" | egrep -v ^$ | sort -u | sha256sum -t | cut -d" " -f1) + eval $__resultvar="'$__shasum'" + __retval=0 + fi + return $__retval +} + +# Retrieves a sha stored in a file +# Param: +# $1 = output variable +# $2 = file to use to calculate the shasum +# $3 = file comment type (defaults to # if unspecified) +retr_sha() { + __check_reqd_binaries + + if [ "$1" == "" ]; then + echo "Please pass in a storage variable." + return 1 + fi + + local __resultvar=$1 + __retval=1 + shift + + local __file=$1 + local cmnt=${2:-#} + + if [ -f "$__file" ]; then + if grep -q "$cmnt -\*- cfg-sha:" "$__file"; then + local __shasum=$(grep "$cmnt -\*- cfg-sha:" "$__file" | sed -e "s@$cmnt -\*- cfg-sha: @@" | cut -d" " -f1) + eval $__resultvar="'$__shasum'" + __retval=0 + fi + fi + return $__retval +} + + +# Set a config value +# set_conf dpdk_build_tree parameter value +# dpdk_build_tree is the directory where the .config lives +# parameter is the config parameter +# value is the value to set for the config parameter +set_conf() { + c="$1/.config" + shift + + if grep -q "$1" "$c"; then + sed -i "s:^$1=.*$:$1=$2:g" $c + else + echo $1=$2 >> "$c" + fi +} + diff --git a/SOURCES/gen_config_group.sh b/SOURCES/gen_config_group.sh new file mode 100755 index 0000000..651a0c5 --- /dev/null +++ b/SOURCES/gen_config_group.sh @@ -0,0 +1,216 @@ +#!/bin/bash + +source configlib.sh + +# Generates arch configurations in the current directory based on +# 1. an openvswitch.spec file +# 2. an expanded dpdk tree + +if (( $# != 2 )); then + echo "$0: openvswitch.spec dpdk_tree" >&2 + exit 1 +fi + +OVSSPEC="$1" +DPDKDIR="$2" + +# accumulate all arch + name triples +OVS_DPDK_CONF_MACH_ARCH=() +for arch in $(grep %define\ dpdk_mach_arch "$OVSSPEC" | sed 's@%define dpdk_mach_arch @@') +do + OVS_DPDK_CONF_MACH_ARCH+=($arch) +done + +OVS_DPDK_CONF_MACH_TMPL=() +for tmpl in $(grep %define\ dpdk_mach_tmpl "$OVSSPEC" | sed 's@%define dpdk_mach_tmpl @@') +do + OVS_DPDK_CONF_MACH_TMPL+=($tmpl) +done + +OVS_DPDK_CONF_MACH=() +for mach in $(grep %define\ dpdk_mach\ "$OVSSPEC" | sed 's@%define dpdk_mach @@') +do + OVS_DPDK_CONF_MACH+=($mach) +done + +OVS_DPDK_TARGETS=() +for ((i=0; i < ${#OVS_DPDK_CONF_MACH[@]}; i++)); +do + OVS_DPDK_TARGETS+=("${OVS_DPDK_CONF_MACH_ARCH[$i]}-${OVS_DPDK_CONF_MACH_TMPL[$i]}-linuxapp-gcc") + echo "DPDK-target: ${OVS_DPDK_TARGETS[$i]}" +done + +OUTPUT_DIR=$(pwd) +pushd "$DPDKDIR" +for ((i=0; i < ${#OVS_DPDK_TARGETS[@]}; i++)); +do + echo "For ${OVS_DPDK_TARGETS[$i]}:" + + echo " a. Generating initial config" + echo " make V=1 T=${OVS_DPDK_TARGETS[$i]} O=${OVS_DPDK_TARGETS[$i]}" + make V=1 T=${OVS_DPDK_TARGETS[$i]} O=${OVS_DPDK_TARGETS[$i]} -j8 config + ORIG_SHA="" + OUTDIR="${OVS_DPDK_TARGETS[$i]}" + + echo " b. calculating and applying sha" + calc_sha ORIG_SHA "${OUTDIR}/.config" + if [ "$ORIG_SHA" == "" ]; then + echo "ERROR: Unable to get sha for arch ${OVS_DPDK_TARGETS[$i]}" + exit 1 + fi + echo "# -*- cfg-sha: ${ORIG_SHA}" > ${OUTDIR}/.config.new + cat "${OUTDIR}/.config" >> "${OUTDIR}/.config.new" + cp "${OUTDIR}/.config" "${OUTDIR}/.config.orig" + mv -f "${OUTDIR}/.config.new" "${OUTDIR}/.config" + + echo " c. setting initial configurations" + # these are the original setconf values from openvswitch.spec + set_conf "${OUTDIR}" CONFIG_RTE_MACHINE "\\\"${OVS_DPDK_CONF_MACH[$i]}\\\"" + + # Disable DPDK libraries not needed + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_TIMER n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_CFGFILE n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_JOBSTATS n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_LPM n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_ACL n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_POWER n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_SCHED n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_DISTRIBUTOR n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_REORDER n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PORT n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_TABLE n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PIPELINE n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_KNI n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_CRYPTODEV n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_SECURITY n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_FLOW_CLASSIFY n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_BBDEV n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_COMPRESSDEV n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_BPF n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_OCTEONTX_MEMPOOL n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_DPAA_MEMPOOL n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_DPAA2_MEMPOOL n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_CFGFILE n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_EFD n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_FLOW_CLASSIFY n + + # Disable all eventdevs + for eventdev in $(grep _EVENTDEV= "${OUTDIR}/.config" | sed 's@=\(y\|n\)@@g') + do + set_conf "${OUTDIR}" $eventdev n + done + + # Disable all rawdevs + for rawdev in $(grep _RAWDEV= "${OUTDIR}/.config" | sed 's@=\(y\|n\)@@g') + do + set_conf "${OUTDIR}" $rawdev n + done + + # Disable virtio user + set_conf "${OUTDIR}" CONFIG_RTE_VIRTIO_USER n + + # Enable vhost numa as libnuma dep is ok + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VHOST_NUMA y + + # start by disabling ALL PMDs + for pmd in $(grep _PMD= "${OUTDIR}/.config" | sed 's@=\(y\|n\)@@g') + do + set_conf "${OUTDIR}" $pmd n + done + + # PMDs which have their own naming scheme + # the default for this was 'n' at one point. Make sure we keep it + # as such + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_QAT n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_OCTEONTX_ZIPVF n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_VHOST n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_KNI n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_XENVIRT n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_NULL n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_PCAP n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_BOND n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_AF_PACKET n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_SOFTNIC n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_DPAA_SEC n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_VIRTIO_CRYPTO n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_COMMON_DPAAX n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_CAAM_JR n + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_CAAM_JR_BE n + + # whitelist of enabled PMDs + # Soft PMDs to enable + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_RING y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_VHOST y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VIRTIO_PMD y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_TAP y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PMD_FAILSAFE y + + + # start by disabling all buses + for bus in $(grep _BUS= "${OUTDIR}/.config" | sed 's@=\(y\|n\)@@g') + do + set_conf "${OUTDIR}" $bus n + done + + # blacklist buses that don't conform to std naming + # May override VMBUS later in arch specific section + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VMBUS n + + # whitelist buses + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_PCI_BUS y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VDEV_BUS y + + + # Disable some other miscellanous items related to test apps + set_conf "${OUTDIR}" CONFIG_RTE_TEST_BBDEV n + set_conf "${OUTDIR}" CONFIG_RTE_APP_CRYPTO_PERF n + + # Disable kernel modules + set_conf "${OUTDIR}" CONFIG_RTE_EAL_IGB_UIO n + set_conf "${OUTDIR}" CONFIG_RTE_KNI_KMOD n + + # Disable experimental stuff + set_conf "${OUTDIR}" CONFIG_RTE_NEXT_ABI n + + # Arch specific + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_I40E_PMD y + case "${OVS_DPDK_CONF_MACH_ARCH[i]}" in + x86_64) + # Hw PMD + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_BNXT_PMD y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_ENIC_PMD y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_MLX4_PMD y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_MLX5_PMD y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_NFP_PMD y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_QEDE_PMD y + # Sw PMD + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_NETVSC_PMD y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD y + # Bus + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_VMBUS y + ;& + arm64) + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_IXGBE_PMD y + set_conf "${OUTDIR}" CONFIG_RTE_LIBRTE_IGB_PMD y + ;; + esac + + cp "${OUTDIR}/.config" "${OUTPUT_DIR}/${OVS_DPDK_TARGETS[$i]}-config" +done +popd >/dev/null + +echo -n "For each arch ( " +for ((i=0; i < ${#OVS_DPDK_CONF_MACH_ARCH[@]}; i++)); +do + echo -n "${OVS_DPDK_CONF_MACH_ARCH[i]} " +done +echo "):" +echo "1. ensure you enable the requisite hw" diff --git a/SOURCES/ppc_64-power8-linuxapp-gcc-config b/SOURCES/ppc_64-power8-linuxapp-gcc-config new file mode 100644 index 0000000..2319b68 --- /dev/null +++ b/SOURCES/ppc_64-power8-linuxapp-gcc-config @@ -0,0 +1,550 @@ +# -*- cfg-sha: ac783e64ca20c977a7c1c42e72e6dce151b31aa9aecfbfa121b45e49e938f418 +# BSD LICENSE +# Copyright (C) IBM Corporation 2014. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of IBM Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2016 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2017 Intel Corporation +# RTE_EXEC_ENV values are the directories in mk/exec-env/ +CONFIG_RTE_EXEC_ENV="linuxapp" +# RTE_ARCH values are architecture we compile for. directories in mk/arch/ +CONFIG_RTE_ARCH="ppc_64" +# machine can define specific variables or action for a specific board +# RTE_MACHINE values are architecture we compile for. directories in mk/machine/ +CONFIG_RTE_MACHINE="power8" +# The compiler we use. +# RTE_TOOLCHAIN values are architecture we compile for. directories in mk/toolchain/ +CONFIG_RTE_TOOLCHAIN="gcc" +# Use intrinsics or assembly code for key routines +CONFIG_RTE_FORCE_INTRINSICS=n +# Machine forces strict alignment constraints. +CONFIG_RTE_ARCH_STRICT_ALIGN=n +# Compile to share library +CONFIG_RTE_BUILD_SHARED_LIB=n +# Use newest code breaking previous ABI +CONFIG_RTE_NEXT_ABI=n +# Major ABI to overwrite library specific LIBABIVER +CONFIG_RTE_MAJOR_ABI= +# Machine's cache line size +CONFIG_RTE_CACHE_LINE_SIZE=128 +# Memory model +CONFIG_RTE_USE_C11_MEM_MODEL=n +# Compile Environment Abstraction Layer +CONFIG_RTE_LIBRTE_EAL=y +CONFIG_RTE_MAX_LCORE=256 +CONFIG_RTE_MAX_NUMA_NODES=32 +CONFIG_RTE_MAX_HEAPS=32 +CONFIG_RTE_MAX_MEMSEG_LISTS=64 +# each memseg list will be limited to either RTE_MAX_MEMSEG_PER_LIST pages +# or RTE_MAX_MEM_MB_PER_LIST megabytes worth of memory, whichever is smaller +CONFIG_RTE_MAX_MEMSEG_PER_LIST=8192 +CONFIG_RTE_MAX_MEM_MB_PER_LIST=32768 +# a "type" is a combination of page size and NUMA node. total number of memseg +# lists per type will be limited to either RTE_MAX_MEMSEG_PER_TYPE pages (split +# over multiple lists of RTE_MAX_MEMSEG_PER_LIST pages), or +# RTE_MAX_MEM_MB_PER_TYPE megabytes of memory (split over multiple lists of +# RTE_MAX_MEM_MB_PER_LIST), whichever is smaller +CONFIG_RTE_MAX_MEMSEG_PER_TYPE=32768 +CONFIG_RTE_MAX_MEM_MB_PER_TYPE=131072 +# global maximum usable amount of VA, in megabytes +CONFIG_RTE_MAX_MEM_MB=524288 +CONFIG_RTE_MAX_MEMZONE=2560 +CONFIG_RTE_MAX_TAILQ=32 +CONFIG_RTE_ENABLE_ASSERT=n +CONFIG_RTE_LOG_DP_LEVEL=RTE_LOG_INFO +CONFIG_RTE_LOG_HISTORY=256 +CONFIG_RTE_BACKTRACE=y +CONFIG_RTE_LIBEAL_USE_HPET=n +CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID=n +CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n +CONFIG_RTE_EAL_IGB_UIO=n +CONFIG_RTE_EAL_VFIO=y +CONFIG_RTE_MAX_VFIO_GROUPS=64 +CONFIG_RTE_MAX_VFIO_CONTAINERS=64 +CONFIG_RTE_MALLOC_DEBUG=n +CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=y +CONFIG_RTE_USE_LIBBSD=n +# Recognize/ignore architecture we compile for. AVX/AVX512 CPU flags for performance/power testing. +# AVX512 is marked as experimental for now, will enable it after enough +# field test and possible optimization. +CONFIG_RTE_ENABLE_AVX=y +CONFIG_RTE_ENABLE_AVX512=n +# Default driver path (or "" to disable) +CONFIG_RTE_EAL_PMD_PATH="" +# Compile Environment Abstraction Layer to support Vmware TSC map +CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=n +# Compile architecture we compile for. PCI library +CONFIG_RTE_LIBRTE_PCI=y +# Compile architecture we compile for. argument parser library +CONFIG_RTE_LIBRTE_KVARGS=y +# Compile generic ethernet library +CONFIG_RTE_LIBRTE_ETHER=y +CONFIG_RTE_LIBRTE_ETHDEV_DEBUG=n +CONFIG_RTE_MAX_ETHPORTS=32 +CONFIG_RTE_MAX_QUEUES_PER_PORT=1024 +CONFIG_RTE_LIBRTE_IEEE1588=n +CONFIG_RTE_ETHDEV_QUEUE_STAT_CNTRS=16 +CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y +CONFIG_RTE_ETHDEV_PROFILE_WITH_VTUNE=n +# Turn off Tx preparation stage +# Warning: rte_eth_tx_prepare() can be safely disabled only if using a +# driver which do not implement any Tx preparation. +CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n +# Common libraries, before Bus/PMDs +CONFIG_RTE_LIBRTE_COMMON_DPAAX=n +# Compile architecture we compile for. Intel FPGA bus +CONFIG_RTE_LIBRTE_IFPGA_BUS=n +# Compile PCI bus driver +CONFIG_RTE_LIBRTE_PCI_BUS=y +# Compile architecture we compile for. vdev bus +CONFIG_RTE_LIBRTE_VDEV_BUS=y +# Compile ARK PMD +CONFIG_RTE_LIBRTE_ARK_PMD=n +CONFIG_RTE_LIBRTE_ARK_PAD_TX=y +CONFIG_RTE_LIBRTE_ARK_DEBUG_RX=n +CONFIG_RTE_LIBRTE_ARK_DEBUG_TX=n +CONFIG_RTE_LIBRTE_ARK_DEBUG_STATS=n +CONFIG_RTE_LIBRTE_ARK_DEBUG_TRACE=n +# Compile Aquantia Atlantic PMD driver +CONFIG_RTE_LIBRTE_ATLANTIC_PMD=n +# Compile AMD PMD +CONFIG_RTE_LIBRTE_AXGBE_PMD=n +CONFIG_RTE_LIBRTE_AXGBE_PMD_DEBUG=n +# Compile burst-oriented Broadcom PMD driver +CONFIG_RTE_LIBRTE_BNX2X_PMD=n +CONFIG_RTE_LIBRTE_BNX2X_DEBUG_RX=n +CONFIG_RTE_LIBRTE_BNX2X_DEBUG_TX=n +CONFIG_RTE_LIBRTE_BNX2X_MF_SUPPORT=n +CONFIG_RTE_LIBRTE_BNX2X_DEBUG_PERIODIC=n +# Compile burst-oriented Broadcom BNXT PMD driver +CONFIG_RTE_LIBRTE_BNXT_PMD=n +# Compile burst-oriented Chelsio Terminator (CXGBE) PMD +CONFIG_RTE_LIBRTE_CXGBE_PMD=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_REG=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_MBOX=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_TX=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_RX=n +CONFIG_RTE_LIBRTE_CXGBE_TPUT=y +# NXP DPAA Bus +CONFIG_RTE_LIBRTE_DPAA_BUS=n +CONFIG_RTE_LIBRTE_DPAA_MEMPOOL=n +CONFIG_RTE_LIBRTE_DPAA_PMD=n +CONFIG_RTE_LIBRTE_DPAA_HWDEBUG=n +# Compile NXP DPAA2 FSL-MC Bus +CONFIG_RTE_LIBRTE_FSLMC_BUS=n +# Compile Support Libraries for NXP DPAA2 +CONFIG_RTE_LIBRTE_DPAA2_MEMPOOL=n +CONFIG_RTE_LIBRTE_DPAA2_USE_PHYS_IOVA=y +# Compile burst-oriented NXP DPAA2 PMD driver +CONFIG_RTE_LIBRTE_DPAA2_PMD=n +CONFIG_RTE_LIBRTE_DPAA2_DEBUG_DRIVER=n +# Compile NXP ENETC PMD Driver +CONFIG_RTE_LIBRTE_ENETC_PMD=n +# Compile burst-oriented Amazon ENA PMD driver +CONFIG_RTE_LIBRTE_ENA_PMD=n +CONFIG_RTE_LIBRTE_ENA_DEBUG_RX=n +CONFIG_RTE_LIBRTE_ENA_DEBUG_TX=n +CONFIG_RTE_LIBRTE_ENA_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_ENA_COM_DEBUG=n +# Compile burst-oriented Cisco ENIC PMD driver +CONFIG_RTE_LIBRTE_ENIC_PMD=n +# Compile burst-oriented IGB & EM PMD drivers +CONFIG_RTE_LIBRTE_EM_PMD=n +CONFIG_RTE_LIBRTE_IGB_PMD=n +CONFIG_RTE_LIBRTE_E1000_DEBUG_RX=n +CONFIG_RTE_LIBRTE_E1000_DEBUG_TX=n +CONFIG_RTE_LIBRTE_E1000_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC=n +# Compile burst-oriented IXGBE PMD driver +CONFIG_RTE_LIBRTE_IXGBE_PMD=n +CONFIG_RTE_LIBRTE_IXGBE_DEBUG_RX=n +CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX=n +CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_IXGBE_PF_DISABLE_STRIP_CRC=n +CONFIG_RTE_IXGBE_INC_VECTOR=y +CONFIG_RTE_LIBRTE_IXGBE_BYPASS=n +# Compile burst-oriented I40E PMD driver +CONFIG_RTE_LIBRTE_I40E_PMD=y +CONFIG_RTE_LIBRTE_I40E_DEBUG_RX=n +CONFIG_RTE_LIBRTE_I40E_DEBUG_TX=n +CONFIG_RTE_LIBRTE_I40E_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC=y +CONFIG_RTE_LIBRTE_I40E_INC_VECTOR=y +CONFIG_RTE_LIBRTE_I40E_16BYTE_RX_DESC=n +CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_PF=64 +CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM=4 +# Compile burst-oriented FM10K PMD +CONFIG_RTE_LIBRTE_FM10K_PMD=n +CONFIG_RTE_LIBRTE_FM10K_DEBUG_RX=n +CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX=n +CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE=y +CONFIG_RTE_LIBRTE_FM10K_INC_VECTOR=y +# Compile burst-oriented AVF PMD driver +CONFIG_RTE_LIBRTE_AVF_PMD=n +CONFIG_RTE_LIBRTE_AVF_INC_VECTOR=y +CONFIG_RTE_LIBRTE_AVF_DEBUG_TX=n +CONFIG_RTE_LIBRTE_AVF_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_AVF_DEBUG_RX=n +CONFIG_RTE_LIBRTE_AVF_16BYTE_RX_DESC=n +# Compile burst-oriented Mellanox ConnectX-3 (MLX4) PMD +CONFIG_RTE_LIBRTE_MLX4_PMD=n +CONFIG_RTE_LIBRTE_MLX4_DEBUG=n +CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS=n +# Compile burst-oriented Mellanox ConnectX-4, ConnectX-5 & Bluefield +# (MLX5) PMD +CONFIG_RTE_LIBRTE_MLX5_PMD=n +CONFIG_RTE_LIBRTE_MLX5_DEBUG=n +CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS=n +# Compile burst-oriented Netronome NFP PMD driver +CONFIG_RTE_LIBRTE_NFP_PMD=n +CONFIG_RTE_LIBRTE_NFP_DEBUG_TX=n +CONFIG_RTE_LIBRTE_NFP_DEBUG_RX=n +# QLogic 10G/25G/40G/50G/100G PMD +CONFIG_RTE_LIBRTE_QEDE_PMD=n +CONFIG_RTE_LIBRTE_QEDE_DEBUG_TX=n +CONFIG_RTE_LIBRTE_QEDE_DEBUG_RX=n +#Provides abs path/name of architecture we compile for. firmware file. +#Empty string denotes driver will use default firmware +CONFIG_RTE_LIBRTE_QEDE_FW="" +# Compile burst-oriented Solarflare libefx-based PMD +CONFIG_RTE_LIBRTE_SFC_EFX_PMD=n +CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n +# Compile software PMD backed by SZEDATA2 device +CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n +# Compile burst-oriented Cavium Thunderx NICVF PMD driver +CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD=n +CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_RX=n +CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_TX=n +# Compile burst-oriented Cavium LiquidIO PMD driver +CONFIG_RTE_LIBRTE_LIO_PMD=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_RX=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_TX=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_MBOX=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_REGS=n +# Compile burst-oriented Cavium OCTEONTX network PMD driver +CONFIG_RTE_LIBRTE_OCTEONTX_PMD=n +# Compile WRS accelerated virtual port (AVP) guest PMD driver +CONFIG_RTE_LIBRTE_AVP_PMD=n +CONFIG_RTE_LIBRTE_AVP_DEBUG_RX=n +CONFIG_RTE_LIBRTE_AVP_DEBUG_TX=n +CONFIG_RTE_LIBRTE_AVP_DEBUG_BUFFERS=n +# Compile burst-oriented VIRTIO PMD driver +CONFIG_RTE_LIBRTE_VIRTIO_PMD=y +CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_RX=n +CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_TX=n +CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_DUMP=n +# Compile virtio device emulation inside virtio PMD driver +CONFIG_RTE_VIRTIO_USER=n +# Compile burst-oriented VMXNET3 PMD driver +CONFIG_RTE_LIBRTE_VMXNET3_PMD=n +CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_RX=n +CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX=n +CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX_FREE=n +# Compile software PMD backed by AF_PACKET sockets (Linux only) +CONFIG_RTE_LIBRTE_PMD_AF_PACKET=n +# Compile link bonding PMD library +CONFIG_RTE_LIBRTE_PMD_BOND=n +CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n +CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n +# Compile fail-safe PMD +CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y +# Compile Marvell PMD driver +CONFIG_RTE_LIBRTE_MVPP2_PMD=n +# Compile Marvell MVNETA PMD driver +CONFIG_RTE_LIBRTE_MVNETA_PMD=n +# Compile support for VMBus library +CONFIG_RTE_LIBRTE_VMBUS=n +# Compile native PMD for Hyper-V/Azure +CONFIG_RTE_LIBRTE_NETVSC_PMD=n +CONFIG_RTE_LIBRTE_NETVSC_DEBUG_RX=n +CONFIG_RTE_LIBRTE_NETVSC_DEBUG_TX=n +CONFIG_RTE_LIBRTE_NETVSC_DEBUG_DUMP=n +# Compile virtual device driver for NetVSC on Hyper-V/Azure +CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD=n +# Compile null PMD +CONFIG_RTE_LIBRTE_PMD_NULL=n +# Compile software PMD backed by PCAP files +CONFIG_RTE_LIBRTE_PMD_PCAP=n +# Compile example software rings based PMD +CONFIG_RTE_LIBRTE_PMD_RING=y +CONFIG_RTE_PMD_RING_MAX_RX_RINGS=16 +CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16 +# Compile SOFTNIC PMD +CONFIG_RTE_LIBRTE_PMD_SOFTNIC=n +# Compile architecture we compile for. TAP PMD +# It is enabled by default for Linux only. +CONFIG_RTE_LIBRTE_PMD_TAP=y +# Do prefetch of packet data within PMD driver receive function +CONFIG_RTE_PMD_PACKET_PREFETCH=y +# Compile generic wireless base band device library +# EXPERIMENTAL: API may change without prior notice +CONFIG_RTE_LIBRTE_BBDEV=n +CONFIG_RTE_BBDEV_MAX_DEVS=128 +CONFIG_RTE_BBDEV_OFFLOAD_COST=n +# Compile PMD for NULL bbdev device +CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL=y +# Compile PMD for turbo software bbdev device +CONFIG_RTE_LIBRTE_PMD_BBDEV_TURBO_SW=n +# Compile generic crypto device library +CONFIG_RTE_LIBRTE_CRYPTODEV=n +CONFIG_RTE_CRYPTO_MAX_DEVS=64 +# Compile PMD for ARMv8 Crypto device +CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO=n +CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO_DEBUG=n +# Compile NXP CAAM JR crypto Driver +CONFIG_RTE_LIBRTE_PMD_CAAM_JR=n +CONFIG_RTE_LIBRTE_PMD_CAAM_JR_BE=n +# Compile NXP DPAA2 crypto sec driver for CAAM HW +CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC=n +# NXP DPAA caam - crypto driver +CONFIG_RTE_LIBRTE_PMD_DPAA_SEC=n +CONFIG_RTE_LIBRTE_DPAA_MAX_CRYPTODEV=4 +# Compile PMD for Cavium OCTEON TX crypto device +CONFIG_RTE_LIBRTE_PMD_OCTEONTX_CRYPTO=y +# Compile PMD for QuickAssist based devices - see docs for details +CONFIG_RTE_LIBRTE_PMD_QAT=n +CONFIG_RTE_LIBRTE_PMD_QAT_SYM=n +# Max. number of QuickAssist devices, which can be detected and attached +CONFIG_RTE_PMD_QAT_MAX_PCI_DEVICES=48 +CONFIG_RTE_PMD_QAT_COMP_SGL_MAX_SEGMENTS=16 +CONFIG_RTE_PMD_QAT_COMP_IM_BUFFER_SIZE=65536 +# Compile PMD for virtio crypto devices +CONFIG_RTE_LIBRTE_PMD_VIRTIO_CRYPTO=n +# Number of maximum virtio crypto devices +CONFIG_RTE_MAX_VIRTIO_CRYPTO=32 +# Compile PMD for AESNI backed device +CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n +# Compile PMD for Software backed device +CONFIG_RTE_LIBRTE_PMD_OPENSSL=n +# Compile PMD for AESNI GCM device +CONFIG_RTE_LIBRTE_PMD_AESNI_GCM=n +# Compile PMD for SNOW 3G device +CONFIG_RTE_LIBRTE_PMD_SNOW3G=n +CONFIG_RTE_LIBRTE_PMD_SNOW3G_DEBUG=n +# Compile PMD for KASUMI device +CONFIG_RTE_LIBRTE_PMD_KASUMI=n +# Compile PMD for ZUC device +CONFIG_RTE_LIBRTE_PMD_ZUC=n +# Compile PMD for Crypto Scheduler device +CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER=n +# Compile PMD for NULL Crypto device +CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=n +# Compile PMD for AMD CCP crypto device +CONFIG_RTE_LIBRTE_PMD_CCP=n +# Compile PMD for Marvell Crypto device +CONFIG_RTE_LIBRTE_PMD_MVSAM_CRYPTO=n +# Compile generic security library +CONFIG_RTE_LIBRTE_SECURITY=n +# Compile generic compression device library +CONFIG_RTE_LIBRTE_COMPRESSDEV=n +CONFIG_RTE_COMPRESS_MAX_DEVS=64 +# Compile compressdev unit test +CONFIG_RTE_COMPRESSDEV_TEST=n +# Compile PMD for Octeontx ZIPVF compression device +CONFIG_RTE_LIBRTE_PMD_OCTEONTX_ZIPVF=n +# Compile PMD for ISA-L compression device +CONFIG_RTE_LIBRTE_PMD_ISAL=n +# Compile PMD for ZLIB compression device +CONFIG_RTE_LIBRTE_PMD_ZLIB=n +# Compile generic event device library +CONFIG_RTE_LIBRTE_EVENTDEV=n +CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n +CONFIG_RTE_EVENT_MAX_DEVS=16 +CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64 +CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32 +CONFIG_RTE_EVENT_ETH_INTR_RING_SIZE=1024 +CONFIG_RTE_EVENT_CRYPTO_ADAPTER_MAX_INSTANCE=32 +CONFIG_RTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE=32 +# Compile PMD for skeleton event device +CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV=n +CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV_DEBUG=n +# Compile PMD for software event device +CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV=n +# Compile PMD for distributed software event device +CONFIG_RTE_LIBRTE_PMD_DSW_EVENTDEV=n +# Compile PMD for octeontx sso event device +CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF=n +# Compile PMD for OPDL event device +CONFIG_RTE_LIBRTE_PMD_OPDL_EVENTDEV=n +# Compile PMD for NXP DPAA event device +CONFIG_RTE_LIBRTE_PMD_DPAA_EVENTDEV=n +# Compile PMD for NXP DPAA2 event device +CONFIG_RTE_LIBRTE_PMD_DPAA2_EVENTDEV=n +# Compile raw device support +# EXPERIMENTAL: API may change without prior notice +CONFIG_RTE_LIBRTE_RAWDEV=n +CONFIG_RTE_RAWDEV_MAX_DEVS=10 +CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV=n +# Compile PMD for NXP DPAA2 CMDIF raw device +CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n +# Compile PMD for NXP DPAA2 QDMA raw device +CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n +# Compile PMD for Intel FPGA raw device +CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=n +# Compile librte_ring +CONFIG_RTE_LIBRTE_RING=y +# Compile librte_mempool +CONFIG_RTE_LIBRTE_MEMPOOL=y +CONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE=512 +CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG=n +# Compile Mempool drivers +CONFIG_RTE_DRIVER_MEMPOOL_BUCKET=y +CONFIG_RTE_DRIVER_MEMPOOL_BUCKET_SIZE_KB=64 +CONFIG_RTE_DRIVER_MEMPOOL_RING=y +CONFIG_RTE_DRIVER_MEMPOOL_STACK=y +# Compile PMD for octeontx fpa mempool device +CONFIG_RTE_LIBRTE_OCTEONTX_MEMPOOL=n +# Compile librte_mbuf +CONFIG_RTE_LIBRTE_MBUF=y +CONFIG_RTE_LIBRTE_MBUF_DEBUG=n +CONFIG_RTE_MBUF_DEFAULT_MEMPOOL_OPS="ring_mp_mc" +CONFIG_RTE_MBUF_REFCNT_ATOMIC=y +CONFIG_RTE_PKTMBUF_HEADROOM=128 +# Compile librte_timer +CONFIG_RTE_LIBRTE_TIMER=n +CONFIG_RTE_LIBRTE_TIMER_DEBUG=n +# Compile librte_cfgfile +CONFIG_RTE_LIBRTE_CFGFILE=n +# Compile librte_cmdline +CONFIG_RTE_LIBRTE_CMDLINE=y +CONFIG_RTE_LIBRTE_CMDLINE_DEBUG=n +# Compile librte_hash +CONFIG_RTE_LIBRTE_HASH=y +CONFIG_RTE_LIBRTE_HASH_DEBUG=n +# Compile librte_efd +CONFIG_RTE_LIBRTE_EFD=n +# Compile librte_member +CONFIG_RTE_LIBRTE_MEMBER=y +# Compile librte_jobstats +CONFIG_RTE_LIBRTE_JOBSTATS=n +# Compile architecture we compile for. device metrics library +CONFIG_RTE_LIBRTE_METRICS=y +# Compile architecture we compile for. bitrate statistics library +CONFIG_RTE_LIBRTE_BITRATE=y +# Compile architecture we compile for. latency statistics library +CONFIG_RTE_LIBRTE_LATENCY_STATS=y +# Compile librte_telemetry +CONFIG_RTE_LIBRTE_TELEMETRY=n +# Compile librte_lpm +CONFIG_RTE_LIBRTE_LPM=n +CONFIG_RTE_LIBRTE_LPM_DEBUG=n +# Compile librte_acl +CONFIG_RTE_LIBRTE_ACL=n +CONFIG_RTE_LIBRTE_ACL_DEBUG=n +# Compile librte_power +CONFIG_RTE_LIBRTE_POWER=n +CONFIG_RTE_LIBRTE_POWER_DEBUG=n +CONFIG_RTE_MAX_LCORE_FREQS=64 +# Compile librte_net +CONFIG_RTE_LIBRTE_NET=y +# Compile librte_ip_frag +CONFIG_RTE_LIBRTE_IP_FRAG=y +CONFIG_RTE_LIBRTE_IP_FRAG_DEBUG=n +CONFIG_RTE_LIBRTE_IP_FRAG_MAX_FRAG=4 +CONFIG_RTE_LIBRTE_IP_FRAG_TBL_STAT=n +# Compile GRO library +CONFIG_RTE_LIBRTE_GRO=y +# Compile GSO library +CONFIG_RTE_LIBRTE_GSO=y +# Compile librte_meter +CONFIG_RTE_LIBRTE_METER=y +# Compile librte_classify +CONFIG_RTE_LIBRTE_FLOW_CLASSIFY=n +# Compile librte_sched +CONFIG_RTE_LIBRTE_SCHED=n +CONFIG_RTE_SCHED_DEBUG=n +CONFIG_RTE_SCHED_RED=n +CONFIG_RTE_SCHED_COLLECT_STATS=n +CONFIG_RTE_SCHED_SUBPORT_TC_OV=n +CONFIG_RTE_SCHED_PORT_N_GRINDERS=8 +CONFIG_RTE_SCHED_VECTOR=n +# Compile architecture we compile for. distributor library +CONFIG_RTE_LIBRTE_DISTRIBUTOR=n +# Compile architecture we compile for. reorder library +CONFIG_RTE_LIBRTE_REORDER=n +# Compile librte_port +CONFIG_RTE_LIBRTE_PORT=n +CONFIG_RTE_PORT_STATS_COLLECT=n +CONFIG_RTE_PORT_PCAP=n +# Compile librte_table +CONFIG_RTE_LIBRTE_TABLE=n +CONFIG_RTE_TABLE_STATS_COLLECT=n +# Compile librte_pipeline +CONFIG_RTE_LIBRTE_PIPELINE=n +CONFIG_RTE_PIPELINE_STATS_COLLECT=n +# Compile librte_kni +CONFIG_RTE_LIBRTE_KNI=n +CONFIG_RTE_LIBRTE_PMD_KNI=n +CONFIG_RTE_KNI_KMOD=n +CONFIG_RTE_KNI_KMOD_ETHTOOL=n +CONFIG_RTE_KNI_PREEMPT_DEFAULT=y +# Compile architecture we compile for. pdump library +CONFIG_RTE_LIBRTE_PDUMP=y +# Compile vhost user library +CONFIG_RTE_LIBRTE_VHOST=y +CONFIG_RTE_LIBRTE_VHOST_NUMA=y +CONFIG_RTE_LIBRTE_VHOST_DEBUG=n +# Compile vhost PMD +# To compile, CONFIG_RTE_LIBRTE_VHOST should be enabled. +CONFIG_RTE_LIBRTE_PMD_VHOST=y +# Compile IFC driver +# To compile, CONFIG_RTE_LIBRTE_VHOST and CONFIG_RTE_EAL_VFIO +# should be enabled. +CONFIG_RTE_LIBRTE_IFC_PMD=n +# Compile librte_bpf +CONFIG_RTE_LIBRTE_BPF=n +# allow load BPF from ELF files (requires libelf) +CONFIG_RTE_LIBRTE_BPF_ELF=n +# Compile architecture we compile for. test application +CONFIG_RTE_APP_TEST=y +CONFIG_RTE_APP_TEST_RESOURCE_TAR=n +# Compile architecture we compile for. procinfo application +CONFIG_RTE_PROC_INFO=y +# Compile architecture we compile for. PMD test application +CONFIG_RTE_TEST_PMD=n +CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n +CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n +# Compile architecture we compile for. bbdev test application +CONFIG_RTE_TEST_BBDEV=n +# Compile architecture we compile for. crypto performance application +CONFIG_RTE_APP_CRYPTO_PERF=n +# Compile architecture we compile for. eventdev application +CONFIG_RTE_APP_EVENTDEV=n +CONFIG_RTE_EXEC_ENV_LINUXAPP=y +CONFIG_RTE_LIBRTE_VHOST_POSTCOPY=n +# Common libraries, before Bus/PMDs +# NXP DPAA BUS and drivers +# NXP FSLMC BUS and DPAA2 drivers +# NXP ENETC PMD Driver +CONFIG_RTE_ARCH_PPC_64=y +CONFIG_RTE_ARCH_64=y +CONFIG_RTE_TOOLCHAIN_GCC=y +# Note: Power doesn't have this support +# Note: Initially, all of architecture we compile for. PMD drivers compilation are turned off on Power +# Will turn on them only after architecture we compile for. successful testing on Power +CONFIG_RTE_LIBRTE_PMD_XENVIRT=n diff --git a/SOURCES/set_config.sh b/SOURCES/set_config.sh new file mode 100755 index 0000000..002386b --- /dev/null +++ b/SOURCES/set_config.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# Copyright (C) 2017, Red Hat, Inc. +# +# set_config.sh will copy a configuration from $1 to $2, in the process +# checking that the sha header for $1 matches the header in $2 + +source configlib.sh + +if (( $# < 2 )); then + echo "$0: source dest [comment-marker]" + exit 1 +fi + +if [ ! -f "$1" ]; then + echo "Source file $1 must exist." + exit 1 +fi +src_file=$1 +shift + +if [ ! -f "$1" ]; then + echo "Dest file $1 must exist." + exit 1 +fi +dst_file=$1 +shift + +comment_sep=${1:-#} + +export LANG=en_US.utf8 + +DEST_FILE_SHA="" +SRC_FILE_SHA="" + +calc_sha DEST_FILE_SHA "$dst_file" "$comment_sep" || echo "Failed to calc sha" +retr_sha SRC_FILE_SHA "$src_file" "$comment_sep" || echo "Failed to retrieve sha" + +if [ "$DEST_FILE_SHA" != "$SRC_FILE_SHA" ]; then + echo "ERROR: The requisite starting sha from $dst_file does not match the" + echo " specified sha in $src_file." + echo "[ $DEST_FILE_SHA ] vs [ $SRC_FILE_SHA ]" + exit 1 +fi + +mv "$dst_file" "$dst_file".OLD +cp "$src_file" "$dst_file" +echo "copied 1 config file." +exit 0 diff --git a/SOURCES/x86_64-native-linuxapp-gcc-config b/SOURCES/x86_64-native-linuxapp-gcc-config new file mode 100644 index 0000000..4b7a7ea --- /dev/null +++ b/SOURCES/x86_64-native-linuxapp-gcc-config @@ -0,0 +1,525 @@ +# -*- cfg-sha: 2ba93102021dc5d38494cf5090c3ecaca37db13153dd558b1511a56f2a3d9b10 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2014 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2016 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2017 Intel Corporation +# RTE_EXEC_ENV values are the directories in mk/exec-env/ +CONFIG_RTE_EXEC_ENV="linuxapp" +# RTE_ARCH values are architecture we compile for. directories in mk/arch/ +CONFIG_RTE_ARCH="x86_64" +# machine can define specific variables or action for a specific board +# RTE_MACHINE values are architecture we compile for. directories in mk/machine/ +CONFIG_RTE_MACHINE="default" +# The compiler we use. +# RTE_TOOLCHAIN values are architecture we compile for. directories in mk/toolchain/ +CONFIG_RTE_TOOLCHAIN="gcc" +# Use intrinsics or assembly code for key routines +CONFIG_RTE_FORCE_INTRINSICS=n +# Machine forces strict alignment constraints. +CONFIG_RTE_ARCH_STRICT_ALIGN=n +# Compile to share library +CONFIG_RTE_BUILD_SHARED_LIB=n +# Use newest code breaking previous ABI +CONFIG_RTE_NEXT_ABI=n +# Major ABI to overwrite library specific LIBABIVER +CONFIG_RTE_MAJOR_ABI= +# Machine's cache line size +CONFIG_RTE_CACHE_LINE_SIZE=64 +# Memory model +CONFIG_RTE_USE_C11_MEM_MODEL=n +# Compile Environment Abstraction Layer +CONFIG_RTE_LIBRTE_EAL=y +CONFIG_RTE_MAX_LCORE=128 +CONFIG_RTE_MAX_NUMA_NODES=8 +CONFIG_RTE_MAX_HEAPS=32 +CONFIG_RTE_MAX_MEMSEG_LISTS=64 +# each memseg list will be limited to either RTE_MAX_MEMSEG_PER_LIST pages +# or RTE_MAX_MEM_MB_PER_LIST megabytes worth of memory, whichever is smaller +CONFIG_RTE_MAX_MEMSEG_PER_LIST=8192 +CONFIG_RTE_MAX_MEM_MB_PER_LIST=32768 +# a "type" is a combination of page size and NUMA node. total number of memseg +# lists per type will be limited to either RTE_MAX_MEMSEG_PER_TYPE pages (split +# over multiple lists of RTE_MAX_MEMSEG_PER_LIST pages), or +# RTE_MAX_MEM_MB_PER_TYPE megabytes of memory (split over multiple lists of +# RTE_MAX_MEM_MB_PER_LIST), whichever is smaller +CONFIG_RTE_MAX_MEMSEG_PER_TYPE=32768 +CONFIG_RTE_MAX_MEM_MB_PER_TYPE=131072 +# global maximum usable amount of VA, in megabytes +CONFIG_RTE_MAX_MEM_MB=524288 +CONFIG_RTE_MAX_MEMZONE=2560 +CONFIG_RTE_MAX_TAILQ=32 +CONFIG_RTE_ENABLE_ASSERT=n +CONFIG_RTE_LOG_DP_LEVEL=RTE_LOG_INFO +CONFIG_RTE_LOG_HISTORY=256 +CONFIG_RTE_BACKTRACE=y +CONFIG_RTE_LIBEAL_USE_HPET=n +CONFIG_RTE_EAL_ALLOW_INV_SOCKET_ID=n +CONFIG_RTE_EAL_ALWAYS_PANIC_ON_ERROR=n +CONFIG_RTE_EAL_IGB_UIO=n +CONFIG_RTE_EAL_VFIO=y +CONFIG_RTE_MAX_VFIO_GROUPS=64 +CONFIG_RTE_MAX_VFIO_CONTAINERS=64 +CONFIG_RTE_MALLOC_DEBUG=n +CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=y +CONFIG_RTE_USE_LIBBSD=n +# Recognize/ignore architecture we compile for. AVX/AVX512 CPU flags for performance/power testing. +# AVX512 is marked as experimental for now, will enable it after enough +# field test and possible optimization. +CONFIG_RTE_ENABLE_AVX=y +CONFIG_RTE_ENABLE_AVX512=n +# Default driver path (or "" to disable) +CONFIG_RTE_EAL_PMD_PATH="" +# Compile Environment Abstraction Layer to support Vmware TSC map +CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y +# Compile architecture we compile for. PCI library +CONFIG_RTE_LIBRTE_PCI=y +# Compile architecture we compile for. argument parser library +CONFIG_RTE_LIBRTE_KVARGS=y +# Compile generic ethernet library +CONFIG_RTE_LIBRTE_ETHER=y +CONFIG_RTE_LIBRTE_ETHDEV_DEBUG=n +CONFIG_RTE_MAX_ETHPORTS=32 +CONFIG_RTE_MAX_QUEUES_PER_PORT=1024 +CONFIG_RTE_LIBRTE_IEEE1588=n +CONFIG_RTE_ETHDEV_QUEUE_STAT_CNTRS=16 +CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y +CONFIG_RTE_ETHDEV_PROFILE_WITH_VTUNE=n +# Turn off Tx preparation stage +# Warning: rte_eth_tx_prepare() can be safely disabled only if using a +# driver which do not implement any Tx preparation. +CONFIG_RTE_ETHDEV_TX_PREPARE_NOOP=n +# Common libraries, before Bus/PMDs +CONFIG_RTE_LIBRTE_COMMON_DPAAX=n +# Compile architecture we compile for. Intel FPGA bus +CONFIG_RTE_LIBRTE_IFPGA_BUS=n +# Compile PCI bus driver +CONFIG_RTE_LIBRTE_PCI_BUS=y +# Compile architecture we compile for. vdev bus +CONFIG_RTE_LIBRTE_VDEV_BUS=y +# Compile ARK PMD +CONFIG_RTE_LIBRTE_ARK_PMD=n +CONFIG_RTE_LIBRTE_ARK_PAD_TX=y +CONFIG_RTE_LIBRTE_ARK_DEBUG_RX=n +CONFIG_RTE_LIBRTE_ARK_DEBUG_TX=n +CONFIG_RTE_LIBRTE_ARK_DEBUG_STATS=n +CONFIG_RTE_LIBRTE_ARK_DEBUG_TRACE=n +# Compile Aquantia Atlantic PMD driver +CONFIG_RTE_LIBRTE_ATLANTIC_PMD=n +# Compile AMD PMD +CONFIG_RTE_LIBRTE_AXGBE_PMD=n +CONFIG_RTE_LIBRTE_AXGBE_PMD_DEBUG=n +# Compile burst-oriented Broadcom PMD driver +CONFIG_RTE_LIBRTE_BNX2X_PMD=n +CONFIG_RTE_LIBRTE_BNX2X_DEBUG_RX=n +CONFIG_RTE_LIBRTE_BNX2X_DEBUG_TX=n +CONFIG_RTE_LIBRTE_BNX2X_MF_SUPPORT=n +CONFIG_RTE_LIBRTE_BNX2X_DEBUG_PERIODIC=n +# Compile burst-oriented Broadcom BNXT PMD driver +CONFIG_RTE_LIBRTE_BNXT_PMD=y +# Compile burst-oriented Chelsio Terminator (CXGBE) PMD +CONFIG_RTE_LIBRTE_CXGBE_PMD=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_REG=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_MBOX=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_TX=n +CONFIG_RTE_LIBRTE_CXGBE_DEBUG_RX=n +CONFIG_RTE_LIBRTE_CXGBE_TPUT=y +# NXP DPAA Bus +CONFIG_RTE_LIBRTE_DPAA_BUS=n +CONFIG_RTE_LIBRTE_DPAA_MEMPOOL=n +CONFIG_RTE_LIBRTE_DPAA_PMD=n +CONFIG_RTE_LIBRTE_DPAA_HWDEBUG=n +# Compile NXP DPAA2 FSL-MC Bus +CONFIG_RTE_LIBRTE_FSLMC_BUS=n +# Compile Support Libraries for NXP DPAA2 +CONFIG_RTE_LIBRTE_DPAA2_MEMPOOL=n +CONFIG_RTE_LIBRTE_DPAA2_USE_PHYS_IOVA=y +# Compile burst-oriented NXP DPAA2 PMD driver +CONFIG_RTE_LIBRTE_DPAA2_PMD=n +CONFIG_RTE_LIBRTE_DPAA2_DEBUG_DRIVER=n +# Compile NXP ENETC PMD Driver +CONFIG_RTE_LIBRTE_ENETC_PMD=n +# Compile burst-oriented Amazon ENA PMD driver +CONFIG_RTE_LIBRTE_ENA_PMD=n +CONFIG_RTE_LIBRTE_ENA_DEBUG_RX=n +CONFIG_RTE_LIBRTE_ENA_DEBUG_TX=n +CONFIG_RTE_LIBRTE_ENA_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_ENA_COM_DEBUG=n +# Compile burst-oriented Cisco ENIC PMD driver +CONFIG_RTE_LIBRTE_ENIC_PMD=y +# Compile burst-oriented IGB & EM PMD drivers +CONFIG_RTE_LIBRTE_EM_PMD=n +CONFIG_RTE_LIBRTE_IGB_PMD=y +CONFIG_RTE_LIBRTE_E1000_DEBUG_RX=n +CONFIG_RTE_LIBRTE_E1000_DEBUG_TX=n +CONFIG_RTE_LIBRTE_E1000_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC=n +# Compile burst-oriented IXGBE PMD driver +CONFIG_RTE_LIBRTE_IXGBE_PMD=y +CONFIG_RTE_LIBRTE_IXGBE_DEBUG_RX=n +CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX=n +CONFIG_RTE_LIBRTE_IXGBE_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_IXGBE_PF_DISABLE_STRIP_CRC=n +CONFIG_RTE_IXGBE_INC_VECTOR=y +CONFIG_RTE_LIBRTE_IXGBE_BYPASS=n +# Compile burst-oriented I40E PMD driver +CONFIG_RTE_LIBRTE_I40E_PMD=y +CONFIG_RTE_LIBRTE_I40E_DEBUG_RX=n +CONFIG_RTE_LIBRTE_I40E_DEBUG_TX=n +CONFIG_RTE_LIBRTE_I40E_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC=y +CONFIG_RTE_LIBRTE_I40E_INC_VECTOR=y +CONFIG_RTE_LIBRTE_I40E_16BYTE_RX_DESC=n +CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_PF=64 +CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM=4 +# Compile burst-oriented FM10K PMD +CONFIG_RTE_LIBRTE_FM10K_PMD=n +CONFIG_RTE_LIBRTE_FM10K_DEBUG_RX=n +CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX=n +CONFIG_RTE_LIBRTE_FM10K_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_FM10K_RX_OLFLAGS_ENABLE=y +CONFIG_RTE_LIBRTE_FM10K_INC_VECTOR=y +# Compile burst-oriented AVF PMD driver +CONFIG_RTE_LIBRTE_AVF_PMD=n +CONFIG_RTE_LIBRTE_AVF_INC_VECTOR=y +CONFIG_RTE_LIBRTE_AVF_DEBUG_TX=n +CONFIG_RTE_LIBRTE_AVF_DEBUG_TX_FREE=n +CONFIG_RTE_LIBRTE_AVF_DEBUG_RX=n +CONFIG_RTE_LIBRTE_AVF_16BYTE_RX_DESC=n +# Compile burst-oriented Mellanox ConnectX-3 (MLX4) PMD +CONFIG_RTE_LIBRTE_MLX4_PMD=y +CONFIG_RTE_LIBRTE_MLX4_DEBUG=n +CONFIG_RTE_LIBRTE_MLX4_DLOPEN_DEPS=y +# Compile burst-oriented Mellanox ConnectX-4, ConnectX-5 & Bluefield +# (MLX5) PMD +CONFIG_RTE_LIBRTE_MLX5_PMD=y +CONFIG_RTE_LIBRTE_MLX5_DEBUG=n +CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS=y +# Compile burst-oriented Netronome NFP PMD driver +CONFIG_RTE_LIBRTE_NFP_PMD=y +CONFIG_RTE_LIBRTE_NFP_DEBUG_TX=n +CONFIG_RTE_LIBRTE_NFP_DEBUG_RX=n +# QLogic 10G/25G/40G/50G/100G PMD +CONFIG_RTE_LIBRTE_QEDE_PMD=y +CONFIG_RTE_LIBRTE_QEDE_DEBUG_TX=n +CONFIG_RTE_LIBRTE_QEDE_DEBUG_RX=n +#Provides abs path/name of architecture we compile for. firmware file. +#Empty string denotes driver will use default firmware +CONFIG_RTE_LIBRTE_QEDE_FW="" +# Compile burst-oriented Solarflare libefx-based PMD +CONFIG_RTE_LIBRTE_SFC_EFX_PMD=n +CONFIG_RTE_LIBRTE_SFC_EFX_DEBUG=n +# Compile software PMD backed by SZEDATA2 device +CONFIG_RTE_LIBRTE_PMD_SZEDATA2=n +# Compile burst-oriented Cavium Thunderx NICVF PMD driver +CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD=n +CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_RX=n +CONFIG_RTE_LIBRTE_THUNDERX_NICVF_DEBUG_TX=n +# Compile burst-oriented Cavium LiquidIO PMD driver +CONFIG_RTE_LIBRTE_LIO_PMD=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_RX=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_TX=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_MBOX=n +CONFIG_RTE_LIBRTE_LIO_DEBUG_REGS=n +# Compile burst-oriented Cavium OCTEONTX network PMD driver +CONFIG_RTE_LIBRTE_OCTEONTX_PMD=n +# Compile WRS accelerated virtual port (AVP) guest PMD driver +CONFIG_RTE_LIBRTE_AVP_PMD=n +CONFIG_RTE_LIBRTE_AVP_DEBUG_RX=n +CONFIG_RTE_LIBRTE_AVP_DEBUG_TX=n +CONFIG_RTE_LIBRTE_AVP_DEBUG_BUFFERS=n +# Compile burst-oriented VIRTIO PMD driver +CONFIG_RTE_LIBRTE_VIRTIO_PMD=y +CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_RX=n +CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_TX=n +CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_DUMP=n +# Compile virtio device emulation inside virtio PMD driver +CONFIG_RTE_VIRTIO_USER=n +# Compile burst-oriented VMXNET3 PMD driver +CONFIG_RTE_LIBRTE_VMXNET3_PMD=n +CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_RX=n +CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX=n +CONFIG_RTE_LIBRTE_VMXNET3_DEBUG_TX_FREE=n +# Compile software PMD backed by AF_PACKET sockets (Linux only) +CONFIG_RTE_LIBRTE_PMD_AF_PACKET=n +# Compile link bonding PMD library +CONFIG_RTE_LIBRTE_PMD_BOND=n +CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB=n +CONFIG_RTE_LIBRTE_BOND_DEBUG_ALB_L1=n +# Compile fail-safe PMD +CONFIG_RTE_LIBRTE_PMD_FAILSAFE=y +# Compile Marvell PMD driver +CONFIG_RTE_LIBRTE_MVPP2_PMD=n +# Compile Marvell MVNETA PMD driver +CONFIG_RTE_LIBRTE_MVNETA_PMD=n +# Compile support for VMBus library +CONFIG_RTE_LIBRTE_VMBUS=y +# Compile native PMD for Hyper-V/Azure +CONFIG_RTE_LIBRTE_NETVSC_PMD=y +CONFIG_RTE_LIBRTE_NETVSC_DEBUG_RX=n +CONFIG_RTE_LIBRTE_NETVSC_DEBUG_TX=n +CONFIG_RTE_LIBRTE_NETVSC_DEBUG_DUMP=n +# Compile virtual device driver for NetVSC on Hyper-V/Azure +CONFIG_RTE_LIBRTE_VDEV_NETVSC_PMD=y +# Compile null PMD +CONFIG_RTE_LIBRTE_PMD_NULL=n +# Compile software PMD backed by PCAP files +CONFIG_RTE_LIBRTE_PMD_PCAP=n +# Compile example software rings based PMD +CONFIG_RTE_LIBRTE_PMD_RING=y +CONFIG_RTE_PMD_RING_MAX_RX_RINGS=16 +CONFIG_RTE_PMD_RING_MAX_TX_RINGS=16 +# Compile SOFTNIC PMD +CONFIG_RTE_LIBRTE_PMD_SOFTNIC=n +# Compile architecture we compile for. TAP PMD +# It is enabled by default for Linux only. +CONFIG_RTE_LIBRTE_PMD_TAP=y +# Do prefetch of packet data within PMD driver receive function +CONFIG_RTE_PMD_PACKET_PREFETCH=y +# Compile generic wireless base band device library +# EXPERIMENTAL: API may change without prior notice +CONFIG_RTE_LIBRTE_BBDEV=n +CONFIG_RTE_BBDEV_MAX_DEVS=128 +CONFIG_RTE_BBDEV_OFFLOAD_COST=n +# Compile PMD for NULL bbdev device +CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL=y +# Compile PMD for turbo software bbdev device +CONFIG_RTE_LIBRTE_PMD_BBDEV_TURBO_SW=n +# Compile generic crypto device library +CONFIG_RTE_LIBRTE_CRYPTODEV=n +CONFIG_RTE_CRYPTO_MAX_DEVS=64 +# Compile PMD for ARMv8 Crypto device +CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO=n +CONFIG_RTE_LIBRTE_PMD_ARMV8_CRYPTO_DEBUG=n +# Compile NXP CAAM JR crypto Driver +CONFIG_RTE_LIBRTE_PMD_CAAM_JR=n +CONFIG_RTE_LIBRTE_PMD_CAAM_JR_BE=n +# Compile NXP DPAA2 crypto sec driver for CAAM HW +CONFIG_RTE_LIBRTE_PMD_DPAA2_SEC=n +# NXP DPAA caam - crypto driver +CONFIG_RTE_LIBRTE_PMD_DPAA_SEC=n +CONFIG_RTE_LIBRTE_DPAA_MAX_CRYPTODEV=4 +# Compile PMD for Cavium OCTEON TX crypto device +CONFIG_RTE_LIBRTE_PMD_OCTEONTX_CRYPTO=y +# Compile PMD for QuickAssist based devices - see docs for details +CONFIG_RTE_LIBRTE_PMD_QAT=n +CONFIG_RTE_LIBRTE_PMD_QAT_SYM=n +# Max. number of QuickAssist devices, which can be detected and attached +CONFIG_RTE_PMD_QAT_MAX_PCI_DEVICES=48 +CONFIG_RTE_PMD_QAT_COMP_SGL_MAX_SEGMENTS=16 +CONFIG_RTE_PMD_QAT_COMP_IM_BUFFER_SIZE=65536 +# Compile PMD for virtio crypto devices +CONFIG_RTE_LIBRTE_PMD_VIRTIO_CRYPTO=n +# Number of maximum virtio crypto devices +CONFIG_RTE_MAX_VIRTIO_CRYPTO=32 +# Compile PMD for AESNI backed device +CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n +# Compile PMD for Software backed device +CONFIG_RTE_LIBRTE_PMD_OPENSSL=n +# Compile PMD for AESNI GCM device +CONFIG_RTE_LIBRTE_PMD_AESNI_GCM=n +# Compile PMD for SNOW 3G device +CONFIG_RTE_LIBRTE_PMD_SNOW3G=n +CONFIG_RTE_LIBRTE_PMD_SNOW3G_DEBUG=n +# Compile PMD for KASUMI device +CONFIG_RTE_LIBRTE_PMD_KASUMI=n +# Compile PMD for ZUC device +CONFIG_RTE_LIBRTE_PMD_ZUC=n +# Compile PMD for Crypto Scheduler device +CONFIG_RTE_LIBRTE_PMD_CRYPTO_SCHEDULER=n +# Compile PMD for NULL Crypto device +CONFIG_RTE_LIBRTE_PMD_NULL_CRYPTO=n +# Compile PMD for AMD CCP crypto device +CONFIG_RTE_LIBRTE_PMD_CCP=n +# Compile PMD for Marvell Crypto device +CONFIG_RTE_LIBRTE_PMD_MVSAM_CRYPTO=n +# Compile generic security library +CONFIG_RTE_LIBRTE_SECURITY=n +# Compile generic compression device library +CONFIG_RTE_LIBRTE_COMPRESSDEV=n +CONFIG_RTE_COMPRESS_MAX_DEVS=64 +# Compile compressdev unit test +CONFIG_RTE_COMPRESSDEV_TEST=n +# Compile PMD for Octeontx ZIPVF compression device +CONFIG_RTE_LIBRTE_PMD_OCTEONTX_ZIPVF=n +# Compile PMD for ISA-L compression device +CONFIG_RTE_LIBRTE_PMD_ISAL=n +# Compile PMD for ZLIB compression device +CONFIG_RTE_LIBRTE_PMD_ZLIB=n +# Compile generic event device library +CONFIG_RTE_LIBRTE_EVENTDEV=n +CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n +CONFIG_RTE_EVENT_MAX_DEVS=16 +CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64 +CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32 +CONFIG_RTE_EVENT_ETH_INTR_RING_SIZE=1024 +CONFIG_RTE_EVENT_CRYPTO_ADAPTER_MAX_INSTANCE=32 +CONFIG_RTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE=32 +# Compile PMD for skeleton event device +CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV=n +CONFIG_RTE_LIBRTE_PMD_SKELETON_EVENTDEV_DEBUG=n +# Compile PMD for software event device +CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV=n +# Compile PMD for distributed software event device +CONFIG_RTE_LIBRTE_PMD_DSW_EVENTDEV=n +# Compile PMD for octeontx sso event device +CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF=n +# Compile PMD for OPDL event device +CONFIG_RTE_LIBRTE_PMD_OPDL_EVENTDEV=n +# Compile PMD for NXP DPAA event device +CONFIG_RTE_LIBRTE_PMD_DPAA_EVENTDEV=n +# Compile PMD for NXP DPAA2 event device +CONFIG_RTE_LIBRTE_PMD_DPAA2_EVENTDEV=n +# Compile raw device support +# EXPERIMENTAL: API may change without prior notice +CONFIG_RTE_LIBRTE_RAWDEV=n +CONFIG_RTE_RAWDEV_MAX_DEVS=10 +CONFIG_RTE_LIBRTE_PMD_SKELETON_RAWDEV=n +# Compile PMD for NXP DPAA2 CMDIF raw device +CONFIG_RTE_LIBRTE_PMD_DPAA2_CMDIF_RAWDEV=n +# Compile PMD for NXP DPAA2 QDMA raw device +CONFIG_RTE_LIBRTE_PMD_DPAA2_QDMA_RAWDEV=n +# Compile PMD for Intel FPGA raw device +CONFIG_RTE_LIBRTE_PMD_IFPGA_RAWDEV=n +# Compile librte_ring +CONFIG_RTE_LIBRTE_RING=y +# Compile librte_mempool +CONFIG_RTE_LIBRTE_MEMPOOL=y +CONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE=512 +CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG=n +# Compile Mempool drivers +CONFIG_RTE_DRIVER_MEMPOOL_BUCKET=y +CONFIG_RTE_DRIVER_MEMPOOL_BUCKET_SIZE_KB=64 +CONFIG_RTE_DRIVER_MEMPOOL_RING=y +CONFIG_RTE_DRIVER_MEMPOOL_STACK=y +# Compile PMD for octeontx fpa mempool device +CONFIG_RTE_LIBRTE_OCTEONTX_MEMPOOL=n +# Compile librte_mbuf +CONFIG_RTE_LIBRTE_MBUF=y +CONFIG_RTE_LIBRTE_MBUF_DEBUG=n +CONFIG_RTE_MBUF_DEFAULT_MEMPOOL_OPS="ring_mp_mc" +CONFIG_RTE_MBUF_REFCNT_ATOMIC=y +CONFIG_RTE_PKTMBUF_HEADROOM=128 +# Compile librte_timer +CONFIG_RTE_LIBRTE_TIMER=n +CONFIG_RTE_LIBRTE_TIMER_DEBUG=n +# Compile librte_cfgfile +CONFIG_RTE_LIBRTE_CFGFILE=n +# Compile librte_cmdline +CONFIG_RTE_LIBRTE_CMDLINE=y +CONFIG_RTE_LIBRTE_CMDLINE_DEBUG=n +# Compile librte_hash +CONFIG_RTE_LIBRTE_HASH=y +CONFIG_RTE_LIBRTE_HASH_DEBUG=n +# Compile librte_efd +CONFIG_RTE_LIBRTE_EFD=n +# Compile librte_member +CONFIG_RTE_LIBRTE_MEMBER=y +# Compile librte_jobstats +CONFIG_RTE_LIBRTE_JOBSTATS=n +# Compile architecture we compile for. device metrics library +CONFIG_RTE_LIBRTE_METRICS=y +# Compile architecture we compile for. bitrate statistics library +CONFIG_RTE_LIBRTE_BITRATE=y +# Compile architecture we compile for. latency statistics library +CONFIG_RTE_LIBRTE_LATENCY_STATS=y +# Compile librte_telemetry +CONFIG_RTE_LIBRTE_TELEMETRY=n +# Compile librte_lpm +CONFIG_RTE_LIBRTE_LPM=n +CONFIG_RTE_LIBRTE_LPM_DEBUG=n +# Compile librte_acl +CONFIG_RTE_LIBRTE_ACL=n +CONFIG_RTE_LIBRTE_ACL_DEBUG=n +# Compile librte_power +CONFIG_RTE_LIBRTE_POWER=n +CONFIG_RTE_LIBRTE_POWER_DEBUG=n +CONFIG_RTE_MAX_LCORE_FREQS=64 +# Compile librte_net +CONFIG_RTE_LIBRTE_NET=y +# Compile librte_ip_frag +CONFIG_RTE_LIBRTE_IP_FRAG=y +CONFIG_RTE_LIBRTE_IP_FRAG_DEBUG=n +CONFIG_RTE_LIBRTE_IP_FRAG_MAX_FRAG=4 +CONFIG_RTE_LIBRTE_IP_FRAG_TBL_STAT=n +# Compile GRO library +CONFIG_RTE_LIBRTE_GRO=y +# Compile GSO library +CONFIG_RTE_LIBRTE_GSO=y +# Compile librte_meter +CONFIG_RTE_LIBRTE_METER=y +# Compile librte_classify +CONFIG_RTE_LIBRTE_FLOW_CLASSIFY=n +# Compile librte_sched +CONFIG_RTE_LIBRTE_SCHED=n +CONFIG_RTE_SCHED_DEBUG=n +CONFIG_RTE_SCHED_RED=n +CONFIG_RTE_SCHED_COLLECT_STATS=n +CONFIG_RTE_SCHED_SUBPORT_TC_OV=n +CONFIG_RTE_SCHED_PORT_N_GRINDERS=8 +CONFIG_RTE_SCHED_VECTOR=n +# Compile architecture we compile for. distributor library +CONFIG_RTE_LIBRTE_DISTRIBUTOR=n +# Compile architecture we compile for. reorder library +CONFIG_RTE_LIBRTE_REORDER=n +# Compile librte_port +CONFIG_RTE_LIBRTE_PORT=n +CONFIG_RTE_PORT_STATS_COLLECT=n +CONFIG_RTE_PORT_PCAP=n +# Compile librte_table +CONFIG_RTE_LIBRTE_TABLE=n +CONFIG_RTE_TABLE_STATS_COLLECT=n +# Compile librte_pipeline +CONFIG_RTE_LIBRTE_PIPELINE=n +CONFIG_RTE_PIPELINE_STATS_COLLECT=n +# Compile librte_kni +CONFIG_RTE_LIBRTE_KNI=n +CONFIG_RTE_LIBRTE_PMD_KNI=n +CONFIG_RTE_KNI_KMOD=n +CONFIG_RTE_KNI_KMOD_ETHTOOL=n +CONFIG_RTE_KNI_PREEMPT_DEFAULT=y +# Compile architecture we compile for. pdump library +CONFIG_RTE_LIBRTE_PDUMP=y +# Compile vhost user library +CONFIG_RTE_LIBRTE_VHOST=y +CONFIG_RTE_LIBRTE_VHOST_NUMA=y +CONFIG_RTE_LIBRTE_VHOST_DEBUG=n +# Compile vhost PMD +# To compile, CONFIG_RTE_LIBRTE_VHOST should be enabled. +CONFIG_RTE_LIBRTE_PMD_VHOST=y +# Compile IFC driver +# To compile, CONFIG_RTE_LIBRTE_VHOST and CONFIG_RTE_EAL_VFIO +# should be enabled. +CONFIG_RTE_LIBRTE_IFC_PMD=n +# Compile librte_bpf +CONFIG_RTE_LIBRTE_BPF=n +# allow load BPF from ELF files (requires libelf) +CONFIG_RTE_LIBRTE_BPF_ELF=n +# Compile architecture we compile for. test application +CONFIG_RTE_APP_TEST=y +CONFIG_RTE_APP_TEST_RESOURCE_TAR=n +# Compile architecture we compile for. procinfo application +CONFIG_RTE_PROC_INFO=y +# Compile architecture we compile for. PMD test application +CONFIG_RTE_TEST_PMD=n +CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n +CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n +# Compile architecture we compile for. bbdev test application +CONFIG_RTE_TEST_BBDEV=n +# Compile architecture we compile for. crypto performance application +CONFIG_RTE_APP_CRYPTO_PERF=n +# Compile architecture we compile for. eventdev application +CONFIG_RTE_APP_EVENTDEV=n +CONFIG_RTE_EXEC_ENV_LINUXAPP=y +CONFIG_RTE_LIBRTE_VHOST_POSTCOPY=n +# Common libraries, before Bus/PMDs +# NXP DPAA BUS and drivers +# NXP FSLMC BUS and DPAA2 drivers +# NXP ENETC PMD Driver +CONFIG_RTE_ARCH_X86_64=y +CONFIG_RTE_ARCH_X86=y +CONFIG_RTE_ARCH_64=y +CONFIG_RTE_TOOLCHAIN_GCC=y +CONFIG_RTE_LIBRTE_PMD_XENVIRT=n diff --git a/SPECS/ovn2.13.spec b/SPECS/ovn2.13.spec new file mode 100644 index 0000000..bc9e75b --- /dev/null +++ b/SPECS/ovn2.13.spec @@ -0,0 +1,1011 @@ +# Spec file for Open Virtual Network (OVN). + +# Copyright (C) 2020 Red Hat, Inc. +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without warranty of any kind. +# +# If tests have to be skipped while building, specify the '--without check' +# option. For example: +# rpmbuild -bb --without check rhel/ovn-fedora.spec +# + +# This defines the base package name's version. +%define pkgver 2.13 +%define pkgname ovn%{pkgver} + +#%%global commit0 7886ac9ed807d6ff942edde624a3f9331da7332a +#%%global date 20200217 +#%%global shortcommit0 %(c=%{commit0}; echo ${c:0:7}) + +# openvswitch commit +#%%global commit1 8ae6a5f98c3ad57d10220596054f6a0c4d6ea358 +#%%global shortcommit1 %(c=%{commit1}; echo ${c:0:7}) + +# If libcap-ng isn't available and there is no need for running OVS +# as regular user, specify the '--without libcapng' +%bcond_without libcapng + +# Enable PIE, bz#955181 +%global _hardened_build 1 + +# some distros (e.g: RHEL-7) don't define _rundir macro yet +# Fedora 15 onwards uses /run as _rundir +%if 0%{!?_rundir:1} +%define _rundir /run +%endif + +%if 0%{?rhel} > 7 || 0%{?fedora} +# On RHEL8 Sphinx is included in buildroot +%global external_sphinx 1 +%else +# Don't use external sphinx (RHV doesn't have optional repositories enabled) +%global external_sphinx 0 +%endif + +# We would see rpmlinit error - E: hardcoded-library-path in '% {_prefix}/lib'. +# But there is no solution to fix this. Using {_lib} macro will solve the +# rpmlink error, but will install the files in /usr/lib64/. +# OVN pacemaker ocf script file is copied in /usr/lib/ocf/resource.d/ovn/ +# and we are not sure if pacemaker looks into this path to find the +# OVN resource agent script. +%global ovnlibdir %{_prefix}/lib + +Name: %{pkgname} +Summary: Open Virtual Network support +Group: System Environment/Daemons +URL: http://www.openvswitch.org/ +Version: %{pkgver}.0 +Release: 39%{?commit0:.%{date}git%{shortcommit0}}%{?dist} +Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1 + +# Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the +# lib/sflow*.[ch] files are SISSL +License: ASL 2.0 and LGPLv2+ and SISSL + +%if 0%{?commit0:1} +Source: https://github.com/ovn-org/ovn/archive/%{commit0}.tar.gz#/ovn-%{shortcommit0}.tar.gz +%else +# Upstream version is called 20.03, not 2.13. Once we switch to using the +# same versioning scheme for RH, we can reference %{version} here. +# XXX Are OVN releases listed on openvswitch.org? +Source: https://www.openvswitch.org/releases/ovn-%{version}.tar.gz +%endif + + +%define ovsver %{version} + +%if 0%{?commit1:1} +Source10: https://github.com/openvswitch/ovs/archive/%{commit1}.tar.gz#/openvswitch-%{shortcommit1}.tar.gz +%define ovsdir ovs-%{commit1} +%else +Source10: https://openvswitch.org/releases/openvswitch-%{ovsver}.tar.gz +%define ovsdir openvswitch-%{ovsver} +%endif + +%define docutilsver 0.12 +%define pygmentsver 1.4 +%define sphinxver 1.1.3 +Source100: https://pypi.io/packages/source/d/docutils/docutils-%{docutilsver}.tar.gz +Source101: https://pypi.io/packages/source/P/Pygments/Pygments-%{pygmentsver}.tar.gz +Source102: https://pypi.io/packages/source/S/Sphinx/Sphinx-%{sphinxver}.tar.gz + +Source500: configlib.sh +Source501: gen_config_group.sh +Source502: set_config.sh + +# Important: source503 is used as the actual copy file +# @TODO: this causes a warning - fix it? +Source504: arm64-armv8a-linuxapp-gcc-config +Source505: ppc_64-power8-linuxapp-gcc-config +Source506: x86_64-native-linuxapp-gcc-config + +# ovn-patches + +# OVN (including OVS if required) backports (0 - 399) +# Bug 1812038 +Patch0: 0001-system-tests-Fix-occasional-failure-of-the-test-Load.patch +Patch1: 0002-Broadcast-DHCPREPLY-when-BROADCAST-flag-is-set.patch +Patch2: 0003-logical-fields-fix-memory-leak-caused-by-initialize-.patch + +# Bug 1813046 +Patch10: 0001-ovn-northd-Add-lflows-to-by-pass-the-svc-monitor-pac.patch + +# Bug 1816087 +Patch20: 0001-ovn-northd-Don-t-add-arp-responder-flows-for-lports-.patch + +# Bug 1816616 +Patch30: 0001-ovn-northd-Forward-ARP-requests-on-localnet-ports.patch +Patch31: 0001-ovn.at-Fix-ARP-test-that-fails-due-to-timing.patch + +# Bug 1815217 +Patch040: 0001-northd-do-not-insert-identical-lflows-in-S_ROUTER_IN.patch +Patch041: 0002-ovn-northd-Skip-unsnat-flows-for-load-balancer-vips-.patch + +# Bug 1819604 +Patch050: 0001-ovn-controller-Fix-potential-segfault-with-virtual-p.patch +Patch051: 0001-ovn-controller-Skip-vport-bindings-done-through-OVS-.patch + +# Bug 1718372 +Patch060: 0001-Add-external_ids-column-for-tables-in-nb-schema.patch +Patch061: 0001-Add-SCTP-support-to-load-balancers.patch + +# Bug 1815009 +Patch070: 0001-controller-use-LLA-IPv6-address-as-NS-source-address.patch + +# Bug 1822859 +Patch080: 0001-ovn-ctl-Provide-the-option-to-configure-inactive-pro.patch + +# Bug 1823226 +Patch090: 0001-tests-Wait-up-to-OVS_CTL_TIMEOUT-seconds.patch +Patch091: 0002-controller-Add-ipv6-prefix-delegation-state-machine.patch +Patch092: 0003-northd-Add-logical-flows-for-dhcpv6-pfd-parsing.patch + +# Bug 1778016 +Patch100: 0001-ovn-nbctl-Create-daemon-control-socket-in-ovn-run-di.patch + +# Bug 1801058 +Patch110: 0001-pinctrl-Handle-service-monitors-even-if-the-lport-do.patch + +# Bug 1825334 +Patch120: 0001-ovn-northd-Limit-IPv6-ND-NS-RA-RS-to-the-local-netwo.patch + +# Bug 1819069 +# Bug 1778016 +Patch130: 0001-DNS-Make-DNS-lookups-case-insensitive.patch +Patch131: 0002-Create-daemon-pidfiles-in-ovn-run-dir.patch + +# Bug 1819785 +Patch140: 0001-Fix-conntrack-entry-leaks-because-of-TCP-RST-packets.patch + +# Bug 1827403 +Patch150: 0001-ovn-northd-Optimize-flows-for-LB-Hairpin-traffic.patch + +# Bug 1817606 +Patch160: 0001-Rely-on-unique-name-for-ovn-qos-meters.patch + +# Bug 1826623 +Patch170: 0001-IPv6-PD-assume-status-to-be-Success-if-not-present.patch + +# Bug 1827090 +Patch180: 0001-IPv6-PD-time-parameter-checks.patch + +# Bug 1828637 +Patch190: 0001-ovn-northd-Clear-SB-records-depending-on-stale-datap.patch +Patch191: 0002-ovn-northd-Fix-tunnel_key-allocation-for-SB-Port_Bin.patch + +# Bug 1826683 and 1827084 +Patch200: 0001-Disable-IPv6-prefix-reporting-if-IPv6-PD-is-disabled.patch +Patch201: 0002-controller-Add-garbage-collector-for-ipv6_prefixd.patch +Patch202: 0003-IPv6-PD-Disable-pd-processing-if-the-router-port-is-.patch + +# Bug 1823755 +Patch210: 0001-Fix-ACL-reject-action-for-UDP-packets.patch + +# Bug 1707513 +# Bug 1825073 +Patch220: 0001-controller-Use-OpenFlow-version-1.5.patch +Patch221: 0002-ovn-northd-Fix-memory-leak-and-incorrect-limiting-of.patch +Patch222: 0003-Support-selection-fields-in-load-balancer.patch +Patch223: 0004-tests-Fix-occasional-failures-for-test-85.patch + +# Bug 1834655 +Patch230: 0001-pinctrl-Fix-icmp6-packet-corruption-issue.patch + +# Bug 1827769 +Patch240: 0001-ovn-northd-Fix-leak-of-lport-addresses-during-DHCPv6.patch +Patch241: 0002-ovn-northd-Fix-memory-leak-in-case-of-duplicate-logi.patch + +# Bug 1779854 +Patch250: 0001-ofctrl-Split-large-group_mod-messages-up.patch + +# Bug 1836976 +Patch260: 0001-ovn-northd-Remove-useless-flow-for-GW_REDIRECT.patch +Patch261: 0002-Revert-Manage-ARP-process-locally-in-a-DVR-scenario.patch +Patch262: 0003-controller-fix-ip-buffering-with-static-routes.patch +Patch263: 0004-northd-manage-ARP-request-locally-for-FIP-traffic.patch + +# Bug 1843512 +Patch270: 0001-Make-the-notify-calls-work-with-IPv6-in-the-OCF-reso.patch + +# Bug 1832176 +# Bug 1804576 +Patch280: 0001-Fix-ovn-controller-generated-packets-from-getting-dr.patch +Patch281: 0002-Honour-router_preference-for-solicited-RA.patch + +# Bug 1848398 +Patch290: 0001-northd-By-pass-IPv6-Router-Adv-and-Router-Solicitati.patch + +# Bug 1818128 +Patch300: 0001-Split-SB-Port_Group-per-datapath.patch + +# Bug 1849162 +Patch310: 0001-ovn-northd-Fix-the-missing-lflow-issue-in-LS_OUT_PRE.patch + +# OpenvSwitch backports (800-) if required. +Patch800: 0001-Revert-ovsdb-idl-Avoid-sending-redundant-conditional.patch + +Patch810: 0003-ovsdb-idl-Try-committing-the-pending-txn-in-ovsdb_id.patch + +# Bug 1808580 +Patch820: 0001-ovsdb-idl-Avoid-inconsistent-IDL-state-with-OVSDB_MO.patch + +# FIXME Sphinx is used to generate some manpages, unfortunately, on RHEL, it's +# in the -optional repository and so we can't require it directly since RHV +# doesn't have the -optional repository enabled and so TPS fails +%if %{external_sphinx} +BuildRequires: python3-sphinx +%else +# Sphinx dependencies +BuildRequires: python-devel +BuildRequires: python-setuptools +#BuildRequires: python2-docutils +BuildRequires: python-jinja2 +BuildRequires: python-nose +#BuildRequires: python2-pygments +# docutils dependencies +BuildRequires: python-imaging +# pygments dependencies +BuildRequires: python-nose +%endif + +BuildRequires: gcc gcc-c++ make +BuildRequires: autoconf automake libtool +BuildRequires: systemd-units openssl openssl-devel +BuildRequires: python3-devel python3-setuptools +BuildRequires: desktop-file-utils +BuildRequires: groff-base graphviz +BuildRequires: unbound-devel + +# make check dependencies +BuildRequires: procps-ng +%if 0%{?rhel} > 7 || 0%{?fedora} +BuildRequires: python3-pyOpenSSL +%endif + +%if %{with libcapng} +BuildRequires: libcap-ng libcap-ng-devel +%endif + +Requires: hostname openssl iproute module-init-tools + +Requires(post): systemd-units +Requires(preun): systemd-units +Requires(postun): systemd-units + +# to skip running checks, pass --without check +# Disable Tests due to https://bugs.centos.org/view.php?id=16969, tests failing +# as build is running on CentOS7 builder, once builders are CentOS8 based tests can +# be re enabled. +%bcond_with check + +%description +OVN, the Open Virtual Network, is a system to support virtual network +abstraction. OVN complements the existing capabilities of OVS to add +native support for virtual network abstractions, such as virtual L2 and L3 +overlays and security groups. + +%package central +Summary: Open Virtual Network support +License: ASL 2.0 +Requires: %{pkgname} +Requires: firewalld-filesystem +Provides: openvswitch%{pkgver}-ovn-central = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-central < 2.11.0-1 + +%description central +OVN DB servers and ovn-northd running on a central node. + +%package host +Summary: Open Virtual Network support +License: ASL 2.0 +Requires: %{pkgname} +Requires: firewalld-filesystem +Provides: openvswitch%{pkgver}-ovn-host = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-host < 2.11.0-1 + +%description host +OVN controller running on each host. + +%package vtep +Summary: Open Virtual Network support +License: ASL 2.0 +Requires: %{pkgname} +Provides: openvswitch%{pkgver}-ovn-vtep = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-vtep < 2.11.0-1 + +%description vtep +OVN vtep controller + +%prep +%if 0%{?commit0:1} +%autosetup -n ovn-%{commit0} -a 10 -p 1 +%else +%autosetup -n ovn-%{version} -a 10 -p 1 +%endif + +%build +%if 0%{?commit0:1} +# fix the snapshot unreleased version to be the released one. +sed -i.old -e "s/^AC_INIT(openvswitch,.*,/AC_INIT(openvswitch, %{version},/" configure.ac +%endif +./boot.sh + +# OVN source code is now separate. +# Build openvswitch first. +# XXX Current openvswitch2.13 doesn't +# use "2.13.0" for version. It's a commit hash +pushd %{ovsdir} +./boot.sh +%configure \ +%if %{with libcapng} + --enable-libcapng \ +%else + --disable-libcapng \ +%endif + --enable-ssl \ + --with-pkidir=%{_sharedstatedir}/openvswitch/pki + +make %{?_smp_mflags} +popd + +# Build OVN. +# XXX OVS version needs to be updated when ovs2.13 is updated. +%configure \ + --with-ovs-source=$PWD/%{ovsdir} \ +%if %{with libcapng} + --enable-libcapng \ +%else + --disable-libcapng \ +%endif + --enable-ssl \ + --with-pkidir=%{_sharedstatedir}/openvswitch/pki + +make %{?_smp_mflags} + +%install +%make_install +install -p -D -m 0644 \ + rhel/usr_share_ovn_scripts_systemd_sysconfig.template \ + $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/ovn + +for service in ovn-controller ovn-controller-vtep ovn-northd; do + install -p -D -m 0644 \ + rhel/usr_lib_systemd_system_${service}.service \ + $RPM_BUILD_ROOT%{_unitdir}/${service}.service +done + +install -d -m 0755 $RPM_BUILD_ROOT/%{_sharedstatedir}/ovn + +install -d $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ +install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-central-firewall-service.xml \ + $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml +install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-host-firewall-service.xml \ + $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml + +install -d -m 0755 $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn +ln -s %{_datadir}/ovn/scripts/ovndb-servers.ocf \ + $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers + +install -p -D -m 0644 rhel/etc_logrotate.d_ovn \ + $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/ovn + +# remove unneeded files. +rm -f $RPM_BUILD_ROOT%{_bindir}/ovs* +rm -f $RPM_BUILD_ROOT%{_bindir}/vtep-ctl +rm -f $RPM_BUILD_ROOT%{_sbindir}/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man1/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man5/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man5/vtep* +rm -f $RPM_BUILD_ROOT%{_mandir}/man7/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man8/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man8/vtep* +rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/python +rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovs* +rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/bugtool-plugins +rm -f $RPM_BUILD_ROOT%{_libdir}/*.a +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la +rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/*.pc +rm -f $RPM_BUILD_ROOT%{_includedir}/ovn/* +rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash +rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash +rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/openvswitch +rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovn-bugtool* +rm -f $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-overlay-driver \ + $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-underlay-driver + +%check +%if %{with check} + touch resolv.conf + export OVS_RESOLV_CONF=$(pwd)/resolv.conf + if ! make check TESTSUITEFLAGS='%{_smp_mflags} -k ovn'; then + cat tests/testsuite.log + if ! make check TESTSUITEFLAGS='--recheck'; then + cat tests/testsuite.log + # Presently a test case - "2796: ovn -- ovn-controller incremental processing" + # is failing on aarch64 arch. Let's not exit for this arch + # until we figure out why it is failing. + # Test case 93: ovn.at:12105 ovn -- ACLs on Port Groups is failing + # repeatedly on s390x. This needs to be investigated. + %ifnarch aarch64 + %ifnarch ppc64le + %ifnarch s390x + exit 1 + %endif + %endif + %endif + fi + fi +%endif + +%clean +rm -rf $RPM_BUILD_ROOT + +%pre central +if [ $1 -eq 1 ] ; then + # Package install. + /bin/systemctl status ovn-northd.service >/dev/null + ovn_status=$? + rpm -ql openvswitch-ovn-central > /dev/null + if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then + # ovn-northd service is running which means old openvswitch-ovn-central + # is already installed and it will be cleaned up. So start ovn-northd + # service when posttrans central is called. + touch %{_localstatedir}/lib/rpm-state/ovn-northd + fi +fi + +%pre host +if [ $1 -eq 1 ] ; then + # Package install. + /bin/systemctl status ovn-controller.service >/dev/null + ovn_status=$? + rpm -ql openvswitch-ovn-host > /dev/null + if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then + # ovn-controller service is running which means old + # openvswitch-ovn-host is installed and it will be cleaned up. So + # start ovn-controller service when posttrans host is called. + touch %{_localstatedir}/lib/rpm-state/ovn-controller + fi +fi + +%pre vtep +if [ $1 -eq 1 ] ; then + # Package install. + /bin/systemctl status ovn-controller-vtep.service >/dev/null + ovn_status=$? + rpm -ql openvswitch-ovn-vtep > /dev/null + if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then + # ovn-controller-vtep service is running which means old + # openvswitch-ovn-vtep is installed and it will be cleaned up. So + # start ovn-controller-vtep service when posttrans host is called. + touch %{_localstatedir}/lib/rpm-state/ovn-controller-vtep + fi +fi + +%preun central +%if 0%{?systemd_preun:1} + %systemd_preun ovn-northd.service +%else + if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable ovn-northd.service >/dev/null 2>&1 || : + /bin/systemctl stop ovn-northd.service >/dev/null 2>&1 || : + fi +%endif + +%preun host +%if 0%{?systemd_preun:1} + %systemd_preun ovn-controller.service +%else + if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable ovn-controller.service >/dev/null 2>&1 || : + /bin/systemctl stop ovn-controller.service >/dev/null 2>&1 || : + fi +%endif + +%preun vtep +%if 0%{?systemd_preun:1} + %systemd_preun ovn-controller-vtep.service +%else + if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable ovn-controller-vtep.service >/dev/null 2>&1 || : + /bin/systemctl stop ovn-controller-vtep.service >/dev/null 2>&1 || : + fi +%endif + +%post +%if %{with libcapng} +if [ $1 -eq 1 ]; then + sed -i 's:^#OVN_USER_ID=:OVN_USER_ID=:' %{_sysconfdir}/sysconfig/ovn + sed -i 's:\(.*su\).*:\1 openvswitch openvswitch:' %{_sysconfdir}/logrotate.d/ovn +fi +%endif + +%post central +%if 0%{?systemd_post:1} + %systemd_post ovn-northd.service +%else + # Package install, not upgrade + if [ $1 -eq 1 ]; then + /bin/systemctl daemon-reload >dev/null || : + fi +%endif + +%post host +%if 0%{?systemd_post:1} + %systemd_post ovn-controller.service +%else + # Package install, not upgrade + if [ $1 -eq 1 ]; then + /bin/systemctl daemon-reload >dev/null || : + fi +%endif + +%post vtep +%if 0%{?systemd_post:1} + %systemd_post ovn-controller-vtep.service +%else + # Package install, not upgrade + if [ $1 -eq 1 ]; then + /bin/systemctl daemon-reload >dev/null || : + fi +%endif + +%postun + +%postun central +%if 0%{?systemd_postun_with_restart:1} + %systemd_postun_with_restart ovn-northd.service +%else + /bin/systemctl daemon-reload >/dev/null 2>&1 || : + if [ "$1" -ge "1" ] ; then + # Package upgrade, not uninstall + /bin/systemctl try-restart ovn-northd.service >/dev/null 2>&1 || : + fi +%endif + +%postun host +%if 0%{?systemd_postun_with_restart:1} + %systemd_postun_with_restart ovn-controller.service +%else + /bin/systemctl daemon-reload >/dev/null 2>&1 || : + if [ "$1" -ge "1" ] ; then + # Package upgrade, not uninstall + /bin/systemctl try-restart ovn-controller.service >/dev/null 2>&1 || : + fi +%endif + +%postun vtep +%if 0%{?systemd_postun_with_restart:1} + %systemd_postun_with_restart ovn-controller-vtep.service +%else + /bin/systemctl daemon-reload >/dev/null 2>&1 || : + if [ "$1" -ge "1" ] ; then + # Package upgrade, not uninstall + /bin/systemctl try-restart ovn-controller-vtep.service >/dev/null 2>&1 || : + fi +%endif + +%posttrans central +if [ $1 -eq 1 ]; then + # Package install, not upgrade + if [ -e %{_localstatedir}/lib/rpm-state/ovn-northd ]; then + rm %{_localstatedir}/lib/rpm-state/ovn-northd + /bin/systemctl start ovn-northd.service >/dev/null 2>&1 || : + fi +fi + + +%posttrans host +if [ $1 -eq 1 ]; then + # Package install, not upgrade + if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller ]; then + rm %{_localstatedir}/lib/rpm-state/ovn-controller + /bin/systemctl start ovn-controller.service >/dev/null 2>&1 || : + fi +fi + +%posttrans vtep +if [ $1 -eq 1 ]; then + # Package install, not upgrade + if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller-vtep ]; then + rm %{_localstatedir}/lib/rpm-state/ovn-controller-vtep + /bin/systemctl start ovn-controller-vtep.service >/dev/null 2>&1 || : + fi +fi + +%files +%{_bindir}/ovn-nbctl +%{_bindir}/ovn-sbctl +%{_bindir}/ovn-trace +%{_bindir}/ovn-detrace +%{_bindir}/ovn-appctl +%{_bindir}/ovn-ic-nbctl +%{_bindir}/ovn-ic-sbctl +%dir %{_datadir}/ovn/ +%dir %{_datadir}/ovn/scripts/ +%{_datadir}/ovn/scripts/ovn-ctl +%{_datadir}/ovn/scripts/ovn-lib +%{_datadir}/ovn/scripts/ovndb-servers.ocf +%{_mandir}/man8/ovn-ctl.8* +%{_mandir}/man8/ovn-appctl.8* +%{_mandir}/man8/ovn-nbctl.8* +%{_mandir}/man8/ovn-ic-nbctl.8* +%{_mandir}/man8/ovn-trace.8* +%{_mandir}/man1/ovn-detrace.1* +%{_mandir}/man7/ovn-architecture.7* +%{_mandir}/man8/ovn-sbctl.8* +%{_mandir}/man8/ovn-ic-sbctl.8* +%{_mandir}/man5/ovn-nb.5* +%{_mandir}/man5/ovn-ic-nb.5* +%{_mandir}/man5/ovn-sb.5* +%{_mandir}/man5/ovn-ic-sb.5* +%dir %{ovnlibdir}/ocf/resource.d/ovn/ +%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers +%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/logrotate.d/ovn +%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/ovn + +%files central +%{_bindir}/ovn-northd +%{_bindir}/ovn-ic +%{_mandir}/man8/ovn-northd.8* +%{_mandir}/man8/ovn-ic.8* +%{_datadir}/ovn/ovn-nb.ovsschema +%{_datadir}/ovn/ovn-ic-nb.ovsschema +%{_datadir}/ovn/ovn-sb.ovsschema +%{_datadir}/ovn/ovn-ic-sb.ovsschema +%{_unitdir}/ovn-northd.service +%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml + +%files host +%{_bindir}/ovn-controller +%{_mandir}/man8/ovn-controller.8* +%{_unitdir}/ovn-controller.service +%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml + +%files vtep +%{_bindir}/ovn-controller-vtep +%{_mandir}/man8/ovn-controller-vtep.8* +%{_unitdir}/ovn-controller-vtep.service + +%changelog +* Wed Jul 08 2020 Numan Siddique - 2.13.0-39 +- Backport "ovn-northd: Fix the missing lflow issue in LS_OUT_PRE_LB." (#1849162) + +* Wed Jul 08 2020 Numan Siddique - 2.13.0-38 +- Backport "Split SB Port_Group per datapath." (#1818128) + +* Fri Jun 19 2020 Dumitru Ceara - 2.13.0-37 +- Backport "ovsdb-idl: Avoid inconsistent IDL state with OVSDB_MONITOR_V3." (#1808580) + +* Thu Jun 18 2020 Numan Siddique - 2.13.0-36 +- Backport "northd: By pass IPv6 Router Adv and Router Solicitation packets from ACL stages." (#1848398) + +* Thu Jun 18 2020 Numan Siddique - 2.13.0-35 +- Backport "Fix ovn-controller generated packets from getting dropped for reject ACL action." (#1832176) +- Backport "Honour router_preference for solicited RA" (#1804576) +- Backport "ovsdb idl: Try committing the pending txn in ovsdb_idl_loop_run." + +* Mon Jun 08 2020 Numan Siddique - 2.13.0-34 +- Backport "Make the notify() calls work with IPv6 in the OCF resource-agent" (#1843512) + +* Fri Jun 5 2020 Lorenzo Bianconi - 2.13.0-33 +- Backport "ovn-northd: Remove useless flow for GW_REDIRECT" (#1836976) +- Backport "Revert "Manage ARP process locally in a DVR scenario" (#1836976) +- Backport "controller: fix ip buffering with static routes" (#1836976) +- Backport "northd: manage ARP request locally for FIP traffic" (#1836976) + +* Tue Jun 02 2020 Mark Michelson - 2.13.0-32 +- No change. Just bumping revision to appease errata system. + +* Fri May 15 2020 Mark Michelson - 2.13.0-31 +- Backport "ofctrl: Split large group_mod messages up." (#1779854) + +* Tue May 12 2020 Numan Siddique - 2.13.0-30 +- Backport "ovn-northd: Fix leak of lport addresses during DHCPv6 reply handling." (#1827769) +- Backport "ovn-northd: Fix memory leak in case of duplicate logical router port." (#1827769) + +* Tue May 12 2020 Numan Siddique - 2.13.0-29 +- Backport "pinctrl: Fix icmp6 packet corruption issue" (#1834655) + +* Sun May 10 2020 Numan Siddique - 2.13.0-28 +- Backport "controller: Use OpenFlow version 1.5" (#1825073, #1707513) +- Backport "ovn-northd: Fix memory leak and incorrect limiting of ECMP routes." +- Backport "Support selection fields in load balancer." (#1825073, #1707513) +- Backport "tests: Fix occasional failures for test 85." + +* Wed May 06 2020 Numan Siddique - 2.13.0-27 +- Backport "Fix ACL reject action for UDP packets." (#1823755) + +* Mon May 04 2020 Lorenzo Bianconi - 2.13.0-26 +- Backport "0001-Disable-IPv6-prefix-reporting-if-IPv6-PD-is-disabled.patch" (#1826683) +- Backport "0002-controller-Add-garbage-collector-for-ipv6_prefixd.patch" (#1827084) +- Backport "0003-IPv6-PD-Disable-pd-processing-if-the-router-port-is-.patch" (#1827084) + +* Mon May 04 2020 Dumitru Ceara - 2.13.0-25 +- Backport "ovn-northd: Clear SB records depending on stale datapaths." (#1828637) +- Backport "ovn-northd: Fix tunnel_key allocation for SB Port_Bindings." (#1828637) + +* Mon May 04 2020 Lorenzo Bianconi - 2.13.0-24 +- Backport "IPv6 PD: time parameter checks" (#1827090) + +* Mon May 04 2020 Lorenzo Bianconi - 2.13.0-23 +- Backport "IPv6 PD: assume status to be Success if not present" (#1826623) + +* Wed Apr 29 2020 Lorenzo Bianconi - 2.13.0-22 +- Backport "Rely on unique name for ovn qos meters" (#1817606) + +* Tue Apr 28 2020 Dumitru Ceara - 2.13.0-21 +- Backport "ovn-northd: Optimize flows for LB Hairpin traffic." (#1827403) + +* Mon Apr 27 2020 Numan Siddique - 2.13.0-20 +- Backport "Fix conntrack entry leaks because of TCP RST packets not sent to conntrack." (#1819785) + +* Mon Apr 27 2020 Numan Siddique - 2.13.0-19 +- Backport "DNS: Make DNS lookups case insensitive." (#1819069) +- Backport "Create daemon pidfiles in ovn run dir." (#1778016) + +* Mon Apr 20 2020 Numan Siddique - 2.13.0-18 +- Backport "ovn-northd: Limit IPv6 ND NS/RA/RS to the local network." (#1825334) + +* Sat Apr 18 2020 Numan Siddique - 2.13.0-17 +- Backport "pinctrl: Handle service monitors even if the lport doesn't have IPv4 addresses set." (#1801058) + +* Fri Apr 17 2020 Numan Siddique - 2.13.0-16 +- Backport "ovn-nbctl: Create daemon control socket in ovn run dir". (#1778016) + +* Sun Apr 12 2020 Lorenzo Bianconi - 2.13.0-15 +- Backport "OVN - Support IPv6 Prefix Delegation" (#1823226) + +* Fri Apr 10 2020 Numan Siddique - 2.13.0-14 +- Backport "ovn-ctl: Provide the option to configure inactive probe from standby to active". (#1822859) + +* Thu Apr 09 2020 Dumitru Ceara - 2.13.0-13 +- Backport "ovn-controller: Skip vport bindings done through OVS external_ids:iface-id." (#1819604) + +* Thu Apr 02 2020 Lorenzo Bianconi - 2.13.0-12 +- Backport "controller: use LLA IPv6 address as NS source address" (#1815009) + +* Wed Apr 01 2020 Dumitru Ceara - 2.13.0-11 +- Backport "Add SCTP support to Load Balancers" (#1718372) +- Also backport "Add external_ids column for tables in nb schema" to avoid + conflicts. + +* Wed Apr 01 2020 Dumitru Ceara - 2.13.0-10 +- Backport "ovn-controller: Fix potential segfault with "virtual" port bindings." (#1819604) + +* Mon Mar 30 2020 Numan Siddique - 2.13.0-9 +- Backport "ovn-northd: Skip unsnat flows for load balancer vips in router ingress pipeline" (#1815217) +- Backport "northd: do not insert identical lflows in S_ROUTER_IN_ARP_RESOLVE" (required for #1815217) + +* Mon Mar 30 2020 Dumitru Ceara - 2.13.0-8 +- Backport "Revert "ovsdb-idl: Avoid sending redundant conditional monitoring updates"" (#1818754) + +* Tue Mar 24 2020 Dumitru Ceara - 2.13.0-7 +- Backport "ovn.at: Fix ARP test that fails due to timing." (#1816616) + +* Tue Mar 24 2020 Dumitru Ceara - 2.13.0-6 +- Backport "ovn-northd: Forward ARP requests on localnet ports." (#1816616) + +* Mon Mar 23 2020 Numan Siddique - 2.13.0-5 +- Backport "ovn-northd: Don't add arp responder flows for lports with 'unknown' address." (#1816087) + +* Fri Mar 13 2020 Numan Siddique - 2.13.0-4 +- Backport "ovn-northd: Add lflows to by pass the svc monitor packets from conntrack". (#1813046) + +* Tue Mar 10 2020 Numan Siddique - 2.13.0-3 +- Backport "Broadcast DHCPREPLY when BROADCAST flag is set" (#1812038) +- Also backported 2 other patches to sync with 20.03 (to fix the sparse compilation issue) + +* Wed Mar 04 2020 Numan Siddique - 2.13.0-2 +- Update to use openvswitch-2.13.0.tar.gz from v2.13.0 tag. + +* Tue Mar 03 2020 Mark Michelson - 2.13.0-1 +- Update to upstream release of OVN 20.03.0 + +* Tue Feb 18 2020 Open vSwitch Bot - 2.13.0-0.20200217git7886ac9 +- Snapshot of branch-20.03 7886ac9ed807 + +* Mon Feb 10 2020 Mark Michelson - 2.13.0-0 +* Initial repository setup using snapshot build of OVN 20.03 branch + +* Tue Feb 4 2020 Numan Siddique - 2.12.0-27 +* Backport "ovn-northd: Address scale issues with DNAT flows." (#1798173) + +* Thu Jan 30 2020 Numan Siddique - 2.12.0-26 +* Backport "[RFE] LB health check : ovn-northd: Consider load balancer active backends in router pipeline" (#1703162) + +* Fri Jan 24 2020 Dumitru Ceara - 2.12.0-25 +* Backport "tests: Updated expected log message" (#1794671) + +* Thu Jan 16 2020 Mark Michelson - 2.12.0-24 +- Backport "nbctl: Log the source of duplicate IP addresses" (#1794671) +- Backport "northd: Log all dynamic address assignments" (#1794671) +- Backport "northd: Load config before processing nbdb contents" (#1794671) + +* Fri Jan 10 2020 Numan Siddique - 2.12.0-23 +- Backport "ovn-controller: Don't monitor connection table columns" +- Backport "Restrict ARP/IPv6 ND replies for LB VIP only on chassis redirect port" (#1788456) + +* Thu Jan 09 2020 Lorenzo Bianconi - 2.12.0-22 +- Backport "pinctrl.c: Fix maybe-uninitialized warnings with old GCC versions" (#1789476) +- Backport "DNSSL: copy dnssl string in order to avoid truncated value" (#1789476) +- Backport "RA Route Info Option: copy route info string in order to avoid truncated value" (#1789476) + +* Thu Jan 02 2020 Dumitru Ceara - 2.12.0-21 +- Backport "ovn-controller: Run I-P engine even when no SB txn is available." (#1787360) + +* Thu Jan 02 2020 Dumitru Ceara - 2.12.0-20 +- Backport "ovn-controller: Refactor I-P engine_run() tracking." (#1787318) +- Backport "ovn-controller: Add per node states to I-P engine." (#1787318) +- Backport "ovn-controller: Add separate I-P engine node for processing ct-zones." (#1787318) +- Backport "ovn-controller.c: Fix memory leak of local_datapath->ports." +- Backport "ovn-controller: Fix use of dangling pointers in I-P runtime_data." (#1787318) + +* Thu Dec 05 2019 Numan Siddique - 2.12.0-19 +- Backport "[RFE] Support for load balancing health checks in OVN" (#1703162) +- Backport "Stateless NAT support (backported due to conflicts)" + +* Tue Dec 03 2019 Lorenzo Bianconi - 2.12.0-18 +- Backport "Add support to Default Router Preference (PRF) - RFC4191" (#1769849) +- Backport "Add support for Route Info Option in RA - RFC4191" + +* Tue Dec 3 2019 Dumitru Ceara - 2.12.0-17 +- Backport "ovn-controller: Consider non-virtual ports first when updating bindings." (#1779110) +- Backport "ovn-controller: Add missing port group lflow references." (#1779115) +- Backport "ovn-controller: Add command to trigger an I-P full recompute." (#1779121) + +* Tue Nov 26 2019 Dumitru Ceara - 2.12.0-16 +- Backport "ovn-northd: Fix get_router_load_balancer_ips() for mixed address families." +- Backport "ovn-northd: Limit ARP/ND broadcast domain whenever possible." (#1776712) +- Backport "ovn-northd: Avoid empty address list when limiting ARP/ND broadcast." (#1776712) + +* Wed Nov 20 2019 Numan Siddique - 2.12.0-15 +- Backport "Skip IPv6 NS packets in router egress SNAT pipeline" (#1773605) +- Backport "northd: Match IPv4 or IPv6 for MAC resolution" + +* Tue Nov 19 2019 Dumitru Ceara - 2.12.0-14 +- Backport "Fix virtual port binding when the parents are scheduled in the same chassis" (#1762341) + +* Mon Nov 18 2019 Lorenzo Bianconi - 2.12.0-13 +- Backport "Add DNSSL support to OVN" (#1764718) + +* Mon Nov 18 2019 Lorenzo Bianconi - 2.12.0-12 +- Backport "Add RDNSS support to OVN" (#1699332) + +* Fri Nov 15 2019 Mark Michelson - 2.12.0-11 +- Update user of logrotate file to be "openvswitch" + +* Fri Nov 15 2019 Mark Michelson - 2.12.0-10 +- Update verification of sysconfig and logrotate files + +* Wed Nov 13 2019 Numan Siddique - 2.12.0-9 +- Backport "Support IPv6 NAT" (#1768347) +- Backport "Add IPv6 load balancer tests in OVN" (#1768477) + +* Mon Nov 11 2019 Dumitru Ceara - 2.12.0-8 +- Backport "lflow.c: Fix memory leak of lflow_ref_list_node->ref_name." (#1770953) + +* Fri Nov 8 2019 Numan Siddique - 2.12.0-7 +- Backport: "ovn-ctl related changes" (#1770127) + +* Fri Nov 8 2019 Numan Siddique - 2.12.0-6 +- Backport: "Fix ha chassis failover issues for stale ha chassis entries" (#1762777) +- Backport: "ovn-northd: Validate dnat_and_snat external_mac/logical_ip. (#1769709) + +* Fri Nov 8 2019 Numan Siddique - 2.12.0-5 +- Backport: "ovndb-servers.ocf: Change from 'openvswitch' to 'ovn' in OVN_CTL_DEFAULT var" (#1770127) + +* Sun Nov 3 2019 Mark Michelson - 2.12.0-4 +- Backport "Revert conjunctive match removal patches" (#1764032) +- Backport "Combine conjunctions with identical matches into one" (#1764032) + +* Wed Oct 16 2019 Dumitru Ceara - 2.12.0-3 +- Backport: "ovn-northd: Fix IP multicast flooding to mrouter." (#1757714) + +* Sun Oct 13 2019 Numan Siddique - 2.12.0-2 +- Backport: "ovn-ctl: Create etcdir when starting ovsdb servers" (#1761182) + +* Thu Oct 10 2019 Numan Siddique - 2.12.0-1 +- Update to OVN master from new repo with the commit 79308138891ae04a02a07068501696ef78157912 +- This will be the base for OVN 2.12. + +* Mon Aug 05 2019 Numan Siddique - 2.12.0-0.20190804git38a85a0 +- Snapshot build of ovn2.12 38a85a041dd8 + +* Mon Aug 05 2019 Numan Siddique - 2.11.0-27 +- Backport ovn-northd pause/resume support (#1720728) + +* Wed Jul 17 2019 Lorenzo Bianconi - 2.11.0-26 +- Backport ovn uindling support (#1730759) + +* Wed Jul 17 2019 Numan Siddique - 2.11.0-25 +- Backport related to GARP handling for router ips (#1561880) + +* Tue Jul 9 2019 Lorenzo Bianconi - 2.11.0-24 +- Backport related to ip buffering with gw router port issue (#1728318) + +* Mon Jul 1 2019 Lorenzo Bianconi - 2.11.0-23 +- Backport "OVN: add the possibility to specify tunnel dst port" (#1720371) + +* Mon Jun 24 2019 Dumitru Ceara - 2.11.0-22 +- Backport "ovn-controller: Fix parsing of OVN tunnel IDs" (#1708131) + +* Mon Jun 24 2019 Numan Siddique - 2.11.0-21 +- Backport "ovn-nbctl.8.xml: Fix typo." (#1720194) + +* Mon Jun 17 2019 Numan Siddique - 2.11.0-20 +- Backport "ovn: Add support for DHCP option 15 - domain name" (#1721012) + +* Thu Jun 06 2019 Timothy Redaelli - 2.11.0-19 +- Avoid collisions during installation of sources in debuginfo package (#1717933) + +* Mon May 27 2019 Dumitru Ceara - 2.11.0-18 +- Backport "ovn: Properly set the index for chassis lookup" (#1698462) + +* Tue May 14 2019 Dumitru Ceara - 2.11.0-17 +- Backport "stopwatch: Free stopwatch packets after processing" (#1698462) + +* Fri Apr 26 2019 Numan Siddique - 2.11.0-16 +- Fix the ovn-northd sync issue with HA_Chassis group (#1666673) + +* Wed Apr 24 2019 Numan Siddique - 2.11.0-15 +- Backport "RFE: Limit Geneve to within Transport Zones" (#1702550) + +* Wed Apr 24 2019 Numan Siddique - 2.11.0-14 +- Backport "RFE: [OVN] Fragmentation support" (#1702331) + +* Sat Apr 20 2019 Numan Siddique - 2.11.0-13 +- Backport "RFE: OVN - Support Logical ports of type external" (#1666673) + +* Thu Apr 18 2019 Lorenzo Bianconi - 2.11.0-12 +- Backport "OVN: fix DVR Floating IP support" (#1701183) + +* Wed Apr 17 2019 Timothy Redaelli - 2.11.0-11 +- Add 'Obsoletes' to the old OVN openvswitch2.11 sub-packages to allow to upgrade from FDP.A + +* Wed Apr 17 2019 Lorenzo Bianconi - 2.11.0-10 +- Backport "OVN: add the possibility to configure a static IPv4/IPv6 address and dynamic MAC" + +* Tue Apr 16 2019 Timothy Redaelli - 2.11.0-9 +- Remove 'Obsoletes' lines like on openvswitch2.11 package + +* Tue Apr 16 2019 Numan Siddique - 2.11.0-8 +- Fix the 'Provides' to include '%pkgver' + +* Tue Mar 26 2019 Numan Siddique - 2.11.0-7 +- Backport Fixes for #1677616 (pinctrl thread) and fixes related to IPv6 RA." + +* Tue Mar 19 2019 Numan Siddique - 2.11.0-6 +- Removed ovn-common package and moved all the related files to main 'ovn' package. + +* Tue Mar 19 2019 Timothy Redaelli - 2.11.0-5 +- Disable ovn-docker subpackage by default + +* Thu Mar 07 2019 Mark Michelson - 2.11.0-4 +- Backport "OVN: Add port addresses to IPAM after all ports are joined." + +* Sat Mar 02 2019 Numan Siddique - 2.11.0-3 +- Backport "ovn-controller: Provide the option to set the datapath-type of br-int" (#1684796) + +* Fri Mar 01 2019 Timothy Redaelli - 2.11.0-2 +- Backport "rhel: Use PIDFile on forking systemd service files" (#1684477) + +* Thu Feb 28 2019 Numan Siddique - 2.11.0-1 +- Update to official 2.11 release + +* Wed Jan 23 2019 Numan Siddique - 2.11.0-0.20190117git4e4f80e +- Update to OVS 2.11 branch + +* Thu Jan 17 2019 Numan Siddique - 2.11.0-0.20190117gitab66223 +- Update to a snapshot of OVS 2.11 from master + +* Thu Dec 20 2018 Numan Siddique +- OVS/OVN split. +