Extract port security and logical switch port addresses once and store them as part of the ovn_port structure. Use the string representations from the extracted addresses.
Signed-off-by: Justin Pettit <jpet...@ovn.org> --- ovn/northd/ovn-northd.c | 331 +++++++++++++++++++++++++----------------------- 1 file changed, 174 insertions(+), 157 deletions(-) diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 2fba68f..23e3532 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -480,11 +480,20 @@ struct ovn_port { char *key; /* nbs->name, nbr->name, sb->logical_port. */ char *json_key; /* 'key', quoted for use in JSON. */ - const struct nbrec_logical_switch_port *nbs; /* May be NULL. */ - const struct nbrec_logical_router_port *nbr; /* May be NULL. */ const struct sbrec_port_binding *sb; /* May be NULL. */ + /* Logical switch port data. */ + const struct nbrec_logical_switch_port *nbs; /* May be NULL. */ + + struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ + unsigned int n_lsp_addrs; + + struct lport_addresses *ps_addrs; /* Port security addresses. */ + unsigned int n_ps_addrs; + /* Logical router port data. */ + const struct nbrec_logical_router_port *nbr; /* May be NULL. */ + char *ip_s; /* "192.168.10.123" */ char *network_s; /* "192.168.10.0" */ char *bcast_s; /* "192.168.10.255" */ @@ -530,6 +539,17 @@ ovn_port_destroy(struct hmap *ports, struct ovn_port *port) * private list and once we've exited that function it is not safe to * use it. */ hmap_remove(ports, &port->key_node); + + for (int i = 0; i < port->n_lsp_addrs; i++) { + destroy_lport_addresses(&port->lsp_addrs[i]); + } + free(port->lsp_addrs); + + for (int i = 0; i < port->n_ps_addrs; i++) { + destroy_lport_addresses(&port->ps_addrs[i]); + } + free(port->ps_addrs); + free(port->bcast_s); free(port->network_s); free(port->ip_s); @@ -594,11 +614,49 @@ join_logical_ports(struct northd_context *ctx, op->nbs = nbs; ovs_list_remove(&op->list); ovs_list_push_back(both, &op->list); + + /* This port exists due to a SB binding, but should + * not have been initialized fully. */ + ovs_assert(!op->n_lsp_addrs && !op->n_ps_addrs); } else { op = ovn_port_create(ports, nbs->name, nbs, NULL, NULL); ovs_list_push_back(nb_only, &op->list); } + op->lsp_addrs + = xmalloc(sizeof *op->lsp_addrs * nbs->n_addresses); + for (size_t j = 0; j < nbs->n_addresses; j++) { + if (!strcmp(nbs->addresses[j], "unknown")) { + continue; + } + if (!extract_lsp_addresses(nbs->addresses[j], + &op->lsp_addrs[op->n_lsp_addrs])) { + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_INFO_RL(&rl, "invalid syntax '%s' in logical " + "switch port addresses. No MAC " + "address found", + op->nbs->addresses[j]); + continue; + } + op->n_lsp_addrs++; + } + + op->ps_addrs + = xmalloc(sizeof *op->ps_addrs * nbs->n_port_security); + for (size_t j = 0; j < nbs->n_port_security; j++) { + if (!extract_lsp_addresses(nbs->port_security[j], + &op->ps_addrs[op->n_ps_addrs])) { + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_INFO_RL(&rl, "invalid syntax '%s' in port " + "security. No MAC address found", + op->nbs->port_security[j]); + continue; + } + op->n_ps_addrs++; + } + op->od = od; } } else { @@ -985,33 +1043,27 @@ ovn_lflow_destroy(struct hmap *lflows, struct ovn_lflow *lflow) } /* Appends port security constraints on L2 address field 'eth_addr_field' - * (e.g. "eth.src" or "eth.dst") to 'match'. 'port_security', with - * 'n_port_security' elements, is the collection of port_security constraints - * from an OVN_NB Logical_Switch_Port row. */ + * (e.g. "eth.src" or "eth.dst") to 'match'. 'ps_addrs', with 'n_ps_addrs' + * elements, is the collection of port_security constraints from an + * OVN_NB Logical_Switch_Port row generated by extract_lsp_addresses(). */ static void build_port_security_l2(const char *eth_addr_field, - char **port_security, size_t n_port_security, + struct lport_addresses *ps_addrs, + unsigned int n_ps_addrs, struct ds *match) { - size_t base_len = match->length; - ds_put_format(match, " && %s == {", eth_addr_field); + if (!n_ps_addrs) { + return; + } - size_t n = 0; - for (size_t i = 0; i < n_port_security; i++) { - struct eth_addr ea; + ds_put_format(match, " && %s == {", eth_addr_field); - if (eth_addr_from_string(port_security[i], &ea)) { - ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea)); - ds_put_char(match, ' '); - n++; - } + for (size_t i = 0; i < n_ps_addrs; i++) { + ds_put_format(match, "%s", ps_addrs[i].ea_s); + ds_put_char(match, ' '); } ds_chomp(match, ' '); ds_put_cstr(match, "}"); - - if (!n) { - match->length = base_len; - } } static void @@ -1099,69 +1151,60 @@ build_port_security_ipv6_flow( static void build_port_security_nd(struct ovn_port *op, struct hmap *lflows) { - for (size_t i = 0; i < op->nbs->n_port_security; i++) { - struct lport_addresses ps; - if (!extract_lsp_addresses(op->nbs->port_security[i], &ps)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_INFO_RL(&rl, "invalid syntax '%s' in port security. No MAC" - " address found", op->nbs->port_security[i]); - continue; - } + struct ds match = DS_EMPTY_INITIALIZER; + + for (size_t i = 0; i < op->n_ps_addrs; i++) { + struct lport_addresses *ps = &op->ps_addrs[i]; - bool no_ip = !(ps.n_ipv4_addrs || ps.n_ipv6_addrs); - struct ds match = DS_EMPTY_INITIALIZER; + bool no_ip = !(ps->n_ipv4_addrs || ps->n_ipv6_addrs); - if (ps.n_ipv4_addrs || no_ip) { - ds_put_format( - &match, "inport == %s && eth.src == "ETH_ADDR_FMT" && arp.sha == " - ETH_ADDR_FMT, op->json_key, ETH_ADDR_ARGS(ps.ea), - ETH_ADDR_ARGS(ps.ea)); + ds_clear(&match); + if (ps->n_ipv4_addrs || no_ip) { + ds_put_format(&match, + "inport == %s && eth.src == %s && arp.sha == %s", + op->json_key, ps->ea_s, ps->ea_s); - if (ps.n_ipv4_addrs) { - ds_put_cstr(&match, " && ("); - for (size_t i = 0; i < ps.n_ipv4_addrs; i++) { - ds_put_cstr(&match, "arp.spa == "); - ovs_be32 mask = be32_prefix_mask(ps.ipv4_addrs[i].plen); + if (ps->n_ipv4_addrs) { + ds_put_cstr(&match, " && arp.spa == {"); + for (size_t i = 0; i < ps->n_ipv4_addrs; i++) { /* When the netmask is applied, if the host portion is * non-zero, the host can only use the specified * address in the arp.spa. If zero, the host is allowed * to use any address in the subnet. */ - if (ps.ipv4_addrs[i].addr & ~mask) { - ds_put_format(&match, IP_FMT, - IP_ARGS(ps.ipv4_addrs[i].addr)); + if (ps->ipv4_addrs[i].plen == 32 + || ps->ipv4_addrs[i].addr & ~ps->ipv4_addrs[i].mask) { + ds_put_format(&match, "%s", ps->ipv4_addrs[i].addr_s); } else { - ip_format_masked(ps.ipv4_addrs[i].addr & mask, mask, - &match); + ds_put_format(&match, "%s/%d", + ps->ipv4_addrs[i].network_s, + ps->ipv4_addrs[i].plen); } - ds_put_cstr(&match, " || "); + ds_put_cstr(&match, ", "); } ds_chomp(&match, ' '); - ds_chomp(&match, '|'); - ds_chomp(&match, '|'); - ds_put_cstr(&match, ")"); + ds_chomp(&match, ','); + ds_put_cstr(&match, "}"); } ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90, ds_cstr(&match), "next;"); - ds_destroy(&match); } - if (ps.n_ipv6_addrs || no_ip) { - ds_init(&match); - ds_put_format(&match, "inport == %s && eth.src == "ETH_ADDR_FMT, - op->json_key, ETH_ADDR_ARGS(ps.ea)); - build_port_security_ipv6_nd_flow(&match, ps.ea, ps.ipv6_addrs, - ps.n_ipv6_addrs); + if (ps->n_ipv6_addrs || no_ip) { + ds_clear(&match); + ds_put_format(&match, "inport == %s && eth.src == %s", + op->json_key, ps->ea_s); + build_port_security_ipv6_nd_flow(&match, ps->ea, ps->ipv6_addrs, + ps->n_ipv6_addrs); ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90, ds_cstr(&match), "next;"); - ds_destroy(&match); } - destroy_lport_addresses(&ps); } - char *match = xasprintf("inport == %s && (arp || nd)", op->json_key); + ds_clear(&match); + ds_put_format(&match, "inport == %s && (arp || nd)", op->json_key); ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 80, - match, "drop;"); - free(match); + ds_cstr(&match), "drop;"); + ds_destroy(&match); } /** @@ -1193,60 +1236,56 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, stage = S_SWITCH_OUT_PORT_SEC_IP; } - for (size_t i = 0; i < op->nbs->n_port_security; i++) { - struct lport_addresses ps; - if (!extract_lsp_addresses(op->nbs->port_security[i], &ps)) { - continue; - } + for (size_t i = 0; i < op->n_ps_addrs; i++) { + struct lport_addresses *ps = &op->ps_addrs[i]; - if (!(ps.n_ipv4_addrs || ps.n_ipv6_addrs)) { + if (!(ps->n_ipv4_addrs || ps->n_ipv6_addrs)) { continue; } - if (ps.n_ipv4_addrs) { + if (ps->n_ipv4_addrs) { struct ds match = DS_EMPTY_INITIALIZER; if (pipeline == P_IN) { /* Permit use of the unspecified address for DHCP discovery */ struct ds dhcp_match = DS_EMPTY_INITIALIZER; ds_put_format(&dhcp_match, "inport == %s" - " && eth.src == "ETH_ADDR_FMT + " && eth.src == %s" " && ip4.src == 0.0.0.0" " && ip4.dst == 255.255.255.255" - " && udp.src == 68 && udp.dst == 67", op->json_key, - ETH_ADDR_ARGS(ps.ea)); + " && udp.src == 68 && udp.dst == 67", + op->json_key, ps->ea_s); ovn_lflow_add(lflows, op->od, stage, 90, ds_cstr(&dhcp_match), "next;"); ds_destroy(&dhcp_match); - ds_put_format(&match, "inport == %s && eth.src == "ETH_ADDR_FMT + ds_put_format(&match, "inport == %s && eth.src == %s" " && ip4.src == {", op->json_key, - ETH_ADDR_ARGS(ps.ea)); + ps->ea_s); } else { - ds_put_format(&match, "outport == %s && eth.dst == "ETH_ADDR_FMT + ds_put_format(&match, "outport == %s && eth.dst == %s" " && ip4.dst == {255.255.255.255, 224.0.0.0/4, ", - op->json_key, ETH_ADDR_ARGS(ps.ea)); + op->json_key, ps->ea_s); } - for (int i = 0; i < ps.n_ipv4_addrs; i++) { - ovs_be32 mask = be32_prefix_mask(ps.ipv4_addrs[i].plen); + for (int i = 0; i < ps->n_ipv4_addrs; i++) { + ovs_be32 mask = ps->ipv4_addrs[i].mask; /* When the netmask is applied, if the host portion is * non-zero, the host can only use the specified * address. If zero, the host is allowed to use any * address in the subnet. - * */ - if (ps.ipv4_addrs[i].addr & ~mask) { - ds_put_format(&match, IP_FMT, - IP_ARGS(ps.ipv4_addrs[i].addr)); - if (pipeline == P_OUT && ps.ipv4_addrs[i].plen != 32) { - /* Host is also allowed to receive packets to the - * broadcast address in the specified subnet. - */ - ds_put_format(&match, ", "IP_FMT, - IP_ARGS(ps.ipv4_addrs[i].addr | ~mask)); + */ + if (ps->ipv4_addrs[i].plen == 32 + || ps->ipv4_addrs[i].addr & ~mask) { + ds_put_format(&match, "%s", ps->ipv4_addrs[i].addr_s); + if (pipeline == P_OUT && ps->ipv4_addrs[i].plen != 32) { + /* Host is also allowed to receive packets to the + * broadcast address in the specified subnet. */ + ds_put_format(&match, ", %s", + ps->ipv4_addrs[i].bcast_s); } } else { /* host portion is zero */ - ip_format_masked(ps.ipv4_addrs[i].addr & mask, mask, - &match); + ds_put_format(&match, "%s/%d", ps->ipv4_addrs[i].network_s, + ps->ipv4_addrs[i].plen); } ds_put_cstr(&match, ", "); } @@ -1259,39 +1298,36 @@ build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op, ds_destroy(&match); } - if (ps.n_ipv6_addrs) { + if (ps->n_ipv6_addrs) { struct ds match = DS_EMPTY_INITIALIZER; if (pipeline == P_IN) { /* Permit use of unspecified address for duplicate address * detection */ struct ds dad_match = DS_EMPTY_INITIALIZER; ds_put_format(&dad_match, "inport == %s" - " && eth.src == "ETH_ADDR_FMT + " && eth.src == %s" " && ip6.src == ::" " && ip6.dst == ff02::/16" " && icmp6.type == {131, 135, 143}", op->json_key, - ETH_ADDR_ARGS(ps.ea)); + ps->ea_s); ovn_lflow_add(lflows, op->od, stage, 90, ds_cstr(&dad_match), "next;"); ds_destroy(&dad_match); } - ds_put_format(&match, "%s == %s && %s == "ETH_ADDR_FMT"", + ds_put_format(&match, "%s == %s && %s == %s", port_direction, op->json_key, - pipeline == P_IN ? "eth.src" : "eth.dst", - ETH_ADDR_ARGS(ps.ea)); - build_port_security_ipv6_flow(pipeline, &match, ps.ea, - ps.ipv6_addrs, ps.n_ipv6_addrs); + pipeline == P_IN ? "eth.src" : "eth.dst", ps->ea_s); + build_port_security_ipv6_flow(pipeline, &match, ps->ea, + ps->ipv6_addrs, ps->n_ipv6_addrs); ovn_lflow_add(lflows, op->od, stage, 90, ds_cstr(&match), "next;"); ds_destroy(&match); } - destroy_lport_addresses(&ps); - - char *match = xasprintf( - "%s == %s && %s == "ETH_ADDR_FMT" && ip", port_direction, - op->json_key, pipeline == P_IN ? "eth.src" : "eth.dst", - ETH_ADDR_ARGS(ps.ea)); + char *match = xasprintf("%s == %s && %s == %s && ip", + port_direction, op->json_key, + pipeline == P_IN ? "eth.src" : "eth.dst", + ps->ea_s); ovn_lflow_add(lflows, op->od, stage, 80, match, "drop;"); free(match); } @@ -1775,9 +1811,8 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&match); ds_put_format(&match, "inport == %s", op->json_key); - build_port_security_l2( - "eth.src", op->nbs->port_security, op->nbs->n_port_security, - &match); + build_port_security_l2("eth.src", op->ps_addrs, op->n_ps_addrs, + &match); ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50, ds_cstr(&match), "next;"); @@ -1829,48 +1864,40 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, continue; } - for (size_t i = 0; i < op->nbs->n_addresses; i++) { - struct lport_addresses laddrs; - if (!extract_lsp_addresses(op->nbs->addresses[i], &laddrs)) { - continue; - } - for (size_t j = 0; j < laddrs.n_ipv4_addrs; j++) { + for (size_t i = 0; i < op->n_lsp_addrs; i++) { + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) { ds_clear(&match); - ds_put_format(&match, "arp.tpa == "IP_FMT" && arp.op == 1", - IP_ARGS(laddrs.ipv4_addrs[j].addr)); + ds_put_format(&match, "arp.tpa == %s && arp.op == 1", + op->lsp_addrs[i].ipv4_addrs[j].addr_s); ds_clear(&actions); ds_put_format(&actions, "eth.dst = eth.src; " - "eth.src = "ETH_ADDR_FMT"; " + "eth.src = %s; " "arp.op = 2; /* ARP reply */ " "arp.tha = arp.sha; " - "arp.sha = "ETH_ADDR_FMT"; " + "arp.sha = %s; " "arp.tpa = arp.spa; " - "arp.spa = "IP_FMT"; " + "arp.spa = %s; " "outport = inport; " "inport = \"\"; /* Allow sending out inport. */ " "output;", - ETH_ADDR_ARGS(laddrs.ea), - ETH_ADDR_ARGS(laddrs.ea), - IP_ARGS(laddrs.ipv4_addrs[j].addr)); + op->lsp_addrs[i].ea_s, op->lsp_addrs[i].ea_s, + op->lsp_addrs[i].ipv4_addrs[j].addr_s); ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50, ds_cstr(&match), ds_cstr(&actions)); } - if (laddrs.n_ipv6_addrs > 0) { - char ip6_str[INET6_ADDRSTRLEN + 1]; + if (op->lsp_addrs[i].n_ipv6_addrs > 0) { ds_clear(&match); ds_put_cstr(&match, "icmp6 && icmp6.type == 135 && "); - if (laddrs.n_ipv6_addrs == 1) { - ipv6_string_mapped(ip6_str, - &(laddrs.ipv6_addrs[0].addr)); - ds_put_format(&match, "nd.target == %s", ip6_str); + if (op->lsp_addrs[i].n_ipv6_addrs == 1) { + ds_put_format(&match, "nd.target == %s", + op->lsp_addrs[i].ipv6_addrs[0].addr_s); } else { ds_put_cstr(&match, "("); - for (size_t j = 0; j < laddrs.n_ipv6_addrs; j++) { - ipv6_string_mapped(ip6_str, - &(laddrs.ipv6_addrs[j].addr)); - ds_put_format(&match, "nd.target == %s || ", ip6_str); + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) { + ds_put_format(&match, "nd.target == %s || ", + op->lsp_addrs[i].ipv6_addrs[j].addr_s); } ds_chomp(&match, ' '); ds_chomp(&match, '|'); @@ -1880,20 +1907,18 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, } ds_clear(&actions); ds_put_format(&actions, - "na { eth.src = "ETH_ADDR_FMT"; " - "nd.tll = "ETH_ADDR_FMT"; " + "na { eth.src = %s; " + "nd.tll = %s; " "outport = inport; " "inport = \"\"; /* Allow sending out inport. */ " "output; };", - ETH_ADDR_ARGS(laddrs.ea), - ETH_ADDR_ARGS(laddrs.ea)); + op->lsp_addrs[i].ea_s, + op->lsp_addrs[i].ea_s); ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50, ds_cstr(&match), ds_cstr(&actions)); } - - destroy_lport_addresses(&laddrs); } } @@ -2002,8 +2027,8 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&match); ds_put_format(&match, "outport == %s", op->json_key); if (lsp_is_enabled(op->nbs)) { - build_port_security_l2("eth.dst", op->nbs->port_security, - op->nbs->n_port_security, &match); + build_port_security_l2("eth.dst", op->ps_addrs, op->n_ps_addrs, + &match); ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 50, ds_cstr(&match), "output;"); } else { @@ -2547,27 +2572,21 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * connects) and if the address in question is reachable from the * router port, add an ARP entry in that router's pipeline. */ - for (size_t i = 0; i < op->nbs->n_addresses; i++) { - struct lport_addresses laddrs; - if (!extract_lsp_addresses(op->nbs->addresses[i], &laddrs)) { - continue; - } - - for (size_t k = 0; k < laddrs.n_ipv4_addrs; k++) { - ovs_be32 ip = laddrs.ipv4_addrs[k].addr; - for (size_t j = 0; j < op->od->n_router_ports; j++) { + for (size_t i = 0; i < op->n_lsp_addrs; i++) { + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) { + ovs_be32 ip = op->lsp_addrs[i].ipv4_addrs[j].addr; + for (size_t k = 0; k < op->od->n_router_ports; k++) { /* Get the Logical_Router_Port that the * Logical_Switch_Port is connected to, as * 'peer'. */ const char *peer_name = smap_get( - &op->od->router_ports[j]->nbs->options, + &op->od->router_ports[k]->nbs->options, "router-port"); if (!peer_name) { continue; } - struct ovn_port *peer - = ovn_port_find(ports, peer_name); + struct ovn_port *peer = ovn_port_find(ports, peer_name); if (!peer || !peer->nbr) { continue; } @@ -2578,20 +2597,18 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, } ds_clear(&match); - ds_put_format(&match, "outport == %s && reg0 == "IP_FMT, - peer->json_key, IP_ARGS(ip)); + ds_put_format(&match, "outport == %s && reg0 == %s", + peer->json_key, + op->lsp_addrs[i].ipv4_addrs[j].addr_s); ds_clear(&actions); - ds_put_format(&actions, - "eth.dst = "ETH_ADDR_FMT"; next;", - ETH_ADDR_ARGS(laddrs.ea)); + ds_put_format(&actions, "eth.dst = %s; next;", + op->lsp_addrs[i].ea_s); ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100, ds_cstr(&match), ds_cstr(&actions)); break; } } - - destroy_lport_addresses(&laddrs); } } else if (!strcmp(op->nbs->type, "router")) { /* This is a logical switch port that connects to a router. */ -- 1.9.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev