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 <arpa/inet.h>
19 #include "openvswitch/ofp-ed-props.h"
20 #include "openvswitch/ofp-util.h"
21 #include "openvswitch/ofpbuf.h"
22 #include "openvswitch/ofp-parse.h"
24 #include "lib/packets.h"
28 decode_ed_prop(const struct ofp_ed_prop_header
**ofp_prop
,
29 struct ofpbuf
*out OVS_UNUSED
,
32 uint16_t prop_class
= ntohs((*ofp_prop
)->prop_class
);
33 uint8_t prop_type
= (*ofp_prop
)->type
;
34 size_t len
= (*ofp_prop
)->len
;
35 size_t pad_len
= ROUND_UP(len
, 8);
37 if (pad_len
> *remaining
) {
38 return OFPERR_OFPBAC_BAD_LEN
;
44 case OFPPPT_PROP_NSH_MDTYPE
: {
45 struct ofp_ed_prop_nsh_md_type
*opnmt
=
46 ALIGNED_CAST(struct ofp_ed_prop_nsh_md_type
*, *ofp_prop
);
47 if (len
> sizeof(*opnmt
) || len
> *remaining
) {
48 return OFPERR_NXBAC_BAD_ED_PROP
;
50 struct ofpact_ed_prop_nsh_md_type
*pnmt
=
51 ofpbuf_put_uninit(out
, sizeof(*pnmt
));
52 pnmt
->header
.prop_class
= prop_class
;
53 pnmt
->header
.type
= prop_type
;
54 pnmt
->header
.len
= len
;
55 pnmt
->md_type
= opnmt
->md_type
;
58 case OFPPPT_PROP_NSH_TLV
: {
59 struct ofp_ed_prop_nsh_tlv
*opnt
=
60 ALIGNED_CAST(struct ofp_ed_prop_nsh_tlv
*, *ofp_prop
);
61 size_t tlv_pad_len
= ROUND_UP(opnt
->tlv_len
, 8);
62 if (len
!= sizeof(*opnt
) + tlv_pad_len
|| len
> *remaining
) {
63 return OFPERR_NXBAC_BAD_ED_PROP
;
65 struct ofpact_ed_prop_nsh_tlv
*pnt
=
66 ofpbuf_put_uninit(out
, sizeof(*pnt
));
67 pnt
->header
.prop_class
= prop_class
;
68 pnt
->header
.type
= prop_type
;
69 pnt
->header
.len
= len
;
70 pnt
->tlv_class
= opnt
->tlv_class
;
71 pnt
->tlv_type
= opnt
->tlv_type
;
72 pnt
->tlv_len
= opnt
->tlv_len
;
73 ofpbuf_put(out
, opnt
->data
, tlv_pad_len
);
77 return OFPERR_NXBAC_UNKNOWN_ED_PROP
;
82 return OFPERR_NXBAC_UNKNOWN_ED_PROP
;
85 *remaining
-= pad_len
;
86 *ofp_prop
= ALIGNED_CAST(const struct ofp_ed_prop_header
*,
87 ((char *)(*ofp_prop
) + pad_len
));
92 encode_ed_prop(const struct ofpact_ed_prop
**prop
,
93 struct ofpbuf
*out OVS_UNUSED
)
97 switch ((*prop
)->prop_class
) {
99 switch ((*prop
)->type
) {
100 case OFPPPT_PROP_NSH_MDTYPE
: {
101 struct ofpact_ed_prop_nsh_md_type
*pnmt
=
102 ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type
*, *prop
);
103 struct ofp_ed_prop_nsh_md_type
*opnmt
=
104 ofpbuf_put_uninit(out
, sizeof(*opnmt
));
105 opnmt
->header
.prop_class
= htons((*prop
)->prop_class
);
106 opnmt
->header
.type
= (*prop
)->type
;
108 offsetof(struct ofp_ed_prop_nsh_md_type
, pad
);
109 opnmt
->md_type
= pnmt
->md_type
;
110 prop_len
= sizeof(*pnmt
);
113 case OFPPPT_PROP_NSH_TLV
: {
114 struct ofpact_ed_prop_nsh_tlv
*pnt
=
115 ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv
*, *prop
);
116 struct ofp_ed_prop_nsh_tlv
*opnt
;
117 size_t tlv_pad_len
= ROUND_UP(pnt
->tlv_len
, 8);
118 size_t len
= sizeof(*opnt
) + tlv_pad_len
;
119 opnt
= ofpbuf_put_uninit(out
, len
);
120 opnt
->header
.prop_class
= htons((*prop
)->prop_class
);
121 opnt
->header
.type
= (*prop
)->type
;
122 opnt
->header
.len
= len
;
123 opnt
->tlv_class
= pnt
->tlv_class
;
124 opnt
->tlv_type
= pnt
->tlv_type
;
125 opnt
->tlv_len
= pnt
->tlv_len
;
126 memcpy(opnt
->data
, pnt
->data
, tlv_pad_len
);
127 prop_len
= sizeof(*pnt
) + tlv_pad_len
;
131 return OFPERR_OFPBAC_BAD_ARGUMENT
;
136 return OFPERR_OFPBAC_BAD_ARGUMENT
;
139 *prop
= ALIGNED_CAST(const struct ofpact_ed_prop
*,
140 ((char *)(*prop
) + prop_len
));
145 parse_ed_prop_class(const char *str OVS_UNUSED
,
146 uint16_t *prop_class
)
148 if (!strcmp(str
,"basic")) {
149 *prop_class
= OFPPPC_BASIC
;
150 } else if (!strcmp(str
,"ethernet")) {
151 *prop_class
= OFPPPC_BASIC
;
152 } else if (!strcmp(str
,"mpls")) {
153 *prop_class
= OFPPPC_MPLS
;
154 } else if (!strcmp(str
,"gre")) {
155 *prop_class
= OFPPPC_GRE
;
156 } else if (!strcmp(str
,"gtp")) {
157 *prop_class
= OFPPPC_GTP
;
158 } else if (!strcmp(str
,"nsh")) {
159 *prop_class
= OFPPPC_NSH
;
167 parse_ed_prop_type(uint16_t prop_class
,
168 const char *str OVS_UNUSED
,
169 uint8_t *type OVS_UNUSED
)
171 switch (prop_class
) {
173 if (!strcmp(str
, "md_type")) {
174 *type
= OFPPPT_PROP_NSH_MDTYPE
;
176 } else if (!strcmp(str
, "tlv")) {
177 *type
= OFPPPT_PROP_NSH_TLV
;
187 /* Parse the value of an encap/decap property based on property class
188 * and type and append the parsed property in internal format to the
190 * Returns a malloced string in the event of a parse error. The caller
191 * must free the string.
195 parse_ed_prop_value(uint16_t prop_class
, uint8_t prop_type OVS_UNUSED
,
196 const char *value
, struct ofpbuf
*out OVS_UNUSED
)
200 if (value
== NULL
|| *value
== '\0') {
201 return xstrdup("Value missing for encap property");
204 switch (prop_class
) {
207 case OFPPPT_PROP_NSH_MDTYPE
: {
208 /* Format: "<md_type>:uint8_t". */
210 error
= str_to_u8(value
, "md_type", &md_type
);
214 if (md_type
< 1 || md_type
> 2) {
215 return xstrdup("invalid md_type");
217 struct ofpact_ed_prop_nsh_md_type
*pnmt
=
218 ofpbuf_put_uninit(out
, sizeof(*pnmt
));
219 pnmt
->header
.prop_class
= prop_class
;
220 pnmt
->header
.type
= prop_type
;
222 offsetof(struct ofp_ed_prop_nsh_md_type
, pad
);
223 pnmt
->md_type
= md_type
;
226 case OFPPPT_PROP_NSH_TLV
: {
227 /* Format: "<class>:ovs_be16,<type>:uint8_t,<val>:hex_string" */
228 struct ofpact_ed_prop_nsh_tlv
*pnt
;
232 size_t tlv_value_len
, padding
;
233 size_t start_ofs
= out
->size
;
235 if (!ovs_scan(value
, "0x%"SCNx16
",%"SCNu8
",0x%251[0-9a-fA-F]",
236 &tlv_class
, &tlv_type
, buf
)) {
237 return xasprintf("Invalid NSH TLV header: %s", value
);
239 ofpbuf_put_uninit(out
, sizeof(*pnt
));
240 ofpbuf_put_hex(out
, buf
, &tlv_value_len
);
241 pnt
= ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv
*,
242 ((char *)out
->data
+ start_ofs
));
243 padding
= ROUND_UP(tlv_value_len
, 8) - tlv_value_len
;
244 pnt
->header
.prop_class
= prop_class
;
245 pnt
->header
.type
= prop_type
;
246 pnt
->header
.len
= sizeof(*pnt
) + tlv_value_len
+ padding
;
247 pnt
->tlv_class
= htons(tlv_class
);
248 pnt
->tlv_type
= tlv_type
;
249 pnt
->tlv_len
= tlv_value_len
;
251 ofpbuf_put_zeros(out
, padding
);
256 /* Unsupported property types rejected before. */
261 /* Unsupported property classes rejected before. */
269 format_ed_prop_class(const struct ofpact_ed_prop
*prop
)
271 switch (prop
->prop_class
) {
288 format_ed_prop_type(const struct ofpact_ed_prop
*prop
)
290 switch (prop
->prop_class
) {
292 switch (prop
->type
) {
293 case OFPPPT_PROP_NSH_MDTYPE
:
295 case OFPPPT_PROP_NSH_TLV
:
307 format_ed_prop(struct ds
*s OVS_UNUSED
,
308 const struct ofpact_ed_prop
*prop
)
310 switch (prop
->prop_class
) {
312 switch (prop
->type
) {
313 case OFPPPT_PROP_NSH_MDTYPE
: {
314 struct ofpact_ed_prop_nsh_md_type
*pnmt
=
315 ALIGNED_CAST(struct ofpact_ed_prop_nsh_md_type
*, prop
);
316 ds_put_format(s
, "%s=%d", format_ed_prop_type(prop
),
320 case OFPPPT_PROP_NSH_TLV
: {
321 struct ofpact_ed_prop_nsh_tlv
*pnt
=
322 ALIGNED_CAST(struct ofpact_ed_prop_nsh_tlv
*, prop
);
323 ds_put_format(s
, "%s(0x%04x,%d,",
324 format_ed_prop_type(prop
),
325 ntohs(pnt
->tlv_class
), pnt
->tlv_type
);
326 ds_put_hex(s
, pnt
->data
, pnt
->tlv_len
);