[ovs-dev] [ovn-ipv6 13/26] ovn-northd: Use strings from extract_lsp_addresses().
Justin Pettit
jpettit at ovn.org
Tue Jul 12 06:56:43 UTC 2016
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 <jpettit at 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
More information about the dev
mailing list