iprule: fix missing ip rules after a reload (FS#2296)
[oweals/netifd.git] / iprule.c
index 3e5788849f46acba521513ce1a453f4d133b7c60..c3a629f6103624e6cb8578959ecd3ed4c814bf7a 100644 (file)
--- a/iprule.c
+++ b/iprule.c
@@ -290,7 +290,7 @@ iprule_add(struct blob_attr *attr, bool v6)
                rule->flags |= IPRULE_GOTO;
        }
 
-       vlist_add(&iprules, &rule->node, &rule->flags);
+       vlist_add(&iprules, &rule->node, rule);
        return;
 
 error:
@@ -320,7 +320,32 @@ iprule_update_complete(void)
 static int
 rule_cmp(const void *k1, const void *k2, void *ptr)
 {
-       return memcmp(k1, k2, sizeof(struct iprule)-offsetof(struct iprule, flags));
+       const struct iprule *r1 = k1, *r2 = k2;
+       int ret;
+
+       /* First compare the interface names */
+       if (r1->flags & IPRULE_IN || r2->flags & IPRULE_IN) {
+               char *str1 = r1->flags & IPRULE_IN ? r1->in_iface : "";
+               char *str2 = r2->flags & IPRULE_IN ? r2->in_iface : "";
+
+               ret = strcmp(str1, str2);
+               if (ret)
+                       return ret;
+       }
+
+       if (r1->flags & IPRULE_OUT || r2->flags & IPRULE_OUT) {
+               char *str1 = r1->flags & IPRULE_OUT ? r1->out_iface : "";
+               char *str2 = r2->flags & IPRULE_OUT ? r2->out_iface : "";
+
+               ret = strcmp(str1, str2);
+               if (ret)
+                       return ret;
+       }
+
+       /* Next compare everything after the flags field */
+       return memcmp(k1 + offsetof(struct iprule, flags),
+                     k2 + offsetof(struct iprule, flags),
+                     sizeof(struct iprule) - offsetof(struct iprule, flags));
 }
 
 static void deregister_interfaces(struct iprule *rule)