]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ofp-ed-props.c
cirrus: Use FreeBSD 12.2.
[mirror_ovs.git] / lib / ofp-ed-props.c
CommitLineData
f839892a
JS
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>
b2befd5b
BP
18#include <sys/types.h>
19#include <netinet/in.h>
f839892a
JS
20#include <arpa/inet.h>
21#include "openvswitch/ofp-ed-props.h"
f839892a
JS
22#include "openvswitch/ofpbuf.h"
23#include "openvswitch/ofp-parse.h"
24#include "util.h"
25#include "lib/packets.h"
26
27
28enum ofperr
29decode_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);
1fc11c59 34 uint8_t prop_type = (*ofp_prop)->type;
f839892a
JS
35 size_t len = (*ofp_prop)->len;
36 size_t pad_len = ROUND_UP(len, 8);
37
be5e6d68 38 if (len < sizeof **ofp_prop || pad_len > *remaining) {
f839892a
JS
39 return OFPERR_OFPBAC_BAD_LEN;
40 }
41
42 switch (prop_class) {
1fc11c59
JS
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 =
51dec40f 52 ofpbuf_put_zeros(out, sizeof *pnmt);
1fc11c59
JS
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 }
f839892a
JS
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
92enum ofperr
93encode_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) {
1fc11c59
JS
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;
51dec40f 111 memset(opnmt->pad, 0, sizeof opnmt->pad);
1fc11c59
JS
112 prop_len = sizeof(*pnmt);
113 break;
114 }
115 case OFPPPT_PROP_NSH_TLV: {
116 struct ofpact_ed_prop_nsh_tlv *pnt =
117 ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *, *prop);
118 struct ofp_ed_prop_nsh_tlv *opnt;
119 size_t tlv_pad_len = ROUND_UP(pnt->tlv_len, 8);
120 size_t len = sizeof(*opnt) + tlv_pad_len;
121 opnt = ofpbuf_put_uninit(out, len);
122 opnt->header.prop_class = htons((*prop)->prop_class);
123 opnt->header.type = (*prop)->type;
124 opnt->header.len = len;
125 opnt->tlv_class = pnt->tlv_class;
126 opnt->tlv_type = pnt->tlv_type;
127 opnt->tlv_len = pnt->tlv_len;
128 memcpy(opnt->data, pnt->data, tlv_pad_len);
129 prop_len = sizeof(*pnt) + tlv_pad_len;
130 break;
131 }
132 default:
133 return OFPERR_OFPBAC_BAD_ARGUMENT;
134 }
135 break;
136 }
f839892a
JS
137 default:
138 return OFPERR_OFPBAC_BAD_ARGUMENT;
139 }
140
141 *prop = ALIGNED_CAST(const struct ofpact_ed_prop *,
142 ((char *)(*prop) + prop_len));
143 return 0;
144}
145
146bool
147parse_ed_prop_class(const char *str OVS_UNUSED,
148 uint16_t *prop_class)
149{
150 if (!strcmp(str,"basic")) {
151 *prop_class = OFPPPC_BASIC;
152 } else if (!strcmp(str,"ethernet")) {
153 *prop_class = OFPPPC_BASIC;
154 } else if (!strcmp(str,"mpls")) {
155 *prop_class = OFPPPC_MPLS;
156 } else if (!strcmp(str,"gre")) {
157 *prop_class = OFPPPC_GRE;
158 } else if (!strcmp(str,"gtp")) {
159 *prop_class = OFPPPC_GTP;
1fc11c59
JS
160 } else if (!strcmp(str,"nsh")) {
161 *prop_class = OFPPPC_NSH;
f839892a
JS
162 } else {
163 return false;
164 }
165 return true;
166}
167
168bool
169parse_ed_prop_type(uint16_t prop_class,
170 const char *str OVS_UNUSED,
171 uint8_t *type OVS_UNUSED)
172{
173 switch (prop_class) {
1fc11c59
JS
174 case OFPPPC_NSH:
175 if (!strcmp(str, "md_type")) {
176 *type = OFPPPT_PROP_NSH_MDTYPE;
177 return true;
178 } else if (!strcmp(str, "tlv")) {
179 *type = OFPPPT_PROP_NSH_TLV;
180 return true;
181 } else {
182 return false;
183 }
f839892a
JS
184 default:
185 return false;
186 }
187}
188
189/* Parse the value of an encap/decap property based on property class
190 * and type and append the parsed property in internal format to the
191 * ofpbuf out.
192 * Returns a malloced string in the event of a parse error. The caller
193 * must free the string.
194 */
195
196char *
197parse_ed_prop_value(uint16_t prop_class, uint8_t prop_type OVS_UNUSED,
198 const char *value, struct ofpbuf *out OVS_UNUSED)
199{
1fc11c59 200 char *error = NULL;
f839892a
JS
201
202 if (value == NULL || *value == '\0') {
203 return xstrdup("Value missing for encap property");
204 }
205
206 switch (prop_class) {
1fc11c59
JS
207 case OFPPPC_NSH:
208 switch (prop_type) {
209 case OFPPPT_PROP_NSH_MDTYPE: {
210 /* Format: "<md_type>:uint8_t". */
211 uint8_t md_type;
212 error = str_to_u8(value, "md_type", &md_type);
213 if (error != NULL) {
214 return error;
215 }
216 if (md_type < 1 || md_type > 2) {
217 return xstrdup("invalid md_type");
218 }
219 struct ofpact_ed_prop_nsh_md_type *pnmt =
220 ofpbuf_put_uninit(out, sizeof(*pnmt));
221 pnmt->header.prop_class = prop_class;
222 pnmt->header.type = prop_type;
223 pnmt->header.len =
224 offsetof(struct ofp_ed_prop_nsh_md_type, pad);
225 pnmt->md_type = md_type;
226 break;
227 }
228 case OFPPPT_PROP_NSH_TLV: {
229 /* Format: "<class>:ovs_be16,<type>:uint8_t,<val>:hex_string" */
230 struct ofpact_ed_prop_nsh_tlv *pnt;
231 uint16_t tlv_class;
232 uint8_t tlv_type;
233 char buf[256];
234 size_t tlv_value_len, padding;
235 size_t start_ofs = out->size;
236
237 if (!ovs_scan(value, "0x%"SCNx16",%"SCNu8",0x%251[0-9a-fA-F]",
238 &tlv_class, &tlv_type, buf)) {
239 return xasprintf("Invalid NSH TLV header: %s", value);
240 }
241 ofpbuf_put_uninit(out, sizeof(*pnt));
242 ofpbuf_put_hex(out, buf, &tlv_value_len);
243 pnt = ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *,
244 ((char *)out->data + start_ofs));
245 padding = ROUND_UP(tlv_value_len, 8) - tlv_value_len;
246 pnt->header.prop_class = prop_class;
247 pnt->header.type = prop_type;
248 pnt->header.len = sizeof(*pnt) + tlv_value_len + padding;
249 pnt->tlv_class = htons(tlv_class);
250 pnt->tlv_type = tlv_type;
251 pnt->tlv_len = tlv_value_len;
252 if (padding > 0) {
253 ofpbuf_put_zeros(out, padding);
254 }
255 break;
256 }
257 default:
258 /* Unsupported property types rejected before. */
259 OVS_NOT_REACHED();
260 }
261 break;
f839892a
JS
262 default:
263 /* Unsupported property classes rejected before. */
264 OVS_NOT_REACHED();
265 }
266
267 return NULL;
268}
269
270char *
271format_ed_prop_class(const struct ofpact_ed_prop *prop)
272{
273 switch (prop->prop_class) {
274 case OFPPPC_BASIC:
275 return "basic";
276 case OFPPPC_MPLS:
277 return "mpls";
278 case OFPPPC_GRE:
279 return "gre";
280 case OFPPPC_GTP:
281 return "gtp";
1fc11c59
JS
282 case OFPPPC_NSH:
283 return "nsh";
f839892a
JS
284 default:
285 OVS_NOT_REACHED();
286 }
287}
288
289char *
290format_ed_prop_type(const struct ofpact_ed_prop *prop)
291{
292 switch (prop->prop_class) {
1fc11c59
JS
293 case OFPPPC_NSH:
294 switch (prop->type) {
295 case OFPPPT_PROP_NSH_MDTYPE:
296 return "md_type";
297 case OFPPPT_PROP_NSH_TLV:
298 return "tlv";
299 default:
300 OVS_NOT_REACHED();
301 }
302 break;
f839892a
JS
303 default:
304 OVS_NOT_REACHED();
305 }
306}
307
308void
309format_ed_prop(struct ds *s OVS_UNUSED,
310 const struct ofpact_ed_prop *prop)
311{
312 switch (prop->prop_class) {
1fc11c59
JS
313 case OFPPPC_NSH:
314 switch (prop->type) {
315 case OFPPPT_PROP_NSH_MDTYPE: {
316 struct ofpact_ed_prop_nsh_md_type *pnmt =
317 ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type *, prop);
318 ds_put_format(s, "%s=%d", format_ed_prop_type(prop),
319 pnmt->md_type);
320 return;
321 }
322 case OFPPPT_PROP_NSH_TLV: {
323 struct ofpact_ed_prop_nsh_tlv *pnt =
324 ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv *, prop);
325 ds_put_format(s, "%s(0x%04x,%d,",
326 format_ed_prop_type(prop),
327 ntohs(pnt->tlv_class), pnt->tlv_type);
328 ds_put_hex(s, pnt->data, pnt->tlv_len);
329 ds_put_cstr(s,")");
330 return;
331 }
332 default:
333 OVS_NOT_REACHED();
334 }
f839892a
JS
335 default:
336 OVS_NOT_REACHED();
337 }
338}