Commit | Line | Data |
---|---|---|
1ce84604 YG |
1 | /* |
2 | * net/ife/ife.c - Inter-FE protocol based on ForCES WG InterFE LFB | |
3 | * Copyright (c) 2015 Jamal Hadi Salim <jhs@mojatatu.com> | |
4 | * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> | |
5 | * | |
6 | * Refer to: draft-ietf-forces-interfelfb-03 and netdev01 paper: | |
7 | * "Distributing Linux Traffic Control Classifier-Action Subsystem" | |
8 | * Authors: Jamal Hadi Salim and Damascene M. Joachimpillai | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation. | |
13 | */ | |
14 | ||
15 | #include <linux/types.h> | |
16 | #include <linux/kernel.h> | |
17 | #include <linux/string.h> | |
18 | #include <linux/errno.h> | |
19 | #include <linux/skbuff.h> | |
20 | #include <linux/rtnetlink.h> | |
21 | #include <linux/module.h> | |
22 | #include <linux/init.h> | |
23 | #include <net/net_namespace.h> | |
24 | #include <net/netlink.h> | |
25 | #include <net/pkt_sched.h> | |
26 | #include <linux/etherdevice.h> | |
27 | #include <net/ife.h> | |
28 | ||
29 | struct ifeheadr { | |
30 | __be16 metalen; | |
31 | u8 tlv_data[]; | |
32 | }; | |
33 | ||
34 | void *ife_encode(struct sk_buff *skb, u16 metalen) | |
35 | { | |
36 | /* OUTERHDR:TOTMETALEN:{TLVHDR:Metadatum:TLVHDR..}:ORIGDATA | |
37 | * where ORIGDATA = original ethernet header ... | |
38 | */ | |
39 | int hdrm = metalen + IFE_METAHDRLEN; | |
40 | int total_push = hdrm + skb->dev->hard_header_len; | |
41 | struct ifeheadr *ifehdr; | |
42 | struct ethhdr *iethh; /* inner ether header */ | |
43 | int skboff = 0; | |
44 | int err; | |
45 | ||
46 | err = skb_cow_head(skb, total_push); | |
47 | if (unlikely(err)) | |
48 | return NULL; | |
49 | ||
50 | iethh = (struct ethhdr *) skb->data; | |
51 | ||
52 | __skb_push(skb, total_push); | |
53 | memcpy(skb->data, iethh, skb->dev->hard_header_len); | |
54 | skb_reset_mac_header(skb); | |
55 | skboff += skb->dev->hard_header_len; | |
56 | ||
57 | /* total metadata length */ | |
58 | ifehdr = (struct ifeheadr *) (skb->data + skboff); | |
59 | metalen += IFE_METAHDRLEN; | |
60 | ifehdr->metalen = htons(metalen); | |
61 | ||
62 | return ifehdr->tlv_data; | |
63 | } | |
64 | EXPORT_SYMBOL_GPL(ife_encode); | |
65 | ||
66 | void *ife_decode(struct sk_buff *skb, u16 *metalen) | |
67 | { | |
68 | struct ifeheadr *ifehdr; | |
69 | int total_pull; | |
70 | u16 ifehdrln; | |
71 | ||
72 | ifehdr = (struct ifeheadr *) (skb->data + skb->dev->hard_header_len); | |
73 | ifehdrln = ntohs(ifehdr->metalen); | |
74 | total_pull = skb->dev->hard_header_len + ifehdrln; | |
75 | ||
76 | if (unlikely(ifehdrln < 2)) | |
77 | return NULL; | |
78 | ||
79 | if (unlikely(!pskb_may_pull(skb, total_pull))) | |
80 | return NULL; | |
81 | ||
82 | skb_set_mac_header(skb, total_pull); | |
83 | __skb_pull(skb, total_pull); | |
84 | *metalen = ifehdrln - IFE_METAHDRLEN; | |
85 | ||
86 | return &ifehdr->tlv_data; | |
87 | } | |
88 | EXPORT_SYMBOL_GPL(ife_decode); | |
89 | ||
90 | struct meta_tlvhdr { | |
91 | __be16 type; | |
92 | __be16 len; | |
93 | }; | |
94 | ||
95 | /* Caller takes care of presenting data in network order | |
96 | */ | |
97 | void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen) | |
98 | { | |
99 | struct meta_tlvhdr *tlv = (struct meta_tlvhdr *) skbdata; | |
100 | ||
101 | *dlen = ntohs(tlv->len) - NLA_HDRLEN; | |
102 | *attrtype = ntohs(tlv->type); | |
103 | ||
104 | if (totlen) | |
105 | *totlen = nla_total_size(*dlen); | |
106 | ||
107 | return skbdata + sizeof(struct meta_tlvhdr); | |
108 | } | |
109 | EXPORT_SYMBOL_GPL(ife_tlv_meta_decode); | |
110 | ||
111 | void *ife_tlv_meta_next(void *skbdata) | |
112 | { | |
113 | struct meta_tlvhdr *tlv = (struct meta_tlvhdr *) skbdata; | |
114 | u16 tlvlen = ntohs(tlv->len); | |
115 | ||
116 | tlvlen = NLA_ALIGN(tlvlen); | |
117 | ||
118 | return skbdata + tlvlen; | |
119 | } | |
120 | EXPORT_SYMBOL_GPL(ife_tlv_meta_next); | |
121 | ||
122 | /* Caller takes care of presenting data in network order | |
123 | */ | |
124 | int ife_tlv_meta_encode(void *skbdata, u16 attrtype, u16 dlen, const void *dval) | |
125 | { | |
126 | __be32 *tlv = (__be32 *) (skbdata); | |
127 | u16 totlen = nla_total_size(dlen); /*alignment + hdr */ | |
128 | char *dptr = (char *) tlv + NLA_HDRLEN; | |
129 | u32 htlv = attrtype << 16 | (dlen + NLA_HDRLEN); | |
130 | ||
131 | *tlv = htonl(htlv); | |
132 | memset(dptr, 0, totlen - NLA_HDRLEN); | |
133 | memcpy(dptr, dval, dlen); | |
134 | ||
135 | return totlen; | |
136 | } | |
137 | EXPORT_SYMBOL_GPL(ife_tlv_meta_encode); | |
138 | ||
139 | MODULE_AUTHOR("Jamal Hadi Salim <jhs@mojatatu.com>"); | |
f1fd20c3 | 140 | MODULE_AUTHOR("Yotam Gigi <yotam.gi@gmail.com>"); |
1ce84604 YG |
141 | MODULE_DESCRIPTION("Inter-FE LFB action"); |
142 | MODULE_LICENSE("GPL"); |