diff --git a/SOURCES/ovn-21.06.0.patch b/SOURCES/ovn-21.06.0.patch index 365364d..a7d4f84 100644 --- a/SOURCES/ovn-21.06.0.patch +++ b/SOURCES/ovn-21.06.0.patch @@ -1,3 +1,27 @@ +diff --git a/AUTHORS.rst b/AUTHORS.rst +index 9f9b4fbaa..c243c5358 100644 +--- a/AUTHORS.rst ++++ b/AUTHORS.rst +@@ -271,6 +271,7 @@ Miguel Angel Ajo majopela@redhat.com + Mijo Safradin mijo@linux.vnet.ibm.com + Mika Vaisanen mika.vaisanen@gmail.com + Minoru TAKAHASHI takahashi.minoru7@gmail.com ++Mohammad Heib mheib@redhat.com + Moshe Levi moshele@mellanox.com + Murphy McCauley murphy.mccauley@gmail.com + Natasha Gude +diff --git a/NEWS b/NEWS +index 839ab2cfe..237a9d8f6 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,3 +1,7 @@ ++OVN v21.06.1 - xx xxx xxxx ++-------------------------- ++ - Allow static routes without nexthops. ++ + OVN v21.06.0 - 18 Jun 2021 + ------------------------- + - ovn-northd-ddlog: New implementation of northd, based on DDlog. This diff --git a/TODO.rst b/TODO.rst index c89fe203e..618ea4844 100644 --- a/TODO.rst @@ -12,6 +36,19 @@ index c89fe203e..618ea4844 100644 + * physical.c has a global simap -localvif_to_ofport which stores the + local OVS interfaces and the ofport numbers. Move this to the engine data + of the engine data node - ed_type_pflow_output. +diff --git a/configure.ac b/configure.ac +index 53034388a..a1cdcb7a9 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -13,7 +13,7 @@ + # limitations under the License. + + AC_PREREQ(2.63) +-AC_INIT(ovn, 21.06.0, bugs@openvswitch.org) ++AC_INIT(ovn, 21.06.1, bugs@openvswitch.org) + AC_CONFIG_MACRO_DIR([m4]) + AC_CONFIG_AUX_DIR([build-aux]) + AC_CONFIG_HEADERS([config.h]) diff --git a/controller/binding.c b/controller/binding.c index 7fde0fdbb..ba558efdb 100644 --- a/controller/binding.c @@ -2144,6 +2181,92 @@ index 0bf13f268..feab41df4 100644 void physical_handle_port_binding_changes(struct physical_ctx *, struct ovn_desired_flow_table *); void physical_handle_mc_group_changes(struct physical_ctx *, +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index 78ecfed84..1859d33d6 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -768,6 +768,13 @@ pinctrl_parse_dhcpv6_advt(struct rconn *swconn, const struct flow *ip_flow, + + pfd->state = PREFIX_REQUEST; + ++ char ip6_s[INET6_ADDRSTRLEN + 1]; ++ if (ipv6_string_mapped(ip6_s, &ip_flow->ipv6_src)) { ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 40); ++ VLOG_DBG_RL(&rl, "Received DHCPv6 advt from %s with aid %d" ++ " sending DHCPv6 request", ip6_s, aid); ++ } ++ + uint64_t packet_stub[256 / 8]; + struct dp_packet packet; + +@@ -936,6 +943,14 @@ pinctrl_parse_dhcpv6_reply(struct dp_packet *pkt_in, + in_dhcpv6_data += opt_len; + } + if (status) { ++ char prefix[INET6_ADDRSTRLEN + 1]; ++ char ip6_s[INET6_ADDRSTRLEN + 1]; ++ if (ipv6_string_mapped(ip6_s, &ip_flow->ipv6_src) && ++ ipv6_string_mapped(prefix, &ipv6)) { ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 40); ++ VLOG_DBG_RL(&rl, "Received DHCPv6 reply from %s with prefix %s/%d" ++ " aid %d", ip6_s, prefix, prefix_len, aid); ++ } + pinctrl_prefixd_state_handler(ip_flow, ipv6, aid, eth->eth_src, + in_ip->ip6_src, prefix_len, t1, t2, + plife_time, vlife_time, uuid, uuid_len); +@@ -1226,18 +1241,26 @@ fill_ipv6_prefix_state(struct ovsdb_idl_txn *ovnsb_idl_txn, + } + } else if (pfd->state == PREFIX_PENDING && ovnsb_idl_txn) { + char prefix_str[INET6_ADDRSTRLEN + 1] = {}; +- struct smap options; ++ if (!ipv6_string_mapped(prefix_str, &pfd->prefix)) { ++ goto out; ++ } ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 40); ++ VLOG_DBG_RL(&rl, "updating port_binding for %s with prefix %s/%d" ++ " aid %d", pb->logical_port, prefix_str, pfd->plen, ++ pfd->aid); + + pfd->state = PREFIX_DONE; + pfd->last_complete = time_msec(); + pfd->next_announce = pfd->last_complete + pfd->t1; +- ipv6_string_mapped(prefix_str, &pfd->prefix); ++ struct smap options; + smap_clone(&options, &pb->options); ++ smap_remove(&options, "ipv6_ra_pd_list"); + 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); + } ++out: + pfd->last_used = time_msec(); + destroy_lport_addresses(&c_addrs); + } +@@ -1288,7 +1311,8 @@ prepare_ipv6_prefixd(struct ovsdb_idl_txn *ovnsb_idl_txn, + sbrec_port_binding_by_name, chassis, active_tunnels, + redirect_name); + free(redirect_name); +- if (!resident && strcmp(pb->type, "l3gateway")) { ++ if ((strcmp(pb->type, "l3gateway") || pb->chassis != chassis) && ++ !resident) { + continue; + } + +diff --git a/debian/changelog b/debian/changelog +index 9e6e5215d..42b952144 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,9 @@ ++ovn (21.06.1-1) unstable; urgency=low ++ ++ * New upstream version ++ ++ -- OVN team Fri, 18 Jun 2021 13:21:08 -0400 ++ + ovn (21.06.0-1) unstable; urgency=low + + * New upstream version diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 040213177..f5eb01eb7 100644 --- a/include/ovn/actions.h @@ -2399,6 +2522,91 @@ index 000000000..deb97581e +} + +OVSTEST_REGISTER("test-ovn-features", test_ovn_features_main); +diff --git a/northd/lrouter.dl b/northd/lrouter.dl +index 6c25b1ca9..6805b9036 100644 +--- a/northd/lrouter.dl ++++ b/northd/lrouter.dl +@@ -692,6 +692,17 @@ relation &StaticRoute(lrsr: nb::Logical_Router_Static_Route, + }, + var esr = lrsr.options.get_bool_def("ecmp_symmetric_reply", false). + ++relation &StaticRouteEmptyNextHop(lrsr: nb::Logical_Router_Static_Route, ++ key: route_key, ++ output_port: Option) ++&StaticRouteEmptyNextHop(.lrsr = lrsr, ++ .key = RouteKey{policy, ip_prefix, plen}, ++ .output_port = lrsr.output_port) :- ++ lrsr in nb::Logical_Router_Static_Route(.nexthop = ""), ++ not StaticRouteDown(lrsr._uuid), ++ var policy = route_policy_from_string(lrsr.policy), ++ Some{(var ip_prefix, var plen)} = ip46_parse_cidr(lrsr.ip_prefix). ++ + /* Returns the IP address of the router port 'op' that + * overlaps with 'ip'. If one is not found, returns None. */ + function find_lrp_member_ip(networks: lport_addresses, ip: v46_ip): Option = +@@ -743,6 +754,19 @@ RouterStaticRoute_(.router = router, + var route_id = FlatMap(routes), + route in &StaticRoute(.lrsr = nb::Logical_Router_Static_Route{._uuid = route_id}). + ++relation RouterStaticRouteEmptyNextHop_( ++ router : Intern, ++ key : route_key, ++ output_port : Option) ++ ++RouterStaticRouteEmptyNextHop_(.router = router, ++ .key = route.key, ++ .output_port = route.output_port) :- ++ router in &Router(), ++ nb::Logical_Router(._uuid = router._uuid, .static_routes = routes), ++ var route_id = FlatMap(routes), ++ route in &StaticRouteEmptyNextHop(.lrsr = nb::Logical_Router_Static_Route{._uuid = route_id}). ++ + /* Step-2: compute output_port for each pair */ + typedef route_dst = RouteDst { + nexthop: v46_ip, +@@ -805,6 +829,42 @@ RouterStaticRoute(router, key, dsts) :- + }, + var dsts = set_singleton(RouteDst{nexthop, src_ip, port, ecmp_symmetric_reply}). + ++relation RouterStaticRouteEmptyNextHop( ++ router : Intern, ++ key : route_key, ++ dsts : Set) ++ ++RouterStaticRouteEmptyNextHop(router, key, dsts) :- ++ RouterStaticRouteEmptyNextHop_(.router = router, ++ .key = key, ++ .output_port = Some{oport}), ++ /* output_port specified */ ++ port in &RouterPort(.lrp = &nb::Logical_Router_Port{.name = oport}, ++ .networks = networks), ++ /* There are no IP networks configured on the router's port via ++ * which 'route->nexthop' is theoretically reachable. But since ++ * 'out_port' has been specified, we honor it by trying to reach ++ * 'route->nexthop' via the first IP address of 'out_port'. ++ * (There are cases, e.g in GCE, where each VM gets a /32 IP ++ * address and the default gateway is still reachable from it.) */ ++ Some{var src_ip} = match (key.ip_prefix) { ++ IPv4{_} -> match (networks.ipv4_addrs.nth(0)) { ++ Some{addr} -> Some{IPv4{addr.addr}}, ++ None -> { ++ warn("No path for static route ${key.ip_prefix}"); ++ None ++ } ++ }, ++ IPv6{_} -> match (networks.ipv6_addrs.nth(0)) { ++ Some{addr} -> Some{IPv6{addr.addr}}, ++ None -> { ++ warn("No path for static route ${key.ip_prefix}"); ++ None ++ } ++ } ++ }, ++ var dsts = set_singleton(RouteDst{src_ip, src_ip, port, false}). ++ + /* compute route-route pairs for nexthop = "discard" routes */ + relation &DiscardRoute(lrsr: nb::Logical_Router_Static_Route, + key: route_key) diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index 407464602..890775797 100644 --- a/northd/ovn-northd.8.xml @@ -2431,7 +2639,7 @@ index 407464602..890775797 100644 A priority-50 logical flow with match outport == GW has actions diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c -index 3dae7bb1c..576b6cbc9 100644 +index 3dae7bb1c..148e3ee21 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -7007,6 +7007,10 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, @@ -2475,7 +2683,94 @@ index 3dae7bb1c..576b6cbc9 100644 mcast_sw_info->table_size)) { return; } -@@ -11656,6 +11658,7 @@ lrouter_check_nat_entry(struct ovn_datapath *od, const struct nbrec_nat *nat, +@@ -8039,10 +8041,16 @@ route_hash(struct parsed_route *route) + + static struct ovs_mutex bfd_lock = OVS_MUTEX_INITIALIZER; + ++static bool ++find_static_route_outport(struct ovn_datapath *od, struct hmap *ports, ++ const struct nbrec_logical_router_static_route *route, bool is_ipv4, ++ const char **p_lrp_addr_s, struct ovn_port **p_out_port); ++ + /* Parse and validate the route. Return the parsed route if successful. + * Otherwise return NULL. */ + static struct parsed_route * +-parsed_routes_add(struct ovs_list *routes, ++parsed_routes_add(struct ovn_datapath *od, struct hmap *ports, ++ struct ovs_list *routes, + const struct nbrec_logical_router_static_route *route, + struct hmap *bfd_connections) + { +@@ -8050,7 +8058,8 @@ parsed_routes_add(struct ovs_list *routes, + struct in6_addr nexthop; + unsigned int plen; + bool is_discard_route = !strcmp(route->nexthop, "discard"); +- if (!is_discard_route) { ++ bool valid_nexthop = strlen(route->nexthop) && !is_discard_route; ++ if (valid_nexthop) { + if (!ip46_parse_cidr(route->nexthop, &nexthop, &plen)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad 'nexthop' %s in static route" +@@ -8079,7 +8088,7 @@ parsed_routes_add(struct ovs_list *routes, + } + + /* Verify that ip_prefix and nexthop have same address familiy. */ +- if (!is_discard_route) { ++ if (valid_nexthop) { + if (IN6_IS_ADDR_V4MAPPED(&prefix) != IN6_IS_ADDR_V4MAPPED(&nexthop)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "Address family doesn't match between 'ip_prefix'" +@@ -8090,6 +8099,14 @@ parsed_routes_add(struct ovs_list *routes, + } + } + ++ /* Verify that ip_prefix and nexthop are on the same network. */ ++ if (!is_discard_route && ++ !find_static_route_outport(od, ports, route, ++ IN6_IS_ADDR_V4MAPPED(&prefix), ++ NULL, NULL)) { ++ return NULL; ++ } ++ + const struct nbrec_bfd *nb_bt = route->bfd; + if (nb_bt && !strcmp(nb_bt->dst_ip, route->nexthop)) { + struct bfd_entry *bfd_e; +@@ -8364,8 +8381,12 @@ find_static_route_outport(struct ovn_datapath *od, struct hmap *ports, + route->ip_prefix, route->nexthop); + return false; + } +- *p_out_port = out_port; +- *p_lrp_addr_s = lrp_addr_s; ++ if (p_out_port) { ++ *p_out_port = out_port; ++ } ++ if (p_lrp_addr_s) { ++ *p_lrp_addr_s = lrp_addr_s; ++ } + + return true; + } +@@ -8563,7 +8584,7 @@ add_route(struct hmap *lflows, struct ovn_datapath *od, + } else { + ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s = ", + is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6); +- if (gateway) { ++ if (gateway && strlen(gateway)) { + ds_put_cstr(&common_actions, gateway); + } else { + ds_put_format(&common_actions, "ip%s.dst", is_ipv4 ? "4" : "6"); +@@ -9892,8 +9913,8 @@ build_static_route_flows_for_lrouter( + struct ecmp_groups_node *group; + for (int i = 0; i < od->nbr->n_static_routes; i++) { + struct parsed_route *route = +- parsed_routes_add(&parsed_routes, od->nbr->static_routes[i], +- bfd_connections); ++ parsed_routes_add(od, ports, &parsed_routes, ++ od->nbr->static_routes[i], bfd_connections); + if (!route) { + continue; + } +@@ -11656,6 +11677,7 @@ lrouter_check_nat_entry(struct ovn_datapath *od, const struct nbrec_nat *nat, static void build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, @@ -2483,7 +2778,7 @@ index 3dae7bb1c..576b6cbc9 100644 struct shash *meter_groups, struct hmap *lbs, struct ds *match, struct ds *actions) -@@ -11763,10 +11766,21 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, +@@ -11763,10 +11785,21 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, ds_clear(match); ds_clear(actions); ds_put_format(match, @@ -2508,7 +2803,7 @@ index 3dae7bb1c..576b6cbc9 100644 ds_put_format(actions, "eth.src = %s; %s = %s; next;", nat->external_mac, is_v6 ? REG_SRC_IPV6 : REG_SRC_IPV4, -@@ -11800,6 +11814,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, +@@ -11800,6 +11833,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, ds_put_format(actions, "clone { ct_clear; " "inport = outport; outport = \"\"; " @@ -2516,7 +2811,7 @@ index 3dae7bb1c..576b6cbc9 100644 "flags = 0; flags.loopback = 1; "); for (int j = 0; j < MFF_N_LOG_REGS; j++) { ds_put_format(actions, "reg%d = 0; ", j); -@@ -11925,8 +11940,9 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, +@@ -11925,8 +11959,9 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, &lsi->actions); build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows); build_lrouter_arp_nd_for_datapath(od, lsi->lflows); @@ -2528,8 +2823,30 @@ index 3dae7bb1c..576b6cbc9 100644 } /* Helper function to combine all lflow generation which is iterated by port. +@@ -13271,7 +13306,7 @@ ovnnb_db_run(struct northd_context *ctx, + struct smap options; + smap_clone(&options, &nb->options); + +- smap_add(&options, "mac_prefix", mac_addr_prefix); ++ smap_replace(&options, "mac_prefix", mac_addr_prefix); + + if (!monitor_mac) { + eth_addr_random(&svc_monitor_mac_ea); +@@ -13286,8 +13321,10 @@ ovnnb_db_run(struct northd_context *ctx, + + smap_replace(&options, "northd_internal_version", ovn_internal_version); + +- nbrec_nb_global_verify_options(nb); +- nbrec_nb_global_set_options(nb, &options); ++ if (!smap_equal(&nb->options, &options)) { ++ nbrec_nb_global_verify_options(nb); ++ nbrec_nb_global_set_options(nb, &options); ++ } + + smap_destroy(&options); + diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl -index 3afa80a3b..46da9a3a4 100644 +index 3afa80a3b..de6a0652e 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -3309,7 +3309,8 @@ for (CheckLspIsUp[check_lsp_is_up]) { @@ -2598,6 +2915,18 @@ index 3afa80a3b..46da9a3a4 100644 "flags = 0; flags.loopback = 1; " ++ regs.join("") ++ "${rEGBIT_EGRESS_LOOPBACK()} = 1; " +@@ -6468,6 +6486,11 @@ Route(key, dst.port, dst.src_ip, Some{dst.nexthop}) :- + dsts.size() == 1, + Some{var dst} = dsts.nth(0). + ++Route(key, dst.port, dst.src_ip, None) :- ++ RouterStaticRouteEmptyNextHop(.router = router, .key = key, .dsts = dsts), ++ dsts.size() == 1, ++ Some{var dst} = dsts.nth(0). ++ + /* Return a vector of pairs (1, set[0]), ... (n, set[n - 1]). */ + function numbered_vec(set: Set<'A>) : Vec<(bit<16>, 'A)> = { + var vec = vec_with_capacity(set.size()); diff --git a/tests/automake.mk b/tests/automake.mk index 742e5cff2..a8ec64212 100644 --- a/tests/automake.mk @@ -2627,7 +2956,7 @@ index 742e5cff2..a8ec64212 100644 northd/ipam.c \ northd/ipam.h diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at -index 72c07b3fa..9c25193e8 100644 +index 72c07b3fa..1aab49ae8 100644 --- a/tests/ovn-controller.at +++ b/tests/ovn-controller.at @@ -151,23 +151,24 @@ sysid=$(ovs-vsctl get Open_vSwitch . external_ids:system-id) @@ -2671,6 +3000,44 @@ index 72c07b3fa..9c25193e8 100644 OVS_WAIT_UNTIL([check_datapath_type foobar]) expected_iface_types=$(ovs-vsctl get Open_vSwitch . iface_types | tr -d '[[]] ""') +@@ -393,6 +392,37 @@ OVN_CLEANUP([hv]) + AT_CLEANUP + ]) + ++# check that nb_cfg overflow cases handled properly ++AT_SETUP([ovn-controller - overflow the nb_cfg value across the tables]) ++AT_KEYWORDS([ovn]) ++ovn_start ++ ++net_add n1 ++sim_add hv ++as hv ++ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++ ++check ovn-nbctl --wait=hv sync ++ ++# overflow the NB_Global nb_cfg value ++check ovn-nbctl set NB_Global . nb_cfg=9223372036854775806 ++ ++# nb_cfg must be set to zero if it exceed the value of LLONG_MAX ++# the command below will try incress the value of nb_cfg to be greater than LLONG_MAX and ++# expect zero as a return value ++check ovn-nbctl --wait=hv sync ++check ovn-nbctl --wait=hv sync ++ ++# nb_cfg should be set to 1 in the chassis_private/nb_global/sb_global table ++check_column 1 chassis_private nb_cfg ++check_column 1 sb_global nb_cfg ++check_column 1 nb:nb_global nb_cfg ++check_column 0 chassis nb_cfg ++ ++OVN_CLEANUP([hv]) ++AT_CLEANUP ++ + # Test unix command: debug/delay-nb-cfg-report + OVN_FOR_EACH_NORTHD([ + AT_SETUP([ovn-controller - debug/delay-nb-cfg-report]) diff --git a/tests/ovn-features.at b/tests/ovn-features.at new file mode 100644 index 000000000..36bd83055 @@ -2685,8 +3052,201 @@ index 000000000..36bd83055 +AT_SETUP([ovn -- unit test -- OVS feature detection tests]) +AT_CHECK([ovstest test-ovn-features run], [0], []) +AT_CLEANUP +diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at +index 1058d418a..0922e1aa0 100644 +--- a/tests/ovn-nbctl.at ++++ b/tests/ovn-nbctl.at +@@ -1442,11 +1442,16 @@ dnl --------------------------------------------------------------------- + + OVN_NBCTL_TEST([ovn_nbctl_routes], [routes], [ + AT_CHECK([ovn-nbctl lr-add lr0]) ++AT_CHECK([ovn-nbctl lrp-add lr0 lp0 f0:00:00:00:00:01 10.0.0.254/24]) + + dnl Check IPv4 routes + AT_CHECK([ovn-nbctl lr-route-add lr0 0.0.0.0/0 192.168.0.1]) + AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.1.0/24 11.0.1.1 lp0]) + AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.1/24 11.0.0.2]) ++AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp0]) ++AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp1], [1], [], ++ [ovn-nbctl: bad IPv4 nexthop argument: lp1 ++]) + + dnl Add overlapping route with 10.0.0.1/24 + AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1], [1], [], +@@ -1495,6 +1500,7 @@ AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl + IPv4 Routes + 10.0.0.0/24 11.0.0.1 dst-ip + 10.0.1.0/24 11.0.1.1 dst-ip lp0 ++ 10.0.10.0/24 dst-ip lp0 + 20.0.0.0/24 discard dst-ip + 9.16.1.0/24 11.0.0.1 src-ip + 10.0.0.0/24 11.0.0.2 src-ip +@@ -1502,11 +1508,13 @@ IPv4 Routes + 0.0.0.0/0 192.168.0.1 dst-ip + ]) + ++AT_CHECK([ovn-nbctl lrp-add lr0 lp1 f0:00:00:00:00:02 11.0.0.254/24]) + AT_CHECK([ovn-nbctl --may-exist lr-route-add lr0 10.0.0.111/24 11.0.0.1 lp1]) + AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl + IPv4 Routes + 10.0.0.0/24 11.0.0.1 dst-ip lp1 + 10.0.1.0/24 11.0.1.1 dst-ip lp0 ++ 10.0.10.0/24 dst-ip lp0 + 20.0.0.0/24 discard dst-ip + 9.16.1.0/24 11.0.0.1 src-ip + 10.0.0.0/24 11.0.0.2 src-ip +@@ -1535,6 +1543,7 @@ AT_CHECK([ovn-nbctl --policy=src-ip lr-route-del lr0 9.16.1.0/24]) + AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl + IPv4 Routes + 10.0.0.0/24 11.0.0.1 dst-ip lp1 ++ 10.0.10.0/24 dst-ip lp0 + 10.0.0.0/24 11.0.0.2 src-ip + 0.0.0.0/0 192.168.0.1 dst-ip + ]) +@@ -1544,6 +1553,7 @@ AT_CHECK([ovn-nbctl --policy=dst-ip lr-route-del lr0 10.0.0.0/24]) + AT_CHECK([ovn-nbctl --policy=src-ip lr-route-del lr0 10.0.0.0/24]) + AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl + IPv4 Routes ++ 10.0.10.0/24 dst-ip lp0 + 0.0.0.0/0 192.168.0.1 dst-ip + ]) + +@@ -1553,6 +1563,7 @@ AT_CHECK([ovn-nbctl --policy=src-ip lr-route-add lr0 10.0.0.0/24 11.0.0.2]) + AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24]) + AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl + IPv4 Routes ++ 10.0.10.0/24 dst-ip lp0 + 0.0.0.0/0 192.168.0.1 dst-ip + ]) + +diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at +index ad1732da3..2b70f48f6 100644 +--- a/tests/ovn-northd.at ++++ b/tests/ovn-northd.at +@@ -3016,16 +3016,16 @@ for i in $(seq 1 5); do + check ovn-nbctl --wait=sb lsp-set-addresses sw$i-r0 00:00:00:00:00:0$i + done + +-uuid=$(ovn-nbctl create bfd logical_port=r0-sw1 dst_ip=192.168.10.2 status=down min_tx=250 min_rx=250 detect_mult=10) +-ovn-nbctl create bfd logical_port=r0-sw2 dst_ip=192.168.20.2 status=down min_tx=500 min_rx=500 detect_mult=20 +-ovn-nbctl create bfd logical_port=r0-sw3 dst_ip=192.168.30.2 status=down +-ovn-nbctl create bfd logical_port=r0-sw4 dst_ip=192.168.40.2 status=down min_tx=0 detect_mult=0 ++uuid=$(ovn-nbctl create bfd logical_port=r0-sw1 dst_ip=192.168.1.2 status=down min_tx=250 min_rx=250 detect_mult=10) ++ovn-nbctl create bfd logical_port=r0-sw2 dst_ip=192.168.2.2 status=down min_tx=500 min_rx=500 detect_mult=20 ++ovn-nbctl create bfd logical_port=r0-sw3 dst_ip=192.168.3.2 status=down ++ovn-nbctl create bfd logical_port=r0-sw4 dst_ip=192.168.4.2 status=down min_tx=0 detect_mult=0 + +-wait_row_count bfd 1 logical_port=r0-sw1 detect_mult=10 dst_ip=192.168.10.2 \ ++wait_row_count bfd 1 logical_port=r0-sw1 detect_mult=10 dst_ip=192.168.1.2 \ + min_rx=250 min_tx=250 status=admin_down +-wait_row_count bfd 1 logical_port=r0-sw2 detect_mult=20 dst_ip=192.168.20.2 \ ++wait_row_count bfd 1 logical_port=r0-sw2 detect_mult=20 dst_ip=192.168.2.2 \ + min_rx=500 min_tx=500 status=admin_down +-wait_row_count bfd 1 logical_port=r0-sw3 detect_mult=5 dst_ip=192.168.30.2 \ ++wait_row_count bfd 1 logical_port=r0-sw3 detect_mult=5 dst_ip=192.168.3.2 \ + min_rx=1000 min_tx=1000 status=admin_down + + uuid=$(fetch_column nb:bfd _uuid logical_port=r0-sw1) +@@ -3036,17 +3036,17 @@ check ovn-nbctl clear bfd $uuid_2 min_rx + wait_row_count bfd 1 logical_port=r0-sw2 min_rx=1000 + wait_row_count bfd 1 logical_port=r0-sw1 min_rx=1000 min_tx=1000 detect_mult=100 + +-check ovn-nbctl --bfd=$uuid lr-route-add r0 100.0.0.0/8 192.168.10.2 ++check ovn-nbctl --bfd=$uuid lr-route-add r0 100.0.0.0/8 192.168.1.2 + wait_column down bfd status logical_port=r0-sw1 +-AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.10.2 | grep -q bfd],[0]) ++AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.1.2 | grep -q bfd],[0]) + +-check ovn-nbctl --bfd lr-route-add r0 200.0.0.0/8 192.168.20.2 ++check ovn-nbctl --bfd lr-route-add r0 200.0.0.0/8 192.168.2.2 + wait_column down bfd status logical_port=r0-sw2 +-AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.20.2 | grep -q bfd],[0]) ++AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.2.2 | grep -q bfd],[0]) + +-check ovn-nbctl --bfd lr-route-add r0 240.0.0.0/8 192.168.50.2 r0-sw5 ++check ovn-nbctl --bfd lr-route-add r0 240.0.0.0/8 192.168.5.2 r0-sw5 + wait_column down bfd status logical_port=r0-sw5 +-AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.50.2 | grep -q bfd],[0]) ++AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.5.2 | grep -q bfd],[0]) + + route_uuid=$(fetch_column nb:logical_router_static_route _uuid ip_prefix="100.0.0.0/8") + check ovn-nbctl clear logical_router_static_route $route_uuid bfd +@@ -3659,3 +3659,73 @@ check ovn-nbctl --wait=sb sync + OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) + AT_CLEANUP + ]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([ovn -- static routes flows]) ++AT_KEYWORDS([static-routes-flows]) ++ovn_start ++ ++check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 ++ ++check ovn-nbctl lr-add lr0 ++check ovn-nbctl ls-add public ++check ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 192.168.0.1/24 ++check ovn-nbctl lsp-add public public-lr0 ++check ovn-nbctl lsp-set-type public-lr0 router ++check ovn-nbctl lsp-set-addresses public-lr0 router ++check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public ++ ++check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.0.10 ++ ++ovn-sbctl dump-flows lr0 > lr0flows ++ ++AT_CHECK([grep -e "lr_in_ip_routing.*select" lr0flows |sort], [0], [dnl ++]) ++AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows |sort], [0], [dnl ++ table=11(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) ++]) ++ ++check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.0.20 ++ ++ovn-sbctl dump-flows lr0 > lr0flows ++AT_CHECK([grep -e "lr_in_ip_routing.*select" lr0flows |sort], [0], [dnl ++ table=10(lr_in_ip_routing ), priority=65 , match=(ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);) ++]) ++AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' |sort], [0], [dnl ++ table=11(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) ++ table=11(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) ++ table=11(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) ++]) ++ ++# add ecmp route with wrong nexthop ++check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.1.20 ++ ++ovn-sbctl dump-flows lr0 > lr0flows ++AT_CHECK([grep -e "lr_in_ip_routing.*select" lr0flows |sort], [0], [dnl ++ table=10(lr_in_ip_routing ), priority=65 , match=(ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);) ++]) ++AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' |sort], [0], [dnl ++ table=11(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) ++ table=11(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) ++ table=11(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) ++]) ++ ++check ovn-nbctl lr-route-del lr0 ++wait_row_count nb:Logical_Router_Static_Route 0 ++ ++check ovn-nbctl --wait=sb lr-route-add lr0 1.0.0.0/24 192.168.0.10 ++ovn-sbctl dump-flows lr0 > lr0flows ++ ++AT_CHECK([grep -e "lr_in_ip_routing.*192.168.0.10" lr0flows |sort], [0], [dnl ++ table=10(lr_in_ip_routing ), priority=49 , match=(ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) ++]) ++ ++check ovn-nbctl --wait=sb lr-route-add lr0 2.0.0.0/24 lr0-public ++ ++ovn-sbctl dump-flows lr0 > lr0flows ++AT_CHECK([grep -e "lr_in_ip_routing.*2.0.0.0" lr0flows |sort], [0], [dnl ++ table=10(lr_in_ip_routing ), priority=49 , match=(ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) ++]) ++ ++AT_CLEANUP ++]) diff --git a/tests/ovn.at b/tests/ovn.at -index aa80a7c48..450445036 100644 +index aa80a7c48..5eb7f8b7b 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -3169,6 +3169,118 @@ OVN_CLEANUP([hv-1],[hv-2]) @@ -2808,7 +3368,27 @@ index aa80a7c48..450445036 100644 OVN_FOR_EACH_NORTHD([ AT_SETUP([ovn -- VLAN transparency, passthru=true, multiple hosts]) ovn_start -@@ -11260,7 +11372,7 @@ ovn-nbctl lsp-add foo ln-foo +@@ -7821,6 +7933,19 @@ mac_prefix=$(ovn-nbctl --wait=sb get NB_Global . options:mac_prefix | tr -d \") + port_addr=$(ovn-nbctl get Logical-Switch-Port p91 dynamic_addresses | tr -d \") + AT_CHECK([test "$port_addr" = "${mac_prefix}:00:00:09"], [0], []) + ++# set mac_prefix to all-zeroes and check it is allocated in a random manner ++ovn-nbctl --wait=hv set NB_Global . options:mac_prefix="00:00:00:00:00:00" ++ovn-nbctl ls-add sw14 ++ovn-nbctl --wait=sb set Logical-Switch sw14 other_config:mac_only=true ++ovn-nbctl --wait=sb lsp-add sw14 p141 -- lsp-set-addresses p141 dynamic ++ ++mac_prefix=$(ovn-nbctl --wait=sb get NB_Global . options:mac_prefix | tr -d \") ++port_addr=$(ovn-nbctl get Logical-Switch-Port p141 dynamic_addresses | tr -d \") ++AT_CHECK([test "$mac_prefix" != "00:00:00:00:00:00"], [0], []) ++AT_CHECK([test "$port_addr" = "${mac_prefix}:00:00:0a"], [0], []) ++ovn-nbctl --wait=sb lsp-del sw14 p141 ++ovn-nbctl --wait=sb ls-del sw14 ++ + ovn-nbctl --wait=hv set NB_Global . options:mac_prefix="00:11:22" + ovn-nbctl ls-add sw10 + ovn-nbctl --wait=sb set Logical-Switch sw10 other_config:ipv6_prefix="ae01::" +@@ -11260,7 +11385,7 @@ ovn-nbctl lsp-add foo ln-foo ovn-nbctl lsp-set-addresses ln-foo unknown ovn-nbctl lsp-set-options ln-foo network_name=public ovn-nbctl lsp-set-type ln-foo localnet @@ -2817,7 +3397,7 @@ index aa80a7c48..450445036 100644 # Create localnet port in alice ovn-nbctl lsp-add alice ln-alice -@@ -12024,6 +12136,91 @@ OVN_CLEANUP([hv1]) +@@ -12024,6 +12149,91 @@ OVN_CLEANUP([hv1]) AT_CLEANUP ]) @@ -2909,7 +3489,7 @@ index aa80a7c48..450445036 100644 OVN_FOR_EACH_NORTHD([ AT_SETUP([ovn -- 1 LR with HA distributed router gateway port]) ovn_start -@@ -12668,7 +12865,7 @@ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv2/br-phys_n1-tx.pcap | trim_zeros +@@ -12668,7 +12878,7 @@ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv2/br-phys_n1-tx.pcap | trim_zeros AT_CHECK([grep $garp hv2_br_phys_tx | sort], [0], []) # change localnet port tag. @@ -2918,7 +3498,7 @@ index aa80a7c48..450445036 100644 # wait for earlier changes to take effect OVS_WAIT_UNTIL([test 1 = `as hv2 ovs-ofctl dump-flows br-int table=65 | \ -@@ -17172,6 +17369,16 @@ send_arp_reply() { +@@ -17172,6 +17382,16 @@ send_arp_reply() { as hv$hv ovs-appctl netdev-dummy/receive hv${hv}-vif$inport $request } @@ -2935,7 +3515,7 @@ index aa80a7c48..450445036 100644 net_add n1 sim_add hv1 -@@ -17311,27 +17518,29 @@ logical_port=sw0-vir) = x]) +@@ -17311,27 +17531,29 @@ logical_port=sw0-vir) = x]) as hv1 ovs-vsctl set interface hv1-vif3 external-ids:iface-id=sw0-vir @@ -2974,7 +3554,7 @@ index aa80a7c48..450445036 100644 ]) } -@@ -17384,6 +17593,22 @@ logical_port=sw0-vir) = x]) +@@ -17384,6 +17606,22 @@ logical_port=sw0-vir) = x]) wait_row_count nb:Logical_Switch_Port 1 up=false name=sw0-vir check ovn-nbctl --wait=hv sync @@ -2997,7 +3577,7 @@ index aa80a7c48..450445036 100644 # hv1 should remove the flow for the ACL with is_chassis_redirect check for sw0-vir. check_virtual_offlows_not_present hv1 -@@ -23116,7 +23341,7 @@ AT_CHECK([ +@@ -23116,7 +23354,7 @@ AT_CHECK([ for hv in 1 2; do grep table=15 hv${hv}flows | \ grep "priority=100" | \ @@ -3006,7 +3586,7 @@ index aa80a7c48..450445036 100644 grep table=22 hv${hv}flows | \ grep "priority=200" | \ -@@ -23241,7 +23466,7 @@ AT_CHECK([ +@@ -23241,7 +23479,7 @@ AT_CHECK([ for hv in 1 2; do grep table=15 hv${hv}flows | \ grep "priority=100" | \ @@ -3015,7 +3595,7 @@ index aa80a7c48..450445036 100644 grep table=22 hv${hv}flows | \ grep "priority=200" | \ -@@ -26688,6 +26913,50 @@ OVN_CLEANUP([hv1]) +@@ -26688,6 +26926,50 @@ OVN_CLEANUP([hv1]) AT_CLEANUP ]) @@ -3525,3 +4105,175 @@ index ddc3f11d6..b716a1ad9 100644 m4_include([tests/ovn-lflow-cache.at]) m4_include([tests/ovn-ofctrl-seqno.at]) m4_include([tests/ovn-sbctl.at]) +diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c +index dc13fa9ca..3a0b7c3e3 100644 +--- a/utilities/ovn-nbctl.c ++++ b/utilities/ovn-nbctl.c +@@ -805,6 +805,8 @@ static void + nbctl_pre_sync(struct ctl_context *base OVS_UNUSED) + { + force_wait = true; ++ /* Monitor nb_cfg to detect and handle potential overflows. */ ++ ovsdb_idl_add_column(base->idl, &nbrec_nb_global_col_nb_cfg); + } + + static void +@@ -3976,6 +3978,8 @@ nbctl_pre_lr_route_add(struct ctl_context *ctx) + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_col_name); + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_col_static_routes); + ++ ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name); ++ + ovsdb_idl_add_column(ctx->idl, &nbrec_bfd_col_dst_ip); + + ovsdb_idl_add_column(ctx->idl, +@@ -3992,6 +3996,10 @@ nbctl_pre_lr_route_add(struct ctl_context *ctx) + &nbrec_logical_router_static_route_col_options); + } + ++static char * OVS_WARN_UNUSED_RESULT ++lrp_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist, ++ const struct nbrec_logical_router_port **lrp_p); ++ + static void + nbctl_lr_route_add(struct ctl_context *ctx) + { +@@ -4001,6 +4009,7 @@ nbctl_lr_route_add(struct ctl_context *ctx) + ctx->error = error; + return; + } ++ const struct nbrec_logical_router_port *out_lrp = NULL; + char *prefix = NULL, *next_hop = NULL; + + const char *policy = shash_find_data(&ctx->options, "--policy"); +@@ -4034,9 +4043,15 @@ nbctl_lr_route_add(struct ctl_context *ctx) + ? normalize_ipv6_addr_str(ctx->argv[3]) + : normalize_ipv4_addr_str(ctx->argv[3]); + if (!next_hop) { +- ctl_error(ctx, "bad %s nexthop argument: %s", +- v6_prefix ? "IPv6" : "IPv4", ctx->argv[3]); +- goto cleanup; ++ /* check if it is a output port. */ ++ error = lrp_by_name_or_uuid(ctx, ctx->argv[3], true, &out_lrp); ++ if (error) { ++ ctl_error(ctx, "bad %s nexthop argument: %s", ++ v6_prefix ? "IPv6" : "IPv4", ctx->argv[3]); ++ free(error); ++ goto cleanup; ++ } ++ next_hop = ""; + } + } + +@@ -4063,6 +4078,15 @@ nbctl_lr_route_add(struct ctl_context *ctx) + } + } + ++ if (ctx->argc == 5) { ++ /* validate output port. */ ++ error = lrp_by_name_or_uuid(ctx, ctx->argv[4], true, &out_lrp); ++ if (error) { ++ ctx->error = error; ++ goto cleanup; ++ } ++ } ++ + bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; + bool ecmp_symmetric_reply = shash_find(&ctx->options, + "--ecmp-symmetric-reply") != NULL; +@@ -4081,7 +4105,7 @@ nbctl_lr_route_add(struct ctl_context *ctx) + ctl_error(ctx, "bfd dst_ip cannot be discard."); + goto cleanup; + } +- if (ctx->argc == 5) { ++ if (out_lrp) { + if (is_discard_route) { + ctl_error(ctx, "outport is not valid for discard routes."); + goto cleanup; +@@ -4104,22 +4128,22 @@ nbctl_lr_route_add(struct ctl_context *ctx) + nbrec_logical_router_static_route_verify_nexthop(route); + nbrec_logical_router_static_route_set_ip_prefix(route, prefix); + nbrec_logical_router_static_route_set_nexthop(route, next_hop); +- if (ctx->argc == 5) { ++ if (out_lrp) { + nbrec_logical_router_static_route_set_output_port( +- route, ctx->argv[4]); ++ route, out_lrp->name); + } + if (policy) { + nbrec_logical_router_static_route_set_policy(route, policy); + } + if (bfd) { + if (!nb_bt) { +- if (ctx->argc != 5) { ++ if (!out_lrp) { + ctl_error(ctx, "insert entry in the BFD table failed"); + goto cleanup; + } + nb_bt = nbrec_bfd_insert(ctx->txn); + nbrec_bfd_set_dst_ip(nb_bt, next_hop); +- nbrec_bfd_set_logical_port(nb_bt, ctx->argv[4]); ++ nbrec_bfd_set_logical_port(nb_bt, out_lrp->name); + } + nbrec_logical_router_static_route_set_bfd(route, nb_bt); + } +@@ -4142,8 +4166,9 @@ nbctl_lr_route_add(struct ctl_context *ctx) + route = nbrec_logical_router_static_route_insert(ctx->txn); + nbrec_logical_router_static_route_set_ip_prefix(route, prefix); + nbrec_logical_router_static_route_set_nexthop(route, next_hop); +- if (ctx->argc == 5) { +- nbrec_logical_router_static_route_set_output_port(route, ctx->argv[4]); ++ if (out_lrp) { ++ nbrec_logical_router_static_route_set_output_port(route, ++ out_lrp->name); + } + if (policy) { + nbrec_logical_router_static_route_set_policy(route, policy); +@@ -4159,19 +4184,21 @@ nbctl_lr_route_add(struct ctl_context *ctx) + nbrec_logical_router_update_static_routes_addvalue(lr, route); + if (bfd) { + if (!nb_bt) { +- if (ctx->argc != 5) { ++ if (!out_lrp) { + ctl_error(ctx, "insert entry in the BFD table failed"); + goto cleanup; + } + nb_bt = nbrec_bfd_insert(ctx->txn); + nbrec_bfd_set_dst_ip(nb_bt, next_hop); +- nbrec_bfd_set_logical_port(nb_bt, ctx->argv[4]); ++ nbrec_bfd_set_logical_port(nb_bt, out_lrp->name); + } + nbrec_logical_router_static_route_set_bfd(route, nb_bt); + } + + cleanup: +- free(next_hop); ++ if (next_hop && strlen(next_hop)) { ++ free(next_hop); ++ } + free(prefix); + } + +@@ -5847,12 +5874,18 @@ print_route(const struct nbrec_logical_router_static_route *route, + { + + char *prefix = normalize_prefix_str(route->ip_prefix); +- char *next_hop = !strcmp(route->nexthop, "discard") +- ? xasprintf("discard") +- : normalize_prefix_str(route->nexthop); ++ char *next_hop = ""; ++ ++ if (!strcmp(route->nexthop, "discard")) { ++ next_hop = xasprintf("discard"); ++ } else if (strlen(route->nexthop)) { ++ next_hop = normalize_prefix_str(route->nexthop); ++ } + ds_put_format(s, "%25s %25s", prefix, next_hop); + free(prefix); +- free(next_hop); ++ if (strlen(next_hop)) { ++ free(next_hop); ++ } + + if (route->policy) { + ds_put_format(s, " %s", route->policy); diff --git a/SPECS/ovn-2021.spec b/SPECS/ovn-2021.spec index 1936c34..951f225 100644 --- a/SPECS/ovn-2021.spec +++ b/SPECS/ovn-2021.spec @@ -51,7 +51,7 @@ Summary: Open Virtual Network support Group: System Environment/Daemons URL: http://www.ovn.org/ Version: 21.06.0 -Release: 17%{?commit0:.%{date}git%{shortcommit0}}%{?dist} +Release: 29%{?commit0:.%{date}git%{shortcommit0}}%{?dist} Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release} Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1 @@ -527,73 +527,133 @@ fi %{_unitdir}/ovn-controller-vtep.service %changelog -* Tue Jul 27 2021 Numan Siddique - 21.06.0-17 +* Tue Sep 14 2021 Ilya Maximets - 21.06.0-29 +- ovn-northd: Avoid verification of NB_Global.options if nothing changed. + [Gerrit: 50dc6ec9b9d1312caf2d6f9d19cf19d6bc73e3f3] + [Upstream: 27064c554fe6a3dfe4dd5800e884eec70cd3d793] + +* Tue Sep 14 2021 Ilya Maximets - 21.06.0-28 +- ovn-northd: Fix update of a mac prefix. + [Gerrit: ea2eb903d7220c01931c7e05f53dad8a84f0a715] + [Upstream: b6bf5e99b5a76c9a9df83896c2d1e40e3c5f4471] + +* Thu Sep 02 2021 Mohammad Heib - 21.06.0-27 +- ovn-nbctl: Monitor nb_cfg to detect and handle potential overflows (#1979774) + [Gerrit: 5a7342c8f1340e5739a8bceb2d3a81a07b371d1d] + [Upstream: b1a07090740ac9a29e4a2475ad07bf9c37991b43] + +* Mon Aug 30 2021 Numan Siddique - 21.06.0-26 +- Revert "Revert features detection and zero-snat patches." + [Gerrit: 666d6640be7155ca0b0bc12b0d5af626090e0375] + [Upstream: N/A] + +* Mon Aug 30 2021 Mark Michelson - 21.06.0-25 +- Revert features detection and zero-snat patches. (#1992705) + [Gerrit: 8f5c081c322a25576aea1cc7d2f5d996f5804196] + [Upstream: N/A] + +* Wed Aug 25 2021 Lorenzo Bianconi - 21.06.0-24 +- northd: allow to configure routes with no nexthop + [Gerrit: c86436ca8edbb7c4cdf3b965269792c51592c385] + [Upstream: c0085228893e7bf07190fcccf50cf588b028edaa] + +* Wed Aug 25 2021 Lorenzo Bianconi - 21.06.0-23 +- nbctl: validate outport in nbctl_lr_route_add + [Gerrit: ddccb1dbaf54c78c810d4d32da6d96197cc16caf] + [Upstream: d866959ba6ea066f88558071eda9943258ee7fa7] + +* Wed Aug 18 2021 Lorenzo Bianconi - 21.06.0-22 +- controller: run ipv6_pd only on a proper controller for l3gateway mode + [Gerrit: 11d6a1bac2e38a81646271c127b602533a3f9dc4] + [Upstream: b8b24398657e5bb82dcbdb5ce55a74e261e30767] + +* Wed Aug 18 2021 Lorenzo Bianconi - 21.06.0-21 +- controller: ipv6_pd: properly update ipv6_ra_pd_list pb option in sb db + [Gerrit: 55ec986ed1a506e3c149c5a7d69fdd661970d777] + [Upstream: 9704cfe54dc2a0a6752139d07bb9f563e7e27aae] + +* Wed Aug 18 2021 Lorenzo Bianconi - 21.06.0-20 +- controller: add ipv6_pd debug messages + [Gerrit: 969495b1f078b8e52fb2c1b1b53bb561c8f66d22] + [Upstream: c3afcb44846116fd6e311ca9a250a46dbff6b2a8] + +* Fri Aug 06 2021 Lorenzo Bianconi - 21.06.0-19 +- northd: do not configure ECMP routes with wrong next-hop + [Gerrit: c8b215179d2408ce1d1e0dd6569f72a3c7e5724d] + [Upstream: 9cd64780d89c4acd2ae0c12693be66962ada97cd] + +* Tue Jul 27 2021 Numan Siddique - 21.06.0-18 - ovn-controller: Split logical flow and physical flow processing. (#1986484) [Gerrit: 6e1e90064ad1f5769fdc96e3b735ee236c30b7e2] [Upstream: ceb12c9190a124c70bc938e8e1bea17612b498be] -* Tue Jul 27 2021 Dumitru Ceara - 21.06.0-16 +* Tue Jul 27 2021 Dumitru Ceara - 21.06.0-17 - ovn.at: Fix "Symmetric IPv6 ECMP reply flows" test. [Gerrit: 801f6c69c3bb45f981135ac6c197fdbd3f18118d] [Upstream: 4e6c498068dc4fa9546d3661f78f0a42e99c74bb] -* Tue Jul 27 2021 Dumitru Ceara - 21.06.0-15 +* Tue Jul 27 2021 Dumitru Ceara - 21.06.0-16 - ovn-controller: Handle DNAT/no-NAT conntrack tuple collisions. (#1939676) [Gerrit: abfd62cb228b7d311ae7cae18adfe9cfcf68affc] [Upstream: 58683a4271e6a885f2f2aea27f3df88e69a5c388] -* Tue Jul 27 2021 Dumitru Ceara - 21.06.0-14 +* Tue Jul 27 2021 Dumitru Ceara - 21.06.0-15 - ovn-controller: Detect OVS datapath capabilities. [Gerrit: ca1df0396e6e6eb016c3cad82db7c49cc05ec99a] [Upstream: 56e2cd3a2f06b79b7d57cc8637fc0d258652aff5] -* Mon Jul 26 2021 Lorenzo Bianconi - 21.06.0-13 +* Mon Jul 26 2021 Lorenzo Bianconi - 21.06.0-14 - northd: do not centralize traffic for unclaimed virtual ports [Gerrit: 5b6826906a76779b527d72d1c49d211ce492e62e] [Upstream: N/A] -* Thu Jul 15 2021 Ihar Hrachyshka - 21.06.0-12 +* Thu Jul 15 2021 Ihar Hrachyshka - 21.06.0-13 - Don't suppress localport traffic directed to external port (#1974062) [Gerrit: 330e6e7400e1d5e4e6ef4fc6446eeaa945ac6a13] [Upstream: 1148580290d0ace803f20aeaa0241dd51c100630] -* Thu Jul 15 2021 Dumitru Ceara - 21.06.0-11 +* Thu Jul 15 2021 Dumitru Ceara - 21.06.0-12 - northd: Fix multicast table full comparison. (#1979870) [Gerrit: 38f44df1b8a0ed1ebb86183de29d9e5c3423abdb] [Upstream: 969c98d7297b526c704c6fd2a7138f584f9ad577] -* Thu Jul 15 2021 Dumitru Ceara - 21.06.0-10 +* Thu Jul 15 2021 Dumitru Ceara - 21.06.0-11 - northd-ddlog: Fix IP family match for DNAT flows. [Gerrit: 518ea2e15df2c77fc19afe74b68d616983638743] [Upstream: 38467229905bdf09a3afa325eaa7a98183f44c72] -* Thu Jul 15 2021 Ihar Hrachyshka - 21.06.0-9 +* Thu Jul 15 2021 Ihar Hrachyshka - 21.06.0-10 - Disable ARP/NA responders for vlan-passthru switches [Gerrit: 56fbcfaf71d9a6df0b4cdee583c8d17ca7a82aab] [Upstream: ea57f666f6eef1eb1d578f0e975baa14c5d23ec9] -* Thu Jul 15 2021 Ben Pfaff - 21.06.0-8 +* Thu Jul 15 2021 Ben Pfaff - 21.06.0-9 - tests: Fix "vlan traffic for external network with distributed..." [Gerrit: ca26e77c4206a39ae6eab4a1d430ef04b726b640] [Upstream: 5453cc8ca5535e3f33d1b191929e1a3c9ad30f20] -* Thu Jul 15 2021 Dumitru Ceara - 21.06.0-7 +* Thu Jul 15 2021 Dumitru Ceara - 21.06.0-8 - ovn-controller: Fix port group I-P when they contain non-vif ports. [Gerrit: 3c7f29238c889b248155cbb2c866c0adbf8b46c1] [Upstream: 1bb32e0f8146d7f4fff84af5e3d2836ebe939e04] -* Thu Jul 15 2021 Numan Siddique - 21.06.0-6 +* Thu Jul 15 2021 Numan Siddique - 21.06.0-7 - system-tests: Fix the test file. [Gerrit: 85337cec3f2e5967a14afc5a552ac17dff6c15f6] [Upstream: 9c1978300fa12709e01df07ed8403d8ad43f61fb] -* Thu Jul 15 2021 Mark Michelson - 21.06.0-5 +* Thu Jul 15 2021 Mark Michelson - 21.06.0-6 - northd: Swap src and dst eth addresses in router egress loop. [Gerrit: 86207fcac41b639d14de05e1b0965ad9d8293218] [Upstream: 9be470dc69daf16ac1fbbe13cc295f46862226ad] -* Tue Jun 29 2021 Han Zhou - 21.06.0-4 +* Tue Jun 29 2021 Han Zhou - 21.06.0-5 - ovn.at: Fix test "virtual ports -- ovn-northd-ddlog". [Gerrit: d61cfca4cadca33e598ba1a23cfdbe81a72d3501] [Upstream: 9e3404e03620f183adc4f05db13bf5a38618b757] +* Fri Jun 18 2021 Mark Michelson - 21.06.0-4 +- Prepare for 21.06.1. + [Gerrit: 9ae4001f70b4a828018a55a36a1b228f4846b624] + [Upstream: N/A] +