]>
git.proxmox.com Git - mirror_ovs.git/blob - lib/ofp-parse.c
2 * Copyright (c) 2010 Nicira Networks.
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.
19 #include "ofp-parse.h"
24 #include "byte-order.h"
25 #include "dynamic-string.h"
29 #include "openflow/openflow.h"
31 #include "socket-util.h"
35 VLOG_DEFINE_THIS_MODULE(ofp_parse
)
38 str_to_u32(const char *str
)
44 ovs_fatal(0, "missing required numeric argument");
48 value
= strtoul(str
, &tail
, 0);
49 if (errno
== EINVAL
|| errno
== ERANGE
|| *tail
) {
50 ovs_fatal(0, "invalid numeric format %s", str
);
56 str_to_u64(const char *str
)
62 value
= strtoull(str
, &tail
, 0);
63 if (errno
== EINVAL
|| errno
== ERANGE
|| *tail
) {
64 ovs_fatal(0, "invalid numeric format %s", str
);
70 str_to_mac(const char *str
, uint8_t mac
[6])
72 if (sscanf(str
, ETH_ADDR_SCAN_FMT
, ETH_ADDR_SCAN_ARGS(mac
))
73 != ETH_ADDR_SCAN_COUNT
) {
74 ovs_fatal(0, "invalid mac address %s", str
);
79 str_to_ip(const char *str_
, uint32_t *ip
)
81 char *str
= xstrdup(str_
);
82 char *save_ptr
= NULL
;
83 const char *name
, *netmask
;
84 struct in_addr in_addr
;
87 name
= strtok_r(str
, "/", &save_ptr
);
88 retval
= name
? lookup_ip(name
, &in_addr
) : EINVAL
;
90 ovs_fatal(0, "%s: could not convert to IP address", str
);
94 netmask
= strtok_r(NULL
, "/", &save_ptr
);
97 if (sscanf(netmask
, "%"SCNu8
".%"SCNu8
".%"SCNu8
".%"SCNu8
,
98 &o
[0], &o
[1], &o
[2], &o
[3]) == 4) {
99 uint32_t nm
= (o
[0] << 24) | (o
[1] << 16) | (o
[2] << 8) | o
[3];
102 /* Find first 1-bit. */
103 for (i
= 0; i
< 32; i
++) {
104 if (nm
& (1u << i
)) {
110 /* Verify that the rest of the bits are 1-bits. */
111 for (; i
< 32; i
++) {
112 if (!(nm
& (1u << i
))) {
113 ovs_fatal(0, "%s: %s is not a valid netmask",
118 int prefix
= atoi(netmask
);
119 if (prefix
<= 0 || prefix
> 32) {
120 ovs_fatal(0, "%s: network prefix bits not between 1 and 32",
123 n_wild
= 32 - prefix
;
134 put_action(struct ofpbuf
*b
, size_t size
, uint16_t type
)
136 struct ofp_action_header
*ah
= ofpbuf_put_zeros(b
, size
);
137 ah
->type
= htons(type
);
138 ah
->len
= htons(size
);
142 static struct ofp_action_output
*
143 put_output_action(struct ofpbuf
*b
, uint16_t port
)
145 struct ofp_action_output
*oao
= put_action(b
, sizeof *oao
, OFPAT_OUTPUT
);
146 oao
->port
= htons(port
);
151 put_enqueue_action(struct ofpbuf
*b
, uint16_t port
, uint32_t queue
)
153 struct ofp_action_enqueue
*oae
= put_action(b
, sizeof *oae
, OFPAT_ENQUEUE
);
154 oae
->port
= htons(port
);
155 oae
->queue_id
= htonl(queue
);
159 put_dl_addr_action(struct ofpbuf
*b
, uint16_t type
, const char *addr
)
161 struct ofp_action_dl_addr
*oada
= put_action(b
, sizeof *oada
, type
);
162 str_to_mac(addr
, oada
->dl_addr
);
167 parse_port_name(const char *name
, uint16_t *port
)
173 static const struct pair pairs
[] = {
174 #define DEF_PAIR(NAME) {#NAME, OFPP_##NAME}
180 DEF_PAIR(CONTROLLER
),
185 static const int n_pairs
= ARRAY_SIZE(pairs
);
188 for (i
= 0; i
< n_pairs
; i
++) {
189 if (!strcasecmp(name
, pairs
[i
].name
)) {
190 *port
= pairs
[i
].value
;
198 str_to_action(char *str
, struct ofpbuf
*b
)
201 char *saveptr
= NULL
;
205 for (act
= strtok_r(str
, ", \t\r\n", &saveptr
), n_actions
= 0; act
;
206 act
= strtok_r(NULL
, ", \t\r\n", &saveptr
), n_actions
++)
211 ovs_fatal(0, "Drop actions must not be followed by other actions");
214 /* Arguments are separated by colons */
215 arg
= strchr(act
, ':');
221 if (!strcasecmp(act
, "mod_vlan_vid")) {
222 struct ofp_action_vlan_vid
*va
;
223 va
= put_action(b
, sizeof *va
, OFPAT_SET_VLAN_VID
);
224 va
->vlan_vid
= htons(str_to_u32(arg
));
225 } else if (!strcasecmp(act
, "mod_vlan_pcp")) {
226 struct ofp_action_vlan_pcp
*va
;
227 va
= put_action(b
, sizeof *va
, OFPAT_SET_VLAN_PCP
);
228 va
->vlan_pcp
= str_to_u32(arg
);
229 } else if (!strcasecmp(act
, "strip_vlan")) {
230 struct ofp_action_header
*ah
;
231 ah
= put_action(b
, sizeof *ah
, OFPAT_STRIP_VLAN
);
232 ah
->type
= htons(OFPAT_STRIP_VLAN
);
233 } else if (!strcasecmp(act
, "mod_dl_src")) {
234 put_dl_addr_action(b
, OFPAT_SET_DL_SRC
, arg
);
235 } else if (!strcasecmp(act
, "mod_dl_dst")) {
236 put_dl_addr_action(b
, OFPAT_SET_DL_DST
, arg
);
237 } else if (!strcasecmp(act
, "mod_nw_src")) {
238 struct ofp_action_nw_addr
*na
;
239 na
= put_action(b
, sizeof *na
, OFPAT_SET_NW_SRC
);
240 str_to_ip(arg
, &na
->nw_addr
);
241 } else if (!strcasecmp(act
, "mod_nw_dst")) {
242 struct ofp_action_nw_addr
*na
;
243 na
= put_action(b
, sizeof *na
, OFPAT_SET_NW_DST
);
244 str_to_ip(arg
, &na
->nw_addr
);
245 } else if (!strcasecmp(act
, "mod_tp_src")) {
246 struct ofp_action_tp_port
*ta
;
247 ta
= put_action(b
, sizeof *ta
, OFPAT_SET_TP_SRC
);
248 ta
->tp_port
= htons(str_to_u32(arg
));
249 } else if (!strcasecmp(act
, "mod_tp_dst")) {
250 struct ofp_action_tp_port
*ta
;
251 ta
= put_action(b
, sizeof *ta
, OFPAT_SET_TP_DST
);
252 ta
->tp_port
= htons(str_to_u32(arg
));
253 } else if (!strcasecmp(act
, "mod_nw_tos")) {
254 struct ofp_action_nw_tos
*nt
;
255 nt
= put_action(b
, sizeof *nt
, OFPAT_SET_NW_TOS
);
256 nt
->nw_tos
= str_to_u32(arg
);
257 } else if (!strcasecmp(act
, "resubmit")) {
258 struct nx_action_resubmit
*nar
;
259 nar
= put_action(b
, sizeof *nar
, OFPAT_VENDOR
);
260 nar
->vendor
= htonl(NX_VENDOR_ID
);
261 nar
->subtype
= htons(NXAST_RESUBMIT
);
262 nar
->in_port
= htons(str_to_u32(arg
));
263 } else if (!strcasecmp(act
, "set_tunnel")) {
264 struct nx_action_set_tunnel
*nast
;
265 nast
= put_action(b
, sizeof *nast
, OFPAT_VENDOR
);
266 nast
->vendor
= htonl(NX_VENDOR_ID
);
267 nast
->subtype
= htons(NXAST_SET_TUNNEL
);
268 nast
->tun_id
= htonl(str_to_u32(arg
));
269 } else if (!strcasecmp(act
, "drop_spoofed_arp")) {
270 struct nx_action_header
*nah
;
271 nah
= put_action(b
, sizeof *nah
, OFPAT_VENDOR
);
272 nah
->vendor
= htonl(NX_VENDOR_ID
);
273 nah
->subtype
= htons(NXAST_DROP_SPOOFED_ARP
);
274 } else if (!strcasecmp(act
, "set_queue")) {
275 struct nx_action_set_queue
*nasq
;
276 nasq
= put_action(b
, sizeof *nasq
, OFPAT_VENDOR
);
277 nasq
->vendor
= htonl(NX_VENDOR_ID
);
278 nasq
->subtype
= htons(NXAST_SET_QUEUE
);
279 nasq
->queue_id
= htonl(str_to_u32(arg
));
280 } else if (!strcasecmp(act
, "pop_queue")) {
281 struct nx_action_header
*nah
;
282 nah
= put_action(b
, sizeof *nah
, OFPAT_VENDOR
);
283 nah
->vendor
= htonl(NX_VENDOR_ID
);
284 nah
->subtype
= htons(NXAST_POP_QUEUE
);
285 } else if (!strcasecmp(act
, "output")) {
286 put_output_action(b
, str_to_u32(arg
));
287 } else if (!strcasecmp(act
, "enqueue")) {
289 char *port_s
= strtok_r(arg
, ":q", &sp
);
290 char *queue
= strtok_r(NULL
, "", &sp
);
291 if (port_s
== NULL
|| queue
== NULL
) {
292 ovs_fatal(0, "\"enqueue\" syntax is \"enqueue:PORT:QUEUE\"");
294 put_enqueue_action(b
, str_to_u32(port_s
), str_to_u32(queue
));
295 } else if (!strcasecmp(act
, "drop")) {
296 /* A drop action in OpenFlow occurs by just not setting
300 ovs_fatal(0, "Drop actions must not be preceded by other "
303 } else if (!strcasecmp(act
, "CONTROLLER")) {
304 struct ofp_action_output
*oao
;
305 oao
= put_output_action(b
, OFPP_CONTROLLER
);
307 /* Unless a numeric argument is specified, we send the whole
308 * packet to the controller. */
309 if (arg
&& (strspn(arg
, "0123456789") == strlen(arg
))) {
310 oao
->max_len
= htons(str_to_u32(arg
));
312 oao
->max_len
= htons(UINT16_MAX
);
314 } else if (parse_port_name(act
, &port
)) {
315 put_output_action(b
, port
);
316 } else if (strspn(act
, "0123456789") == strlen(act
)) {
317 put_output_action(b
, str_to_u32(act
));
319 ovs_fatal(0, "Unknown action: %s", act
);
331 parse_protocol(const char *name
, const struct protocol
**p_out
)
333 static const struct protocol protocols
[] = {
334 { "ip", ETH_TYPE_IP
, 0 },
335 { "arp", ETH_TYPE_ARP
, 0 },
336 { "icmp", ETH_TYPE_IP
, IP_TYPE_ICMP
},
337 { "tcp", ETH_TYPE_IP
, IP_TYPE_TCP
},
338 { "udp", ETH_TYPE_IP
, IP_TYPE_UDP
},
340 const struct protocol
*p
;
342 for (p
= protocols
; p
< &protocols
[ARRAY_SIZE(protocols
)]; p
++) {
343 if (!strcmp(p
->name
, name
)) {
355 enum { F_U8
, F_U16
, F_MAC
, F_IP
} type
;
356 size_t offset
, shift
;
360 parse_field(const char *name
, const struct field
**f_out
)
362 #define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER)
363 static const struct field fields
[] = {
364 { "in_port", OFPFW_IN_PORT
, F_U16
, F_OFS(in_port
), 0 },
365 { "dl_vlan", OFPFW_DL_VLAN
, F_U16
, F_OFS(dl_vlan
), 0 },
366 { "dl_vlan_pcp", OFPFW_DL_VLAN_PCP
, F_U8
, F_OFS(dl_vlan_pcp
), 0 },
367 { "dl_src", OFPFW_DL_SRC
, F_MAC
, F_OFS(dl_src
), 0 },
368 { "dl_dst", OFPFW_DL_DST
, F_MAC
, F_OFS(dl_dst
), 0 },
369 { "dl_type", OFPFW_DL_TYPE
, F_U16
, F_OFS(dl_type
), 0 },
370 { "nw_src", OFPFW_NW_SRC_MASK
, F_IP
,
371 F_OFS(nw_src
), OFPFW_NW_SRC_SHIFT
},
372 { "nw_dst", OFPFW_NW_DST_MASK
, F_IP
,
373 F_OFS(nw_dst
), OFPFW_NW_DST_SHIFT
},
374 { "nw_proto", OFPFW_NW_PROTO
, F_U8
, F_OFS(nw_proto
), 0 },
375 { "nw_tos", OFPFW_NW_TOS
, F_U8
, F_OFS(nw_tos
), 0 },
376 { "tp_src", OFPFW_TP_SRC
, F_U16
, F_OFS(tp_src
), 0 },
377 { "tp_dst", OFPFW_TP_DST
, F_U16
, F_OFS(tp_dst
), 0 },
378 { "icmp_type", OFPFW_ICMP_TYPE
, F_U16
, F_OFS(icmp_type
), 0 },
379 { "icmp_code", OFPFW_ICMP_CODE
, F_U16
, F_OFS(icmp_code
), 0 }
381 const struct field
*f
;
383 for (f
= fields
; f
< &fields
[ARRAY_SIZE(fields
)]; f
++) {
384 if (!strcmp(f
->name
, name
)) {
393 /* Convert 'string' (as described in the Flow Syntax section of the
394 * ovs-ofctl man page) into 'match'. The other arguments are optional
395 * and may be NULL if their value is not needed. If 'actions' is
396 * specified, an action must be in 'string' and may be expanded or
399 parse_ofp_str(char *string
, struct ofp_match
*match
, struct ofpbuf
*actions
,
400 uint8_t *table_idx
, uint16_t *out_port
, uint16_t *priority
,
401 uint16_t *idle_timeout
, uint16_t *hard_timeout
,
404 struct ofp_match normalized
;
405 char *save_ptr
= NULL
;
413 *out_port
= OFPP_NONE
;
416 *priority
= OFP_DEFAULT_PRIORITY
;
419 *idle_timeout
= OFP_FLOW_PERMANENT
;
422 *hard_timeout
= OFP_FLOW_PERMANENT
;
428 char *act_str
= strstr(string
, "action");
430 ovs_fatal(0, "must specify an action");
434 act_str
= strchr(act_str
+ 1, '=');
436 ovs_fatal(0, "must specify an action");
441 str_to_action(act_str
, actions
);
443 memset(match
, 0, sizeof *match
);
444 wildcards
= OFPFW_ALL
;
445 for (name
= strtok_r(string
, "=, \t\r\n", &save_ptr
); name
;
446 name
= strtok_r(NULL
, "=, \t\r\n", &save_ptr
)) {
447 const struct protocol
*p
;
449 if (parse_protocol(name
, &p
)) {
450 wildcards
&= ~OFPFW_DL_TYPE
;
451 match
->dl_type
= htons(p
->dl_type
);
453 wildcards
&= ~OFPFW_NW_PROTO
;
454 match
->nw_proto
= p
->nw_proto
;
457 const struct field
*f
;
460 value
= strtok_r(NULL
, ", \t\r\n", &save_ptr
);
462 ovs_fatal(0, "field %s missing value", name
);
465 if (table_idx
&& !strcmp(name
, "table")) {
466 *table_idx
= atoi(value
);
467 } else if (out_port
&& !strcmp(name
, "out_port")) {
468 *out_port
= atoi(value
);
469 } else if (priority
&& !strcmp(name
, "priority")) {
470 *priority
= atoi(value
);
471 } else if (idle_timeout
&& !strcmp(name
, "idle_timeout")) {
472 *idle_timeout
= atoi(value
);
473 } else if (hard_timeout
&& !strcmp(name
, "hard_timeout")) {
474 *hard_timeout
= atoi(value
);
475 } else if (cookie
&& !strcmp(name
, "cookie")) {
476 *cookie
= str_to_u64(value
);
477 } else if (!strcmp(name
, "tun_id_wild")) {
478 wildcards
|= NXFW_TUN_ID
;
479 } else if (parse_field(name
, &f
)) {
480 void *data
= (char *) match
+ f
->offset
;
481 if (!strcmp(value
, "*") || !strcmp(value
, "ANY")) {
482 wildcards
|= f
->wildcard
;
486 wildcards
&= ~f
->wildcard
;
487 if (f
->wildcard
== OFPFW_IN_PORT
488 && parse_port_name(value
, &port_no
)) {
489 match
->in_port
= htons(port_no
);
490 } else if (f
->type
== F_U8
) {
491 *(uint8_t *) data
= str_to_u32(value
);
492 } else if (f
->type
== F_U16
) {
493 *(uint16_t *) data
= htons(str_to_u32(value
));
494 } else if (f
->type
== F_MAC
) {
495 str_to_mac(value
, data
);
496 } else if (f
->type
== F_IP
) {
497 wildcards
|= str_to_ip(value
, data
) << f
->shift
;
503 ovs_fatal(0, "unknown keyword %s", name
);
507 match
->wildcards
= htonl(wildcards
);
510 normalize_match(&normalized
);
511 if (memcmp(match
, &normalized
, sizeof normalized
)) {
512 char *old
= ofp_match_to_literal_string(match
);
513 char *new = ofp_match_to_literal_string(&normalized
);
514 VLOG_WARN("The specified flow is not in normal form:");
515 VLOG_WARN(" as specified: %s", old
);
516 VLOG_WARN("as normalized: %s", new);
522 /* Parses 'string' as a OFPT_FLOW_MOD with subtype OFPFC_ADD and returns an
523 * ofpbuf that contains it. */
525 parse_ofp_add_flow_str(char *string
)
527 struct ofpbuf
*buffer
;
528 struct ofp_flow_mod
*ofm
;
529 uint16_t priority
, idle_timeout
, hard_timeout
;
531 struct ofp_match match
;
533 /* parse_ofp_str() will expand and reallocate the data in 'buffer', so we
534 * can't keep pointers to across the parse_ofp_str() call. */
535 make_openflow(sizeof *ofm
, OFPT_FLOW_MOD
, &buffer
);
536 parse_ofp_str(string
, &match
, buffer
,
537 NULL
, NULL
, &priority
, &idle_timeout
, &hard_timeout
,
541 ofm
->command
= htons(OFPFC_ADD
);
542 ofm
->cookie
= htonll(cookie
);
543 ofm
->idle_timeout
= htons(idle_timeout
);
544 ofm
->hard_timeout
= htons(hard_timeout
);
545 ofm
->buffer_id
= htonl(UINT32_MAX
);
546 ofm
->priority
= htons(priority
);
547 update_openflow_length(buffer
);
552 /* Parses an OFPT_FLOW_MOD with subtype OFPFC_ADD from 'stream' and returns an
553 * ofpbuf that contains it. Returns a null pointer if end-of-file is reached
554 * before reading a flow. */
556 parse_ofp_add_flow_file(FILE *stream
)
558 struct ofpbuf
*b
= NULL
;
559 struct ds s
= DS_EMPTY_INITIALIZER
;
561 while (!ds_get_line(&s
, stream
)) {
562 char *line
= ds_cstr(&s
);
565 /* Delete comments. */
566 comment
= strchr(line
, '#');
571 /* Drop empty lines. */
572 if (line
[strspn(line
, " \t\n")] == '\0') {
576 b
= parse_ofp_add_flow_str(line
);