This commit adds the ability for ovn-ic to filter routes between VPCs. In use cases where the user is using vpc-peering(route tag) handling multiple points of redistribution, when we connect more than one TS in the same Logical Router it is essential that we have control over which routes will be filtered or advertised by transit switch.
Co-authored-by: Lucas Vargas Dias <[email protected]> Signed-off-by: Lucas Vargas Dias <[email protected]> Signed-off-by: Paulo Guilherme da Silva <[email protected]> --- ic/ovn-ic.c | 122 ++++++++------- lib/ovn-util.c | 49 ++++++ lib/ovn-util.h | 3 + ovn-nb.xml | 44 +++++- tests/ovn-ic.at | 399 ++++++++++++------------------------------------ 5 files changed, 260 insertions(+), 357 deletions(-) diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c index c8796680b..1ef331420 100644 --- a/ic/ovn-ic.c +++ b/ic/ovn-ic.c @@ -1069,69 +1069,63 @@ get_nexthop_from_lport_addresses(bool is_v4, return true; } +static bool +prefix_is_filtered(struct in6_addr *prefix, + unsigned int plen, + const struct nbrec_logical_router *nb_lr, + const struct nbrec_logical_router_port *ts_lrp, + bool is_advertisement) +{ + struct ds filter_list = DS_EMPTY_INITIALIZER; + const char *filter_direction = is_advertisement ? "ic-route-filter-adv" :\ + "ic-route-filter-learn"; + if (ts_lrp) { + const char *lrp_route_filter = smap_get(&ts_lrp->options, + filter_direction); + if (lrp_route_filter) { + ds_put_format(&filter_list, "%s,", lrp_route_filter); + } + } + const char *lr_route_filter = smap_get(&nb_lr->options, + filter_direction); + if (lr_route_filter) { + ds_put_format(&filter_list, "%s,", lr_route_filter); + } + + if (!filter_list.length) { + ds_destroy(&filter_list); + return true; + } + + bool matched = find_prefix_in_list(prefix, plen, ds_cstr(&filter_list), + filter_direction); + ds_destroy(&filter_list); + return matched; +} + static bool prefix_is_deny_listed(const struct smap *nb_options, struct in6_addr *prefix, unsigned int plen) { - const char *denylist = smap_get(nb_options, "ic-route-denylist"); + const char *filter_name = "ic-route-denylist"; + const char *denylist = smap_get(nb_options, filter_name); if (!denylist || !denylist[0]) { denylist = smap_get(nb_options, "ic-route-blacklist"); if (!denylist || !denylist[0]) { return false; } } - struct in6_addr bl_prefix; - unsigned int bl_plen; - char *cur, *next, *start; - next = start = xstrdup(denylist); - bool matched = false; - while ((cur = strsep(&next, ",")) && *cur) { - if (!ip46_parse_cidr(cur, &bl_prefix, &bl_plen)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "Bad format in nb_global options:" - "ic-route-denylist: %s. CIDR expected.", cur); - continue; - } - - if (IN6_IS_ADDR_V4MAPPED(&bl_prefix) != IN6_IS_ADDR_V4MAPPED(prefix)) { - continue; - } - - /* 192.168.0.0/16 does not belong to 192.168.0.0/17 */ - if (plen < bl_plen) { - continue; - } - - if (IN6_IS_ADDR_V4MAPPED(prefix)) { - ovs_be32 bl_prefix_v4 = in6_addr_get_mapped_ipv4(&bl_prefix); - ovs_be32 prefix_v4 = in6_addr_get_mapped_ipv4(prefix); - ovs_be32 mask = be32_prefix_mask(bl_plen); - - if ((prefix_v4 & mask) != (bl_prefix_v4 & mask)) { - continue; - } - } else { - struct in6_addr bl_mask = ipv6_create_mask(bl_plen); - struct in6_addr m_prefix = ipv6_addr_bitand(prefix, &bl_mask); - struct in6_addr m_bl_prefix = ipv6_addr_bitand(&bl_prefix, - &bl_mask); - if (!ipv6_addr_equals(&m_prefix, &m_bl_prefix)) { - continue; - } - } - matched = true; - break; - } - free(start); - return matched; + return find_prefix_in_list(prefix, plen, denylist, filter_name); } static bool route_need_advertise(const char *policy, struct in6_addr *prefix, unsigned int plen, - const struct smap *nb_options) + const struct smap *nb_options, + const struct nbrec_logical_router *nb_lr, + const struct nbrec_logical_router_port *ts_lrp) { if (!smap_get_bool(nb_options, "ic-route-adv", false)) { return false; @@ -1153,6 +1147,11 @@ route_need_advertise(const char *policy, if (prefix_is_deny_listed(nb_options, prefix, plen)) { return false; } + + if (!prefix_is_filtered(prefix, plen, nb_lr, ts_lrp, true)) { + return false; + } + return true; } @@ -1207,7 +1206,8 @@ add_static_to_routes_ad( const struct nbrec_logical_router *nb_lr, const struct lport_addresses *nexthop_addresses, const struct smap *nb_options, - const char *route_tag) + const char *route_tag, + const struct nbrec_logical_router_port *ts_lrp) { struct in6_addr prefix, nexthop; unsigned int plen; @@ -1216,7 +1216,8 @@ add_static_to_routes_ad( return; } - if (!route_need_advertise(nb_route->policy, &prefix, plen, nb_options)) { + if (!route_need_advertise(nb_route->policy, &prefix, plen, nb_options, + nb_lr, ts_lrp)) { return; } @@ -1257,7 +1258,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network, const struct lport_addresses *nexthop_addresses, const struct smap *nb_options, const struct nbrec_logical_router *nb_lr, - const char *route_tag) + const char *route_tag, + const struct nbrec_logical_router_port *ts_lrp) { struct in6_addr prefix, nexthop; unsigned int plen; @@ -1265,7 +1267,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network, return; } - if (!route_need_advertise(NULL, &prefix, plen, nb_options)) { + if (!route_need_advertise(NULL, &prefix, plen, nb_options, + nb_lr, ts_lrp)) { VLOG_DBG("Route ad: skip network %s of lrp %s.", network, nb_lrp->name); return; @@ -1319,7 +1322,8 @@ static bool route_need_learn(const struct nbrec_logical_router *lr, const struct icsbrec_route *isb_route, struct in6_addr *prefix, unsigned int plen, - const struct smap *nb_options) + const struct smap *nb_options, + const struct nbrec_logical_router_port *ts_lrp) { if (!smap_get_bool(nb_options, "ic-route-learn", false)) { return false; @@ -1338,6 +1342,11 @@ route_need_learn(const struct nbrec_logical_router *lr, return false; } + if (!prefix_is_filtered(prefix, plen, lr, ts_lrp, false)) { + return false; + } + + if (route_has_local_gw(lr, isb_route->route_table, isb_route->ip_prefix)) { VLOG_DBG("Skip learning %s (rtb:%s) route, as we've got one with " "local GW", isb_route->ip_prefix, isb_route->route_table); @@ -1467,7 +1476,7 @@ sync_learned_routes(struct ic_context *ctx, continue; } if (!route_need_learn(ic_lr->lr, isb_route, &prefix, plen, - &nb_global->options)) { + &nb_global->options, lrp)) { continue; } @@ -1653,7 +1662,8 @@ build_ts_routes_to_adv(struct ic_context *ctx, struct lport_addresses *ts_port_addrs, const struct nbrec_nb_global *nb_global, const char *ts_route_table, - const char *route_tag) + const char *route_tag, + const struct nbrec_logical_router_port *ts_lrp) { const struct nbrec_logical_router *lr = ic_lr->lr; @@ -1676,7 +1686,7 @@ build_ts_routes_to_adv(struct ic_context *ctx, } else if (!strcmp(ts_route_table, nb_route->route_table)) { /* It may be a route to be advertised */ add_static_to_routes_ad(routes_ad, nb_route, lr, ts_port_addrs, - &nb_global->options, route_tag); + &nb_global->options, route_tag, ts_lrp); } } @@ -1688,7 +1698,7 @@ build_ts_routes_to_adv(struct ic_context *ctx, add_network_to_routes_ad(routes_ad, lrp->networks[j], lrp, ts_port_addrs, &nb_global->options, - lr, route_tag); + lr, route_tag, ts_lrp); } } else { /* The router port of the TS port is ignored. */ @@ -1752,7 +1762,7 @@ collect_lr_routes(struct ic_context *ctx, route_tag = ""; } build_ts_routes_to_adv(ctx, ic_lr, routes_ad, &ts_port_addrs, - nb_global, route_table, route_tag); + nb_global, route_table, route_tag, lrp); destroy_lport_addresses(&ts_port_addrs); } } diff --git a/lib/ovn-util.c b/lib/ovn-util.c index c65b36bb5..675890c32 100644 --- a/lib/ovn-util.c +++ b/lib/ovn-util.c @@ -1384,6 +1384,55 @@ prefix_is_link_local(const struct in6_addr *prefix, unsigned int plen) ((prefix->s6_addr[1] & 0xc0) == 0x80)); } +bool +find_prefix_in_list(const struct in6_addr *prefix, unsigned int plen, + const char *prefix_list, const char *filter_name) +{ + struct in6_addr bl_prefix; + char *cur, *next, *start; + unsigned int bl_plen; + bool matched = false; + next = start = xstrdup(prefix_list); + while ((cur = strsep(&next, ",")) && *cur) { + if (!ip46_parse_cidr(cur, &bl_prefix, &bl_plen)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "Bad format in LR, LRP or nb_global options:" + "%s: %s. CIDR expected.", filter_name, cur); + continue; + } + + if (IN6_IS_ADDR_V4MAPPED(&bl_prefix) != IN6_IS_ADDR_V4MAPPED(prefix)) { + continue; + } + + /* 192.168.0.0/16 does not belong to 192.168.0.0/17 */ + if (plen < bl_plen) { + continue; + } + + if (IN6_IS_ADDR_V4MAPPED(prefix)) { + ovs_be32 bl_prefix_v4 = in6_addr_get_mapped_ipv4(&bl_prefix); + ovs_be32 prefix_v4 = in6_addr_get_mapped_ipv4(prefix); + ovs_be32 mask = be32_prefix_mask(bl_plen); + + if ((prefix_v4 & mask) != (bl_prefix_v4 & mask)) { + continue; + } + } else { + struct in6_addr bl_mask = ipv6_create_mask(bl_plen); + struct in6_addr m_prefix = ipv6_addr_bitand(prefix, &bl_mask); + struct in6_addr m_bl_prefix = ipv6_addr_bitand(&bl_prefix, + &bl_mask); + if (!ipv6_addr_equals(&m_prefix, &m_bl_prefix)) { + continue; + } + } + matched = true; + break; + } + free(start); + return matched; +} const struct sbrec_port_binding * lport_lookup_by_name(struct ovsdb_idl_index *sbrec_port_binding_by_name, const char *name) diff --git a/lib/ovn-util.h b/lib/ovn-util.h index ce8cc0568..cdbd2f3d1 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -492,6 +492,9 @@ bool ovn_update_swconn_at(struct rconn *swconn, const char *target, bool prefix_is_link_local(const struct in6_addr *prefix, unsigned int plen); +bool find_prefix_in_list(const struct in6_addr *prefix, unsigned int plen, + const char *prefix_list, const char *filter_name); + const struct sbrec_port_binding *lport_lookup_by_name( struct ovsdb_idl_index *sbrec_port_binding_by_name, const char *name); diff --git a/ovn-nb.xml b/ovn-nb.xml index ff5f2f249..55872ea36 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -3161,8 +3161,29 @@ or for established sessions as we will commit everything in addition to already existing stateful NATs and LBs. </column> - </group> + <column name="options" key="ic-route-filter-adv"> + <p> + This option expects list of CIDRs delimited by "," that's present + in the Logical Router. A route will not be advertised if the + route's prefix belongs to any of the CIDRs listed. + + This allows to filter CIDR prefixes in the process of advertising + routes in <code>ovn-ic</code> daemon. + </p> + </column> + + <column name="options" key="ic-route-filter-learn"> + <p> + This option expects list of CIDRs delimited by "," that's present + in the Logical Router. A route will not be learned if the + route's prefix belongs to any of the CIDRs listed. + + This allows to filter CIDR prefixes in the process of learning + routes in <code>ovn-ic</code> daemon. + </p> + </column> + </group> <group title="Common Columns"> <column name="external_ids"> See <em>External IDs</em> at the beginning of this document. @@ -4097,6 +4118,27 @@ or instead of the autodiscovery. Also it is then irrelevant if the port is bound locally. </column> + <column name="options" key="ic-route-filter-adv"> + <p> + This option expects list of CIDRs delimited by "," that's present + in the Logical Router Port. A route will be advertised if the + route's prefix belongs to any of the CIDRs listed. + + This allows to filter CIDR prefixes in the process of advertising + routes in <code>ovn-ic</code> daemon. + </p> + </column> + + <column name="options" key="ic-route-filter-learn"> + <p> + This option expects list of CIDRs delimited by "," that's present + in the Logical Router Port. A route will be learned if the + route's prefix belongs to any of the CIDRs listed. + + This allows to filter CIDR prefixes in the process of learning + routes in <code>ovn-ic</code> daemon. + </p> + </column> </group> <group title="Attachment"> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at index 0fd38acb2..508db8f75 100644 --- a/tests/ovn-ic.at +++ b/tests/ovn-ic.at @@ -2673,331 +2673,130 @@ OVN_CLEANUP_IC([az1], [az2]) AT_CLEANUP ]) + OVN_FOR_EACH_NORTHD([ -AT_SETUP([spine-leaf: 3 AZs, 3 HVs, 3 LSs, connected via transit spine switch]) -AT_KEYWORDS([spine leaf]) -AT_SKIP_IF([test $HAVE_SCAPY = no]) +AT_SETUP([ovn-ic -- prefix filter -- filtering routes]) ovn_init_ic_db +ovn-ic-nbctl ts-add ts1 -ovn_start az1 -ovn_start az2 -ovn_start az3 +for i in 1 2; do + ovn_start az$i + ovn_as az$i -# Logical network: -# Single network 172.16.1.0/24. Three switches with VIF ports on HVs in three -# separate AZs, connected to a spine transit switch via 'switch' ports. -# Third switch has a port with unknown address, but we're only sending packets -# between ports on other two switches. + # Enable route learning at AZ level + check ovn-nbctl set nb_global . options:ic-route-learn=true + # Enable route advertising at AZ level + check ovn-nbctl set nb_global . options:ic-route-adv=true +done -ovn-ic-nbctl ts-add spine -ovn_as az1 check ovn-nbctl ls-add ls1 -ovn_as az2 check ovn-nbctl ls-add ls2 -ovn_as az3 check ovn-nbctl ls-add ls3 +# Create new transit switche and LRs. Test topology is next: +# logical router (lr11) - transit switch (ts1) - logical router (lr12) -# Connect ls1 to spine. -ovn_as az1 -check ovn-nbctl lsp-add spine spine-to-ls1 -check ovn-nbctl lsp-add ls1 ls1-to-spine -check ovn-nbctl lsp-set-type spine-to-ls1 switch peer=ls1-to-spine -check ovn-nbctl lsp-set-type ls1-to-spine switch peer=spine-to-ls1 -# Connect ls2 to spine. -ovn_as az2 -check ovn-nbctl lsp-add spine spine-to-ls2 -check ovn-nbctl lsp-add ls2 ls2-to-spine -check ovn-nbctl lsp-set-type spine-to-ls2 switch peer=ls2-to-spine -check ovn-nbctl lsp-set-type ls2-to-spine switch peer=spine-to-ls2 - -# Connect ls3 to spine. -ovn_as az3 -check ovn-nbctl lsp-add spine spine-to-ls3 -check ovn-nbctl lsp-add ls3 ls3-to-spine -check ovn-nbctl lsp-set-type spine-to-ls3 switch peer=ls3-to-spine -check ovn-nbctl lsp-set-type ls3-to-spine switch peer=spine-to-ls3 - -# Create logical port ls1-lp1 in ls1 -ovn_as az1 check ovn-nbctl lsp-add ls1 ls1-lp1 \ --- lsp-set-addresses ls1-lp1 "f0:00:00:01:02:01 172.16.1.1" -# Create logical port ls1-lp2 in ls1 -ovn_as az1 check ovn-nbctl lsp-add ls1 ls1-lp2 \ --- lsp-set-addresses ls1-lp2 "f0:00:00:01:02:02 172.16.1.2" - -# Create logical port ls2-lp1 in ls2 -ovn_as az2 check ovn-nbctl lsp-add ls2 ls2-lp1 \ --- lsp-set-addresses ls2-lp1 "f0:00:00:01:02:03 172.16.1.3" -# Create logical port ls2-lp2 in ls2 -ovn_as az2 check ovn-nbctl lsp-add ls2 ls2-lp2 \ --- lsp-set-addresses ls2-lp2 "f0:00:00:01:02:04 172.16.1.4" - -# Create logical port ls3-lp1 in ls3 with unknown address. -check ovn-nbctl lsp-add ls3 ls3-lp1 -- lsp-set-addresses ls3-lp1 unknown - -# Create hypervisors and OVS ports corresponding to logical ports. -net_add n1 +# create lr11, lr12 and connect them to ts1 +for i in 1 2; do + ovn_as az$i -sim_add hv1 -as hv1 -check ovs-vsctl add-br br-phys -ovn_az_attach az1 n1 br-phys 192.168.1.1 16 -check ovs-vsctl set open . external-ids:ovn-is-interconn=true -ovs-vsctl -- add-port br-int vif1 -- \ - set interface vif1 external-ids:iface-id=ls1-lp1 \ - options:tx_pcap=hv1/vif1-tx.pcap \ - options:rxq_pcap=hv1/vif1-rx.pcap \ - ofport-request=1 -ovs-vsctl -- add-port br-int vif2 -- \ - set interface vif2 external-ids:iface-id=ls1-lp2 \ - options:tx_pcap=hv1/vif2-tx.pcap \ - options:rxq_pcap=hv1/vif2-rx.pcap \ - ofport-request=2 + lr=lr1$i + check ovn-nbctl lr-add $lr -sim_add hv2 -as hv2 -check ovs-vsctl add-br br-phys -ovn_az_attach az2 n1 br-phys 192.168.2.1 16 -check ovs-vsctl set open . external-ids:ovn-is-interconn=true -ovs-vsctl -- add-port br-int vif3 -- \ - set interface vif3 external-ids:iface-id=ls2-lp1 \ - options:tx_pcap=hv2/vif3-tx.pcap \ - options:rxq_pcap=hv2/vif3-rx.pcap \ - ofport-request=3 -ovs-vsctl -- add-port br-int vif4 -- \ - set interface vif4 external-ids:iface-id=ls2-lp2 \ - options:tx_pcap=hv2/vif4-tx.pcap \ - options:rxq_pcap=hv2/vif4-rx.pcap \ - ofport-request=4 - -sim_add hv3 -as hv3 -check ovs-vsctl add-br br-phys -ovn_az_attach az3 n1 br-phys 192.168.3.1 16 -check ovs-vsctl set open . external-ids:ovn-is-interconn=true -ovs-vsctl -- add-port br-int vif5 -- \ - set interface vif5 external-ids:iface-id=ls3-lp1 \ - options:tx_pcap=hv3/vif5-tx.pcap \ - options:rxq_pcap=hv3/vif5-rx.pcap \ - ofport-request=5 + lrp=lrp-$lr-ts1 + lsp=lsp-ts1-$lr + # Create LRP and connect to TS + check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:ab:0$i 169.254.101.$i/24 fe80:10::$i/64 + check ovn-nbctl lsp-add ts1 $lsp \ + -- lsp-set-addresses $lsp router \ + -- lsp-set-type $lsp router \ + -- lsp-set-options $lsp router-port=$lrp +done -# Bind transit switch ports to their chassis. -check ovn_as az1 ovn-nbctl lsp-set-options spine-to-ls1 requested-chassis=hv1 -check ovn_as az2 ovn-nbctl lsp-set-options spine-to-ls2 requested-chassis=hv2 -check ovn_as az3 ovn-nbctl lsp-set-options spine-to-ls3 requested-chassis=hv3 -# Pre-populate the hypervisors' ARP tables so that we don't lose any -# packets for ARP resolution (native tunneling doesn't queue packets -# for ARP resolution). -OVN_POPULATE_ARP -ovn_as az1 -check ovn-nbctl --wait=hv sync -ovn-sbctl dump-flows > az1/sbflows +# Create directly-connected route in lr12 -ovn_as az2 -check ovn-nbctl --wait=hv sync -ovn-sbctl dump-flows > az2/sbflows +ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12-1 aa:aa:aa:aa:bb:01 "192.168.12.1/24" "2001:db12::1/64" +ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12-2 aa:aa:aa:aa:bb:02 "192.168.2.1/24" "2001:db22::1/64" -ovn_as az3 -check ovn-nbctl --wait=hv sync -ovn-sbctl dump-flows > az3/sbflows -dnl Check that FDB learning is enabled for remote ports in the egress pipeline. -AT_CHECK([grep -E "ls_out.*fdb.*spine-to-" az1/sbflows | ovn_strip_lflows], [0], [dnl - table=??(ls_out_lookup_fdb ), priority=100 , match=(inport == "spine-to-ls2"), action=(reg0[[11]] = lookup_fdb(inport, eth.src); next;) - table=??(ls_out_lookup_fdb ), priority=100 , match=(inport == "spine-to-ls3"), action=(reg0[[11]] = lookup_fdb(inport, eth.src); next;) - table=??(ls_out_put_fdb ), priority=100 , match=(inport == "spine-to-ls2" && reg0[[11]] == 0), action=(put_fdb(inport, eth.src); next;) - table=??(ls_out_put_fdb ), priority=100 , match=(inport == "spine-to-ls3" && reg0[[11]] == 0), action=(put_fdb(inport, eth.src); next;) +# Create directly-connected route in lr11 +ovn_as az1 ovn-nbctl --wait=sb lrp-add lr11 lrp-lr11 aa:aa:aa:aa:cc:01 "192.168.11.1/24" "2001:db11::1/64" + +check ovn-ic-nbctl --wait=sb sync + +# Test direct routes from lr12 were learned to lr11 +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl +192.168.12.0/24 169.254.101.2 +192.168.2.0/24 169.254.101.2 ]) -AT_CHECK([grep -E "ls_out.*fdb.*spine-to-" az2/sbflows | ovn_strip_lflows], [0], [dnl - table=??(ls_out_lookup_fdb ), priority=100 , match=(inport == "spine-to-ls1"), action=(reg0[[11]] = lookup_fdb(inport, eth.src); next;) - table=??(ls_out_lookup_fdb ), priority=100 , match=(inport == "spine-to-ls3"), action=(reg0[[11]] = lookup_fdb(inport, eth.src); next;) - table=??(ls_out_put_fdb ), priority=100 , match=(inport == "spine-to-ls1" && reg0[[11]] == 0), action=(put_fdb(inport, eth.src); next;) - table=??(ls_out_put_fdb ), priority=100 , match=(inport == "spine-to-ls3" && reg0[[11]] == 0), action=(put_fdb(inport, eth.src); next;) + +# Test direct routes from lr11 were learned to lr12 +OVS_WAIT_FOR_OUTPUT([ovn_as az2 ovn-nbctl lr-route-list lr12 | grep 192.168 | + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl +192.168.11.0/24 169.254.101.1 ]) -AT_CHECK([grep -E "ls_out.*fdb.*spine-to-" az3/sbflows | ovn_strip_lflows], [0], [dnl - table=??(ls_out_lookup_fdb ), priority=100 , match=(inport == "spine-to-ls1"), action=(reg0[[11]] = lookup_fdb(inport, eth.src); next;) - table=??(ls_out_lookup_fdb ), priority=100 , match=(inport == "spine-to-ls2"), action=(reg0[[11]] = lookup_fdb(inport, eth.src); next;) - table=??(ls_out_put_fdb ), priority=100 , match=(inport == "spine-to-ls1" && reg0[[11]] == 0), action=(put_fdb(inport, eth.src); next;) - table=??(ls_out_put_fdb ), priority=100 , match=(inport == "spine-to-ls2" && reg0[[11]] == 0), action=(put_fdb(inport, eth.src); next;) + +ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 options:ic-route-filter-adv=192.168.12.0/24 +# Test direct routes from lr12 were learned to lr11 +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl +192.168.12.0/24 169.254.101.2 ]) -check ovn-ic-nbctl --wait=sb sync +# set ic-route-filter-adv with invalid CIDR to advertise all routes +ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 options:ic-route-filter-adv="192.168.12.0/24,invalid" -ovn-ic-nbctl show > ic-nbctl.dump -AT_CAPTURE_FILE([ic-nbctl.dump]) +# Test direct routes from lr12 were learned to lr11 +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl +192.168.12.0/24 169.254.101.2 +192.168.2.0/24 169.254.101.2 +]) -(echo "---------ISB dump-----" - ovn-ic-sbctl show - echo "---------------------" - ovn-ic-sbctl list gateway - echo "---------------------" - ovn-ic-sbctl list datapath_binding - echo "---------------------" - ovn-ic-sbctl list port_binding - echo "---------------------" - ovn-ic-sbctl list route - echo "---------------------") > ic-sbctl.dump -AT_CAPTURE_FILE([ic-sbctl.dump]) +ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options ic-route-filter-adv +ovn_as az1 check ovn-nbctl set logical_router_port lrp-lr11-ts1 options:ic-route-filter-learn=192.168.2.0/24 -# Send ip packets between the two ports. -src_mac="f0:00:00:01:02:01" -dst_mac="f0:00:00:01:02:03" -src_ip=172.16.1.1 -dst_ip=172.16.1.3 -packet=$(fmt_pkt "Ether(dst='${dst_mac}', src='${src_mac}')/ \ - IP(src='${src_ip}', dst='${dst_ip}')/ \ - UDP(sport=1538, dport=4369)") - -# Check that datapath is not doing any extra work and sends the packet out -# through the tunnels. We expect the packet to enter the spine switch, be -# sent to userspace for FDB learning, then get broadcasted to other two -# zones via remote ports. -AT_CHECK([ovn_as az1 as hv1 ovs-appctl ofproto/trace --names \ - br-int in_port=vif1 $packet > ofproto-trace-1]) -AT_CAPTURE_FILE([ofproto-trace-1]) -AT_CHECK([grep 'Megaflow:' ofproto-trace-1], [0], [dnl -Megaflow: recirc_id=0,eth,ip,in_port=vif1,dl_src=f0:00:00:01:02:01,dl_dst=f0:00:00:01:02:03,nw_ecn=0,nw_frag=no -]) -AT_CHECK([cat ofproto-trace-1 | tail -1 \ - | grep -oE 'tnl_push|userspace|clone|br-phys_n1|vif[[0-9]]'], [0], [dnl -userspace -clone -tnl_push -br-phys_n1 -tnl_push -br-phys_n1 -]) - -# Actually send the packet. -check as hv1 ovs-appctl netdev-dummy/receive vif1 $packet - -# Wait for the FDB entries to be created and propagated to OpenFlow. Only -# one entry will be created - the entry for spine-to-ls1 port in the spine -# switch. -ovn_as az1 -wait_row_count FDB 1 -check ovn-nbctl --wait=hv sync +# Test direct routes from lr12 were learned to lr11 +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl +192.168.2.0/24 169.254.101.2 +]) -# Two entries are expected in the other zones - one for the remote port on -# the spine switch and one for the switch port on the leaf. -ovn_as az2 -wait_row_count FDB 2 -check ovn-nbctl --wait=hv sync -ovn_as az3 -wait_row_count FDB 2 -check ovn-nbctl --wait=hv sync -# FDB entry was created from the userspace() action in the datapath, but -# those actions will be updated to not have it shortly, so just wait for -# that to happen and don't try to catch the action while it's still in the -# datapath. -as hv2 ovs-appctl revalidator/wait -as hv3 ovs-appctl revalidator/wait - -# It's a little problematic to trace the other side, but we can check datapath -# actions. Note: 'actions:br-phys' is a stray tunnel packet destined for the -# other zone, but OVS from the 'main' namespace didn't learn addresses yet, -# so it broadcasts. -AT_CHECK([as hv2 ovs-appctl dpctl/dump-flows --names \ - | grep actions | sed 's/.*\(actions:.*\)/\1/' | sort], [0], [dnl -actions:br-phys -actions:tnl_pop(genev_sys_6081) -actions:vif3 -]) -AT_CHECK([as hv3 ovs-appctl dpctl/dump-flows --names \ - | grep actions | sed 's/.*\(actions:.*\)/\1/' | sort], [0], [dnl -actions:br-phys -actions:tnl_pop(genev_sys_6081) -actions:vif5 -]) - -# No modifications expected. -AT_CHECK([echo $packet > expected]) - -AT_CHECK([touch empty]) - -# Check that it is delivered where needed and not delivered where not. -OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [empty]) -OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [empty]) -OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected]) -OVN_CHECK_PACKETS([hv2/vif4-tx.pcap], [empty]) -OVN_CHECK_PACKETS([hv3/vif5-tx.pcap], [expected]) - -# Trace a reply packet. -reply=$(fmt_pkt "Ether(dst='${src_mac}', src='${dst_mac}')/ \ - IP(src='${dst_ip}', dst='${src_ip}')/ \ - UDP(sport=4369, dport=1538)") -# For the reply packet we expect only one userspace action for FDB update on -# the spine switch and only one tunnel push and send, because we already -# learned that MAC of vif1 is behind spine-ls1 and no longer need to broadcast -# to zone 3. -AT_CHECK([ovn_as az2 as hv2 ovs-appctl ofproto/trace --names \ - br-int in_port=vif3 $reply > ofproto-trace-2]) -AT_CAPTURE_FILE([ofproto-trace-2]) -AT_CHECK([grep 'Megaflow:' ofproto-trace-2], [0], [dnl -Megaflow: recirc_id=0,eth,ip,in_port=vif3,dl_src=f0:00:00:01:02:03,dl_dst=f0:00:00:01:02:01,nw_ecn=0,nw_frag=no -]) -AT_CHECK([cat ofproto-trace-2 | tail -1 \ - | grep -oE 'tnl_push|userspace|clone|br-phys_n1|vif[[0-9]]'], [0], [dnl -userspace -tnl_push -br-phys_n1 -]) - -# Now actually send it. -check as hv2 ovs-appctl netdev-dummy/receive vif3 $reply - -AT_CHECK([echo $reply > reply]) -# Check that it is delivered where needed and not delivered where not. -OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [reply]) -OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [empty]) -OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected]) -OVN_CHECK_PACKETS([hv2/vif4-tx.pcap], [empty]) -OVN_CHECK_PACKETS([hv3/vif5-tx.pcap], [expected]) - -# Zones 1 and 2 should have 2 FDB entries now each. One for a remote port and -# one per side of a switch-switch port connecting ls[12] with the spine. Zone -# 3 still only has two entries created for the original request from vif1. -ovn_as az1 -wait_row_count FDB 3 -check ovn-nbctl --wait=hv sync -ovn_as az2 -wait_row_count FDB 3 -check ovn-nbctl --wait=hv sync -ovn_as az3 -wait_row_count FDB 2 -check ovn-nbctl --wait=hv sync +ovn_as az1 check ovn-nbctl remove logical_router_port lrp-lr11-ts1 options ic-route-filter-learn + +# Test direct routes from lr12 were learned to lr11 +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001 | + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl +2001:db12::/64 fe80:10::2 +2001:db22::/64 fe80:10::2 +]) + +ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 options:ic-route-filter-adv=2001:db22::/64 + +# Test direct routes from lr12 were learned to lr11 +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001 | + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl +2001:db22::/64 fe80:10::2 +]) + +ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options ic-route-filter-adv +# Test direct routes from lr12 were learned to lr11 +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001 | + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl +2001:db12::/64 fe80:10::2 +2001:db22::/64 fe80:10::2 +]) + +ovn_as az1 check ovn-nbctl set logical_router_port lrp-lr11-ts1 options:ic-route-filter-learn=2001:db12::/64 +# Test direct routes from lr12 were learned to lr11 +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001 | + grep learned | awk '{print $1, $2}' | sort ], [0], [dnl +2001:db12::/64 fe80:10::2 +]) + +OVN_CLEANUP_IC([az1], [az2]) -# Packets should flow directly to the destination (via tunnels) in both -# directions now. -AT_CHECK([as hv1 ovs-appctl ofproto/trace --names \ - br-int in_port=vif1 $packet | tail -2 \ - | grep -oE 'Megaflow.*|tnl_push|userspace|clone|br-phys_n1|vif[[0-9]]'], [0], [dnl -Megaflow: recirc_id=0,eth,ip,in_port=vif1,dl_src=f0:00:00:01:02:01,dl_dst=f0:00:00:01:02:03,nw_ecn=0,nw_frag=no -tnl_push -br-phys_n1 -]) -AT_CHECK([as hv2 ovs-appctl ofproto/trace --names \ - br-int in_port=vif3 $reply | tail -2 \ - | grep -oE 'Megaflow.*|tnl_push|userspace|clone|br-phys_n1|vif[[0-9]]'], [0], [dnl -Megaflow: recirc_id=0,eth,ip,in_port=vif3,dl_src=f0:00:00:01:02:03,dl_dst=f0:00:00:01:02:01,nw_ecn=0,nw_frag=no -tnl_push -br-phys_n1 -]) - -# Send and check one more time. -check as hv1 ovs-appctl netdev-dummy/receive vif1 $packet -check as hv2 ovs-appctl netdev-dummy/receive vif3 $reply - -AT_CHECK([cp expected expected-vif5]) -AT_CHECK([echo $packet >> expected]) -AT_CHECK([echo $reply >> reply]) -OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [reply]) -OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [empty]) -OVN_CHECK_PACKETS([hv2/vif3-tx.pcap], [expected]) -OVN_CHECK_PACKETS([hv2/vif4-tx.pcap], [empty]) -OVN_CHECK_PACKETS([hv3/vif5-tx.pcap], [expected-vif5]) - -OVN_CLEANUP_IC([az1], [az2], [az3]) AT_CLEANUP ]) -- 2.34.1 -- _'Esta mensagem é direcionada apenas para os endereços constantes no cabeçalho inicial. Se você não está listado nos endereços constantes no cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão imediatamente anuladas e proibidas'._ * **'Apesar do Magazine Luiza tomar todas as precauções razoáveis para assegurar que nenhum vírus esteja presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.* _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
