ofp-util: Treat a packet-out in_port of OFPP_CONTROLLER as OFPP_NONE.
[sliver-openvswitch.git] / lib / odp-util.c
index ee1c378..fef42ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -189,9 +189,7 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
 
         memcpy(&cookie, &userdata, sizeof cookie);
 
-        if (cookie.type == USER_ACTION_COOKIE_CONTROLLER) {
-            ds_put_format(ds, ",controller,length=%"PRIu32, cookie.data);
-        } else if (cookie.type == USER_ACTION_COOKIE_SFLOW) {
+        if (cookie.type == USER_ACTION_COOKIE_SFLOW) {
             ds_put_format(ds, ",sFlow,n_output=%"PRIu8","
                           "vid=%"PRIu16",pcp=%"PRIu8",ifindex=%"PRIu32,
                           cookie.n_output, vlan_tci_to_vid(cookie.vlan_tci),
@@ -280,10 +278,16 @@ format_odp_actions(struct ds *ds, const struct nlattr *actions,
             format_odp_action(ds, a);
         }
         if (left) {
+            int i;
+
             if (left == actions_len) {
                 ds_put_cstr(ds, "<empty>");
             }
-            ds_put_format(ds, ",***%u leftover bytes***", left);
+            ds_put_format(ds, ",***%u leftover bytes*** (", left);
+            for (i = 0; i < left; i++) {
+                ds_put_format(ds, "%02x", ((const uint8_t *) a)[i]);
+            }
+            ds_put_char(ds, ')');
         }
     } else {
         ds_put_cstr(ds, "drop");
@@ -328,7 +332,6 @@ parse_odp_action(const char *s, const struct shash *port_names,
 
     {
         unsigned long long int pid;
-        unsigned long long int length;
         unsigned long long int ifindex;
         char userdata_s[32];
         int n_output;
@@ -338,16 +341,6 @@ parse_odp_action(const char *s, const struct shash *port_names,
         if (sscanf(s, "userspace(pid=%lli)%n", &pid, &n) > 0 && n > 0) {
             odp_put_userspace_action(pid, NULL, actions);
             return n;
-        } else if (sscanf(s, "userspace(pid=%lli,controller,length=%lli)%n",
-                          &pid, &length, &n) > 0 && n > 0) {
-            struct user_action_cookie cookie;
-
-            cookie.type = USER_ACTION_COOKIE_CONTROLLER;
-            cookie.n_output = 0;
-            cookie.vlan_tci = htons(0);
-            cookie.data = length;
-            odp_put_userspace_action(pid, &cookie, actions);
-            return n;
         } else if (sscanf(s, "userspace(pid=%lli,sFlow,n_output=%i,vid=%i,"
                           "pcp=%i,ifindex=%lli)%n", &pid, &n_output,
                           &vid, &pcp, &ifindex, &n) > 0 && n > 0) {
@@ -740,10 +733,16 @@ odp_flow_key_format(const struct nlattr *key, size_t key_len, struct ds *ds)
             format_odp_key_attr(a, ds);
         }
         if (left) {
+            int i;
+            
             if (left == key_len) {
                 ds_put_cstr(ds, "<empty>");
             }
-            ds_put_format(ds, ",***%u leftover bytes***", left);
+            ds_put_format(ds, ",***%u leftover bytes*** (", left);
+            for (i = 0; i < left; i++) {
+                ds_put_format(ds, "%02x", ((const uint8_t *) a)[i]);
+            }
+            ds_put_char(ds, ')');
         }
     } else {
         ds_put_cstr(ds, "<empty>");
@@ -1149,11 +1148,11 @@ odp_flow_key_from_string(const char *s, const struct shash *port_names,
 }
 
 static uint8_t
-ovs_to_odp_frag(uint8_t ovs_frag)
+ovs_to_odp_frag(uint8_t nw_frag)
 {
-    return (ovs_frag & FLOW_NW_FRAG_LATER ? OVS_FRAG_TYPE_LATER
-            : ovs_frag & FLOW_NW_FRAG_ANY ? OVS_FRAG_TYPE_FIRST
-            : OVS_FRAG_TYPE_NONE);
+    return (nw_frag == 0 ? OVS_FRAG_TYPE_NONE
+          : nw_frag == FLOW_NW_FRAG_ANY ? OVS_FRAG_TYPE_FIRST
+          : OVS_FRAG_TYPE_LATER);
 }
 
 /* Appends a representation of 'flow' as OVS_KEY_ATTR_* attributes to 'buf'. */
@@ -1163,15 +1162,15 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow)
     struct ovs_key_ethernet *eth_key;
     size_t encap;
 
-    if (flow->priority) {
-        nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->priority);
+    if (flow->skb_priority) {
+        nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->skb_priority);
     }
 
     if (flow->tun_id != htonll(0)) {
         nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tun_id);
     }
 
-    if (flow->in_port != OFPP_NONE) {
+    if (flow->in_port != OFPP_NONE && flow->in_port != OFPP_CONTROLLER) {
         nl_msg_put_u32(buf, OVS_KEY_ATTR_IN_PORT,
                        ofp_port_to_odp_port(flow->in_port));
     }
@@ -1655,7 +1654,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
 
     /* Metadata. */
     if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_PRIORITY)) {
-        flow->priority = nl_attr_get_u32(attrs[OVS_KEY_ATTR_PRIORITY]);
+        flow->skb_priority = nl_attr_get_u32(attrs[OVS_KEY_ATTR_PRIORITY]);
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_PRIORITY;
     }
 
@@ -1700,6 +1699,24 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
                            expected_attrs, flow, key, key_len);
 }
 
