When a Logical_Router_Port has DHCP relay enabled and multiple IPv4 addresses configured, ovn-northd needs to pick one of them as the relay agent address (giaddr). This choice was hard-coded to lrp_networks.ipv4_addrs[0] which depends entirely on internal ordering.
The 'networks' column on Logical_Router_Port is an OVSDB set whose elements are sorted by strcmp() on the raw CIDR strings. This makes lrp_networks.ipv4_addrs[0] simply whichever CIDR sorts first as a string, which may not match the address intended as the "DHCP relay" address of the port. Add a new key 'options:dhcpv4_primary_ip' on Logical_Router_Port. When set, it must be an IPv4 host address that equals one of the port's configured addresses; ovn-northd then uses that address as the giaddr in all DHCP relay flows it emits for the port. When unset, behavior is unchanged: ovn-northd falls back to lrp_networks.ipv4_addrs[0] (whichever CIDR sorts first as a string), so existing deployments are unaffected on upgrade. If 'options:dhcpv4_primary_ip' is set but is not a valid IPv4 address or does not match any address in 'networks', ovn-northd treats it as a misconfiguration: it logs a warning and skips emitting DHCP relay flows for the port rather than silently falling back to the default address. Reported-by: Dumitru Ceara <[email protected]> Signed-off-by: Naveen Yerramneni <[email protected]> Acked-by: Aditya Mehakare <[email protected]> Acked-by: Huzaifa Calcuttawala <[email protected]> Acked-by: Lorenzo Bianconi <[email protected]> Assisted-by: Claude Opus 4.7, Cursor --- NEWS | 8 ++++ northd/northd.c | 99 +++++++++++++++++++++++++++++++++-------- ovn-nb.xml | 24 ++++++++++ tests/ovn-northd.at | 104 ++++++++++++++++++++++++++++++++++++++------ 4 files changed, 202 insertions(+), 33 deletions(-) diff --git a/NEWS b/NEWS index b233ee01a..e22c983c2 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,13 @@ Post v26.03.0 ------------- + - Logical_Router_Port: Added a new "options:dhcpv4_primary_ip" key + that selects which of the port's IPv4 addresses ovn-northd uses as + the relay agent address (giaddr) in relayed DHCP packets. When + unset, ovn-northd picks the same address it picked before + (whichever CIDR in "networks" sorts first as a string), so + existing deployments are unaffected; deployments that need a + specific address on a multi-IP port can pin it via the new + option. - OVN Interconnection now supports advertising Address_Sets to remote availability zones. Set options:ic-adv=true on an NB Address_Set to have ovn-ic publish it to the IC-SB database and import it into the diff --git a/northd/northd.c b/northd/northd.c index 4ca9820d4..b00141ae4 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -10209,6 +10209,9 @@ ls_dhcp_relay_port(const struct ovn_datapath *od) return smap_get(&od->nbs->other_config, "dhcp_relay_port"); } +static const struct ipv4_netaddr *lrp_get_dhcpv4_primary_ip( + const struct ovn_port *op); + static void build_lswitch_dhcp_relay_flows(struct ovn_port *op, const struct hmap *ls_ports, @@ -10248,6 +10251,12 @@ build_lswitch_dhcp_relay_flows(struct ovn_port *op, return; } + /* Resolve the LRP's DHCPv4 primary IP (giaddr). */ + const struct ipv4_netaddr *lrp_ipv4_addr = lrp_get_dhcpv4_primary_ip(rp); + if (!lrp_ipv4_addr) { + return; + } + char *server_ip_str = NULL; uint16_t port; int addr_family; @@ -10271,8 +10280,7 @@ build_lswitch_dhcp_relay_flows(struct ovn_port *op, "ip4.src == {0.0.0.0, %s/%u} && ip4.dst == 255.255.255.255 && " "udp.src == 68 && udp.dst == 67", op->json_key, op->lsp_addrs[0].ea_s, - rp->lrp_networks.ipv4_addrs[0].network_s, - rp->lrp_networks.ipv4_addrs[0].plen); + lrp_ipv4_addr->network_s, lrp_ipv4_addr->plen); ds_put_format(actions, "eth.dst = %s; outport = %s; next; /* DHCP_RELAY_REQ */", rp->lrp_networks.ea_s, sp->json_key); @@ -16901,6 +16909,59 @@ build_dhcpv6_reply_flows_for_lrouter_port( } } +/* Resolve the LRP's DHCPv4 "primary" IPv4 address - the address used + * by DHCP relay as the relay agent address (giaddr) in relayed DHCP + * packets on this port. + * + * If 'options:dhcpv4_primary_ip' is set, returns the entry from + * 'lrp_networks' whose address matches it. If the option is unset, + * returns lrp_networks.ipv4_addrs[0] - the first address from + * 'networks' in OVSDB sort order (set members are sorted by strcmp() + * on their string form). + * + * Returns NULL when the port has no IPv4 address at all, or when + * 'options:dhcpv4_primary_ip' is set but is not a valid IPv4 address + * or does not match any address on the port. Callers must skip + * emitting DHCP relay flows in those cases. + */ +static const struct ipv4_netaddr * +lrp_get_dhcpv4_primary_ip(const struct ovn_port *op) +{ + if (!op->lrp_networks.n_ipv4_addrs) { + return NULL; + } + + const char *primary_ip = smap_get(&op->nbrp->options, + "dhcpv4_primary_ip"); + + if (!primary_ip || !primary_ip[0]) { + return &op->lrp_networks.ipv4_addrs[0]; + } + + ovs_be32 primary_ip4; + if (!ip_parse(primary_ip, &primary_ip4)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, + "Logical_Router_Port %s: options:dhcpv4_primary_ip=%s " + "is not a valid IPv4 address.", + op->nbrp->name, primary_ip); + return NULL; + } + + for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + if (op->lrp_networks.ipv4_addrs[i].addr == primary_ip4) { + return &op->lrp_networks.ipv4_addrs[i]; + } + } + + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, + "Logical_Router_Port %s: options:dhcpv4_primary_ip=%s " + "does not match any address in 'networks'.", + op->nbrp->name, primary_ip); + return NULL; +} + static void build_dhcp_relay_flows_for_lrouter_port(struct ovn_port *op, struct lflow_table *lflows, @@ -16925,6 +16986,12 @@ build_dhcp_relay_flows_for_lrouter_port(struct ovn_port *op, return; } + /* Resolve the LRP's DHCPv4 primary IP (giaddr). */ + const struct ipv4_netaddr *lrp_ipv4_addr = lrp_get_dhcpv4_primary_ip(op); + if (!lrp_ipv4_addr) { + return; + } + int addr_family; /* currently not supporting custom port, * dhcp server port is always set to 67 when installing flows */ @@ -16948,14 +17015,12 @@ build_dhcp_relay_flows_for_lrouter_port(struct ovn_port *op, match, "inport == %s && " "ip4.src == {0.0.0.0, %s/%u} && ip4.dst == 255.255.255.255 && " "ip.frag == 0 && udp.src == 68 && udp.dst == 67", - op->json_key, - op->lrp_networks.ipv4_addrs[0].network_s, - op->lrp_networks.ipv4_addrs[0].plen); + op->json_key, lrp_ipv4_addr->network_s, lrp_ipv4_addr->plen); ds_put_format(actions, REGBIT_DHCP_RELAY_REQ_CHK " = dhcp_relay_req_chk(%s, %s);" "next; /* DHCP_RELAY_REQ */", - op->lrp_networks.ipv4_addrs[0].addr_s, server_ip_str); + lrp_ipv4_addr->addr_s, server_ip_str); ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110, ds_cstr(match), ds_cstr(actions), lflow_ref, @@ -16972,13 +17037,11 @@ build_dhcp_relay_flows_for_lrouter_port(struct ovn_port *op, "ip4.src == {0.0.0.0, %s/%u} && ip4.dst == 255.255.255.255 && " "udp.src == 68 && udp.dst == 67 && " REGBIT_DHCP_RELAY_REQ_CHK, - op->json_key, - op->lrp_networks.ipv4_addrs[0].network_s, - op->lrp_networks.ipv4_addrs[0].plen); + op->json_key, lrp_ipv4_addr->network_s, lrp_ipv4_addr->plen); ds_put_format(actions, "ip4.src = %s; ip4.dst = %s; udp.src = 67; next; " "/* DHCP_RELAY_REQ */", - op->lrp_networks.ipv4_addrs[0].addr_s, server_ip_str); + lrp_ipv4_addr->addr_s, server_ip_str); ovn_lflow_add(lflows, op->od, S_ROUTER_IN_DHCP_RELAY_REQ, 100, ds_cstr(match), ds_cstr(actions), lflow_ref, @@ -16992,9 +17055,7 @@ build_dhcp_relay_flows_for_lrouter_port(struct ovn_port *op, "ip4.src == {0.0.0.0, %s/%u} && ip4.dst == 255.255.255.255 && " "udp.src == 68 && udp.dst == 67 && " REGBIT_DHCP_RELAY_REQ_CHK" == 0", - op->json_key, - op->lrp_networks.ipv4_addrs[0].network_s, - op->lrp_networks.ipv4_addrs[0].plen); + op->json_key, lrp_ipv4_addr->network_s, lrp_ipv4_addr->plen); ds_put_format(actions, "drop; /* DHCP_RELAY_REQ */"); ovn_lflow_add(lflows, op->od, S_ROUTER_IN_DHCP_RELAY_REQ, 1, @@ -17007,7 +17068,7 @@ build_dhcp_relay_flows_for_lrouter_port(struct ovn_port *op, ds_put_format( match, "ip4.src == %s && ip4.dst == %s && " "ip.frag == 0 && udp.src == 67 && udp.dst == 67", - server_ip_str, op->lrp_networks.ipv4_addrs[0].addr_s); + server_ip_str, lrp_ipv4_addr->addr_s); ds_put_format(actions, "next; /* DHCP_RELAY_RESP */"); ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110, ds_cstr(match), ds_cstr(actions), lflow_ref, @@ -17019,12 +17080,12 @@ build_dhcp_relay_flows_for_lrouter_port(struct ovn_port *op, ds_put_format( match, "ip4.src == %s && ip4.dst == %s && " "udp.src == 67 && udp.dst == 67", - server_ip_str, op->lrp_networks.ipv4_addrs[0].addr_s); + server_ip_str, lrp_ipv4_addr->addr_s); ds_put_format(actions, REG_DHCP_RELAY_DIP_IPV4" = ip4.dst; " REGBIT_DHCP_RELAY_RESP_CHK " = dhcp_relay_resp_chk(%s, %s); next; /* DHCP_RELAY_RESP */", - op->lrp_networks.ipv4_addrs[0].addr_s, server_ip_str); + lrp_ipv4_addr->addr_s, server_ip_str); ovn_lflow_add(lflows, op->od, S_ROUTER_IN_DHCP_RELAY_RESP_CHK, 100, ds_cstr(match), ds_cstr(actions), lflow_ref, @@ -17042,11 +17103,11 @@ build_dhcp_relay_flows_for_lrouter_port(struct ovn_port *op, REG_DHCP_RELAY_DIP_IPV4" == %s && " "udp.src == 67 && udp.dst == 67 && " REGBIT_DHCP_RELAY_RESP_CHK, - server_ip_str, op->lrp_networks.ipv4_addrs[0].addr_s); + server_ip_str, lrp_ipv4_addr->addr_s); ds_put_format(actions, "ip4.src = %s; udp.dst = 68; " "outport = %s; output; /* DHCP_RELAY_RESP */", - op->lrp_networks.ipv4_addrs[0].addr_s, op->json_key); + lrp_ipv4_addr->addr_s, op->json_key); ovn_lflow_add(lflows, op->od, S_ROUTER_IN_DHCP_RELAY_RESP, 100, ds_cstr(match), ds_cstr(actions), lflow_ref, WITH_HINT(&op->nbrp->header_)); @@ -17058,7 +17119,7 @@ build_dhcp_relay_flows_for_lrouter_port(struct ovn_port *op, REG_DHCP_RELAY_DIP_IPV4" == %s && " "udp.src == 67 && udp.dst == 67 && " REGBIT_DHCP_RELAY_RESP_CHK" == 0", - server_ip_str, op->lrp_networks.ipv4_addrs[0].addr_s); + server_ip_str, lrp_ipv4_addr->addr_s); ds_put_format(actions, "drop; /* DHCP_RELAY_RESP */"); ovn_lflow_add(lflows, op->od, S_ROUTER_IN_DHCP_RELAY_RESP, 1, ds_cstr(match), ds_cstr(actions), lflow_ref, diff --git a/ovn-nb.xml b/ovn-nb.xml index 9657c849d..a576c318e 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -4193,6 +4193,30 @@ or to <ref table="DHCP_Relay"/> table. </column> + <column name="options" key="dhcpv4_primary_ip"> + <p> + Optional. Selects which of the logical router port's IPv4 + addresses <code>ovn-northd</code> uses as the relay agent + address (<code>giaddr</code>) in DHCP packets relayed via this + port (see <ref column="dhcp_relay"/>). The value must be a + bare IPv4 host address (no prefix length, e.g. + <code>10.0.0.1</code>) that equals one of the addresses + configured in <ref column="networks"/>. If the value is not a + valid IPv4 address or does not match one of the addresses in + <ref column="networks"/>, <code>ovn-northd</code> skips + emitting DHCP relay flows for this port. + </p> + <p> + When unset, <code>ovn-northd</code> defaults to the first + address in <ref column="networks"/> as ordered by OVSDB: the + CIDR that sorts first as a string. This default may not match + the address intended as the DHCP relay address of the port, so + on multi-IP ports this option should be set explicitly. On + single-IP ports the only configured address is always used and + the option may be left unset. + </p> + </column> + <group title="Distributed Gateway Ports"> <p> Gateways, as documented under <code>Gateways</code> in the OVN diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 810e9f2d7..08582a83b 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -13857,14 +13857,14 @@ check ovn-nbctl --wait=sb sync ovn-sbctl lflow-list > lflows AT_CAPTURE_FILE([lflows]) -AT_CHECK([grep -e "DHCP_RELAY_" lflows | sed 's/table=../table=??/'], [0], [dnl - table=??(lr_in_ip_input ), priority=110 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && ip.frag == 0 && udp.src == 68 && udp.dst == 67), action=(reg9[[7]] = dhcp_relay_req_chk(192.168.1.1, 172.16.1.1);next; /* DHCP_RELAY_REQ */) - table=??(lr_in_ip_input ), priority=110 , match=(ip4.src == 172.16.1.1 && ip4.dst == 192.168.1.1 && ip.frag == 0 && udp.src == 67 && udp.dst == 67), action=(next; /* DHCP_RELAY_RESP */) - table=??(lr_in_dhcp_relay_req), priority=100 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]]), action=(ip4.src = 192.168.1.1; ip4.dst = 172.16.1.1; udp.src = 67; next; /* DHCP_RELAY_REQ */) +AT_CHECK([grep -e "DHCP_RELAY_" lflows | ovn_strip_lflows], [0], [dnl table=??(lr_in_dhcp_relay_req), priority=1 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]] == 0), action=(drop; /* DHCP_RELAY_REQ */) - table=??(lr_in_dhcp_relay_resp_chk), priority=100 , match=(ip4.src == 172.16.1.1 && ip4.dst == 192.168.1.1 && udp.src == 67 && udp.dst == 67), action=(reg2 = ip4.dst; reg9[[8]] = dhcp_relay_resp_chk(192.168.1.1, 172.16.1.1); next; /* DHCP_RELAY_RESP */) - table=??(lr_in_dhcp_relay_resp), priority=100 , match=(ip4.src == 172.16.1.1 && reg2 == 192.168.1.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]]), action=(ip4.src = 192.168.1.1; udp.dst = 68; outport = "lrp1"; output; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_req), priority=100 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]]), action=(ip4.src = 192.168.1.1; ip4.dst = 172.16.1.1; udp.src = 67; next; /* DHCP_RELAY_REQ */) table=??(lr_in_dhcp_relay_resp), priority=1 , match=(ip4.src == 172.16.1.1 && reg2 == 192.168.1.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]] == 0), action=(drop; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_resp), priority=100 , match=(ip4.src == 172.16.1.1 && reg2 == 192.168.1.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]]), action=(ip4.src = 192.168.1.1; udp.dst = 68; outport = "lrp1"; output; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_resp_chk), priority=100 , match=(ip4.src == 172.16.1.1 && ip4.dst == 192.168.1.1 && udp.src == 67 && udp.dst == 67), action=(reg2 = ip4.dst; reg9[[8]] = dhcp_relay_resp_chk(192.168.1.1, 172.16.1.1); next; /* DHCP_RELAY_RESP */) + table=??(lr_in_ip_input ), priority=110 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && ip.frag == 0 && udp.src == 68 && udp.dst == 67), action=(reg9[[7]] = dhcp_relay_req_chk(192.168.1.1, 172.16.1.1);next; /* DHCP_RELAY_REQ */) + table=??(lr_in_ip_input ), priority=110 , match=(ip4.src == 172.16.1.1 && ip4.dst == 192.168.1.1 && ip.frag == 0 && udp.src == 67 && udp.dst == 67), action=(next; /* DHCP_RELAY_RESP */) table=??(ls_in_l2_lkup ), priority=100 , match=(inport == "ls0-port1" && eth.src == 02:00:00:00:00:10 && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67), action=(eth.dst = 02:00:00:00:00:01; outport = "lrp1-attachment"; next; /* DHCP_RELAY_REQ */) ]) @@ -13874,14 +13874,14 @@ check ovn-nbctl --wait=sb set Logical_Switch ls0 other_config:dhcp_relay_port=fo ovn-sbctl lflow-list > lflows AT_CAPTURE_FILE([lflows]) -AT_CHECK([grep -e "DHCP_RELAY_" lflows | sed 's/table=../table=??/'], [0], [dnl - table=??(lr_in_ip_input ), priority=110 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && ip.frag == 0 && udp.src == 68 && udp.dst == 67), action=(reg9[[7]] = dhcp_relay_req_chk(192.168.1.1, 172.16.1.1);next; /* DHCP_RELAY_REQ */) - table=??(lr_in_ip_input ), priority=110 , match=(ip4.src == 172.16.1.1 && ip4.dst == 192.168.1.1 && ip.frag == 0 && udp.src == 67 && udp.dst == 67), action=(next; /* DHCP_RELAY_RESP */) - table=??(lr_in_dhcp_relay_req), priority=100 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]]), action=(ip4.src = 192.168.1.1; ip4.dst = 172.16.1.1; udp.src = 67; next; /* DHCP_RELAY_REQ */) +AT_CHECK([grep -e "DHCP_RELAY_" lflows | ovn_strip_lflows], [0], [dnl table=??(lr_in_dhcp_relay_req), priority=1 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]] == 0), action=(drop; /* DHCP_RELAY_REQ */) - table=??(lr_in_dhcp_relay_resp_chk), priority=100 , match=(ip4.src == 172.16.1.1 && ip4.dst == 192.168.1.1 && udp.src == 67 && udp.dst == 67), action=(reg2 = ip4.dst; reg9[[8]] = dhcp_relay_resp_chk(192.168.1.1, 172.16.1.1); next; /* DHCP_RELAY_RESP */) - table=??(lr_in_dhcp_relay_resp), priority=100 , match=(ip4.src == 172.16.1.1 && reg2 == 192.168.1.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]]), action=(ip4.src = 192.168.1.1; udp.dst = 68; outport = "lrp1"; output; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_req), priority=100 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]]), action=(ip4.src = 192.168.1.1; ip4.dst = 172.16.1.1; udp.src = 67; next; /* DHCP_RELAY_REQ */) table=??(lr_in_dhcp_relay_resp), priority=1 , match=(ip4.src == 172.16.1.1 && reg2 == 192.168.1.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]] == 0), action=(drop; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_resp), priority=100 , match=(ip4.src == 172.16.1.1 && reg2 == 192.168.1.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]]), action=(ip4.src = 192.168.1.1; udp.dst = 68; outport = "lrp1"; output; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_resp_chk), priority=100 , match=(ip4.src == 172.16.1.1 && ip4.dst == 192.168.1.1 && udp.src == 67 && udp.dst == 67), action=(reg2 = ip4.dst; reg9[[8]] = dhcp_relay_resp_chk(192.168.1.1, 172.16.1.1); next; /* DHCP_RELAY_RESP */) + table=??(lr_in_ip_input ), priority=110 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && ip.frag == 0 && udp.src == 68 && udp.dst == 67), action=(reg9[[7]] = dhcp_relay_req_chk(192.168.1.1, 172.16.1.1);next; /* DHCP_RELAY_REQ */) + table=??(lr_in_ip_input ), priority=110 , match=(ip4.src == 172.16.1.1 && ip4.dst == 192.168.1.1 && ip.frag == 0 && udp.src == 67 && udp.dst == 67), action=(next; /* DHCP_RELAY_RESP */) ]) # Clear the dhcp_relay from lrp1 @@ -13890,7 +13890,7 @@ check ovn-nbctl --wait=sb clear Logical_Router_port lrp1 dhcp_relay ovn-sbctl lflow-list > lflows AT_CAPTURE_FILE([lflows]) -AT_CHECK([grep -e "DHCP_RELAY_" lflows | sed 's/table=../table=??/'], [0], [dnl +AT_CHECK([grep -e "DHCP_RELAY_" lflows | ovn_strip_lflows], [0], [dnl ]) # set the dhcp_relay_port in ls0 to proper one. @@ -13899,7 +13899,83 @@ check ovn-nbctl --wait=sb set Logical_Switch ls0 other_config:dhcp_relay_port=lr ovn-sbctl lflow-list > lflows AT_CAPTURE_FILE([lflows]) -AT_CHECK([grep -e "DHCP_RELAY_" lflows | sed 's/table=../table=??/'], [0], [dnl +AT_CHECK([grep -e "DHCP_RELAY_" lflows | ovn_strip_lflows], [0], [dnl +]) + +# Multi-IP LRP: re-enable DHCP relay on lrp1 and add a second IPv4 +# network. options:dhcpv4_primary_ip is unset, so ovn-northd falls +# back to the first address returned by OVSDB - whichever CIDR sorts +# first as a string. For ["10.0.0.1/24","192.168.1.1/24"] that is +# 10.0.0.1/24, so DHCP relay flows are emitted using 10.0.0.1. +check ovn-nbctl --wait=sb set Logical_Router_port lrp1 dhcp_relay=$dhcp_relay +check ovn-nbctl --wait=sb set Logical_Router_port lrp1 \ + 'networks=["10.0.0.1/24","192.168.1.1/24"]' + +ovn-sbctl lflow-list > lflows +AT_CAPTURE_FILE([lflows]) + +AT_CHECK([grep -e "DHCP_RELAY_" lflows | ovn_strip_lflows], [0], [dnl + table=??(lr_in_dhcp_relay_req), priority=1 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 10.0.0.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]] == 0), action=(drop; /* DHCP_RELAY_REQ */) + table=??(lr_in_dhcp_relay_req), priority=100 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 10.0.0.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]]), action=(ip4.src = 10.0.0.1; ip4.dst = 172.16.1.1; udp.src = 67; next; /* DHCP_RELAY_REQ */) + table=??(lr_in_dhcp_relay_resp), priority=1 , match=(ip4.src == 172.16.1.1 && reg2 == 10.0.0.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]] == 0), action=(drop; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_resp), priority=100 , match=(ip4.src == 172.16.1.1 && reg2 == 10.0.0.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]]), action=(ip4.src = 10.0.0.1; udp.dst = 68; outport = "lrp1"; output; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_resp_chk), priority=100 , match=(ip4.src == 172.16.1.1 && ip4.dst == 10.0.0.1 && udp.src == 67 && udp.dst == 67), action=(reg2 = ip4.dst; reg9[[8]] = dhcp_relay_resp_chk(10.0.0.1, 172.16.1.1); next; /* DHCP_RELAY_RESP */) + table=??(lr_in_ip_input ), priority=110 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 10.0.0.0/24} && ip4.dst == 255.255.255.255 && ip.frag == 0 && udp.src == 68 && udp.dst == 67), action=(reg9[[7]] = dhcp_relay_req_chk(10.0.0.1, 172.16.1.1);next; /* DHCP_RELAY_REQ */) + table=??(lr_in_ip_input ), priority=110 , match=(ip4.src == 172.16.1.1 && ip4.dst == 10.0.0.1 && ip.frag == 0 && udp.src == 67 && udp.dst == 67), action=(next; /* DHCP_RELAY_RESP */) + table=??(ls_in_l2_lkup ), priority=100 , match=(inport == "ls0-port1" && eth.src == 02:00:00:00:00:10 && ip4.src == {0.0.0.0, 10.0.0.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67), action=(eth.dst = 02:00:00:00:00:01; outport = "lrp1-attachment"; next; /* DHCP_RELAY_REQ */) +]) + +# Pin the DHCPv4 primary IP via options:dhcpv4_primary_ip. Every DHCP +# relay flow should now reference 192.168.1.1/24 instead of 10.0.0.1/24. +check ovn-nbctl --wait=sb set Logical_Router_port lrp1 \ + options:dhcpv4_primary_ip=192.168.1.1 + +ovn-sbctl lflow-list > lflows +AT_CAPTURE_FILE([lflows]) + +AT_CHECK([grep -e "DHCP_RELAY_" lflows | ovn_strip_lflows], [0], [dnl + table=??(lr_in_dhcp_relay_req), priority=1 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]] == 0), action=(drop; /* DHCP_RELAY_REQ */) + table=??(lr_in_dhcp_relay_req), priority=100 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]]), action=(ip4.src = 192.168.1.1; ip4.dst = 172.16.1.1; udp.src = 67; next; /* DHCP_RELAY_REQ */) + table=??(lr_in_dhcp_relay_resp), priority=1 , match=(ip4.src == 172.16.1.1 && reg2 == 192.168.1.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]] == 0), action=(drop; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_resp), priority=100 , match=(ip4.src == 172.16.1.1 && reg2 == 192.168.1.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]]), action=(ip4.src = 192.168.1.1; udp.dst = 68; outport = "lrp1"; output; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_resp_chk), priority=100 , match=(ip4.src == 172.16.1.1 && ip4.dst == 192.168.1.1 && udp.src == 67 && udp.dst == 67), action=(reg2 = ip4.dst; reg9[[8]] = dhcp_relay_resp_chk(192.168.1.1, 172.16.1.1); next; /* DHCP_RELAY_RESP */) + table=??(lr_in_ip_input ), priority=110 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && ip.frag == 0 && udp.src == 68 && udp.dst == 67), action=(reg9[[7]] = dhcp_relay_req_chk(192.168.1.1, 172.16.1.1);next; /* DHCP_RELAY_REQ */) + table=??(lr_in_ip_input ), priority=110 , match=(ip4.src == 172.16.1.1 && ip4.dst == 192.168.1.1 && ip.frag == 0 && udp.src == 67 && udp.dst == 67), action=(next; /* DHCP_RELAY_RESP */) + table=??(ls_in_l2_lkup ), priority=100 , match=(inport == "ls0-port1" && eth.src == 02:00:00:00:00:10 && ip4.src == {0.0.0.0, 192.168.1.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67), action=(eth.dst = 02:00:00:00:00:01; outport = "lrp1-attachment"; next; /* DHCP_RELAY_REQ */) +]) + +# Setting options:dhcpv4_primary_ip to an address that does not belong +# to 'networks' is a misconfiguration: ovn-northd logs a warning and +# skips DHCP relay flow generation for the port. +check ovn-nbctl --wait=sb set Logical_Router_port lrp1 \ + options:dhcpv4_primary_ip=10.99.99.99 + +ovn-sbctl lflow-list > lflows +AT_CAPTURE_FILE([lflows]) + +AT_CHECK([grep -e "DHCP_RELAY_" lflows | ovn_strip_lflows], [0], [dnl +]) +AT_CHECK([grep -q "options:dhcpv4_primary_ip=10.99.99.99 does not match any address in 'networks'" northd/ovn-northd.log]) + +# Reducing 'networks' back to a single IPv4 makes the option no longer +# mandatory; clearing it should restore DHCP relay flows that reference +# the remaining address. +check ovn-nbctl --wait=sb set Logical_Router_port lrp1 \ + 'networks=["10.0.0.1/24"]' +check ovn-nbctl --wait=sb remove Logical_Router_port lrp1 options dhcpv4_primary_ip + +ovn-sbctl lflow-list > lflows +AT_CAPTURE_FILE([lflows]) + +AT_CHECK([grep -e "DHCP_RELAY_" lflows | ovn_strip_lflows], [0], [dnl + table=??(lr_in_dhcp_relay_req), priority=1 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 10.0.0.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]] == 0), action=(drop; /* DHCP_RELAY_REQ */) + table=??(lr_in_dhcp_relay_req), priority=100 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 10.0.0.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg9[[7]]), action=(ip4.src = 10.0.0.1; ip4.dst = 172.16.1.1; udp.src = 67; next; /* DHCP_RELAY_REQ */) + table=??(lr_in_dhcp_relay_resp), priority=1 , match=(ip4.src == 172.16.1.1 && reg2 == 10.0.0.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]] == 0), action=(drop; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_resp), priority=100 , match=(ip4.src == 172.16.1.1 && reg2 == 10.0.0.1 && udp.src == 67 && udp.dst == 67 && reg9[[8]]), action=(ip4.src = 10.0.0.1; udp.dst = 68; outport = "lrp1"; output; /* DHCP_RELAY_RESP */) + table=??(lr_in_dhcp_relay_resp_chk), priority=100 , match=(ip4.src == 172.16.1.1 && ip4.dst == 10.0.0.1 && udp.src == 67 && udp.dst == 67), action=(reg2 = ip4.dst; reg9[[8]] = dhcp_relay_resp_chk(10.0.0.1, 172.16.1.1); next; /* DHCP_RELAY_RESP */) + table=??(lr_in_ip_input ), priority=110 , match=(inport == "lrp1" && ip4.src == {0.0.0.0, 10.0.0.0/24} && ip4.dst == 255.255.255.255 && ip.frag == 0 && udp.src == 68 && udp.dst == 67), action=(reg9[[7]] = dhcp_relay_req_chk(10.0.0.1, 172.16.1.1);next; /* DHCP_RELAY_REQ */) + table=??(lr_in_ip_input ), priority=110 , match=(ip4.src == 172.16.1.1 && ip4.dst == 10.0.0.1 && ip.frag == 0 && udp.src == 67 && udp.dst == 67), action=(next; /* DHCP_RELAY_RESP */) + table=??(ls_in_l2_lkup ), priority=100 , match=(inport == "ls0-port1" && eth.src == 02:00:00:00:00:10 && ip4.src == {0.0.0.0, 10.0.0.0/24} && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67), action=(eth.dst = 02:00:00:00:00:01; outport = "lrp1-attachment"; next; /* DHCP_RELAY_REQ */) ]) OVN_CLEANUP_NORTHD -- 2.43.5 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
