]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ofp-ed-props.c
dpif-netdev: Fix typo in copyright header.
[mirror_ovs.git] / lib / ofp-ed-props.c
1 /*
2 * Copyright (c) 2017 Intel, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18 #include <sys/types.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include "openvswitch/ofp-ed-props.h"
22 #include "openvswitch/ofpbuf.h"
23 #include "openvswitch/ofp-parse.h"
24 #include "util.h"
25 #include "lib/packets.h"
26
27
28 enum ofperr
29 decode_ed_prop(const struct ofp_ed_prop_header **ofp_prop,
30 struct ofpbuf *out OVS_UNUSED,
31 size_t *remaining)
32 {
33 uint16_t prop_class = ntohs((*ofp_prop)->prop_class);
34 uint8_t prop_type = (*ofp_prop)->type;
35 size_t len = (*ofp_prop)->len;
36 size_t pad_len = ROUND_UP(len, 8);
37
38 if (len < sizeof **ofp_prop || pad_len > *remaining) {
39 return OFPERR_OFPBAC_BAD_LEN;
40 }
41
42 switch (prop_class) {
43 case OFPPPC_NSH: {
44 switch (prop_type) {
45 case OFPPPT_PROP_NSH_MDTYPE: {
46 struct ofp_ed_prop_nsh_md_type *opnmt =
47 ALIGNED_CAST(struct ofp_ed_prop_nsh_md_type *, *ofp_prop);
48 if (len > sizeof(*opnmt) || len > *remaining) {
49 return OFPERR_NXBAC_BAD_ED_PROP;
50 }
51 struct ofpact_ed_prop_nsh_md_type *pnmt =
52 ofpbuf_put_uninit(out, sizeof(*pnmt));
53 pnmt->header.prop_class = prop_class;
54 pnmt->header.type = prop_type;
55 pnmt->header.len = len;
56 pnmt->md_type = opnmt->md_type;
57 break;
58 }
59 case OFPPPT_PROP_NSH_TLV: {
60 struct ofp_ed_prop_nsh_tlv *opnt =
61 ALIGNED_CAST(struct ofp_ed_prop_nsh_tlv *, *ofp_prop);
62 size_t tlv_pad_len = ROUND_UP(opnt->tlv_len, 8);
63 if (len != sizeof(*opnt) + tlv_pad_len || len > *remaining) {
64 return OFPERR_NXBAC_BAD_ED_PROP;
65 }
66 struct ofpact_ed_prop_nsh_tlv *pnt =
67 ofpbuf_put_uninit(out, sizeof(*pnt));
68 pnt->header.prop_class = prop_class;
69 pnt->header.type = prop_type;
70 pnt->header.len = len;
71 pnt->tlv_class = opnt->tlv_class;
72 pnt->tlv_type = opnt->tlv_type;
73 pnt->tlv_len = opnt->tlv_len;
74 ofpbuf_put(out, opnt->data, tlv_pad_len);
75 break;
76 }
77 default:
78 return OFPERR_NXBAC_UNKNOWN_ED_PROP;
79 }
80 break;
81 }
82 default:
83 return OFPERR_NXBAC_UNKNOWN_ED_PROP;
84 }
85
86 *remaining -= pad_len;
87 *ofp_prop = ALIGNED_CAST(const struct ofp_ed_prop_header *,
88 ((char *)(*ofp_prop) + pad_len));
89 return 0;
90 }
91
92 enum ofperr
93 encode_ed_prop(const struct ofpact_ed_prop **prop,
94 struct ofpbuf *out OVS_UNUSED)
95 {
96 size_t prop_len;
97
98 switch ((*prop)->prop_class) {
99 case OFPPPC_NSH: {
100 switch ((*prop)->type) {
101 case OFPPPT_PROP_NSH_MDTYPE: {
102 struct ofpact_ed_prop_nsh_md_type *pnmt =
103 ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *, *prop);
104 struct ofp_ed_prop_nsh_md_type *opnmt =
105 ofpbuf_put_uninit(out, sizeof(*opnmt));
106 opnmt->header.prop_class = htons((*prop)->prop_class);
107 opnmt->header.type = (*prop)->type;
108 opnmt->header.len =
109 offsetof(struct ofp_ed_prop_nsh_md_type, pad);
110 opnmt->md_type = pnmt->md_type;
111 prop_len = sizeof(*pnmt);
112 break;
113 }
114 case OFPPPT_PROP_NSH_TLV: {
115 struct ofpact_ed_prop_nsh_tlv *pnt =
116 ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *, *prop);
117 struct ofp_ed_prop_nsh_tlv *opnt;
118 size_t tlv_pad_len = ROUND_UP(pnt->tlv_len, 8);
119 size_t len = sizeof(*opnt) + tlv_pad_len;
120 opnt = ofpbuf_put_uninit(out, len);
121 opnt->header.prop_class = htons((*prop)->prop_class);
122 opnt->header.type = (*prop)->type;
123 opnt->header.len = len;
124 opnt->tlv_class = pnt->tlv_class;
125 opnt->tlv_type = pnt->tlv_type;
126 opnt->tlv_len = pnt->tlv_len;
127 memcpy(opnt->data, pnt->data, tlv_pad_len);
128 prop_len = sizeof(*pnt) + tlv_pad_len;
129 break;
130 }
131 default:
132 return OFPERR_OFPBAC_BAD_ARGUMENT;
133 }
134 break;
135 }
136 default:
137 return OFPERR_OFPBAC_BAD_ARGUMENT;
138 }
139
140 *prop = ALIGNED_CAST(const struct ofpact_ed_prop *,
141 ((char *)(*prop) + prop_len));
142 return 0;
143 }
144
145 bool
146 parse_ed_prop_class(const char *str OVS_UNUSED,
147 uint16_t *prop_class)
148 {
149 if (!strcmp(str,"basic")) {
150 *prop_class = OFPPPC_BASIC;
151 } else if (!strcmp(str,"ethernet")) {
152 *prop_class = OFPPPC_BASIC;
153 } else if (!strcmp(str,"mpls")) {
154 *prop_class = OFPPPC_MPLS;
155 } else if (!strcmp(str,"gre")) {
156 *prop_class = OFPPPC_GRE;
157 } else if (!strcmp(str,"gtp")) {
158 *prop_class = OFPPPC_GTP;
159 } else if (!strcmp(str,"nsh")) {
160 *prop_class = OFPPPC_NSH;
161 } else {
162 return false;
163 }
164 return true;
165 }
166
167 bool
168 parse_ed_prop_type(uint16_t prop_class,
169 const char *str OVS_UNUSED,
170 uint8_t *type OVS_UNUSED)
171 {
172 switch (prop_class) {
173 case OFPPPC_NSH:
174 if (!strcmp(str, "md_type")) {
175 *type = OFPPPT_PROP_NSH_MDTYPE;
176 return true;
177 } else if (!strcmp(str, "tlv")) {
178 *type = OFPPPT_PROP_NSH_TLV;
179 return true;
180 } else {
181 return false;
182 }
183 default:
184 return false;
185 }
186 }
187
188 /* Parse the value of an encap/decap property based on property class
189 * and type and append the parsed property in internal format to the
190 * ofpbuf out.
191 * Returns a malloced string in the event of a parse error. The caller
192 * must free the string.
193 */
194
195 char *
196 parse_ed_prop_value(uint16_t prop_class, uint8_t prop_type OVS_UNUSED,
197 const char *value, struct ofpbuf *out OVS_UNUSED)
198 {
199 char *error = NULL;
200
201 if (value == NULL || *value == '\0') {
202 return xstrdup("Value missing for encap property");
203 }
204
205 switch (prop_class) {
206 case OFPPPC_NSH:
207 switch (prop_type) {
208 case OFPPPT_PROP_NSH_MDTYPE: {
209 /* Format: "<md_type>:uint8_t". */
210 uint8_t md_type;
211 error = str_to_u8(value, "md_type", &md_type);
212 if (error != NULL) {
213 return error;
214 }
215 if (md_type < 1 || md_type > 2) {
216 return xstrdup("invalid md_type");
217 }
218 struct ofpact_ed_prop_nsh_md_type *pnmt =
219 ofpbuf_put_uninit(out, sizeof(*pnmt));
220 pnmt->header.prop_class = prop_class;
221 pnmt->header.type = prop_type;
222 pnmt->header.len =
223 offsetof(struct ofp_ed_prop_nsh_md_type, pad);
224 pnmt->md_type = md_type;
225 break;
226 }
227 case OFPPPT_PROP_NSH_TLV: {
228 /* Format: "<class>:ovs_be16,<type>:uint8_t,<val>:hex_string" */
229 struct ofpact_ed_prop_nsh_tlv *pnt;
230 uint16_t tlv_class;
231 uint8_t tlv_type;
232 char buf[256];
233 size_t tlv_value_len, padding;
234 size_t start_ofs = out->size;
235
236 if (!ovs_scan(value, "0x%"SCNx16",%"SCNu8",0x%251[0-9a-fA-F]",
237 &tlv_class, &tlv_type, buf)) {
238 return xasprintf("Invalid NSH TLV header: %s", value);
239 }
240 ofpbuf_put_uninit(out, sizeof(*pnt));
241 ofpbuf_put_hex(out, buf, &tlv_value_len);
242 pnt = ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *,
243 ((char *)out->data + start_ofs));
244 padding = ROUND_UP(tlv_value_len, 8) - tlv_value_len;
245 pnt->header.prop_class = prop_class;
246 pnt->header.type = prop_type;
247 pnt->header.len = sizeof(*pnt) + tlv_value_len + padding;
248 pnt->tlv_class = htons(tlv_class);
249 pnt->tlv_type = tlv_type;
250 pnt->tlv_len = tlv_value_len;
251 if (padding > 0) {
252 ofpbuf_put_zeros(out, padding);
253 }
254 break;
255 }
256 default:
257 /* Unsupported property types rejected before. */
258 OVS_NOT_REACHED();
259 }
260 break;
261 default:
262 /* Unsupported property classes rejected before. */
263 OVS_NOT_REACHED();
264 }
265
266 return NULL;
267 }
268
269 char *
270 format_ed_prop_class(const struct ofpact_ed_prop *prop)
271 {
272 switch (prop->prop_class) {
273 case OFPPPC_BASIC:
274 return "basic";
275 case OFPPPC_MPLS:
276 return "mpls";
277 case OFPPPC_GRE:
278 return "gre";
279 case OFPPPC_GTP:
280 return "gtp";
281 case OFPPPC_NSH:
282 return "nsh";
283 default:
284 OVS_NOT_REACHED();
285 }
286 }
287
288 char *
289 format_ed_prop_type(const struct ofpact_ed_prop *prop)
290 {
291 switch (prop->prop_class) {
292 case OFPPPC_NSH:
293 switch (prop->type) {
294 case OFPPPT_PROP_NSH_MDTYPE:
295 return "md_type";
296 case OFPPPT_PROP_NSH_TLV:
297 return "tlv";
298 default:
299 OVS_NOT_REACHED();
300 }
301 break;
302 default:
303 OVS_NOT_REACHED();
304 }
305 }
306
307 void
308 format_ed_prop(struct ds *s OVS_UNUSED,
309 const struct ofpact_ed_prop *prop)
310 {
311 switch (prop->prop_class) {
312 case OFPPPC_NSH:
313 switch (prop->type) {
314 case OFPPPT_PROP_NSH_MDTYPE: {
315 struct ofpact_ed_prop_nsh_md_type *pnmt =
316 ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *, prop);
317 ds_put_format(s, "%s=%d", format_ed_prop_type(prop),
318 pnmt->md_type);
319 return;
320 }
321 case OFPPPT_PROP_NSH_TLV: {
322 struct ofpact_ed_prop_nsh_tlv *pnt =
323 ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *, prop);
324 ds_put_format(s, "%s(0x%04x,%d,",
325 format_ed_prop_type(prop),
326 ntohs(pnt->tlv_class), pnt->tlv_type);
327 ds_put_hex(s, pnt->data, pnt->tlv_len);
328 ds_put_cstr(s,")");
329 return;
330 }
331 default:
332 OVS_NOT_REACHED();
333 }
334 default:
335 OVS_NOT_REACHED();
336 }
337 }