int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr);
 #endif
 
+int ipv6_chk_rpl_srh_loop(struct net *net, const struct in6_addr *segs,
+                         unsigned char nsegs);
+
 bool ipv6_chk_custom_prefix(const struct in6_addr *addr,
                                   const unsigned int prefix_len,
                                   struct net_device *dev);
 
 }
 #endif
 
+/* RFC6554 has some algorithm to avoid loops in segment routing by
+ * checking if the segments contains any of a local interface address.
+ *
+ * Quote:
+ *
+ * To detect loops in the SRH, a router MUST determine if the SRH
+ * includes multiple addresses assigned to any interface on that router.
+ * If such addresses appear more than once and are separated by at least
+ * one address not assigned to that router.
+ */
+int ipv6_chk_rpl_srh_loop(struct net *net, const struct in6_addr *segs,
+                         unsigned char nsegs)
+{
+       const struct in6_addr *addr;
+       int i, ret = 0, found = 0;
+       struct inet6_ifaddr *ifp;
+       bool separated = false;
+       unsigned int hash;
+       bool hash_found;
+
+       rcu_read_lock();
+       for (i = 0; i < nsegs; i++) {
+               addr = &segs[i];
+               hash = inet6_addr_hash(net, addr);
+
+               hash_found = false;
+               hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) {
+                       if (!net_eq(dev_net(ifp->idev->dev), net))
+                               continue;
+
+                       if (ipv6_addr_equal(&ifp->addr, addr)) {
+                               hash_found = true;
+                               break;
+                       }
+               }
+
+               if (hash_found) {
+                       if (found > 1 && separated) {
+                               ret = 1;
+                               break;
+                       }
+
+                       separated = false;
+                       found++;
+               } else {
+                       separated = true;
+               }
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+
 /*
  *     Periodic address status verification
  */