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/ofpbuf.h"
23 #include "openvswitch/ofp-parse.h"
25 #include "lib/packets.h"
29 decode_ed_prop(const struct ofp_ed_prop_header
**ofp_prop
,
30 struct ofpbuf
*out OVS_UNUSED
,
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);
38 if (len
< sizeof **ofp_prop
|| pad_len
> *remaining
) {
39 return OFPERR_OFPBAC_BAD_LEN
;
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
;
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
;
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
;
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
);
78 return OFPERR_NXBAC_UNKNOWN_ED_PROP
;
83 return OFPERR_NXBAC_UNKNOWN_ED_PROP
;
86 *remaining
-= pad_len
;
87 *ofp_prop
= ALIGNED_CAST(const struct ofp_ed_prop_header
*,
88 ((char *)(*ofp_prop
) + pad_len
));
93 encode_ed_prop(const struct ofpact_ed_prop
**prop
,
94 struct ofpbuf
*out OVS_UNUSED
)
98 switch ((*prop
)->prop_class
) {
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
;
109 offsetof(struct ofp_ed_prop_nsh_md_type
, pad
);
110 opnmt
->md_type
= pnmt
->md_type
;
111 prop_len
= sizeof(*pnmt
);
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
;
132 return OFPERR_OFPBAC_BAD_ARGUMENT
;
137 return OFPERR_OFPBAC_BAD_ARGUMENT
;
140 *prop
= ALIGNED_CAST(const struct ofpact_ed_prop
*,
141 ((char *)(*prop
) + prop_len
));
146 parse_ed_prop_class(const char *str OVS_UNUSED
,
147 uint16_t *prop_class
)
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
;
168 parse_ed_prop_type(uint16_t prop_class
,
169 const char *str OVS_UNUSED
,
170 uint8_t *type OVS_UNUSED
)
172 switch (prop_class
) {
174 if (!strcmp(str
, "md_type")) {
175 *type
= OFPPPT_PROP_NSH_MDTYPE
;
177 } else if (!strcmp(str
, "tlv")) {
178 *type
= OFPPPT_PROP_NSH_TLV
;
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
191 * Returns a malloced string in the event of a parse error. The caller
192 * must free the string.
196 parse_ed_prop_value(uint16_t prop_class
, uint8_t prop_type OVS_UNUSED
,
197 const char *value
, struct ofpbuf
*out OVS_UNUSED
)
201 if (value
== NULL
|| *value
== '\0') {
202 return xstrdup("Value missing for encap property");
205 switch (prop_class
) {
208 case OFPPPT_PROP_NSH_MDTYPE
: {
209 /* Format: "<md_type>:uint8_t". */
211 error
= str_to_u8(value
, "md_type", &md_type
);
215 if (md_type
< 1 || md_type
> 2) {
216 return xstrdup("invalid md_type");
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
;
223 offsetof(struct ofp_ed_prop_nsh_md_type
, pad
);
224 pnmt
->md_type
= md_type
;
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
;
233 size_t tlv_value_len
, padding
;
234 size_t start_ofs
= out
->size
;
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
);
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
;
252 ofpbuf_put_zeros(out
, padding
);
257 /* Unsupported property types rejected before. */
262 /* Unsupported property classes rejected before. */
270 format_ed_prop_class(const struct ofpact_ed_prop
*prop
)
272 switch (prop
->prop_class
) {
289 format_ed_prop_type(const struct ofpact_ed_prop
*prop
)
291 switch (prop
->prop_class
) {
293 switch (prop
->type
) {
294 case OFPPPT_PROP_NSH_MDTYPE
:
296 case OFPPPT_PROP_NSH_TLV
:
308 format_ed_prop(struct ds
*s OVS_UNUSED
,
309 const struct ofpact_ed_prop
*prop
)
311 switch (prop
->prop_class
) {
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
),
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
);