|
@@ -22,6 +22,7 @@
|
|
|
#include <linux/prefetch.h>
|
|
|
|
|
|
#include <net/dst.h>
|
|
|
+#include <net/dst_metadata.h>
|
|
|
|
|
|
/*
|
|
|
* Theory of operations:
|
|
@@ -158,19 +159,10 @@ const u32 dst_default_metrics[RTAX_MAX + 1] = {
|
|
|
[RTAX_MAX] = 0xdeadbeef,
|
|
|
};
|
|
|
|
|
|
-
|
|
|
-void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
|
|
|
- int initial_ref, int initial_obsolete, unsigned short flags)
|
|
|
+void dst_init(struct dst_entry *dst, struct dst_ops *ops,
|
|
|
+ struct net_device *dev, int initial_ref, int initial_obsolete,
|
|
|
+ unsigned short flags)
|
|
|
{
|
|
|
- struct dst_entry *dst;
|
|
|
-
|
|
|
- if (ops->gc && dst_entries_get_fast(ops) > ops->gc_thresh) {
|
|
|
- if (ops->gc(ops))
|
|
|
- return NULL;
|
|
|
- }
|
|
|
- dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC);
|
|
|
- if (!dst)
|
|
|
- return NULL;
|
|
|
dst->child = NULL;
|
|
|
dst->dev = dev;
|
|
|
if (dev)
|
|
@@ -200,6 +192,25 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
|
|
|
dst->next = NULL;
|
|
|
if (!(flags & DST_NOCOUNT))
|
|
|
dst_entries_add(ops, 1);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dst_init);
|
|
|
+
|
|
|
+void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
|
|
|
+ int initial_ref, int initial_obsolete, unsigned short flags)
|
|
|
+{
|
|
|
+ struct dst_entry *dst;
|
|
|
+
|
|
|
+ if (ops->gc && dst_entries_get_fast(ops) > ops->gc_thresh) {
|
|
|
+ if (ops->gc(ops))
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC);
|
|
|
+ if (!dst)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ dst_init(dst, ops, dev, initial_ref, initial_obsolete, flags);
|
|
|
+
|
|
|
return dst;
|
|
|
}
|
|
|
EXPORT_SYMBOL(dst_alloc);
|
|
@@ -248,7 +259,11 @@ again:
|
|
|
dst->ops->destroy(dst);
|
|
|
if (dst->dev)
|
|
|
dev_put(dst->dev);
|
|
|
- kmem_cache_free(dst->ops->kmem_cachep, dst);
|
|
|
+
|
|
|
+ if (dst->flags & DST_METADATA)
|
|
|
+ kfree(dst);
|
|
|
+ else
|
|
|
+ kmem_cache_free(dst->ops->kmem_cachep, dst);
|
|
|
|
|
|
dst = child;
|
|
|
if (dst) {
|
|
@@ -327,6 +342,47 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old)
|
|
|
}
|
|
|
EXPORT_SYMBOL(__dst_destroy_metrics_generic);
|
|
|
|
|
|
+static struct dst_ops md_dst_ops = {
|
|
|
+ .family = AF_UNSPEC,
|
|
|
+};
|
|
|
+
|
|
|
+static int dst_md_discard_sk(struct sock *sk, struct sk_buff *skb)
|
|
|
+{
|
|
|
+ WARN_ONCE(1, "Attempting to call output on metadata dst\n");
|
|
|
+ kfree_skb(skb);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int dst_md_discard(struct sk_buff *skb)
|
|
|
+{
|
|
|
+ WARN_ONCE(1, "Attempting to call input on metadata dst\n");
|
|
|
+ kfree_skb(skb);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags)
|
|
|
+{
|
|
|
+ struct metadata_dst *md_dst;
|
|
|
+ struct dst_entry *dst;
|
|
|
+
|
|
|
+ md_dst = kmalloc(sizeof(*md_dst) + optslen, flags);
|
|
|
+ if (!md_dst)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
+
|
|
|
+ dst = &md_dst->dst;
|
|
|
+ dst_init(dst, &md_dst_ops, NULL, 1, DST_OBSOLETE_NONE,
|
|
|
+ DST_METADATA | DST_NOCACHE | DST_NOCOUNT);
|
|
|
+
|
|
|
+ dst->input = dst_md_discard;
|
|
|
+ dst->output = dst_md_discard_sk;
|
|
|
+
|
|
|
+ memset(dst + 1, 0, sizeof(*md_dst) + optslen - sizeof(*dst));
|
|
|
+ md_dst->opts_len = optslen;
|
|
|
+
|
|
|
+ return md_dst;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(metadata_dst_alloc);
|
|
|
+
|
|
|
/* Dirty hack. We did it in 2.2 (in __dst_free),
|
|
|
* we have _very_ good reasons not to repeat
|
|
|
* this mistake in 2.3, but we have no choice
|
|
@@ -391,7 +447,7 @@ static struct notifier_block dst_dev_notifier = {
|
|
|
.priority = -10, /* must be called after other network notifiers */
|
|
|
};
|
|
|
|
|
|
-void __init dst_init(void)
|
|
|
+void __init dst_subsys_init(void)
|
|
|
{
|
|
|
register_netdevice_notifier(&dst_dev_notifier);
|
|
|
}
|