]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: delete interface that disappeared 1927/head
authorPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 16 Mar 2018 17:37:08 +0000 (18:37 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Mon, 26 Mar 2018 09:31:44 +0000 (11:31 +0200)
When moving interfaces to an other place, like other netns, the
remaining interface is still present, with inactive status.
Now, that interface is deleted from the list, if the interface appears
on an other netns. If not, the interface is kept.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
zebra/if_netlink.c
zebra/interface.c
zebra/interface.h

index a37d74416be37fb1ee4430b03bafaecc27677694..47c99127c79a8003e3f40334e9ccb5afdb5b5224 100644 (file)
@@ -1008,6 +1008,54 @@ int netlink_interface_addr(struct sockaddr_nl *snl, struct nlmsghdr *h,
        return 0;
 }
 
+/* helper function called by if_netlink_change
+ * to delete interfaces in case the interface moved
+ * to an other netns
+ */
+static void if_netlink_check_ifp_instance_consistency(uint16_t cmd,
+                                                    struct interface *ifp,
+                                                    ns_id_t ns_id)
+{
+       struct interface *old_ifp;
+
+       /*
+        * look if interface name is also found on other netns
+        * - only if vrf backend is netns
+        * - do not concern lo interface
+        * - then remove previous one
+        * - for new link case, check found interface is not active
+        */
+       if (!vrf_is_backend_netns() ||
+           !strcmp(ifp->name, "lo"))
+               return;
+       old_ifp = if_lookup_by_name_not_ns(ns_id, ifp->name);
+       if (!old_ifp)
+               return;
+       if ((cmd == RTM_NEWLINK)
+           && (CHECK_FLAG(old_ifp->status, ZEBRA_INTERFACE_ACTIVE)))
+               return;
+       if (IS_ZEBRA_DEBUG_KERNEL)
+               zlog_debug("%s %s(%u) %s VRF %u",
+                          cmd == RTM_DELLINK ?
+                          "RTM_DELLINK replaced by" :
+                          "RTM_NEWLINK replaces",
+                          ifp->name,
+                          old_ifp->ifindex,
+                          cmd == RTM_DELLINK ?
+                          "in" : "from",
+                          old_ifp->vrf_id);
+       /* the found interface replaces the current one
+        * remove it
+        */
+       if (cmd == RTM_DELLINK)
+               if_delete(ifp);
+       else
+               if_delete(old_ifp);
+       /* the found interface is replaced by the current one
+        * suppress it
+        */
+}
+
 int netlink_link_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
                        ns_id_t ns_id, int startup)
 {
@@ -1169,6 +1217,8 @@ int netlink_link_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
                        if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
                                zebra_l2if_update_bridge_slave(ifp,
                                                               bridge_ifindex);
+                       if_netlink_check_ifp_instance_consistency(RTM_NEWLINK,
+                                                                 ifp, ns_id);
                } else if (ifp->vrf_id != vrf_id) {
                        /* VRF change for an interface. */
                        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1236,6 +1286,8 @@ int netlink_link_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
                        if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave)
                                zebra_l2if_update_bridge_slave(ifp,
                                                               bridge_ifindex);
+                       if_netlink_check_ifp_instance_consistency(RTM_NEWLINK,
+                                                                 ifp, ns_id);
                }
        } else {
                /* Delete interface notification from kernel */
@@ -1259,6 +1311,8 @@ int netlink_link_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
 
                if (!IS_ZEBRA_IF_VRF(ifp))
                        if_delete_update(ifp);
+               if_netlink_check_ifp_instance_consistency(RTM_DELLINK,
+                                                         ifp, ns_id);
        }
 
        return 0;
index 01283f9122d89dd6cb197a76ef39bacf2bedd970..8d3639b31546dfd326c856f85f46ffb7a7946ed1 100644 (file)
@@ -252,6 +252,30 @@ struct interface *if_lookup_by_name_per_ns(struct zebra_ns *ns,
        return NULL;
 }
 
+/* this function must be used only if the vrf backend
+ * is a netns backend
+ */
+struct interface *if_lookup_by_name_not_ns(ns_id_t ns_id,
+                                          const char *ifname)
+{
+       struct interface *ifp;
+       struct ns *ns;
+
+       RB_FOREACH (ns, ns_head, &ns_tree) {
+               if (ns->ns_id == ns_id)
+                       continue;
+               /* if_delete_update has removed interface
+                * from zns->if_table
+                * so to look for interface, use the vrf list
+                */
+               ifp = if_lookup_by_name(ifname, (vrf_id_t)ns->ns_id);
+               if (!ifp)
+                       continue;
+               return ifp;
+       }
+       return NULL;
+}
+
 const char *ifindex2ifname_per_ns(struct zebra_ns *zns, unsigned int ifindex)
 {
        struct interface *ifp;
index 9f109fc05f1837c1a53c4fbeb4829c9a269be4be..f01864c9fb16ca05a8a30d4f0e3e8acc234ba0f3 100644 (file)
@@ -318,6 +318,8 @@ extern struct interface *if_lookup_by_index_per_ns(struct zebra_ns *,
                                                   u_int32_t);
 extern struct interface *if_lookup_by_name_per_ns(struct zebra_ns *,
                                                  const char *);
+extern struct interface *if_lookup_by_name_not_ns(ns_id_t ns_id,
+                                                 const char *ifname);
 extern struct interface *if_link_per_ns(struct zebra_ns *, struct interface *);
 extern const char *ifindex2ifname_per_ns(struct zebra_ns *, unsigned int);