+static const char *
+slow_path_reason_to_string(uint32_t data)
+{
+ enum slow_path_reason bit = (enum slow_path_reason) data;
+
+ switch (bit) {
+ case SLOW_CFM:
+ return "cfm";
+ case SLOW_LACP:
+ return "lacp";
+ case SLOW_STP:
+ return "stp";
+ case SLOW_IN_BAND:
+ return "in_band";
+ case SLOW_CONTROLLER:
+ return "controller";
+ case SLOW_MATCH:
+ return "match";
+ default:
+ return NULL;
+ }
+}
+
+static void
+format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t),
+ uint32_t flags)
+{
+ uint32_t bad = 0;
+
+ ds_put_format(ds, "(");
+ if (!flags) {
+ goto out;
+ }
+ while (flags) {
+ uint32_t bit = rightmost_1bit(flags);
+ const char *s;
+
+ s = bit_to_string(bit);
+ if (s) {
+ ds_put_format(ds, "%s,", s);
+ } else {
+ bad |= bit;
+ }
+
+ flags &= ~bit;
+ }
+
+ if (bad) {
+ ds_put_format(ds, "0x%"PRIx32",", bad);
+ }
+ ds_chomp(ds, ',');
+out:
+ ds_put_format(ds, ")");
+}
+
+static int
+parse_flags(const char *s, const char *(*bit_to_string)(uint32_t),
+ uint32_t *res)
+{
+ uint32_t result = 0;
+ int n = 0;
+
+ if (s[n] != '(') {
+ return -EINVAL;
+ }
+ n++;
+
+ while (s[n] != ')') {
+ unsigned long long int flags;
+ uint32_t bit;
+ int n0;
+
+ if (sscanf(&s[n], "%lli%n", &flags, &n0) > 0 && n0 > 0) {
+ n += n0 + (s[n + n0] == ',');
+ result |= flags;
+ continue;
+ }
+
+ for (bit = 1; bit; bit <<= 1) {
+ const char *name = bit_to_string(bit);
+ size_t len;
+
+ if (!name) {
+ continue;
+ }
+
+ len = strlen(name);
+ if (!strncmp(s + n, name, len) &&
+ (s[n + len] == ',' || s[n + len] == ')')) {
+ result |= bit;
+ n += len + (s[n + len] == ',');
+ break;
+ }
+ }
+
+ if (!bit) {
+ return -EINVAL;
+ }
+ }
+ n++;
+
+ *res = result;
+ return n;
+}
+