vswitch: Use "ipsec_gre" vport instead of "gre" with "other_config"
[sliver-openvswitch.git] / lib / odp-util.c
index 998dab2..29f536d 100644 (file)
 #include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
+#include "byte-order.h"
 #include "coverage.h"
 #include "dynamic-string.h"
 #include "flow.h"
+#include "netlink.h"
+#include "openvswitch/tunnel.h"
 #include "packets.h"
 #include "timeval.h"
 #include "util.h"
 
-union odp_action *
-odp_actions_add(struct odp_actions *actions, uint16_t type)
-{
-    union odp_action *a;
-    size_t idx;
-
-    idx = actions->n_actions++ & (MAX_ODP_ACTIONS - 1);
-    a = &actions->actions[idx];
-    memset(a, 0, sizeof *a);
-    a->type = type;
-    return a;
-}
-
 void
 format_odp_flow_key(struct ds *ds, const struct odp_flow_key *key)
 {
-    ds_put_format(ds, "tun_id0x%08x in_port%04x tci(", key->tun_id, key->in_port);
+    ds_put_format(ds, "tun_id%#"PRIx64" in_port%d tci(",
+                  ntohll(key->tun_id), key->in_port);
     if (key->dl_tci) {
         ds_put_format(ds, "vlan%"PRIu16",pcp%d",
                       vlan_tci_to_vid(key->dl_tci),
@@ -58,54 +49,116 @@ format_odp_flow_key(struct ds *ds, const struct odp_flow_key *key)
                   ntohs(key->tp_src), ntohs(key->tp_dst));
 }
 
+int
+odp_action_len(uint16_t type)
+{
+    if (type > ODPAT_MAX) {
+        return -1;
+    }
+
+    switch ((enum odp_action_type) type) {
+    case ODPAT_OUTPUT: return 4;
+    case ODPAT_CONTROLLER: return 8;
+    case ODPAT_SET_DL_TCI: return 2;
+    case ODPAT_STRIP_VLAN: return 0;
+    case ODPAT_SET_DL_SRC: return ETH_ADDR_LEN;
+    case ODPAT_SET_DL_DST: return ETH_ADDR_LEN;
+    case ODPAT_SET_NW_SRC: return 4;
+    case ODPAT_SET_NW_DST: return 4;
+    case ODPAT_SET_NW_TOS: return 1;
+    case ODPAT_SET_TP_SRC: return 2;
+    case ODPAT_SET_TP_DST: return 2;
+    case ODPAT_SET_TUNNEL: return 8;
+    case ODPAT_SET_PRIORITY: return 4;
+    case ODPAT_POP_PRIORITY: return 0;
+    case ODPAT_DROP_SPOOFED_ARP: return 0;
+
+    case ODPAT_UNSPEC:
+    case __ODPAT_MAX:
+        return -1;
+    }
+
+    return -1;
+}
+
+static void
+format_generic_odp_action(struct ds *ds, const struct nlattr *a)
+{
+    size_t len = nl_attr_get_size(a);
+
+    ds_put_format(ds, "action%"PRId16, nl_attr_type(a));
+    if (len) {
+        const uint8_t *unspec;
+        unsigned int i;
+
+        unspec = nl_attr_get(a);
+        for (i = 0; i < len; i++) {
+            ds_put_char(ds, i ? ' ': '(');
+            ds_put_format(ds, "%02x", unspec[i]);
+        }
+        ds_put_char(ds, ')');
+    }
+}
+
 void
-format_odp_action(struct ds *ds, const union odp_action *a)
+format_odp_action(struct ds *ds, const struct nlattr *a)
 {
-    switch (a->type) {
+    const uint8_t *eth;
+    ovs_be32 ip;
+
+    if (nl_attr_get_size(a) != odp_action_len(nl_attr_type(a))) {
+        ds_put_format(ds, "bad length %zu, expected %d for: ",
+                      nl_attr_get_size(a), odp_action_len(nl_attr_type(a)));
+        format_generic_odp_action(ds, a);
+        return;
+    }
+
+    switch (nl_attr_type(a)) {
     case ODPAT_OUTPUT:
-        ds_put_format(ds, "%"PRIu16, a->output.port);
+        ds_put_format(ds, "%"PRIu16, nl_attr_get_u32(a));
         break;
     case ODPAT_CONTROLLER:
-        ds_put_format(ds, "ctl(%"PRIu32")", a->controller.arg);
+        ds_put_format(ds, "ctl(%"PRIu64")", nl_attr_get_u64(a));
         break;
     case ODPAT_SET_TUNNEL:
-        ds_put_format(ds, "set_tunnel(0x%08"PRIx32")", ntohl(a->tunnel.tun_id));
+        ds_put_format(ds, "set_tunnel(%#"PRIx64")",
+                      ntohll(nl_attr_get_be64(a)));
         break;
     case ODPAT_SET_DL_TCI:
         ds_put_format(ds, "set_tci(vid=%"PRIu16",pcp=%d)",
-                      vlan_tci_to_vid(a->dl_tci.tci),
-                      vlan_tci_to_pcp(a->dl_tci.tci));
+                      vlan_tci_to_vid(nl_attr_get_be16(a)),
+                      vlan_tci_to_pcp(nl_attr_get_be16(a)));
         break;
     case ODPAT_STRIP_VLAN:
         ds_put_format(ds, "strip_vlan");
         break;
     case ODPAT_SET_DL_SRC:
-        ds_put_format(ds, "set_dl_src("ETH_ADDR_FMT")",
-               ETH_ADDR_ARGS(a->dl_addr.dl_addr));
+        eth = nl_attr_get_unspec(a, ETH_ADDR_LEN);
+        ds_put_format(ds, "set_dl_src("ETH_ADDR_FMT")", ETH_ADDR_ARGS(eth));
         break;
     case ODPAT_SET_DL_DST:
-        ds_put_format(ds, "set_dl_dst("ETH_ADDR_FMT")",
-               ETH_ADDR_ARGS(a->dl_addr.dl_addr));
+        eth = nl_attr_get_unspec(a, ETH_ADDR_LEN);
+        ds_put_format(ds, "set_dl_dst("ETH_ADDR_FMT")", ETH_ADDR_ARGS(eth));
         break;
     case ODPAT_SET_NW_SRC:
-        ds_put_format(ds, "set_nw_src("IP_FMT")",
-                      IP_ARGS(&a->nw_addr.nw_addr));
+        ip = nl_attr_get_be32(a);
+        ds_put_format(ds, "set_nw_src("IP_FMT")", IP_ARGS(&ip));
         break;
     case ODPAT_SET_NW_DST:
-        ds_put_format(ds, "set_nw_dst("IP_FMT")",
-                      IP_ARGS(&a->nw_addr.nw_addr));
+        ip = nl_attr_get_be32(a);
+        ds_put_format(ds, "set_nw_dst("IP_FMT")", IP_ARGS(&ip));
         break;
     case ODPAT_SET_NW_TOS:
-        ds_put_format(ds, "set_nw_tos(%"PRIu8")", a->nw_tos.nw_tos);
+        ds_put_format(ds, "set_nw_tos(%"PRIu8")", nl_attr_get_u8(a));
         break;
     case ODPAT_SET_TP_SRC:
-        ds_put_format(ds, "set_tp_src(%"PRIu16")", ntohs(a->tp_port.tp_port));
+        ds_put_format(ds, "set_tp_src(%"PRIu16")", ntohs(nl_attr_get_be16(a)));
         break;
     case ODPAT_SET_TP_DST:
-        ds_put_format(ds, "set_tp_dst(%"PRIu16")", ntohs(a->tp_port.tp_port));
+        ds_put_format(ds, "set_tp_dst(%"PRIu16")", ntohs(nl_attr_get_be16(a)));
         break;
     case ODPAT_SET_PRIORITY:
-        ds_put_format(ds, "set_priority(0x%"PRIx32")", a->priority.priority);
+        ds_put_format(ds, "set_priority(%#"PRIx32")", nl_attr_get_u32(a));
         break;
     case ODPAT_POP_PRIORITY:
         ds_put_cstr(ds, "pop_priority");
@@ -114,23 +167,29 @@ format_odp_action(struct ds *ds, const union odp_action *a)
         ds_put_cstr(ds, "drop_spoofed_arp");
         break;
     default:
-        ds_put_format(ds, "***bad action 0x%"PRIx16"***", a->type);
+        format_generic_odp_action(ds, a);
         break;
     }
 }
 
 void
-format_odp_actions(struct ds *ds, const union odp_action *actions,
-                   size_t n_actions)
+format_odp_actions(struct ds *ds, const struct nlattr *actions,
+                   size_t actions_len)
 {
-    size_t i;
-    for (i = 0; i < n_actions; i++) {
-        if (i) {
-            ds_put_char(ds, ',');
+    if (actions_len) {
+        const struct nlattr *a;
+        unsigned int left;
+
+        NL_ATTR_FOR_EACH (a, left, actions, actions_len) {
+            if (a != actions) {
+                ds_put_char(ds, ',');
+            }
+            format_odp_action(ds, a);
         }
-        format_odp_action(ds, &actions[i]);
-    }
-    if (!n_actions) {
+        if (left) {
+            ds_put_format(ds, " ***%u leftover bytes***", left);
+        }
+    } else {
         ds_put_cstr(ds, "drop");
     }
 }
@@ -156,7 +215,36 @@ format_odp_flow(struct ds *ds, const struct odp_flow *f)
     ds_put_cstr(ds, ", ");
     format_odp_flow_stats(ds, &f->stats);
     ds_put_cstr(ds, ", actions:");
-    format_odp_actions(ds, f->actions, f->n_actions);
+    format_odp_actions(ds, f->actions, f->actions_len);
+}
+
+void
+format_odp_port_type(struct ds *ds, const struct odp_port *p)
+{
+    if (!strcmp(p->type, "gre") 
+            || !strcmp(p->type, "ipsec_gre")
+            || !strcmp(p->type, "capwap")) {
+        const struct tnl_port_config *config;
+
+        config = (struct tnl_port_config *)p->config;
+
+        ds_put_format(ds, " (%s: remote_ip="IP_FMT, 
+                p->type, IP_ARGS(&config->daddr));
+
+        if (config->saddr) {
+            ds_put_format(ds, ", local_ip="IP_FMT, IP_ARGS(&config->saddr));
+        }
+
+        if (config->in_key) {
+            ds_put_format(ds, ", in_key=%#"PRIx64, ntohll(config->in_key));
+        }
+
+        ds_put_cstr(ds, ")");
+    } else if (!strcmp(p->type, "patch")) {
+        ds_put_format(ds, " (%s: peer=%s)", p->type, (char *)p->config);
+    } else if (strcmp(p->type, "system")) {
+        ds_put_format(ds, " (%s)", p->type);
+    }
 }
 \f
 void
@@ -166,14 +254,7 @@ odp_flow_key_from_flow(struct odp_flow_key *key, const struct flow *flow)
     key->nw_src = flow->nw_src;
     key->nw_dst = flow->nw_dst;
     key->in_port = flow->in_port;
-    if (flow->dl_vlan == htons(OFP_VLAN_NONE)) {
-        key->dl_tci = htons(0);
-    } else {
-        uint16_t vid = flow->dl_vlan & htons(VLAN_VID_MASK);
-        uint16_t pcp = htons((flow->dl_vlan_pcp << VLAN_PCP_SHIFT)
-                             & VLAN_PCP_MASK);
-        key->dl_tci = vid | pcp | htons(ODP_TCI_PRESENT);
-    }
+    key->dl_tci = flow->vlan_tci;
     key->dl_type = flow->dl_type;
     key->tp_src = flow->tp_src;
     key->tp_dst = flow->tp_dst;
@@ -186,17 +267,12 @@ odp_flow_key_from_flow(struct odp_flow_key *key, const struct flow *flow)
 void
 odp_flow_key_to_flow(const struct odp_flow_key *key, struct flow *flow)
 {
+    memset(flow->regs, 0, sizeof flow->regs);
     flow->tun_id = key->tun_id;
     flow->nw_src = key->nw_src;
     flow->nw_dst = key->nw_dst;
     flow->in_port = key->in_port;
-    if (key->dl_tci) {
-        flow->dl_vlan = htons(vlan_tci_to_vid(key->dl_tci));
-        flow->dl_vlan_pcp = vlan_tci_to_pcp(key->dl_tci);
-    } else {
-        flow->dl_vlan = htons(OFP_VLAN_NONE);
-        flow->dl_vlan_pcp = 0;
-    }
+    flow->vlan_tci = key->dl_tci;
     flow->dl_type = key->dl_type;
     flow->tp_src = key->tp_src;
     flow->tp_dst = key->tp_dst;