+/* Returns 'fitness' as a string, for use in debug messages. */
+const char *
+odp_key_fitness_to_string(enum odp_key_fitness fitness)
+{
+    switch (fitness) {
+    case ODP_FIT_PERFECT:
+        return "OK";
+    case ODP_FIT_TOO_MUCH:
+        return "too_much";
+    case ODP_FIT_TOO_LITTLE:
+        return "too_little";
+    case ODP_FIT_ERROR:
+        return "error";
+    default:
+        return "<unknown>";
+    }
+}
+
 /* Appends an OVS_ACTION_ATTR_USERSPACE action to 'odp_actions' that specifies
  * Netlink PID 'pid'.  If 'cookie' is nonnull, adds a userdata attribute whose
  * contents contains 'cookie' and returns the offset within 'odp_actions' of
@@ -1791,16 +1808,11 @@ commit_vlan_action(const struct flow *flow, struct flow *base,
 }
 
 static void
-commit_set_nw_action(const struct flow *flow, struct flow *base,
+commit_set_ipv4_action(const struct flow *flow, struct flow *base,
                      struct ofpbuf *odp_actions)
 {
     struct ovs_key_ipv4 ipv4_key;
 
-    if (base->dl_type != htons(ETH_TYPE_IP) ||
-        !base->nw_src || !base->nw_dst) {
-        return;
-    }
-
     if (base->nw_src == flow->nw_src &&
         base->nw_dst == flow->nw_dst &&
         base->nw_tos == flow->nw_tos &&
@@ -1814,14 +1826,58 @@ commit_set_nw_action(const struct flow *flow, struct flow *base,
     ipv4_key.ipv4_tos = base->nw_tos = flow->nw_tos;
     ipv4_key.ipv4_ttl = base->nw_ttl = flow->nw_ttl;
     ipv4_key.ipv4_proto = base->nw_proto;
-    ipv4_key.ipv4_frag = (base->nw_frag == 0 ? OVS_FRAG_TYPE_NONE
-                          : base->nw_frag == FLOW_NW_FRAG_ANY
-                          ? OVS_FRAG_TYPE_FIRST : OVS_FRAG_TYPE_LATER);
+    ipv4_key.ipv4_frag = ovs_to_odp_frag(base->nw_frag);
 
     commit_set_action(odp_actions, OVS_KEY_ATTR_IPV4,
                       &ipv4_key, sizeof(ipv4_key));
 }
 
+static void
+commit_set_ipv6_action(const struct flow *flow, struct flow *base,
+                       struct ofpbuf *odp_actions)
+{
+    struct ovs_key_ipv6 ipv6_key;
+
+    if (ipv6_addr_equals(&base->ipv6_src, &flow->ipv6_src) &&
+        ipv6_addr_equals(&base->ipv6_dst, &flow->ipv6_dst) &&
+        base->ipv6_label == flow->ipv6_label &&
+        base->nw_tos == flow->nw_tos &&
+        base->nw_ttl == flow->nw_ttl &&
+        base->nw_frag == flow->nw_frag) {
+        return;
+    }
+
+    base->ipv6_src = flow->ipv6_src;
+    memcpy(&ipv6_key.ipv6_src, &base->ipv6_src, sizeof(ipv6_key.ipv6_src));
+    base->ipv6_dst = flow->ipv6_dst;
+    memcpy(&ipv6_key.ipv6_dst, &base->ipv6_dst, sizeof(ipv6_key.ipv6_dst));
+
+    ipv6_key.ipv6_label = base->ipv6_label = flow->ipv6_label;
+    ipv6_key.ipv6_tclass = base->nw_tos = flow->nw_tos;
+    ipv6_key.ipv6_hlimit = base->nw_ttl = flow->nw_ttl;
+    ipv6_key.ipv6_proto = base->nw_proto;
+    ipv6_key.ipv6_frag = ovs_to_odp_frag(base->nw_frag);
+
+    commit_set_action(odp_actions, OVS_KEY_ATTR_IPV6,
+                      &ipv6_key, sizeof(ipv6_key));
+}
+
+static void
+commit_set_nw_action(const struct flow *flow, struct flow *base,
+                     struct ofpbuf *odp_actions)
+{
+    /* Check if flow really have an IP header. */
+    if (!flow->nw_proto) {
+        return;
+    }
+
+    if (base->dl_type == htons(ETH_TYPE_IP)) {
+        commit_set_ipv4_action(flow, base, odp_actions);
+    } else if (base->dl_type == htons(ETH_TYPE_IPV6)) {
+        commit_set_ipv6_action(flow, base, odp_actions);
+    }
+}
+
 static void
 commit_set_port_action(const struct flow *flow, struct flow *base,
                        struct ofpbuf *odp_actions)
@@ -1859,13 +1915,13 @@ static void
 commit_set_priority_action(const struct flow *flow, struct flow *base,
                            struct ofpbuf *odp_actions)
 {
-    if (base->priority == flow->priority) {
+    if (base->skb_priority == flow->skb_priority) {
         return;
     }
-    base->priority = flow->priority;
+    base->skb_priority = flow->skb_priority;
 
     commit_set_action(odp_actions, OVS_KEY_ATTR_PRIORITY,
-                      &base->priority, sizeof(base->priority));
+                      &base->skb_priority, sizeof(base->skb_priority));
 }
 
 /* If any of the flow key data that ODP actions can modify are different in