X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=ovn%2Fnorthd%2Fovn-northd.c;h=b2b1a45cc60ee5ed1bd4f4e15ba731b69309cb67;hb=7dc88496081cccc0b22e3e341d88d2e4867323df;hp=270b116a71fca1650987542c5b7ffa349278db47;hpb=57d143eb6f44bd941a448b1f498dc0decdfca8bf;p=cascardo%2Fovs.git diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 270b116a7..b2b1a45cc 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -914,6 +914,112 @@ ovn_lflow_destroy(struct hmap *lflows, struct ovn_lflow *lflow) } } +struct ipv4_netaddr { + ovs_be32 addr; + unsigned int plen; +}; + +struct ipv6_netaddr { + struct in6_addr addr; + unsigned int plen; +}; + +struct lport_addresses { + struct eth_addr ea; + size_t n_ipv4_addrs; + struct ipv4_netaddr *ipv4_addrs; + size_t n_ipv6_addrs; + struct ipv6_netaddr *ipv6_addrs; +}; + +/* + * Extracts the mac, ipv4 and ipv6 addresses from the input param 'address' + * which should be of the format 'MAC [IP1 IP2 ..]" where IPn should be + * a valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and + * 'ipv6_addrs' fields of input param 'laddrs'. + * The caller has to free the 'ipv4_addrs' and 'ipv6_addrs' fields. + * If input param 'store_ipv6' is true only then extracted ipv6 addresses + * are stored in 'ipv6_addrs' fields. + * Return true if at least 'MAC' is found in 'address', false otherwise. + * Eg 1. + * If 'address' = '00:00:00:00:00:01 10.0.0.4 fe80::ea2a:eaff:fe28:3390/64 + * 30.0.0.3/23' and 'store_ipv6' = true + * then returns true with laddrs->n_ipv4_addrs = 2, naddrs->n_ipv6_addrs = 1. + * + * Eg. 2 + * If 'address' = '00:00:00:00:00:01 10.0.0.4 fe80::ea2a:eaff:fe28:3390/64 + * 30.0.0.3/23' and 'store_ipv6' = false + * then returns true with laddrs->n_ipv4_addrs = 2, naddrs->n_ipv6_addrs = 0. + * + * Eg 3. If 'address' = '00:00:00:00:00:01 10.0.0.4 addr 30.0.0.4', then + * returns true with laddrs->n_ipv4_addrs = 1 and laddrs->n_ipv6_addrs = 0. + */ +static bool +extract_lport_addresses(char *address, struct lport_addresses *laddrs, + bool store_ipv6) +{ + char *buf = address; + int buf_index = 0; + char *buf_end = buf + strlen(address); + if (!ovs_scan_len(buf, &buf_index, ETH_ADDR_SCAN_FMT, + ETH_ADDR_SCAN_ARGS(laddrs->ea))) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_INFO_RL(&rl, "invalid syntax '%s' in address. No MAC address" + " found", address); + return false; + } + + ovs_be32 ip4; + struct in6_addr ip6; + unsigned int plen; + char *error; + + laddrs->n_ipv4_addrs = 0; + laddrs->n_ipv6_addrs = 0; + laddrs->ipv4_addrs = NULL; + laddrs->ipv6_addrs = NULL; + + /* Loop through the buffer and extract the IPv4/IPv6 addresses + * and store in the 'laddrs'. Break the loop if invalid data is found. + */ + buf += buf_index; + while (buf < buf_end) { + buf_index = 0; + error = ip_parse_cidr_len(buf, &buf_index, &ip4, &plen); + if (!error) { + laddrs->n_ipv4_addrs++; + laddrs->ipv4_addrs = xrealloc( + laddrs->ipv4_addrs, + sizeof (struct ipv4_netaddr) * laddrs->n_ipv4_addrs); + laddrs->ipv4_addrs[laddrs->n_ipv4_addrs - 1].addr = ip4; + laddrs->ipv4_addrs[laddrs->n_ipv4_addrs - 1].plen = plen; + buf += buf_index; + continue; + } + free(error); + error = ipv6_parse_cidr_len(buf, &buf_index, &ip6, &plen); + if (!error && store_ipv6) { + laddrs->n_ipv6_addrs++; + laddrs->ipv6_addrs = xrealloc( + laddrs->ipv6_addrs, + sizeof(struct ipv6_netaddr) * laddrs->n_ipv6_addrs); + memcpy(&laddrs->ipv6_addrs[laddrs->n_ipv6_addrs - 1].addr, &ip6, + sizeof(struct in6_addr)); + laddrs->ipv6_addrs[laddrs->n_ipv6_addrs - 1].plen = plen; + } + + if (error) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", address); + free(error); + break; + } + buf += buf_index; + } + + return true; +} + /* 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 @@ -950,6 +1056,12 @@ lport_is_enabled(const struct nbrec_logical_port *lport) return !lport->enabled || *lport->enabled; } +static bool +lport_is_up(const struct nbrec_logical_port *lport) +{ + return !lport->up || *lport->up; +} + static bool has_stateful_acl(struct ovn_datapath *od) { @@ -964,9 +1076,11 @@ has_stateful_acl(struct ovn_datapath *od) } static void -build_acls(struct ovn_datapath *od, struct hmap *lflows) +build_acls(struct ovn_datapath *od, struct hmap *lflows, struct hmap *ports) { bool has_stateful = has_stateful_acl(od); + struct ovn_port *op; + struct ds match_in, match_out; /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are * allowed by default. */ @@ -983,6 +1097,30 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows) * send all IP packets through the conntrack action, which handles * defragmentation, in order to match L4 headers. */ if (has_stateful) { + HMAP_FOR_EACH (op, key_node, ports) { + if (op->od == od && !strcmp(op->nbs->type, "router")) { + /* Can't use ct() for router ports. Consider the following configuration: + lp1(10.0.0.2) on hostA--ls1--lr0--ls2--lp2(10.0.1.2) on hostB, + For a ping from lp1 to lp2, First, the response will go through ct() + with a zone for lp2 in the ls2 ingress pipeline on hostB. + That ct zone knows about this connection. Next, it goes through ct() + with the zone for the router port in the egress pipeline of ls2 on hostB. + This zone does not know about the connection, as the icmp request + went through the logical router on hostA, not hostB. This would only work + with distributed conntrack state across all chassis. */ + + ds_init(&match_in); + ds_init(&match_out); + ds_put_format(&match_in, "ip && inport == %s", op->json_key); + ds_put_format(&match_out, "ip && outport == %s", op->json_key); + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, ds_cstr(&match_in), "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, ds_cstr(&match_out), "next;"); + + ds_destroy(&match_in); + ds_destroy(&match_out); + } + } + /* Ingress and Egress Pre-ACL Table (Priority 100). * * Regardless of whether the ACL is "from-lport" or "to-lport", @@ -1100,7 +1238,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, continue; } - build_acls(od, lflows); + build_acls(od, lflows, ports); } /* Logical switch ingress table 0: Admission control framework (priority @@ -1152,15 +1290,25 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, continue; } - for (size_t i = 0; i < op->nbs->n_addresses; i++) { - struct eth_addr ea; - ovs_be32 ip; + /* + * Add ARP reply flows if either the + * - port is up or + * - port type is router + */ + if (!lport_is_up(op->nbs) && strcmp(op->nbs->type, "router")) { + continue; + } - if (ovs_scan(op->nbs->addresses[i], - ETH_ADDR_SCAN_FMT" "IP_SCAN_FMT, - ETH_ADDR_SCAN_ARGS(ea), IP_SCAN_ARGS(&ip))) { + for (size_t i = 0; i < op->nbs->n_addresses; i++) { + struct lport_addresses laddrs; + if (!extract_lport_addresses(op->nbs->addresses[i], &laddrs, + false)) { + continue; + } + for (size_t j = 0; j < laddrs.n_ipv4_addrs; j++) { char *match = xasprintf( - "arp.tpa == "IP_FMT" && arp.op == 1", IP_ARGS(ip)); + "arp.tpa == "IP_FMT" && arp.op == 1", + IP_ARGS(laddrs.ipv4_addrs[j].addr)); char *actions = xasprintf( "eth.dst = eth.src; " "eth.src = "ETH_ADDR_FMT"; " @@ -1172,14 +1320,16 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, "outport = inport; " "inport = \"\"; /* Allow sending out inport. */ " "output;", - ETH_ADDR_ARGS(ea), - ETH_ADDR_ARGS(ea), - IP_ARGS(ip)); + ETH_ADDR_ARGS(laddrs.ea), + ETH_ADDR_ARGS(laddrs.ea), + IP_ARGS(laddrs.ipv4_addrs[j].addr)); ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 150, match, actions); free(match); free(actions); } + + free(laddrs.ipv4_addrs); } } @@ -1500,12 +1650,14 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* XXX ARP for neighboring router */ } else if (op->od->n_router_ports) { for (size_t i = 0; i < op->nbs->n_addresses; i++) { - struct eth_addr ea; - ovs_be32 ip; + struct lport_addresses laddrs; + if (!extract_lport_addresses(op->nbs->addresses[i], &laddrs, + false)) { + continue; + } - if (ovs_scan(op->nbs->addresses[i], - ETH_ADDR_SCAN_FMT" "IP_SCAN_FMT, - ETH_ADDR_SCAN_ARGS(ea), IP_SCAN_ARGS(&ip))) { + 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++) { /* Get the Logical_Router_Port that the Logical_Port is * connected to, as 'peer'. */ @@ -1533,7 +1685,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "outport = %s; " "output;", ETH_ADDR_ARGS(peer->mac), - ETH_ADDR_ARGS(ea), + ETH_ADDR_ARGS(laddrs.ea), peer->json_key); ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP, 200, match, actions); @@ -1542,6 +1694,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, break; } } + + free(laddrs.ipv4_addrs); } } } @@ -1836,8 +1990,6 @@ add_column_noalert(struct ovsdb_idl *idl, int main(int argc, char *argv[]) { - extern struct vlog_module VLM_reconnect; - unsigned int ovnnb_seqno, ovnsb_seqno; int res = EXIT_SUCCESS; struct unixctl_server *unixctl; int retval; @@ -1846,8 +1998,6 @@ main(int argc, char *argv[]) fatal_ignore_sigpipe(); set_program_name(argv[0]); service_start(&argc, &argv); - vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN); - vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN); parse_options(argc, argv); daemonize_start(false); @@ -1907,9 +2057,6 @@ main(int argc, char *argv[]) add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_mac); ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_chassis); - ovnnb_seqno = ovsdb_idl_get_seqno(ovnnb_idl_loop.idl); - ovnsb_seqno = ovsdb_idl_get_seqno(ovnsb_idl_loop.idl); - /* Main loop. */ exiting = false; while (!exiting) { @@ -1920,14 +2067,8 @@ main(int argc, char *argv[]) .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop), }; - if (ovnnb_seqno != ovsdb_idl_get_seqno(ctx.ovnnb_idl)) { - ovnnb_seqno = ovsdb_idl_get_seqno(ctx.ovnnb_idl); - ovnnb_db_run(&ctx); - } - if (ovnsb_seqno != ovsdb_idl_get_seqno(ctx.ovnsb_idl)) { - ovnsb_seqno = ovsdb_idl_get_seqno(ctx.ovnsb_idl); - ovnsb_db_run(&ctx); - } + ovnnb_db_run(&ctx); + ovnsb_db_run(&ctx); unixctl_server_run(unixctl); unixctl_server_wait(unixctl);