This patch fails to apply on the latest master. Thanks Numan
On Wed, Jun 8, 2016 at 12:58 PM, Zong Kai LI <zealo...@gmail.com> wrote: > 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, dont do conntrack on them. > Also modfiy current table 32 and table 48, to make these packets > output directly. > > Signed-off-by: Zong Kai LI <zealo...@gmail.com> > --- > ovn/controller/physical.c | 41 ++++++++++++++++++ > ovn/northd/ovn-northd.c | 104 > +++++++++++++++++++++++++++++++++++++++++----- > tutorial/OVN-Tutorial.md | 6 +-- > 3 files changed, 137 insertions(+), 14 deletions(-) > > diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c > index 576c695..d6886da 100644 > --- a/ovn/controller/physical.c > +++ b/ovn/controller/physical.c > @@ -14,6 +14,8 @@ > */ > > #include <config.h> > +#include <linux/if_ether.h> > +#include <netinet/icmp6.h> > #include "byte-order.h" > #include "flow.h" > #include "lflow.h" > @@ -24,6 +26,7 @@ > #include "openvswitch/vlog.h" > #include "ovn-controller.h" > #include "ovn/lib/ovn-sb-idl.h" > +#include "ovn/lib/ovn-util.h" > #include "physical.h" > #include "shash.h" > #include "simap.h" > @@ -367,6 +370,21 @@ physical_run(struct controller_ctx *ctx, enum > mf_field_id mff_ovn_geneve, > put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); > } > > + int zone_id_dnat, zone_id_snat; > + char *dnat = alloc_nat_zone_key(binding, "dnat"); > + char *snat = alloc_nat_zone_key(binding, "snat"); > + zone_id_dnat = simap_get(ct_zones, dnat); > + if (zone_id_dnat) { > + put_load(zone_id_dnat, MFF_LOG_DNAT_ZONE, 0, 32, > &ofpacts); > + } > + free(dnat); > + > + zone_id_snat = simap_get(ct_zones, snat); > + if (zone_id_snat) { > + put_load(zone_id_snat, MFF_LOG_SNAT_ZONE, 0, 32, > &ofpacts); > + } > + free(snat); > + > /* Set MFF_LOG_DATAPATH and MFF_LOG_INPORT. */ > put_load(dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts); > put_load(port_key, MFF_LOG_INPORT, 0, 32, &ofpacts); > @@ -403,6 +421,12 @@ physical_run(struct controller_ctx *ctx, enum > mf_field_id mff_ovn_geneve, > if (zone_id) { > put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); > } > + if (zone_id_dnat) { > + put_load(zone_id_dnat, MFF_LOG_DNAT_ZONE, 0, 32, > &ofpacts); > + } > + if (zone_id_snat) { > + put_load(zone_id_snat, MFF_LOG_SNAT_ZONE, 0, 32, > &ofpacts); > + } > > /* Resubmit to table 34. */ > put_resubmit(OFTABLE_DROP_LOOPBACK, &ofpacts); > @@ -707,6 +731,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(ETH_P_IPV6)); > + match_set_nw_proto(&match, (uint8_t)IPPROTO_ICMPV6); > + match_set_icmp_type(&match, (uint8_t)ND_NEIGHBOR_ADVERT); > + 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..b2790bd 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;"); > } > } > + > + 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) { > + /* Egress Pre-ACL Table (Priority 110). > + * > + * Directly output RA packets replied by ovn-controller, they dont > + * need go through conntrack. > + */ > + 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,24 +1670,45 @@ 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[j].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); > } > } > > - /* Ingress table 5: ARP responder, by default goto next. > + /* Ingress table 5: ARP/ND responder, by default goto next. > * (priority 0)*/ > HMAP_FOR_EACH (od, key_node, datapaths) { > if (!od->nbs) { > 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 > @@ -1952,11 +2031,14 @@ build_lrouter_flows(struct hmap *datapaths, struct > hmap *ports, > free(match); > > /* ICMP echo reply. These flows reply to ICMP echo requests > - * received for the router's IP address. */ > + * received for the router's IP address. Since packets only > + * get here as part of the logical router datapath, the inport > + * (i.e. the incoming locally attached net) does not matter. > + * The ip.ttl also does not matter (RFC1812 section 4.2.2.9) */ > match = xasprintf( > - "inport == %s && (ip4.dst == "IP_FMT" || ip4.dst == "IP_FMT") > && " > + "(ip4.dst == "IP_FMT" || ip4.dst == "IP_FMT") && " > "icmp4.type == 8 && icmp4.code == 0", > - op->json_key, IP_ARGS(op->ip), IP_ARGS(op->bcast)); > + IP_ARGS(op->ip), IP_ARGS(op->bcast)); > char *actions = xasprintf( > "ip4.dst = ip4.src; " > "ip4.src = "IP_FMT"; " > 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 > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev