Message ID | 20200703183434.22921.95770.stgit@dceara.remote.csb |
---|---|
State | Accepted |
Headers | show |
Series | Reduce number of flows in IN_IP_INPUT table for DNAT. | expand |
On Sat, Jul 4, 2020 at 12:05 AM Dumitru Ceara <dceara@redhat.com> wrote: > Store NAT entries pointers in ovn_datapath and pre-parse the external IP > addresses. This simplifies the code and makes it easier to reuse the parsed > external IP and solicited-node address without reparsing. > > Acked-by: Han Zhou <hzhou@ovn.org> > Signed-off-by: Dumitru Ceara <dceara@redhat.com> > Hi Dumitru for the patches and Han for the Acks. I applied the first 4 patches of this series to master with the below small change in patch 3. I swapped the last 2 params of the functions build_lrouter_arp_flow/build_lrouter_nd_flow. I think you need to resubmit p5 of this series after resolving the conflicts. ******** diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 14e121593..cbe6a1771 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -7986,7 +7986,8 @@ static void build_lrouter_arp_flow(struct ovn_datapath *od, struct ovn_port *op, const char *ip_address, const char *eth_addr, struct ds *extra_match, uint16_t priority, - struct hmap *lflows, const struct ovsdb_idl_row *hint) + const struct ovsdb_idl_row *hint, + struct hmap *lflows) { struct ds match = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; @@ -8033,8 +8034,8 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op, const char *action, const char *ip_address, const char *sn_ip_address, const char *eth_addr, struct ds *extra_match, uint16_t priority, - struct hmap *lflows, - const struct ovsdb_idl_row *hint) + const struct ovsdb_idl_row *hint, + struct hmap *lflows) { struct ds match = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; @@ -8408,8 +8409,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, build_lrouter_arp_flow(op->od, op, op->lrp_networks.ipv4_addrs[i].addr_s, - REG_INPORT_ETH_ADDR, &match, 90, lflows, - &op->nbrp->header_); + REG_INPORT_ETH_ADDR, &match, 90, + &op->nbrp->header_, lflows); } /* A set to hold all load-balancer vips that need ARP responses. */ @@ -8427,7 +8428,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, build_lrouter_arp_flow(op->od, op, ip_address, REG_INPORT_ETH_ADDR, - &match, 90, lflows, NULL); + &match, 90, NULL, lflows); } SSET_FOR_EACH (ip_address, &all_ips_v6) { @@ -8439,7 +8440,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, build_lrouter_nd_flow(op->od, op, "nd_na", ip_address, NULL, REG_INPORT_ETH_ADDR, - &match, 90, lflows, NULL); + &match, 90, NULL, lflows); } sset_destroy(&all_ips_v4); @@ -8543,11 +8544,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, build_lrouter_nd_flow(op->od, op, "nd_na", nat->external_ip, sn_addr_s, mac_s, &match, 90, - lflows, &nat->header_); + &nat->header_, lflows); } else { build_lrouter_arp_flow(op->od, op, nat->external_ip, mac_s, &match, 90, - lflows, &nat->header_); + &nat->header_, lflows); } } @@ -8734,8 +8735,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, build_lrouter_nd_flow(op->od, op, "nd_na_router", op->lrp_networks.ipv6_addrs[i].addr_s, op->lrp_networks.ipv6_addrs[i].sn_addr_s, - REG_INPORT_ETH_ADDR, &match, 90, lflows, - &op->nbrp->header_); + REG_INPORT_ETH_ADDR, &match, 90, + &op->nbrp->header_, lflows); } /* UDP/TCP port unreachable */ ************** Thanks Numan --- > northd/ovn-northd.c | 119 > ++++++++++++++++++++++++++++++++++++++------------- > 1 file changed, 89 insertions(+), 30 deletions(-) > > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c > index 14e1215..2dc4e20 100644 > --- a/northd/ovn-northd.c > +++ b/northd/ovn-northd.c > @@ -607,6 +607,9 @@ struct ovn_datapath { > * the "redirect-chassis". */ > struct ovn_port *l3redirect_port; > > + /* NAT entries configured on the router. */ > + struct ovn_nat *nat_entries; > + > struct ovn_port **localnet_ports; > size_t n_localnet_ports; > > @@ -619,6 +622,69 @@ struct ovn_datapath { > struct hmap nb_pgs; > }; > > +/* Contains a NAT entry with the external addresses pre-parsed. */ > +struct ovn_nat { > + const struct nbrec_nat *nb; > + struct lport_addresses ext_addrs; > +}; > + > +/* Returns true if a 'nat_entry' is valid, i.e.: > + * - parsing was successful. > + * - the string yielded exactly one IPv4 address or exactly one IPv6 > address. > + */ > +static bool > +nat_entry_is_valid(const struct ovn_nat *nat_entry) > +{ > + const struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; > + > + return (ext_addrs->n_ipv4_addrs == 1 && ext_addrs->n_ipv6_addrs == 0) > || > + (ext_addrs->n_ipv4_addrs == 0 && ext_addrs->n_ipv6_addrs == 1); > +} > + > +static bool > +nat_entry_is_v6(const struct ovn_nat *nat_entry) > +{ > + return nat_entry->ext_addrs.n_ipv6_addrs > 0; > +} > + > +static void > +init_nat_entries(struct ovn_datapath *od) > +{ > + if (!od->nbr || od->nbr->n_nat == 0) { > + return; > + } > + > + od->nat_entries = xmalloc(od->nbr->n_nat * sizeof *od->nat_entries); > + > + for (size_t i = 0; i < od->nbr->n_nat; i++) { > + const struct nbrec_nat *nat = od->nbr->nat[i]; > + struct ovn_nat *nat_entry = &od->nat_entries[i]; > + > + nat_entry->nb = nat; > + if (!extract_ip_addresses(nat->external_ip, > + &nat_entry->ext_addrs) || > + !nat_entry_is_valid(nat_entry)) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > + > + VLOG_WARN_RL(&rl, > + "Bad ip address %s in nat configuration " > + "for router %s", nat->external_ip, > od->nbr->name); > + } > + } > +} > + > +static void > +destroy_nat_entries(struct ovn_datapath *od) > +{ > + if (!od->nbr) { > + return; > + } > + > + for (size_t i = 0; i < od->nbr->n_nat; i++) { > + destroy_lport_addresses(&od->nat_entries[i].ext_addrs); > + } > +} > + > /* A group of logical router datapaths which are connected - either > * directly or indirectly. > * Each logical router can belong to only one group. */ > @@ -676,6 +742,8 @@ ovn_datapath_destroy(struct hmap *datapaths, struct > ovn_datapath *od) > ovn_destroy_tnlids(&od->port_tnlids); > bitmap_free(od->ipam_info.allocated_ipv4s); > free(od->router_ports); > + destroy_nat_entries(od); > + free(od->nat_entries); > free(od->localnet_ports); > ovn_ls_port_group_destroy(&od->nb_pgs); > destroy_mcast_info_for_datapath(od); > @@ -1104,6 +1172,7 @@ join_datapaths(struct northd_context *ctx, struct > hmap *datapaths, > ovs_list_push_back(nb_only, &od->list); > } > init_mcast_info_for_datapath(od); > + init_nat_entries(od); > ovs_list_push_back(lr_list, &od->lr_list); > } > } > @@ -8465,30 +8534,24 @@ build_lrouter_flows(struct hmap *datapaths, struct > hmap *ports, > snat_ips[n_snat_ips++] = snat_ip; > } > > - for (int i = 0; i < op->od->nbr->n_nat; i++) { > - const struct nbrec_nat *nat; > - > - nat = op->od->nbr->nat[i]; > + for (size_t i = 0; i < op->od->nbr->n_nat; i++) { > + struct ovn_nat *nat_entry = &op->od->nat_entries[i]; > + const struct nbrec_nat *nat = nat_entry->nb; > > - ovs_be32 ip; > - struct in6_addr ipv6; > - bool is_v6 = false; > - if (!ip_parse(nat->external_ip, &ip) || !ip) { > - if (!ipv6_parse(nat->external_ip, &ipv6)) { > - static struct vlog_rate_limit rl = > - VLOG_RATE_LIMIT_INIT(5, 1); > - VLOG_WARN_RL(&rl, "bad ip address %s in nat > configuration " > - "for router %s", nat->external_ip, > op->key); > - continue; > - } > - is_v6 = true; > + /* Skip entries we failed to parse. */ > + if (!nat_entry_is_valid(nat_entry)) { > + continue; > } > > if (!strcmp(nat->type, "snat")) { > - if (is_v6) { > + if (nat_entry_is_v6(nat_entry)) { > + struct in6_addr *ipv6 = > + &nat_entry->ext_addrs.ipv6_addrs[0].addr; > + > snat_ips[n_snat_ips].family = AF_INET6; > - snat_ips[n_snat_ips++].ipv6 = ipv6; > + snat_ips[n_snat_ips++].ipv6 = *ipv6; > } else { > + ovs_be32 ip = nat_entry->ext_addrs.ipv4_addrs[0].addr; > snat_ips[n_snat_ips].family = AF_INET; > snat_ips[n_snat_ips++].ipv4 = ip; > } > @@ -8531,22 +8594,18 @@ build_lrouter_flows(struct hmap *datapaths, struct > hmap *ports, > } > } > } > - if (is_v6) { > - /* For ND solicitations, we need to listen for both the > - * unicast IPv6 address and its all-nodes multicast > address, > - * but always respond with the unicast IPv6 address. */ > - char sn_addr_s[INET6_ADDRSTRLEN + 1]; > - struct in6_addr sn_addr; > - in6_addr_solicited_node(&sn_addr, &ipv6); > - ipv6_string_mapped(sn_addr_s, &sn_addr); > > + struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; > + if (nat_entry_is_v6(nat_entry)) { > build_lrouter_nd_flow(op->od, op, "nd_na", > - nat->external_ip, sn_addr_s, > - mac_s, &match, 90, > - lflows, &nat->header_); > + ext_addrs->ipv6_addrs[0].addr_s, > + ext_addrs->ipv6_addrs[0].sn_addr_s, > + mac_s, &match, 90, > + lflows, &nat->header_); > } else { > build_lrouter_arp_flow(op->od, op, > - nat->external_ip, mac_s, &match, > 90, > + ext_addrs->ipv4_addrs[0].addr_s, > + mac_s, &match, 90, > lflows, &nat->header_); > } > } > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > >
On 7/6/20 12:56 PM, Numan Siddique wrote: > > > On Sat, Jul 4, 2020 at 12:05 AM Dumitru Ceara <dceara@redhat.com > <mailto:dceara@redhat.com>> wrote: > > Store NAT entries pointers in ovn_datapath and pre-parse the external IP > addresses. This simplifies the code and makes it easier to reuse the > parsed > external IP and solicited-node address without reparsing. > > Acked-by: Han Zhou <hzhou@ovn.org <mailto:hzhou@ovn.org>> > Signed-off-by: Dumitru Ceara <dceara@redhat.com > <mailto:dceara@redhat.com>> > > > Hi Dumitru for the patches and Han for the Acks. > > I applied the first 4 patches of this series to master with the below > small change in patch 3. > I swapped the last 2 params of the > functions build_lrouter_arp_flow/build_lrouter_nd_flow. > > I think you need to resubmit p5 of this series after resolving the > conflicts. > Thanks Han, Numan! I sent a v5 with patch 5 here: https://patchwork.ozlabs.org/project/openvswitch/patch/1594035141-21430-1-git-send-email-dceara@redhat.com/ Thanks, Dumitru
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 14e1215..2dc4e20 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -607,6 +607,9 @@ struct ovn_datapath { * the "redirect-chassis". */ struct ovn_port *l3redirect_port; + /* NAT entries configured on the router. */ + struct ovn_nat *nat_entries; + struct ovn_port **localnet_ports; size_t n_localnet_ports; @@ -619,6 +622,69 @@ struct ovn_datapath { struct hmap nb_pgs; }; +/* Contains a NAT entry with the external addresses pre-parsed. */ +struct ovn_nat { + const struct nbrec_nat *nb; + struct lport_addresses ext_addrs; +}; + +/* Returns true if a 'nat_entry' is valid, i.e.: + * - parsing was successful. + * - the string yielded exactly one IPv4 address or exactly one IPv6 address. + */ +static bool +nat_entry_is_valid(const struct ovn_nat *nat_entry) +{ + const struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; + + return (ext_addrs->n_ipv4_addrs == 1 && ext_addrs->n_ipv6_addrs == 0) || + (ext_addrs->n_ipv4_addrs == 0 && ext_addrs->n_ipv6_addrs == 1); +} + +static bool +nat_entry_is_v6(const struct ovn_nat *nat_entry) +{ + return nat_entry->ext_addrs.n_ipv6_addrs > 0; +} + +static void +init_nat_entries(struct ovn_datapath *od) +{ + if (!od->nbr || od->nbr->n_nat == 0) { + return; + } + + od->nat_entries = xmalloc(od->nbr->n_nat * sizeof *od->nat_entries); + + for (size_t i = 0; i < od->nbr->n_nat; i++) { + const struct nbrec_nat *nat = od->nbr->nat[i]; + struct ovn_nat *nat_entry = &od->nat_entries[i]; + + nat_entry->nb = nat; + if (!extract_ip_addresses(nat->external_ip, + &nat_entry->ext_addrs) || + !nat_entry_is_valid(nat_entry)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + + VLOG_WARN_RL(&rl, + "Bad ip address %s in nat configuration " + "for router %s", nat->external_ip, od->nbr->name); + } + } +} + +static void +destroy_nat_entries(struct ovn_datapath *od) +{ + if (!od->nbr) { + return; + } + + for (size_t i = 0; i < od->nbr->n_nat; i++) { + destroy_lport_addresses(&od->nat_entries[i].ext_addrs); + } +} + /* A group of logical router datapaths which are connected - either * directly or indirectly. * Each logical router can belong to only one group. */ @@ -676,6 +742,8 @@ ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od) ovn_destroy_tnlids(&od->port_tnlids); bitmap_free(od->ipam_info.allocated_ipv4s); free(od->router_ports); + destroy_nat_entries(od); + free(od->nat_entries); free(od->localnet_ports); ovn_ls_port_group_destroy(&od->nb_pgs); destroy_mcast_info_for_datapath(od); @@ -1104,6 +1172,7 @@ join_datapaths(struct northd_context *ctx, struct hmap *datapaths, ovs_list_push_back(nb_only, &od->list); } init_mcast_info_for_datapath(od); + init_nat_entries(od); ovs_list_push_back(lr_list, &od->lr_list); } } @@ -8465,30 +8534,24 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, snat_ips[n_snat_ips++] = snat_ip; } - for (int i = 0; i < op->od->nbr->n_nat; i++) { - const struct nbrec_nat *nat; - - nat = op->od->nbr->nat[i]; + for (size_t i = 0; i < op->od->nbr->n_nat; i++) { + struct ovn_nat *nat_entry = &op->od->nat_entries[i]; + const struct nbrec_nat *nat = nat_entry->nb; - ovs_be32 ip; - struct in6_addr ipv6; - bool is_v6 = false; - if (!ip_parse(nat->external_ip, &ip) || !ip) { - if (!ipv6_parse(nat->external_ip, &ipv6)) { - static struct vlog_rate_limit rl = - VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "bad ip address %s in nat configuration " - "for router %s", nat->external_ip, op->key); - continue; - } - is_v6 = true; + /* Skip entries we failed to parse. */ + if (!nat_entry_is_valid(nat_entry)) { + continue; } if (!strcmp(nat->type, "snat")) { - if (is_v6) { + if (nat_entry_is_v6(nat_entry)) { + struct in6_addr *ipv6 = + &nat_entry->ext_addrs.ipv6_addrs[0].addr; + snat_ips[n_snat_ips].family = AF_INET6; - snat_ips[n_snat_ips++].ipv6 = ipv6; + snat_ips[n_snat_ips++].ipv6 = *ipv6; } else { + ovs_be32 ip = nat_entry->ext_addrs.ipv4_addrs[0].addr; snat_ips[n_snat_ips].family = AF_INET; snat_ips[n_snat_ips++].ipv4 = ip; } @@ -8531,22 +8594,18 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, } } } - if (is_v6) { - /* For ND solicitations, we need to listen for both the - * unicast IPv6 address and its all-nodes multicast address, - * but always respond with the unicast IPv6 address. */ - char sn_addr_s[INET6_ADDRSTRLEN + 1]; - struct in6_addr sn_addr; - in6_addr_solicited_node(&sn_addr, &ipv6); - ipv6_string_mapped(sn_addr_s, &sn_addr); + struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; + if (nat_entry_is_v6(nat_entry)) { build_lrouter_nd_flow(op->od, op, "nd_na", - nat->external_ip, sn_addr_s, - mac_s, &match, 90, - lflows, &nat->header_); + ext_addrs->ipv6_addrs[0].addr_s, + ext_addrs->ipv6_addrs[0].sn_addr_s, + mac_s, &match, 90, + lflows, &nat->header_); } else { build_lrouter_arp_flow(op->od, op, - nat->external_ip, mac_s, &match, 90, + ext_addrs->ipv4_addrs[0].addr_s, + mac_s, &match, 90, lflows, &nat->header_); } }