This patch adds some lflows for 'na' action to support ND versus ARP. For ovn-northd, it will generate lflows per each IPv6 address on echo lport, with lport mac and IPv6 addresss, with 'na' action. e.g. match=(ip6 && nd && icmp6.type == 135 && nd.target == fde3:f657:aac1:0:f816:3eff:fe13:8198), action=(na{fa:16:3e:13:81:98; reg0 = 0x1; outport = inport; inport = ""; output;};) And new lflows will be set in tabel ls_in_arp_nd_rsp, which is renamed from previous ls_in_arp_rsp.
Setting reg0 = 0x1 to mention that such kind of NA packets are replied by ovn-controller, and for these packets, they dont need conntrack. So I also modfiy current table 32 and table 48, to make these packets output directly. (Will try to add test once I figure out what to test.) Signed-off-by: Zong Kai LI <zealo...@gmail.com> --- ovn/controller/physical.c | 17 +++++++++ ovn/northd/ovn-northd.c | 93 +++++++++++++++++++++++++++++++++++++++++++---- tutorial/OVN-Tutorial.md | 6 +-- 3 files changed, 106 insertions(+), 10 deletions(-) diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c index 576c695..df19680 100644 --- a/ovn/controller/physical.c +++ b/ovn/controller/physical.c @@ -707,6 +707,23 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve, put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts); ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 0, &match, &ofpacts); + /* Table 32, Priority 100. + * ======================= + * + * Directly output NA packets replied by ovn-controller for NS packets + * come from local VMs. + * - match: ip6 && icmp6 && icmp6.type == 136 && reg0 == 0x1 + * - action: resubmit(,48) + */ + match_init_catchall(&match); + match_set_dl_type(&match, htons(0x86dd)); + match_set_nw_proto(&match, (uint8_t)58); + match_set_icmp_type(&match, (uint8_t)136); + match_set_reg(&match, 0, (uint32_t)1); + ofpbuf_clear(&ofpacts); + put_resubmit(OFTABLE_LOG_EGRESS_PIPELINE, &ofpacts); + ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 100, &match, &ofpacts); + /* Table 34, Priority 0. * ======================= * diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index a8dd2bb..0263d5c 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -93,7 +93,7 @@ enum ovn_stage { PIPELINE_STAGE(SWITCH, IN, PORT_SEC_ND, 2, "ls_in_port_sec_nd") \ PIPELINE_STAGE(SWITCH, IN, PRE_ACL, 3, "ls_in_pre_acl") \ PIPELINE_STAGE(SWITCH, IN, ACL, 4, "ls_in_acl") \ - PIPELINE_STAGE(SWITCH, IN, ARP_RSP, 5, "ls_in_arp_rsp") \ + PIPELINE_STAGE(SWITCH, IN, ARP_ND_RSP, 5, "ls_in_arp_nd_rsp") \ PIPELINE_STAGE(SWITCH, IN, L2_LKUP, 6, "ls_in_l2_lkup") \ \ /* Logical switch egress stages. */ \ @@ -1475,6 +1475,64 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, struct hmap *ports) acl->match, "drop;"); } } + + /* Egress Pre-ACL Table (Priority 110). + * + * Directly output RA packets replied by ovn-controller, they dont + * need go through conntrack. + */ + bool ra_allowed = false; + /* Consider the following cases are RA allowed: + * - has: + * match: "... ip6 && icmp6", + * action: "allow"/"allow-related". + * and has no: + * match: "... ip6 && icmp6 && icmp6.type == 136", + * action: "drop"/"reject". + * - has: + * match: "... ip6 && icmp6 && icmp6.type == 136", + * action: "allow"/"allow-related". + * and has no: + * match: "... ip6 && icmp6", + * action: "drop"/"reject". + */ + for (size_t i = 0; i < od->nbs->n_acls; i++) { + struct nbrec_acl *acl = od->nbs->acls[i]; + if (!strcmp(acl->direction, "from-lport")) { + continue; + } + char *icmp6 = strstr(acl->match, "ip6 && icmp6"); + if (!icmp6) { + continue; + } + /* strlen("ip6 && icmp6") == 12 */ + if (*(icmp6 + 12) == '\0') { + if (!strcmp(acl->action, "drop") + || !strcmp(acl->action, "reject")) { + ra_allowed = false; + break; + } else { + ra_allowed = true; + } + } else { + char *ra = strstr(icmp6 + 12, "icmp6.type == 136"); + /* strlen("icmp6.type == 136") == 17 */ + if (ra && *(ra + 17) == '\0') { + if (!strcmp(acl->action, "drop") + || !strcmp(acl->action, "reject")) { + ra_allowed = false; + break; + } else { + ra_allowed = true; + } + } + } + } + if (ra_allowed) { + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, + "ip6 && icmp6 && icmp6.type == 136 && reg0 == 0x1", + "output;"); + } } static void @@ -1566,13 +1624,13 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, if (!strcmp(op->nbs->type, "localnet")) { char *match = xasprintf("inport == %s", op->json_key); - ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_RSP, 100, + ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 100, match, "next;"); free(match); } } - /* Ingress table 5: ARP responder, reply for known IPs. + /* Ingress table 5: ARP/ND responder, reply for known IPs. * (priority 50). */ HMAP_FOR_EACH (op, key_node, ports) { if (!op->nbs) { @@ -1580,7 +1638,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, } /* - * Add ARP reply flows if either the + * Add ARP/ND reply flows if either the * - port is up or * - port type is router */ @@ -1591,7 +1649,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, 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)) { + true)) { continue; } for (size_t j = 0; j < laddrs.n_ipv4_addrs; j++) { @@ -1612,13 +1670,34 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, 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_ARP_RSP, 50, + ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50, match, actions); free(match); free(actions); } + char ip6_str[INET6_ADDRSTRLEN + 1]; + for (size_t j = 0; j < laddrs.n_ipv6_addrs; j++) { + ipv6_string_mapped(ip6_str, &(laddrs.ipv6_addrs[i].addr)); + + struct ds match = DS_EMPTY_INITIALIZER; + ds_put_cstr(&match, "ip6 && nd && icmp6.type == 135 " + "&& nd.target == "); + ds_put_format(&match, "%s", ip6_str); + struct ds actions = DS_EMPTY_INITIALIZER; + ds_put_cstr(&actions, "na{"); + ds_put_format(&actions, ETH_ADDR_FMT, ETH_ADDR_ARGS(laddrs.ea)); + ds_put_cstr(&actions, "; reg0 = 0x1; outport = inport; " + "inport = \"\"; output;};"); + + ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 50, + ds_cstr(&match), ds_cstr(&actions)); + + ds_destroy(&actions); + ds_destroy(&match); + } free(laddrs.ipv4_addrs); + free(laddrs.ipv6_addrs); } } @@ -1629,7 +1708,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, continue; } - ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_RSP, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 0, "1", "next;"); } /* Ingress table 6: Destination lookup, broadcast and multicast handling diff --git a/tutorial/OVN-Tutorial.md b/tutorial/OVN-Tutorial.md index 7b31fe2..bb3cdae 100644 --- a/tutorial/OVN-Tutorial.md +++ b/tutorial/OVN-Tutorial.md @@ -104,7 +104,7 @@ show the logical flows. table=2(ls_in_port_sec_nd), priority= 0, match=(1), action=(next;) table=3( ls_in_pre_acl), priority= 0, match=(1), action=(next;) table=4( ls_in_acl), priority= 0, match=(1), action=(next;) - table=5( ls_in_arp_rsp), priority= 0, match=(1), action=(next;) + table=5(ls_in_arp_nd_rsp), priority= 0, match=(1), action=(next;) table=6( ls_in_l2_lkup), priority= 100, match=(eth.mcast), action=(outport = "_MC_flood"; output;) table=6( ls_in_l2_lkup), priority= 50, match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0-port1"; output;) table=6( ls_in_l2_lkup), priority= 50, match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0-port2"; output;) @@ -277,7 +277,7 @@ OVN creates separate logical flows for each logical switch. table=2(ls_in_port_sec_nd), priority= 0, match=(1), action=(next;) table=3( ls_in_pre_acl), priority= 0, match=(1), action=(next;) table=4( ls_in_acl), priority= 0, match=(1), action=(next;) - table=5( ls_in_arp_rsp), priority= 0, match=(1), action=(next;) + table=5(ls_in_arp_nd_rsp), priority= 0, match=(1), action=(next;) table=6( ls_in_l2_lkup), priority= 100, match=(eth.mcast), action=(outport = "_MC_flood"; output;) table=6( ls_in_l2_lkup), priority= 50, match=(eth.dst == 00:00:00:00:00:03), action=(outport = "sw1-port1"; output;) table=6( ls_in_l2_lkup), priority= 50, match=(eth.dst == 00:00:00:00:00:04), action=(outport = "sw1-port2"; output;) @@ -303,7 +303,7 @@ OVN creates separate logical flows for each logical switch. table=2(ls_in_port_sec_nd), priority= 0, match=(1), action=(next;) table=3( ls_in_pre_acl), priority= 0, match=(1), action=(next;) table=4( ls_in_acl), priority= 0, match=(1), action=(next;) - table=5( ls_in_arp_rsp), priority= 0, match=(1), action=(next;) + table=5(ls_in_arp_nd_rsp), priority= 0, match=(1), action=(next;) table=6( ls_in_l2_lkup), priority= 100, match=(eth.mcast), action=(outport = "_MC_flood"; output;) table=6( ls_in_l2_lkup), priority= 50, match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0-port1"; output;) table=6( ls_in_l2_lkup), priority= 50, match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0-port2"; output;) -- 1.9.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev