2 * Copyright (c) 2017 Intel, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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/ofp-util.h"
23 #include "openvswitch/ofpbuf.h"
24 #include "openvswitch/ofp-parse.h"
26 #include "lib/packets.h"
30 decode_ed_prop(const struct ofp_ed_prop_header
**ofp_prop
,
31 struct ofpbuf
*out OVS_UNUSED
,
34 uint16_t prop_class
= ntohs((*ofp_prop
)->prop_class
);
35 uint8_t prop_type
= (*ofp_prop
)->type
;
36 size_t len
= (*ofp_prop
)->len
;
37 size_t pad_len
= ROUND_UP(len
, 8);
39 if (pad_len
> *remaining
) {
40 return OFPERR_OFPBAC_BAD_LEN
;
46 case OFPPPT_PROP_NSH_MDTYPE
: {
47 struct ofp_ed_prop_nsh_md_type
*opnmt
=
48 ALIGNED_CAST(struct ofp_ed_prop_nsh_md_type
*, *ofp_prop
);
49 if (len
> sizeof(*opnmt
) || len
> *remaining
) {
50 return OFPERR_NXBAC_BAD_ED_PROP
;
52 struct ofpact_ed_prop_nsh_md_type
*pnmt
=
53 ofpbuf_put_uninit(out
, sizeof(*pnmt
));
54 pnmt
->header
.prop_class
= prop_class
;
55 pnmt
->header
.type
= prop_type
;
56 pnmt
->header
.len
= len
;
57 pnmt
->md_type
= opnmt
->md_type
;
60 case OFPPPT_PROP_NSH_TLV
: {
61 struct ofp_ed_prop_nsh_tlv
*opnt
=
62 ALIGNED_CAST(struct ofp_ed_prop_nsh_tlv
*, *ofp_prop
);
63 size_t tlv_pad_len
= ROUND_UP(opnt
->tlv_len
, 8);
64 if (len
!= sizeof(*opnt
) + tlv_pad_len
|| len
> *remaining
) {
65 return OFPERR_NXBAC_BAD_ED_PROP
;
67 struct ofpact_ed_prop_nsh_tlv
*pnt
=
68 ofpbuf_put_uninit(out
, sizeof(*pnt
));
69 pnt
->header
.prop_class
= prop_class
;
70 pnt
->header
.type
= prop_type
;
71 pnt
->header
.len
= len
;
72 pnt
->tlv_class
= opnt
->tlv_class
;
73 pnt
->tlv_type
= opnt
->tlv_type
;
74 pnt
->tlv_len
= opnt
->tlv_len
;
75 ofpbuf_put(out
, opnt
->data
, tlv_pad_len
);
79 return OFPERR_NXBAC_UNKNOWN_ED_PROP
;
84 return OFPERR_NXBAC_UNKNOWN_ED_PROP
;
87 *remaining
-= pad_len
;
88 *ofp_prop
= ALIGNED_CAST(const struct ofp_ed_prop_header
*,
89 ((char *)(*ofp_prop
) + pad_len
));
94 encode_ed_prop(const struct ofpact_ed_prop
**prop
,
95 struct ofpbuf
*out OVS_UNUSED
)
99 switch ((*prop
)->prop_class
) {
101 switch ((*prop
)->type
) {
102 case OFPPPT_PROP_NSH_MDTYPE
: {
103 struct ofpact_ed_prop_nsh_md_type
*pnmt
=
104 ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type
*, *prop
);
105 struct ofp_ed_prop_nsh_md_type
*opnmt
=
106 ofpbuf_put_uninit(out
, sizeof(*opnmt
));
107 opnmt
->header
.prop_class
= htons((*prop
)->prop_class
);
108 opnmt
->header
.type
= (*prop
)->type
;
110 offsetof(struct ofp_ed_prop_nsh_md_type
, pad
);
111 opnmt
->md_type
= pnmt
->md_type
;
112 prop_len
= sizeof(*pnmt
);
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
;
133 return OFPERR_OFPBAC_BAD_ARGUMENT
;
138 return OFPERR_OFPBAC_BAD_ARGUMENT
;
141 *prop
= ALIGNED_CAST(const struct ofpact_ed_prop
*,
142 ((char *)(*prop
) + prop_len
));
147 parse_ed_prop_class(const char *str OVS_UNUSED
,
148 uint16_t *prop_class
)
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
;
160 } else if (!strcmp(str
,"nsh")) {
161 *prop_class
= OFPPPC_NSH
;
169 parse_ed_prop_type(uint16_t prop_class
,
170 const char *str OVS_UNUSED
,
171 uint8_t *type OVS_UNUSED
)
173 switch (prop_class
) {
175 if (!strcmp(str
, "md_type")) {
176 *type
= OFPPPT_PROP_NSH_MDTYPE
;
178 } else if (!strcmp(str
, "tlv")) {
179 *type
= OFPPPT_PROP_NSH_TLV
;
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
192 * Returns a malloced string in the event of a parse error. The caller
193 * must free the string.
197 parse_ed_prop_value(uint16_t prop_class
, uint8_t prop_type OVS_UNUSED
,
198 const char *value
, struct ofpbuf
*out OVS_UNUSED
)
202 if (value
== NULL
|| *value
== '\0') {
203 return xstrdup("Value missing for encap property");
206 switch (prop_class
) {
209 case OFPPPT_PROP_NSH_MDTYPE
: {
210 /* Format: "<md_type>:uint8_t". */
212 error
= str_to_u8(value
, "md_type", &md_type
);
216 if (md_type
< 1 || md_type
> 2) {
217 return xstrdup("invalid md_type");
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
;
224 offsetof(struct ofp_ed_prop_nsh_md_type
, pad
);
225 pnmt
->md_type
= md_type
;
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
;
234 size_t tlv_value_len
, padding
;
235 size_t start_ofs
= out
->size
;
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
);
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
;
253 ofpbuf_put_zeros(out
, padding
);
258 /* Unsupported property types rejected before. */
263 /* Unsupported property classes rejected before. */
271 format_ed_prop_class(const struct ofpact_ed_prop
*prop
)
273 switch (prop
->prop_class
) {
290 format_ed_prop_type(const struct ofpact_ed_prop
*prop
)
292 switch (prop
->prop_class
) {
294 switch (prop
->type
) {
295 case OFPPPT_PROP_NSH_MDTYPE
:
297 case OFPPPT_PROP_NSH_TLV
:
309 format_ed_prop(struct ds
*s OVS_UNUSED
,
310 const struct ofpact_ed_prop
*prop
)
312 switch (prop
->prop_class
) {
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
),
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
);