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

Reply via email to