bfd: Implement Bidirectional Forwarding Detection.
[sliver-openvswitch.git] / lib / odp-util.c
index f9e9321..5bf94fe 100644 (file)
@@ -183,6 +183,8 @@ slow_path_reason_to_string(uint32_t data)
         return "stp";
     case SLOW_IN_BAND:
         return "in_band";
+    case SLOW_BFD:
+        return "bfd";
     case SLOW_CONTROLLER:
         return "controller";
     case SLOW_MATCH:
@@ -262,43 +264,60 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
                   nl_attr_get_u32(a[OVS_USERSPACE_ATTR_PID]));
 
     userdata_attr = a[OVS_USERSPACE_ATTR_USERDATA];
-    if (userdata_attr && nl_attr_get_size(userdata_attr) == sizeof(uint64_t)) {
-        uint64_t userdata = nl_attr_get_u64(a[OVS_USERSPACE_ATTR_USERDATA]);
-        union user_action_cookie cookie;
-
-        memcpy(&cookie, &userdata, sizeof cookie);
-
-        switch (cookie.type) {
-        case USER_ACTION_COOKIE_SFLOW:
-            ds_put_format(ds, ",sFlow("
-                          "vid=%"PRIu16",pcp=%"PRIu8",output=%"PRIu32")",
-                          vlan_tci_to_vid(cookie.sflow.vlan_tci),
-                          vlan_tci_to_pcp(cookie.sflow.vlan_tci),
-                          cookie.sflow.output);
-            break;
 
-        case USER_ACTION_COOKIE_SLOW_PATH:
-            ds_put_cstr(ds, ",slow_path(");
-            format_flags(ds, slow_path_reason_to_string,
-                         cookie.slow_path.reason, ',');
-            ds_put_format(ds, ")");
-            break;
+    if (userdata_attr) {
+        const uint8_t *userdata = nl_attr_get(userdata_attr);
+        size_t userdata_len = nl_attr_get_size(userdata_attr);
+        bool userdata_unspec = true;
+        union user_action_cookie cookie;
 
-        case USER_ACTION_COOKIE_UNSPEC:
-        default:
-            ds_put_format(ds, ",userdata=0x%"PRIx64, userdata);
-            break;
+        if (userdata_len >= sizeof cookie.type
+            && userdata_len <= sizeof cookie) {
+
+            memset(&cookie, 0, sizeof cookie);
+            memcpy(&cookie, userdata, userdata_len);
+
+            userdata_unspec = false;
+
+            if (userdata_len == sizeof cookie.sflow
+                && cookie.type == USER_ACTION_COOKIE_SFLOW) {
+                ds_put_format(ds, ",sFlow("
+                              "vid=%"PRIu16",pcp=%"PRIu8",output=%"PRIu32")",
+                              vlan_tci_to_vid(cookie.sflow.vlan_tci),
+                              vlan_tci_to_pcp(cookie.sflow.vlan_tci),
+                              cookie.sflow.output);
+            } else if (userdata_len == sizeof cookie.slow_path
+                       && cookie.type == USER_ACTION_COOKIE_SLOW_PATH) {
+                ds_put_cstr(ds, ",slow_path(");
+                format_flags(ds, slow_path_reason_to_string,
+                             cookie.slow_path.reason, ',');
+                ds_put_format(ds, ")");
+            } else if (userdata_len == sizeof cookie.flow_sample
+                       && cookie.type == USER_ACTION_COOKIE_FLOW_SAMPLE) {
+                ds_put_format(ds, ",flow_sample(probability=%"PRIu16
+                              ",collector_set_id=%"PRIu32
+                              ",obs_domain_id=%"PRIu32
+                              ",obs_point_id=%"PRIu32")",
+                              cookie.flow_sample.probability,
+                              cookie.flow_sample.collector_set_id,
+                              cookie.flow_sample.obs_domain_id,
+                              cookie.flow_sample.obs_point_id);
+            } else if (userdata_len == sizeof cookie.ipfix
+                       && cookie.type == USER_ACTION_COOKIE_IPFIX) {
+                ds_put_format(ds, ",ipfix");
+            } else {
+                userdata_unspec = true;
+            }
         }
-    } else if (userdata_attr) {
-        const uint8_t *userdata = nl_attr_get(userdata_attr);
-        size_t len = nl_attr_get_size(userdata_attr);
-        size_t i;
 
-        ds_put_format(ds, ",userdata(");
-        for (i = 0; i < len; i++) {
-            ds_put_format(ds, "%02x", userdata[i]);
+        if (userdata_unspec) {
+            size_t i;
+            ds_put_format(ds, ",userdata(");
+            for (i = 0; i < userdata_len; i++) {
+                ds_put_format(ds, "%02x", userdata[i]);
+            }
+            ds_put_char(ds, ')');
         }
-        ds_put_char(ds, ')');
     }
 
     ds_put_char(ds, ')');
@@ -456,7 +475,10 @@ parse_odp_action(const char *s, const struct simap *port_names,
     {
         unsigned long long int pid;
         unsigned long long int output;
-        char userdata_s[32];
+        unsigned long long int probability;
+        unsigned long long int collector_set_id;
+        unsigned long long int obs_domain_id;
+        unsigned long long int obs_point_id;
         int vid, pcp;
         int n = -1;
 
@@ -477,7 +499,8 @@ parse_odp_action(const char *s, const struct simap *port_names,
             cookie.type = USER_ACTION_COOKIE_SFLOW;
             cookie.sflow.vlan_tci = htons(tci);
             cookie.sflow.output = output;
-            odp_put_userspace_action(pid, &cookie, sizeof cookie, actions);
+            odp_put_userspace_action(pid, &cookie, sizeof cookie.sflow,
+                                     actions);
             return n;
         } else if (sscanf(s, "userspace(pid=%lli,slow_path%n", &pid, &n) > 0
                    && n > 0) {
@@ -499,15 +522,30 @@ parse_odp_action(const char *s, const struct simap *port_names,
             }
             n++;
 
-            odp_put_userspace_action(pid, &cookie, sizeof cookie, actions);
+            odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path,
+                                     actions);
             return n;
-        } else if (sscanf(s, "userspace(pid=%lli,userdata="
-                          "%31[x0123456789abcdefABCDEF])%n", &pid, userdata_s,
-                          &n) > 0 && n > 0) {
-            uint64_t userdata;
+        } else if (sscanf(s, "userspace(pid=%lli,flow_sample(probability=%lli,"
+                          "collector_set_id=%lli,obs_domain_id=%lli,"
+                          "obs_point_id=%lli))%n",
+                          &pid, &probability, &collector_set_id,
+                          &obs_domain_id, &obs_point_id, &n) > 0 && n > 0) {
+            union user_action_cookie cookie;
 
-            userdata = strtoull(userdata_s, NULL, 0);
-            odp_put_userspace_action(pid, &userdata, sizeof(userdata),
+            cookie.type = USER_ACTION_COOKIE_FLOW_SAMPLE;
+            cookie.flow_sample.probability = probability;
+            cookie.flow_sample.collector_set_id = collector_set_id;
+            cookie.flow_sample.obs_domain_id = obs_domain_id;
+            cookie.flow_sample.obs_point_id = obs_point_id;
+            odp_put_userspace_action(pid, &cookie, sizeof cookie.flow_sample,
+                                     actions);
+            return n;
+        } else if (sscanf(s, "userspace(pid=%lli,ipfix)%n", &pid, &n) > 0
+                   && n > 0) {
+            union user_action_cookie cookie;
+
+            cookie.type = USER_ACTION_COOKIE_IPFIX;
+            odp_put_userspace_action(pid, &cookie, sizeof cookie.ipfix,
                                      actions);
             return n;
         } else if (sscanf(s, "userspace(pid=%lli,userdata(%n", &pid, &n) > 0
@@ -906,7 +944,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
     case OVS_KEY_ATTR_MPLS: {
         const struct ovs_key_mpls *mpls_key = nl_attr_get(a);
         ds_put_char(ds, '(');
-        format_mpls_lse(ds, mpls_key->mpls_top_lse);
+        format_mpls_lse(ds, mpls_key->mpls_lse);
         ds_put_char(ds, ')');
         break;
     }
@@ -1231,7 +1269,7 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
 
             mpls = nl_msg_put_unspec_uninit(key, OVS_KEY_ATTR_MPLS,
                                             sizeof *mpls);
-            mpls->mpls_top_lse = mpls_lse_from_components(label, tc, ttl, bos);
+            mpls->mpls_lse = mpls_lse_from_components(label, tc, ttl, bos);
             return n;
         }
     }
@@ -1594,7 +1632,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
 
         mpls_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_MPLS,
                                             sizeof *mpls_key);
-        mpls_key->mpls_top_lse = flow->mpls_lse;
+        mpls_key->mpls_lse = flow->mpls_lse;
     }
 
     if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
@@ -1714,6 +1752,7 @@ parse_flow_nlattrs(const struct nlattr *key, size_t key_len,
     uint64_t present_attrs;
     size_t left;
 
+    BUILD_ASSERT(OVS_KEY_ATTR_MAX < CHAR_BIT * sizeof present_attrs);
     present_attrs = 0;
     *out_of_range_attrp = 0;
     NL_ATTR_FOR_EACH (nla, left, key, key_len) {
@@ -1728,7 +1767,7 @@ parse_flow_nlattrs(const struct nlattr *key, size_t key_len,
             return false;
         }
 
-        if (type >= CHAR_BIT * sizeof present_attrs) {
+        if (type > OVS_KEY_ATTR_MAX) {
             *out_of_range_attrp = type;
         } else {
             if (present_attrs & (UINT64_C(1) << type)) {
@@ -2160,13 +2199,12 @@ void
 commit_odp_tunnel_action(const struct flow *flow, struct flow *base,
                          struct ofpbuf *odp_actions)
 {
-    if (!memcmp(&base->tunnel, &flow->tunnel, sizeof base->tunnel)) {
-        return;
-    }
-    memcpy(&base->tunnel, &flow->tunnel, sizeof base->tunnel);
-
     /* A valid IPV4_TUNNEL must have non-zero ip_dst. */
     if (flow->tunnel.ip_dst) {
+        if (!memcmp(&base->tunnel, &flow->tunnel, sizeof base->tunnel)) {
+            return;
+        }
+        memcpy(&base->tunnel, &flow->tunnel, sizeof base->tunnel);
         odp_put_tunnel_action(&base->tunnel, odp_actions);
     }
 }
@@ -2249,7 +2287,7 @@ commit_mpls_action(const struct flow *flow, struct flow *base,
     } else {
         struct ovs_key_mpls mpls_key;
 
-        mpls_key.mpls_top_lse = flow->mpls_lse;
+        mpls_key.mpls_lse = flow->mpls_lse;
         commit_set_action(odp_actions, OVS_KEY_ATTR_MPLS,
                           &mpls_key, sizeof(mpls_key));
     }